diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2021-03-30 01:55:49 +0300 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2021-03-30 01:55:49 +0300 |
commit | 762bee3e3e9f42cafdb3ead64b7aee37f9b7369f (patch) | |
tree | ac41e90b78bee9bbfb73b4650d519f3081043b6d /drivers/pinctrl/bcm | |
parent | 22667a63fe3e5fbda7b02ac51d769ad906a385b2 (diff) | |
parent | d28039fccf948a407de69106465caa465b1dcf32 (diff) | |
download | linux-762bee3e3e9f42cafdb3ead64b7aee37f9b7369f.tar.xz |
Merge branch 'ib-bcm63xx' into devel
Diffstat (limited to 'drivers/pinctrl/bcm')
-rw-r--r-- | drivers/pinctrl/bcm/Kconfig | 55 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/Makefile | 7 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm6318.c | 498 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm63268.c | 643 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm6328.c | 404 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm6358.c | 369 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm6362.c | 617 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm6368.c | 523 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm63xx.c | 109 | ||||
-rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm63xx.h | 43 |
10 files changed, 3268 insertions, 0 deletions
diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig index 0ed14de0134c..33660e8fec05 100644 --- a/drivers/pinctrl/bcm/Kconfig +++ b/drivers/pinctrl/bcm/Kconfig @@ -29,6 +29,61 @@ config PINCTRL_BCM2835 help Say Y here to enable the Broadcom BCM2835 GPIO driver. +config PINCTRL_BCM63XX + bool + select GENERIC_PINCONF + select GPIO_REGMAP + select PINCONF + select PINMUX + +config PINCTRL_BCM6318 + bool "Broadcom BCM6318 GPIO driver" + depends on (BMIPS_GENERIC || COMPILE_TEST) + select PINCTRL_BCM63XX + default BMIPS_GENERIC + help + Say Y here to enable the Broadcom BCM6318 GPIO driver. + +config PINCTRL_BCM6328 + bool "Broadcom BCM6328 GPIO driver" + depends on (BMIPS_GENERIC || COMPILE_TEST) + select PINCTRL_BCM63XX + default BMIPS_GENERIC + help + Say Y here to enable the Broadcom BCM6328 GPIO driver. + +config PINCTRL_BCM6358 + bool "Broadcom BCM6358 GPIO driver" + depends on (BMIPS_GENERIC || COMPILE_TEST) + select PINCTRL_BCM63XX + default BMIPS_GENERIC + help + Say Y here to enable the Broadcom BCM6358 GPIO driver. + +config PINCTRL_BCM6362 + bool "Broadcom BCM6362 GPIO driver" + depends on (BMIPS_GENERIC || COMPILE_TEST) + select PINCTRL_BCM63XX + default BMIPS_GENERIC + help + Say Y here to enable the Broadcom BCM6362 GPIO driver. + +config PINCTRL_BCM6368 + bool "Broadcom BCM6368 GPIO driver" + depends on (BMIPS_GENERIC || COMPILE_TEST) + select PINCTRL_BCM63XX + default BMIPS_GENERIC + help + Say Y here to enable the Broadcom BCM6368 GPIO driver. + +config PINCTRL_BCM63268 + bool "Broadcom BCM63268 GPIO driver" + depends on (BMIPS_GENERIC || COMPILE_TEST) + select PINCTRL_BCM63XX + default BMIPS_GENERIC + help + Say Y here to enable the Broadcom BCM63268 GPIO driver. + config PINCTRL_IPROC_GPIO bool "Broadcom iProc GPIO (with PINCONF) driver" depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST) diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile index 79d5e49fdd9a..00c7b7775e63 100644 --- a/drivers/pinctrl/bcm/Makefile +++ b/drivers/pinctrl/bcm/Makefile @@ -3,6 +3,13 @@ obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o +obj-$(CONFIG_PINCTRL_BCM63XX) += pinctrl-bcm63xx.o +obj-$(CONFIG_PINCTRL_BCM6318) += pinctrl-bcm6318.o +obj-$(CONFIG_PINCTRL_BCM6328) += pinctrl-bcm6328.o +obj-$(CONFIG_PINCTRL_BCM6358) += pinctrl-bcm6358.o +obj-$(CONFIG_PINCTRL_BCM6362) += pinctrl-bcm6362.o +obj-$(CONFIG_PINCTRL_BCM6368) += pinctrl-bcm6368.o +obj-$(CONFIG_PINCTRL_BCM63268) += pinctrl-bcm63268.o obj-$(CONFIG_PINCTRL_IPROC_GPIO) += pinctrl-iproc-gpio.o obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o obj-$(CONFIG_PINCTRL_NS) += pinctrl-ns.o diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6318.c b/drivers/pinctrl/bcm/pinctrl-bcm6318.c new file mode 100644 index 000000000000..77fd9b58067d --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm6318.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for BCM6318 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 BCM6318_NUM_GPIOS 50 +#define BCM6318_NUM_MUX 48 + +#define BCM6318_MODE_REG 0x18 +#define BCM6318_MUX_REG 0x1c +#define BCM6328_MUX_MASK GENMASK(1, 0) +#define BCM6318_PAD_REG 0x54 +#define BCM6328_PAD_MASK GENMASK(3, 0) + +struct bcm6318_pingroup { + const char *name; + const unsigned * const pins; + const unsigned num_pins; +}; + +struct bcm6318_function { + const char *name; + const char * const *groups; + const unsigned num_groups; + + unsigned mode_val:1; + unsigned mux_val:2; +}; + +static const struct pinctrl_pin_desc bcm6318_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + PINCTRL_PIN(8, "gpio8"), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + PINCTRL_PIN(12, "gpio12"), + PINCTRL_PIN(13, "gpio13"), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), + PINCTRL_PIN(16, "gpio16"), + PINCTRL_PIN(17, "gpio17"), + PINCTRL_PIN(18, "gpio18"), + PINCTRL_PIN(19, "gpio19"), + PINCTRL_PIN(20, "gpio20"), + PINCTRL_PIN(21, "gpio21"), + PINCTRL_PIN(22, "gpio22"), + PINCTRL_PIN(23, "gpio23"), + PINCTRL_PIN(24, "gpio24"), + PINCTRL_PIN(25, "gpio25"), + PINCTRL_PIN(26, "gpio26"), + PINCTRL_PIN(27, "gpio27"), + PINCTRL_PIN(28, "gpio28"), + PINCTRL_PIN(29, "gpio29"), + PINCTRL_PIN(30, "gpio30"), + PINCTRL_PIN(31, "gpio31"), + PINCTRL_PIN(32, "gpio32"), + PINCTRL_PIN(33, "gpio33"), + PINCTRL_PIN(34, "gpio34"), + PINCTRL_PIN(35, "gpio35"), + PINCTRL_PIN(36, "gpio36"), + PINCTRL_PIN(37, "gpio37"), + PINCTRL_PIN(38, "gpio38"), + PINCTRL_PIN(39, "gpio39"), + PINCTRL_PIN(40, "gpio40"), + PINCTRL_PIN(41, "gpio41"), + PINCTRL_PIN(42, "gpio42"), + PINCTRL_PIN(43, "gpio43"), + PINCTRL_PIN(44, "gpio44"), + PINCTRL_PIN(45, "gpio45"), + PINCTRL_PIN(46, "gpio46"), + PINCTRL_PIN(47, "gpio47"), + PINCTRL_PIN(48, "gpio48"), + PINCTRL_PIN(49, "gpio49"), +}; + +static unsigned gpio0_pins[] = { 0 }; +static unsigned gpio1_pins[] = { 1 }; +static unsigned gpio2_pins[] = { 2 }; +static unsigned gpio3_pins[] = { 3 }; +static unsigned gpio4_pins[] = { 4 }; +static unsigned gpio5_pins[] = { 5 }; +static unsigned gpio6_pins[] = { 6 }; +static unsigned gpio7_pins[] = { 7 }; +static unsigned gpio8_pins[] = { 8 }; +static unsigned gpio9_pins[] = { 9 }; +static unsigned gpio10_pins[] = { 10 }; +static unsigned gpio11_pins[] = { 11 }; +static unsigned gpio12_pins[] = { 12 }; +static unsigned gpio13_pins[] = { 13 }; +static unsigned gpio14_pins[] = { 14 }; +static unsigned gpio15_pins[] = { 15 }; +static unsigned gpio16_pins[] = { 16 }; +static unsigned gpio17_pins[] = { 17 }; +static unsigned gpio18_pins[] = { 18 }; +static unsigned gpio19_pins[] = { 19 }; +static unsigned gpio20_pins[] = { 20 }; +static unsigned gpio21_pins[] = { 21 }; +static unsigned gpio22_pins[] = { 22 }; +static unsigned gpio23_pins[] = { 23 }; +static unsigned gpio24_pins[] = { 24 }; +static unsigned gpio25_pins[] = { 25 }; +static unsigned gpio26_pins[] = { 26 }; +static unsigned gpio27_pins[] = { 27 }; +static unsigned gpio28_pins[] = { 28 }; +static unsigned gpio29_pins[] = { 29 }; +static unsigned gpio30_pins[] = { 30 }; +static unsigned gpio31_pins[] = { 31 }; +static unsigned gpio32_pins[] = { 32 }; +static unsigned gpio33_pins[] = { 33 }; +static unsigned gpio34_pins[] = { 34 }; +static unsigned gpio35_pins[] = { 35 }; +static unsigned gpio36_pins[] = { 36 }; +static unsigned gpio37_pins[] = { 37 }; +static unsigned gpio38_pins[] = { 38 }; +static unsigned gpio39_pins[] = { 39 }; +static unsigned gpio40_pins[] = { 40 }; +static unsigned gpio41_pins[] = { 41 }; +static unsigned gpio42_pins[] = { 42 }; +static unsigned gpio43_pins[] = { 43 }; +static unsigned gpio44_pins[] = { 44 }; +static unsigned gpio45_pins[] = { 45 }; +static unsigned gpio46_pins[] = { 46 }; +static unsigned gpio47_pins[] = { 47 }; +static unsigned gpio48_pins[] = { 48 }; +static unsigned gpio49_pins[] = { 49 }; + +#define BCM6318_GROUP(n) \ + { \ + .name = #n, \ + .pins = n##_pins, \ + .num_pins = ARRAY_SIZE(n##_pins), \ + } + +static struct bcm6318_pingroup bcm6318_groups[] = { + BCM6318_GROUP(gpio0), + BCM6318_GROUP(gpio1), + BCM6318_GROUP(gpio2), + BCM6318_GROUP(gpio3), + BCM6318_GROUP(gpio4), + BCM6318_GROUP(gpio5), + BCM6318_GROUP(gpio6), + BCM6318_GROUP(gpio7), + BCM6318_GROUP(gpio8), + BCM6318_GROUP(gpio9), + BCM6318_GROUP(gpio10), + BCM6318_GROUP(gpio11), + BCM6318_GROUP(gpio12), + BCM6318_GROUP(gpio13), + BCM6318_GROUP(gpio14), + BCM6318_GROUP(gpio15), + BCM6318_GROUP(gpio16), + BCM6318_GROUP(gpio17), + BCM6318_GROUP(gpio18), + BCM6318_GROUP(gpio19), + BCM6318_GROUP(gpio20), + BCM6318_GROUP(gpio21), + BCM6318_GROUP(gpio22), + BCM6318_GROUP(gpio23), + BCM6318_GROUP(gpio24), + BCM6318_GROUP(gpio25), + BCM6318_GROUP(gpio26), + BCM6318_GROUP(gpio27), + BCM6318_GROUP(gpio28), + BCM6318_GROUP(gpio29), + BCM6318_GROUP(gpio30), + BCM6318_GROUP(gpio31), + BCM6318_GROUP(gpio32), + BCM6318_GROUP(gpio33), + BCM6318_GROUP(gpio34), + BCM6318_GROUP(gpio35), + BCM6318_GROUP(gpio36), + BCM6318_GROUP(gpio37), + BCM6318_GROUP(gpio38), + BCM6318_GROUP(gpio39), + BCM6318_GROUP(gpio40), + BCM6318_GROUP(gpio41), + BCM6318_GROUP(gpio42), + BCM6318_GROUP(gpio43), + BCM6318_GROUP(gpio44), + BCM6318_GROUP(gpio45), + BCM6318_GROUP(gpio46), + BCM6318_GROUP(gpio47), + BCM6318_GROUP(gpio48), + BCM6318_GROUP(gpio49), +}; + +/* GPIO_MODE */ +static const char * const led_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", + "gpio4", + "gpio5", + "gpio6", + "gpio7", + "gpio8", + "gpio9", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gpio15", + "gpio16", + "gpio17", + "gpio18", + "gpio19", + "gpio20", + "gpio21", + "gpio22", + "gpio23", +}; + +/* PINMUX_SEL */ +static const char * const ephy0_spd_led_groups[] = { + "gpio0", +}; + +static const char * const ephy1_spd_led_groups[] = { + "gpio1", +}; + +static const char * const ephy2_spd_led_groups[] = { + "gpio2", +}; + +static const char * const ephy3_spd_led_groups[] = { + "gpio3", +}; + +static const char * const ephy0_act_led_groups[] = { + "gpio4", +}; + +static const char * const ephy1_act_led_groups[] = { + "gpio5", +}; + +static const char * const ephy2_act_led_groups[] = { + "gpio6", +}; + +static const char * const ephy3_act_led_groups[] = { + "gpio7", +}; + +static const char * const serial_led_data_groups[] = { + "gpio6", +}; + +static const char * const serial_led_clk_groups[] = { + "gpio7", +}; + +static const char * const inet_act_led_groups[] = { + "gpio8", +}; + +static const char * const inet_fail_led_groups[] = { + "gpio9", +}; + +static const char * const dsl_led_groups[] = { + "gpio10", +}; + +static const char * const post_fail_led_groups[] = { + "gpio11", +}; + +static const char * const wlan_wps_led_groups[] = { + "gpio12", +}; + +static const char * const usb_pwron_groups[] = { + "gpio13", +}; + +static const char * const usb_device_led_groups[] = { + "gpio13", +}; + +static const char * const usb_active_groups[] = { + "gpio40", +}; + +#define BCM6318_MODE_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .mode_val = 1, \ + } + +#define BCM6318_MUX_FUN(n, mux) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .mux_val = mux, \ + } + +static const struct bcm6318_function bcm6318_funcs[] = { + BCM6318_MODE_FUN(led), + BCM6318_MUX_FUN(ephy0_spd_led, 1), + BCM6318_MUX_FUN(ephy1_spd_led, 1), + BCM6318_MUX_FUN(ephy2_spd_led, 1), + BCM6318_MUX_FUN(ephy3_spd_led, 1), + BCM6318_MUX_FUN(ephy0_act_led, 1), + BCM6318_MUX_FUN(ephy1_act_led, 1), + BCM6318_MUX_FUN(ephy2_act_led, 1), + BCM6318_MUX_FUN(ephy3_act_led, 1), + BCM6318_MUX_FUN(serial_led_data, 3), + BCM6318_MUX_FUN(serial_led_clk, 3), + BCM6318_MUX_FUN(inet_act_led, 1), + BCM6318_MUX_FUN(inet_fail_led, 1), + BCM6318_MUX_FUN(dsl_led, 1), + BCM6318_MUX_FUN(post_fail_led, 1), + BCM6318_MUX_FUN(wlan_wps_led, 1), + BCM6318_MUX_FUN(usb_pwron, 1), + BCM6318_MUX_FUN(usb_device_led, 2), + BCM6318_MUX_FUN(usb_active, 2), +}; + +static inline unsigned int bcm6318_mux_off(unsigned int pin) +{ + return BCM6318_MUX_REG + (pin / 16) * 4; +} + +static inline unsigned int bcm6318_pad_off(unsigned int pin) +{ + return BCM6318_PAD_REG + (pin / 8) * 4; +} + +static int bcm6318_pinctrl_get_group_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6318_groups); +} + +static const char *bcm6318_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return bcm6318_groups[group].name; +} + +static int bcm6318_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, + unsigned *num_pins) +{ + *pins = bcm6318_groups[group].pins; + *num_pins = bcm6318_groups[group].num_pins; + + return 0; +} + +static int bcm6318_pinctrl_get_func_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6318_funcs); +} + +static const char *bcm6318_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return bcm6318_funcs[selector].name; +} + +static int bcm6318_pinctrl_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + *groups = bcm6318_funcs[selector].groups; + *num_groups = bcm6318_funcs[selector].num_groups; + + return 0; +} + +static inline void bcm6318_rmw_mux(struct bcm63xx_pinctrl *pc, unsigned pin, + unsigned int mode, unsigned int mux) +{ + if (pin < BCM63XX_BANK_GPIOS) + regmap_update_bits(pc->regs, BCM6318_MODE_REG, BIT(pin), + mode ? BIT(pin) : 0); + + if (pin < BCM6318_NUM_MUX) + regmap_update_bits(pc->regs, + bcm6318_mux_off(pin), + BCM6328_MUX_MASK << ((pin % 16) * 2), + mux << ((pin % 16) * 2)); +} + +static inline void bcm6318_set_pad(struct bcm63xx_pinctrl *pc, unsigned pin, + uint8_t val) +{ + regmap_update_bits(pc->regs, bcm6318_pad_off(pin), + BCM6328_PAD_MASK << ((pin % 8) * 4), + val << ((pin % 8) * 4)); +} + +static int bcm6318_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + const struct bcm6318_pingroup *pg = &bcm6318_groups[group]; + const struct bcm6318_function *f = &bcm6318_funcs[selector]; + + bcm6318_rmw_mux(pc, pg->pins[0], f->mode_val, f->mux_val); + + return 0; +} + +static int bcm6318_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + + /* disable all functions using this pin */ + if (offset < 13) { + /* GPIOs 0-12 use mux 0 as GPIO function */ + bcm6318_rmw_mux(pc, offset, 0, 0); + } else if (offset < 42) { + /* GPIOs 13-41 use mux 3 as GPIO function */ + bcm6318_rmw_mux(pc, offset, 0, 3); + + bcm6318_set_pad(pc, offset, 0); + } + + return 0; +} + +static struct pinctrl_ops bcm6318_pctl_ops = { + .dt_free_map = pinctrl_utils_free_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .get_group_name = bcm6318_pinctrl_get_group_name, + .get_group_pins = bcm6318_pinctrl_get_group_pins, + .get_groups_count = bcm6318_pinctrl_get_group_count, +}; + +static struct pinmux_ops bcm6318_pmx_ops = { + .get_function_groups = bcm6318_pinctrl_get_groups, + .get_function_name = bcm6318_pinctrl_get_func_name, + .get_functions_count = bcm6318_pinctrl_get_func_count, + .gpio_request_enable = bcm6318_gpio_request_enable, + .set_mux = bcm6318_pinctrl_set_mux, + .strict = true, +}; + +static const struct bcm63xx_pinctrl_soc bcm6318_soc = { + .ngpios = BCM6318_NUM_GPIOS, + .npins = ARRAY_SIZE(bcm6318_pins), + .pctl_ops = &bcm6318_pctl_ops, + .pins = bcm6318_pins, + .pmx_ops = &bcm6318_pmx_ops, +}; + +static int bcm6318_pinctrl_probe(struct platform_device *pdev) +{ + return bcm63xx_pinctrl_probe(pdev, &bcm6318_soc, NULL); +} + +static const struct of_device_id bcm6318_pinctrl_match[] = { + { .compatible = "brcm,bcm6318-pinctrl", }, + { /* sentinel */ } +}; + +static struct platform_driver bcm6318_pinctrl_driver = { + .probe = bcm6318_pinctrl_probe, + .driver = { + .name = "bcm6318-pinctrl", + .of_match_table = bcm6318_pinctrl_match, + }, +}; + +builtin_platform_driver(bcm6318_pinctrl_driver); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63268.c b/drivers/pinctrl/bcm/pinctrl-bcm63268.c new file mode 100644 index 000000000000..d4c5fad7fb7d --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm63268.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for BCM63268 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 BCM63268_NUM_GPIOS 52 +#define BCM63268_NUM_LEDS 24 + +#define BCM63268_LED_REG 0x10 +#define BCM63268_MODE_REG 0x18 +#define BCM63268_CTRL_REG 0x1c +#define BCM63268_BASEMODE_REG 0x38 +#define BCM63268_BASEMODE_NAND BIT(2) /* GPIOs 2-7, 24-31 */ +#define BCM63268_BASEMODE_GPIO35 BIT(4) /* GPIO 35 */ +#define BCM63268_BASEMODE_DECTPD BIT(5) /* GPIOs 8/9 */ +#define BCM63268_BASEMODE_VDSL_PHY_0 BIT(6) /* GPIOs 10/11 */ +#define BCM63268_BASEMODE_VDSL_PHY_1 BIT(7) /* GPIOs 12/13 */ +#define BCM63268_BASEMODE_VDSL_PHY_2 BIT(8) /* GPIOs 24/25 */ +#define BCM63268_BASEMODE_VDSL_PHY_3 BIT(9) /* GPIOs 26/27 */ + +enum bcm63268_pinctrl_reg { + BCM63268_LEDCTRL, + BCM63268_MODE, + BCM63268_CTRL, + BCM63268_BASEMODE, +}; + +struct bcm63268_pingroup { + const char *name; + const unsigned * const pins; + const unsigned num_pins; +}; + +struct bcm63268_function { + const char *name; + const char * const *groups; + const unsigned num_groups; + + enum bcm63268_pinctrl_reg reg; + uint32_t mask; +}; + +#define BCM63268_PIN(a, b, basemode) \ + { \ + .number = a, \ + .name = b, \ + .drv_data = (void *)(basemode) \ + } + +static const struct pinctrl_pin_desc bcm63268_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + BCM63268_PIN(2, "gpio2", BCM63268_BASEMODE_NAND), + BCM63268_PIN(3, "gpio3", BCM63268_BASEMODE_NAND), + BCM63268_PIN(4, "gpio4", BCM63268_BASEMODE_NAND), + BCM63268_PIN(5, "gpio5", BCM63268_BASEMODE_NAND), + BCM63268_PIN(6, "gpio6", BCM63268_BASEMODE_NAND), + BCM63268_PIN(7, "gpio7", BCM63268_BASEMODE_NAND), + BCM63268_PIN(8, "gpio8", BCM63268_BASEMODE_DECTPD), + BCM63268_PIN(9, "gpio9", BCM63268_BASEMODE_DECTPD), + BCM63268_PIN(10, "gpio10", BCM63268_BASEMODE_VDSL_PHY_0), + BCM63268_PIN(11, "gpio11", BCM63268_BASEMODE_VDSL_PHY_0), + BCM63268_PIN(12, "gpio12", BCM63268_BASEMODE_VDSL_PHY_1), + BCM63268_PIN(13, "gpio13", BCM63268_BASEMODE_VDSL_PHY_1), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), + PINCTRL_PIN(16, "gpio16"), + PINCTRL_PIN(17, "gpio17"), + PINCTRL_PIN(18, "gpio18"), + PINCTRL_PIN(19, "gpio19"), + PINCTRL_PIN(20, "gpio20"), + PINCTRL_PIN(21, "gpio21"), + PINCTRL_PIN(22, "gpio22"), + PINCTRL_PIN(23, "gpio23"), + BCM63268_PIN(24, "gpio24", + BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_2), + BCM63268_PIN(25, "gpio25", + BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_2), + BCM63268_PIN(26, "gpio26", + BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_3), + BCM63268_PIN(27, "gpio27", + BCM63268_BASEMODE_NAND | BCM63268_BASEMODE_VDSL_PHY_3), + BCM63268_PIN(28, "gpio28", BCM63268_BASEMODE_NAND), + BCM63268_PIN(29, "gpio29", BCM63268_BASEMODE_NAND), + BCM63268_PIN(30, "gpio30", BCM63268_BASEMODE_NAND), + BCM63268_PIN(31, "gpio31", BCM63268_BASEMODE_NAND), + PINCTRL_PIN(32, "gpio32"), + PINCTRL_PIN(33, "gpio33"), + PINCTRL_PIN(34, "gpio34"), + PINCTRL_PIN(35, "gpio35"), + PINCTRL_PIN(36, "gpio36"), + PINCTRL_PIN(37, "gpio37"), + PINCTRL_PIN(38, "gpio38"), + PINCTRL_PIN(39, "gpio39"), + PINCTRL_PIN(40, "gpio40"), + PINCTRL_PIN(41, "gpio41"), + PINCTRL_PIN(42, "gpio42"), + PINCTRL_PIN(43, "gpio43"), + PINCTRL_PIN(44, "gpio44"), + PINCTRL_PIN(45, "gpio45"), + PINCTRL_PIN(46, "gpio46"), + PINCTRL_PIN(47, "gpio47"), + PINCTRL_PIN(48, "gpio48"), + PINCTRL_PIN(49, "gpio49"), + PINCTRL_PIN(50, "gpio50"), + PINCTRL_PIN(51, "gpio51"), +}; + +static unsigned gpio0_pins[] = { 0 }; +static unsigned gpio1_pins[] = { 1 }; +static unsigned gpio2_pins[] = { 2 }; +static unsigned gpio3_pins[] = { 3 }; +static unsigned gpio4_pins[] = { 4 }; +static unsigned gpio5_pins[] = { 5 }; +static unsigned gpio6_pins[] = { 6 }; +static unsigned gpio7_pins[] = { 7 }; +static unsigned gpio8_pins[] = { 8 }; +static unsigned gpio9_pins[] = { 9 }; +static unsigned gpio10_pins[] = { 10 }; +static unsigned gpio11_pins[] = { 11 }; +static unsigned gpio12_pins[] = { 12 }; +static unsigned gpio13_pins[] = { 13 }; +static unsigned gpio14_pins[] = { 14 }; +static unsigned gpio15_pins[] = { 15 }; +static unsigned gpio16_pins[] = { 16 }; +static unsigned gpio17_pins[] = { 17 }; +static unsigned gpio18_pins[] = { 18 }; +static unsigned gpio19_pins[] = { 19 }; +static unsigned gpio20_pins[] = { 20 }; +static unsigned gpio21_pins[] = { 21 }; +static unsigned gpio22_pins[] = { 22 }; +static unsigned gpio23_pins[] = { 23 }; +static unsigned gpio24_pins[] = { 24 }; +static unsigned gpio25_pins[] = { 25 }; +static unsigned gpio26_pins[] = { 26 }; +static unsigned gpio27_pins[] = { 27 }; +static unsigned gpio28_pins[] = { 28 }; +static unsigned gpio29_pins[] = { 29 }; +static unsigned gpio30_pins[] = { 30 }; +static unsigned gpio31_pins[] = { 31 }; +static unsigned gpio32_pins[] = { 32 }; +static unsigned gpio33_pins[] = { 33 }; +static unsigned gpio34_pins[] = { 34 }; +static unsigned gpio35_pins[] = { 35 }; +static unsigned gpio36_pins[] = { 36 }; +static unsigned gpio37_pins[] = { 37 }; +static unsigned gpio38_pins[] = { 38 }; +static unsigned gpio39_pins[] = { 39 }; +static unsigned gpio40_pins[] = { 40 }; +static unsigned gpio41_pins[] = { 41 }; +static unsigned gpio42_pins[] = { 42 }; +static unsigned gpio43_pins[] = { 43 }; +static unsigned gpio44_pins[] = { 44 }; +static unsigned gpio45_pins[] = { 45 }; +static unsigned gpio46_pins[] = { 46 }; +static unsigned gpio47_pins[] = { 47 }; +static unsigned gpio48_pins[] = { 48 }; +static unsigned gpio49_pins[] = { 49 }; +static unsigned gpio50_pins[] = { 50 }; +static unsigned gpio51_pins[] = { 51 }; + +static unsigned nand_grp_pins[] = { + 2, 3, 4, 5, 6, 7, 24, + 25, 26, 27, 28, 29, 30, 31, +}; + +static unsigned dectpd_grp_pins[] = { 8, 9 }; +static unsigned vdsl_phy0_grp_pins[] = { 10, 11 }; +static unsigned vdsl_phy1_grp_pins[] = { 12, 13 }; +static unsigned vdsl_phy2_grp_pins[] = { 24, 25 }; +static unsigned vdsl_phy3_grp_pins[] = { 26, 27 }; + +#define BCM63268_GROUP(n) \ + { \ + .name = #n, \ + .pins = n##_pins, \ + .num_pins = ARRAY_SIZE(n##_pins), \ + } + +static struct bcm63268_pingroup bcm63268_groups[] = { + BCM63268_GROUP(gpio0), + BCM63268_GROUP(gpio1), + BCM63268_GROUP(gpio2), + BCM63268_GROUP(gpio3), + BCM63268_GROUP(gpio4), + BCM63268_GROUP(gpio5), + BCM63268_GROUP(gpio6), + BCM63268_GROUP(gpio7), + BCM63268_GROUP(gpio8), + BCM63268_GROUP(gpio9), + BCM63268_GROUP(gpio10), + BCM63268_GROUP(gpio11), + BCM63268_GROUP(gpio12), + BCM63268_GROUP(gpio13), + BCM63268_GROUP(gpio14), + BCM63268_GROUP(gpio15), + BCM63268_GROUP(gpio16), + BCM63268_GROUP(gpio17), + BCM63268_GROUP(gpio18), + BCM63268_GROUP(gpio19), + BCM63268_GROUP(gpio20), + BCM63268_GROUP(gpio21), + BCM63268_GROUP(gpio22), + BCM63268_GROUP(gpio23), + BCM63268_GROUP(gpio24), + BCM63268_GROUP(gpio25), + BCM63268_GROUP(gpio26), + BCM63268_GROUP(gpio27), + BCM63268_GROUP(gpio28), + BCM63268_GROUP(gpio29), + BCM63268_GROUP(gpio30), + BCM63268_GROUP(gpio31), + BCM63268_GROUP(gpio32), + BCM63268_GROUP(gpio33), + BCM63268_GROUP(gpio34), + BCM63268_GROUP(gpio35), + BCM63268_GROUP(gpio36), + BCM63268_GROUP(gpio37), + BCM63268_GROUP(gpio38), + BCM63268_GROUP(gpio39), + BCM63268_GROUP(gpio40), + BCM63268_GROUP(gpio41), + BCM63268_GROUP(gpio42), + BCM63268_GROUP(gpio43), + BCM63268_GROUP(gpio44), + BCM63268_GROUP(gpio45), + BCM63268_GROUP(gpio46), + BCM63268_GROUP(gpio47), + BCM63268_GROUP(gpio48), + BCM63268_GROUP(gpio49), + BCM63268_GROUP(gpio50), + BCM63268_GROUP(gpio51), + + /* multi pin groups */ + BCM63268_GROUP(nand_grp), + BCM63268_GROUP(dectpd_grp), + BCM63268_GROUP(vdsl_phy0_grp), + BCM63268_GROUP(vdsl_phy1_grp), + BCM63268_GROUP(vdsl_phy2_grp), + BCM63268_GROUP(vdsl_phy3_grp), +}; + +static const char * const led_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", + "gpio4", + "gpio5", + "gpio6", + "gpio7", + "gpio8", + "gpio9", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gpio15", + "gpio16", + "gpio17", + "gpio18", + "gpio19", + "gpio20", + "gpio21", + "gpio22", + "gpio23", +}; + +static const char * const serial_led_clk_groups[] = { + "gpio0", +}; + +static const char * const serial_led_data_groups[] = { + "gpio1", +}; + +static const char * const hsspi_cs4_groups[] = { + "gpio16", +}; + +static const char * const hsspi_cs5_groups[] = { + "gpio17", +}; + +static const char * const hsspi_cs6_groups[] = { + "gpio8", +}; + +static const char * const hsspi_cs7_groups[] = { + "gpio9", +}; + +static const char * const uart1_scts_groups[] = { + "gpio10", + "gpio24", +}; + +static const char * const uart1_srts_groups[] = { + "gpio11", + "gpio25", +}; + +static const char * const uart1_sdin_groups[] = { + "gpio12", + "gpio26", +}; + +static const char * const uart1_sdout_groups[] = { + "gpio13", + "gpio27", +}; + +static const char * const ntr_pulse_in_groups[] = { + "gpio14", + "gpio28", +}; + +static const char * const dsl_ntr_pulse_out_groups[] = { + "gpio15", + "gpio29", +}; + +static const char * const adsl_spi_miso_groups[] = { + "gpio18", +}; + +static const char * const adsl_spi_mosi_groups[] = { + "gpio19", +}; + +static const char * const vreg_clk_groups[] = { + "gpio22", +}; + +static const char * const pcie_clkreq_b_groups[] = { + "gpio23", +}; + +static const char * const switch_led_clk_groups[] = { + "gpio30", +}; + +static const char * const switch_led_data_groups[] = { + "gpio31", +}; + +static const char * const wifi_groups[] = { + "gpio32", + "gpio33", + "gpio34", + "gpio35", + "gpio36", + "gpio37", + "gpio38", + "gpio39", + "gpio40", + "gpio41", + "gpio42", + "gpio43", + "gpio44", + "gpio45", + "gpio46", + "gpio47", + "gpio48", + "gpio49", + "gpio50", + "gpio51", +}; + +static const char * const nand_groups[] = { + "nand_grp", +}; + +static const char * const dectpd_groups[] = { + "dectpd_grp", +}; + +static const char * const vdsl_phy_override_0_groups[] = { + "vdsl_phy_override_0_grp", +}; + +static const char * const vdsl_phy_override_1_groups[] = { + "vdsl_phy_override_1_grp", +}; + +static const char * const vdsl_phy_override_2_groups[] = { + "vdsl_phy_override_2_grp", +}; + +static const char * const vdsl_phy_override_3_groups[] = { + "vdsl_phy_override_3_grp", +}; + +#define BCM63268_LED_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM63268_LEDCTRL, \ + } + +#define BCM63268_MODE_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM63268_MODE, \ + } + +#define BCM63268_CTRL_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM63268_CTRL, \ + } + +#define BCM63268_BASEMODE_FUN(n, val) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM63268_BASEMODE, \ + .mask = val, \ + } + +static const struct bcm63268_function bcm63268_funcs[] = { + BCM63268_LED_FUN(led), + BCM63268_MODE_FUN(serial_led_clk), + BCM63268_MODE_FUN(serial_led_data), + BCM63268_MODE_FUN(hsspi_cs6), + BCM63268_MODE_FUN(hsspi_cs7), + BCM63268_MODE_FUN(uart1_scts), + BCM63268_MODE_FUN(uart1_srts), + BCM63268_MODE_FUN(uart1_sdin), + BCM63268_MODE_FUN(uart1_sdout), + BCM63268_MODE_FUN(ntr_pulse_in), + BCM63268_MODE_FUN(dsl_ntr_pulse_out), + BCM63268_MODE_FUN(hsspi_cs4), + BCM63268_MODE_FUN(hsspi_cs5), + BCM63268_MODE_FUN(adsl_spi_miso), + BCM63268_MODE_FUN(adsl_spi_mosi), + BCM63268_MODE_FUN(vreg_clk), + BCM63268_MODE_FUN(pcie_clkreq_b), + BCM63268_MODE_FUN(switch_led_clk), + BCM63268_MODE_FUN(switch_led_data), + BCM63268_CTRL_FUN(wifi), + BCM63268_BASEMODE_FUN(nand, BCM63268_BASEMODE_NAND), + BCM63268_BASEMODE_FUN(dectpd, BCM63268_BASEMODE_DECTPD), + BCM63268_BASEMODE_FUN(vdsl_phy_override_0, + BCM63268_BASEMODE_VDSL_PHY_0), + BCM63268_BASEMODE_FUN(vdsl_phy_override_1, + BCM63268_BASEMODE_VDSL_PHY_1), + BCM63268_BASEMODE_FUN(vdsl_phy_override_2, + BCM63268_BASEMODE_VDSL_PHY_2), + BCM63268_BASEMODE_FUN(vdsl_phy_override_3, + BCM63268_BASEMODE_VDSL_PHY_3), +}; + +static int bcm63268_pinctrl_get_group_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm63268_groups); +} + +static const char *bcm63268_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return bcm63268_groups[group].name; +} + +static int bcm63268_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + *pins = bcm63268_groups[group].pins; + *num_pins = bcm63268_groups[group].num_pins; + + return 0; +} + +static int bcm63268_pinctrl_get_func_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm63268_funcs); +} + +static const char *bcm63268_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return bcm63268_funcs[selector].name; +} + +static int bcm63268_pinctrl_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + *groups = bcm63268_funcs[selector].groups; + *num_groups = bcm63268_funcs[selector].num_groups; + + return 0; +} + +static void bcm63268_set_gpio(struct bcm63xx_pinctrl *pc, unsigned pin) +{ + const struct pinctrl_pin_desc *desc = &bcm63268_pins[pin]; + unsigned int basemode = (unsigned long) desc->drv_data; + unsigned int mask = BIT(bcm63xx_bank_pin(pin)); + + if (basemode) + regmap_update_bits(pc->regs, BCM63268_BASEMODE_REG, basemode, + 0); + + if (pin < BCM63XX_BANK_GPIOS) { + /* base mode: 0 => gpio, 1 => mux function */ + regmap_update_bits(pc->regs, BCM63268_MODE_REG, mask, 0); + + /* pins 0-23 might be muxed to led */ + if (pin < BCM63268_NUM_LEDS) + regmap_update_bits(pc->regs, BCM63268_LED_REG, mask, + 0); + } else if (pin < BCM63268_NUM_GPIOS) { + /* ctrl reg: 0 => wifi function, 1 => gpio */ + regmap_update_bits(pc->regs, BCM63268_CTRL_REG, mask, mask); + } +} + +static int bcm63268_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + const struct bcm63268_pingroup *pg = &bcm63268_groups[group]; + const struct bcm63268_function *f = &bcm63268_funcs[selector]; + unsigned i; + unsigned int reg; + unsigned int val, mask; + + for (i = 0; i < pg->num_pins; i++) + bcm63268_set_gpio(pc, pg->pins[i]); + + switch (f->reg) { + case BCM63268_LEDCTRL: + reg = BCM63268_LED_REG; + mask = BIT(pg->pins[0]); + val = BIT(pg->pins[0]); + break; + case BCM63268_MODE: + reg = BCM63268_MODE_REG; + mask = BIT(pg->pins[0]); + val = BIT(pg->pins[0]); + break; + case BCM63268_CTRL: + reg = BCM63268_CTRL_REG; + mask = BIT(pg->pins[0]); + val = 0; + break; + case BCM63268_BASEMODE: + reg = BCM63268_BASEMODE_REG; + mask = f->mask; + val = f->mask; + break; + default: + WARN_ON(1); + return -EINVAL; + } + + regmap_update_bits(pc->regs, reg, mask, val); + + return 0; +} + +static int bcm63268_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + + /* disable all functions using this pin */ + bcm63268_set_gpio(pc, offset); + + return 0; +} + +static struct pinctrl_ops bcm63268_pctl_ops = { + .dt_free_map = pinctrl_utils_free_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .get_group_name = bcm63268_pinctrl_get_group_name, + .get_group_pins = bcm63268_pinctrl_get_group_pins, + .get_groups_count = bcm63268_pinctrl_get_group_count, +}; + +static struct pinmux_ops bcm63268_pmx_ops = { + .get_function_groups = bcm63268_pinctrl_get_groups, + .get_function_name = bcm63268_pinctrl_get_func_name, + .get_functions_count = bcm63268_pinctrl_get_func_count, + .gpio_request_enable = bcm63268_gpio_request_enable, + .set_mux = bcm63268_pinctrl_set_mux, + .strict = true, +}; + +static const struct bcm63xx_pinctrl_soc bcm63268_soc = { + .ngpios = BCM63268_NUM_GPIOS, + .npins = ARRAY_SIZE(bcm63268_pins), + .pctl_ops = &bcm63268_pctl_ops, + .pins = bcm63268_pins, + .pmx_ops = &bcm63268_pmx_ops, +}; + +static int bcm63268_pinctrl_probe(struct platform_device *pdev) +{ + return bcm63xx_pinctrl_probe(pdev, &bcm63268_soc, NULL); +} + +static const struct of_device_id bcm63268_pinctrl_match[] = { + { .compatible = "brcm,bcm63268-pinctrl", }, + { /* sentinel */ } +}; + +static struct platform_driver bcm63268_pinctrl_driver = { + .probe = bcm63268_pinctrl_probe, + .driver = { + .name = "bcm63268-pinctrl", + .of_match_table = bcm63268_pinctrl_match, + }, +}; + +builtin_platform_driver(bcm63268_pinctrl_driver); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6328.c b/drivers/pinctrl/bcm/pinctrl-bcm6328.c new file mode 100644 index 000000000000..c9efce600550 --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm6328.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for BCM6328 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 BCM6328_NUM_GPIOS 32 + +#define BCM6328_MODE_REG 0x18 +#define BCM6328_MUX_HI_REG 0x1c +#define BCM6328_MUX_LO_REG 0x20 +#define BCM6328_MUX_OTHER_REG 0x24 +#define BCM6328_MUX_MASK GENMASK(1, 0) + +struct bcm6328_pingroup { + const char *name; + const unsigned * const pins; + const unsigned num_pins; +}; + +struct bcm6328_function { + const char *name; + const char * const *groups; + const unsigned num_groups; + + unsigned mode_val:1; + unsigned mux_val:2; +}; + +static const unsigned int bcm6328_mux[] = { + BCM6328_MUX_LO_REG, + BCM6328_MUX_HI_REG, + BCM6328_MUX_OTHER_REG +}; + +static const struct pinctrl_pin_desc bcm6328_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + PINCTRL_PIN(8, "gpio8"), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + PINCTRL_PIN(12, "gpio12"), + PINCTRL_PIN(13, "gpio13"), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), + PINCTRL_PIN(16, "gpio16"), + PINCTRL_PIN(17, "gpio17"), + PINCTRL_PIN(18, "gpio18"), + PINCTRL_PIN(19, "gpio19"), + PINCTRL_PIN(20, "gpio20"), + PINCTRL_PIN(21, "gpio21"), + PINCTRL_PIN(22, "gpio22"), + PINCTRL_PIN(23, "gpio23"), + PINCTRL_PIN(24, "gpio24"), + PINCTRL_PIN(25, "gpio25"), + PINCTRL_PIN(26, "gpio26"), + PINCTRL_PIN(27, "gpio27"), + PINCTRL_PIN(28, "gpio28"), + PINCTRL_PIN(29, "gpio29"), + PINCTRL_PIN(30, "gpio30"), + PINCTRL_PIN(31, "gpio31"), + + /* + * No idea where they really are; so let's put them according + * to their mux offsets. + */ + PINCTRL_PIN(36, "hsspi_cs1"), + PINCTRL_PIN(38, "usb_p2"), +}; + +static unsigned gpio0_pins[] = { 0 }; +static unsigned gpio1_pins[] = { 1 }; +static unsigned gpio2_pins[] = { 2 }; +static unsigned gpio3_pins[] = { 3 }; +static unsigned gpio4_pins[] = { 4 }; +static unsigned gpio5_pins[] = { 5 }; +static unsigned gpio6_pins[] = { 6 }; +static unsigned gpio7_pins[] = { 7 }; +static unsigned gpio8_pins[] = { 8 }; +static unsigned gpio9_pins[] = { 9 }; +static unsigned gpio10_pins[] = { 10 }; +static unsigned gpio11_pins[] = { 11 }; +static unsigned gpio12_pins[] = { 12 }; +static unsigned gpio13_pins[] = { 13 }; +static unsigned gpio14_pins[] = { 14 }; +static unsigned gpio15_pins[] = { 15 }; +static unsigned gpio16_pins[] = { 16 }; +static unsigned gpio17_pins[] = { 17 }; +static unsigned gpio18_pins[] = { 18 }; +static unsigned gpio19_pins[] = { 19 }; +static unsigned gpio20_pins[] = { 20 }; +static unsigned gpio21_pins[] = { 21 }; +static unsigned gpio22_pins[] = { 22 }; +static unsigned gpio23_pins[] = { 23 }; +static unsigned gpio24_pins[] = { 24 }; +static unsigned gpio25_pins[] = { 25 }; +static unsigned gpio26_pins[] = { 26 }; +static unsigned gpio27_pins[] = { 27 }; +static unsigned gpio28_pins[] = { 28 }; +static unsigned gpio29_pins[] = { 29 }; +static unsigned gpio30_pins[] = { 30 }; +static unsigned gpio31_pins[] = { 31 }; + +static unsigned hsspi_cs1_pins[] = { 36 }; +static unsigned usb_port1_pins[] = { 38 }; + +#define BCM6328_GROUP(n) \ + { \ + .name = #n, \ + .pins = n##_pins, \ + .num_pins = ARRAY_SIZE(n##_pins), \ + } + +static struct bcm6328_pingroup bcm6328_groups[] = { + BCM6328_GROUP(gpio0), + BCM6328_GROUP(gpio1), + BCM6328_GROUP(gpio2), + BCM6328_GROUP(gpio3), + BCM6328_GROUP(gpio4), + BCM6328_GROUP(gpio5), + BCM6328_GROUP(gpio6), + BCM6328_GROUP(gpio7), + BCM6328_GROUP(gpio8), + BCM6328_GROUP(gpio9), + BCM6328_GROUP(gpio10), + BCM6328_GROUP(gpio11), + BCM6328_GROUP(gpio12), + BCM6328_GROUP(gpio13), + BCM6328_GROUP(gpio14), + BCM6328_GROUP(gpio15), + BCM6328_GROUP(gpio16), + BCM6328_GROUP(gpio17), + BCM6328_GROUP(gpio18), + BCM6328_GROUP(gpio19), + BCM6328_GROUP(gpio20), + BCM6328_GROUP(gpio21), + BCM6328_GROUP(gpio22), + BCM6328_GROUP(gpio23), + BCM6328_GROUP(gpio24), + BCM6328_GROUP(gpio25), + BCM6328_GROUP(gpio26), + BCM6328_GROUP(gpio27), + BCM6328_GROUP(gpio28), + BCM6328_GROUP(gpio29), + BCM6328_GROUP(gpio30), + BCM6328_GROUP(gpio31), + + BCM6328_GROUP(hsspi_cs1), + BCM6328_GROUP(usb_port1), +}; + +/* GPIO_MODE */ +static const char * const led_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", + "gpio4", + "gpio5", + "gpio6", + "gpio7", + "gpio8", + "gpio9", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gpio15", + "gpio16", + "gpio17", + "gpio18", + "gpio19", + "gpio20", + "gpio21", + "gpio22", + "gpio23", +}; + +/* PINMUX_SEL */ +static const char * const serial_led_data_groups[] = { + "gpio6", +}; + +static const char * const serial_led_clk_groups[] = { + "gpio7", +}; + +static const char * const inet_act_led_groups[] = { + "gpio11", +}; + +static const char * const pcie_clkreq_groups[] = { + "gpio16", +}; + +static const char * const ephy0_act_led_groups[] = { + "gpio25", +}; + +static const char * const ephy1_act_led_groups[] = { + "gpio26", +}; + +static const char * const ephy2_act_led_groups[] = { + "gpio27", +}; + +static const char * const ephy3_act_led_groups[] = { + "gpio28", +}; + +static const char * const hsspi_cs1_groups[] = { + "hsspi_cs1" +}; + +static const char * const usb_host_port_groups[] = { + "usb_port1", +}; + +static const char * const usb_device_port_groups[] = { + "usb_port1", +}; + +#define BCM6328_MODE_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .mode_val = 1, \ + } + +#define BCM6328_MUX_FUN(n, mux) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .mux_val = mux, \ + } + +static const struct bcm6328_function bcm6328_funcs[] = { + BCM6328_MODE_FUN(led), + BCM6328_MUX_FUN(serial_led_data, 2), + BCM6328_MUX_FUN(serial_led_clk, 2), + BCM6328_MUX_FUN(inet_act_led, 1), + BCM6328_MUX_FUN(pcie_clkreq, 2), + BCM6328_MUX_FUN(ephy0_act_led, 1), + BCM6328_MUX_FUN(ephy1_act_led, 1), + BCM6328_MUX_FUN(ephy2_act_led, 1), + BCM6328_MUX_FUN(ephy3_act_led, 1), + BCM6328_MUX_FUN(hsspi_cs1, 2), + BCM6328_MUX_FUN(usb_host_port, 1), + BCM6328_MUX_FUN(usb_device_port, 2), +}; + +static inline unsigned int bcm6328_mux_off(unsigned int pin) +{ + return bcm6328_mux[pin / 16]; +} + +static int bcm6328_pinctrl_get_group_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6328_groups); +} + +static const char *bcm6328_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return bcm6328_groups[group].name; +} + +static int bcm6328_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, + unsigned *num_pins) +{ + *pins = bcm6328_groups[group].pins; + *num_pins = bcm6328_groups[group].num_pins; + + return 0; +} + +static int bcm6328_pinctrl_get_func_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6328_funcs); +} + +static const char *bcm6328_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return bcm6328_funcs[selector].name; +} + +static int bcm6328_pinctrl_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + *groups = bcm6328_funcs[selector].groups; + *num_groups = bcm6328_funcs[selector].num_groups; + + return 0; +} + +static void bcm6328_rmw_mux(struct bcm63xx_pinctrl *pc, unsigned pin, + unsigned int mode, unsigned int mux) +{ + if (pin < BCM6328_NUM_GPIOS) + regmap_update_bits(pc->regs, BCM6328_MODE_REG, BIT(pin), + mode ? BIT(pin) : 0); + + regmap_update_bits(pc->regs, bcm6328_mux_off(pin), + BCM6328_MUX_MASK << ((pin % 16) * 2), + mux << ((pin % 16) * 2)); +} + +static int bcm6328_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + const struct bcm6328_pingroup *pg = &bcm6328_groups[group]; + const struct bcm6328_function *f = &bcm6328_funcs[selector]; + + bcm6328_rmw_mux(pc, pg->pins[0], f->mode_val, f->mux_val); + + return 0; +} + +static int bcm6328_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + + /* disable all functions using this pin */ + bcm6328_rmw_mux(pc, offset, 0, 0); + + return 0; +} + +static struct pinctrl_ops bcm6328_pctl_ops = { + .dt_free_map = pinctrl_utils_free_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .get_group_name = bcm6328_pinctrl_get_group_name, + .get_group_pins = bcm6328_pinctrl_get_group_pins, + .get_groups_count = bcm6328_pinctrl_get_group_count, +}; + +static struct pinmux_ops bcm6328_pmx_ops = { + .get_function_groups = bcm6328_pinctrl_get_groups, + .get_function_name = bcm6328_pinctrl_get_func_name, + .get_functions_count = bcm6328_pinctrl_get_func_count, + .gpio_request_enable = bcm6328_gpio_request_enable, + .set_mux = bcm6328_pinctrl_set_mux, + .strict = true, +}; + +static const struct bcm63xx_pinctrl_soc bcm6328_soc = { + .ngpios = BCM6328_NUM_GPIOS, + .npins = ARRAY_SIZE(bcm6328_pins), + .pctl_ops = &bcm6328_pctl_ops, + .pins = bcm6328_pins, + .pmx_ops = &bcm6328_pmx_ops, +}; + +static int bcm6328_pinctrl_probe(struct platform_device *pdev) +{ + return bcm63xx_pinctrl_probe(pdev, &bcm6328_soc, NULL); +} + +static const struct of_device_id bcm6328_pinctrl_match[] = { + { .compatible = "brcm,bcm6328-pinctrl", }, + { /* sentinel */ } +}; + +static struct platform_driver bcm6328_pinctrl_driver = { + .probe = bcm6328_pinctrl_probe, + .driver = { + .name = "bcm6328-pinctrl", + .of_match_table = bcm6328_pinctrl_match, + }, +}; + +builtin_platform_driver(bcm6328_pinctrl_driver); 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); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6362.c b/drivers/pinctrl/bcm/pinctrl-bcm6362.c new file mode 100644 index 000000000000..eb7ec80353e9 --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm6362.c @@ -0,0 +1,617 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for BCM6362 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 BCM6362_BANK_GPIOS 32 +#define BCM6362_NUM_GPIOS 48 +#define BCM6362_NUM_LEDS 24 + +#define BCM6362_LED_REG 0x10 +#define BCM6362_MODE_REG 0x18 +#define BCM6362_CTRL_REG 0x1c +#define BCM6362_BASEMODE_REG 0x38 +#define BASEMODE_NAND BIT(2) + +enum bcm6362_pinctrl_reg { + BCM6362_LEDCTRL, + BCM6362_MODE, + BCM6362_CTRL, + BCM6362_BASEMODE, +}; + +struct bcm6362_pingroup { + const char *name; + const unsigned * const pins; + const unsigned num_pins; +}; + +struct bcm6362_function { + const char *name; + const char * const *groups; + const unsigned num_groups; + + enum bcm6362_pinctrl_reg reg; + uint32_t basemode_mask; +}; + +#define BCM6362_PIN(a, b, mask) \ + { \ + .number = a, \ + .name = b, \ + .drv_data = (void *)(mask), \ + } + +static const struct pinctrl_pin_desc bcm6362_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + BCM6362_PIN(8, "gpio8", BASEMODE_NAND), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + BCM6362_PIN(12, "gpio12", BASEMODE_NAND), + BCM6362_PIN(13, "gpio13", BASEMODE_NAND), + BCM6362_PIN(14, "gpio14", BASEMODE_NAND), + BCM6362_PIN(15, "gpio15", BASEMODE_NAND), + BCM6362_PIN(16, "gpio16", BASEMODE_NAND), + BCM6362_PIN(17, "gpio17", BASEMODE_NAND), + BCM6362_PIN(18, "gpio18", BASEMODE_NAND), + BCM6362_PIN(19, "gpio19", BASEMODE_NAND), + BCM6362_PIN(20, "gpio20", BASEMODE_NAND), + BCM6362_PIN(21, "gpio21", BASEMODE_NAND), + BCM6362_PIN(22, "gpio22", BASEMODE_NAND), + BCM6362_PIN(23, "gpio23", BASEMODE_NAND), + PINCTRL_PIN(24, "gpio24"), + PINCTRL_PIN(25, "gpio25"), + PINCTRL_PIN(26, "gpio26"), + BCM6362_PIN(27, "gpio27", BASEMODE_NAND), + PINCTRL_PIN(28, "gpio28"), + PINCTRL_PIN(29, "gpio29"), + PINCTRL_PIN(30, "gpio30"), + PINCTRL_PIN(31, "gpio31"), + PINCTRL_PIN(32, "gpio32"), + PINCTRL_PIN(33, "gpio33"), + PINCTRL_PIN(34, "gpio34"), + PINCTRL_PIN(35, "gpio35"), + PINCTRL_PIN(36, "gpio36"), + PINCTRL_PIN(37, "gpio37"), + PINCTRL_PIN(38, "gpio38"), + PINCTRL_PIN(39, "gpio39"), + PINCTRL_PIN(40, "gpio40"), + PINCTRL_PIN(41, "gpio41"), + PINCTRL_PIN(42, "gpio42"), + PINCTRL_PIN(43, "gpio43"), + PINCTRL_PIN(44, "gpio44"), + PINCTRL_PIN(45, "gpio45"), + PINCTRL_PIN(46, "gpio46"), + PINCTRL_PIN(47, "gpio47"), +}; + +static unsigned gpio0_pins[] = { 0 }; +static unsigned gpio1_pins[] = { 1 }; +static unsigned gpio2_pins[] = { 2 }; +static unsigned gpio3_pins[] = { 3 }; +static unsigned gpio4_pins[] = { 4 }; +static unsigned gpio5_pins[] = { 5 }; +static unsigned gpio6_pins[] = { 6 }; +static unsigned gpio7_pins[] = { 7 }; +static unsigned gpio8_pins[] = { 8 }; +static unsigned gpio9_pins[] = { 9 }; +static unsigned gpio10_pins[] = { 10 }; +static unsigned gpio11_pins[] = { 11 }; +static unsigned gpio12_pins[] = { 12 }; +static unsigned gpio13_pins[] = { 13 }; +static unsigned gpio14_pins[] = { 14 }; +static unsigned gpio15_pins[] = { 15 }; +static unsigned gpio16_pins[] = { 16 }; +static unsigned gpio17_pins[] = { 17 }; +static unsigned gpio18_pins[] = { 18 }; +static unsigned gpio19_pins[] = { 19 }; +static unsigned gpio20_pins[] = { 20 }; +static unsigned gpio21_pins[] = { 21 }; +static unsigned gpio22_pins[] = { 22 }; +static unsigned gpio23_pins[] = { 23 }; +static unsigned gpio24_pins[] = { 24 }; +static unsigned gpio25_pins[] = { 25 }; +static unsigned gpio26_pins[] = { 26 }; +static unsigned gpio27_pins[] = { 27 }; +static unsigned gpio28_pins[] = { 28 }; +static unsigned gpio29_pins[] = { 29 }; +static unsigned gpio30_pins[] = { 30 }; +static unsigned gpio31_pins[] = { 31 }; +static unsigned gpio32_pins[] = { 32 }; +static unsigned gpio33_pins[] = { 33 }; +static unsigned gpio34_pins[] = { 34 }; +static unsigned gpio35_pins[] = { 35 }; +static unsigned gpio36_pins[] = { 36 }; +static unsigned gpio37_pins[] = { 37 }; +static unsigned gpio38_pins[] = { 38 }; +static unsigned gpio39_pins[] = { 39 }; +static unsigned gpio40_pins[] = { 40 }; +static unsigned gpio41_pins[] = { 41 }; +static unsigned gpio42_pins[] = { 42 }; +static unsigned gpio43_pins[] = { 43 }; +static unsigned gpio44_pins[] = { 44 }; +static unsigned gpio45_pins[] = { 45 }; +static unsigned gpio46_pins[] = { 46 }; +static unsigned gpio47_pins[] = { 47 }; + +static unsigned nand_grp_pins[] = { + 8, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 27, +}; + +#define BCM6362_GROUP(n) \ + { \ + .name = #n, \ + .pins = n##_pins, \ + .num_pins = ARRAY_SIZE(n##_pins), \ + } + +static struct bcm6362_pingroup bcm6362_groups[] = { + BCM6362_GROUP(gpio0), + BCM6362_GROUP(gpio1), + BCM6362_GROUP(gpio2), + BCM6362_GROUP(gpio3), + BCM6362_GROUP(gpio4), + BCM6362_GROUP(gpio5), + BCM6362_GROUP(gpio6), + BCM6362_GROUP(gpio7), + BCM6362_GROUP(gpio8), + BCM6362_GROUP(gpio9), + BCM6362_GROUP(gpio10), + BCM6362_GROUP(gpio11), + BCM6362_GROUP(gpio12), + BCM6362_GROUP(gpio13), + BCM6362_GROUP(gpio14), + BCM6362_GROUP(gpio15), + BCM6362_GROUP(gpio16), + BCM6362_GROUP(gpio17), + BCM6362_GROUP(gpio18), + BCM6362_GROUP(gpio19), + BCM6362_GROUP(gpio20), + BCM6362_GROUP(gpio21), + BCM6362_GROUP(gpio22), + BCM6362_GROUP(gpio23), + BCM6362_GROUP(gpio24), + BCM6362_GROUP(gpio25), + BCM6362_GROUP(gpio26), + BCM6362_GROUP(gpio27), + BCM6362_GROUP(gpio28), + BCM6362_GROUP(gpio29), + BCM6362_GROUP(gpio30), + BCM6362_GROUP(gpio31), + BCM6362_GROUP(gpio32), + BCM6362_GROUP(gpio33), + BCM6362_GROUP(gpio34), + BCM6362_GROUP(gpio35), + BCM6362_GROUP(gpio36), + BCM6362_GROUP(gpio37), + BCM6362_GROUP(gpio38), + BCM6362_GROUP(gpio39), + BCM6362_GROUP(gpio40), + BCM6362_GROUP(gpio41), + BCM6362_GROUP(gpio42), + BCM6362_GROUP(gpio43), + BCM6362_GROUP(gpio44), + BCM6362_GROUP(gpio45), + BCM6362_GROUP(gpio46), + BCM6362_GROUP(gpio47), + BCM6362_GROUP(nand_grp), +}; + +static const char * const led_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", + "gpio4", + "gpio5", + "gpio6", + "gpio7", + "gpio8", + "gpio9", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gpio15", + "gpio16", + "gpio17", + "gpio18", + "gpio19", + "gpio20", + "gpio21", + "gpio22", + "gpio23", +}; + +static const char * const usb_device_led_groups[] = { + "gpio0", +}; + +static const char * const sys_irq_groups[] = { + "gpio1", +}; + +static const char * const serial_led_clk_groups[] = { + "gpio2", +}; + +static const char * const serial_led_data_groups[] = { + "gpio3", +}; + +static const char * const robosw_led_data_groups[] = { + "gpio4", +}; + +static const char * const robosw_led_clk_groups[] = { + "gpio5", +}; + +static const char * const robosw_led0_groups[] = { + "gpio6", +}; + +static const char * const robosw_led1_groups[] = { + "gpio7", +}; + +static const char * const inet_led_groups[] = { + "gpio8", +}; + +static const char * const spi_cs2_groups[] = { + "gpio9", +}; + +static const char * const spi_cs3_groups[] = { + "gpio10", +}; + +static const char * const ntr_pulse_groups[] = { + "gpio11", +}; + +static const char * const uart1_scts_groups[] = { + "gpio12", +}; + +static const char * const uart1_srts_groups[] = { + "gpio13", +}; + +static const char * const uart1_sdin_groups[] = { + "gpio14", +}; + +static const char * const uart1_sdout_groups[] = { + "gpio15", +}; + +static const char * const adsl_spi_miso_groups[] = { + "gpio16", +}; + +static const char * const adsl_spi_mosi_groups[] = { + "gpio17", +}; + +static const char * const adsl_spi_clk_groups[] = { + "gpio18", +}; + +static const char * const adsl_spi_cs_groups[] = { + "gpio19", +}; + +static const char * const ephy0_led_groups[] = { + "gpio20", +}; + +static const char * const ephy1_led_groups[] = { + "gpio21", +}; + +static const char * const ephy2_led_groups[] = { + "gpio22", +}; + +static const char * const ephy3_led_groups[] = { + "gpio23", +}; + +static const char * const ext_irq0_groups[] = { + "gpio24", +}; + +static const char * const ext_irq1_groups[] = { + "gpio25", +}; + +static const char * const ext_irq2_groups[] = { + "gpio26", +}; + +static const char * const ext_irq3_groups[] = { + "gpio27", +}; + +static const char * const wifi_groups[] = { + "gpio32", + "gpio33", + "gpio34", + "gpio35", + "gpio36", + "gpio37", + "gpio38", + "gpio39", + "gpio40", + "gpio41", + "gpio42", + "gpio43", + "gpio44", + "gpio45", + "gpio46", + "gpio47", +}; + +static const char * const nand_groups[] = { + "nand_grp", +}; + +#define BCM6362_LED_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM6362_LEDCTRL, \ + } + +#define BCM6362_MODE_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM6362_MODE, \ + } + +#define BCM6362_CTRL_FUN(n) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM6362_CTRL, \ + } + +#define BCM6362_BASEMODE_FUN(n, mask) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .reg = BCM6362_BASEMODE, \ + .basemode_mask = (mask), \ + } + +static const struct bcm6362_function bcm6362_funcs[] = { + BCM6362_LED_FUN(led), + BCM6362_MODE_FUN(usb_device_led), + BCM6362_MODE_FUN(sys_irq), + BCM6362_MODE_FUN(serial_led_clk), + BCM6362_MODE_FUN(serial_led_data), + BCM6362_MODE_FUN(robosw_led_data), + BCM6362_MODE_FUN(robosw_led_clk), + BCM6362_MODE_FUN(robosw_led0), + BCM6362_MODE_FUN(robosw_led1), + BCM6362_MODE_FUN(inet_led), + BCM6362_MODE_FUN(spi_cs2), + BCM6362_MODE_FUN(spi_cs3), + BCM6362_MODE_FUN(ntr_pulse), + BCM6362_MODE_FUN(uart1_scts), + BCM6362_MODE_FUN(uart1_srts), + BCM6362_MODE_FUN(uart1_sdin), + BCM6362_MODE_FUN(uart1_sdout), + BCM6362_MODE_FUN(adsl_spi_miso), + BCM6362_MODE_FUN(adsl_spi_mosi), + BCM6362_MODE_FUN(adsl_spi_clk), + BCM6362_MODE_FUN(adsl_spi_cs), + BCM6362_MODE_FUN(ephy0_led), + BCM6362_MODE_FUN(ephy1_led), + BCM6362_MODE_FUN(ephy2_led), + BCM6362_MODE_FUN(ephy3_led), + BCM6362_MODE_FUN(ext_irq0), + BCM6362_MODE_FUN(ext_irq1), + BCM6362_MODE_FUN(ext_irq2), + BCM6362_MODE_FUN(ext_irq3), + BCM6362_CTRL_FUN(wifi), + BCM6362_BASEMODE_FUN(nand, BASEMODE_NAND), +}; + +static int bcm6362_pinctrl_get_group_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6362_groups); +} + +static const char *bcm6362_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return bcm6362_groups[group].name; +} + +static int bcm6362_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, + unsigned *num_pins) +{ + *pins = bcm6362_groups[group].pins; + *num_pins = bcm6362_groups[group].num_pins; + + return 0; +} + +static int bcm6362_pinctrl_get_func_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6362_funcs); +} + +static const char *bcm6362_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return bcm6362_funcs[selector].name; +} + +static int bcm6362_pinctrl_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + *groups = bcm6362_funcs[selector].groups; + *num_groups = bcm6362_funcs[selector].num_groups; + + return 0; +} + +static void bcm6362_set_gpio(struct bcm63xx_pinctrl *pc, unsigned pin) +{ + const struct pinctrl_pin_desc *desc = &bcm6362_pins[pin]; + unsigned int mask = bcm63xx_bank_pin(pin); + + if (desc->drv_data) + regmap_update_bits(pc->regs, BCM6362_BASEMODE_REG, + (uint32_t) desc->drv_data, 0); + + if (pin < BCM63XX_BANK_GPIOS) { + /* base mode 0 => gpio 1 => mux function */ + regmap_update_bits(pc->regs, BCM6362_MODE_REG, mask, 0); + + /* pins 0-23 might be muxed to led */ + if (pin < BCM6362_NUM_LEDS) + regmap_update_bits(pc->regs, BCM6362_LED_REG, mask, 0); + } else { + /* ctrl reg 0 => wifi function 1 => gpio */ + regmap_update_bits(pc->regs, BCM6362_CTRL_REG, mask, mask); + } +} + +static int bcm6362_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + const struct bcm6362_pingroup *pg = &bcm6362_groups[group]; + const struct bcm6362_function *f = &bcm6362_funcs[selector]; + unsigned i; + unsigned int reg; + unsigned int val, mask; + + for (i = 0; i < pg->num_pins; i++) + bcm6362_set_gpio(pc, pg->pins[i]); + + switch (f->reg) { + case BCM6362_LEDCTRL: + reg = BCM6362_LED_REG; + mask = BIT(pg->pins[0]); + val = BIT(pg->pins[0]); + break; + case BCM6362_MODE: + reg = BCM6362_MODE_REG; + mask = BIT(pg->pins[0]); + val = BIT(pg->pins[0]); + break; + case BCM6362_CTRL: + reg = BCM6362_CTRL_REG; + mask = BIT(pg->pins[0]); + val = 0; + break; + case BCM6362_BASEMODE: + reg = BCM6362_BASEMODE_REG; + mask = f->basemode_mask; + val = f->basemode_mask; + break; + default: + WARN_ON(1); + return -EINVAL; + } + + regmap_update_bits(pc->regs, reg, mask, val); + + return 0; +} + +static int bcm6362_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + + /* disable all functions using this pin */ + bcm6362_set_gpio(pc, offset); + + return 0; +} + +static struct pinctrl_ops bcm6362_pctl_ops = { + .dt_free_map = pinctrl_utils_free_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .get_group_name = bcm6362_pinctrl_get_group_name, + .get_group_pins = bcm6362_pinctrl_get_group_pins, + .get_groups_count = bcm6362_pinctrl_get_group_count, +}; + +static struct pinmux_ops bcm6362_pmx_ops = { + .get_function_groups = bcm6362_pinctrl_get_groups, + .get_function_name = bcm6362_pinctrl_get_func_name, + .get_functions_count = bcm6362_pinctrl_get_func_count, + .gpio_request_enable = bcm6362_gpio_request_enable, + .set_mux = bcm6362_pinctrl_set_mux, + .strict = true, +}; + +static const struct bcm63xx_pinctrl_soc bcm6362_soc = { + .ngpios = BCM6362_NUM_GPIOS, + .npins = ARRAY_SIZE(bcm6362_pins), + .pctl_ops = &bcm6362_pctl_ops, + .pins = bcm6362_pins, + .pmx_ops = &bcm6362_pmx_ops, +}; + +static int bcm6362_pinctrl_probe(struct platform_device *pdev) +{ + return bcm63xx_pinctrl_probe(pdev, &bcm6362_soc, NULL); +} + +static const struct of_device_id bcm6362_pinctrl_match[] = { + { .compatible = "brcm,bcm6362-pinctrl", }, + { /* sentinel */ } +}; + +static struct platform_driver bcm6362_pinctrl_driver = { + .probe = bcm6362_pinctrl_probe, + .driver = { + .name = "bcm6362-pinctrl", + .of_match_table = bcm6362_pinctrl_match, + }, +}; + +builtin_platform_driver(bcm6362_pinctrl_driver); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6368.c b/drivers/pinctrl/bcm/pinctrl-bcm6368.c new file mode 100644 index 000000000000..838095f9e890 --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm6368.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for BCM6368 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 BCM6368_NUM_GPIOS 38 + +#define BCM6368_MODE_REG 0x18 +#define BCM6368_BASEMODE_REG 0x38 +#define BCM6368_BASEMODE_MASK 0x7 +#define BCM6368_BASEMODE_GPIO 0x0 +#define BCM6368_BASEMODE_UART1 0x1 + +struct bcm6368_pingroup { + const char *name; + const unsigned * const pins; + const unsigned num_pins; +}; + +struct bcm6368_function { + const char *name; + const char * const *groups; + const unsigned num_groups; + + unsigned dir_out:16; + unsigned basemode:3; +}; + +struct bcm6368_priv { + struct regmap_field *overlays; +}; + +#define BCM6368_BASEMODE_PIN(a, b) \ + { \ + .number = a, \ + .name = b, \ + .drv_data = (void *)true \ + } + +static const struct pinctrl_pin_desc bcm6368_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + PINCTRL_PIN(8, "gpio8"), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + PINCTRL_PIN(12, "gpio12"), + PINCTRL_PIN(13, "gpio13"), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), + PINCTRL_PIN(16, "gpio16"), + PINCTRL_PIN(17, "gpio17"), + PINCTRL_PIN(18, "gpio18"), + PINCTRL_PIN(19, "gpio19"), + PINCTRL_PIN(20, "gpio20"), + PINCTRL_PIN(21, "gpio21"), + PINCTRL_PIN(22, "gpio22"), + PINCTRL_PIN(23, "gpio23"), + PINCTRL_PIN(24, "gpio24"), + PINCTRL_PIN(25, "gpio25"), + PINCTRL_PIN(26, "gpio26"), + PINCTRL_PIN(27, "gpio27"), + PINCTRL_PIN(28, "gpio28"), + PINCTRL_PIN(29, "gpio29"), + BCM6368_BASEMODE_PIN(30, "gpio30"), + BCM6368_BASEMODE_PIN(31, "gpio31"), + BCM6368_BASEMODE_PIN(32, "gpio32"), + BCM6368_BASEMODE_PIN(33, "gpio33"), + PINCTRL_PIN(34, "gpio34"), + PINCTRL_PIN(35, "gpio35"), + PINCTRL_PIN(36, "gpio36"), + PINCTRL_PIN(37, "gpio37"), +}; + +static unsigned gpio0_pins[] = { 0 }; +static unsigned gpio1_pins[] = { 1 }; +static unsigned gpio2_pins[] = { 2 }; +static unsigned gpio3_pins[] = { 3 }; +static unsigned gpio4_pins[] = { 4 }; +static unsigned gpio5_pins[] = { 5 }; +static unsigned gpio6_pins[] = { 6 }; +static unsigned gpio7_pins[] = { 7 }; +static unsigned gpio8_pins[] = { 8 }; +static unsigned gpio9_pins[] = { 9 }; +static unsigned gpio10_pins[] = { 10 }; +static unsigned gpio11_pins[] = { 11 }; +static unsigned gpio12_pins[] = { 12 }; +static unsigned gpio13_pins[] = { 13 }; +static unsigned gpio14_pins[] = { 14 }; +static unsigned gpio15_pins[] = { 15 }; +static unsigned gpio16_pins[] = { 16 }; +static unsigned gpio17_pins[] = { 17 }; +static unsigned gpio18_pins[] = { 18 }; +static unsigned gpio19_pins[] = { 19 }; +static unsigned gpio20_pins[] = { 20 }; +static unsigned gpio21_pins[] = { 21 }; +static unsigned gpio22_pins[] = { 22 }; +static unsigned gpio23_pins[] = { 23 }; +static unsigned gpio24_pins[] = { 24 }; +static unsigned gpio25_pins[] = { 25 }; +static unsigned gpio26_pins[] = { 26 }; +static unsigned gpio27_pins[] = { 27 }; +static unsigned gpio28_pins[] = { 28 }; +static unsigned gpio29_pins[] = { 29 }; +static unsigned gpio30_pins[] = { 30 }; +static unsigned gpio31_pins[] = { 31 }; +static unsigned uart1_grp_pins[] = { 30, 31, 32, 33 }; + +#define BCM6368_GROUP(n) \ + { \ + .name = #n, \ + .pins = n##_pins, \ + .num_pins = ARRAY_SIZE(n##_pins), \ + } + +static struct bcm6368_pingroup bcm6368_groups[] = { + BCM6368_GROUP(gpio0), + BCM6368_GROUP(gpio1), + BCM6368_GROUP(gpio2), + BCM6368_GROUP(gpio3), + BCM6368_GROUP(gpio4), + BCM6368_GROUP(gpio5), + BCM6368_GROUP(gpio6), + BCM6368_GROUP(gpio7), + BCM6368_GROUP(gpio8), + BCM6368_GROUP(gpio9), + BCM6368_GROUP(gpio10), + BCM6368_GROUP(gpio11), + BCM6368_GROUP(gpio12), + BCM6368_GROUP(gpio13), + BCM6368_GROUP(gpio14), + BCM6368_GROUP(gpio15), + BCM6368_GROUP(gpio16), + BCM6368_GROUP(gpio17), + BCM6368_GROUP(gpio18), + BCM6368_GROUP(gpio19), + BCM6368_GROUP(gpio20), + BCM6368_GROUP(gpio21), + BCM6368_GROUP(gpio22), + BCM6368_GROUP(gpio23), + BCM6368_GROUP(gpio24), + BCM6368_GROUP(gpio25), + BCM6368_GROUP(gpio26), + BCM6368_GROUP(gpio27), + BCM6368_GROUP(gpio28), + BCM6368_GROUP(gpio29), + BCM6368_GROUP(gpio30), + BCM6368_GROUP(gpio31), + BCM6368_GROUP(uart1_grp), +}; + +static const char * const analog_afe_0_groups[] = { + "gpio0", +}; + +static const char * const analog_afe_1_groups[] = { + "gpio1", +}; + +static const char * const sys_irq_groups[] = { + "gpio2", +}; + +static const char * const serial_led_data_groups[] = { + "gpio3", +}; + +static const char * const serial_led_clk_groups[] = { + "gpio4", +}; + +static const char * const inet_led_groups[] = { + "gpio5", +}; + +static const char * const ephy0_led_groups[] = { + "gpio6", +}; + +static const char * const ephy1_led_groups[] = { + "gpio7", +}; + +static const char * const ephy2_led_groups[] = { + "gpio8", +}; + +static const char * const ephy3_led_groups[] = { + "gpio9", +}; + +static const char * const robosw_led_data_groups[] = { + "gpio10", +}; + +static const char * const robosw_led_clk_groups[] = { + "gpio11", +}; + +static const char * const robosw_led0_groups[] = { + "gpio12", +}; + +static const char * const robosw_led1_groups[] = { + "gpio13", +}; + +static const char * const usb_device_led_groups[] = { + "gpio14", +}; + +static const char * const pci_req1_groups[] = { + "gpio16", +}; + +static const char * const pci_gnt1_groups[] = { + "gpio17", +}; + +static const char * const pci_intb_groups[] = { + "gpio18", +}; + +static const char * const pci_req0_groups[] = { + "gpio19", +}; + +static const char * const pci_gnt0_groups[] = { + "gpio20", +}; + +static const char * const pcmcia_cd1_groups[] = { + "gpio22", +}; + +static const char * const pcmcia_cd2_groups[] = { + "gpio23", +}; + +static const char * const pcmcia_vs1_groups[] = { + "gpio24", +}; + +static const char * const pcmcia_vs2_groups[] = { + "gpio25", +}; + +static const char * const ebi_cs2_groups[] = { + "gpio26", +}; + +static const char * const ebi_cs3_groups[] = { + "gpio27", +}; + +static const char * const spi_cs2_groups[] = { + "gpio28", +}; + +static const char * const spi_cs3_groups[] = { + "gpio29", +}; + +static const char * const spi_cs4_groups[] = { + "gpio30", +}; + +static const char * const spi_cs5_groups[] = { + "gpio31", +}; + +static const char * const uart1_groups[] = { + "uart1_grp", +}; + +#define BCM6368_FUN(n, out) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .dir_out = out, \ + } + +#define BCM6368_BASEMODE_FUN(n, val, out) \ + { \ + .name = #n, \ + .groups = n##_groups, \ + .num_groups = ARRAY_SIZE(n##_groups), \ + .basemode = BCM6368_BASEMODE_##val, \ + .dir_out = out, \ + } + +static const struct bcm6368_function bcm6368_funcs[] = { + BCM6368_FUN(analog_afe_0, 1), + BCM6368_FUN(analog_afe_1, 1), + BCM6368_FUN(sys_irq, 1), + BCM6368_FUN(serial_led_data, 1), + BCM6368_FUN(serial_led_clk, 1), + BCM6368_FUN(inet_led, 1), + BCM6368_FUN(ephy0_led, 1), + BCM6368_FUN(ephy1_led, 1), + BCM6368_FUN(ephy2_led, 1), + BCM6368_FUN(ephy3_led, 1), + BCM6368_FUN(robosw_led_data, 1), + BCM6368_FUN(robosw_led_clk, 1), + BCM6368_FUN(robosw_led0, 1), + BCM6368_FUN(robosw_led1, 1), + BCM6368_FUN(usb_device_led, 1), + BCM6368_FUN(pci_req1, 0), + BCM6368_FUN(pci_gnt1, 0), + BCM6368_FUN(pci_intb, 0), + BCM6368_FUN(pci_req0, 0), + BCM6368_FUN(pci_gnt0, 0), + BCM6368_FUN(pcmcia_cd1, 0), + BCM6368_FUN(pcmcia_cd2, 0), + BCM6368_FUN(pcmcia_vs1, 0), + BCM6368_FUN(pcmcia_vs2, 0), + BCM6368_FUN(ebi_cs2, 1), + BCM6368_FUN(ebi_cs3, 1), + BCM6368_FUN(spi_cs2, 1), + BCM6368_FUN(spi_cs3, 1), + BCM6368_FUN(spi_cs4, 1), + BCM6368_FUN(spi_cs5, 1), + BCM6368_BASEMODE_FUN(uart1, UART1, 0x6), +}; + +static int bcm6368_pinctrl_get_group_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6368_groups); +} + +static const char *bcm6368_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return bcm6368_groups[group].name; +} + +static int bcm6368_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, + unsigned *num_pins) +{ + *pins = bcm6368_groups[group].pins; + *num_pins = bcm6368_groups[group].num_pins; + + return 0; +} + +static int bcm6368_pinctrl_get_func_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(bcm6368_funcs); +} + +static const char *bcm6368_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return bcm6368_funcs[selector].name; +} + +static int bcm6368_pinctrl_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + *groups = bcm6368_funcs[selector].groups; + *num_groups = bcm6368_funcs[selector].num_groups; + + return 0; +} + +static int bcm6368_pinctrl_set_mux(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + struct bcm6368_priv *priv = pc->driver_data; + const struct bcm6368_pingroup *pg = &bcm6368_groups[group]; + const struct bcm6368_function *fun = &bcm6368_funcs[selector]; + int i, pin; + + if (fun->basemode) { + unsigned int mask = 0; + + for (i = 0; i < pg->num_pins; i++) { + pin = pg->pins[i]; + if (pin < BCM63XX_BANK_GPIOS) + mask |= BIT(pin); + } + + regmap_update_bits(pc->regs, BCM6368_MODE_REG, mask, 0); + regmap_field_write(priv->overlays, fun->basemode); + } else { + pin = pg->pins[0]; + + if (bcm6368_pins[pin].drv_data) + regmap_field_write(priv->overlays, + BCM6368_BASEMODE_GPIO); + + regmap_update_bits(pc->regs, BCM6368_MODE_REG, BIT(pin), + BIT(pin)); + } + + for (pin = 0; pin < pg->num_pins; pin++) { + struct pinctrl_gpio_range *range; + int hw_gpio = bcm6368_pins[pin].number; + + range = pinctrl_find_gpio_range_from_pin(pctldev, hw_gpio); + if (range) { + struct gpio_chip *gc = range->gc; + + if (fun->dir_out & BIT(pin)) + gc->direction_output(gc, hw_gpio, 0); + else + gc->direction_input(gc, hw_gpio); + } + } + + return 0; +} + +static int bcm6368_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); + struct bcm6368_priv *priv = pc->driver_data; + + if (offset >= BCM63XX_BANK_GPIOS && !bcm6368_pins[offset].drv_data) + return 0; + + /* disable all functions using this pin */ + if (offset < BCM63XX_BANK_GPIOS) + regmap_update_bits(pc->regs, BCM6368_MODE_REG, BIT(offset), 0); + + if (bcm6368_pins[offset].drv_data) + regmap_field_write(priv->overlays, BCM6368_BASEMODE_GPIO); + + return 0; +} + +static struct pinctrl_ops bcm6368_pctl_ops = { + .dt_free_map = pinctrl_utils_free_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .get_group_name = bcm6368_pinctrl_get_group_name, + .get_group_pins = bcm6368_pinctrl_get_group_pins, + .get_groups_count = bcm6368_pinctrl_get_group_count, +}; + +static struct pinmux_ops bcm6368_pmx_ops = { + .get_function_groups = bcm6368_pinctrl_get_groups, + .get_function_name = bcm6368_pinctrl_get_func_name, + .get_functions_count = bcm6368_pinctrl_get_func_count, + .gpio_request_enable = bcm6368_gpio_request_enable, + .set_mux = bcm6368_pinctrl_set_mux, + .strict = true, +}; + +static const struct bcm63xx_pinctrl_soc bcm6368_soc = { + .ngpios = BCM6368_NUM_GPIOS, + .npins = ARRAY_SIZE(bcm6368_pins), + .pctl_ops = &bcm6368_pctl_ops, + .pins = bcm6368_pins, + .pmx_ops = &bcm6368_pmx_ops, +}; + +static int bcm6368_pinctrl_probe(struct platform_device *pdev) +{ + struct reg_field overlays = REG_FIELD(BCM6368_BASEMODE_REG, 0, 15); + struct device *dev = &pdev->dev; + struct bcm63xx_pinctrl *pc; + struct bcm6368_priv *priv; + int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + err = bcm63xx_pinctrl_probe(pdev, &bcm6368_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 bcm6368_pinctrl_match[] = { + { .compatible = "brcm,bcm6368-pinctrl", }, + { /* sentinel */ } +}; + +static struct platform_driver bcm6368_pinctrl_driver = { + .probe = bcm6368_pinctrl_probe, + .driver = { + .name = "bcm6368-pinctrl", + .of_match_table = bcm6368_pinctrl_match, + }, +}; + +builtin_platform_driver(bcm6368_pinctrl_driver); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c new file mode 100644 index 000000000000..e1285fe2fbc0 --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for BCM63xx 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/gpio/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "pinctrl-bcm63xx.h" + +#define BCM63XX_BANK_SIZE 4 + +#define BCM63XX_DIROUT_REG 0x04 +#define BCM63XX_DATA_REG 0x0c + +static int bcm63xx_reg_mask_xlate(struct gpio_regmap *gpio, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask) +{ + unsigned int line = offset % BCM63XX_BANK_GPIOS; + unsigned int stride = offset / BCM63XX_BANK_GPIOS; + + *reg = base - stride * BCM63XX_BANK_SIZE; + *mask = BIT(line); + + return 0; +} + +static const struct of_device_id bcm63xx_gpio_of_match[] = { + { .compatible = "brcm,bcm6318-gpio", }, + { .compatible = "brcm,bcm6328-gpio", }, + { .compatible = "brcm,bcm6358-gpio", }, + { .compatible = "brcm,bcm6362-gpio", }, + { .compatible = "brcm,bcm6368-gpio", }, + { .compatible = "brcm,bcm63268-gpio", }, + { /* sentinel */ } +}; + +static int bcm63xx_gpio_probe(struct device *dev, struct device_node *node, + const struct bcm63xx_pinctrl_soc *soc, + struct bcm63xx_pinctrl *pc) +{ + struct gpio_regmap_config grc = {0}; + + grc.parent = dev; + grc.fwnode = &node->fwnode; + grc.ngpio = soc->ngpios; + grc.ngpio_per_reg = BCM63XX_BANK_GPIOS; + grc.regmap = pc->regs; + grc.reg_dat_base = BCM63XX_DATA_REG; + grc.reg_dir_out_base = BCM63XX_DIROUT_REG; + grc.reg_set_base = BCM63XX_DATA_REG; + grc.reg_mask_xlate = bcm63xx_reg_mask_xlate; + + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &grc)); +} + +int bcm63xx_pinctrl_probe(struct platform_device *pdev, + const struct bcm63xx_pinctrl_soc *soc, + void *driver_data) +{ + struct device *dev = &pdev->dev; + struct bcm63xx_pinctrl *pc; + struct device_node *node; + int err; + + pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + platform_set_drvdata(pdev, pc); + + pc->dev = dev; + pc->driver_data = driver_data; + + pc->regs = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(pc->regs)) + return PTR_ERR(pc->regs); + + pc->pctl_desc.name = dev_name(dev); + pc->pctl_desc.pins = soc->pins; + pc->pctl_desc.npins = soc->npins; + pc->pctl_desc.pctlops = soc->pctl_ops; + pc->pctl_desc.pmxops = soc->pmx_ops; + pc->pctl_desc.owner = THIS_MODULE; + + pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); + if (IS_ERR(pc->pctl_dev)) + return PTR_ERR(pc->pctl_dev); + + for_each_child_of_node(dev->parent->of_node, node) { + if (of_match_node(bcm63xx_gpio_of_match, node)) { + err = bcm63xx_gpio_probe(dev, node, soc, pc); + if (err) { + dev_err(dev, "could not add GPIO chip\n"); + of_node_put(node); + return err; + } + } + } + + return 0; +} diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.h b/drivers/pinctrl/bcm/pinctrl-bcm63xx.h new file mode 100644 index 000000000000..3bdb50021f1b --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com> + * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com> + */ + +#ifndef __PINCTRL_BCM63XX_H__ +#define __PINCTRL_BCM63XX_H__ + +#include <linux/pinctrl/pinctrl.h> + +#define BCM63XX_BANK_GPIOS 32 + +struct bcm63xx_pinctrl_soc { + struct pinctrl_ops *pctl_ops; + struct pinmux_ops *pmx_ops; + + const struct pinctrl_pin_desc *pins; + unsigned npins; + + unsigned int ngpios; +}; + +struct bcm63xx_pinctrl { + struct device *dev; + struct regmap *regs; + + struct pinctrl_desc pctl_desc; + struct pinctrl_dev *pctl_dev; + + void *driver_data; +}; + +static inline unsigned int bcm63xx_bank_pin(unsigned int pin) +{ + return pin % BCM63XX_BANK_GPIOS; +} + +int bcm63xx_pinctrl_probe(struct platform_device *pdev, + const struct bcm63xx_pinctrl_soc *soc, + void *driver_data); + +#endif /* __PINCTRL_BCM63XX_H__ */ |