diff options
Diffstat (limited to 'drivers/gpio')
54 files changed, 2256 insertions, 382 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1ca78263f0f7..1c211b4c63be 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -731,14 +731,12 @@ config GPIO_XILINX Say yes here to support the Xilinx FPGA GPIO device. config GPIO_XLP - tristate "Netlogic XLP GPIO support" - depends on OF_GPIO && (CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST) + tristate "Cavium ThunderX2 GPIO support" + depends on ARCH_THUNDER2 || COMPILE_TEST select GPIOLIB_IRQCHIP help - This driver provides support for GPIO interface on Netlogic XLP MIPS64 - SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, - XLP9XX and XLP5XX. The same GPIO controller block is also present in - Cavium's ThunderX2 CN99XX SoCs. + This driver provides support for GPIO interface on Cavium's ThunderX2 + CN99XX SoCs (Originally from Netlogic XLP). If unsure, say N. @@ -1683,6 +1681,14 @@ config GPIO_VIRTIO These virtual GPIOs can be routed to real GPIOs or attached to simulators on the host (like QEMU). +config GPIO_SIM + tristate "GPIO Simulator Module" + select IRQ_SIM + select CONFIGFS_FS + help + This enables the GPIO simulator - a configfs-based GPIO testing + driver. + endmenu endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ed5f9b1a75ce..edbaa3cb343c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -132,6 +132,7 @@ obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o +obj-$(CONFIG_GPIO_SIM) += gpio-sim.o obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o obj-$(CONFIG_GPIO_SL28CPLD) += gpio-sl28cpld.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 8eedfc6451df..cc349d4e4973 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -458,7 +458,6 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios, chip->ngpio = num_gpios; chip->label = adnp->client->name; chip->parent = &adnp->client->dev; - chip->of_node = chip->parent->of_node; chip->owner = THIS_MODULE; if (is_irq_controller) { diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index e9671d1660ef..869dc952cf45 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -371,6 +371,13 @@ static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset, return gpiod_set_config(fwd->descs[offset], config); } +static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_to_irq(fwd->descs[offset]); +} + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer @@ -411,7 +418,8 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, for (i = 0; i < ngpios; i++) { struct gpio_chip *parent = gpiod_to_chip(descs[i]); - dev_dbg(dev, "%u => gpio-%d\n", i, desc_to_gpio(descs[i])); + dev_dbg(dev, "%u => gpio %d irq %d\n", i, + desc_to_gpio(descs[i]), gpiod_to_irq(descs[i])); if (gpiod_cansleep(descs[i])) chip->can_sleep = true; @@ -429,6 +437,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip->get_multiple = gpio_fwd_get_multiple_locked; chip->set = gpio_fwd_set; chip->set_multiple = gpio_fwd_set_multiple_locked; + chip->to_irq = gpio_fwd_to_irq; chip->base = -1; chip->ngpio = ngpios; fwd->descs = descs; diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c index bbf53e289141..8cfb353c3abb 100644 --- a/drivers/gpio/gpio-amdpt.c +++ b/drivers/gpio/gpio-amdpt.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #define PT_TOTAL_GPIO 8 +#define PT_TOTAL_GPIO_EX 24 /* PCI-E MMIO register offsets */ #define PT_DIRECTION_REG 0x00 @@ -103,10 +104,8 @@ static int pt_gpio_probe(struct platform_device *pdev) pt_gpio->gc.owner = THIS_MODULE; pt_gpio->gc.request = pt_gpio_request; pt_gpio->gc.free = pt_gpio_free; - pt_gpio->gc.ngpio = PT_TOTAL_GPIO; -#if defined(CONFIG_OF_GPIO) - pt_gpio->gc.of_node = dev->of_node; -#endif + pt_gpio->gc.ngpio = (uintptr_t)device_get_match_data(dev); + ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio); if (ret) { dev_err(dev, "Failed to register GPIO lib\n"); @@ -133,8 +132,9 @@ static int pt_gpio_remove(struct platform_device *pdev) } static const struct acpi_device_id pt_gpio_acpi_match[] = { - { "AMDF030", 0 }, - { "AMDIF030", 0 }, + { "AMDF030", PT_TOTAL_GPIO }, + { "AMDIF030", PT_TOTAL_GPIO }, + { "AMDIF031", PT_TOTAL_GPIO_EX }, { }, }; MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match); diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 2bc173c352ce..02f9ae19cd44 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -151,6 +151,8 @@ static int arizona_gpio_probe(struct platform_device *pdev) struct arizona_gpio *arizona_gpio; int ret; + device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); + arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio), GFP_KERNEL); if (!arizona_gpio) @@ -159,9 +161,6 @@ static int arizona_gpio_probe(struct platform_device *pdev) arizona_gpio->arizona = arizona; arizona_gpio->gpio_chip = template_chip; arizona_gpio->gpio_chip.parent = &pdev->dev; -#ifdef CONFIG_OF_GPIO - arizona_gpio->gpio_chip.of_node = arizona->dev->of_node; -#endif switch (arizona->type) { case WM5102: diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index b3a9b8488f11..454cefbeecf0 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -31,7 +31,7 @@ struct aspeed_sgpio { struct gpio_chip chip; struct irq_chip intc; struct clk *pclk; - spinlock_t lock; + raw_spinlock_t lock; void __iomem *base; int irq; }; @@ -173,12 +173,12 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) enum aspeed_sgpio_reg reg; int rc = 0; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } @@ -215,11 +215,11 @@ static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) struct aspeed_sgpio *gpio = gpiochip_get_data(gc); unsigned long flags; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); sgpio_set_value(gc, offset, val); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); } static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) @@ -236,9 +236,9 @@ static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int v /* No special action is required for setting the direction; we'll * error-out in sgpio_set_value if this isn't an output GPIO */ - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); rc = sgpio_set_value(gc, offset, val); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } @@ -277,11 +277,11 @@ static void aspeed_sgpio_irq_ack(struct irq_data *d) status_addr = bank_reg(gpio, bank, reg_irq_status); - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); iowrite32(bit, status_addr); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); } static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) @@ -296,7 +296,7 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); addr = bank_reg(gpio, bank, reg_irq_enable); - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); reg = ioread32(addr); if (set) @@ -306,7 +306,7 @@ static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) iowrite32(reg, addr); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); } static void aspeed_sgpio_irq_mask(struct irq_data *d) @@ -355,7 +355,7 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); addr = bank_reg(gpio, bank, reg_irq_type0); reg = ioread32(addr); @@ -372,7 +372,7 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) reg = (reg & ~bit) | type2; iowrite32(reg, addr); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); irq_set_handler_locked(d, handler); @@ -467,7 +467,7 @@ static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, reg = bank_reg(gpio, to_bank(offset), reg_tolerance); - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); val = readl(reg); @@ -478,7 +478,7 @@ static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, writel(val, reg); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return 0; } @@ -575,7 +575,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL); - spin_lock_init(&gpio->lock); + raw_spin_lock_init(&gpio->lock); gpio->chip.parent = &pdev->dev; gpio->chip.ngpio = nr_gpios * 2; diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 3c8f20c57695..318a7d95a1a8 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -53,7 +53,7 @@ struct aspeed_gpio_config { struct aspeed_gpio { struct gpio_chip chip; struct irq_chip irqc; - spinlock_t lock; + raw_spinlock_t lock; void __iomem *base; int irq; const struct aspeed_gpio_config *config; @@ -413,14 +413,14 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, unsigned long flags; bool copro; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); } static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) @@ -435,7 +435,7 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) if (!have_input(gpio, offset)) return -ENOTSUPP; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); reg = ioread32(addr); reg &= ~GPIO_BIT(offset); @@ -445,7 +445,7 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return 0; } @@ -463,7 +463,7 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, if (!have_output(gpio, offset)) return -ENOTSUPP; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); reg = ioread32(addr); reg |= GPIO_BIT(offset); @@ -474,7 +474,7 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return 0; } @@ -492,11 +492,11 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) if (!have_output(gpio, offset)) return GPIO_LINE_DIRECTION_IN; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return val ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; } @@ -539,14 +539,14 @@ static void aspeed_gpio_irq_ack(struct irq_data *d) status_addr = bank_reg(gpio, bank, reg_irq_status); - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); iowrite32(bit, status_addr); if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); } static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) @@ -565,7 +565,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) addr = bank_reg(gpio, bank, reg_irq_enable); - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); reg = ioread32(addr); @@ -577,7 +577,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); } static void aspeed_gpio_irq_mask(struct irq_data *d) @@ -629,7 +629,7 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); addr = bank_reg(gpio, bank, reg_irq_type0); @@ -649,7 +649,7 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); irq_set_handler_locked(d, handler); @@ -716,7 +716,7 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, treg = bank_reg(gpio, to_bank(offset), reg_tolerance); - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); val = readl(treg); @@ -730,7 +730,7 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, if (copro) aspeed_gpio_copro_release(gpio, offset); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return 0; } @@ -856,7 +856,7 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, return rc; } - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); if (timer_allocation_registered(gpio, offset)) { rc = unregister_allocated_timer(gpio, offset); @@ -916,7 +916,7 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, configure_timer(gpio, offset, i); out: - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } @@ -927,13 +927,13 @@ static int disable_debounce(struct gpio_chip *chip, unsigned int offset) unsigned long flags; int rc; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); rc = unregister_allocated_timer(gpio, offset); if (!rc) configure_timer(gpio, offset, 0); - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } @@ -1015,7 +1015,7 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, return -EINVAL; bindex = offset >> 3; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); /* Sanity check, this shouldn't happen */ if (gpio->cf_copro_bankmap[bindex] == 0xff) { @@ -1036,7 +1036,7 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, if (bit) *bit = GPIO_OFFSET(offset); bail: - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } EXPORT_SYMBOL_GPL(aspeed_gpio_copro_grab_gpio); @@ -1060,7 +1060,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) return -EINVAL; bindex = offset >> 3; - spin_lock_irqsave(&gpio->lock, flags); + raw_spin_lock_irqsave(&gpio->lock, flags); /* Sanity check, this shouldn't happen */ if (gpio->cf_copro_bankmap[bindex] == 0) { @@ -1074,7 +1074,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) aspeed_gpio_change_cmd_source(gpio, bank, bindex, GPIO_CMDSRC_ARM); bail: - spin_unlock_irqrestore(&gpio->lock, flags); + raw_spin_unlock_irqrestore(&gpio->lock, flags); return rc; } EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio); @@ -1148,7 +1148,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio->base)) return PTR_ERR(gpio->base); - spin_lock_init(&gpio->lock); + raw_spin_lock_init(&gpio->lock); gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node); if (!gpio_id) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index d329a143f5ec..e84474494429 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -606,7 +606,7 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) kona_gpio->pdev = pdev; platform_set_drvdata(pdev, kona_gpio); - chip->of_node = dev->of_node; + chip->parent = dev; chip->ngpio = kona_gpio->num_bank * GPIO_PER_BANK; kona_gpio->irq_domain = irq_domain_add_linear(dev->of_node, diff --git a/drivers/gpio/gpio-bd71828.c b/drivers/gpio/gpio-bd71828.c index c8e382b53f2f..b2ccc320c7b5 100644 --- a/drivers/gpio/gpio-bd71828.c +++ b/drivers/gpio/gpio-bd71828.c @@ -121,7 +121,6 @@ static int bd71828_probe(struct platform_device *pdev) * "gpio-reserved-ranges" and exclude them from control */ bdgpio->gpio.ngpio = 4; - bdgpio->gpio.of_node = dev->parent->of_node; bdgpio->regmap = dev_get_regmap(dev->parent, NULL); if (!bdgpio->regmap) return -ENODEV; diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 895a79936248..74ef89248867 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -703,9 +703,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) goto fail; } - gc->of_node = np; gc->owner = THIS_MODULE; - gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", dev->of_node); + gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); if (!gc->label) { err = -ENOMEM; goto fail; diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c index 1d0827e79703..789384c6e178 100644 --- a/drivers/gpio/gpio-creg-snps.c +++ b/drivers/gpio/gpio-creg-snps.c @@ -163,12 +163,12 @@ static int creg_gpio_probe(struct platform_device *pdev) spin_lock_init(&hcg->lock); + hcg->gc.parent = dev; hcg->gc.label = dev_name(dev); hcg->gc.base = -1; hcg->gc.ngpio = ngpios; hcg->gc.set = creg_gpio_set; hcg->gc.direction_output = creg_gpio_dir_out; - hcg->gc.of_node = dev->of_node; ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg); if (ret) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index cb5afaa7ed48..f960587f86a3 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -254,7 +254,6 @@ static int davinci_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF_GPIO chips->chip.of_gpio_n_cells = 2; chips->chip.parent = dev; - chips->chip.of_node = dev->of_node; chips->chip.request = gpiochip_generic_request; chips->chip.free = gpiochip_generic_free; #endif diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index f98fa33e1679..b0f3aca61974 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -15,7 +15,6 @@ #include <linux/irq.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/reset.h> @@ -53,7 +52,9 @@ #define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */ #define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */ +#define GPIO_REG_OFFSET_V1 0 #define GPIO_REG_OFFSET_V2 1 +#define GPIO_REG_OFFSET_MASK BIT(0) #define GPIO_INTMASK_V2 0x44 #define GPIO_INTTYPE_LEVEL_V2 0x34 @@ -141,7 +142,7 @@ static inline u32 gpio_reg_v2_convert(unsigned int offset) static inline u32 gpio_reg_convert(struct dwapb_gpio *gpio, unsigned int offset) { - if (gpio->flags & GPIO_REG_OFFSET_V2) + if ((gpio->flags & GPIO_REG_OFFSET_MASK) == GPIO_REG_OFFSET_V2) return gpio_reg_v2_convert(offset); return offset; @@ -513,9 +514,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, return err; } -#ifdef CONFIG_OF_GPIO - port->gc.of_node = to_of_node(pp->fwnode); -#endif + port->gc.fwnode = pp->fwnode; port->gc.ngpio = pp->ngpio; port->gc.base = pp->gpio_base; @@ -668,15 +667,15 @@ static int dwapb_get_clks(struct dwapb_gpio *gpio) } static const struct of_device_id dwapb_of_match[] = { - { .compatible = "snps,dw-apb-gpio", .data = (void *)0}, + { .compatible = "snps,dw-apb-gpio", .data = (void *)GPIO_REG_OFFSET_V1}, { .compatible = "apm,xgene-gpio-v2", .data = (void *)GPIO_REG_OFFSET_V2}, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dwapb_of_match); static const struct acpi_device_id dwapb_acpi_match[] = { - {"HISI0181", 0}, - {"APMC0D07", 0}, + {"HISI0181", GPIO_REG_OFFSET_V1}, + {"APMC0D07", GPIO_REG_OFFSET_V1}, {"APMC0D81", GPIO_REG_OFFSET_V2}, { } }; diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index 865ab2b34fdd..8d722e026e9c 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -609,7 +609,6 @@ static int sprd_eic_probe(struct platform_device *pdev) sprd_eic->chip.ngpio = pdata->num_eics; sprd_eic->chip.base = -1; sprd_eic->chip.parent = &pdev->dev; - sprd_eic->chip.of_node = pdev->dev.of_node; sprd_eic->chip.direction_input = sprd_eic_direction_input; switch (sprd_eic->type) { case SPRD_EIC_DEBOUNCE: diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 90b336e6ee27..858e6ebbb584 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -306,7 +306,6 @@ static int em_gio_probe(struct platform_device *pdev) } gpio_chip = &p->gpio_chip; - gpio_chip->of_node = dev->of_node; gpio_chip->direction_input = em_gio_direction_input; gpio_chip->get = em_gio_get; gpio_chip->direction_output = em_gio_direction_output; diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 636952769bc8..f6a3de99f7db 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -82,7 +82,6 @@ static int __init gef_gpio_probe(struct platform_device *pdev) gc->base = -1; gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev); gc->of_gpio_n_cells = 2; - gc->of_node = pdev->dev.of_node; /* This function adds a memory mapped GPIO chip */ ret = devm_gpiochip_add_data(&pdev->dev, gc, NULL); diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index f954359c9544..23d447e17a67 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -358,7 +358,6 @@ static int grgpio_probe(struct platform_device *ofdev) priv->imask = gc->read_reg(regs + GRGPIO_IMASK); priv->dev = &ofdev->dev; - gc->of_node = np; gc->owner = THIS_MODULE; gc->to_irq = grgpio_to_irq; gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np); diff --git a/drivers/gpio/gpio-gw-pld.c b/drivers/gpio/gpio-gw-pld.c index 242112ff60ee..2109803ffb38 100644 --- a/drivers/gpio/gpio-gw-pld.c +++ b/drivers/gpio/gpio-gw-pld.c @@ -71,7 +71,6 @@ static int gw_pld_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct device_node *np = dev->of_node; struct gw_pld *gw; int ret; @@ -82,7 +81,6 @@ static int gw_pld_probe(struct i2c_client *client, gw->chip.base = -1; gw->chip.can_sleep = true; gw->chip.parent = dev; - gw->chip.of_node = np; gw->chip.owner = THIS_MODULE; gw->chip.label = dev_name(dev); gw->chip.ngpio = 8; diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 4e626c4235c2..d2b65cfb336e 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -512,10 +512,10 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev) return PTR_ERR(reg_base); for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) { + lpc32xx_gpiochip[i].chip.parent = &pdev->dev; if (pdev->dev.of_node) { lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate; lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3; - lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node; lpc32xx_gpiochip[i].reg_base = reg_base; } devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip, diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index 310d1a248cae..51cd6f98d1c7 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -326,7 +326,7 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, bitmap_zero(values, ndescs); gpiod_set_array_value_cansleep(ndescs, desc, info, values); - kfree(values); + bitmap_free(values); } static struct gpio_descs *devm_gpiod_get_array_optional_count( diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index efa9acdc320a..b060c4773698 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -98,9 +98,9 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->regs[chip->ch].po); if (val) - reg_val |= (1 << nr); + reg_val |= BIT(nr); else - reg_val &= ~(1 << nr); + reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->regs[chip->ch].po); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -110,7 +110,7 @@ static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr) { struct ioh_gpio *chip = gpiochip_get_data(gpio); - return !!(ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr)); + return !!(ioread32(&chip->reg->regs[chip->ch].pi) & BIT(nr)); } static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, @@ -122,16 +122,16 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->regs[chip->ch].pm) & - ((1 << num_ports[chip->ch]) - 1); - pm |= (1 << nr); + pm = ioread32(&chip->reg->regs[chip->ch].pm); + pm &= BIT(num_ports[chip->ch]) - 1; + pm |= BIT(nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); reg_val = ioread32(&chip->reg->regs[chip->ch].po); if (val) - reg_val |= (1 << nr); + reg_val |= BIT(nr); else - reg_val &= ~(1 << nr); + reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->regs[chip->ch].po); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -146,9 +146,9 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->regs[chip->ch].pm) & - ((1 << num_ports[chip->ch]) - 1); - pm &= ~(1 << nr); + pm = ioread32(&chip->reg->regs[chip->ch].pm); + pm &= BIT(num_ports[chip->ch]) - 1; + pm &= ~BIT(nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -304,7 +304,7 @@ static void ioh_irq_unmask(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct ioh_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->regs[chip->ch].imaskclr); } @@ -313,7 +313,7 @@ static void ioh_irq_mask(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct ioh_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->regs[chip->ch].imask); } @@ -326,7 +326,7 @@ static void ioh_irq_disable(struct irq_data *d) spin_lock_irqsave(&chip->spinlock, flags); ien = ioread32(&chip->reg->regs[chip->ch].ien); - ien &= ~(1 << (d->irq - chip->irq_base)); + ien &= ~BIT(d->irq - chip->irq_base); iowrite32(ien, &chip->reg->regs[chip->ch].ien); spin_unlock_irqrestore(&chip->spinlock, flags); } @@ -340,7 +340,7 @@ static void ioh_irq_enable(struct irq_data *d) spin_lock_irqsave(&chip->spinlock, flags); ien = ioread32(&chip->reg->regs[chip->ch].ien); - ien |= 1 << (d->irq - chip->irq_base); + ien |= BIT(d->irq - chip->irq_base); iowrite32(ien, &chip->reg->regs[chip->ch].ien); spin_unlock_irqrestore(&chip->spinlock, flags); } @@ -401,6 +401,7 @@ static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, static int ioh_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; int ret; int i, j; struct ioh_gpio *chip; @@ -410,19 +411,19 @@ static int ioh_gpio_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "%s : pci_enable_device failed", __func__); + dev_err(dev, "%s : pci_enable_device failed", __func__); goto err_pci_enable; } ret = pci_request_regions(pdev, KBUILD_MODNAME); if (ret) { - dev_err(&pdev->dev, "pci_request_regions failed-%d", ret); + dev_err(dev, "pci_request_regions failed-%d", ret); goto err_request_regions; } base = pci_iomap(pdev, 1, 0); if (!base) { - dev_err(&pdev->dev, "%s : pci_iomap failed", __func__); + dev_err(dev, "%s : pci_iomap failed", __func__); ret = -ENOMEM; goto err_iomap; } @@ -435,7 +436,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev, chip = chip_save; for (i = 0; i < 8; i++, chip++) { - chip->dev = &pdev->dev; + chip->dev = dev; chip->base = base; chip->reg = chip->base; chip->ch = i; @@ -443,17 +444,17 @@ static int ioh_gpio_probe(struct pci_dev *pdev, ioh_gpio_setup(chip, num_ports[i]); ret = gpiochip_add_data(&chip->gpio, chip); if (ret) { - dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n"); + dev_err(dev, "IOH gpio: Failed to register GPIO\n"); goto err_gpiochip_add; } } chip = chip_save; for (j = 0; j < 8; j++, chip++) { - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, IOH_IRQ_BASE, + irq_base = devm_irq_alloc_descs(dev, -1, IOH_IRQ_BASE, num_ports[j], NUMA_NO_NODE); if (irq_base < 0) { - dev_warn(&pdev->dev, + dev_warn(dev, "ml_ioh_gpio: Failed to get IRQ base num\n"); ret = irq_base; goto err_gpiochip_add; @@ -467,11 +468,10 @@ static int ioh_gpio_probe(struct pci_dev *pdev, } chip = chip_save; - ret = devm_request_irq(&pdev->dev, pdev->irq, ioh_gpio_handler, + ret = devm_request_irq(dev, pdev->irq, ioh_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); if (ret != 0) { - dev_err(&pdev->dev, - "%s request_irq failed\n", __func__); + dev_err(dev, "%s request_irq failed\n", __func__); goto err_gpiochip_add; } @@ -498,7 +498,7 @@ err_request_regions: err_pci_enable: - dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret); + dev_err(dev, "%s Failed returns %d\n", __func__, ret); return ret; } diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c index da31a5ff7a2b..b2c90bdd39d0 100644 --- a/drivers/gpio/gpio-msc313.c +++ b/drivers/gpio/gpio-msc313.c @@ -221,6 +221,263 @@ static const unsigned int msc313_offsets[] = { }; MSC313_GPIO_CHIPDATA(msc313); + +/* + * Unlike the msc313(e) the ssd20xd have a bunch of pins + * that are actually called gpio probably because they + * have no dedicated function. + */ +#define SSD20XD_PINNAME_GPIO0 "gpio0" +#define SSD20XD_PINNAME_GPIO1 "gpio1" +#define SSD20XD_PINNAME_GPIO2 "gpio2" +#define SSD20XD_PINNAME_GPIO3 "gpio3" +#define SSD20XD_PINNAME_GPIO4 "gpio4" +#define SSD20XD_PINNAME_GPIO5 "gpio5" +#define SSD20XD_PINNAME_GPIO6 "gpio6" +#define SSD20XD_PINNAME_GPIO7 "gpio7" +#define SSD20XD_PINNAME_GPIO10 "gpio10" +#define SSD20XD_PINNAME_GPIO11 "gpio11" +#define SSD20XD_PINNAME_GPIO12 "gpio12" +#define SSD20XD_PINNAME_GPIO13 "gpio13" +#define SSD20XD_PINNAME_GPIO14 "gpio14" +#define SSD20XD_PINNAME_GPIO85 "gpio85" +#define SSD20XD_PINNAME_GPIO86 "gpio86" +#define SSD20XD_PINNAME_GPIO90 "gpio90" + +#define SSD20XD_GPIO_NAMES SSD20XD_PINNAME_GPIO0, \ + SSD20XD_PINNAME_GPIO1, \ + SSD20XD_PINNAME_GPIO2, \ + SSD20XD_PINNAME_GPIO3, \ + SSD20XD_PINNAME_GPIO4, \ + SSD20XD_PINNAME_GPIO5, \ + SSD20XD_PINNAME_GPIO6, \ + SSD20XD_PINNAME_GPIO7, \ + SSD20XD_PINNAME_GPIO10, \ + SSD20XD_PINNAME_GPIO11, \ + SSD20XD_PINNAME_GPIO12, \ + SSD20XD_PINNAME_GPIO13, \ + SSD20XD_PINNAME_GPIO14, \ + SSD20XD_PINNAME_GPIO85, \ + SSD20XD_PINNAME_GPIO86, \ + SSD20XD_PINNAME_GPIO90 + +#define SSD20XD_GPIO_OFF_GPIO0 0x0 +#define SSD20XD_GPIO_OFF_GPIO1 0x4 +#define SSD20XD_GPIO_OFF_GPIO2 0x8 +#define SSD20XD_GPIO_OFF_GPIO3 0xc +#define SSD20XD_GPIO_OFF_GPIO4 0x10 +#define SSD20XD_GPIO_OFF_GPIO5 0x14 +#define SSD20XD_GPIO_OFF_GPIO6 0x18 +#define SSD20XD_GPIO_OFF_GPIO7 0x1c +#define SSD20XD_GPIO_OFF_GPIO10 0x28 +#define SSD20XD_GPIO_OFF_GPIO11 0x2c +#define SSD20XD_GPIO_OFF_GPIO12 0x30 +#define SSD20XD_GPIO_OFF_GPIO13 0x34 +#define SSD20XD_GPIO_OFF_GPIO14 0x38 +#define SSD20XD_GPIO_OFF_GPIO85 0x100 +#define SSD20XD_GPIO_OFF_GPIO86 0x104 +#define SSD20XD_GPIO_OFF_GPIO90 0x114 + +#define SSD20XD_GPIO_OFFSETS SSD20XD_GPIO_OFF_GPIO0, \ + SSD20XD_GPIO_OFF_GPIO1, \ + SSD20XD_GPIO_OFF_GPIO2, \ + SSD20XD_GPIO_OFF_GPIO3, \ + SSD20XD_GPIO_OFF_GPIO4, \ + SSD20XD_GPIO_OFF_GPIO5, \ + SSD20XD_GPIO_OFF_GPIO6, \ + SSD20XD_GPIO_OFF_GPIO7, \ + SSD20XD_GPIO_OFF_GPIO10, \ + SSD20XD_GPIO_OFF_GPIO11, \ + SSD20XD_GPIO_OFF_GPIO12, \ + SSD20XD_GPIO_OFF_GPIO13, \ + SSD20XD_GPIO_OFF_GPIO14, \ + SSD20XD_GPIO_OFF_GPIO85, \ + SSD20XD_GPIO_OFF_GPIO86, \ + SSD20XD_GPIO_OFF_GPIO90 + +/* "ttl" pins lcd interface pins */ +#define SSD20XD_PINNAME_TTL0 "ttl0" +#define SSD20XD_PINNAME_TTL1 "ttl1" +#define SSD20XD_PINNAME_TTL2 "ttl2" +#define SSD20XD_PINNAME_TTL3 "ttl3" +#define SSD20XD_PINNAME_TTL4 "ttl4" +#define SSD20XD_PINNAME_TTL5 "ttl5" +#define SSD20XD_PINNAME_TTL6 "ttl6" +#define SSD20XD_PINNAME_TTL7 "ttl7" +#define SSD20XD_PINNAME_TTL8 "ttl8" +#define SSD20XD_PINNAME_TTL9 "ttl9" +#define SSD20XD_PINNAME_TTL10 "ttl10" +#define SSD20XD_PINNAME_TTL11 "ttl11" +#define SSD20XD_PINNAME_TTL12 "ttl12" +#define SSD20XD_PINNAME_TTL13 "ttl13" +#define SSD20XD_PINNAME_TTL14 "ttl14" +#define SSD20XD_PINNAME_TTL15 "ttl15" +#define SSD20XD_PINNAME_TTL16 "ttl16" +#define SSD20XD_PINNAME_TTL17 "ttl17" +#define SSD20XD_PINNAME_TTL18 "ttl18" +#define SSD20XD_PINNAME_TTL19 "ttl19" +#define SSD20XD_PINNAME_TTL20 "ttl20" +#define SSD20XD_PINNAME_TTL21 "ttl21" +#define SSD20XD_PINNAME_TTL22 "ttl22" +#define SSD20XD_PINNAME_TTL23 "ttl23" +#define SSD20XD_PINNAME_TTL24 "ttl24" +#define SSD20XD_PINNAME_TTL25 "ttl25" +#define SSD20XD_PINNAME_TTL26 "ttl26" +#define SSD20XD_PINNAME_TTL27 "ttl27" + +#define SSD20XD_TTL_PINNAMES SSD20XD_PINNAME_TTL0, \ + SSD20XD_PINNAME_TTL1, \ + SSD20XD_PINNAME_TTL2, \ + SSD20XD_PINNAME_TTL3, \ + SSD20XD_PINNAME_TTL4, \ + SSD20XD_PINNAME_TTL5, \ + SSD20XD_PINNAME_TTL6, \ + SSD20XD_PINNAME_TTL7, \ + SSD20XD_PINNAME_TTL8, \ + SSD20XD_PINNAME_TTL9, \ + SSD20XD_PINNAME_TTL10, \ + SSD20XD_PINNAME_TTL11, \ + SSD20XD_PINNAME_TTL12, \ + SSD20XD_PINNAME_TTL13, \ + SSD20XD_PINNAME_TTL14, \ + SSD20XD_PINNAME_TTL15, \ + SSD20XD_PINNAME_TTL16, \ + SSD20XD_PINNAME_TTL17, \ + SSD20XD_PINNAME_TTL18, \ + SSD20XD_PINNAME_TTL19, \ + SSD20XD_PINNAME_TTL20, \ + SSD20XD_PINNAME_TTL21, \ + SSD20XD_PINNAME_TTL22, \ + SSD20XD_PINNAME_TTL23, \ + SSD20XD_PINNAME_TTL24, \ + SSD20XD_PINNAME_TTL25, \ + SSD20XD_PINNAME_TTL26, \ + SSD20XD_PINNAME_TTL27 + +#define SSD20XD_TTL_OFFSET_TTL0 0x80 +#define SSD20XD_TTL_OFFSET_TTL1 0x84 +#define SSD20XD_TTL_OFFSET_TTL2 0x88 +#define SSD20XD_TTL_OFFSET_TTL3 0x8c +#define SSD20XD_TTL_OFFSET_TTL4 0x90 +#define SSD20XD_TTL_OFFSET_TTL5 0x94 +#define SSD20XD_TTL_OFFSET_TTL6 0x98 +#define SSD20XD_TTL_OFFSET_TTL7 0x9c +#define SSD20XD_TTL_OFFSET_TTL8 0xa0 +#define SSD20XD_TTL_OFFSET_TTL9 0xa4 +#define SSD20XD_TTL_OFFSET_TTL10 0xa8 +#define SSD20XD_TTL_OFFSET_TTL11 0xac +#define SSD20XD_TTL_OFFSET_TTL12 0xb0 +#define SSD20XD_TTL_OFFSET_TTL13 0xb4 +#define SSD20XD_TTL_OFFSET_TTL14 0xb8 +#define SSD20XD_TTL_OFFSET_TTL15 0xbc +#define SSD20XD_TTL_OFFSET_TTL16 0xc0 +#define SSD20XD_TTL_OFFSET_TTL17 0xc4 +#define SSD20XD_TTL_OFFSET_TTL18 0xc8 +#define SSD20XD_TTL_OFFSET_TTL19 0xcc +#define SSD20XD_TTL_OFFSET_TTL20 0xd0 +#define SSD20XD_TTL_OFFSET_TTL21 0xd4 +#define SSD20XD_TTL_OFFSET_TTL22 0xd8 +#define SSD20XD_TTL_OFFSET_TTL23 0xdc +#define SSD20XD_TTL_OFFSET_TTL24 0xe0 +#define SSD20XD_TTL_OFFSET_TTL25 0xe4 +#define SSD20XD_TTL_OFFSET_TTL26 0xe8 +#define SSD20XD_TTL_OFFSET_TTL27 0xec + +#define SSD20XD_TTL_OFFSETS SSD20XD_TTL_OFFSET_TTL0, \ + SSD20XD_TTL_OFFSET_TTL1, \ + SSD20XD_TTL_OFFSET_TTL2, \ + SSD20XD_TTL_OFFSET_TTL3, \ + SSD20XD_TTL_OFFSET_TTL4, \ + SSD20XD_TTL_OFFSET_TTL5, \ + SSD20XD_TTL_OFFSET_TTL6, \ + SSD20XD_TTL_OFFSET_TTL7, \ + SSD20XD_TTL_OFFSET_TTL8, \ + SSD20XD_TTL_OFFSET_TTL9, \ + SSD20XD_TTL_OFFSET_TTL10, \ + SSD20XD_TTL_OFFSET_TTL11, \ + SSD20XD_TTL_OFFSET_TTL12, \ + SSD20XD_TTL_OFFSET_TTL13, \ + SSD20XD_TTL_OFFSET_TTL14, \ + SSD20XD_TTL_OFFSET_TTL15, \ + SSD20XD_TTL_OFFSET_TTL16, \ + SSD20XD_TTL_OFFSET_TTL17, \ + SSD20XD_TTL_OFFSET_TTL18, \ + SSD20XD_TTL_OFFSET_TTL19, \ + SSD20XD_TTL_OFFSET_TTL20, \ + SSD20XD_TTL_OFFSET_TTL21, \ + SSD20XD_TTL_OFFSET_TTL22, \ + SSD20XD_TTL_OFFSET_TTL23, \ + SSD20XD_TTL_OFFSET_TTL24, \ + SSD20XD_TTL_OFFSET_TTL25, \ + SSD20XD_TTL_OFFSET_TTL26, \ + SSD20XD_TTL_OFFSET_TTL27 + +/* On the ssd20xd the two normal uarts have dedicated pins */ +#define SSD20XD_PINNAME_UART0_RX "uart0_rx" +#define SSD20XD_PINNAME_UART0_TX "uart0_tx" + +#define SSD20XD_UART0_NAMES \ + SSD20XD_PINNAME_UART0_RX, \ + SSD20XD_PINNAME_UART0_TX + +#define SSD20XD_PINNAME_UART1_RX "uart1_rx" +#define SSD20XD_PINNAME_UART1_TX "uart1_tx" + +#define SSD20XD_UART1_NAMES \ + SSD20XD_PINNAME_UART1_RX, \ + SSD20XD_PINNAME_UART1_TX + +#define SSD20XD_OFF_UART0_RX 0x60 +#define SSD20XD_OFF_UART0_TX 0x64 + +#define SSD20XD_UART0_OFFSETS \ + SSD20XD_OFF_UART0_RX, \ + SSD20XD_OFF_UART0_TX + +#define SSD20XD_OFF_UART1_RX 0x68 +#define SSD20XD_OFF_UART1_TX 0x6c + +#define SSD20XD_UART1_OFFSETS \ + SSD20XD_OFF_UART1_RX, \ + SSD20XD_OFF_UART1_TX + +/* + * ssd20x has the same pin names but different ordering + * of the registers that control the gpio. + */ +#define SSD20XD_OFF_SD_D0 0x140 +#define SSD20XD_OFF_SD_D1 0x144 +#define SSD20XD_OFF_SD_D2 0x148 +#define SSD20XD_OFF_SD_D3 0x14c +#define SSD20XD_OFF_SD_CMD 0x150 +#define SSD20XD_OFF_SD_CLK 0x154 + +#define SSD20XD_SD_OFFSETS SSD20XD_OFF_SD_CLK, \ + SSD20XD_OFF_SD_CMD, \ + SSD20XD_OFF_SD_D0, \ + SSD20XD_OFF_SD_D1, \ + SSD20XD_OFF_SD_D2, \ + SSD20XD_OFF_SD_D3 + +static const char * const ssd20xd_names[] = { + FUART_NAMES, + SD_NAMES, + SSD20XD_UART0_NAMES, + SSD20XD_UART1_NAMES, + SSD20XD_TTL_PINNAMES, + SSD20XD_GPIO_NAMES, +}; + +static const unsigned int ssd20xd_offsets[] = { + FUART_OFFSETS, + SSD20XD_SD_OFFSETS, + SSD20XD_UART0_OFFSETS, + SSD20XD_UART1_OFFSETS, + SSD20XD_TTL_OFFSETS, + SSD20XD_GPIO_OFFSETS, +}; + +MSC313_GPIO_CHIPDATA(ssd20xd); #endif struct msc313_gpio { @@ -344,7 +601,6 @@ static int msc313_gpio_probe(struct platform_device *pdev) struct irq_domain *parent_domain; struct device_node *parent_node; struct device *dev = &pdev->dev; - int ret; match_data = of_device_get_match_data(dev); if (!match_data) @@ -399,8 +655,7 @@ static int msc313_gpio_probe(struct platform_device *pdev) gpioirqchip->handler = handle_bad_irq; gpioirqchip->default_type = IRQ_TYPE_NONE; - ret = devm_gpiochip_add_data(dev, gpiochip, gpio); - return ret; + return devm_gpiochip_add_data(dev, gpiochip, gpio); } static int msc313_gpio_remove(struct platform_device *pdev) @@ -414,6 +669,10 @@ static const struct of_device_id msc313_gpio_of_match[] = { .compatible = "mstar,msc313-gpio", .data = &msc313_data, }, + { + .compatible = "sstar,ssd20xd-gpio", + .data = &ssd20xd_data, + }, #endif { } }; @@ -456,5 +715,4 @@ static struct platform_driver msc313_gpio_driver = { .probe = msc313_gpio_probe, .remove = msc313_gpio_remove, }; - builtin_platform_driver(msc313_gpio_driver); diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c index c3658a597a80..ccaad1cb3c2e 100644 --- a/drivers/gpio/gpio-mt7621.c +++ b/drivers/gpio/gpio-mt7621.c @@ -205,8 +205,7 @@ mediatek_gpio_xlate(struct gpio_chip *chip, } static int -mediatek_gpio_bank_probe(struct device *dev, - struct device_node *node, int bank) +mediatek_gpio_bank_probe(struct device *dev, int bank) { struct mtk *mtk = dev_get_drvdata(dev); struct mtk_gc *rg; @@ -217,7 +216,6 @@ mediatek_gpio_bank_probe(struct device *dev, memset(rg, 0, sizeof(*rg)); spin_lock_init(&rg->lock); - rg->chip.of_node = node; rg->bank = bank; dat = mtk->base + GPIO_REG_DATA + (rg->bank * GPIO_BANK_STRIDE); @@ -311,7 +309,7 @@ mediatek_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mtk); for (i = 0; i < MTK_BANK_CNT; i++) { - ret = mediatek_gpio_bank_probe(dev, np, i); + ret = mediatek_gpio_bank_probe(dev, i); if (ret) return ret; } diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 8f429d9f3661..4c1f9e1091b7 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1183,7 +1183,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; mvchip->chip.ngpio = ngpios; mvchip->chip.can_sleep = false; - mvchip->chip.of_node = np; mvchip->chip.dbg_show = mvebu_gpio_dbg_show; if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 415e8df89d6f..e099c39e0355 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1419,9 +1419,6 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->is_mpuio = pdata->is_mpuio; bank->non_wakeup_gpios = pdata->non_wakeup_gpios; bank->regs = pdata->regs; -#ifdef CONFIG_OF_GPIO - bank->chip.of_node = of_node_get(node); -#endif if (node) { if (!of_property_read_bool(node, "ti,gpio-always-on")) diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index e8e9029ba5bd..bac10c2faf56 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -170,9 +170,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->gpio_chip.set = palmas_gpio_set; palmas_gpio->gpio_chip.get = palmas_gpio_get; palmas_gpio->gpio_chip.parent = &pdev->dev; -#ifdef CONFIG_OF_GPIO - palmas_gpio->gpio_chip.of_node = pdev->dev.of_node; -#endif + palmas_pdata = dev_get_platdata(palmas->dev); if (palmas_pdata && palmas_pdata->gpio_base) palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base; diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index a552df298a97..3a0bd8795741 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -346,51 +346,45 @@ static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, static int pch_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; s32 ret; struct pch_gpio *chip; int irq_base; - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - chip->dev = &pdev->dev; + chip->dev = dev; ret = pcim_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "pci_enable_device FAILED"); + dev_err(dev, "pci_enable_device FAILED"); return ret; } ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME); if (ret) { - dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret); + dev_err(dev, "pci_request_regions FAILED-%d", ret); return ret; } chip->base = pcim_iomap_table(pdev)[1]; - - if (pdev->device == 0x8803) - chip->ioh = INTEL_EG20T_PCH; - else if (pdev->device == 0x8014) - chip->ioh = OKISEMI_ML7223m_IOH; - else if (pdev->device == 0x8043) - chip->ioh = OKISEMI_ML7223n_IOH; - + chip->ioh = id->driver_data; chip->reg = chip->base; pci_set_drvdata(pdev, chip); spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); - ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip); + ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); if (ret) { - dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n"); + dev_err(dev, "PCH gpio: Failed to register GPIO\n"); return ret; } - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, + irq_base = devm_irq_alloc_descs(dev, -1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE); if (irq_base < 0) { - dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n"); + dev_warn(dev, "PCH gpio: Failed to get IRQ base num\n"); chip->irq_base = -1; return 0; } @@ -400,10 +394,10 @@ static int pch_gpio_probe(struct pci_dev *pdev, iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->imask); iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->ien); - ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler, + ret = devm_request_irq(dev, pdev->irq, pch_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); if (ret) { - dev_err(&pdev->dev, "request_irq failed\n"); + dev_err(dev, "request_irq failed\n"); return ret; } @@ -439,10 +433,14 @@ static int __maybe_unused pch_gpio_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); static const struct pci_device_id pch_gpio_pcidev_id[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803), + .driver_data = INTEL_EG20T_PCH }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014), + .driver_data = OKISEMI_ML7223m_IOH }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043), + .driver_data = OKISEMI_ML7223n_IOH }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803), + .driver_data = INTEL_EG20T_PCH }, { 0, } }; MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c index 938285190566..e518490c4b68 100644 --- a/drivers/gpio/gpio-pmic-eic-sprd.c +++ b/drivers/gpio/gpio-pmic-eic-sprd.c @@ -331,7 +331,6 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev) pmic_eic->chip.ngpio = SPRD_PMIC_EIC_NR; pmic_eic->chip.base = -1; pmic_eic->chip.parent = &pdev->dev; - pmic_eic->chip.of_node = pdev->dev.of_node; pmic_eic->chip.direction_input = sprd_pmic_eic_direction_input; pmic_eic->chip.request = sprd_pmic_eic_request; pmic_eic->chip.free = sprd_pmic_eic_free; diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 382468e294e1..c7fbfa3ae43b 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -343,8 +343,7 @@ static int pxa_gpio_of_xlate(struct gpio_chip *gc, } #endif -static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, - struct device_node *np, void __iomem *regbase) +static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, void __iomem *regbase) { int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32); struct pxa_gpio_bank *bank; @@ -354,6 +353,7 @@ static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, if (!pchip->banks) return -ENOMEM; + pchip->chip.parent = pchip->dev; pchip->chip.label = "gpio-pxa"; pchip->chip.direction_input = pxa_gpio_direction_input; pchip->chip.direction_output = pxa_gpio_direction_output; @@ -365,7 +365,6 @@ static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, pchip->chip.free = gpiochip_generic_free; #ifdef CONFIG_OF_GPIO - pchip->chip.of_node = np; pchip->chip.of_xlate = pxa_gpio_of_xlate; pchip->chip.of_gpio_n_cells = 2; #endif @@ -675,8 +674,7 @@ static int pxa_gpio_probe(struct platform_device *pdev) } /* Initialize GPIO chips */ - ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, pdev->dev.of_node, - gpio_reg_base); + ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, gpio_reg_base); if (ret) { clk_put(clk); return ret; diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index 64a552ecc2ad..3c414e0005fc 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -221,7 +221,6 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) rpi_gpio->gc.parent = dev; rpi_gpio->gc.label = MODULE_NAME; rpi_gpio->gc.owner = THIS_MODULE; - rpi_gpio->gc.of_node = np; rpi_gpio->gc.base = -1; rpi_gpio->gc.ngpio = NUM_GPIO; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index f7b653314e7e..bd2e16d6e21c 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -477,7 +477,6 @@ static void gpio_rcar_enable_inputs(struct gpio_rcar_priv *p) static int gpio_rcar_probe(struct platform_device *pdev) { struct gpio_rcar_priv *p; - struct resource *irq; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; struct gpio_irq_chip *girq; @@ -502,12 +501,10 @@ static int gpio_rcar_probe(struct platform_device *pdev) pm_runtime_enable(dev); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(dev, "missing IRQ\n"); - ret = -EINVAL; + ret = platform_get_irq(pdev, 0); + if (ret < 0) goto err0; - } + p->irq_parent = ret; p->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(p->base)) { @@ -555,11 +552,10 @@ static int gpio_rcar_probe(struct platform_device *pdev) goto err0; } - p->irq_parent = irq->start; - if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, - IRQF_SHARED, name, p)) { + ret = devm_request_irq(dev, p->irq_parent, gpio_rcar_irq_handler, + IRQF_SHARED, name, p); + if (ret) { dev_err(dev, "failed to request IRQ\n"); - ret = -ENOENT; goto err1; } diff --git a/drivers/gpio/gpio-rda.c b/drivers/gpio/gpio-rda.c index 463846431183..62ba18b3a602 100644 --- a/drivers/gpio/gpio-rda.c +++ b/drivers/gpio/gpio-rda.c @@ -197,7 +197,6 @@ static void rda_gpio_irq_handler(struct irq_desc *desc) static int rda_gpio_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct gpio_irq_chip *girq; struct rda_gpio *rda_gpio; @@ -240,8 +239,6 @@ static int rda_gpio_probe(struct platform_device *pdev) rda_gpio->chip.label = dev_name(dev); rda_gpio->chip.ngpio = ngpios; rda_gpio->chip.base = -1; - rda_gpio->chip.parent = dev; - rda_gpio->chip.of_node = np; if (rda_gpio->irq >= 0) { rda_gpio->irq_chip.name = "rda-gpio", diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 69c219742083..6383136cbe59 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -244,16 +244,12 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config chip = &gpio->gpio_chip; chip->parent = config->parent; + chip->fwnode = config->fwnode; chip->base = -1; chip->ngpio = config->ngpio; chip->names = config->names; chip->label = config->label ?: dev_name(config->parent); -#if defined(CONFIG_OF_GPIO) - /* gpiolib will use of_node of the parent if chip->of_node is NULL */ - chip->of_node = to_of_node(config->fwnode); -#endif /* CONFIG_OF_GPIO */ - /* * If our regmap is fast_io we should probably set can_sleep to false. * Right now, the regmap doesn't save this property, nor is there any diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index ce63cbd14d69..a4c4e4584f5b 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -465,6 +465,22 @@ out: return ret; } +static int rockchip_irq_reqres(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct rockchip_pin_bank *bank = gc->private; + + return gpiochip_reqres_irq(&bank->gpio_chip, d->hwirq); +} + +static void rockchip_irq_relres(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct rockchip_pin_bank *bank = gc->private; + + gpiochip_relres_irq(&bank->gpio_chip, d->hwirq); +} + static void rockchip_irq_suspend(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); @@ -536,6 +552,8 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank) gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend; gc->chip_types[0].chip.irq_resume = rockchip_irq_resume; gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; + gc->chip_types[0].chip.irq_request_resources = rockchip_irq_reqres; + gc->chip_types[0].chip.irq_release_resources = rockchip_irq_relres; gc->wake_enabled = IRQ_MSK(bank->nr_pins); /* @@ -566,9 +584,6 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) gc->ngpio = bank->nr_pins; gc->label = bank->name; gc->parent = bank->dev; -#ifdef CONFIG_OF_GPIO - gc->of_node = of_node_get(bank->of_node); -#endif ret = gpiochip_add_data(gc, bank); if (ret) { diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c index b7c950658170..3e95da717fc9 100644 --- a/drivers/gpio/gpio-sama5d2-piobu.c +++ b/drivers/gpio/gpio-sama5d2-piobu.c @@ -192,7 +192,6 @@ static int sama5d2_piobu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, piobu); piobu->chip.label = pdev->name; piobu->chip.parent = &pdev->dev; - piobu->chip.of_node = pdev->dev.of_node; piobu->chip.owner = THIS_MODULE, piobu->chip.get_direction = sama5d2_piobu_get_direction, piobu->chip.direction_input = sama5d2_piobu_direction_input, diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 0600f71462b5..acda4c5052d3 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -139,7 +139,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num, /* * according to the datasheet, writing to the level register has no * effect when GPIO is programmed as input. - * Actually the the level register is read-only when configured as input. + * Actually the level register is read-only when configured as input. * Thus presetting the output level before switching to output is _NOT_ possible. * Hence we set the level after configuring the GPIO as output. * But we cannot prevent a short low pulse if direction is set to high diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c new file mode 100644 index 000000000000..838bbfed11d3 --- /dev/null +++ b/drivers/gpio/gpio-sim.c @@ -0,0 +1,1592 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * GPIO testing driver based on configfs. + * + * Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bitmap.h> +#include <linux/completion.h> +#include <linux/configfs.h> +#include <linux/device.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> +#include <linux/idr.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irq_sim.h> +#include <linux/list.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/string_helpers.h> +#include <linux/sysfs.h> + +#include "gpiolib.h" + +#define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ +#define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ + +static DEFINE_IDA(gpio_sim_ida); + +struct gpio_sim_chip { + struct gpio_chip gc; + unsigned long *direction_map; + unsigned long *value_map; + unsigned long *pull_map; + struct irq_domain *irq_sim; + struct mutex lock; + const struct attribute_group **attr_groups; +}; + +struct gpio_sim_attribute { + struct device_attribute dev_attr; + unsigned int offset; +}; + +static struct gpio_sim_attribute * +to_gpio_sim_attr(struct device_attribute *dev_attr) +{ + return container_of(dev_attr, struct gpio_sim_attribute, dev_attr); +} + +static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, + unsigned int offset, int value) +{ + int irq, irq_type, ret; + struct gpio_desc *desc; + struct gpio_chip *gc; + + gc = &chip->gc; + desc = &gc->gpiodev->descs[offset]; + + mutex_lock(&chip->lock); + + if (test_bit(FLAG_REQUESTED, &desc->flags) && + !test_bit(FLAG_IS_OUT, &desc->flags)) { + if (value == !!test_bit(offset, chip->value_map)) + goto set_pull; + + /* + * This is fine - it just means, nobody is listening + * for interrupts on this line, otherwise + * irq_create_mapping() would have been called from + * the to_irq() callback. + */ + irq = irq_find_mapping(chip->irq_sim, offset); + if (!irq) + goto set_value; + + irq_type = irq_get_trigger_type(irq); + + if ((value && (irq_type & IRQ_TYPE_EDGE_RISING)) || + (!value && (irq_type & IRQ_TYPE_EDGE_FALLING))) { + ret = irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, + true); + if (ret) + goto set_pull; + } + } + +set_value: + /* Change the value unless we're actively driving the line. */ + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + !test_bit(FLAG_IS_OUT, &desc->flags)) + __assign_bit(offset, chip->value_map, value); + +set_pull: + __assign_bit(offset, chip->pull_map, value); + mutex_unlock(&chip->lock); + return 0; +} + +static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + int ret; + + mutex_lock(&chip->lock); + ret = !!test_bit(offset, chip->value_map); + mutex_unlock(&chip->lock); + + return ret; +} + +static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->lock); + __assign_bit(offset, chip->value_map, value); + mutex_unlock(&chip->lock); +} + +static int gpio_sim_get_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->lock); + bitmap_copy(bits, chip->value_map, gc->ngpio); + mutex_unlock(&chip->lock); + + return 0; +} + +static void gpio_sim_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->lock); + bitmap_copy(chip->value_map, bits, gc->ngpio); + mutex_unlock(&chip->lock); +} + +static int gpio_sim_direction_output(struct gpio_chip *gc, + unsigned int offset, int value) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->lock); + __clear_bit(offset, chip->direction_map); + __assign_bit(offset, chip->value_map, value); + mutex_unlock(&chip->lock); + + return 0; +} + +static int gpio_sim_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->lock); + __set_bit(offset, chip->direction_map); + mutex_unlock(&chip->lock); + + return 0; +} + +static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + int direction; + + mutex_lock(&chip->lock); + direction = !!test_bit(offset, chip->direction_map); + mutex_unlock(&chip->lock); + + return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; +} + +static int gpio_sim_set_config(struct gpio_chip *gc, + unsigned int offset, unsigned long config) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_UP: + return gpio_sim_apply_pull(chip, offset, 1); + case PIN_CONFIG_BIAS_PULL_DOWN: + return gpio_sim_apply_pull(chip, offset, 0); + default: + break; + } + + return -ENOTSUPP; +} + +static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + return irq_create_mapping(chip->irq_sim, offset); +} + +static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + mutex_lock(&chip->lock); + __assign_bit(offset, chip->value_map, !!test_bit(offset, chip->pull_map)); + mutex_unlock(&chip->lock); +} + +static ssize_t gpio_sim_sysfs_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(attr); + struct gpio_sim_chip *chip = dev_get_drvdata(dev); + int val; + + mutex_lock(&chip->lock); + val = !!test_bit(line_attr->offset, chip->value_map); + mutex_unlock(&chip->lock); + + return sysfs_emit(buf, "%d\n", val); +} + +static ssize_t gpio_sim_sysfs_val_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /* + * Not assigning this function will result in write() returning -EIO + * which is confusing. Return -EPERM explicitly. + */ + return -EPERM; +} + +static const char *const gpio_sim_sysfs_pull_strings[] = { + [0] = "pull-down", + [1] = "pull-up", +}; + +static ssize_t gpio_sim_sysfs_pull_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(attr); + struct gpio_sim_chip *chip = dev_get_drvdata(dev); + int pull; + + mutex_lock(&chip->lock); + pull = !!test_bit(line_attr->offset, chip->pull_map); + mutex_unlock(&chip->lock); + + return sysfs_emit(buf, "%s\n", gpio_sim_sysfs_pull_strings[pull]); +} + +static ssize_t gpio_sim_sysfs_pull_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(attr); + struct gpio_sim_chip *chip = dev_get_drvdata(dev); + int ret, pull; + + pull = sysfs_match_string(gpio_sim_sysfs_pull_strings, buf); + if (pull < 0) + return pull; + + ret = gpio_sim_apply_pull(chip, line_attr->offset, pull); + if (ret) + return ret; + + return len; +} + +static void gpio_sim_mutex_destroy(void *data) +{ + struct mutex *lock = data; + + mutex_destroy(lock); +} + +static void gpio_sim_sysfs_remove(void *data) +{ + struct gpio_sim_chip *chip = data; + + sysfs_remove_groups(&chip->gc.gpiodev->dev.kobj, chip->attr_groups); +} + +static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) +{ + struct device_attribute *val_dev_attr, *pull_dev_attr; + struct gpio_sim_attribute *val_attr, *pull_attr; + unsigned int num_lines = chip->gc.ngpio; + struct device *dev = chip->gc.parent; + struct attribute_group *attr_group; + struct attribute **attrs; + int i, ret; + + chip->attr_groups = devm_kcalloc(dev, sizeof(*chip->attr_groups), + num_lines + 1, GFP_KERNEL); + if (!chip->attr_groups) + return -ENOMEM; + + for (i = 0; i < num_lines; i++) { + attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL); + attrs = devm_kcalloc(dev, sizeof(*attrs), + GPIO_SIM_NUM_ATTRS, GFP_KERNEL); + val_attr = devm_kzalloc(dev, sizeof(*val_attr), GFP_KERNEL); + pull_attr = devm_kzalloc(dev, sizeof(*pull_attr), GFP_KERNEL); + if (!attr_group || !attrs || !val_attr || !pull_attr) + return -ENOMEM; + + attr_group->name = devm_kasprintf(dev, GFP_KERNEL, + "sim_gpio%u", i); + if (!attr_group->name) + return -ENOMEM; + + val_attr->offset = pull_attr->offset = i; + + val_dev_attr = &val_attr->dev_attr; + pull_dev_attr = &pull_attr->dev_attr; + + sysfs_attr_init(&val_dev_attr->attr); + sysfs_attr_init(&pull_dev_attr->attr); + + val_dev_attr->attr.name = "value"; + pull_dev_attr->attr.name = "pull"; + + val_dev_attr->attr.mode = pull_dev_attr->attr.mode = 0644; + + val_dev_attr->show = gpio_sim_sysfs_val_show; + val_dev_attr->store = gpio_sim_sysfs_val_store; + pull_dev_attr->show = gpio_sim_sysfs_pull_show; + pull_dev_attr->store = gpio_sim_sysfs_pull_store; + + attrs[0] = &val_dev_attr->attr; + attrs[1] = &pull_dev_attr->attr; + + attr_group->attrs = attrs; + chip->attr_groups[i] = attr_group; + } + + ret = sysfs_create_groups(&chip->gc.gpiodev->dev.kobj, + chip->attr_groups); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip); +} + +static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) +{ + struct gpio_sim_chip *chip; + struct gpio_chip *gc; + const char *label; + u32 num_lines; + int ret; + + ret = fwnode_property_read_u32(swnode, "ngpios", &num_lines); + if (ret) + return ret; + + ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label); + if (ret) { + label = devm_kasprintf(dev, GFP_KERNEL, "%s-%s", + dev_name(dev), fwnode_get_name(swnode)); + if (!label) + return -ENOMEM; + } + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->direction_map = devm_bitmap_alloc(dev, num_lines, GFP_KERNEL); + if (!chip->direction_map) + return -ENOMEM; + + /* Default to input mode. */ + bitmap_fill(chip->direction_map, num_lines); + + chip->value_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL); + if (!chip->value_map) + return -ENOMEM; + + chip->pull_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL); + if (!chip->pull_map) + return -ENOMEM; + + chip->irq_sim = devm_irq_domain_create_sim(dev, NULL, num_lines); + if (IS_ERR(chip->irq_sim)) + return PTR_ERR(chip->irq_sim); + + mutex_init(&chip->lock); + ret = devm_add_action_or_reset(dev, gpio_sim_mutex_destroy, + &chip->lock); + if (ret) + return ret; + + gc = &chip->gc; + gc->base = -1; + gc->ngpio = num_lines; + gc->label = label; + gc->owner = THIS_MODULE; + gc->parent = dev; + gc->fwnode = swnode; + gc->get = gpio_sim_get; + gc->set = gpio_sim_set; + gc->get_multiple = gpio_sim_get_multiple; + gc->set_multiple = gpio_sim_set_multiple; + gc->direction_output = gpio_sim_direction_output; + gc->direction_input = gpio_sim_direction_input; + gc->get_direction = gpio_sim_get_direction; + gc->set_config = gpio_sim_set_config; + gc->to_irq = gpio_sim_to_irq; + gc->free = gpio_sim_free; + + ret = devm_gpiochip_add_data(dev, gc, chip); + if (ret) + return ret; + + /* Used by sysfs and configfs callbacks. */ + dev_set_drvdata(&gc->gpiodev->dev, chip); + + return gpio_sim_setup_sysfs(chip); +} + +static int gpio_sim_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fwnode_handle *swnode; + int ret; + + device_for_each_child_node(dev, swnode) { + ret = gpio_sim_add_bank(swnode, dev); + if (ret) { + fwnode_handle_put(swnode); + return ret; + } + } + + return 0; +} + +static const struct of_device_id gpio_sim_of_match[] = { + { .compatible = "gpio-simulator" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpio_sim_of_match); + +static struct platform_driver gpio_sim_driver = { + .driver = { + .name = "gpio-sim", + .of_match_table = gpio_sim_of_match, + }, + .probe = gpio_sim_probe, +}; + +struct gpio_sim_device { + struct config_group group; + + /* + * If pdev is NULL, the device is 'pending' (waiting for configuration). + * Once the pointer is assigned, the device has been created and the + * item is 'live'. + */ + struct platform_device *pdev; + int id; + + /* + * Each configfs filesystem operation is protected with the subsystem + * mutex. Each separate attribute is protected with the buffer mutex. + * This structure however can be modified by callbacks of different + * attributes so we need another lock. + * + * We use this lock fo protecting all data structures owned by this + * object too. + */ + struct mutex lock; + + /* + * This is used to synchronously wait for the driver's probe to complete + * and notify the user-space about any errors. + */ + struct notifier_block bus_notifier; + struct completion probe_completion; + bool driver_bound; + + struct gpiod_hog *hogs; + + struct list_head bank_list; +}; + +/* This is called with dev->lock already taken. */ +static int gpio_sim_bus_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct gpio_sim_device *simdev = container_of(nb, + struct gpio_sim_device, + bus_notifier); + struct device *dev = data; + char devname[32]; + + snprintf(devname, sizeof(devname), "gpio-sim.%u", simdev->id); + + if (strcmp(dev_name(dev), devname) == 0) { + if (action == BUS_NOTIFY_BOUND_DRIVER) + simdev->driver_bound = true; + else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) + simdev->driver_bound = false; + else + return NOTIFY_DONE; + + complete(&simdev->probe_completion); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_sim_device, group); +} + +struct gpio_sim_bank { + struct config_group group; + + /* + * We could have used the ci_parent field of the config_item but + * configfs is stupid and calls the item's release callback after + * already having cleared the parent pointer even though the parent + * is guaranteed to survive the child... + * + * So we need to store the pointer to the parent struct here. We can + * dereference it anywhere we need with no checks and no locking as + * it's guaranteed to survive the childred and protected by configfs + * locks. + * + * Same for other structures. + */ + struct gpio_sim_device *parent; + struct list_head siblings; + + char *label; + unsigned int num_lines; + + struct list_head line_list; + + struct fwnode_handle *swnode; +}; + +static struct gpio_sim_bank *to_gpio_sim_bank(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_sim_bank, group); +} + +static struct gpio_sim_device * +gpio_sim_bank_get_device(struct gpio_sim_bank *bank) +{ + return bank->parent; +} + +struct gpio_sim_hog; + +struct gpio_sim_line { + struct config_group group; + + struct gpio_sim_bank *parent; + struct list_head siblings; + + unsigned int offset; + char *name; + + /* There can only be one hog per line. */ + struct gpio_sim_hog *hog; +}; + +static struct gpio_sim_line *to_gpio_sim_line(struct config_item *item) +{ + struct config_group *group = to_config_group(item); + + return container_of(group, struct gpio_sim_line, group); +} + +static struct gpio_sim_device * +gpio_sim_line_get_device(struct gpio_sim_line *line) +{ + struct gpio_sim_bank *bank = line->parent; + + return gpio_sim_bank_get_device(bank); +} + +struct gpio_sim_hog { + struct config_item item; + struct gpio_sim_line *parent; + + char *name; + int dir; +}; + +static struct gpio_sim_hog *to_gpio_sim_hog(struct config_item *item) +{ + return container_of(item, struct gpio_sim_hog, item); +} + +static struct gpio_sim_device *gpio_sim_hog_get_device(struct gpio_sim_hog *hog) +{ + struct gpio_sim_line *line = hog->parent; + + return gpio_sim_line_get_device(line); +} + +static bool gpio_sim_device_is_live_unlocked(struct gpio_sim_device *dev) +{ + return !!dev->pdev; +} + +static char *gpio_sim_strdup_trimmed(const char *str, size_t count) +{ + char *dup, *trimmed; + + dup = kstrndup(str, count, GFP_KERNEL); + if (!dup) + return NULL; + + trimmed = strstrip(dup); + memmove(dup, trimmed, strlen(trimmed) + 1); + + return dup; +} + +static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, + char *page) +{ + struct gpio_sim_device *dev = to_gpio_sim_device(item); + struct platform_device *pdev; + int ret; + + mutex_lock(&dev->lock); + pdev = dev->pdev; + if (pdev) + ret = sprintf(page, "%s\n", dev_name(&pdev->dev)); + else + ret = sprintf(page, "gpio-sim.%d\n", dev->id); + mutex_unlock(&dev->lock); + + return ret; +} + +CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name); + +static ssize_t +gpio_sim_device_config_live_show(struct config_item *item, char *page) +{ + struct gpio_sim_device *dev = to_gpio_sim_device(item); + bool live; + + mutex_lock(&dev->lock); + live = gpio_sim_device_is_live_unlocked(dev); + mutex_unlock(&dev->lock); + + return sprintf(page, "%c\n", live ? '1' : '0'); +} + +static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank, + unsigned int *line_names_size) +{ + unsigned int max_offset = 0; + bool has_line_names = false; + struct gpio_sim_line *line; + char **line_names; + + list_for_each_entry(line, &bank->line_list, siblings) { + if (line->name) { + if (line->offset > max_offset) + max_offset = line->offset; + + /* + * max_offset can stay at 0 so it's not an indicator + * of whether line names were configured at all. + */ + has_line_names = true; + } + } + + if (!has_line_names) + /* + * This is not an error - NULL means, there are no line + * names configured. + */ + return NULL; + + *line_names_size = max_offset + 1; + + line_names = kcalloc(*line_names_size, sizeof(*line_names), GFP_KERNEL); + if (!line_names) + return ERR_PTR(-ENOMEM); + + list_for_each_entry(line, &bank->line_list, siblings) + line_names[line->offset] = line->name; + + return line_names; +} + +static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) +{ + struct gpiod_hog *hog; + + if (!dev->hogs) + return; + + gpiod_remove_hogs(dev->hogs); + + for (hog = dev->hogs; !hog->chip_label; hog++) { + kfree(hog->chip_label); + kfree(hog->line_name); + } + + kfree(dev->hogs); + dev->hogs = NULL; +} + +static int gpio_sim_add_hogs(struct gpio_sim_device *dev) +{ + unsigned int num_hogs = 0, idx = 0; + struct gpio_sim_bank *bank; + struct gpio_sim_line *line; + struct gpiod_hog *hog; + + list_for_each_entry(bank, &dev->bank_list, siblings) { + list_for_each_entry(line, &bank->line_list, siblings) { + if (line->hog) + num_hogs++; + } + } + + if (!num_hogs) + return 0; + + /* Allocate one more for the sentinel. */ + dev->hogs = kcalloc(num_hogs + 1, sizeof(*dev->hogs), GFP_KERNEL); + if (!dev->hogs) + return -ENOMEM; + + list_for_each_entry(bank, &dev->bank_list, siblings) { + list_for_each_entry(line, &bank->line_list, siblings) { + if (!line->hog) + continue; + + hog = &dev->hogs[idx++]; + + /* + * We need to make this string manually because at this + * point the device doesn't exist yet and so dev_name() + * is not available. + */ + hog->chip_label = kasprintf(GFP_KERNEL, + "gpio-sim.%u-%s", dev->id, + fwnode_get_name(bank->swnode)); + if (!hog->chip_label) { + gpio_sim_remove_hogs(dev); + return -ENOMEM; + } + + /* + * We need to duplicate this because the hog config + * item can be removed at any time (and we can't block + * it) and gpiolib doesn't make a deep copy of the hog + * data. + */ + if (line->hog->name) { + hog->line_name = kstrdup(line->hog->name, + GFP_KERNEL); + if (!hog->line_name) { + gpio_sim_remove_hogs(dev); + return -ENOMEM; + } + } + + hog->chip_hwnum = line->offset; + hog->dflags = line->hog->dir; + } + } + + gpiod_add_hogs(dev->hogs); + + return 0; +} + +static struct fwnode_handle * +gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, + struct fwnode_handle *parent) +{ + struct property_entry properties[GPIO_SIM_PROP_MAX]; + unsigned int prop_idx = 0, line_names_size = 0; + struct fwnode_handle *swnode; + char **line_names; + + memset(properties, 0, sizeof(properties)); + + properties[prop_idx++] = PROPERTY_ENTRY_U32("ngpios", bank->num_lines); + + if (bank->label) + properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label", + bank->label); + + line_names = gpio_sim_make_line_names(bank, &line_names_size); + if (IS_ERR(line_names)) + return ERR_CAST(line_names); + + if (line_names) + properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( + "gpio-line-names", + line_names, line_names_size); + + swnode = fwnode_create_software_node(properties, parent); + kfree(line_names); + return swnode; +} + +static void gpio_sim_remove_swnode_recursive(struct fwnode_handle *swnode) +{ + struct fwnode_handle *child; + + fwnode_for_each_child_node(swnode, child) + fwnode_remove_software_node(child); + + fwnode_remove_software_node(swnode); +} + +static bool gpio_sim_bank_labels_non_unique(struct gpio_sim_device *dev) +{ + struct gpio_sim_bank *this, *pos; + + list_for_each_entry(this, &dev->bank_list, siblings) { + list_for_each_entry(pos, &dev->bank_list, siblings) { + if (this == pos || (!this->label || !pos->label)) + continue; + + if (strcmp(this->label, pos->label) == 0) + return true; + } + } + + return false; +} + +static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev) +{ + struct platform_device_info pdevinfo; + struct fwnode_handle *swnode; + struct platform_device *pdev; + struct gpio_sim_bank *bank; + int ret; + + if (list_empty(&dev->bank_list)) + return -ENODATA; + + /* + * Non-unique GPIO device labels are a corner-case we don't support + * as it would interfere with machine hogging mechanism and has little + * use in real life. + */ + if (gpio_sim_bank_labels_non_unique(dev)) + return -EINVAL; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + + swnode = fwnode_create_software_node(NULL, NULL); + if (IS_ERR(swnode)) + return PTR_ERR(swnode); + + list_for_each_entry(bank, &dev->bank_list, siblings) { + bank->swnode = gpio_sim_make_bank_swnode(bank, swnode); + if (IS_ERR(bank->swnode)) { + ret = PTR_ERR(bank->swnode); + gpio_sim_remove_swnode_recursive(swnode); + return ret; + } + } + + ret = gpio_sim_add_hogs(dev); + if (ret) { + gpio_sim_remove_swnode_recursive(swnode); + return ret; + } + + pdevinfo.name = "gpio-sim"; + pdevinfo.fwnode = swnode; + pdevinfo.id = dev->id; + + reinit_completion(&dev->probe_completion); + dev->driver_bound = false; + bus_register_notifier(&platform_bus_type, &dev->bus_notifier); + + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) { + bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); + gpio_sim_remove_hogs(dev); + gpio_sim_remove_swnode_recursive(swnode); + return PTR_ERR(pdev); + } + + wait_for_completion(&dev->probe_completion); + bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); + + if (!dev->driver_bound) { + /* Probe failed, check kernel log. */ + platform_device_unregister(pdev); + gpio_sim_remove_hogs(dev); + gpio_sim_remove_swnode_recursive(swnode); + return -ENXIO; + } + + dev->pdev = pdev; + + return 0; +} + +static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev) +{ + struct fwnode_handle *swnode; + + swnode = dev_fwnode(&dev->pdev->dev); + platform_device_unregister(dev->pdev); + gpio_sim_remove_swnode_recursive(swnode); + dev->pdev = NULL; + gpio_sim_remove_hogs(dev); +} + +static ssize_t +gpio_sim_device_config_live_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_device *dev = to_gpio_sim_device(item); + bool live; + int ret; + + ret = kstrtobool(page, &live); + if (ret) + return ret; + + mutex_lock(&dev->lock); + + if ((!live && !gpio_sim_device_is_live_unlocked(dev)) || + (live && gpio_sim_device_is_live_unlocked(dev))) + ret = -EPERM; + else if (live) + ret = gpio_sim_device_activate_unlocked(dev); + else + gpio_sim_device_deactivate_unlocked(dev); + + mutex_unlock(&dev->lock); + + return ret ?: count; +} + +CONFIGFS_ATTR(gpio_sim_device_config_, live); + +static struct configfs_attribute *gpio_sim_device_config_attrs[] = { + &gpio_sim_device_config_attr_dev_name, + &gpio_sim_device_config_attr_live, + NULL +}; + +struct gpio_sim_chip_name_ctx { + struct gpio_sim_device *dev; + char *page; +}; + +static int gpio_sim_emit_chip_name(struct device *dev, void *data) +{ + struct gpio_sim_chip_name_ctx *ctx = data; + struct fwnode_handle *swnode; + struct gpio_sim_bank *bank; + + /* This would be the sysfs device exported in /sys/class/gpio. */ + if (dev->class) + return 0; + + swnode = dev_fwnode(dev); + + list_for_each_entry(bank, &ctx->dev->bank_list, siblings) { + if (bank->swnode == swnode) + return sprintf(ctx->page, "%s\n", dev_name(dev)); + } + + return -ENODATA; +} + +static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, + char *page) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + struct gpio_sim_chip_name_ctx ctx = { dev, page }; + int ret; + + mutex_lock(&dev->lock); + if (gpio_sim_device_is_live_unlocked(dev)) + ret = device_for_each_child(&dev->pdev->dev, &ctx, + gpio_sim_emit_chip_name); + else + ret = sprintf(page, "none\n"); + mutex_unlock(&dev->lock); + + return ret; +} + +CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name); + +static ssize_t +gpio_sim_bank_config_label_show(struct config_item *item, char *page) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + int ret; + + mutex_lock(&dev->lock); + ret = sprintf(page, "%s\n", bank->label ?: ""); + mutex_unlock(&dev->lock); + + return ret; +} + +static ssize_t gpio_sim_bank_config_label_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + char *trimmed; + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return -EBUSY; + } + + trimmed = gpio_sim_strdup_trimmed(page, count); + if (!trimmed) { + mutex_unlock(&dev->lock); + return -ENOMEM; + } + + kfree(bank->label); + bank->label = trimmed; + + mutex_unlock(&dev->lock); + return count; +} + +CONFIGFS_ATTR(gpio_sim_bank_config_, label); + +static ssize_t +gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + int ret; + + mutex_lock(&dev->lock); + ret = sprintf(page, "%u\n", bank->num_lines); + mutex_unlock(&dev->lock); + + return ret; +} + +static ssize_t +gpio_sim_bank_config_num_lines_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + unsigned int num_lines; + int ret; + + ret = kstrtouint(page, 0, &num_lines); + if (ret) + return ret; + + if (num_lines == 0) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return -EBUSY; + } + + bank->num_lines = num_lines; + + mutex_unlock(&dev->lock); + return count; +} + +CONFIGFS_ATTR(gpio_sim_bank_config_, num_lines); + +static struct configfs_attribute *gpio_sim_bank_config_attrs[] = { + &gpio_sim_bank_config_attr_chip_name, + &gpio_sim_bank_config_attr_label, + &gpio_sim_bank_config_attr_num_lines, + NULL +}; + +static ssize_t +gpio_sim_line_config_name_show(struct config_item *item, char *page) +{ + struct gpio_sim_line *line = to_gpio_sim_line(item); + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); + int ret; + + mutex_lock(&dev->lock); + ret = sprintf(page, "%s\n", line->name ?: ""); + mutex_unlock(&dev->lock); + + return ret; +} + +static ssize_t gpio_sim_line_config_name_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_line *line = to_gpio_sim_line(item); + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); + char *trimmed; + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return -EBUSY; + } + + trimmed = gpio_sim_strdup_trimmed(page, count); + if (!trimmed) { + mutex_unlock(&dev->lock); + return -ENOMEM; + } + + kfree(line->name); + line->name = trimmed; + + mutex_unlock(&dev->lock); + + return count; +} + +CONFIGFS_ATTR(gpio_sim_line_config_, name); + +static struct configfs_attribute *gpio_sim_line_config_attrs[] = { + &gpio_sim_line_config_attr_name, + NULL +}; + +static ssize_t gpio_sim_hog_config_name_show(struct config_item *item, + char *page) +{ + struct gpio_sim_hog *hog = to_gpio_sim_hog(item); + struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); + int ret; + + mutex_lock(&dev->lock); + ret = sprintf(page, "%s\n", hog->name ?: ""); + mutex_unlock(&dev->lock); + + return ret; +} + +static ssize_t gpio_sim_hog_config_name_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_hog *hog = to_gpio_sim_hog(item); + struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); + char *trimmed; + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return -EBUSY; + } + + trimmed = gpio_sim_strdup_trimmed(page, count); + if (!trimmed) { + mutex_unlock(&dev->lock); + return -ENOMEM; + } + + kfree(hog->name); + hog->name = trimmed; + + mutex_unlock(&dev->lock); + + return count; +} + +CONFIGFS_ATTR(gpio_sim_hog_config_, name); + +static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item, + char *page) +{ + struct gpio_sim_hog *hog = to_gpio_sim_hog(item); + struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); + char *repr; + int dir; + + mutex_lock(&dev->lock); + dir = hog->dir; + mutex_unlock(&dev->lock); + + switch (dir) { + case GPIOD_IN: + repr = "input"; + break; + case GPIOD_OUT_HIGH: + repr = "output-high"; + break; + case GPIOD_OUT_LOW: + repr = "output-low"; + break; + default: + /* This would be a programmer bug. */ + WARN(1, "Unexpected hog direction value: %d", dir); + return -EINVAL; + } + + return sprintf(page, "%s\n", repr); +} + +static ssize_t +gpio_sim_hog_config_direction_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_hog *hog = to_gpio_sim_hog(item); + struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); + char *trimmed; + int dir; + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return -EBUSY; + } + + trimmed = gpio_sim_strdup_trimmed(page, count); + if (!trimmed) { + mutex_unlock(&dev->lock); + return -ENOMEM; + } + + if (strcmp(trimmed, "input") == 0) + dir = GPIOD_IN; + else if (strcmp(trimmed, "output-high") == 0) + dir = GPIOD_OUT_HIGH; + else if (strcmp(trimmed, "output-low") == 0) + dir = GPIOD_OUT_LOW; + else + dir = -EINVAL; + + kfree(trimmed); + + if (dir < 0) { + mutex_unlock(&dev->lock); + return dir; + } + + hog->dir = dir; + + mutex_unlock(&dev->lock); + + return count; +} + +CONFIGFS_ATTR(gpio_sim_hog_config_, direction); + +static struct configfs_attribute *gpio_sim_hog_config_attrs[] = { + &gpio_sim_hog_config_attr_name, + &gpio_sim_hog_config_attr_direction, + NULL +}; + +static void gpio_sim_hog_config_item_release(struct config_item *item) +{ + struct gpio_sim_hog *hog = to_gpio_sim_hog(item); + struct gpio_sim_line *line = hog->parent; + struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); + + mutex_lock(&dev->lock); + line->hog = NULL; + mutex_unlock(&dev->lock); + + kfree(hog->name); + kfree(hog); +} + +struct configfs_item_operations gpio_sim_hog_config_item_ops = { + .release = gpio_sim_hog_config_item_release, +}; + +static const struct config_item_type gpio_sim_hog_config_type = { + .ct_item_ops = &gpio_sim_hog_config_item_ops, + .ct_attrs = gpio_sim_hog_config_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_item * +gpio_sim_line_config_make_hog_item(struct config_group *group, const char *name) +{ + struct gpio_sim_line *line = to_gpio_sim_line(&group->cg_item); + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); + struct gpio_sim_hog *hog; + + if (strcmp(name, "hog") != 0) + return ERR_PTR(-EINVAL); + + mutex_lock(&dev->lock); + + hog = kzalloc(sizeof(*hog), GFP_KERNEL); + if (!hog) { + mutex_unlock(&dev->lock); + return ERR_PTR(-ENOMEM); + } + + config_item_init_type_name(&hog->item, name, + &gpio_sim_hog_config_type); + + hog->dir = GPIOD_IN; + hog->name = NULL; + hog->parent = line; + line->hog = hog; + + mutex_unlock(&dev->lock); + + return &hog->item; +} + +static void gpio_sim_line_config_group_release(struct config_item *item) +{ + struct gpio_sim_line *line = to_gpio_sim_line(item); + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); + + mutex_lock(&dev->lock); + list_del(&line->siblings); + mutex_unlock(&dev->lock); + + kfree(line->name); + kfree(line); +} + +static 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 = { + .make_item = gpio_sim_line_config_make_hog_item, +}; + +static const struct config_item_type gpio_sim_line_config_type = { + .ct_item_ops = &gpio_sim_line_config_item_ops, + .ct_group_ops = &gpio_sim_line_config_group_ops, + .ct_attrs = gpio_sim_line_config_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group * +gpio_sim_bank_config_make_line_group(struct config_group *group, + const char *name) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(&group->cg_item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + struct gpio_sim_line *line; + unsigned int offset; + int ret, nchar; + + ret = sscanf(name, "line%u%n", &offset, &nchar); + if (ret != 1 || nchar != strlen(name)) + return ERR_PTR(-EINVAL); + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return ERR_PTR(-EBUSY); + } + + line = kzalloc(sizeof(*line), GFP_KERNEL); + if (!line) { + mutex_unlock(&dev->lock); + return ERR_PTR(-ENOMEM); + } + + config_group_init_type_name(&line->group, name, + &gpio_sim_line_config_type); + + line->parent = bank; + line->offset = offset; + list_add_tail(&line->siblings, &bank->line_list); + + mutex_unlock(&dev->lock); + + return &line->group; +} + +static void gpio_sim_bank_config_group_release(struct config_item *item) +{ + struct gpio_sim_bank *bank = to_gpio_sim_bank(item); + struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); + + mutex_lock(&dev->lock); + list_del(&bank->siblings); + mutex_unlock(&dev->lock); + + kfree(bank->label); + kfree(bank); +} + +static 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 = { + .make_group = gpio_sim_bank_config_make_line_group, +}; + +static const struct config_item_type gpio_sim_bank_config_group_type = { + .ct_item_ops = &gpio_sim_bank_config_item_ops, + .ct_group_ops = &gpio_sim_bank_config_group_ops, + .ct_attrs = gpio_sim_bank_config_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group * +gpio_sim_device_config_make_bank_group(struct config_group *group, + const char *name) +{ + struct gpio_sim_device *dev = to_gpio_sim_device(&group->cg_item); + struct gpio_sim_bank *bank; + + mutex_lock(&dev->lock); + + if (gpio_sim_device_is_live_unlocked(dev)) { + mutex_unlock(&dev->lock); + return ERR_PTR(-EBUSY); + } + + bank = kzalloc(sizeof(*bank), GFP_KERNEL); + if (!bank) { + mutex_unlock(&dev->lock); + return ERR_PTR(-ENOMEM); + } + + config_group_init_type_name(&bank->group, name, + &gpio_sim_bank_config_group_type); + bank->num_lines = 1; + bank->parent = dev; + INIT_LIST_HEAD(&bank->line_list); + list_add_tail(&bank->siblings, &dev->bank_list); + + mutex_unlock(&dev->lock); + + return &bank->group; +} + +static void gpio_sim_device_config_group_release(struct config_item *item) +{ + struct gpio_sim_device *dev = to_gpio_sim_device(item); + + mutex_lock(&dev->lock); + if (gpio_sim_device_is_live_unlocked(dev)) + gpio_sim_device_deactivate_unlocked(dev); + mutex_unlock(&dev->lock); + + mutex_destroy(&dev->lock); + ida_free(&gpio_sim_ida, dev->id); + kfree(dev); +} + +static 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 = { + .make_group = gpio_sim_device_config_make_bank_group, +}; + +static const struct config_item_type gpio_sim_device_config_group_type = { + .ct_item_ops = &gpio_sim_device_config_item_ops, + .ct_group_ops = &gpio_sim_device_config_group_ops, + .ct_attrs = gpio_sim_device_config_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group * +gpio_sim_config_make_device_group(struct config_group *group, const char *name) +{ + struct gpio_sim_device *dev; + int id; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + id = ida_alloc(&gpio_sim_ida, GFP_KERNEL); + if (id < 0) { + kfree(dev); + return ERR_PTR(id); + } + + config_group_init_type_name(&dev->group, name, + &gpio_sim_device_config_group_type); + dev->id = id; + mutex_init(&dev->lock); + INIT_LIST_HEAD(&dev->bank_list); + + dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; + init_completion(&dev->probe_completion); + + return &dev->group; +} + +static struct configfs_group_operations gpio_sim_config_group_ops = { + .make_group = gpio_sim_config_make_device_group, +}; + +static const struct config_item_type gpio_sim_config_type = { + .ct_group_ops = &gpio_sim_config_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem gpio_sim_config_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "gpio-sim", + .ci_type = &gpio_sim_config_type, + }, + }, +}; + +static int __init gpio_sim_init(void) +{ + int ret; + + ret = platform_driver_register(&gpio_sim_driver); + if (ret) { + pr_err("Error %d while registering the platform driver\n", ret); + return ret; + } + + config_group_init(&gpio_sim_config_subsys.su_group); + mutex_init(&gpio_sim_config_subsys.su_mutex); + ret = configfs_register_subsystem(&gpio_sim_config_subsys); + if (ret) { + pr_err("Error %d while registering the configfs subsystem %s\n", + ret, gpio_sim_config_subsys.su_group.cg_item.ci_namebuf); + mutex_destroy(&gpio_sim_config_subsys.su_mutex); + platform_driver_unregister(&gpio_sim_driver); + return ret; + } + + return 0; +} +module_init(gpio_sim_init); + +static void __exit gpio_sim_exit(void) +{ + configfs_unregister_subsystem(&gpio_sim_config_subsys); + mutex_destroy(&gpio_sim_config_subsys.su_mutex); + platform_driver_unregister(&gpio_sim_driver); +} +module_exit(gpio_sim_exit); + +MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl"); +MODULE_DESCRIPTION("GPIO Simulator Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c index 9dd9dabb579e..9bff63990eee 100644 --- a/drivers/gpio/gpio-sprd.c +++ b/drivers/gpio/gpio-sprd.c @@ -237,7 +237,6 @@ static int sprd_gpio_probe(struct platform_device *pdev) sprd_gpio->chip.ngpio = SPRD_GPIO_NR; sprd_gpio->chip.base = -1; sprd_gpio->chip.parent = &pdev->dev; - sprd_gpio->chip.of_node = pdev->dev.of_node; sprd_gpio->chip.request = sprd_gpio_request; sprd_gpio->chip.free = sprd_gpio_free; sprd_gpio->chip.get = sprd_gpio_get; diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 392fcab06ab8..e07cca0f8d35 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -324,7 +324,7 @@ static int gsta_alloc_irq_chip(struct gsta_gpio *chip) if (rv) return rv; - /* Set up all all 128 interrupts: code from setup_generic_chip */ + /* Set up all 128 interrupts: code from setup_generic_chip */ { struct irq_chip_type *ct = gc->chip_types; int i, j; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index dd4d58b4ae49..0fa4f0a93378 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -477,7 +477,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.parent = &pdev->dev; - stmpe_gpio->chip.of_node = np; stmpe_gpio->chip.base = -1; if (IS_ENABLED(CONFIG_DEBUG_FS)) diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 8d158492488f..443fe975bf13 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -319,7 +319,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->chip.ngpio = tc3589x->num_gpio; tc3589x_gpio->chip.parent = &pdev->dev; tc3589x_gpio->chip.base = -1; - tc3589x_gpio->chip.of_node = np; girq = &tc3589x_gpio->chip.irq; girq->chip = &tc3589x_gpio_irq_chip; diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index c026e7141e4e..34b36a8c035f 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -14,6 +14,8 @@ #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h> +#include <dt-bindings/gpio/tegra234-gpio.h> +#include <dt-bindings/gpio/tegra241-gpio.h> /* security registers */ #define TEGRA186_GPIO_CTL_SCR 0x0c @@ -748,7 +750,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.names = (const char * const *)names; #if defined(CONFIG_OF_GPIO) - gpio->gpio.of_node = pdev->dev.of_node; gpio->gpio.of_gpio_n_cells = 2; gpio->gpio.of_xlate = tegra186_gpio_of_xlate; #endif /* CONFIG_OF_GPIO */ @@ -972,6 +973,124 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .num_irqs_per_bank = 8, }; +#define TEGRA234_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA234_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra234_main_ports[] = { + TEGRA234_MAIN_GPIO_PORT( A, 0, 0, 8), + TEGRA234_MAIN_GPIO_PORT( B, 0, 3, 1), + TEGRA234_MAIN_GPIO_PORT( C, 5, 1, 8), + TEGRA234_MAIN_GPIO_PORT( D, 5, 2, 4), + TEGRA234_MAIN_GPIO_PORT( E, 5, 3, 8), + TEGRA234_MAIN_GPIO_PORT( F, 5, 4, 6), + TEGRA234_MAIN_GPIO_PORT( G, 4, 0, 8), + TEGRA234_MAIN_GPIO_PORT( H, 4, 1, 8), + TEGRA234_MAIN_GPIO_PORT( I, 4, 2, 7), + TEGRA234_MAIN_GPIO_PORT( J, 5, 0, 6), + TEGRA234_MAIN_GPIO_PORT( K, 3, 0, 8), + TEGRA234_MAIN_GPIO_PORT( L, 3, 1, 4), + TEGRA234_MAIN_GPIO_PORT( M, 2, 0, 8), + TEGRA234_MAIN_GPIO_PORT( N, 2, 1, 8), + TEGRA234_MAIN_GPIO_PORT( P, 2, 2, 8), + TEGRA234_MAIN_GPIO_PORT( Q, 2, 3, 8), + TEGRA234_MAIN_GPIO_PORT( R, 2, 4, 6), + TEGRA234_MAIN_GPIO_PORT( X, 1, 0, 8), + TEGRA234_MAIN_GPIO_PORT( Y, 1, 1, 8), + TEGRA234_MAIN_GPIO_PORT( Z, 1, 2, 8), + TEGRA234_MAIN_GPIO_PORT(AC, 0, 1, 8), + TEGRA234_MAIN_GPIO_PORT(AD, 0, 2, 4), + TEGRA234_MAIN_GPIO_PORT(AE, 3, 3, 2), + TEGRA234_MAIN_GPIO_PORT(AF, 3, 4, 4), + TEGRA234_MAIN_GPIO_PORT(AG, 3, 2, 8), +}; + +static const struct tegra_gpio_soc tegra234_main_soc = { + .num_ports = ARRAY_SIZE(tegra234_main_ports), + .ports = tegra234_main_ports, + .name = "tegra234-gpio", + .instance = 0, + .num_irqs_per_bank = 8, +}; + +#define TEGRA234_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA234_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra234_aon_ports[] = { + TEGRA234_AON_GPIO_PORT(AA, 0, 4, 8), + TEGRA234_AON_GPIO_PORT(BB, 0, 5, 4), + TEGRA234_AON_GPIO_PORT(CC, 0, 2, 8), + TEGRA234_AON_GPIO_PORT(DD, 0, 3, 3), + TEGRA234_AON_GPIO_PORT(EE, 0, 0, 8), + TEGRA234_AON_GPIO_PORT(GG, 0, 1, 1), +}; + +static const struct tegra_gpio_soc tegra234_aon_soc = { + .num_ports = ARRAY_SIZE(tegra234_aon_ports), + .ports = tegra234_aon_ports, + .name = "tegra234-gpio-aon", + .instance = 1, + .num_irqs_per_bank = 8, +}; + +#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA241_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra241_main_ports[] = { + TEGRA241_MAIN_GPIO_PORT(A, 0, 0, 8), + TEGRA241_MAIN_GPIO_PORT(B, 0, 1, 8), + TEGRA241_MAIN_GPIO_PORT(C, 0, 2, 2), + TEGRA241_MAIN_GPIO_PORT(D, 0, 3, 6), + TEGRA241_MAIN_GPIO_PORT(E, 0, 4, 8), + TEGRA241_MAIN_GPIO_PORT(F, 1, 0, 8), + TEGRA241_MAIN_GPIO_PORT(G, 1, 1, 8), + TEGRA241_MAIN_GPIO_PORT(H, 1, 2, 8), + TEGRA241_MAIN_GPIO_PORT(J, 1, 3, 8), + TEGRA241_MAIN_GPIO_PORT(K, 1, 4, 4), + TEGRA241_MAIN_GPIO_PORT(L, 1, 5, 6), +}; + +static const struct tegra_gpio_soc tegra241_main_soc = { + .num_ports = ARRAY_SIZE(tegra241_main_ports), + .ports = tegra241_main_ports, + .name = "tegra241-gpio", + .instance = 0, +}; + +#define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA241_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ + } + +static const struct tegra_gpio_port tegra241_aon_ports[] = { + TEGRA241_AON_GPIO_PORT(AA, 0, 0, 8), + TEGRA241_AON_GPIO_PORT(BB, 0, 0, 4), +}; + +static const struct tegra_gpio_soc tegra241_aon_soc = { + .num_ports = ARRAY_SIZE(tegra241_aon_ports), + .ports = tegra241_aon_ports, + .name = "tegra241-gpio-aon", + .instance = 1, +}; + static const struct of_device_id tegra186_gpio_of_match[] = { { .compatible = "nvidia,tegra186-gpio", @@ -986,6 +1105,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = { .compatible = "nvidia,tegra194-gpio-aon", .data = &tegra194_aon_soc }, { + .compatible = "nvidia,tegra234-gpio", + .data = &tegra234_main_soc + }, { + .compatible = "nvidia,tegra234-gpio-aon", + .data = &tegra234_aon_soc + }, { /* sentinel */ } }; @@ -996,6 +1121,8 @@ static const struct acpi_device_id tegra186_gpio_acpi_match[] = { { .id = "NVDA0208", .driver_data = (kernel_ulong_t)&tegra186_aon_soc }, { .id = "NVDA0308", .driver_data = (kernel_ulong_t)&tegra194_main_soc }, { .id = "NVDA0408", .driver_data = (kernel_ulong_t)&tegra194_aon_soc }, + { .id = "NVDA0508", .driver_data = (kernel_ulong_t)&tegra241_main_soc }, + { .id = "NVDA0608", .driver_data = (kernel_ulong_t)&tegra241_aon_soc }, {} }; MODULE_DEVICE_TABLE(acpi, tegra186_gpio_acpi_match); diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c index 912382be48e1..e1d425a18854 100644 --- a/drivers/gpio/gpio-tps65218.c +++ b/drivers/gpio/gpio-tps65218.c @@ -196,9 +196,6 @@ static int tps65218_gpio_probe(struct platform_device *pdev) tps65218_gpio->tps65218 = tps65218; tps65218_gpio->gpio_chip = template_chip; tps65218_gpio->gpio_chip.parent = &pdev->dev; -#ifdef CONFIG_OF_GPIO - tps65218_gpio->gpio_chip.of_node = pdev->dev.of_node; -#endif return devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip, tps65218_gpio); diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index da0304b764a5..c5713524b581 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -77,6 +77,8 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) struct tps6586x_platform_data *pdata; struct tps6586x_gpio *tps6586x_gpio; + device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); + pdata = dev_get_platdata(pdev->dev.parent); tps6586x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps6586x_gpio), GFP_KERNEL); @@ -97,9 +99,6 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get; tps6586x_gpio->gpio_chip.to_irq = tps6586x_gpio_to_irq; -#ifdef CONFIG_OF_GPIO - tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node; -#endif if (pdata && pdata->gpio_base) tps6586x_gpio->gpio_chip.base = pdata->gpio_base; else diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 7fa8c841081f..321e6945f0be 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -111,6 +111,8 @@ static int tps65910_gpio_probe(struct platform_device *pdev) int ret; int i; + device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); + tps65910_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65910_gpio), GFP_KERNEL); if (!tps65910_gpio) @@ -137,9 +139,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev) tps65910_gpio->gpio_chip.set = tps65910_gpio_set; tps65910_gpio->gpio_chip.get = tps65910_gpio_get; tps65910_gpio->gpio_chip.parent = &pdev->dev; -#ifdef CONFIG_OF_GPIO - tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node; -#endif + if (pdata && pdata->gpio_base) tps65910_gpio->gpio_chip.base = pdata->gpio_base; else diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index c91890488402..b159e92a3612 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -317,22 +317,19 @@ static int ts5500_dio_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const char *name = dev_name(dev); struct ts5500_priv *priv; - struct resource *res; unsigned long flags; int ret; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "missing IRQ resource\n"); - return -EINVAL; - } + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; priv = devm_kzalloc(dev, sizeof(struct ts5500_priv), GFP_KERNEL); if (!priv) return -ENOMEM; platform_set_drvdata(pdev, priv); - priv->hwirq = res->start; + priv->hwirq = ret; spin_lock_init(&priv->lock); priv->gpio_chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index 648fb418d775..6c3fbf382dba 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -80,6 +80,8 @@ static int gpo_twl6040_probe(struct platform_device *pdev) struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev); int ret; + device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); + twl6040gpo_chip.base = -1; if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0) @@ -88,9 +90,6 @@ static int gpo_twl6040_probe(struct platform_device *pdev) twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */ twl6040gpo_chip.parent = &pdev->dev; -#ifdef CONFIG_OF_GPIO - twl6040gpo_chip.of_node = twl6040_core_dev->of_node; -#endif ret = devm_gpiochip_add_data(&pdev->dev, &twl6040gpo_chip, NULL); if (ret < 0) { diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index e0f2b67558e7..20780c35da1b 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -298,7 +298,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) } gc = &port->gc; - gc->of_node = np; gc->parent = dev; gc->label = "vf610-gpio"; gc->ngpio = VF610_GPIO_PER_PORT; diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 9cf1e5ebb352..7eaf8a28638c 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -262,6 +262,8 @@ static int wm831x_gpio_probe(struct platform_device *pdev) struct wm831x_pdata *pdata = &wm831x->pdata; struct wm831x_gpio *wm831x_gpio; + device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); + wm831x_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm831x_gpio), GFP_KERNEL); if (wm831x_gpio == NULL) @@ -275,9 +277,6 @@ static int wm831x_gpio_probe(struct platform_device *pdev) wm831x_gpio->gpio_chip.base = pdata->gpio_base; else wm831x_gpio->gpio_chip.base = -1; -#ifdef CONFIG_OF_GPIO - wm831x_gpio->gpio_chip.of_node = wm831x->dev->of_node; -#endif return devm_gpiochip_add_data(&pdev->dev, &wm831x_gpio->gpio_chip, wm831x_gpio); } diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 0d94d3aef752..0199f545335f 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -6,7 +6,6 @@ #include <linux/gpio/driver.h> #include <linux/platform_device.h> -#include <linux/of_device.h> #include <linux/module.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -26,16 +25,6 @@ * * where addr is base address of the that feature register and gpio is the pin. */ -#define GPIO_OUTPUT_EN 0x00 -#define GPIO_PADDRV 0x08 -#define GPIO_INT_EN00 0x18 -#define GPIO_INT_EN10 0x20 -#define GPIO_INT_EN20 0x28 -#define GPIO_INT_EN30 0x30 -#define GPIO_INT_POL 0x38 -#define GPIO_INT_TYPE 0x40 -#define GPIO_INT_STAT 0x48 - #define GPIO_9XX_BYTESWAP 0X00 #define GPIO_9XX_CTRL 0X04 #define GPIO_9XX_OUTPUT_EN 0x14 @@ -52,14 +41,6 @@ #define GPIO_9XX_INT_TYPE 0x114 #define GPIO_9XX_INT_STAT 0x124 -#define GPIO_3XX_INT_EN00 0x18 -#define GPIO_3XX_INT_EN10 0x20 -#define GPIO_3XX_INT_EN20 0x28 -#define GPIO_3XX_INT_EN30 0x30 -#define GPIO_3XX_INT_POL 0x78 -#define GPIO_3XX_INT_TYPE 0x80 -#define GPIO_3XX_INT_STAT 0x88 - /* Interrupt type register mask */ #define XLP_GPIO_IRQ_TYPE_LVL 0x0 #define XLP_GPIO_IRQ_TYPE_EDGE 0x1 @@ -72,16 +53,6 @@ #define XLP_GPIO_IRQ_BASE 768 #define XLP_MAX_NR_GPIO 96 -/* XLP variants supported by this driver */ -enum { - XLP_GPIO_VARIANT_XLP832 = 1, - XLP_GPIO_VARIANT_XLP316, - XLP_GPIO_VARIANT_XLP208, - XLP_GPIO_VARIANT_XLP980, - XLP_GPIO_VARIANT_XLP532, - GPIO_VARIANT_VULCAN -}; - struct xlp_gpio_priv { struct gpio_chip chip; DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO); @@ -257,44 +228,13 @@ static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state) xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state); } -static const struct of_device_id xlp_gpio_of_ids[] = { - { - .compatible = "netlogic,xlp832-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP832, - }, - { - .compatible = "netlogic,xlp316-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP316, - }, - { - .compatible = "netlogic,xlp208-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP208, - }, - { - .compatible = "netlogic,xlp980-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP980, - }, - { - .compatible = "netlogic,xlp532-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP532, - }, - { - .compatible = "brcm,vulcan-gpio", - .data = (void *)GPIO_VARIANT_VULCAN, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids); - static int xlp_gpio_probe(struct platform_device *pdev) { struct gpio_chip *gc; struct gpio_irq_chip *girq; struct xlp_gpio_priv *priv; void __iomem *gpio_base; - int irq_base, irq, err; - int ngpio; - u32 soc_type; + int irq, err; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -308,62 +248,12 @@ static int xlp_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - if (pdev->dev.of_node) { - soc_type = (uintptr_t)of_device_get_match_data(&pdev->dev); - } else { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, - &pdev->dev); - if (!acpi_id || !acpi_id->driver_data) { - dev_err(&pdev->dev, "Unable to match ACPI ID\n"); - return -ENODEV; - } - soc_type = (uintptr_t) acpi_id->driver_data; - } - - switch (soc_type) { - case XLP_GPIO_VARIANT_XLP832: - priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN; - priv->gpio_paddrv = gpio_base + GPIO_PADDRV; - priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT; - priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE; - priv->gpio_intr_pol = gpio_base + GPIO_INT_POL; - priv->gpio_intr_en = gpio_base + GPIO_INT_EN00; - ngpio = 41; - break; - case XLP_GPIO_VARIANT_XLP208: - case XLP_GPIO_VARIANT_XLP316: - priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN; - priv->gpio_paddrv = gpio_base + GPIO_PADDRV; - priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT; - priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE; - priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL; - priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00; - - ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57; - break; - case XLP_GPIO_VARIANT_XLP980: - case XLP_GPIO_VARIANT_XLP532: - case GPIO_VARIANT_VULCAN: - priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN; - priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV; - priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT; - priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE; - priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL; - priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00; - - if (soc_type == XLP_GPIO_VARIANT_XLP980) - ngpio = 66; - else if (soc_type == XLP_GPIO_VARIANT_XLP532) - ngpio = 67; - else - ngpio = 70; - break; - default: - dev_err(&pdev->dev, "Unknown Processor type!\n"); - return -ENODEV; - } + priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN; + priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV; + priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT; + priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE; + priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL; + priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00; bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO); @@ -373,8 +263,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) gc->label = dev_name(&pdev->dev); gc->base = 0; gc->parent = &pdev->dev; - gc->ngpio = ngpio; - gc->of_node = pdev->dev.of_node; + gc->ngpio = 70; gc->direction_output = xlp_gpio_dir_output; gc->direction_input = xlp_gpio_dir_input; gc->set = xlp_gpio_set; @@ -382,19 +271,6 @@ static int xlp_gpio_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); - /* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */ - if (soc_type != GPIO_VARIANT_VULCAN) { - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, - XLP_GPIO_IRQ_BASE, - gc->ngpio, 0); - if (irq_base < 0) { - dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); - return irq_base; - } - } else { - irq_base = 0; - } - girq = &gc->irq; girq->chip = &xlp_gpio_irq_chip; girq->parent_handler = xlp_gpio_generic_handler; @@ -405,7 +281,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) if (!girq->parents) return -ENOMEM; girq->parents[0] = irq; - girq->first = irq_base; + girq->first = 0; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; @@ -420,8 +296,8 @@ static int xlp_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id xlp_gpio_acpi_match[] = { - { "BRCM9006", GPIO_VARIANT_VULCAN }, - { "CAV9006", GPIO_VARIANT_VULCAN }, + { "BRCM9006" }, + { "CAV9006" }, {}, }; MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match); @@ -430,7 +306,6 @@ MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match); static struct platform_driver xlp_gpio_driver = { .driver = { .name = "xlp-gpio", - .of_match_table = xlp_gpio_of_ids, .acpi_match_table = ACPI_PTR(xlp_gpio_acpi_match), }, .probe = xlp_gpio_probe, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 985e8589c58b..c0f6a25c3279 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -219,14 +219,13 @@ EXPORT_SYMBOL_GPL(acpi_gpio_get_io_resource); static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio, struct acpi_gpio_event *event) { + struct device *parent = acpi_gpio->chip->parent; int ret, value; ret = request_threaded_irq(event->irq, NULL, event->handler, event->irqflags | IRQF_ONESHOT, "ACPI:Event", event); if (ret) { - dev_err(acpi_gpio->chip->parent, - "Failed to setup interrupt handler for %d\n", - event->irq); + dev_err(parent, "Failed to setup interrupt handler for %d\n", event->irq); return; } @@ -347,8 +346,7 @@ static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in) return false; err: - pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n", - ignore_wake); + pr_err_once("Error: Invalid value for gpiolib_acpi.ignore_wake: %s\n", ignore_wake); return false; } @@ -579,36 +577,24 @@ void acpi_dev_remove_driver_gpios(struct acpi_device *adev) } EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios); -static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res) +static void acpi_dev_release_driver_gpios(void *adev) { - acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev)); + acpi_dev_remove_driver_gpios(adev); } int devm_acpi_dev_add_driver_gpios(struct device *dev, const struct acpi_gpio_mapping *gpios) { - void *res; + struct acpi_device *adev = ACPI_COMPANION(dev); int ret; - res = devres_alloc(devm_acpi_dev_release_driver_gpios, 0, GFP_KERNEL); - if (!res) - return -ENOMEM; - - ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), gpios); - if (ret) { - devres_free(res); + ret = acpi_dev_add_driver_gpios(adev, gpios); + if (ret) return ret; - } - devres_add(dev, res); - return 0; -} -EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios); -void devm_acpi_dev_remove_driver_gpios(struct device *dev) -{ - WARN_ON(devres_release(dev, devm_acpi_dev_release_driver_gpios, NULL, NULL)); + return devm_add_action_or_reset(dev, acpi_dev_release_driver_gpios, adev); } -EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); +EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios); static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, @@ -941,7 +927,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, if (info.gpioint && (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) { - dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); + dev_dbg(&adev->dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); return ERR_PTR(-ENOENT); } @@ -1056,10 +1042,17 @@ int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int ind irq_flags = acpi_dev_get_irq_type(info.triggering, info.polarity); - /* Set type if specified and different than the current one */ - if (irq_flags != IRQ_TYPE_NONE && - irq_flags != irq_get_trigger_type(irq)) - irq_set_irq_type(irq, irq_flags); + /* + * If the IRQ is not already in use then set type + * if specified and different than the current one. + */ + if (can_request_irq(irq, irq_flags)) { + if (irq_flags != IRQ_TYPE_NONE && + irq_flags != irq_get_trigger_type(irq)) + irq_set_irq_type(irq, irq_flags); + } else { + dev_dbg(&adev->dev, "IRQ %d already in use\n", irq); + } return irq; } @@ -1346,6 +1339,9 @@ void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) /* Set default fwnode to parent's one if present */ if (gc->parent) ACPI_COMPANION_SET(&gdev->dev, ACPI_COMPANION(gc->parent)); + + if (gc->fwnode) + device_set_node(&gdev->dev, gc->fwnode); } static int acpi_gpio_package_count(const union acpi_object *obj) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 0ad288ab6262..91dcf2c6cdd8 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -1046,6 +1046,9 @@ void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) if (gc->parent) gdev->dev.of_node = gc->parent->of_node; + if (gc->fwnode) + gc->of_node = to_of_node(gc->fwnode); + /* If the gpiochip has an assigned OF node this takes precedence */ if (gc->of_node) gdev->dev.of_node = gc->of_node; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index abfbf546d159..3859911b61e9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -422,8 +422,16 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip) if (count > chip->ngpio) count = chip->ngpio; - for (i = 0; i < count; i++) - gdev->descs[i].name = names[chip->offset + i]; + for (i = 0; i < count; i++) { + /* + * Allow overriding "fixed" names provided by the GPIO + * provider. The "fixed" names are more often than not + * generic and less informative than the names given in + * device properties. + */ + if (names[chip->offset + i] && names[chip->offset + i][0]) + gdev->descs[i].name = names[chip->offset + i]; + } kfree(names); @@ -593,12 +601,18 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, struct lock_class_key *lock_key, struct lock_class_key *request_key) { - struct fwnode_handle *fwnode = gc->parent ? dev_fwnode(gc->parent) : NULL; - unsigned long flags; - int ret = 0; - unsigned i; - int base = gc->base; + struct fwnode_handle *fwnode = NULL; struct gpio_device *gdev; + unsigned long flags; + int base = gc->base; + unsigned int i; + int ret = 0; + u32 ngpios; + + if (gc->fwnode) + fwnode = gc->fwnode; + else if (gc->parent) + fwnode = dev_fwnode(gc->parent); /* * First: allocate and populate the internal stat container, and @@ -646,6 +660,26 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, goto err_free_dev_name; } + /* + * Try the device properties if the driver didn't supply the number + * of GPIO lines. + */ + if (gc->ngpio == 0) { + ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios); + if (ret == -ENODATA) + /* + * -ENODATA means that there is no property found and + * we want to issue the error message to the user. + * Besides that, we want to return different error code + * to state that supplied value is not valid. + */ + ngpios = 0; + else if (ret) + goto err_free_descs; + + gc->ngpio = ngpios; + } + if (gc->ngpio == 0) { chip_err(gc, "tried to insert a GPIO chip with zero lines\n"); ret = -EINVAL; @@ -708,10 +742,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, INIT_LIST_HEAD(&gdev->pin_ranges); #endif - if (gc->names) + if (gc->names) { ret = gpiochip_set_desc_names(gc); - else - ret = devprop_gpiochip_set_names(gc); + if (ret) + goto err_remove_from_list; + } + ret = devprop_gpiochip_set_names(gc); if (ret) goto err_remove_from_list; @@ -3487,11 +3523,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); */ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) { - mutex_lock(&gpio_lookup_lock); - - list_add_tail(&table->list, &gpio_lookup_list); - - mutex_unlock(&gpio_lookup_lock); + gpiod_add_lookup_tables(&table, 1); } EXPORT_SYMBOL_GPL(gpiod_add_lookup_table); @@ -3540,6 +3572,17 @@ void gpiod_add_hogs(struct gpiod_hog *hogs) } EXPORT_SYMBOL_GPL(gpiod_add_hogs); +void gpiod_remove_hogs(struct gpiod_hog *hogs) +{ + struct gpiod_hog *hog; + + mutex_lock(&gpio_machine_hogs_mutex); + for (hog = &hogs[0]; hog->chip_label; hog++) + list_del(&hog->list); + mutex_unlock(&gpio_machine_hogs_mutex); +} +EXPORT_SYMBOL_GPL(gpiod_remove_hogs); + static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { const char *dev_id = dev ? dev_name(dev) : NULL; |