summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/bcm/pinctrl-bcm6358.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-04-30 23:04:30 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2021-04-30 23:04:30 +0300
commit65ec0a7d24913b146cd1500d759b8c340319d55e (patch)
treebbc5cd941cd8a922f160360ec110a4c1f42b779f /drivers/pinctrl/bcm/pinctrl-bcm6358.c
parent592fa9532d4e4a7590ca383fd537eb4d53fa585a (diff)
parent8b242ca700f8043be56542efd8360056358a42ed (diff)
downloadlinux-65ec0a7d24913b146cd1500d759b8c340319d55e.tar.xz
Merge tag 'pinctrl-v5.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control updates from Linus Walleij: "There is a lot going on! Core changes: - A semantic change to handle pinmux and pinconf in explicit order while up until now we depended on the semantic order in the device tree. The device tree is a functional programming language and does not imply any order, so the right thing is for the pin control core to provide these semantics. - Add a new pinmux-select debugfs file which makes it possible to go in and select functions for a pin manually (iteratively, at the prompt) for debugging purposes. - Fixes to gpio regmap handling for a new pin control driver making use of regmap-gpio. - Use octal permissions on debugfs files. New drivers: - A massive rewrite of the former custom pin control driver for MIPS Broadcom devices to instead use the pin control subsystem. New pin control drivers for BCM6345, BCM6328, BCM6358, BCM6362, BCM6368, BCM63268 and BCM6318 SoC variants are implemented. - Support for PM8350, PM8350B, PM8350C, PMK8350, PMR735A and PMR735B in the Qualcomm PMIC GPIO driver. Also the two GPIOs on PM8008 are supported. - Support for the Rockchip RK3568/RK3566 pin controller. - Support for Ingenic JZ4730, JZ4750, JZ4755, JZ4775 and X2000. - Support for Mediatek MTK8195. - Add a new Xilinx ZynqMP pin control driver. Driver improvements and non-urgent fixes: - Modularization and improvements of the Rockchip drivers. - Some new pins added to the description of new Renesas SoCs. - Clarifications of the GPIO base calculation in the Intel driver. - Fix the function names for the MPP54 and MPP55 pins in the Armada CP110 pin controller. - GPIO wakeup interrupt map for Qualcomm SC7280 and SM8350. - Support for ACPI probing of the Qualcomm SC8180x. - Fix interrupt clear status on rockchip - Fix some missing pins on the Ingenic JZ4770, some semantic fixes for the behaviour of the Ingenic pin controller. Add DMIC pins for JZ4780, X1000, X1500 and X1830. - A slew of janitorial like of_node_put() calls" * tag 'pinctrl-v5.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (99 commits) pinctrl: Add Xilinx ZynqMP pinctrl driver support firmware: xilinx: Add pinctrl support pinctrl: rockchip: do coding style for mux route struct pinctrl: Add PIN_CONFIG_MODE_PWM to enum pin_config_param pinctrl: Introduce MODE group in enum pin_config_param pinctrl: Keep enum pin_config_param ordered by name dt-bindings: pinctrl: Add binding for ZynqMP pinctrl driver pinctrl: core: Fix kernel doc string for pin_get_name() pinctrl: mediatek: use spin lock in mtk_rmw pinctrl: add drive for I2C related pins on MT8195 pinctrl: add pinctrl driver on mt8195 dt-bindings: pinctrl: mt8195: add pinctrl file and binding document pinctrl: Ingenic: Add pinctrl driver for X2000. pinctrl: Ingenic: Add pinctrl driver for JZ4775. pinctrl: Ingenic: Add pinctrl driver for JZ4755. pinctrl: Ingenic: Add pinctrl driver for JZ4750. pinctrl: Ingenic: Add pinctrl driver for JZ4730. dt-bindings: pinctrl: Add bindings for new Ingenic SoCs. pinctrl: Ingenic: Reformat the code. pinctrl: Ingenic: Add DMIC pins support for Ingenic SoCs. ...
Diffstat (limited to 'drivers/pinctrl/bcm/pinctrl-bcm6358.c')
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6358.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6358.c b/drivers/pinctrl/bcm/pinctrl-bcm6358.c
new file mode 100644
index 000000000000..d638578727f3
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6358.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for BCM6358 GPIO unit (pinctrl + GPIO)
+ *
+ * Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/gpio/driver.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "../pinctrl-utils.h"
+
+#include "pinctrl-bcm63xx.h"
+
+#define BCM6358_NUM_GPIOS 40
+
+#define BCM6358_MODE_REG 0x18
+#define BCM6358_MODE_MUX_NONE 0
+#define BCM6358_MODE_MUX_EBI_CS BIT(5)
+#define BCM6358_MODE_MUX_UART1 BIT(6)
+#define BCM6358_MODE_MUX_SPI_CS BIT(7)
+#define BCM6358_MODE_MUX_ASYNC_MODEM BIT(8)
+#define BCM6358_MODE_MUX_LEGACY_LED BIT(9)
+#define BCM6358_MODE_MUX_SERIAL_LED BIT(10)
+#define BCM6358_MODE_MUX_LED BIT(11)
+#define BCM6358_MODE_MUX_UTOPIA BIT(12)
+#define BCM6358_MODE_MUX_CLKRST BIT(13)
+#define BCM6358_MODE_MUX_PWM_SYN_CLK BIT(14)
+#define BCM6358_MODE_MUX_SYS_IRQ BIT(15)
+
+struct bcm6358_pingroup {
+ const char *name;
+ const unsigned * const pins;
+ const unsigned num_pins;
+
+ const uint16_t mode_val;
+
+ /* non-GPIO function muxes require the gpio direction to be set */
+ const uint16_t direction;
+};
+
+struct bcm6358_function {
+ const char *name;
+ const char * const *groups;
+ const unsigned num_groups;
+};
+
+struct bcm6358_priv {
+ struct regmap_field *overlays;
+};
+
+#define BCM6358_GPIO_PIN(a, b, bit1, bit2, bit3) \
+ { \
+ .number = a, \
+ .name = b, \
+ .drv_data = (void *)(BCM6358_MODE_MUX_##bit1 | \
+ BCM6358_MODE_MUX_##bit2 | \
+ BCM6358_MODE_MUX_##bit3), \
+ }
+
+static const struct pinctrl_pin_desc bcm6358_pins[] = {
+ BCM6358_GPIO_PIN(0, "gpio0", LED, NONE, NONE),
+ BCM6358_GPIO_PIN(1, "gpio1", LED, NONE, NONE),
+ BCM6358_GPIO_PIN(2, "gpio2", LED, NONE, NONE),
+ BCM6358_GPIO_PIN(3, "gpio3", LED, NONE, NONE),
+ PINCTRL_PIN(4, "gpio4"),
+ BCM6358_GPIO_PIN(5, "gpio5", SYS_IRQ, NONE, NONE),
+ BCM6358_GPIO_PIN(6, "gpio6", SERIAL_LED, NONE, NONE),
+ BCM6358_GPIO_PIN(7, "gpio7", SERIAL_LED, NONE, NONE),
+ BCM6358_GPIO_PIN(8, "gpio8", PWM_SYN_CLK, NONE, NONE),
+ BCM6358_GPIO_PIN(9, "gpio09", LEGACY_LED, NONE, NONE),
+ BCM6358_GPIO_PIN(10, "gpio10", LEGACY_LED, NONE, NONE),
+ BCM6358_GPIO_PIN(11, "gpio11", LEGACY_LED, NONE, NONE),
+ BCM6358_GPIO_PIN(12, "gpio12", LEGACY_LED, ASYNC_MODEM, UTOPIA),
+ BCM6358_GPIO_PIN(13, "gpio13", LEGACY_LED, ASYNC_MODEM, UTOPIA),
+ BCM6358_GPIO_PIN(14, "gpio14", LEGACY_LED, ASYNC_MODEM, UTOPIA),
+ BCM6358_GPIO_PIN(15, "gpio15", LEGACY_LED, ASYNC_MODEM, UTOPIA),
+ PINCTRL_PIN(16, "gpio16"),
+ PINCTRL_PIN(17, "gpio17"),
+ PINCTRL_PIN(18, "gpio18"),
+ PINCTRL_PIN(19, "gpio19"),
+ PINCTRL_PIN(20, "gpio20"),
+ PINCTRL_PIN(21, "gpio21"),
+ BCM6358_GPIO_PIN(22, "gpio22", UTOPIA, NONE, NONE),
+ BCM6358_GPIO_PIN(23, "gpio23", UTOPIA, NONE, NONE),
+ BCM6358_GPIO_PIN(24, "gpio24", UTOPIA, NONE, NONE),
+ BCM6358_GPIO_PIN(25, "gpio25", UTOPIA, NONE, NONE),
+ BCM6358_GPIO_PIN(26, "gpio26", UTOPIA, NONE, NONE),
+ BCM6358_GPIO_PIN(27, "gpio27", UTOPIA, NONE, NONE),
+ BCM6358_GPIO_PIN(28, "gpio28", UTOPIA, UART1, NONE),
+ BCM6358_GPIO_PIN(29, "gpio29", UTOPIA, UART1, NONE),
+ BCM6358_GPIO_PIN(30, "gpio30", UTOPIA, UART1, EBI_CS),
+ BCM6358_GPIO_PIN(31, "gpio31", UTOPIA, UART1, EBI_CS),
+ BCM6358_GPIO_PIN(32, "gpio32", SPI_CS, NONE, NONE),
+ BCM6358_GPIO_PIN(33, "gpio33", SPI_CS, NONE, NONE),
+ PINCTRL_PIN(34, "gpio34"),
+ PINCTRL_PIN(35, "gpio35"),
+ PINCTRL_PIN(36, "gpio36"),
+ PINCTRL_PIN(37, "gpio37"),
+ PINCTRL_PIN(38, "gpio38"),
+ PINCTRL_PIN(39, "gpio39"),
+};
+
+static unsigned ebi_cs_grp_pins[] = { 30, 31 };
+
+static unsigned uart1_grp_pins[] = { 28, 29, 30, 31 };
+
+static unsigned spi_cs_grp_pins[] = { 32, 33 };
+
+static unsigned async_modem_grp_pins[] = { 12, 13, 14, 15 };
+
+static unsigned serial_led_grp_pins[] = { 6, 7 };
+
+static unsigned legacy_led_grp_pins[] = { 9, 10, 11, 12, 13, 14, 15 };
+
+static unsigned led_grp_pins[] = { 0, 1, 2, 3 };
+
+static unsigned utopia_grp_pins[] = {
+ 12, 13, 14, 15, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+};
+
+static unsigned pwm_syn_clk_grp_pins[] = { 8 };
+
+static unsigned sys_irq_grp_pins[] = { 5 };
+
+#define BCM6358_GPIO_MUX_GROUP(n, bit, dir) \
+ { \
+ .name = #n, \
+ .pins = n##_pins, \
+ .num_pins = ARRAY_SIZE(n##_pins), \
+ .mode_val = BCM6358_MODE_MUX_##bit, \
+ .direction = dir, \
+ }
+
+static const struct bcm6358_pingroup bcm6358_groups[] = {
+ BCM6358_GPIO_MUX_GROUP(ebi_cs_grp, EBI_CS, 0x3),
+ BCM6358_GPIO_MUX_GROUP(uart1_grp, UART1, 0x2),
+ BCM6358_GPIO_MUX_GROUP(spi_cs_grp, SPI_CS, 0x6),
+ BCM6358_GPIO_MUX_GROUP(async_modem_grp, ASYNC_MODEM, 0x6),
+ BCM6358_GPIO_MUX_GROUP(legacy_led_grp, LEGACY_LED, 0x7f),
+ BCM6358_GPIO_MUX_GROUP(serial_led_grp, SERIAL_LED, 0x3),
+ BCM6358_GPIO_MUX_GROUP(led_grp, LED, 0xf),
+ BCM6358_GPIO_MUX_GROUP(utopia_grp, UTOPIA, 0x000f),
+ BCM6358_GPIO_MUX_GROUP(pwm_syn_clk_grp, PWM_SYN_CLK, 0x1),
+ BCM6358_GPIO_MUX_GROUP(sys_irq_grp, SYS_IRQ, 0x1),
+};
+
+static const char * const ebi_cs_groups[] = {
+ "ebi_cs_grp"
+};
+
+static const char * const uart1_groups[] = {
+ "uart1_grp"
+};
+
+static const char * const spi_cs_2_3_groups[] = {
+ "spi_cs_2_3_grp"
+};
+
+static const char * const async_modem_groups[] = {
+ "async_modem_grp"
+};
+
+static const char * const legacy_led_groups[] = {
+ "legacy_led_grp",
+};
+
+static const char * const serial_led_groups[] = {
+ "serial_led_grp",
+};
+
+static const char * const led_groups[] = {
+ "led_grp",
+};
+
+static const char * const clkrst_groups[] = {
+ "clkrst_grp",
+};
+
+static const char * const pwm_syn_clk_groups[] = {
+ "pwm_syn_clk_grp",
+};
+
+static const char * const sys_irq_groups[] = {
+ "sys_irq_grp",
+};
+
+#define BCM6358_FUN(n) \
+ { \
+ .name = #n, \
+ .groups = n##_groups, \
+ .num_groups = ARRAY_SIZE(n##_groups), \
+ }
+
+static const struct bcm6358_function bcm6358_funcs[] = {
+ BCM6358_FUN(ebi_cs),
+ BCM6358_FUN(uart1),
+ BCM6358_FUN(spi_cs_2_3),
+ BCM6358_FUN(async_modem),
+ BCM6358_FUN(legacy_led),
+ BCM6358_FUN(serial_led),
+ BCM6358_FUN(led),
+ BCM6358_FUN(clkrst),
+ BCM6358_FUN(pwm_syn_clk),
+ BCM6358_FUN(sys_irq),
+};
+
+static int bcm6358_pinctrl_get_group_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(bcm6358_groups);
+}
+
+static const char *bcm6358_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ return bcm6358_groups[group].name;
+}
+
+static int bcm6358_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group, const unsigned **pins,
+ unsigned *num_pins)
+{
+ *pins = bcm6358_groups[group].pins;
+ *num_pins = bcm6358_groups[group].num_pins;
+
+ return 0;
+}
+
+static int bcm6358_pinctrl_get_func_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(bcm6358_funcs);
+}
+
+static const char *bcm6358_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return bcm6358_funcs[selector].name;
+}
+
+static int bcm6358_pinctrl_get_groups(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ *groups = bcm6358_funcs[selector].groups;
+ *num_groups = bcm6358_funcs[selector].num_groups;
+
+ return 0;
+}
+
+static int bcm6358_pinctrl_set_mux(struct pinctrl_dev *pctldev,
+ unsigned selector, unsigned group)
+{
+ struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ struct bcm6358_priv *priv = pc->driver_data;
+ const struct bcm6358_pingroup *pg = &bcm6358_groups[group];
+ unsigned int val = pg->mode_val;
+ unsigned int mask = val;
+ unsigned pin;
+
+ for (pin = 0; pin < pg->num_pins; pin++)
+ mask |= (unsigned long)bcm6358_pins[pin].drv_data;
+
+ regmap_field_update_bits(priv->overlays, mask, val);
+
+ for (pin = 0; pin < pg->num_pins; pin++) {
+ struct pinctrl_gpio_range *range;
+ unsigned int hw_gpio = bcm6358_pins[pin].number;
+
+ range = pinctrl_find_gpio_range_from_pin(pctldev, hw_gpio);
+ if (range) {
+ struct gpio_chip *gc = range->gc;
+
+ if (pg->direction & BIT(pin))
+ gc->direction_output(gc, hw_gpio, 0);
+ else
+ gc->direction_input(gc, hw_gpio);
+ }
+ }
+
+ return 0;
+}
+
+static int bcm6358_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ struct bcm6358_priv *priv = pc->driver_data;
+ unsigned int mask;
+
+ mask = (unsigned long) bcm6358_pins[offset].drv_data;
+ if (!mask)
+ return 0;
+
+ /* disable all functions using this pin */
+ return regmap_field_update_bits(priv->overlays, mask, 0);
+}
+
+static struct pinctrl_ops bcm6358_pctl_ops = {
+ .dt_free_map = pinctrl_utils_free_map,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .get_group_name = bcm6358_pinctrl_get_group_name,
+ .get_group_pins = bcm6358_pinctrl_get_group_pins,
+ .get_groups_count = bcm6358_pinctrl_get_group_count,
+};
+
+static struct pinmux_ops bcm6358_pmx_ops = {
+ .get_function_groups = bcm6358_pinctrl_get_groups,
+ .get_function_name = bcm6358_pinctrl_get_func_name,
+ .get_functions_count = bcm6358_pinctrl_get_func_count,
+ .gpio_request_enable = bcm6358_gpio_request_enable,
+ .set_mux = bcm6358_pinctrl_set_mux,
+ .strict = true,
+};
+
+static const struct bcm63xx_pinctrl_soc bcm6358_soc = {
+ .ngpios = BCM6358_NUM_GPIOS,
+ .npins = ARRAY_SIZE(bcm6358_pins),
+ .pctl_ops = &bcm6358_pctl_ops,
+ .pins = bcm6358_pins,
+ .pmx_ops = &bcm6358_pmx_ops,
+};
+
+static int bcm6358_pinctrl_probe(struct platform_device *pdev)
+{
+ struct reg_field overlays = REG_FIELD(BCM6358_MODE_REG, 0, 15);
+ struct device *dev = &pdev->dev;
+ struct bcm63xx_pinctrl *pc;
+ struct bcm6358_priv *priv;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ err = bcm63xx_pinctrl_probe(pdev, &bcm6358_soc, (void *) priv);
+ if (err)
+ return err;
+
+ pc = platform_get_drvdata(pdev);
+
+ priv->overlays = devm_regmap_field_alloc(dev, pc->regs, overlays);
+ if (IS_ERR(priv->overlays))
+ return PTR_ERR(priv->overlays);
+
+ return 0;
+}
+
+static const struct of_device_id bcm6358_pinctrl_match[] = {
+ { .compatible = "brcm,bcm6358-pinctrl", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver bcm6358_pinctrl_driver = {
+ .probe = bcm6358_pinctrl_probe,
+ .driver = {
+ .name = "bcm6358-pinctrl",
+ .of_match_table = bcm6358_pinctrl_match,
+ },
+};
+
+builtin_platform_driver(bcm6358_pinctrl_driver);