aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/bcm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/bcm')
-rw-r--r--drivers/pinctrl/bcm/Kconfig82
-rw-r--r--drivers/pinctrl/bcm/Makefile8
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm281xx.c22
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c297
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm4908.c563
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6318.c485
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm63268.c630
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6328.c391
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6358.c365
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6362.c604
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6368.c510
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm63xx.c109
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm63xx.h45
-rw-r--r--drivers/pinctrl/bcm/pinctrl-cygnus-mux.c14
-rw-r--r--drivers/pinctrl/bcm/pinctrl-iproc-gpio.c15
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns.c192
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns2-mux.c12
-rw-r--r--drivers/pinctrl/bcm/pinctrl-nsp-gpio.c36
-rw-r--r--drivers/pinctrl/bcm/pinctrl-nsp-mux.c10
19 files changed, 4119 insertions, 271 deletions
diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig
index dcf7df797af7..35b51ce4298e 100644
--- a/drivers/pinctrl/bcm/Kconfig
+++ b/drivers/pinctrl/bcm/Kconfig
@@ -18,16 +18,94 @@ config PINCTRL_BCM281XX
framework. GPIO is provided by a separate GPIO driver.
config PINCTRL_BCM2835
- bool "Broadcom BCM2835 GPIO (with PINCONF) driver"
+ tristate "Broadcom BCM2835 GPIO (with PINCONF) driver"
depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
+ select GPIOLIB
select GPIOLIB_IRQCHIP
default ARCH_BCM2835 || ARCH_BRCMSTB
help
Say Y here to enable the Broadcom BCM2835 GPIO driver.
+config PINCTRL_BCM4908
+ tristate "Broadcom BCM4908 pinmux driver"
+ depends on OF && (ARCH_BCMBCA || COMPILE_TEST)
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ default ARCH_BCMBCA
+ help
+ Driver for BCM4908 family SoCs with integrated pin controller.
+
+ If compiled as module it will be called pinctrl-bcm4908.
+
+config PINCTRL_BCM63XX
+ bool
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select GPIOLIB
+ select REGMAP
+ select GPIO_REGMAP
+
+config PINCTRL_BCM6318
+ bool "Broadcom BCM6318 GPIO driver"
+ depends on (BMIPS_GENERIC || COMPILE_TEST)
+ depends on OF
+ 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)
+ depends on OF
+ 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)
+ depends on OF
+ 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)
+ depends on OF
+ 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)
+ depends on OF
+ 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)
+ depends on OF
+ 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)
@@ -83,6 +161,8 @@ config PINCTRL_NS
depends on OF && (ARCH_BCM_5301X || COMPILE_TEST)
select PINMUX
select GENERIC_PINCONF
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
default ARCH_BCM_5301X
help
Say yes here to enable the Broadcom NS SoC pins driver.
diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile
index 79d5e49fdd9a..82b868ec1471 100644
--- a/drivers/pinctrl/bcm/Makefile
+++ b/drivers/pinctrl/bcm/Makefile
@@ -3,6 +3,14 @@
obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
+obj-$(CONFIG_PINCTRL_BCM4908) += pinctrl-bcm4908.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-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
index f690fc5cd688..fd52a83387ef 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c
@@ -1,15 +1,5 @@
-/*
- * Copyright (C) 2013-2017 Broadcom
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2013-2017 Broadcom
#include <linux/err.h>
#include <linux/io.h>
@@ -59,7 +49,7 @@
#define BCM281XX_HDMI_PIN_REG_MODE_MASK 0x0010
#define BCM281XX_HDMI_PIN_REG_MODE_SHIFT 4
-/**
+/*
* bcm281xx_pin_type - types of pin register
*/
enum bcm281xx_pin_type {
@@ -73,7 +63,7 @@ static enum bcm281xx_pin_type std_pin = BCM281XX_PIN_TYPE_STD;
static enum bcm281xx_pin_type i2c_pin = BCM281XX_PIN_TYPE_I2C;
static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI;
-/**
+/*
* bcm281xx_pin_function- define pin function
*/
struct bcm281xx_pin_function {
@@ -82,7 +72,7 @@ struct bcm281xx_pin_function {
const unsigned ngroups;
};
-/**
+/*
* bcm281xx_pinctrl_data - Broadcom-specific pinctrl data
* @reg_base - base of pinctrl registers
*/
@@ -1406,7 +1396,7 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev)
pdata->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pdata->reg_base)) {
dev_err(&pdev->dev, "Failed to ioremap MEM resource\n");
- return -ENODEV;
+ return PTR_ERR(pdata->reg_base);
}
/* Initialize the dynamic part of pinctrl_desc */
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 0de1a3a96984..7857e612a100 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -19,6 +19,8 @@
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -37,12 +39,10 @@
#define MODULE_NAME "pinctrl-bcm2835"
#define BCM2835_NUM_GPIOS 54
+#define BCM2711_NUM_GPIOS 58
#define BCM2835_NUM_BANKS 2
#define BCM2835_NUM_IRQS 3
-#define BCM2835_PIN_BITMAP_SZ \
- DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8)
-
/* GPIO register offsets */
#define GPFSEL0 0x0 /* Function Select */
#define GPSET0 0x1c /* Pin Output Set */
@@ -78,13 +78,15 @@
struct bcm2835_pinctrl {
struct device *dev;
void __iomem *base;
+ int *wake_irq;
/* note: locking assumes each bank will have its own unsigned long */
unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
- unsigned int irq_type[BCM2835_NUM_GPIOS];
+ unsigned int irq_type[BCM2711_NUM_GPIOS];
struct pinctrl_dev *pctl_dev;
struct gpio_chip gpio_chip;
+ struct pinctrl_desc pctl_desc;
struct pinctrl_gpio_range gpio_range;
raw_spinlock_t irq_lock[BCM2835_NUM_BANKS];
@@ -147,6 +149,10 @@ static struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
BCM2835_GPIO_PIN(51),
BCM2835_GPIO_PIN(52),
BCM2835_GPIO_PIN(53),
+ BCM2835_GPIO_PIN(54),
+ BCM2835_GPIO_PIN(55),
+ BCM2835_GPIO_PIN(56),
+ BCM2835_GPIO_PIN(57),
};
/* one pin per group */
@@ -205,6 +211,10 @@ static const char * const bcm2835_gpio_groups[] = {
"gpio51",
"gpio52",
"gpio53",
+ "gpio54",
+ "gpio55",
+ "gpio56",
+ "gpio57",
};
enum bcm2835_fsel {
@@ -303,7 +313,10 @@ static inline void bcm2835_pinctrl_fsel_set(
static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- return pinctrl_gpio_direction_input(chip->base + offset);
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
+
+ bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
+ return 0;
}
static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -322,7 +335,10 @@ static int bcm2835_gpio_get_direction(struct gpio_chip *chip, unsigned int offse
if (fsel > BCM2835_FSEL_GPIO_OUT)
return -EINVAL;
- return (fsel == BCM2835_FSEL_GPIO_IN);
+ if (fsel == BCM2835_FSEL_GPIO_IN)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
}
static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -335,8 +351,27 @@ static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- bcm2835_gpio_set(chip, offset, value);
- return pinctrl_gpio_direction_output(chip->base + offset);
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
+
+ bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
+ bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_OUT);
+ return 0;
+}
+
+static int bcm2835_of_gpio_ranges_fallback(struct gpio_chip *gc,
+ struct device_node *np)
+{
+ struct pinctrl_dev *pctldev = of_pinctrl_get(np);
+
+ of_node_put(np);
+
+ if (!pctldev)
+ return 0;
+
+ gpiochip_add_pin_range(gc, pinctrl_dev_get_devname(pctldev), 0, 0,
+ gc->ngpio);
+
+ return 0;
}
static const struct gpio_chip bcm2835_gpio_chip = {
@@ -353,6 +388,24 @@ static const struct gpio_chip bcm2835_gpio_chip = {
.base = -1,
.ngpio = BCM2835_NUM_GPIOS,
.can_sleep = false,
+ .of_gpio_ranges_fallback = bcm2835_of_gpio_ranges_fallback,
+};
+
+static const struct gpio_chip bcm2711_gpio_chip = {
+ .label = "pinctrl-bcm2711",
+ .owner = THIS_MODULE,
+ .request = gpiochip_generic_request,
+ .free = gpiochip_generic_free,
+ .direction_input = bcm2835_gpio_direction_input,
+ .direction_output = bcm2835_gpio_direction_output,
+ .get_direction = bcm2835_gpio_get_direction,
+ .get = bcm2835_gpio_get,
+ .set = bcm2835_gpio_set,
+ .set_config = gpiochip_generic_config,
+ .base = -1,
+ .ngpio = BCM2711_NUM_GPIOS,
+ .can_sleep = false,
+ .of_gpio_ranges_fallback = bcm2835_of_gpio_ranges_fallback,
};
static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
@@ -367,8 +420,8 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
events &= pc->enabled_irq_map[bank];
for_each_set_bit(offset, &events, 32) {
gpio = (32 * bank) + offset;
- generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain,
- gpio));
+ generic_handle_domain_irq(pc->gpio_chip.irq.domain,
+ gpio);
}
}
@@ -378,7 +431,7 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
struct irq_chip *host_chip = irq_desc_get_chip(desc);
int irq = irq_desc_get_irq(desc);
- int group;
+ int group = 0;
int i;
for (i = 0; i < BCM2835_NUM_IRQS; i++) {
@@ -388,8 +441,7 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
}
}
/* This should not happen, every IRQ has a bank */
- if (i == BCM2835_NUM_IRQS)
- BUG();
+ BUG_ON(i == BCM2835_NUM_IRQS);
chained_irq_enter(host_chip, desc);
@@ -401,7 +453,7 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000);
bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
break;
- case 2: /* IRQ2 covers GPIOs 46-53 */
+ case 2: /* IRQ2 covers GPIOs 46-57 */
bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
break;
}
@@ -409,6 +461,11 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(host_chip, desc);
}
+static irqreturn_t bcm2835_gpio_wake_irq_handler(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
unsigned reg, unsigned offset, bool enable)
{
@@ -450,7 +507,7 @@ static void bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
}
}
-static void bcm2835_gpio_irq_enable(struct irq_data *data)
+static void bcm2835_gpio_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
@@ -459,13 +516,15 @@ static void bcm2835_gpio_irq_enable(struct irq_data *data)
unsigned bank = GPIO_REG_OFFSET(gpio);
unsigned long flags;
+ gpiochip_enable_irq(chip, gpio);
+
raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
set_bit(offset, &pc->enabled_irq_map[bank]);
bcm2835_gpio_irq_config(pc, gpio, true);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
}
-static void bcm2835_gpio_irq_disable(struct irq_data *data)
+static void bcm2835_gpio_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
@@ -480,6 +539,8 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data)
bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
clear_bit(offset, &pc->enabled_irq_map[bank]);
raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
+
+ gpiochip_disable_irq(chip, gpio);
}
static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc,
@@ -608,19 +669,48 @@ static void bcm2835_gpio_irq_ack(struct irq_data *data)
bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
}
-static struct irq_chip bcm2835_gpio_irq_chip = {
+static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
+ unsigned gpio = irqd_to_hwirq(data);
+ unsigned int irqgroup;
+ int ret = -EINVAL;
+
+ if (!pc->wake_irq)
+ return ret;
+
+ if (gpio <= 27)
+ irqgroup = 0;
+ else if (gpio >= 28 && gpio <= 45)
+ irqgroup = 1;
+ else if (gpio >= 46 && gpio <= 57)
+ irqgroup = 2;
+ else
+ return ret;
+
+ if (on)
+ ret = enable_irq_wake(pc->wake_irq[irqgroup]);
+ else
+ ret = disable_irq_wake(pc->wake_irq[irqgroup]);
+
+ return ret;
+}
+
+static const struct irq_chip bcm2835_gpio_irq_chip = {
.name = MODULE_NAME,
- .irq_enable = bcm2835_gpio_irq_enable,
- .irq_disable = bcm2835_gpio_irq_disable,
.irq_set_type = bcm2835_gpio_irq_set_type,
.irq_ack = bcm2835_gpio_irq_ack,
- .irq_mask = bcm2835_gpio_irq_disable,
- .irq_unmask = bcm2835_gpio_irq_enable,
+ .irq_mask = bcm2835_gpio_irq_mask,
+ .irq_unmask = bcm2835_gpio_irq_unmask,
+ .irq_set_wake = bcm2835_gpio_irq_set_wake,
+ .flags = (IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE),
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev)
{
- return ARRAY_SIZE(bcm2835_gpio_groups);
+ return BCM2835_NUM_GPIOS;
}
static const char *bcm2835_pctl_get_group_name(struct pinctrl_dev *pctldev,
@@ -778,7 +868,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
err = of_property_read_u32_index(np, "brcm,pins", i, &pin);
if (err)
goto out;
- if (pin >= ARRAY_SIZE(bcm2835_gpio_pins)) {
+ if (pin >= pc->pctl_desc.npins) {
dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n",
np, pin);
err = -EINVAL;
@@ -854,7 +944,7 @@ static int bcm2835_pmx_get_function_groups(struct pinctrl_dev *pctldev,
{
/* every pin can do every function */
*groups = bcm2835_gpio_groups;
- *num_groups = ARRAY_SIZE(bcm2835_gpio_groups);
+ *num_groups = BCM2835_NUM_GPIOS;
return 0;
}
@@ -1054,29 +1144,66 @@ static const struct pinconf_ops bcm2711_pinconf_ops = {
.pin_config_set = bcm2711_pinconf_set,
};
-static struct pinctrl_desc bcm2835_pinctrl_desc = {
+static const struct pinctrl_desc bcm2835_pinctrl_desc = {
.name = MODULE_NAME,
.pins = bcm2835_gpio_pins,
- .npins = ARRAY_SIZE(bcm2835_gpio_pins),
+ .npins = BCM2835_NUM_GPIOS,
.pctlops = &bcm2835_pctl_ops,
.pmxops = &bcm2835_pmx_ops,
.confops = &bcm2835_pinconf_ops,
.owner = THIS_MODULE,
};
-static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = {
+static const struct pinctrl_desc bcm2711_pinctrl_desc = {
+ .name = "pinctrl-bcm2711",
+ .pins = bcm2835_gpio_pins,
+ .npins = BCM2711_NUM_GPIOS,
+ .pctlops = &bcm2835_pctl_ops,
+ .pmxops = &bcm2835_pmx_ops,
+ .confops = &bcm2711_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static const struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = {
.name = MODULE_NAME,
.npins = BCM2835_NUM_GPIOS,
};
+static const struct pinctrl_gpio_range bcm2711_pinctrl_gpio_range = {
+ .name = "pinctrl-bcm2711",
+ .npins = BCM2711_NUM_GPIOS,
+};
+
+struct bcm_plat_data {
+ const struct gpio_chip *gpio_chip;
+ const struct pinctrl_desc *pctl_desc;
+ const struct pinctrl_gpio_range *gpio_range;
+};
+
+static const struct bcm_plat_data bcm2835_plat_data = {
+ .gpio_chip = &bcm2835_gpio_chip,
+ .pctl_desc = &bcm2835_pinctrl_desc,
+ .gpio_range = &bcm2835_pinctrl_gpio_range,
+};
+
+static const struct bcm_plat_data bcm2711_plat_data = {
+ .gpio_chip = &bcm2711_gpio_chip,
+ .pctl_desc = &bcm2711_pinctrl_desc,
+ .gpio_range = &bcm2711_pinctrl_gpio_range,
+};
+
static const struct of_device_id bcm2835_pinctrl_match[] = {
{
.compatible = "brcm,bcm2835-gpio",
- .data = &bcm2835_pinconf_ops,
+ .data = &bcm2835_plat_data,
},
{
.compatible = "brcm,bcm2711-gpio",
- .data = &bcm2711_pinconf_ops,
+ .data = &bcm2711_plat_data,
+ },
+ {
+ .compatible = "brcm,bcm7211-gpio",
+ .data = &bcm2711_plat_data,
},
{}
};
@@ -1085,14 +1212,16 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ const struct bcm_plat_data *pdata;
struct bcm2835_pinctrl *pc;
struct gpio_irq_chip *girq;
struct resource iomem;
int err, i;
const struct of_device_id *match;
+ int is_7211 = 0;
- BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2835_NUM_GPIOS);
- BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2835_NUM_GPIOS);
+ BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2711_NUM_GPIOS);
+ BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2711_NUM_GPIOS);
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
@@ -1111,9 +1240,15 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
if (IS_ERR(pc->base))
return PTR_ERR(pc->base);
- pc->gpio_chip = bcm2835_gpio_chip;
+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
+ if (!match)
+ return -EINVAL;
+
+ pdata = match->data;
+ is_7211 = of_device_is_compatible(np, "brcm,bcm7211-gpio");
+
+ pc->gpio_chip = *pdata->gpio_chip;
pc->gpio_chip.parent = dev;
- pc->gpio_chip.of_node = np;
for (i = 0; i < BCM2835_NUM_BANKS; i++) {
unsigned long events;
@@ -1135,15 +1270,40 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
raw_spin_lock_init(&pc->irq_lock[i]);
}
+ pc->pctl_desc = *pdata->pctl_desc;
+ pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
+ if (IS_ERR(pc->pctl_dev)) {
+ gpiochip_remove(&pc->gpio_chip);
+ return PTR_ERR(pc->pctl_dev);
+ }
+
+ pc->gpio_range = *pdata->gpio_range;
+ pc->gpio_range.base = pc->gpio_chip.base;
+ pc->gpio_range.gc = &pc->gpio_chip;
+ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
+
girq = &pc->gpio_chip.irq;
- girq->chip = &bcm2835_gpio_irq_chip;
+ gpio_irq_chip_set_chip(girq, &bcm2835_gpio_irq_chip);
girq->parent_handler = bcm2835_gpio_irq_handler;
girq->num_parents = BCM2835_NUM_IRQS;
girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
sizeof(*girq->parents),
GFP_KERNEL);
- if (!girq->parents)
- return -ENOMEM;
+ if (!girq->parents) {
+ err = -ENOMEM;
+ goto out_remove;
+ }
+
+ if (is_7211) {
+ pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
+ sizeof(*pc->wake_irq),
+ GFP_KERNEL);
+ if (!pc->wake_irq) {
+ err = -ENOMEM;
+ goto out_remove;
+ }
+ }
+
/*
* Use the same handler for all groups: this is necessary
* since we use one gpiochip to cover all lines - the
@@ -1151,35 +1311,54 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
* bank that was firing the IRQ and look up the per-group
* and bank data.
*/
- for (i = 0; i < BCM2835_NUM_IRQS; i++)
+ for (i = 0; i < BCM2835_NUM_IRQS; i++) {
+ int len;
+ char *name;
+
girq->parents[i] = irq_of_parse_and_map(np, i);
+ if (!is_7211) {
+ if (!girq->parents[i]) {
+ girq->num_parents = i;
+ break;
+ }
+ continue;
+ }
+ /* Skip over the all banks interrupts */
+ pc->wake_irq[i] = irq_of_parse_and_map(np, i +
+ BCM2835_NUM_IRQS + 1);
+
+ len = strlen(dev_name(pc->dev)) + 16;
+ name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
+ if (!name) {
+ err = -ENOMEM;
+ goto out_remove;
+ }
+
+ snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
+
+ /* These are optional interrupts */
+ err = devm_request_irq(dev, pc->wake_irq[i],
+ bcm2835_gpio_wake_irq_handler,
+ IRQF_SHARED, name, pc);
+ if (err)
+ dev_warn(dev, "unable to request wake IRQ %d\n",
+ pc->wake_irq[i]);
+ }
+
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
err = gpiochip_add_data(&pc->gpio_chip, pc);
if (err) {
dev_err(dev, "could not add GPIO chip\n");
- return err;
+ goto out_remove;
}
- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
- if (match) {
- bcm2835_pinctrl_desc.confops =
- (const struct pinconf_ops *)match->data;
- }
-
- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
- if (IS_ERR(pc->pctl_dev)) {
- gpiochip_remove(&pc->gpio_chip);
- return PTR_ERR(pc->pctl_dev);
- }
-
- pc->gpio_range = bcm2835_pinctrl_gpio_range;
- pc->gpio_range.base = pc->gpio_chip.base;
- pc->gpio_range.gc = &pc->gpio_chip;
- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
-
return 0;
+
+out_remove:
+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
}
static struct platform_driver bcm2835_pinctrl_driver = {
@@ -1190,4 +1369,10 @@ static struct platform_driver bcm2835_pinctrl_driver = {
.suppress_bind_attrs = true,
},
};
-builtin_platform_driver(bcm2835_pinctrl_driver);
+module_platform_driver(bcm2835_pinctrl_driver);
+
+MODULE_AUTHOR("Chris Boot");
+MODULE_AUTHOR("Simon Arlott");
+MODULE_AUTHOR("Stephen Warren");
+MODULE_DESCRIPTION("Broadcom BCM2835/2711 pinctrl and GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm4908.c b/drivers/pinctrl/bcm/pinctrl-bcm4908.c
new file mode 100644
index 000000000000..cdfa165fc033
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm4908.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+
+#include "../core.h"
+#include "../pinmux.h"
+
+#define BCM4908_NUM_PINS 86
+
+#define BCM4908_TEST_PORT_BLOCK_EN_LSB 0x00
+#define BCM4908_TEST_PORT_BLOCK_DATA_MSB 0x04
+#define BCM4908_TEST_PORT_BLOCK_DATA_LSB 0x08
+#define BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT 12
+#define BCM4908_TEST_PORT_COMMAND 0x0c
+#define BCM4908_TEST_PORT_CMD_LOAD_MUX_REG 0x00000021
+
+struct bcm4908_pinctrl {
+ struct device *dev;
+ void __iomem *base;
+ struct mutex mutex;
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_desc pctldesc;
+};
+
+/*
+ * Groups
+ */
+
+struct bcm4908_pinctrl_pin_setup {
+ unsigned int number;
+ unsigned int function;
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_0_pins_a[] = {
+ { 0, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_1_pins_a[] = {
+ { 1, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_2_pins_a[] = {
+ { 2, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_3_pins_a[] = {
+ { 3, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_4_pins_a[] = {
+ { 4, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_5_pins_a[] = {
+ { 5, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_6_pins_a[] = {
+ { 6, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_7_pins_a[] = {
+ { 7, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_8_pins_a[] = {
+ { 8, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_9_pins_a[] = {
+ { 9, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_10_pins_a[] = {
+ { 10, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_11_pins_a[] = {
+ { 11, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_12_pins_a[] = {
+ { 12, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_13_pins_a[] = {
+ { 13, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_14_pins_a[] = {
+ { 14, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_15_pins_a[] = {
+ { 15, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_16_pins_a[] = {
+ { 16, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_17_pins_a[] = {
+ { 17, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_18_pins_a[] = {
+ { 18, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_19_pins_a[] = {
+ { 19, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_20_pins_a[] = {
+ { 20, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_21_pins_a[] = {
+ { 21, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_22_pins_a[] = {
+ { 22, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_23_pins_a[] = {
+ { 23, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_24_pins_a[] = {
+ { 24, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_25_pins_a[] = {
+ { 25, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_26_pins_a[] = {
+ { 26, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_27_pins_a[] = {
+ { 27, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_28_pins_a[] = {
+ { 28, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_29_pins_a[] = {
+ { 29, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_30_pins_a[] = {
+ { 30, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_31_pins_a[] = {
+ { 31, 3 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_10_pins_b[] = {
+ { 8, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_11_pins_b[] = {
+ { 9, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_12_pins_b[] = {
+ { 0, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_13_pins_b[] = {
+ { 1, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup led_31_pins_b[] = {
+ { 30, 2 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup hs_uart_pins[] = {
+ { 10, 0 }, /* CTS */
+ { 11, 0 }, /* RTS */
+ { 12, 0 }, /* RXD */
+ { 13, 0 }, /* TXD */
+};
+
+static const struct bcm4908_pinctrl_pin_setup i2c_pins_a[] = {
+ { 18, 0 }, /* SDA */
+ { 19, 0 }, /* SCL */
+};
+
+static const struct bcm4908_pinctrl_pin_setup i2c_pins_b[] = {
+ { 22, 0 }, /* SDA */
+ { 23, 0 }, /* SCL */
+};
+
+static const struct bcm4908_pinctrl_pin_setup i2s_pins[] = {
+ { 27, 0 }, /* MCLK */
+ { 28, 0 }, /* LRCK */
+ { 29, 0 }, /* SDATA */
+ { 30, 0 }, /* SCLK */
+};
+
+static const struct bcm4908_pinctrl_pin_setup nand_ctrl_pins[] = {
+ { 32, 0 },
+ { 33, 0 },
+ { 34, 0 },
+ { 43, 0 },
+ { 44, 0 },
+ { 45, 0 },
+ { 56, 1 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup nand_data_pins[] = {
+ { 35, 0 },
+ { 36, 0 },
+ { 37, 0 },
+ { 38, 0 },
+ { 39, 0 },
+ { 40, 0 },
+ { 41, 0 },
+ { 42, 0 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup emmc_ctrl_pins[] = {
+ { 46, 0 },
+ { 47, 0 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup usb0_pwr_pins[] = {
+ { 63, 0 },
+ { 64, 0 },
+};
+
+static const struct bcm4908_pinctrl_pin_setup usb1_pwr_pins[] = {
+ { 66, 0 },
+ { 67, 0 },
+};
+
+struct bcm4908_pinctrl_grp {
+ const char *name;
+ const struct bcm4908_pinctrl_pin_setup *pins;
+ const unsigned int num_pins;
+};
+
+static const struct bcm4908_pinctrl_grp bcm4908_pinctrl_grps[] = {
+ { "led_0_grp_a", led_0_pins_a, ARRAY_SIZE(led_0_pins_a) },
+ { "led_1_grp_a", led_1_pins_a, ARRAY_SIZE(led_1_pins_a) },
+ { "led_2_grp_a", led_2_pins_a, ARRAY_SIZE(led_2_pins_a) },
+ { "led_3_grp_a", led_3_pins_a, ARRAY_SIZE(led_3_pins_a) },
+ { "led_4_grp_a", led_4_pins_a, ARRAY_SIZE(led_4_pins_a) },
+ { "led_5_grp_a", led_5_pins_a, ARRAY_SIZE(led_5_pins_a) },
+ { "led_6_grp_a", led_6_pins_a, ARRAY_SIZE(led_6_pins_a) },
+ { "led_7_grp_a", led_7_pins_a, ARRAY_SIZE(led_7_pins_a) },
+ { "led_8_grp_a", led_8_pins_a, ARRAY_SIZE(led_8_pins_a) },
+ { "led_9_grp_a", led_9_pins_a, ARRAY_SIZE(led_9_pins_a) },
+ { "led_10_grp_a", led_10_pins_a, ARRAY_SIZE(led_10_pins_a) },
+ { "led_11_grp_a", led_11_pins_a, ARRAY_SIZE(led_11_pins_a) },
+ { "led_12_grp_a", led_12_pins_a, ARRAY_SIZE(led_12_pins_a) },
+ { "led_13_grp_a", led_13_pins_a, ARRAY_SIZE(led_13_pins_a) },
+ { "led_14_grp_a", led_14_pins_a, ARRAY_SIZE(led_14_pins_a) },
+ { "led_15_grp_a", led_15_pins_a, ARRAY_SIZE(led_15_pins_a) },
+ { "led_16_grp_a", led_16_pins_a, ARRAY_SIZE(led_16_pins_a) },
+ { "led_17_grp_a", led_17_pins_a, ARRAY_SIZE(led_17_pins_a) },
+ { "led_18_grp_a", led_18_pins_a, ARRAY_SIZE(led_18_pins_a) },
+ { "led_19_grp_a", led_19_pins_a, ARRAY_SIZE(led_19_pins_a) },
+ { "led_20_grp_a", led_20_pins_a, ARRAY_SIZE(led_20_pins_a) },
+ { "led_21_grp_a", led_21_pins_a, ARRAY_SIZE(led_21_pins_a) },
+ { "led_22_grp_a", led_22_pins_a, ARRAY_SIZE(led_22_pins_a) },
+ { "led_23_grp_a", led_23_pins_a, ARRAY_SIZE(led_23_pins_a) },
+ { "led_24_grp_a", led_24_pins_a, ARRAY_SIZE(led_24_pins_a) },
+ { "led_25_grp_a", led_25_pins_a, ARRAY_SIZE(led_25_pins_a) },
+ { "led_26_grp_a", led_26_pins_a, ARRAY_SIZE(led_26_pins_a) },
+ { "led_27_grp_a", led_27_pins_a, ARRAY_SIZE(led_27_pins_a) },
+ { "led_28_grp_a", led_28_pins_a, ARRAY_SIZE(led_28_pins_a) },
+ { "led_29_grp_a", led_29_pins_a, ARRAY_SIZE(led_29_pins_a) },
+ { "led_30_grp_a", led_30_pins_a, ARRAY_SIZE(led_30_pins_a) },
+ { "led_31_grp_a", led_31_pins_a, ARRAY_SIZE(led_31_pins_a) },
+ { "led_10_grp_b", led_10_pins_b, ARRAY_SIZE(led_10_pins_b) },
+ { "led_11_grp_b", led_11_pins_b, ARRAY_SIZE(led_11_pins_b) },
+ { "led_12_grp_b", led_12_pins_b, ARRAY_SIZE(led_12_pins_b) },
+ { "led_13_grp_b", led_13_pins_b, ARRAY_SIZE(led_13_pins_b) },
+ { "led_31_grp_b", led_31_pins_b, ARRAY_SIZE(led_31_pins_b) },
+ { "hs_uart_grp", hs_uart_pins, ARRAY_SIZE(hs_uart_pins) },
+ { "i2c_grp_a", i2c_pins_a, ARRAY_SIZE(i2c_pins_a) },
+ { "i2c_grp_b", i2c_pins_b, ARRAY_SIZE(i2c_pins_b) },
+ { "i2s_grp", i2s_pins, ARRAY_SIZE(i2s_pins) },
+ { "nand_ctrl_grp", nand_ctrl_pins, ARRAY_SIZE(nand_ctrl_pins) },
+ { "nand_data_grp", nand_data_pins, ARRAY_SIZE(nand_data_pins) },
+ { "emmc_ctrl_grp", emmc_ctrl_pins, ARRAY_SIZE(emmc_ctrl_pins) },
+ { "usb0_pwr_grp", usb0_pwr_pins, ARRAY_SIZE(usb0_pwr_pins) },
+ { "usb1_pwr_grp", usb1_pwr_pins, ARRAY_SIZE(usb1_pwr_pins) },
+};
+
+/*
+ * Functions
+ */
+
+struct bcm4908_pinctrl_function {
+ const char *name;
+ const char * const *groups;
+ const unsigned int num_groups;
+};
+
+static const char * const led_0_groups[] = { "led_0_grp_a" };
+static const char * const led_1_groups[] = { "led_1_grp_a" };
+static const char * const led_2_groups[] = { "led_2_grp_a" };
+static const char * const led_3_groups[] = { "led_3_grp_a" };
+static const char * const led_4_groups[] = { "led_4_grp_a" };
+static const char * const led_5_groups[] = { "led_5_grp_a" };
+static const char * const led_6_groups[] = { "led_6_grp_a" };
+static const char * const led_7_groups[] = { "led_7_grp_a" };
+static const char * const led_8_groups[] = { "led_8_grp_a" };
+static const char * const led_9_groups[] = { "led_9_grp_a" };
+static const char * const led_10_groups[] = { "led_10_grp_a", "led_10_grp_b" };
+static const char * const led_11_groups[] = { "led_11_grp_a", "led_11_grp_b" };
+static const char * const led_12_groups[] = { "led_12_grp_a", "led_12_grp_b" };
+static const char * const led_13_groups[] = { "led_13_grp_a", "led_13_grp_b" };
+static const char * const led_14_groups[] = { "led_14_grp_a" };
+static const char * const led_15_groups[] = { "led_15_grp_a" };
+static const char * const led_16_groups[] = { "led_16_grp_a" };
+static const char * const led_17_groups[] = { "led_17_grp_a" };
+static const char * const led_18_groups[] = { "led_18_grp_a" };
+static const char * const led_19_groups[] = { "led_19_grp_a" };
+static const char * const led_20_groups[] = { "led_20_grp_a" };
+static const char * const led_21_groups[] = { "led_21_grp_a" };
+static const char * const led_22_groups[] = { "led_22_grp_a" };
+static const char * const led_23_groups[] = { "led_23_grp_a" };
+static const char * const led_24_groups[] = { "led_24_grp_a" };
+static const char * const led_25_groups[] = { "led_25_grp_a" };
+static const char * const led_26_groups[] = { "led_26_grp_a" };
+static const char * const led_27_groups[] = { "led_27_grp_a" };
+static const char * const led_28_groups[] = { "led_28_grp_a" };
+static const char * const led_29_groups[] = { "led_29_grp_a" };
+static const char * const led_30_groups[] = { "led_30_grp_a" };
+static const char * const led_31_groups[] = { "led_31_grp_a", "led_31_grp_b" };
+static const char * const hs_uart_groups[] = { "hs_uart_grp" };
+static const char * const i2c_groups[] = { "i2c_grp_a", "i2c_grp_b" };
+static const char * const i2s_groups[] = { "i2s_grp" };
+static const char * const nand_ctrl_groups[] = { "nand_ctrl_grp" };
+static const char * const nand_data_groups[] = { "nand_data_grp" };
+static const char * const emmc_ctrl_groups[] = { "emmc_ctrl_grp" };
+static const char * const usb0_pwr_groups[] = { "usb0_pwr_grp" };
+static const char * const usb1_pwr_groups[] = { "usb1_pwr_grp" };
+
+static const struct bcm4908_pinctrl_function bcm4908_pinctrl_functions[] = {
+ { "led_0", led_0_groups, ARRAY_SIZE(led_0_groups) },
+ { "led_1", led_1_groups, ARRAY_SIZE(led_1_groups) },
+ { "led_2", led_2_groups, ARRAY_SIZE(led_2_groups) },
+ { "led_3", led_3_groups, ARRAY_SIZE(led_3_groups) },
+ { "led_4", led_4_groups, ARRAY_SIZE(led_4_groups) },
+ { "led_5", led_5_groups, ARRAY_SIZE(led_5_groups) },
+ { "led_6", led_6_groups, ARRAY_SIZE(led_6_groups) },
+ { "led_7", led_7_groups, ARRAY_SIZE(led_7_groups) },
+ { "led_8", led_8_groups, ARRAY_SIZE(led_8_groups) },
+ { "led_9", led_9_groups, ARRAY_SIZE(led_9_groups) },
+ { "led_10", led_10_groups, ARRAY_SIZE(led_10_groups) },
+ { "led_11", led_11_groups, ARRAY_SIZE(led_11_groups) },
+ { "led_12", led_12_groups, ARRAY_SIZE(led_12_groups) },
+ { "led_13", led_13_groups, ARRAY_SIZE(led_13_groups) },
+ { "led_14", led_14_groups, ARRAY_SIZE(led_14_groups) },
+ { "led_15", led_15_groups, ARRAY_SIZE(led_15_groups) },
+ { "led_16", led_16_groups, ARRAY_SIZE(led_16_groups) },
+ { "led_17", led_17_groups, ARRAY_SIZE(led_17_groups) },
+ { "led_18", led_18_groups, ARRAY_SIZE(led_18_groups) },
+ { "led_19", led_19_groups, ARRAY_SIZE(led_19_groups) },
+ { "led_20", led_20_groups, ARRAY_SIZE(led_20_groups) },
+ { "led_21", led_21_groups, ARRAY_SIZE(led_21_groups) },
+ { "led_22", led_22_groups, ARRAY_SIZE(led_22_groups) },
+ { "led_23", led_23_groups, ARRAY_SIZE(led_23_groups) },
+ { "led_24", led_24_groups, ARRAY_SIZE(led_24_groups) },
+ { "led_25", led_25_groups, ARRAY_SIZE(led_25_groups) },
+ { "led_26", led_26_groups, ARRAY_SIZE(led_26_groups) },
+ { "led_27", led_27_groups, ARRAY_SIZE(led_27_groups) },
+ { "led_28", led_28_groups, ARRAY_SIZE(led_28_groups) },
+ { "led_29", led_29_groups, ARRAY_SIZE(led_29_groups) },
+ { "led_30", led_30_groups, ARRAY_SIZE(led_30_groups) },
+ { "led_31", led_31_groups, ARRAY_SIZE(led_31_groups) },
+ { "hs_uart", hs_uart_groups, ARRAY_SIZE(hs_uart_groups) },
+ { "i2c", i2c_groups, ARRAY_SIZE(i2c_groups) },
+ { "i2s", i2s_groups, ARRAY_SIZE(i2s_groups) },
+ { "nand_ctrl", nand_ctrl_groups, ARRAY_SIZE(nand_ctrl_groups) },
+ { "nand_data", nand_data_groups, ARRAY_SIZE(nand_data_groups) },
+ { "emmc_ctrl", emmc_ctrl_groups, ARRAY_SIZE(emmc_ctrl_groups) },
+ { "usb0_pwr", usb0_pwr_groups, ARRAY_SIZE(usb0_pwr_groups) },
+ { "usb1_pwr", usb1_pwr_groups, ARRAY_SIZE(usb1_pwr_groups) },
+};
+
+/*
+ * Groups code
+ */
+
+static const struct pinctrl_ops bcm4908_pinctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+/*
+ * Functions code
+ */
+
+static int bcm4908_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
+ unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct bcm4908_pinctrl *bcm4908_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ const struct bcm4908_pinctrl_grp *group;
+ struct group_desc *group_desc;
+ int i;
+
+ group_desc = pinctrl_generic_get_group(pctrl_dev, group_selector);
+ if (!group_desc)
+ return -EINVAL;
+ group = group_desc->data;
+
+ mutex_lock(&bcm4908_pinctrl->mutex);
+ for (i = 0; i < group->num_pins; i++) {
+ u32 lsb = 0;
+
+ lsb |= group->pins[i].number;
+ lsb |= group->pins[i].function << BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT;
+
+ writel(0x0, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_MSB);
+ writel(lsb, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_LSB);
+ writel(BCM4908_TEST_PORT_CMD_LOAD_MUX_REG,
+ bcm4908_pinctrl->base + BCM4908_TEST_PORT_COMMAND);
+ }
+ mutex_unlock(&bcm4908_pinctrl->mutex);
+
+ return 0;
+}
+
+static const struct pinmux_ops bcm4908_pinctrl_pmxops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = bcm4908_pinctrl_set_mux,
+};
+
+/*
+ * Controller code
+ */
+
+static struct pinctrl_desc bcm4908_pinctrl_desc = {
+ .name = "bcm4908-pinctrl",
+ .pctlops = &bcm4908_pinctrl_ops,
+ .pmxops = &bcm4908_pinctrl_pmxops,
+};
+
+static const struct of_device_id bcm4908_pinctrl_of_match_table[] = {
+ { .compatible = "brcm,bcm4908-pinctrl", },
+ { }
+};
+
+static int bcm4908_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bcm4908_pinctrl *bcm4908_pinctrl;
+ struct pinctrl_desc *pctldesc;
+ struct pinctrl_pin_desc *pins;
+ char **pin_names;
+ int i;
+
+ bcm4908_pinctrl = devm_kzalloc(dev, sizeof(*bcm4908_pinctrl), GFP_KERNEL);
+ if (!bcm4908_pinctrl)
+ return -ENOMEM;
+ pctldesc = &bcm4908_pinctrl->pctldesc;
+ platform_set_drvdata(pdev, bcm4908_pinctrl);
+
+ /* Set basic properties */
+
+ bcm4908_pinctrl->dev = dev;
+
+ bcm4908_pinctrl->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(bcm4908_pinctrl->base))
+ return PTR_ERR(bcm4908_pinctrl->base);
+
+ mutex_init(&bcm4908_pinctrl->mutex);
+
+ memcpy(pctldesc, &bcm4908_pinctrl_desc, sizeof(*pctldesc));
+
+ /* Set pinctrl properties */
+
+ pin_names = devm_kasprintf_strarray(dev, "pin", BCM4908_NUM_PINS);
+ if (IS_ERR(pin_names))
+ return PTR_ERR(pin_names);
+
+ pins = devm_kcalloc(dev, BCM4908_NUM_PINS, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+ for (i = 0; i < BCM4908_NUM_PINS; i++) {
+ pins[i].number = i;
+ pins[i].name = pin_names[i];
+ }
+ pctldesc->pins = pins;
+ pctldesc->npins = BCM4908_NUM_PINS;
+
+ /* Register */
+
+ bcm4908_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, bcm4908_pinctrl);
+ if (IS_ERR(bcm4908_pinctrl->pctldev))
+ return dev_err_probe(dev, PTR_ERR(bcm4908_pinctrl->pctldev),
+ "Failed to register pinctrl\n");
+
+ /* Groups */
+
+ for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_grps); i++) {
+ const struct bcm4908_pinctrl_grp *group = &bcm4908_pinctrl_grps[i];
+ int *pins;
+ int j;
+
+ pins = devm_kcalloc(dev, group->num_pins, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+ for (j = 0; j < group->num_pins; j++)
+ pins[j] = group->pins[j].number;
+
+ pinctrl_generic_add_group(bcm4908_pinctrl->pctldev, group->name,
+ pins, group->num_pins, (void *)group);
+ }
+
+ /* Functions */
+
+ for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_functions); i++) {
+ const struct bcm4908_pinctrl_function *function = &bcm4908_pinctrl_functions[i];
+
+ pinmux_generic_add_function(bcm4908_pinctrl->pctldev,
+ function->name,
+ function->groups,
+ function->num_groups, NULL);
+ }
+
+ return 0;
+}
+
+static struct platform_driver bcm4908_pinctrl_driver = {
+ .probe = bcm4908_pinctrl_probe,
+ .driver = {
+ .name = "bcm4908-pinctrl",
+ .of_match_table = bcm4908_pinctrl_of_match_table,
+ },
+};
+
+module_platform_driver(bcm4908_pinctrl_driver);
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, bcm4908_pinctrl_of_match_table);
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6318.c b/drivers/pinctrl/bcm/pinctrl-bcm6318.c
new file mode 100644
index 000000000000..64073546310e
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6318.c
@@ -0,0 +1,485 @@
+// 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_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 };
+
+static struct pingroup bcm6318_groups[] = {
+ BCM_PIN_GROUP(gpio0),
+ BCM_PIN_GROUP(gpio1),
+ BCM_PIN_GROUP(gpio2),
+ BCM_PIN_GROUP(gpio3),
+ BCM_PIN_GROUP(gpio4),
+ BCM_PIN_GROUP(gpio5),
+ BCM_PIN_GROUP(gpio6),
+ BCM_PIN_GROUP(gpio7),
+ BCM_PIN_GROUP(gpio8),
+ BCM_PIN_GROUP(gpio9),
+ BCM_PIN_GROUP(gpio10),
+ BCM_PIN_GROUP(gpio11),
+ BCM_PIN_GROUP(gpio12),
+ BCM_PIN_GROUP(gpio13),
+ BCM_PIN_GROUP(gpio14),
+ BCM_PIN_GROUP(gpio15),
+ BCM_PIN_GROUP(gpio16),
+ BCM_PIN_GROUP(gpio17),
+ BCM_PIN_GROUP(gpio18),
+ BCM_PIN_GROUP(gpio19),
+ BCM_PIN_GROUP(gpio20),
+ BCM_PIN_GROUP(gpio21),
+ BCM_PIN_GROUP(gpio22),
+ BCM_PIN_GROUP(gpio23),
+ BCM_PIN_GROUP(gpio24),
+ BCM_PIN_GROUP(gpio25),
+ BCM_PIN_GROUP(gpio26),
+ BCM_PIN_GROUP(gpio27),
+ BCM_PIN_GROUP(gpio28),
+ BCM_PIN_GROUP(gpio29),
+ BCM_PIN_GROUP(gpio30),
+ BCM_PIN_GROUP(gpio31),
+ BCM_PIN_GROUP(gpio32),
+ BCM_PIN_GROUP(gpio33),
+ BCM_PIN_GROUP(gpio34),
+ BCM_PIN_GROUP(gpio35),
+ BCM_PIN_GROUP(gpio36),
+ BCM_PIN_GROUP(gpio37),
+ BCM_PIN_GROUP(gpio38),
+ BCM_PIN_GROUP(gpio39),
+ BCM_PIN_GROUP(gpio40),
+ BCM_PIN_GROUP(gpio41),
+ BCM_PIN_GROUP(gpio42),
+ BCM_PIN_GROUP(gpio43),
+ BCM_PIN_GROUP(gpio44),
+ BCM_PIN_GROUP(gpio45),
+ BCM_PIN_GROUP(gpio46),
+ BCM_PIN_GROUP(gpio47),
+ BCM_PIN_GROUP(gpio48),
+ BCM_PIN_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 *npins)
+{
+ *pins = bcm6318_groups[group].pins;
+ *npins = bcm6318_groups[group].npins;
+
+ 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 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 const 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 const 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..80c2fc55ffa2
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm63268.c
@@ -0,0 +1,630 @@
+// 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_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 };
+
+static struct pingroup bcm63268_groups[] = {
+ BCM_PIN_GROUP(gpio0),
+ BCM_PIN_GROUP(gpio1),
+ BCM_PIN_GROUP(gpio2),
+ BCM_PIN_GROUP(gpio3),
+ BCM_PIN_GROUP(gpio4),
+ BCM_PIN_GROUP(gpio5),
+ BCM_PIN_GROUP(gpio6),
+ BCM_PIN_GROUP(gpio7),
+ BCM_PIN_GROUP(gpio8),
+ BCM_PIN_GROUP(gpio9),
+ BCM_PIN_GROUP(gpio10),
+ BCM_PIN_GROUP(gpio11),
+ BCM_PIN_GROUP(gpio12),
+ BCM_PIN_GROUP(gpio13),
+ BCM_PIN_GROUP(gpio14),
+ BCM_PIN_GROUP(gpio15),
+ BCM_PIN_GROUP(gpio16),
+ BCM_PIN_GROUP(gpio17),
+ BCM_PIN_GROUP(gpio18),
+ BCM_PIN_GROUP(gpio19),
+ BCM_PIN_GROUP(gpio20),
+ BCM_PIN_GROUP(gpio21),
+ BCM_PIN_GROUP(gpio22),
+ BCM_PIN_GROUP(gpio23),
+ BCM_PIN_GROUP(gpio24),
+ BCM_PIN_GROUP(gpio25),
+ BCM_PIN_GROUP(gpio26),
+ BCM_PIN_GROUP(gpio27),
+ BCM_PIN_GROUP(gpio28),
+ BCM_PIN_GROUP(gpio29),
+ BCM_PIN_GROUP(gpio30),
+ BCM_PIN_GROUP(gpio31),
+ BCM_PIN_GROUP(gpio32),
+ BCM_PIN_GROUP(gpio33),
+ BCM_PIN_GROUP(gpio34),
+ BCM_PIN_GROUP(gpio35),
+ BCM_PIN_GROUP(gpio36),
+ BCM_PIN_GROUP(gpio37),
+ BCM_PIN_GROUP(gpio38),
+ BCM_PIN_GROUP(gpio39),
+ BCM_PIN_GROUP(gpio40),
+ BCM_PIN_GROUP(gpio41),
+ BCM_PIN_GROUP(gpio42),
+ BCM_PIN_GROUP(gpio43),
+ BCM_PIN_GROUP(gpio44),
+ BCM_PIN_GROUP(gpio45),
+ BCM_PIN_GROUP(gpio46),
+ BCM_PIN_GROUP(gpio47),
+ BCM_PIN_GROUP(gpio48),
+ BCM_PIN_GROUP(gpio49),
+ BCM_PIN_GROUP(gpio50),
+ BCM_PIN_GROUP(gpio51),
+
+ /* multi pin groups */
+ BCM_PIN_GROUP(nand_grp),
+ BCM_PIN_GROUP(dectpd_grp),
+ BCM_PIN_GROUP(vdsl_phy0_grp),
+ BCM_PIN_GROUP(vdsl_phy1_grp),
+ BCM_PIN_GROUP(vdsl_phy2_grp),
+ BCM_PIN_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 *npins)
+{
+ *pins = bcm63268_groups[group].pins;
+ *npins = bcm63268_groups[group].npins;
+
+ 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 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->npins; 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 const 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 const 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..1e8cc2c80c81
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6328.c
@@ -0,0 +1,391 @@
+// 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_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 };
+
+static struct pingroup bcm6328_groups[] = {
+ BCM_PIN_GROUP(gpio0),
+ BCM_PIN_GROUP(gpio1),
+ BCM_PIN_GROUP(gpio2),
+ BCM_PIN_GROUP(gpio3),
+ BCM_PIN_GROUP(gpio4),
+ BCM_PIN_GROUP(gpio5),
+ BCM_PIN_GROUP(gpio6),
+ BCM_PIN_GROUP(gpio7),
+ BCM_PIN_GROUP(gpio8),
+ BCM_PIN_GROUP(gpio9),
+ BCM_PIN_GROUP(gpio10),
+ BCM_PIN_GROUP(gpio11),
+ BCM_PIN_GROUP(gpio12),
+ BCM_PIN_GROUP(gpio13),
+ BCM_PIN_GROUP(gpio14),
+ BCM_PIN_GROUP(gpio15),
+ BCM_PIN_GROUP(gpio16),
+ BCM_PIN_GROUP(gpio17),
+ BCM_PIN_GROUP(gpio18),
+ BCM_PIN_GROUP(gpio19),
+ BCM_PIN_GROUP(gpio20),
+ BCM_PIN_GROUP(gpio21),
+ BCM_PIN_GROUP(gpio22),
+ BCM_PIN_GROUP(gpio23),
+ BCM_PIN_GROUP(gpio24),
+ BCM_PIN_GROUP(gpio25),
+ BCM_PIN_GROUP(gpio26),
+ BCM_PIN_GROUP(gpio27),
+ BCM_PIN_GROUP(gpio28),
+ BCM_PIN_GROUP(gpio29),
+ BCM_PIN_GROUP(gpio30),
+ BCM_PIN_GROUP(gpio31),
+
+ BCM_PIN_GROUP(hsspi_cs1),
+ BCM_PIN_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 *npins)
+{
+ *pins = bcm6328_groups[group].pins;
+ *npins = bcm6328_groups[group].npins;
+
+ 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 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 const 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 const 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..891de49d76e7
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6358.c
@@ -0,0 +1,365 @@
+// 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 {
+ struct pingroup grp;
+
+ 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) \
+ { \
+ .grp = BCM_PIN_GROUP(n), \
+ .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].grp.name;
+}
+
+static int bcm6358_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group, const unsigned **pins,
+ unsigned *npins)
+{
+ *pins = bcm6358_groups[group].grp.pins;
+ *npins = bcm6358_groups[group].grp.npins;
+
+ 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->grp.npins; pin++)
+ mask |= (unsigned long)bcm6358_pins[pin].drv_data;
+
+ regmap_field_update_bits(priv->overlays, mask, val);
+
+ for (pin = 0; pin < pg->grp.npins; 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 const 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 const 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..d9ba1b6c2aeb
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6362.c
@@ -0,0 +1,604 @@
+// 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_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,
+};
+
+static struct pingroup bcm6362_groups[] = {
+ BCM_PIN_GROUP(gpio0),
+ BCM_PIN_GROUP(gpio1),
+ BCM_PIN_GROUP(gpio2),
+ BCM_PIN_GROUP(gpio3),
+ BCM_PIN_GROUP(gpio4),
+ BCM_PIN_GROUP(gpio5),
+ BCM_PIN_GROUP(gpio6),
+ BCM_PIN_GROUP(gpio7),
+ BCM_PIN_GROUP(gpio8),
+ BCM_PIN_GROUP(gpio9),
+ BCM_PIN_GROUP(gpio10),
+ BCM_PIN_GROUP(gpio11),
+ BCM_PIN_GROUP(gpio12),
+ BCM_PIN_GROUP(gpio13),
+ BCM_PIN_GROUP(gpio14),
+ BCM_PIN_GROUP(gpio15),
+ BCM_PIN_GROUP(gpio16),
+ BCM_PIN_GROUP(gpio17),
+ BCM_PIN_GROUP(gpio18),
+ BCM_PIN_GROUP(gpio19),
+ BCM_PIN_GROUP(gpio20),
+ BCM_PIN_GROUP(gpio21),
+ BCM_PIN_GROUP(gpio22),
+ BCM_PIN_GROUP(gpio23),
+ BCM_PIN_GROUP(gpio24),
+ BCM_PIN_GROUP(gpio25),
+ BCM_PIN_GROUP(gpio26),
+ BCM_PIN_GROUP(gpio27),
+ BCM_PIN_GROUP(gpio28),
+ BCM_PIN_GROUP(gpio29),
+ BCM_PIN_GROUP(gpio30),
+ BCM_PIN_GROUP(gpio31),
+ BCM_PIN_GROUP(gpio32),
+ BCM_PIN_GROUP(gpio33),
+ BCM_PIN_GROUP(gpio34),
+ BCM_PIN_GROUP(gpio35),
+ BCM_PIN_GROUP(gpio36),
+ BCM_PIN_GROUP(gpio37),
+ BCM_PIN_GROUP(gpio38),
+ BCM_PIN_GROUP(gpio39),
+ BCM_PIN_GROUP(gpio40),
+ BCM_PIN_GROUP(gpio41),
+ BCM_PIN_GROUP(gpio42),
+ BCM_PIN_GROUP(gpio43),
+ BCM_PIN_GROUP(gpio44),
+ BCM_PIN_GROUP(gpio45),
+ BCM_PIN_GROUP(gpio46),
+ BCM_PIN_GROUP(gpio47),
+ BCM_PIN_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 *npins)
+{
+ *pins = bcm6362_groups[group].pins;
+ *npins = bcm6362_groups[group].npins;
+
+ 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 basemode = (uintptr_t)desc->drv_data;
+ unsigned int mask = bcm63xx_bank_pin(pin);
+
+ if (basemode)
+ regmap_update_bits(pc->regs, BCM6362_BASEMODE_REG, basemode, 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 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->npins; 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 const 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 const 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..6208467ba6f9
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6368.c
@@ -0,0 +1,510 @@
+// 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_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 };
+
+static struct pingroup bcm6368_groups[] = {
+ BCM_PIN_GROUP(gpio0),
+ BCM_PIN_GROUP(gpio1),
+ BCM_PIN_GROUP(gpio2),
+ BCM_PIN_GROUP(gpio3),
+ BCM_PIN_GROUP(gpio4),
+ BCM_PIN_GROUP(gpio5),
+ BCM_PIN_GROUP(gpio6),
+ BCM_PIN_GROUP(gpio7),
+ BCM_PIN_GROUP(gpio8),
+ BCM_PIN_GROUP(gpio9),
+ BCM_PIN_GROUP(gpio10),
+ BCM_PIN_GROUP(gpio11),
+ BCM_PIN_GROUP(gpio12),
+ BCM_PIN_GROUP(gpio13),
+ BCM_PIN_GROUP(gpio14),
+ BCM_PIN_GROUP(gpio15),
+ BCM_PIN_GROUP(gpio16),
+ BCM_PIN_GROUP(gpio17),
+ BCM_PIN_GROUP(gpio18),
+ BCM_PIN_GROUP(gpio19),
+ BCM_PIN_GROUP(gpio20),
+ BCM_PIN_GROUP(gpio21),
+ BCM_PIN_GROUP(gpio22),
+ BCM_PIN_GROUP(gpio23),
+ BCM_PIN_GROUP(gpio24),
+ BCM_PIN_GROUP(gpio25),
+ BCM_PIN_GROUP(gpio26),
+ BCM_PIN_GROUP(gpio27),
+ BCM_PIN_GROUP(gpio28),
+ BCM_PIN_GROUP(gpio29),
+ BCM_PIN_GROUP(gpio30),
+ BCM_PIN_GROUP(gpio31),
+ BCM_PIN_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 *npins)
+{
+ *pins = bcm6368_groups[group].pins;
+ *npins = bcm6368_groups[group].npins;
+
+ 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 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->npins; 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->npins; 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 const 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 const 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..95243027ecd9
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.h
@@ -0,0 +1,45 @@
+// 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 {
+ const struct pinctrl_ops *pctl_ops;
+ const struct pinmux_ops *pmx_ops;
+
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+
+ unsigned int ngpios;
+};
+
+#define BCM_PIN_GROUP(n) PINCTRL_PINGROUP(#n, n##_pins, ARRAY_SIZE(n##_pins))
+
+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__ */
diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
index 4344c5732400..5251460f6327 100644
--- a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
@@ -1,15 +1,5 @@
-/*
- * Copyright (C) 2014-2017 Broadcom
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2014-2017 Broadcom
/*
* Broadcom Cygnus IOMUX driver
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index 25166217c3e0..52fa2f4cd618 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -131,7 +131,7 @@ static inline unsigned iproc_pin_to_gpio(unsigned pin)
* iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
* Iproc GPIO register
*
- * @iproc_gpio: Iproc GPIO device
+ * @chip: Iproc GPIO device
* @reg: register offset
* @gpio: GPIO pin
* @set: set or clear
@@ -176,7 +176,6 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
unsigned pin = NGPIOS_PER_BANK * i + bit;
- int child_irq = irq_find_mapping(gc->irq.domain, pin);
/*
* Clear the interrupt before invoking the
@@ -185,7 +184,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) +
IPROC_GPIO_INT_CLR_OFFSET);
- generic_handle_irq(child_irq);
+ generic_handle_domain_irq(gc->irq.domain, pin);
}
}
@@ -363,7 +362,10 @@ static int iproc_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
- return !(readl(chip->base + offset) & BIT(shift));
+ if (readl(chip->base + offset) & BIT(shift))
+ return GPIO_LINE_DIRECTION_OUT;
+
+ return GPIO_LINE_DIRECTION_IN;
}
static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
@@ -810,10 +812,8 @@ static int iproc_gpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
chip->io_ctrl = devm_ioremap_resource(dev, res);
- if (IS_ERR(chip->io_ctrl)) {
- dev_err(dev, "unable to map I/O memory\n");
+ if (IS_ERR(chip->io_ctrl))
return PTR_ERR(chip->io_ctrl);
- }
if (of_device_is_compatible(dev->of_node,
"brcm,cygnus-ccm-gpio"))
io_ctrl_type = IOCTRL_TYPE_CDRU;
@@ -836,7 +836,6 @@ static int iproc_gpio_probe(struct platform_device *pdev)
chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
gc->label = dev_name(dev);
gc->parent = dev;
- gc->of_node = dev->of_node;
gc->request = iproc_gpio_request;
gc->free = iproc_gpio_free;
gc->direction_input = iproc_gpio_direction_input;
diff --git a/drivers/pinctrl/bcm/pinctrl-ns.c b/drivers/pinctrl/bcm/pinctrl-ns.c
index e79690bd8b85..465cc96814a1 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns.c
@@ -5,7 +5,6 @@
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -13,9 +12,11 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
-#include <linux/regmap.h>
#include <linux/slab.h>
+#include "../core.h"
+#include "../pinmux.h"
+
#define FLAG_BCM4708 BIT(1)
#define FLAG_BCM4709 BIT(2)
#define FLAG_BCM53012 BIT(3)
@@ -24,14 +25,9 @@ struct ns_pinctrl {
struct device *dev;
unsigned int chipset_flag;
struct pinctrl_dev *pctldev;
- struct regmap *regmap;
- u32 offset;
+ void __iomem *base;
struct pinctrl_desc pctldesc;
- struct ns_pinctrl_group *groups;
- unsigned int num_groups;
- struct ns_pinctrl_function *functions;
- unsigned int num_functions;
};
/*
@@ -68,22 +64,22 @@ static const struct pinctrl_pin_desc ns_pinctrl_pins[] = {
struct ns_pinctrl_group {
const char *name;
- const unsigned int *pins;
+ unsigned int *pins;
const unsigned int num_pins;
unsigned int chipsets;
};
-static const unsigned int spi_pins[] = { 0, 1, 2, 3 };
-static const unsigned int i2c_pins[] = { 4, 5 };
-static const unsigned int mdio_pins[] = { 6, 7 };
-static const unsigned int pwm0_pins[] = { 8 };
-static const unsigned int pwm1_pins[] = { 9 };
-static const unsigned int pwm2_pins[] = { 10 };
-static const unsigned int pwm3_pins[] = { 11 };
-static const unsigned int uart1_pins[] = { 12, 13, 14, 15 };
-static const unsigned int uart2_pins[] = { 16, 17 };
-static const unsigned int sdio_pwr_pins[] = { 22 };
-static const unsigned int sdio_1p8v_pins[] = { 23 };
+static unsigned int spi_pins[] = { 0, 1, 2, 3 };
+static unsigned int i2c_pins[] = { 4, 5 };
+static unsigned int mdio_pins[] = { 6, 7 };
+static unsigned int pwm0_pins[] = { 8 };
+static unsigned int pwm1_pins[] = { 9 };
+static unsigned int pwm2_pins[] = { 10 };
+static unsigned int pwm3_pins[] = { 11 };
+static unsigned int uart1_pins[] = { 12, 13, 14, 15 };
+static unsigned int uart2_pins[] = { 16, 17 };
+static unsigned int sdio_pwr_pins[] = { 22 };
+static unsigned int sdio_1p8v_pins[] = { 23 };
#define NS_GROUP(_name, _pins, _chipsets) \
{ \
@@ -149,38 +145,10 @@ static const struct ns_pinctrl_function ns_pinctrl_functions[] = {
* Groups code
*/
-static int ns_pinctrl_get_groups_count(struct pinctrl_dev *pctrl_dev)
-{
- struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-
- return ns_pinctrl->num_groups;
-}
-
-static const char *ns_pinctrl_get_group_name(struct pinctrl_dev *pctrl_dev,
- unsigned int selector)
-{
- struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-
- return ns_pinctrl->groups[selector].name;
-}
-
-static int ns_pinctrl_get_group_pins(struct pinctrl_dev *pctrl_dev,
- unsigned int selector,
- const unsigned int **pins,
- unsigned int *num_pins)
-{
- struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-
- *pins = ns_pinctrl->groups[selector].pins;
- *num_pins = ns_pinctrl->groups[selector].num_pins;
-
- return 0;
-}
-
static const struct pinctrl_ops ns_pinctrl_ops = {
- .get_groups_count = ns_pinctrl_get_groups_count,
- .get_group_name = ns_pinctrl_get_group_name,
- .get_group_pins = ns_pinctrl_get_group_pins,
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
.dt_free_map = pinconf_generic_dt_free_map,
};
@@ -189,60 +157,34 @@ static const struct pinctrl_ops ns_pinctrl_ops = {
* Functions code
*/
-static int ns_pinctrl_get_functions_count(struct pinctrl_dev *pctrl_dev)
-{
- struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-
- return ns_pinctrl->num_functions;
-}
-
-static const char *ns_pinctrl_get_function_name(struct pinctrl_dev *pctrl_dev,
- unsigned int selector)
-{
- struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-
- return ns_pinctrl->functions[selector].name;
-}
-
-static int ns_pinctrl_get_function_groups(struct pinctrl_dev *pctrl_dev,
- unsigned int selector,
- const char * const **groups,
- unsigned * const num_groups)
-{
- struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-
- *groups = ns_pinctrl->functions[selector].groups;
- *num_groups = ns_pinctrl->functions[selector].num_groups;
-
- return 0;
-}
-
static int ns_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
unsigned int func_select,
- unsigned int grp_select)
+ unsigned int group_selector)
{
struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ struct group_desc *group;
u32 unset = 0;
u32 tmp;
int i;
- for (i = 0; i < ns_pinctrl->groups[grp_select].num_pins; i++) {
- int pin_number = ns_pinctrl->groups[grp_select].pins[i];
+ group = pinctrl_generic_get_group(pctrl_dev, group_selector);
+ if (!group)
+ return -EINVAL;
- unset |= BIT(pin_number);
- }
+ for (i = 0; i < group->num_pins; i++)
+ unset |= BIT(group->pins[i]);
- regmap_read(ns_pinctrl->regmap, ns_pinctrl->offset, &tmp);
+ tmp = readl(ns_pinctrl->base);
tmp &= ~unset;
- regmap_write(ns_pinctrl->regmap, ns_pinctrl->offset, tmp);
+ writel(tmp, ns_pinctrl->base);
return 0;
}
static const struct pinmux_ops ns_pinctrl_pmxops = {
- .get_functions_count = ns_pinctrl_get_functions_count,
- .get_function_name = ns_pinctrl_get_function_name,
- .get_function_groups = ns_pinctrl_get_function_groups,
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
.set_mux = ns_pinctrl_set_mux,
};
@@ -266,13 +208,11 @@ static const struct of_device_id ns_pinctrl_of_match_table[] = {
static int ns_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
const struct of_device_id *of_id;
struct ns_pinctrl *ns_pinctrl;
struct pinctrl_desc *pctldesc;
struct pinctrl_pin_desc *pin;
- struct ns_pinctrl_group *group;
- struct ns_pinctrl_function *function;
+ struct resource *res;
int i;
ns_pinctrl = devm_kzalloc(dev, sizeof(*ns_pinctrl), GFP_KERNEL);
@@ -290,19 +230,11 @@ static int ns_pinctrl_probe(struct platform_device *pdev)
return -EINVAL;
ns_pinctrl->chipset_flag = (uintptr_t)of_id->data;
- ns_pinctrl->regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(ns_pinctrl->regmap)) {
- int err = PTR_ERR(ns_pinctrl->regmap);
-
- dev_err(dev, "Failed to map pinctrl regs: %d\n", err);
-
- return err;
- }
-
- if (of_property_read_u32(np, "offset", &ns_pinctrl->offset)) {
- dev_err(dev, "Failed to get register offset\n");
- return -ENOENT;
- }
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cru_gpio_control");
+ ns_pinctrl->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ns_pinctrl->base))
+ return PTR_ERR(ns_pinctrl->base);
memcpy(pctldesc, &ns_pinctrl_desc, sizeof(*pctldesc));
@@ -324,43 +256,33 @@ static int ns_pinctrl_probe(struct platform_device *pdev)
}
}
- ns_pinctrl->groups = devm_kcalloc(dev, ARRAY_SIZE(ns_pinctrl_groups),
- sizeof(struct ns_pinctrl_group),
- GFP_KERNEL);
- if (!ns_pinctrl->groups)
- return -ENOMEM;
- for (i = 0, group = &ns_pinctrl->groups[0];
- i < ARRAY_SIZE(ns_pinctrl_groups); i++) {
- const struct ns_pinctrl_group *src = &ns_pinctrl_groups[i];
+ /* Register */
- if (src->chipsets & ns_pinctrl->chipset_flag) {
- memcpy(group++, src, sizeof(*src));
- ns_pinctrl->num_groups++;
- }
+ ns_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, ns_pinctrl);
+ if (IS_ERR(ns_pinctrl->pctldev)) {
+ dev_err(dev, "Failed to register pinctrl\n");
+ return PTR_ERR(ns_pinctrl->pctldev);
}
- ns_pinctrl->functions = devm_kcalloc(dev,
- ARRAY_SIZE(ns_pinctrl_functions),
- sizeof(struct ns_pinctrl_function),
- GFP_KERNEL);
- if (!ns_pinctrl->functions)
- return -ENOMEM;
- for (i = 0, function = &ns_pinctrl->functions[0];
- i < ARRAY_SIZE(ns_pinctrl_functions); i++) {
- const struct ns_pinctrl_function *src = &ns_pinctrl_functions[i];
+ for (i = 0; i < ARRAY_SIZE(ns_pinctrl_groups); i++) {
+ const struct ns_pinctrl_group *group = &ns_pinctrl_groups[i];
- if (src->chipsets & ns_pinctrl->chipset_flag) {
- memcpy(function++, src, sizeof(*src));
- ns_pinctrl->num_functions++;
- }
+ if (!(group->chipsets & ns_pinctrl->chipset_flag))
+ continue;
+
+ pinctrl_generic_add_group(ns_pinctrl->pctldev, group->name,
+ group->pins, group->num_pins, NULL);
}
- /* Register */
+ for (i = 0; i < ARRAY_SIZE(ns_pinctrl_functions); i++) {
+ const struct ns_pinctrl_function *function = &ns_pinctrl_functions[i];
- ns_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, ns_pinctrl);
- if (IS_ERR(ns_pinctrl->pctldev)) {
- dev_err(dev, "Failed to register pinctrl\n");
- return PTR_ERR(ns_pinctrl->pctldev);
+ if (!(function->chipsets & ns_pinctrl->chipset_flag))
+ continue;
+
+ pinmux_generic_add_function(ns_pinctrl->pctldev, function->name,
+ function->groups,
+ function->num_groups, NULL);
}
return 0;
diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
index 57044ab376d3..960e253f0be4 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2016 Broadcom Corporation
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* This file contains the Northstar2 IOMUX driver that supports group
* based PINMUX configuration. The PWM is functional only when the
* corresponding mfio pin group is selected as gpio.
@@ -853,7 +845,7 @@ static int ns2_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
ns2_pin_get_pull(pctldev, pin, &pull_up, &pull_down);
- if ((pull_up == false) && (pull_down == false))
+ if (!pull_up && !pull_down)
return 0;
else
return -EINVAL;
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
index bed0124388c0..3c792bf03bda 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
@@ -1,15 +1,5 @@
-/*
- * Copyright (C) 2014-2017 Broadcom
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2014-2017 Broadcom
/*
* This file contains the Broadcom Northstar Plus (NSP) GPIO driver that
@@ -154,15 +144,8 @@ static irqreturn_t nsp_gpio_irq_handler(int irq, void *data)
level &= readl(chip->base + NSP_GPIO_INT_MASK);
int_bits = level | event;
- for_each_set_bit(bit, &int_bits, gc->ngpio) {
- /*
- * Clear the interrupt before invoking the
- * handler, so we do not leave any window
- */
- writel(BIT(bit), chip->base + NSP_GPIO_EVENT);
- generic_handle_irq(
- irq_linear_revmap(gc->irq.domain, bit));
- }
+ for_each_set_bit(bit, &int_bits, gc->ngpio)
+ generic_handle_domain_irq(gc->irq.domain, bit);
}
return int_bits ? IRQ_HANDLED : IRQ_NONE;
@@ -178,7 +161,7 @@ static void nsp_gpio_irq_ack(struct irq_data *d)
trigger_type = irq_get_trigger_type(d->irq);
if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
- nsp_set_bit(chip, REG, NSP_GPIO_EVENT, gpio, val);
+ writel(val, chip->base + NSP_GPIO_EVENT);
}
/*
@@ -262,6 +245,12 @@ static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type)
nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling);
nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low);
+
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ irq_set_handler_locked(d, handle_edge_irq);
+ else
+ irq_set_handler_locked(d, handle_level_irq);
+
raw_spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio,
@@ -649,7 +638,6 @@ static int nsp_gpio_probe(struct platform_device *pdev)
gc->ngpio = val;
gc->label = dev_name(dev);
gc->parent = dev;
- gc->of_node = dev->of_node;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
gc->direction_input = nsp_gpio_direction_input;
@@ -691,7 +679,7 @@ static int nsp_gpio_probe(struct platform_device *pdev)
girq->num_parents = 0;
girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_simple_irq;
+ girq->handler = handle_bad_irq;
}
ret = devm_gpiochip_add_data(dev, gc, chip);
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
index f1d60a708815..db8f79920ff0 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2015 Broadcom Corporation
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* This file contains the Northstar plus (NSP) IOMUX driver that supports
* group based PINMUX configuration. The Northstar plus IOMUX controller
* allows pins to be individually muxed to GPIO function. The NAND and MMC is