summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-11 10:53:39 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-11 10:53:39 -0800
commitd70178215211a7c73ecabeb55eeb0f8ef002bcab (patch)
treeb3943a90930022fb5f36a14d48ccc2742ace3dc3 /drivers/gpio
parent893ace4df0f96b8ad066651453e0519d4ffe35ca (diff)
parentaf9b4a56f0000fb11057e204ddfb05d72ba4dba0 (diff)
Merge tag 'gpio-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "There are two new drivers and some changes to GPIO core but mostly just GPIO driver updates across a wide array of files, adding support for new models as well as various refactoring changes. Nothing controversial and everything has spent a good measure of time in linux-next. GPIOLIB core: - shrink the GPIO bus driver stub code - rework software node support for "undefined" software nodes - provide and use devm_fwnode_gpiod_get_optional() - only compile the OF quirk for MT2701 when needed New drivers: - add the GPIO driver for ROHM bd72720 - add the gpio-line-mux driver providing 1-to-many mapping for a single real GPIO Driver changes: - refactor gpio-pca9570: use lock guard, add missing headers, use devres consistently - add support for a new model (G7 Aspeed sgpiom) to the aspeed-sgpio driver along with some prerequisite refactoring - use device_get_match_data() where applicable and save some lines - add support for more models to gpio-cadence - add the compatible property to reset-gpio and use it in shared GPIO management - drop unnecessary use of irqd_get_trigger_type() in gpio-max77759 - add support for a new variant to gpio-pca953x - extend build coverage with COMPILE_TEST for more drivers - constify configfs structures in gpio-sim and gpio-virtuser - add support for the K3 SoC to gpio-spacemit - implement the missing .get_direction() callback in gpio-max77620 - add support for Tegra264 to gpio-tegra186 - drop unneeded MODULE_ALIAS() from gpio-menz127 DT bindings: - document support for the opencores GPIO controller in gpio-mmio - document new variants for gpio-pca953x Documentation: - extensively describe interrupt source detection for gpio-pca953x and add more models to the list of supported variants" * tag 'gpio-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (59 commits) gpio: tegra186: Add support for Tegra264 dt-bindings: gpio: Add Tegra264 support gpio: spacemit-k1: Use PDR for pin direction, not SDR/CDR gpio: max77620: Implement .get_direction() callback gpio: aspeed-sgpio: Support G7 Aspeed sgpiom controller dt-bindings: gpio: aspeed,sgpio: Support ast2700 gpio: aspeed-sgpio: Convert IRQ functions to use llops callbacks gpio: aspeed-sgpio: Create llops to handle hardware access gpio: aspeed-sgpio: Remove unused bank name field gpio: aspeed-sgpio: Change the macro to support deferred probe regulator: bd71815: switch to devm_fwnode_gpiod_get_optional gpiolib: introduce devm_fwnode_gpiod_get_optional() wrapper gpio: mmio: Add compatible for opencores GPIO dt-bindings: gpio-mmio: Correct opencores GPIO gpio: pca9570: use lock guards gpio: pca9570: Don't use "proxy" headers gpio: pca9570: Use devm_mutex_init() for mutex initialization MAINTAINERS: Add ROHM BD72720 PMIC power: supply: bd71828-power: Support ROHM BD72720 power: supply: bd71828: Support wider register addresses ...
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig24
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-aggregator.c8
-rw-r--r--drivers/gpio/gpio-aspeed-sgpio.c362
-rw-r--r--drivers/gpio/gpio-aspeed.c7
-rw-r--r--drivers/gpio/gpio-bd72720.c281
-rw-r--r--drivers/gpio/gpio-cadence.c76
-rw-r--r--drivers/gpio/gpio-creg-snps.c4
-rw-r--r--drivers/gpio/gpio-line-mux.c116
-rw-r--r--drivers/gpio/gpio-max77620.c19
-rw-r--r--drivers/gpio/gpio-max77759.c10
-rw-r--r--drivers/gpio/gpio-menz127.c1
-rw-r--r--drivers/gpio/gpio-mmio.c1
-rw-r--r--drivers/gpio/gpio-pca953x.c6
-rw-r--r--drivers/gpio/gpio-pca9570.c19
-rw-r--r--drivers/gpio/gpio-realtek-otto.c5
-rw-r--r--drivers/gpio/gpio-sim.c16
-rw-r--r--drivers/gpio/gpio-spacemit-k1.c168
-rw-r--r--drivers/gpio/gpio-tegra186.c90
-rw-r--r--drivers/gpio/gpio-virtuser.c8
-rw-r--r--drivers/gpio/gpio-zynq.c12
-rw-r--r--drivers/gpio/gpiolib-of.c4
-rw-r--r--drivers/gpio/gpiolib-shared.c7
-rw-r--r--drivers/gpio/gpiolib-swnode.c9
-rw-r--r--drivers/gpio/gpiolib.c30
25 files changed, 999 insertions, 286 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bd185482a7fd..b45fb799e36c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -600,7 +600,7 @@ config GPIO_RDA
config GPIO_REALTEK_OTTO
tristate "Realtek Otto GPIO support"
- depends on MACH_REALTEK_RTL
+ depends on MACH_REALTEK_RTL || COMPILE_TEST
default MACH_REALTEK_RTL
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
@@ -1193,11 +1193,11 @@ config GPIO_PCA953X
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
pca9556, pca9557, pca9574, tca6408, tca9554, xra1202,
- pcal6408, pcal9554b, tca9538
+ pcal6408, pcal9554b, tca9538, tcal6408
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
tca6416, pca6416, pcal6416, pcal9535, pcal9555a, max7318,
- tca9539
+ tca9539, tcal6416
18 bits: tca6418
@@ -1317,6 +1317,15 @@ config GPIO_BD71828
This driver can also be built as a module. If so, the module
will be called gpio-bd71828.
+config GPIO_BD72720
+ tristate "ROHM BD72720 and BD73900 PMIC GPIO support"
+ depends on MFD_ROHM_BD71828
+ help
+ Support for GPIO on ROHM BD72720 and BD73900 PMICs. There are two
+ pins which can be configured to GPI or GPO, and three pins which can
+ be configured to GPO on the ROHM PMIC. The pin configuration is done
+ on OTP at manufacturing.
+
config GPIO_BD9571MWV
tristate "ROHM BD9571 GPIO support"
depends on MFD_BD9571MWV
@@ -1994,6 +2003,15 @@ config GPIO_LATCH
Say yes here to enable a driver for GPIO multiplexers based on latches
connected to other GPIOs.
+config GPIO_LINE_MUX
+ tristate "GPIO line mux driver"
+ depends on OF_GPIO
+ select MULTIPLEXER
+ help
+ Say Y here to support the GPIO line mux, which can provide virtual
+ GPIOs backed by a shared real GPIO and a multiplexer in a 1-to-many
+ fashion.
+
config GPIO_MOCKUP
tristate "GPIO Testing Driver (DEPRECATED)"
select IRQ_SIM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2421a8fd3733..c05f7d795c43 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
+obj-$(CONFIG_GPIO_BD72720) += gpio-bd72720.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BLZP1600) += gpio-blzp1600.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
@@ -90,6 +91,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
+obj-$(CONFIG_GPIO_LINE_MUX) += gpio-line-mux.o
obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 416f265d09d0..a4cd32674a96 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -1226,7 +1226,7 @@ gpio_aggregator_line_release(struct config_item *item)
kfree(line);
}
-static struct configfs_item_operations gpio_aggregator_line_item_ops = {
+static const struct configfs_item_operations gpio_aggregator_line_item_ops = {
.release = gpio_aggregator_line_release,
};
@@ -1247,7 +1247,7 @@ static void gpio_aggregator_device_release(struct config_item *item)
gpio_aggregator_free(aggr);
}
-static struct configfs_item_operations gpio_aggregator_device_item_ops = {
+static const struct configfs_item_operations gpio_aggregator_device_item_ops = {
.release = gpio_aggregator_device_release,
};
@@ -1292,7 +1292,7 @@ gpio_aggregator_device_make_group(struct config_group *group, const char *name)
return &line->group;
}
-static struct configfs_group_operations gpio_aggregator_device_group_ops = {
+static const struct configfs_group_operations gpio_aggregator_device_group_ops = {
.make_group = gpio_aggregator_device_make_group,
};
@@ -1328,7 +1328,7 @@ gpio_aggregator_make_group(struct config_group *group, const char *name)
return &aggr->group;
}
-static struct configfs_group_operations gpio_aggregator_group_ops = {
+static const struct configfs_group_operations gpio_aggregator_group_ops = {
.make_group = gpio_aggregator_make_group,
};
diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c
index 7622f9e9f54a..4225261f61c8 100644
--- a/drivers/gpio/gpio-aspeed-sgpio.c
+++ b/drivers/gpio/gpio-aspeed-sgpio.c
@@ -19,7 +19,31 @@
#include <linux/spinlock.h>
#include <linux/string.h>
-#define ASPEED_SGPIO_CTRL 0x54
+#define SGPIO_G7_IRQ_STS_BASE 0x40
+#define SGPIO_G7_IRQ_STS_OFFSET(x) (SGPIO_G7_IRQ_STS_BASE + (x) * 0x4)
+#define SGPIO_G7_CTRL_REG_BASE 0x80
+#define SGPIO_G7_CTRL_REG_OFFSET(x) (SGPIO_G7_CTRL_REG_BASE + (x) * 0x4)
+#define SGPIO_G7_OUT_DATA BIT(0)
+#define SGPIO_G7_PARALLEL_OUT_DATA BIT(1)
+#define SGPIO_G7_IRQ_EN BIT(2)
+#define SGPIO_G7_IRQ_TYPE0 BIT(3)
+#define SGPIO_G7_IRQ_TYPE1 BIT(4)
+#define SGPIO_G7_IRQ_TYPE2 BIT(5)
+#define SGPIO_G7_RST_TOLERANCE BIT(6)
+#define SGPIO_G7_INPUT_MASK BIT(9)
+#define SGPIO_G7_HW_BYPASS_EN BIT(10)
+#define SGPIO_G7_HW_IN_SEL BIT(11)
+#define SGPIO_G7_IRQ_STS BIT(12)
+#define SGPIO_G7_IN_DATA BIT(13)
+#define SGPIO_G7_PARALLEL_IN_DATA BIT(14)
+#define SGPIO_G7_SERIAL_OUT_SEL GENMASK(17, 16)
+#define SGPIO_G7_PARALLEL_OUT_SEL GENMASK(19, 18)
+#define SELECT_FROM_CSR 0
+#define SELECT_FROM_PARALLEL_IN 1
+#define SELECT_FROM_SERIAL_IN 2
+
+#define ASPEED_SGPIO_G4_CFG_OFFSET 0x54
+#define ASPEED_SGPIO_G7_CFG_OFFSET 0x0
#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
#define ASPEED_SGPIO_ENABLE BIT(0)
@@ -27,6 +51,8 @@
struct aspeed_sgpio_pdata {
const u32 pin_mask;
+ const struct aspeed_sgpio_llops *llops;
+ const u32 cfg_offset;
};
struct aspeed_sgpio {
@@ -36,6 +62,7 @@ struct aspeed_sgpio {
raw_spinlock_t lock;
void __iomem *base;
int irq;
+ const struct aspeed_sgpio_pdata *pdata;
};
struct aspeed_sgpio_bank {
@@ -43,7 +70,6 @@ struct aspeed_sgpio_bank {
u16 rdata_reg;
u16 irq_regs;
u16 tolerance_regs;
- const char names[4][3];
};
/*
@@ -59,28 +85,24 @@ static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
.rdata_reg = 0x0070,
.irq_regs = 0x0004,
.tolerance_regs = 0x0018,
- .names = { "A", "B", "C", "D" },
},
{
.val_regs = 0x001C,
.rdata_reg = 0x0074,
.irq_regs = 0x0020,
.tolerance_regs = 0x0034,
- .names = { "E", "F", "G", "H" },
},
{
.val_regs = 0x0038,
.rdata_reg = 0x0078,
.irq_regs = 0x003C,
.tolerance_regs = 0x0050,
- .names = { "I", "J", "K", "L" },
},
{
.val_regs = 0x0090,
.rdata_reg = 0x007C,
.irq_regs = 0x0094,
.tolerance_regs = 0x00A8,
- .names = { "M", "N", "O", "P" },
},
};
@@ -95,6 +117,15 @@ enum aspeed_sgpio_reg {
reg_tolerance,
};
+struct aspeed_sgpio_llops {
+ void (*reg_bit_set)(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg, bool val);
+ bool (*reg_bit_get)(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg);
+ int (*reg_bank_get)(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg);
+};
+
#define GPIO_VAL_VALUE 0x00
#define GPIO_IRQ_ENABLE 0x00
#define GPIO_IRQ_TYPE0 0x04
@@ -102,9 +133,9 @@ enum aspeed_sgpio_reg {
#define GPIO_IRQ_TYPE2 0x0C
#define GPIO_IRQ_STATUS 0x10
-static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
- const struct aspeed_sgpio_bank *bank,
- const enum aspeed_sgpio_reg reg)
+static void __iomem *aspeed_sgpio_g4_bank_reg(struct aspeed_sgpio *gpio,
+ const struct aspeed_sgpio_bank *bank,
+ const enum aspeed_sgpio_reg reg)
{
switch (reg) {
case reg_val:
@@ -129,6 +160,30 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
}
}
+static u32 aspeed_sgpio_g7_reg_mask(const enum aspeed_sgpio_reg reg)
+{
+ switch (reg) {
+ case reg_val:
+ case reg_rdata:
+ return SGPIO_G7_OUT_DATA;
+ case reg_irq_enable:
+ return SGPIO_G7_IRQ_EN;
+ case reg_irq_type0:
+ return SGPIO_G7_IRQ_TYPE0;
+ case reg_irq_type1:
+ return SGPIO_G7_IRQ_TYPE1;
+ case reg_irq_type2:
+ return SGPIO_G7_IRQ_TYPE2;
+ case reg_irq_status:
+ return SGPIO_G7_IRQ_STS;
+ case reg_tolerance:
+ return SGPIO_G7_RST_TOLERANCE;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
#define GPIO_BANK(x) ((x) >> 6)
#define GPIO_OFFSET(x) ((x) & GENMASK(5, 0))
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1)
@@ -170,14 +225,13 @@ static bool aspeed_sgpio_is_input(unsigned int offset)
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
- const struct aspeed_sgpio_bank *bank = to_bank(offset);
enum aspeed_sgpio_reg reg;
int rc = 0;
guard(raw_spinlock_irqsave)(&gpio->lock);
reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
- rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
+ rc = gpio->pdata->llops->reg_bit_get(gpio, offset, reg);
return rc;
}
@@ -185,26 +239,11 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
- const struct aspeed_sgpio_bank *bank = to_bank(offset);
- void __iomem *addr_r, *addr_w;
- u32 reg = 0;
if (aspeed_sgpio_is_input(offset))
return -EINVAL;
- /* Since this is an output, read the cached value from rdata, then
- * update val. */
- addr_r = bank_reg(gpio, bank, reg_rdata);
- addr_w = bank_reg(gpio, bank, reg_val);
-
- reg = ioread32(addr_r);
-
- if (val)
- reg |= GPIO_BIT(offset);
- else
- reg &= ~GPIO_BIT(offset);
-
- iowrite32(reg, addr_w);
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val);
return 0;
}
@@ -243,69 +282,34 @@ static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
return !!aspeed_sgpio_is_input(offset);
}
-static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
- struct aspeed_sgpio **gpio,
- const struct aspeed_sgpio_bank **bank,
- u32 *bit, int *offset)
-{
- struct aspeed_sgpio *internal;
-
- *offset = irqd_to_hwirq(d);
- internal = irq_data_get_irq_chip_data(d);
- WARN_ON(!internal);
-
- *gpio = internal;
- *bank = to_bank(*offset);
- *bit = GPIO_BIT(*offset);
-}
static void aspeed_sgpio_irq_ack(struct irq_data *d)
{
- const struct aspeed_sgpio_bank *bank;
- struct aspeed_sgpio *gpio;
- void __iomem *status_addr;
- int offset;
- u32 bit;
-
- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
-
- status_addr = bank_reg(gpio, bank, reg_irq_status);
+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
+ int offset = irqd_to_hwirq(d);
guard(raw_spinlock_irqsave)(&gpio->lock);
- iowrite32(bit, status_addr);
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_status, 1);
}
static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
{
- const struct aspeed_sgpio_bank *bank;
- struct aspeed_sgpio *gpio;
- u32 reg, bit;
- void __iomem *addr;
- int offset;
-
- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
- addr = bank_reg(gpio, bank, reg_irq_enable);
+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
+ int offset = irqd_to_hwirq(d);
/* Unmasking the IRQ */
if (set)
- gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
-
- scoped_guard(raw_spinlock_irqsave, &gpio->lock) {
- reg = ioread32(addr);
- if (set)
- reg |= bit;
- else
- reg &= ~bit;
-
- iowrite32(reg, addr);
+ gpiochip_enable_irq(&gpio->chip, offset);
+ scoped_guard(raw_spinlock_irqsave, &gpio->lock)
+ {
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_enable,
+ set);
}
/* Masking the IRQ */
if (!set)
- gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
-
-
+ gpiochip_disable_irq(&gpio->chip, offset);
}
static void aspeed_sgpio_irq_mask(struct irq_data *d)
@@ -323,30 +327,25 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
u32 type0 = 0;
u32 type1 = 0;
u32 type2 = 0;
- u32 bit, reg;
- const struct aspeed_sgpio_bank *bank;
irq_flow_handler_t handler;
- struct aspeed_sgpio *gpio;
- void __iomem *addr;
- int offset;
-
- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
+ int offset = irqd_to_hwirq(d);
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_BOTH:
- type2 |= bit;
+ type2 = 1;
fallthrough;
case IRQ_TYPE_EDGE_RISING:
- type0 |= bit;
+ type0 = 1;
fallthrough;
case IRQ_TYPE_EDGE_FALLING:
handler = handle_edge_irq;
break;
case IRQ_TYPE_LEVEL_HIGH:
- type0 |= bit;
+ type0 = 1;
fallthrough;
case IRQ_TYPE_LEVEL_LOW:
- type1 |= bit;
+ type1 = 1;
handler = handle_level_irq;
break;
default:
@@ -354,20 +353,9 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
}
scoped_guard(raw_spinlock_irqsave, &gpio->lock) {
- addr = bank_reg(gpio, bank, reg_irq_type0);
- reg = ioread32(addr);
- reg = (reg & ~bit) | type0;
- iowrite32(reg, addr);
-
- addr = bank_reg(gpio, bank, reg_irq_type1);
- reg = ioread32(addr);
- reg = (reg & ~bit) | type1;
- iowrite32(reg, addr);
-
- addr = bank_reg(gpio, bank, reg_irq_type2);
- reg = ioread32(addr);
- reg = (reg & ~bit) | type2;
- iowrite32(reg, addr);
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0);
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1);
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2);
}
irq_set_handler_locked(d, handler);
@@ -380,15 +368,14 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct irq_chip *ic = irq_desc_get_chip(desc);
struct aspeed_sgpio *data = gpiochip_get_data(gc);
- unsigned int i, p;
+ unsigned int i, p, banks;
unsigned long reg;
chained_irq_enter(ic, desc);
- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
- const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
-
- reg = ioread32(bank_reg(data, bank, reg_irq_status));
+ banks = DIV_ROUND_UP(gc->ngpio, 64);
+ for (i = 0; i < banks; i++) {
+ reg = data->pdata->llops->reg_bank_get(data, i << 6, reg_irq_status);
for_each_set_bit(p, &reg, 32)
generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2);
@@ -399,12 +386,8 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
{
- const struct aspeed_sgpio_bank *bank;
- struct aspeed_sgpio *gpio;
- u32 bit;
- int offset;
+ struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
- irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
seq_puts(p, dev_name(gpio->dev));
}
@@ -422,7 +405,6 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
struct platform_device *pdev)
{
int rc, i;
- const struct aspeed_sgpio_bank *bank;
struct gpio_irq_chip *irq;
rc = platform_get_irq(pdev, 0);
@@ -432,12 +414,11 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
gpio->irq = rc;
/* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */
- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
- bank = &aspeed_sgpio_banks[i];
+ for (i = 0; i < gpio->chip.ngpio; i += 2) {
/* disable irq enable bits */
- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_enable, 0);
/* clear status bits */
- iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_status, 1);
}
irq = &gpio->chip.irq;
@@ -451,42 +432,91 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
irq->num_parents = 1;
/* Apply default IRQ settings */
- for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
- bank = &aspeed_sgpio_banks[i];
+ for (i = 0; i < gpio->chip.ngpio; i += 2) {
/* set falling or level-low irq */
- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type0, 0);
/* trigger type is edge */
- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type1, 0);
/* single edge trigger */
- iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
+ gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type2, 0);
}
return 0;
}
+static void aspeed_sgpio_g4_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg, bool val)
+{
+ const struct aspeed_sgpio_bank *bank = to_bank(offset);
+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
+ u32 temp;
+
+ if (reg == reg_val) {
+ /* Since this is an output, read the cached value from rdata, then update val. */
+ addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_rdata);
+ temp = ioread32(addr);
+ if (val)
+ temp |= GPIO_BIT(offset);
+ else
+ temp &= ~GPIO_BIT(offset);
+
+ addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_val);
+ iowrite32(temp, addr);
+ } else if (reg == reg_irq_status) {
+ if (val)
+ iowrite32(GPIO_BIT(offset), addr);
+ } else {
+ /* When setting other registers, we read from the register itself */
+ temp = ioread32(addr);
+ if (val)
+ temp |= GPIO_BIT(offset);
+ else
+ temp &= ~GPIO_BIT(offset);
+ iowrite32(temp, addr);
+ }
+}
+
+static bool aspeed_sgpio_g4_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg)
+{
+ const struct aspeed_sgpio_bank *bank = to_bank(offset);
+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
+
+ return !!(ioread32(addr) & GPIO_BIT(offset));
+}
+
+static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg)
+{
+ const struct aspeed_sgpio_bank *bank = to_bank(offset);
+ void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
+
+ if (reg == reg_irq_status)
+ return ioread32(addr);
+ else
+ return -EOPNOTSUPP;
+}
+
+static const struct aspeed_sgpio_llops aspeed_sgpio_g4_llops = {
+ .reg_bit_set = aspeed_sgpio_g4_reg_bit_set,
+ .reg_bit_get = aspeed_sgpio_g4_reg_bit_get,
+ .reg_bank_get = aspeed_sgpio_g4_reg_bank_get,
+};
+
static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = {
.pin_mask = GENMASK(9, 6),
+ .llops = &aspeed_sgpio_g4_llops,
+ .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET,
};
static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
unsigned int offset, bool enable)
{
struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
- void __iomem *reg;
- u32 val;
-
- reg = bank_reg(gpio, to_bank(offset), reg_tolerance);
guard(raw_spinlock_irqsave)(&gpio->lock);
- val = readl(reg);
-
- if (enable)
- val |= GPIO_BIT(offset);
- else
- val &= ~GPIO_BIT(offset);
-
- writel(val, reg);
+ gpio->pdata->llops->reg_bit_set(gpio, offset, reg_tolerance, enable);
return 0;
}
@@ -505,21 +535,77 @@ static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = {
.pin_mask = GENMASK(10, 6),
+ .llops = &aspeed_sgpio_g4_llops,
+ .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET,
+};
+
+static void aspeed_sgpio_g7_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg, bool val)
+{
+ u32 mask = aspeed_sgpio_g7_reg_mask(reg);
+ void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1);
+ u32 write_val;
+
+ if (mask) {
+ write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val);
+ iowrite32(write_val, addr);
+ }
+}
+
+static bool aspeed_sgpio_g7_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg)
+{
+ u32 mask = aspeed_sgpio_g7_reg_mask(reg);
+ void __iomem *addr;
+
+ addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1);
+ if (reg == reg_val)
+ mask = SGPIO_G7_IN_DATA;
+
+ if (mask)
+ return field_get(mask, ioread32(addr));
+ else
+ return 0;
+}
+
+static int aspeed_sgpio_g7_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset,
+ const enum aspeed_sgpio_reg reg)
+{
+ void __iomem *addr;
+
+ if (reg == reg_irq_status) {
+ addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(offset >> 6);
+ return ioread32(addr);
+ } else {
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct aspeed_sgpio_llops aspeed_sgpio_g7_llops = {
+ .reg_bit_set = aspeed_sgpio_g7_reg_bit_set,
+ .reg_bit_get = aspeed_sgpio_g7_reg_bit_get,
+ .reg_bank_get = aspeed_sgpio_g7_reg_bank_get,
+};
+
+static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = {
+ .pin_mask = GENMASK(11, 6),
+ .llops = &aspeed_sgpio_g7_llops,
+ .cfg_offset = ASPEED_SGPIO_G7_CFG_OFFSET,
};
static const struct of_device_id aspeed_sgpio_of_table[] = {
{ .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, },
{ .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, },
{ .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, },
+ { .compatible = "aspeed,ast2700-sgpiom", .data = &ast2700_sgpiom_pdata, },
{}
};
MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
-static int __init aspeed_sgpio_probe(struct platform_device *pdev)
+static int aspeed_sgpio_probe(struct platform_device *pdev)
{
u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask;
- const struct aspeed_sgpio_pdata *pdata;
struct aspeed_sgpio *gpio;
unsigned long apb_freq;
int rc;
@@ -534,12 +620,11 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
gpio->dev = &pdev->dev;
- pdata = device_get_match_data(&pdev->dev);
- if (!pdata)
+ gpio->pdata = device_get_match_data(&pdev->dev);
+ if (!gpio->pdata)
return -EINVAL;
- pin_mask = pdata->pin_mask;
-
+ pin_mask = gpio->pdata->pin_mask;
rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios);
if (rc < 0) {
dev_err(&pdev->dev, "Could not read ngpios property\n");
@@ -583,7 +668,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask;
iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval |
- ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL);
+ ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset);
raw_spin_lock_init(&gpio->lock);
@@ -611,11 +696,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
}
static struct platform_driver aspeed_sgpio_driver = {
+ .probe = aspeed_sgpio_probe,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = aspeed_sgpio_of_table,
},
};
-module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
+module_platform_driver(aspeed_sgpio_driver);
MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index cbdf781994dc..9115e56a1626 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -1302,7 +1302,6 @@ MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
static int aspeed_gpio_probe(struct platform_device *pdev)
{
- const struct of_device_id *gpio_id;
struct gpio_irq_chip *girq;
struct aspeed_gpio *gpio;
int rc, irq, i, banks, err;
@@ -1320,8 +1319,8 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
raw_spin_lock_init(&gpio->lock);
- gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
- if (!gpio_id)
+ gpio->config = device_get_match_data(&pdev->dev);
+ if (!gpio->config)
return -EINVAL;
gpio->clk = devm_clk_get_enabled(&pdev->dev, NULL);
@@ -1331,8 +1330,6 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
gpio->clk = NULL;
}
- gpio->config = gpio_id->data;
-
if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get ||
!gpio->config->llops->reg_bank_get)
return -EINVAL;
diff --git a/drivers/gpio/gpio-bd72720.c b/drivers/gpio/gpio-bd72720.c
new file mode 100644
index 000000000000..6549dbf4c7ad
--- /dev/null
+++ b/drivers/gpio/gpio-bd72720.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support to GPIOs on ROHM BD72720 and BD79300
+ * Copyright 2025 ROHM Semiconductors.
+ * Author: Matti Vaittinen <mazziesaccount@gmail.com>
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/rohm-bd72720.h>
+
+#define BD72720_GPIO_OPEN_DRAIN 0
+#define BD72720_GPIO_CMOS BIT(1)
+#define BD72720_INT_GPIO1_IN_SRC 4
+/*
+ * The BD72720 has several "one time programmable" (OTP) configurations which
+ * can be set at manufacturing phase. A set of these options allow using pins
+ * as GPIO. The OTP configuration can't be read at run-time, so drivers rely on
+ * device-tree to advertise the correct options.
+ *
+ * Both DVS[0,1] pins can be configured to be used for:
+ * - OTP0: regulator RUN state control
+ * - OTP1: GPI
+ * - OTP2: GPO
+ * - OTP3: Power sequencer output
+ * Data-sheet also states that these PINs can always be used for IRQ but the
+ * driver limits this by allowing them to be used for IRQs with OTP1 only.
+ *
+ * Pins GPIO_EXTEN0 (GPIO3), GPIO_EXTEN1 (GPIO4), GPIO_FAULT_B (GPIO5) have OTP
+ * options for a specific (non GPIO) purposes, but also an option to configure
+ * them to be used as a GPO.
+ *
+ * OTP settings can be separately configured for each pin.
+ *
+ * DT properties:
+ * "rohm,pin-dvs0" and "rohm,pin-dvs1" can be set to one of the values:
+ * "dvs-input", "gpi", "gpo".
+ *
+ * "rohm,pin-exten0", "rohm,pin-exten1" and "rohm,pin-fault_b" can be set to:
+ * "gpo"
+ */
+
+enum bd72720_gpio_state {
+ BD72720_PIN_UNKNOWN,
+ BD72720_PIN_GPI,
+ BD72720_PIN_GPO,
+};
+
+enum {
+ BD72720_GPIO1,
+ BD72720_GPIO2,
+ BD72720_GPIO3,
+ BD72720_GPIO4,
+ BD72720_GPIO5,
+ BD72720_GPIO_EPDEN,
+ BD72720_NUM_GPIOS
+};
+
+struct bd72720_gpio {
+ /* chip.parent points the MFD which provides DT node and regmap */
+ struct gpio_chip chip;
+ /* dev points to the platform device for devm and prints */
+ struct device *dev;
+ struct regmap *regmap;
+ int gpio_is_input;
+};
+
+static int bd72720gpi_get(struct bd72720_gpio *bdgpio, unsigned int reg_offset)
+{
+ int ret, val, shift;
+
+ ret = regmap_read(bdgpio->regmap, BD72720_REG_INT_ETC1_SRC, &val);
+ if (ret)
+ return ret;
+
+ shift = BD72720_INT_GPIO1_IN_SRC + reg_offset;
+
+ return (val >> shift) & 1;
+}
+
+static int bd72720gpo_get(struct bd72720_gpio *bdgpio,
+ unsigned int offset)
+{
+ const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+ BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+ BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+ int ret, val;
+
+ ret = regmap_read(bdgpio->regmap, regs[offset], &val);
+ if (ret)
+ return ret;
+
+ return val & BD72720_GPIO_HIGH;
+}
+
+static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+
+ if (BIT(offset) & bdgpio->gpio_is_input)
+ return bd72720gpi_get(bdgpio, offset);
+
+ return bd72720gpo_get(bdgpio, offset);
+}
+
+static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+ const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+ BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+ BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+
+ if (BIT(offset) & bdgpio->gpio_is_input) {
+ dev_dbg(bdgpio->dev, "pin %d not output.\n", offset);
+ return -EINVAL;
+ }
+
+ if (value)
+ return regmap_set_bits(bdgpio->regmap, regs[offset],
+ BD72720_GPIO_HIGH);
+
+ return regmap_clear_bits(bdgpio->regmap, regs[offset],
+ BD72720_GPIO_HIGH);
+}
+
+static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+ const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+ BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+ BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+
+ /*
+ * We can only set the output mode, which makes sense only when output
+ * OTP configuration is used.
+ */
+ if (BIT(offset) & bdgpio->gpio_is_input)
+ return -ENOTSUPP;
+
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ return regmap_update_bits(bdgpio->regmap,
+ regs[offset],
+ BD72720_GPIO_DRIVE_MASK,
+ BD72720_GPIO_OPEN_DRAIN);
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return regmap_update_bits(bdgpio->regmap,
+ regs[offset],
+ BD72720_GPIO_DRIVE_MASK,
+ BD72720_GPIO_CMOS);
+ default:
+ break;
+ }
+
+ return -ENOTSUPP;
+}
+
+static int bd72720gpo_direction_get(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+
+ if (BIT(offset) & bdgpio->gpio_is_input)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int bd72720_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ static const char * const properties[] = {
+ "rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0",
+ "rohm,pin-exten1", "rohm,pin-fault_b"
+ };
+ struct bd72720_gpio *g = gpiochip_get_data(gc);
+ const char *val;
+ int i, ret;
+
+ *valid_mask = BIT(BD72720_GPIO_EPDEN);
+
+ if (!gc->parent)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(properties); i++) {
+ ret = fwnode_property_read_string(dev_fwnode(gc->parent),
+ properties[i], &val);
+
+ if (ret) {
+ if (ret == -EINVAL)
+ continue;
+
+ dev_err(g->dev, "pin %d (%s), bad configuration\n", i,
+ properties[i]);
+
+ return ret;
+ }
+
+ if (strcmp(val, "gpi") == 0) {
+ if (i != BD72720_GPIO1 && i != BD72720_GPIO2) {
+ dev_warn(g->dev,
+ "pin %d (%s) does not support INPUT mode",
+ i, properties[i]);
+ continue;
+ }
+
+ *valid_mask |= BIT(i);
+ g->gpio_is_input |= BIT(i);
+ } else if (strcmp(val, "gpo") == 0) {
+ *valid_mask |= BIT(i);
+ }
+ }
+
+ return 0;
+}
+
+/* Template for GPIO chip */
+static const struct gpio_chip bd72720gpo_chip = {
+ .label = "bd72720",
+ .owner = THIS_MODULE,
+ .get = bd72720gpio_get,
+ .get_direction = bd72720gpo_direction_get,
+ .set = bd72720gpo_set,
+ .set_config = bd72720_gpio_set_config,
+ .init_valid_mask = bd72720_valid_mask,
+ .can_sleep = true,
+ .ngpio = BD72720_NUM_GPIOS,
+ .base = -1,
+};
+
+static int gpo_bd72720_probe(struct platform_device *pdev)
+{
+ struct bd72720_gpio *g;
+ struct device *parent, *dev;
+
+ /*
+ * Bind devm lifetime to this platform device => use dev for devm.
+ * also the prints should originate from this device.
+ */
+ dev = &pdev->dev;
+ /* The device-tree and regmap come from MFD => use parent for that */
+ parent = dev->parent;
+
+ g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
+ if (!g)
+ return -ENOMEM;
+
+ g->chip = bd72720gpo_chip;
+ g->dev = dev;
+ g->chip.parent = parent;
+ g->regmap = dev_get_regmap(parent, NULL);
+
+ return devm_gpiochip_add_data(dev, &g->chip, g);
+}
+
+static const struct platform_device_id bd72720_gpio_id[] = {
+ { "bd72720-gpio" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
+
+static struct platform_driver gpo_bd72720_driver = {
+ .driver = {
+ .name = "bd72720-gpio",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = gpo_bd72720_probe,
+ .id_table = bd72720_gpio_id,
+};
+module_platform_driver(gpo_bd72720_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c
index b75734ca22dd..d7790fc35c22 100644
--- a/drivers/gpio/gpio-cadence.c
+++ b/drivers/gpio/gpio-cadence.c
@@ -2,6 +2,7 @@
/*
* Copyright 2017-2018 Cadence
+ * Copyright (C) 2025 Axiado Corporation.
*
* Authors:
* Jan Kotas <jank@cadence.com>
@@ -31,10 +32,23 @@
#define CDNS_GPIO_IRQ_VALUE 0x28
#define CDNS_GPIO_IRQ_ANY_EDGE 0x2c
+struct cdns_gpio_quirks {
+ bool skip_init;
+};
+
struct cdns_gpio_chip {
struct gpio_generic_chip gen_gc;
void __iomem *regs;
u32 bypass_orig;
+ const struct cdns_gpio_quirks *quirks;
+};
+
+static const struct cdns_gpio_quirks cdns_default_quirks = {
+ .skip_init = false,
+};
+
+static const struct cdns_gpio_quirks ax3000_gpio_quirks = {
+ .skip_init = true,
};
static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset)
@@ -84,6 +98,7 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
u32 int_value;
u32 int_type;
+ u32 int_any;
u32 mask = BIT(d->hwirq);
int ret = 0;
@@ -91,24 +106,35 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask;
int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask;
-
/*
- * The GPIO controller doesn't have an ACK register.
- * All interrupt statuses are cleared on a status register read.
- * Don't support edge interrupts for now.
+ * Interrupt polarity and trigger behaviour is configured like this:
+ *
+ * (type, value)
+ * (0, 0) = Falling edge triggered
+ * (0, 1) = Rising edge triggered
+ * (1, 0) = Low level triggered
+ * (1, 1) = High level triggered
*/
+ int_any = ioread32(cgpio->regs + CDNS_GPIO_IRQ_ANY_EDGE) & ~mask;
if (type == IRQ_TYPE_LEVEL_HIGH) {
int_type |= mask;
int_value |= mask;
} else if (type == IRQ_TYPE_LEVEL_LOW) {
int_type |= mask;
+ } else if (type == IRQ_TYPE_EDGE_RISING) {
+ int_value |= mask;
+ } else if (type == IRQ_TYPE_EDGE_FALLING) {
+ /* edge trigger, int_value remains cleared for falling */
+ } else if (type == IRQ_TYPE_EDGE_BOTH) {
+ int_any |= mask;
} else {
return -EINVAL;
}
iowrite32(int_value, cgpio->regs + CDNS_GPIO_IRQ_VALUE);
iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE);
+ iowrite32(int_any, cgpio->regs + CDNS_GPIO_IRQ_ANY_EDGE);
return ret;
}
@@ -141,6 +167,19 @@ static const struct irq_chip cdns_gpio_irqchip = {
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
+static const struct of_device_id cdns_of_ids[] = {
+ {
+ .compatible = "axiado,ax3000-gpio",
+ .data = &ax3000_gpio_quirks
+ },
+ {
+ .compatible = "cdns,gpio-r1p02",
+ .data = &cdns_default_quirks
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, cdns_of_ids);
+
static int cdns_gpio_probe(struct platform_device *pdev)
{
struct gpio_generic_chip_config config = { };
@@ -165,6 +204,10 @@ static int cdns_gpio_probe(struct platform_device *pdev)
return -EINVAL;
}
+ cgpio->quirks = device_get_match_data(&pdev->dev);
+ if (!cgpio->quirks)
+ cgpio->quirks = &cdns_default_quirks;
+
/*
* Set all pins as inputs by default, otherwise:
* gpiochip_lock_as_irq:
@@ -173,8 +216,15 @@ static int cdns_gpio_probe(struct platform_device *pdev)
* so it needs to be changed before gpio_generic_chip_init() is called.
*/
dir_prev = ioread32(cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
- iowrite32(GENMASK(num_gpios - 1, 0),
- cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
+
+ /*
+ * The AX3000 platform performs the required configuration at boot time
+ * before Linux boots, so this quirk disables pinmux initialization.
+ */
+ if (!cgpio->quirks->skip_init) {
+ iowrite32(GENMASK(num_gpios - 1, 0),
+ cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
+ }
config.dev = &pdev->dev;
config.sz = 4;
@@ -240,9 +290,11 @@ static int cdns_gpio_probe(struct platform_device *pdev)
/*
* Enable gpio outputs, ignored for input direction
*/
- iowrite32(GENMASK(num_gpios - 1, 0),
- cgpio->regs + CDNS_GPIO_OUTPUT_EN);
- iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
+ if (!cgpio->quirks->skip_init) {
+ iowrite32(GENMASK(num_gpios - 1, 0),
+ cgpio->regs + CDNS_GPIO_OUTPUT_EN);
+ iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
+ }
platform_set_drvdata(pdev, cgpio);
return 0;
@@ -260,12 +312,6 @@ static void cdns_gpio_remove(struct platform_device *pdev)
iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
}
-static const struct of_device_id cdns_of_ids[] = {
- { .compatible = "cdns,gpio-r1p02" },
- { /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, cdns_of_ids);
-
static struct platform_driver cdns_gpio_driver = {
.driver = {
.name = "cdns-gpio",
diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c
index f8ea961fa1de..157ab90f5ba8 100644
--- a/drivers/gpio/gpio-creg-snps.c
+++ b/drivers/gpio/gpio-creg-snps.c
@@ -134,7 +134,6 @@ static const struct of_device_id creg_gpio_ids[] = {
static int creg_gpio_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct creg_gpio *hcg;
u32 ngpios;
@@ -148,8 +147,7 @@ static int creg_gpio_probe(struct platform_device *pdev)
if (IS_ERR(hcg->regs))
return PTR_ERR(hcg->regs);
- match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
- hcg->layout = match->data;
+ hcg->layout = device_get_match_data(dev);
if (!hcg->layout)
return -EINVAL;
diff --git a/drivers/gpio/gpio-line-mux.c b/drivers/gpio/gpio-line-mux.c
new file mode 100644
index 000000000000..62548fbd3ca0
--- /dev/null
+++ b/drivers/gpio/gpio-line-mux.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO line mux which acts as virtual gpiochip and provides a 1-to-many
+ * mapping between virtual GPIOs and a real GPIO + multiplexer.
+ *
+ * Copyright (c) 2025 Jonas Jelonek <jelonek.jonas@gmail.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/mux/consumer.h>
+#include <linux/platform_device.h>
+
+#define MUX_SELECT_DELAY_US 100
+
+struct gpio_lmux {
+ struct gpio_chip gc;
+ struct mux_control *mux;
+ struct gpio_desc *muxed_gpio;
+
+ u32 num_gpio_mux_states;
+ unsigned int gpio_mux_states[] __counted_by(num_gpio_mux_states);
+};
+
+static int gpio_lmux_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct gpio_lmux *glm = gpiochip_get_data(gc);
+ int ret;
+
+ ret = mux_control_select_delay(glm->mux, glm->gpio_mux_states[offset],
+ MUX_SELECT_DELAY_US);
+ if (ret < 0)
+ return ret;
+
+ ret = gpiod_get_raw_value_cansleep(glm->muxed_gpio);
+ mux_control_deselect(glm->mux);
+ return ret;
+}
+
+static int gpio_lmux_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int gpio_lmux_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_lmux *glm;
+ unsigned int ngpio;
+ size_t size;
+ int ret;
+
+ ngpio = device_property_count_u32(dev, "gpio-line-mux-states");
+ if (!ngpio)
+ return -EINVAL;
+
+ size = struct_size(glm, gpio_mux_states, ngpio);
+ glm = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (!glm)
+ return -ENOMEM;
+
+ glm->gc.base = -1;
+ glm->gc.can_sleep = true;
+ glm->gc.fwnode = dev_fwnode(dev);
+ glm->gc.label = dev_name(dev);
+ glm->gc.ngpio = ngpio;
+ glm->gc.owner = THIS_MODULE;
+ glm->gc.parent = dev;
+
+ glm->gc.get = gpio_lmux_gpio_get;
+ glm->gc.get_direction = gpio_lmux_gpio_get_direction;
+
+ glm->mux = devm_mux_control_get(dev, NULL);
+ if (IS_ERR(glm->mux))
+ return dev_err_probe(dev, PTR_ERR(glm->mux),
+ "could not get mux controller\n");
+
+ glm->muxed_gpio = devm_gpiod_get(dev, "muxed", GPIOD_IN);
+ if (IS_ERR(glm->muxed_gpio))
+ return dev_err_probe(dev, PTR_ERR(glm->muxed_gpio),
+ "could not get muxed-gpio\n");
+
+ glm->num_gpio_mux_states = ngpio;
+ ret = device_property_read_u32_array(dev, "gpio-line-mux-states",
+ &glm->gpio_mux_states[0], ngpio);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not get mux states\n");
+
+ ret = devm_gpiochip_add_data(dev, &glm->gc, glm);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add gpiochip\n");
+
+ return 0;
+}
+
+static const struct of_device_id gpio_lmux_of_match[] = {
+ { .compatible = "gpio-line-mux" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpio_lmux_of_match);
+
+static struct platform_driver gpio_lmux_driver = {
+ .driver = {
+ .name = "gpio-line-mux",
+ .of_match_table = gpio_lmux_of_match,
+ },
+ .probe = gpio_lmux_probe,
+};
+module_platform_driver(gpio_lmux_driver);
+
+MODULE_AUTHOR("Jonas Jelonek <jelonek.jonas@gmail.com>");
+MODULE_DESCRIPTION("GPIO line mux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index 02eca400b307..e6c85411c695 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -132,6 +132,24 @@ static const struct irq_chip max77620_gpio_irqchip = {
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
+static int max77620_gpio_get_dir(struct gpio_chip *gc, unsigned int offset)
+{
+ struct max77620_gpio *mgpio = gpiochip_get_data(gc);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val);
+ if (ret < 0) {
+ dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret);
+ return ret;
+ }
+
+ if (val & MAX77620_CNFG_GPIO_DIR_MASK)
+ return GPIO_LINE_DIRECTION_IN;
+ else
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
{
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
@@ -308,6 +326,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
mgpio->gpio_chip.label = pdev->name;
mgpio->gpio_chip.parent = pdev->dev.parent;
+ mgpio->gpio_chip.get_direction = max77620_gpio_get_dir;
mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
mgpio->gpio_chip.get = max77620_gpio_get;
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
diff --git a/drivers/gpio/gpio-max77759.c b/drivers/gpio/gpio-max77759.c
index 5e48eb03e7b3..3bf9f23d1532 100644
--- a/drivers/gpio/gpio-max77759.c
+++ b/drivers/gpio/gpio-max77759.c
@@ -435,8 +435,6 @@ static int max77759_gpio_probe(struct platform_device *pdev)
int irq;
struct gpio_irq_chip *girq;
int ret;
- unsigned long irq_flags;
- struct irq_data *irqd;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -486,13 +484,9 @@ static int max77759_gpio_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret,
"Failed to add GPIO chip\n");
- irq_flags = IRQF_ONESHOT | IRQF_SHARED;
- irqd = irq_get_irq_data(irq);
- if (irqd)
- irq_flags |= irqd_get_trigger_type(irqd);
-
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
- max77759_gpio_irqhandler, irq_flags,
+ max77759_gpio_irqhandler,
+ IRQF_ONESHOT | IRQF_SHARED,
dev_name(&pdev->dev), chip);
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c
index 52b13c6ae496..f51e7517f551 100644
--- a/drivers/gpio/gpio-menz127.c
+++ b/drivers/gpio/gpio-menz127.c
@@ -223,5 +223,4 @@ module_mcb_driver(men_z127_driver);
MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
MODULE_DESCRIPTION("MEN GPIO Controller");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("mcb:16z127");
MODULE_IMPORT_NS("MCB");
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index 5daf962b0323..edbcaad57d00 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -724,6 +724,7 @@ static const struct of_device_id gpio_mmio_of_match[] = {
{ .compatible = "wd,mbl-gpio" },
{ .compatible = "ni,169445-nand-gpio" },
{ .compatible = "intel,ixp4xx-expansion-bus-mmio-gpio" },
+ { .compatible = "opencores,gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, gpio_mmio_of_match);
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index f93a3dbb2daa..52e96cc5f67b 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -126,6 +126,9 @@ static const struct i2c_device_id pca953x_id[] = {
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
{ "xra1202", 8 | PCA953X_TYPE },
+
+ { "tcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
+ { "tcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
@@ -1469,6 +1472,9 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "ti,tca9538", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "ti,tcal6408", .data = OF_953X( 8, PCA_LATCH_INT), },
+ { .compatible = "ti,tcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
+
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "onnn,pca9655", .data = OF_953X(16, PCA_INT), },
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index c5a1287079a0..4a368803fb03 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -9,11 +9,16 @@
* Andrew F. Davis <afd@ti.com>
*/
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device/devres.h>
+#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
+#include <linux/types.h>
#define SLG7XL45106_GPO_REG 0xDB
@@ -94,7 +99,7 @@ static int pca9570_set(struct gpio_chip *chip, unsigned int offset, int value)
u8 buffer;
int ret;
- mutex_lock(&gpio->lock);
+ guard(mutex)(&gpio->lock);
buffer = gpio->out;
if (value)
@@ -104,18 +109,18 @@ static int pca9570_set(struct gpio_chip *chip, unsigned int offset, int value)
ret = pca9570_write(gpio, buffer);
if (ret)
- goto out;
+ return ret;
gpio->out = buffer;
-out:
- mutex_unlock(&gpio->lock);
- return ret;
+ return 0;
}
static int pca9570_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct pca9570 *gpio;
+ int ret;
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@@ -132,7 +137,9 @@ static int pca9570_probe(struct i2c_client *client)
gpio->chip.ngpio = gpio->chip_data->ngpio;
gpio->chip.can_sleep = true;
- mutex_init(&gpio->lock);
+ ret = devm_mutex_init(dev, &gpio->lock);
+ if (ret)
+ return ret;
/* Read the current output level */
pca9570_read(gpio, &gpio->out);
diff --git a/drivers/gpio/gpio-realtek-otto.c b/drivers/gpio/gpio-realtek-otto.c
index de527f4fc6c2..4cf91528f547 100644
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -359,8 +359,7 @@ static int realtek_gpio_probe(struct platform_device *pdev)
{
struct gpio_generic_chip_config config;
struct device *dev = &pdev->dev;
- unsigned long gen_gc_flags;
- unsigned int dev_flags;
+ unsigned long gen_gc_flags, dev_flags;
struct gpio_irq_chip *girq;
struct realtek_gpio_ctrl *ctrl;
struct resource *res;
@@ -372,7 +371,7 @@ static int realtek_gpio_probe(struct platform_device *pdev)
if (!ctrl)
return -ENOMEM;
- dev_flags = (unsigned int) device_get_match_data(dev);
+ dev_flags = (uintptr_t)device_get_match_data(dev);
ngpios = REALTEK_GPIO_MAX;
device_property_read_u32(dev, "ngpios", &ngpios);
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index a83f5238427c..437b4500f56b 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -1384,7 +1384,7 @@ static void gpio_sim_hog_config_item_release(struct config_item *item)
kfree(hog);
}
-static struct configfs_item_operations gpio_sim_hog_config_item_ops = {
+static const struct configfs_item_operations gpio_sim_hog_config_item_ops = {
.release = gpio_sim_hog_config_item_release,
};
@@ -1433,11 +1433,11 @@ static void gpio_sim_line_config_group_release(struct config_item *item)
kfree(line);
}
-static struct configfs_item_operations gpio_sim_line_config_item_ops = {
+static const struct configfs_item_operations gpio_sim_line_config_item_ops = {
.release = gpio_sim_line_config_group_release,
};
-static struct configfs_group_operations gpio_sim_line_config_group_ops = {
+static const struct configfs_group_operations gpio_sim_line_config_group_ops = {
.make_item = gpio_sim_line_config_make_hog_item,
};
@@ -1494,11 +1494,11 @@ static void gpio_sim_bank_config_group_release(struct config_item *item)
kfree(bank);
}
-static struct configfs_item_operations gpio_sim_bank_config_item_ops = {
+static const struct configfs_item_operations gpio_sim_bank_config_item_ops = {
.release = gpio_sim_bank_config_group_release,
};
-static struct configfs_group_operations gpio_sim_bank_config_group_ops = {
+static const struct configfs_group_operations gpio_sim_bank_config_group_ops = {
.make_group = gpio_sim_bank_config_make_line_group,
};
@@ -1549,11 +1549,11 @@ static void gpio_sim_device_config_group_release(struct config_item *item)
kfree(dev);
}
-static struct configfs_item_operations gpio_sim_device_config_item_ops = {
+static const struct configfs_item_operations gpio_sim_device_config_item_ops = {
.release = gpio_sim_device_config_group_release,
};
-static struct configfs_group_operations gpio_sim_device_config_group_ops = {
+static const struct configfs_group_operations gpio_sim_device_config_group_ops = {
.make_group = gpio_sim_device_config_make_bank_group,
};
@@ -1589,7 +1589,7 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name)
return &no_free_ptr(dev)->group;
}
-static struct configfs_group_operations gpio_sim_config_group_ops = {
+static const struct configfs_group_operations gpio_sim_config_group_ops = {
.make_group = gpio_sim_config_make_device_group,
};
diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
index eb66a15c002f..dbd2e81094b9 100644
--- a/drivers/gpio/gpio-spacemit-k1.c
+++ b/drivers/gpio/gpio-spacemit-k1.c
@@ -15,29 +15,37 @@
#include <linux/platform_device.h>
#include <linux/seq_file.h>
-/* register offset */
-#define SPACEMIT_GPLR 0x00 /* port level - R */
-#define SPACEMIT_GPDR 0x0c /* port direction - R/W */
-#define SPACEMIT_GPSR 0x18 /* port set - W */
-#define SPACEMIT_GPCR 0x24 /* port clear - W */
-#define SPACEMIT_GRER 0x30 /* port rising edge R/W */
-#define SPACEMIT_GFER 0x3c /* port falling edge R/W */
-#define SPACEMIT_GEDR 0x48 /* edge detect status - R/W1C */
-#define SPACEMIT_GSDR 0x54 /* (set) direction - W */
-#define SPACEMIT_GCDR 0x60 /* (clear) direction - W */
-#define SPACEMIT_GSRER 0x6c /* (set) rising edge detect enable - W */
-#define SPACEMIT_GCRER 0x78 /* (clear) rising edge detect enable - W */
-#define SPACEMIT_GSFER 0x84 /* (set) falling edge detect enable - W */
-#define SPACEMIT_GCFER 0x90 /* (clear) falling edge detect enable - W */
-#define SPACEMIT_GAPMASK 0x9c /* interrupt mask , 0 disable, 1 enable - R/W */
-
#define SPACEMIT_NR_BANKS 4
#define SPACEMIT_NR_GPIOS_PER_BANK 32
#define to_spacemit_gpio_bank(x) container_of((x), struct spacemit_gpio_bank, gc)
+#define to_spacemit_gpio_regs(gb) ((gb)->sg->data->offsets)
+
+enum spacemit_gpio_registers {
+ SPACEMIT_GPLR, /* port level - R */
+ SPACEMIT_GPDR, /* port direction - R/W */
+ SPACEMIT_GPSR, /* port set - W */
+ SPACEMIT_GPCR, /* port clear - W */
+ SPACEMIT_GRER, /* port rising edge R/W */
+ SPACEMIT_GFER, /* port falling edge R/W */
+ SPACEMIT_GEDR, /* edge detect status - R/W1C */
+ SPACEMIT_GSDR, /* (set) direction - W */
+ SPACEMIT_GCDR, /* (clear) direction - W */
+ SPACEMIT_GSRER, /* (set) rising edge detect enable - W */
+ SPACEMIT_GCRER, /* (clear) rising edge detect enable - W */
+ SPACEMIT_GSFER, /* (set) falling edge detect enable - W */
+ SPACEMIT_GCFER, /* (clear) falling edge detect enable - W */
+ SPACEMIT_GAPMASK, /* interrupt mask , 0 disable, 1 enable - R/W */
+ SPACEMIT_GCPMASK, /* interrupt mask for K3 */
+};
struct spacemit_gpio;
+struct spacemit_gpio_data {
+ const unsigned int *offsets;
+ u32 bank_offsets[SPACEMIT_NR_BANKS];
+};
+
struct spacemit_gpio_bank {
struct gpio_generic_chip chip;
struct spacemit_gpio *sg;
@@ -49,9 +57,22 @@ struct spacemit_gpio_bank {
struct spacemit_gpio {
struct device *dev;
+ const struct spacemit_gpio_data *data;
struct spacemit_gpio_bank sgb[SPACEMIT_NR_BANKS];
};
+static u32 spacemit_gpio_read(struct spacemit_gpio_bank *gb,
+ enum spacemit_gpio_registers reg)
+{
+ return readl(gb->base + to_spacemit_gpio_regs(gb)[reg]);
+}
+
+static void spacemit_gpio_write(struct spacemit_gpio_bank *gb,
+ enum spacemit_gpio_registers reg, u32 val)
+{
+ writel(val, gb->base + to_spacemit_gpio_regs(gb)[reg]);
+}
+
static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
{
return (u32)(gb - gb->sg->sgb);
@@ -63,10 +84,10 @@ static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
unsigned long pending;
u32 n, gedr;
- gedr = readl(gb->base + SPACEMIT_GEDR);
+ gedr = spacemit_gpio_read(gb, SPACEMIT_GEDR);
if (!gedr)
return IRQ_NONE;
- writel(gedr, gb->base + SPACEMIT_GEDR);
+ spacemit_gpio_write(gb, SPACEMIT_GEDR, gedr);
pending = gedr & gb->irq_mask;
if (!pending)
@@ -82,7 +103,7 @@ static void spacemit_gpio_irq_ack(struct irq_data *d)
{
struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
- writel(BIT(irqd_to_hwirq(d)), gb->base + SPACEMIT_GEDR);
+ spacemit_gpio_write(gb, SPACEMIT_GEDR, BIT(irqd_to_hwirq(d)));
}
static void spacemit_gpio_irq_mask(struct irq_data *d)
@@ -91,13 +112,13 @@ static void spacemit_gpio_irq_mask(struct irq_data *d)
u32 bit = BIT(irqd_to_hwirq(d));
gb->irq_mask &= ~bit;
- writel(gb->irq_mask, gb->base + SPACEMIT_GAPMASK);
+ spacemit_gpio_write(gb, SPACEMIT_GAPMASK, gb->irq_mask);
if (bit & gb->irq_rising_edge)
- writel(bit, gb->base + SPACEMIT_GCRER);
+ spacemit_gpio_write(gb, SPACEMIT_GCRER, bit);
if (bit & gb->irq_falling_edge)
- writel(bit, gb->base + SPACEMIT_GCFER);
+ spacemit_gpio_write(gb, SPACEMIT_GCFER, bit);
}
static void spacemit_gpio_irq_unmask(struct irq_data *d)
@@ -108,12 +129,12 @@ static void spacemit_gpio_irq_unmask(struct irq_data *d)
gb->irq_mask |= bit;
if (bit & gb->irq_rising_edge)
- writel(bit, gb->base + SPACEMIT_GSRER);
+ spacemit_gpio_write(gb, SPACEMIT_GSRER, bit);
if (bit & gb->irq_falling_edge)
- writel(bit, gb->base + SPACEMIT_GSFER);
+ spacemit_gpio_write(gb, SPACEMIT_GSFER, bit);
- writel(gb->irq_mask, gb->base + SPACEMIT_GAPMASK);
+ spacemit_gpio_write(gb, SPACEMIT_GAPMASK, gb->irq_mask);
}
static int spacemit_gpio_irq_set_type(struct irq_data *d, unsigned int type)
@@ -123,18 +144,18 @@ static int spacemit_gpio_irq_set_type(struct irq_data *d, unsigned int type)
if (type & IRQ_TYPE_EDGE_RISING) {
gb->irq_rising_edge |= bit;
- writel(bit, gb->base + SPACEMIT_GSRER);
+ spacemit_gpio_write(gb, SPACEMIT_GSRER, bit);
} else {
gb->irq_rising_edge &= ~bit;
- writel(bit, gb->base + SPACEMIT_GCRER);
+ spacemit_gpio_write(gb, SPACEMIT_GCRER, bit);
}
if (type & IRQ_TYPE_EDGE_FALLING) {
gb->irq_falling_edge |= bit;
- writel(bit, gb->base + SPACEMIT_GSFER);
+ spacemit_gpio_write(gb, SPACEMIT_GSFER, bit);
} else {
gb->irq_falling_edge &= ~bit;
- writel(bit, gb->base + SPACEMIT_GCFER);
+ spacemit_gpio_write(gb, SPACEMIT_GCFER, bit);
}
return 0;
@@ -178,16 +199,16 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
struct gpio_chip *gc = &gb->chip.gc;
struct device *dev = sg->dev;
struct gpio_irq_chip *girq;
- void __iomem *dat, *set, *clr, *dirin, *dirout;
- int ret, bank_base[] = { 0x0, 0x4, 0x8, 0x100 };
+ void __iomem *dat, *set, *clr, *dirout;
+ int ret;
- gb->base = regs + bank_base[index];
+ gb->base = regs + sg->data->bank_offsets[index];
+ gb->sg = sg;
- dat = gb->base + SPACEMIT_GPLR;
- set = gb->base + SPACEMIT_GPSR;
- clr = gb->base + SPACEMIT_GPCR;
- dirin = gb->base + SPACEMIT_GCDR;
- dirout = gb->base + SPACEMIT_GSDR;
+ dat = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPLR];
+ set = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPSR];
+ clr = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPCR];
+ dirout = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPDR];
config = (struct gpio_generic_chip_config) {
.dev = dev,
@@ -196,9 +217,7 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
.set = set,
.clr = clr,
.dirout = dirout,
- .dirin = dirin,
- .flags = GPIO_GENERIC_UNREADABLE_REG_SET |
- GPIO_GENERIC_UNREADABLE_REG_DIR,
+ .flags = GPIO_GENERIC_UNREADABLE_REG_SET,
};
/* This registers 32 GPIO lines per bank */
@@ -206,8 +225,6 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
if (ret)
return dev_err_probe(dev, ret, "failed to init gpio chip\n");
- gb->sg = sg;
-
gc->label = dev_name(dev);
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
@@ -223,13 +240,13 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
gpio_irq_chip_set_chip(girq, &spacemit_gpio_chip);
/* Disable Interrupt */
- writel(0, gb->base + SPACEMIT_GAPMASK);
+ spacemit_gpio_write(gb, SPACEMIT_GAPMASK, 0);
/* Disable Edge Detection Settings */
- writel(0x0, gb->base + SPACEMIT_GRER);
- writel(0x0, gb->base + SPACEMIT_GFER);
+ spacemit_gpio_write(gb, SPACEMIT_GRER, 0x0);
+ spacemit_gpio_write(gb, SPACEMIT_GFER, 0x0);
/* Clear Interrupt */
- writel(0xffffffff, gb->base + SPACEMIT_GCRER);
- writel(0xffffffff, gb->base + SPACEMIT_GCFER);
+ spacemit_gpio_write(gb, SPACEMIT_GCRER, 0xffffffff);
+ spacemit_gpio_write(gb, SPACEMIT_GCFER, 0xffffffff);
ret = devm_request_threaded_irq(dev, irq, NULL,
spacemit_gpio_irq_handler,
@@ -260,6 +277,10 @@ static int spacemit_gpio_probe(struct platform_device *pdev)
if (!sg)
return -ENOMEM;
+ sg->data = of_device_get_match_data(dev);
+ if (!sg->data)
+ return dev_err_probe(dev, -EINVAL, "No available compatible data.");
+
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
@@ -287,8 +308,55 @@ static int spacemit_gpio_probe(struct platform_device *pdev)
return 0;
}
+static const unsigned int spacemit_gpio_k1_offsets[] = {
+ [SPACEMIT_GPLR] = 0x00,
+ [SPACEMIT_GPDR] = 0x0c,
+ [SPACEMIT_GPSR] = 0x18,
+ [SPACEMIT_GPCR] = 0x24,
+ [SPACEMIT_GRER] = 0x30,
+ [SPACEMIT_GFER] = 0x3c,
+ [SPACEMIT_GEDR] = 0x48,
+ [SPACEMIT_GSDR] = 0x54,
+ [SPACEMIT_GCDR] = 0x60,
+ [SPACEMIT_GSRER] = 0x6c,
+ [SPACEMIT_GCRER] = 0x78,
+ [SPACEMIT_GSFER] = 0x84,
+ [SPACEMIT_GCFER] = 0x90,
+ [SPACEMIT_GAPMASK] = 0x9c,
+ [SPACEMIT_GCPMASK] = 0xA8,
+};
+
+static const unsigned int spacemit_gpio_k3_offsets[] = {
+ [SPACEMIT_GPLR] = 0x0,
+ [SPACEMIT_GPDR] = 0x4,
+ [SPACEMIT_GPSR] = 0x8,
+ [SPACEMIT_GPCR] = 0xc,
+ [SPACEMIT_GRER] = 0x10,
+ [SPACEMIT_GFER] = 0x14,
+ [SPACEMIT_GEDR] = 0x18,
+ [SPACEMIT_GSDR] = 0x1c,
+ [SPACEMIT_GCDR] = 0x20,
+ [SPACEMIT_GSRER] = 0x24,
+ [SPACEMIT_GCRER] = 0x28,
+ [SPACEMIT_GSFER] = 0x2c,
+ [SPACEMIT_GCFER] = 0x30,
+ [SPACEMIT_GAPMASK] = 0x34,
+ [SPACEMIT_GCPMASK] = 0x38,
+};
+
+static const struct spacemit_gpio_data k1_gpio_data = {
+ .offsets = spacemit_gpio_k1_offsets,
+ .bank_offsets = { 0x0, 0x4, 0x8, 0x100 },
+};
+
+static const struct spacemit_gpio_data k3_gpio_data = {
+ .offsets = spacemit_gpio_k3_offsets,
+ .bank_offsets = { 0x0, 0x40, 0x80, 0x100 },
+};
+
static const struct of_device_id spacemit_gpio_dt_ids[] = {
- { .compatible = "spacemit,k1-gpio" },
+ { .compatible = "spacemit,k1-gpio", .data = &k1_gpio_data },
+ { .compatible = "spacemit,k3-gpio", .data = &k3_gpio_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spacemit_gpio_dt_ids);
@@ -296,12 +364,12 @@ MODULE_DEVICE_TABLE(of, spacemit_gpio_dt_ids);
static struct platform_driver spacemit_gpio_driver = {
.probe = spacemit_gpio_probe,
.driver = {
- .name = "k1-gpio",
+ .name = "spacemit-gpio",
.of_match_table = spacemit_gpio_dt_ids,
},
};
module_platform_driver(spacemit_gpio_driver);
MODULE_AUTHOR("Yixun Lan <dlan@gentoo.org>");
-MODULE_DESCRIPTION("GPIO driver for SpacemiT K1 SoC");
+MODULE_DESCRIPTION("GPIO driver for SpacemiT K1/K3 SoC");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index b1498b59a921..9c874f07be75 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2025 NVIDIA Corporation
+ * Copyright (c) 2016-2026 NVIDIA Corporation
*
* Author: Thierry Reding <treding@nvidia.com>
* Dipen Patel <dpatel@nvidia.com>
@@ -21,6 +21,7 @@
#include <dt-bindings/gpio/tegra234-gpio.h>
#include <dt-bindings/gpio/tegra241-gpio.h>
#include <dt-bindings/gpio/tegra256-gpio.h>
+#include <dt-bindings/gpio/nvidia,tegra264-gpio.h>
/* security registers */
#define TEGRA186_GPIO_CTL_SCR 0x0c
@@ -1001,7 +1002,9 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
if (gpio->soc->num_irqs_per_bank > 1)
tegra186_gpio_init_route_mapping(gpio);
- np = of_find_matching_node(NULL, tegra186_pmc_of_match);
+ np = of_parse_phandle(pdev->dev.of_node, "wakeup-parent", 0);
+ if (!np)
+ np = of_find_matching_node(NULL, tegra186_pmc_of_match);
if (np) {
if (of_device_is_available(np)) {
irq->parent_domain = irq_find_host(np);
@@ -1277,6 +1280,80 @@ static const struct tegra_gpio_soc tegra241_aon_soc = {
.has_vm_support = false,
};
+#define TEGRA264_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA264_MAIN, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra264_main_ports[] = {
+ TEGRA264_MAIN_GPIO_PORT(F, 3, 0, 8),
+ TEGRA264_MAIN_GPIO_PORT(G, 3, 1, 5),
+ TEGRA264_MAIN_GPIO_PORT(H, 1, 0, 8),
+ TEGRA264_MAIN_GPIO_PORT(J, 1, 1, 8),
+ TEGRA264_MAIN_GPIO_PORT(K, 1, 2, 8),
+ TEGRA264_MAIN_GPIO_PORT(L, 1, 3, 8),
+ TEGRA264_MAIN_GPIO_PORT(M, 1, 4, 6),
+ TEGRA264_MAIN_GPIO_PORT(P, 2, 0, 8),
+ TEGRA264_MAIN_GPIO_PORT(Q, 2, 1, 8),
+ TEGRA264_MAIN_GPIO_PORT(R, 2, 2, 8),
+ TEGRA264_MAIN_GPIO_PORT(S, 2, 3, 2),
+ TEGRA264_MAIN_GPIO_PORT(T, 0, 0, 7),
+ TEGRA264_MAIN_GPIO_PORT(U, 0, 1, 8),
+ TEGRA264_MAIN_GPIO_PORT(V, 0, 2, 8),
+ TEGRA264_MAIN_GPIO_PORT(W, 0, 3, 8),
+ TEGRA264_MAIN_GPIO_PORT(X, 0, 7, 6),
+ TEGRA264_MAIN_GPIO_PORT(Y, 0, 5, 8),
+ TEGRA264_MAIN_GPIO_PORT(Z, 0, 6, 8),
+ TEGRA264_MAIN_GPIO_PORT(AL, 0, 4, 3),
+};
+
+static const struct tegra_gpio_soc tegra264_main_soc = {
+ .num_ports = ARRAY_SIZE(tegra264_main_ports),
+ .ports = tegra264_main_ports,
+ .name = "tegra264-gpio",
+ .instance = 0,
+ .num_irqs_per_bank = 8,
+ .has_vm_support = true,
+};
+
+#define TEGRA264_AON_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA264_AON, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra264_aon_ports[] = {
+ TEGRA264_AON_GPIO_PORT(AA, 0, 0, 8),
+ TEGRA264_AON_GPIO_PORT(BB, 0, 1, 2),
+ TEGRA264_AON_GPIO_PORT(CC, 0, 2, 8),
+ TEGRA264_AON_GPIO_PORT(DD, 0, 3, 8),
+ TEGRA264_AON_GPIO_PORT(EE, 0, 4, 4)
+};
+
+static const struct tegra_gpio_soc tegra264_aon_soc = {
+ .num_ports = ARRAY_SIZE(tegra264_aon_ports),
+ .ports = tegra264_aon_ports,
+ .name = "tegra264-gpio-aon",
+ .instance = 1,
+ .num_irqs_per_bank = 8,
+ .has_vm_support = true,
+};
+
+#define TEGRA264_UPHY_GPIO_PORT(_name, _bank, _port, _pins) \
+ TEGRA_GPIO_PORT(TEGRA264_UPHY, _name, _bank, _port, _pins)
+
+static const struct tegra_gpio_port tegra264_uphy_ports[] = {
+ TEGRA264_UPHY_GPIO_PORT(A, 0, 0, 6),
+ TEGRA264_UPHY_GPIO_PORT(B, 0, 1, 8),
+ TEGRA264_UPHY_GPIO_PORT(C, 0, 2, 3),
+ TEGRA264_UPHY_GPIO_PORT(D, 1, 0, 8),
+ TEGRA264_UPHY_GPIO_PORT(E, 1, 1, 4),
+};
+
+static const struct tegra_gpio_soc tegra264_uphy_soc = {
+ .num_ports = ARRAY_SIZE(tegra264_uphy_ports),
+ .ports = tegra264_uphy_ports,
+ .name = "tegra264-gpio-uphy",
+ .instance = 2,
+ .num_irqs_per_bank = 8,
+ .has_vm_support = true,
+};
+
#define TEGRA256_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
TEGRA_GPIO_PORT(TEGRA256_MAIN, _name, _bank, _port, _pins)
@@ -1369,6 +1446,15 @@ static const struct of_device_id tegra186_gpio_of_match[] = {
.compatible = "nvidia,tegra256-gpio",
.data = &tegra256_main_soc
}, {
+ .compatible = "nvidia,tegra264-gpio",
+ .data = &tegra264_main_soc
+ }, {
+ .compatible = "nvidia,tegra264-gpio-aon",
+ .data = &tegra264_aon_soc
+ }, {
+ .compatible = "nvidia,tegra264-gpio-uphy",
+ .data = &tegra264_uphy_soc
+ }, {
/* sentinel */
}
};
diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c
index 098e67d70ffa..b6c515e7a876 100644
--- a/drivers/gpio/gpio-virtuser.c
+++ b/drivers/gpio/gpio-virtuser.c
@@ -1631,7 +1631,7 @@ static void gpio_virtuser_lookup_config_group_release(struct config_item *item)
kfree(lookup);
}
-static struct configfs_item_operations gpio_virtuser_lookup_config_item_ops = {
+static const struct configfs_item_operations gpio_virtuser_lookup_config_item_ops = {
.release = gpio_virtuser_lookup_config_group_release,
};
@@ -1692,11 +1692,11 @@ static void gpio_virtuser_device_config_group_release(struct config_item *item)
kfree(dev);
}
-static struct configfs_item_operations gpio_virtuser_device_config_item_ops = {
+static const struct configfs_item_operations gpio_virtuser_device_config_item_ops = {
.release = gpio_virtuser_device_config_group_release,
};
-static struct configfs_group_operations gpio_virtuser_device_config_group_ops = {
+static const struct configfs_group_operations gpio_virtuser_device_config_group_ops = {
.make_group = gpio_virtuser_make_lookup_group,
};
@@ -1729,7 +1729,7 @@ gpio_virtuser_config_make_device_group(struct config_group *group,
return &no_free_ptr(dev)->group;
}
-static struct configfs_group_operations gpio_virtuser_config_group_ops = {
+static const struct configfs_group_operations gpio_virtuser_config_group_ops = {
.make_group = gpio_virtuser_config_make_device_group,
};
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 97780c57ab56..571e366624d2 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -903,18 +903,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
struct zynq_gpio *gpio;
struct gpio_chip *chip;
struct gpio_irq_chip *girq;
- const struct of_device_id *match;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
- match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
- if (!match) {
- dev_err(&pdev->dev, "of_match_node() failed\n");
- return -EINVAL;
- }
- gpio->p_data = match->data;
+ gpio->p_data = device_get_match_data(&pdev->dev);
+ if (!gpio->p_data)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "device_get_match_data() failed\n");
+
platform_set_drvdata(pdev, gpio);
gpio->base_addr = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 8657379e9165..ef1ac68b94b7 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -634,6 +634,7 @@ static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
return ERR_PTR(-ENOENT);
}
+#if IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448)
static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
@@ -665,6 +666,7 @@ static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
return desc;
}
+#endif
/*
* Trigger sources are special, they allow us to use any GPIO as a LED trigger
@@ -699,7 +701,9 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
enum of_gpio_flags *of_flags);
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
of_find_gpio_rename,
+#if IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448)
of_find_mt2701_gpio,
+#endif
of_find_trigger_gpio,
NULL
};
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index 9e6544203439..b3525d1f06a4 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -455,12 +455,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
list_for_each_entry(ref, &entry->refs, list) {
guard(mutex)(&ref->lock);
- /*
- * FIXME: use device_is_compatible() once the reset-gpio
- * drivers gains a compatible string which it currently
- * does not have.
- */
- if (!ref->fwnode && strstarts(dev_name(consumer), "reset.gpio.")) {
+ if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) {
if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
continue;
} else if (!device_match_fwnode(consumer, ref->fwnode)) {
diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c
index b44f35d68459..21478b45c127 100644
--- a/drivers/gpio/gpiolib-swnode.c
+++ b/drivers/gpio/gpiolib-swnode.c
@@ -18,19 +18,18 @@
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/property.h>
#include "gpiolib.h"
#include "gpiolib-swnode.h"
-#define GPIOLIB_SWNODE_UNDEFINED_NAME "swnode-gpio-undefined"
-
static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
{
const struct software_node *gdev_node;
struct gpio_device *gdev;
gdev_node = to_software_node(fwnode);
- if (!gdev_node || !gdev_node->name)
+ if (!gdev_node)
goto fwnode_lookup;
/*
@@ -38,7 +37,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
* primarily used as a key for internal chip selects in SPI bindings.
*/
if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) &&
- !strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME))
+ gdev_node == &swnode_gpio_undefined)
return ERR_PTR(-ENOENT);
fwnode_lookup:
@@ -140,7 +139,7 @@ int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
* a key for internal chip selects in SPI bindings.
*/
const struct software_node swnode_gpio_undefined = {
- .name = GPIOLIB_SWNODE_UNDEFINED_NAME,
+ .name = "swnode-gpio-undefined",
};
EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, "GPIO_SWNODE");
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1578cf3a8c74..c52200eaaaff 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -5261,27 +5261,21 @@ void gpiod_put_array(struct gpio_descs *descs)
}
EXPORT_SYMBOL_GPL(gpiod_put_array);
-static int gpio_stub_drv_probe(struct device *dev)
-{
- /*
- * The DT node of some GPIO chips have a "compatible" property, but
- * never have a struct device added and probed by a driver to register
- * the GPIO chip with gpiolib. In such cases, fw_devlink=on will cause
- * the consumers of the GPIO chip to get probe deferred forever because
- * they will be waiting for a device associated with the GPIO chip
- * firmware node to get added and bound to a driver.
- *
- * To allow these consumers to probe, we associate the struct
- * gpio_device of the GPIO chip with the firmware node and then simply
- * bind it to this stub driver.
- */
- return 0;
-}
-
+/*
+ * The DT node of some GPIO chips have a "compatible" property, but
+ * never have a struct device added and probed by a driver to register
+ * the GPIO chip with gpiolib. In such cases, fw_devlink=on will cause
+ * the consumers of the GPIO chip to get probe deferred forever because
+ * they will be waiting for a device associated with the GPIO chip
+ * firmware node to get added and bound to a driver.
+ *
+ * To allow these consumers to probe, we associate the struct
+ * gpio_device of the GPIO chip with the firmware node and then simply
+ * bind it to this stub driver.
+ */
static struct device_driver gpio_stub_drv = {
.name = "gpio_stub_drv",
.bus = &gpio_bus_type,
- .probe = gpio_stub_drv_probe,
};
static int __init gpiolib_dev_init(void)