diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-07 12:27:27 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-07 12:27:27 -0700 |
commit | 5e6a5845dd651b00754a62edec2f0a439182024d (patch) | |
tree | d93d10b5dc505b64b62ce42cee2bf926d6b42051 /drivers/gpio | |
parent | 75b96f0ec5faf730128c32187e3e28441c27a094 (diff) | |
parent | 889a1b3f35db6ba5ba6a0c23a3a55594570b6a17 (diff) | |
download | linux-5e6a5845dd651b00754a62edec2f0a439182024d.tar.gz linux-5e6a5845dd651b00754a62edec2f0a439182024d.tar.bz2 linux-5e6a5845dd651b00754a62edec2f0a439182024d.zip |
Merge tag 'gpio-updates-for-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"We mostly have various improvements and refactoring all over the place
but also some interesting new features - like the virtio GPIO driver
that allows guest VMs to use host's GPIOs. We also have a new/old GPIO
driver for rockchip - this one has been split out of the pinctrl
driver.
Summary:
- new driver: gpio-virtio allowing a guest VM running linux to access
GPIO lines provided by the host
- split the GPIO driver out of the rockchip pin control driver
- add support for a new model to gpio-aspeed-sgpio, refactor the
driver and use generic device property interfaces, improve property
sanitization
- add ACPI support to gpio-tegra186
- improve the code setting the line names to support multiple GPIO
banks per device
- constify a bunch of OF functions in the core GPIO code and make the
declaration for one of the core OF functions we use consistent
within its header
- use software nodes in intel_quark_i2c_gpio
- add support for the gpio-line-names property in gpio-mt7621
- use the standard GPIO function for setting the GPIO names in
gpio-brcmstb
- fix a bunch of leaks and other bugs in gpio-mpc8xxx
- use generic pm callbacks in gpio-ml-ioh
- improve resource management and PM handling in gpio-mlxbf2
- modernize and improve the gpio-dwapb driver
- coding style improvements in gpio-rcar
- documentation fixes and improvements
- update the MAINTAINERS entry for gpio-zynq
- minor tweaks in several drivers"
* tag 'gpio-updates-for-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (35 commits)
gpio: mpc8xxx: Use 'devm_gpiochip_add_data()' to simplify the code and avoid a leak
gpio: mpc8xxx: Fix a potential double iounmap call in 'mpc8xxx_probe()'
gpio: mpc8xxx: Fix a resources leak in the error handling path of 'mpc8xxx_probe()'
gpio: viperboard: remove platform_set_drvdata() call in probe
gpio: virtio: Add missing mailings lists in MAINTAINERS entry
gpio: virtio: Fix sparse warnings
gpio: remove the obsolete MX35 3DS BOARD MC9S08DZ60 GPIO functions
gpio: max730x: Use the right include
gpio: Add virtio-gpio driver
gpio: mlxbf2: Use DEFINE_RES_MEM_NAMED() helper macro
gpio: mlxbf2: Use devm_platform_ioremap_resource()
gpio: mlxbf2: Drop wrong use of ACPI_PTR()
gpio: mlxbf2: Convert to device PM ops
gpio: dwapb: Get rid of legacy platform data
mfd: intel_quark_i2c_gpio: Convert GPIO to use software nodes
gpio: dwapb: Read GPIO base from gpio-base property
gpio: dwapb: Unify ACPI enumeration checks in get_irq() and configure_irqs()
gpiolib: Deduplicate forward declaration in the consumer.h header
MAINTAINERS: update gpio-zynq.yaml reference
gpio: tegra186: Add ACPI support
...
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 15 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-aspeed-sgpio.c | 178 | ||||
-rw-r--r-- | drivers/gpio/gpio-brcmstb.c | 45 | ||||
-rw-r--r-- | drivers/gpio/gpio-dwapb.c | 56 | ||||
-rw-r--r-- | drivers/gpio/gpio-mc9s08dz60.c | 112 | ||||
-rw-r--r-- | drivers/gpio/gpio-ml-ioh.c | 49 | ||||
-rw-r--r-- | drivers/gpio/gpio-mlxbf2.c | 43 | ||||
-rw-r--r-- | drivers/gpio/gpio-mpc8xxx.c | 13 | ||||
-rw-r--r-- | drivers/gpio/gpio-mt7621.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-rcar.c | 4 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra186.c | 30 | ||||
-rw-r--r-- | drivers/gpio/gpio-viperboard.c | 14 | ||||
-rw-r--r-- | drivers/gpio/gpio-virtio.c | 374 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-devres.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-of.c | 16 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 32 |
17 files changed, 624 insertions, 362 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 81abd890b364..fae5141251e5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1018,12 +1018,6 @@ config GPIO_MAX732X_IRQ Say yes here to enable the max732x to be used as an interrupt controller. It requires the driver to be built in the kernel. -config GPIO_MC9S08DZ60 - bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions" - depends on I2C=y && MACH_MX35_3DS - help - Select this to enable the MC9S08DZ60 GPIO driver - config GPIO_PCA953X tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" select REGMAP_I2C @@ -1677,6 +1671,15 @@ config GPIO_MOCKUP tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in it. +config GPIO_VIRTIO + tristate "VirtIO GPIO support" + depends on VIRTIO + help + Say Y here to enable guest support for virtio-based GPIO controllers. + + These virtual GPIOs can be routed to real GPIOs or attached to + simulators on the host (like QEMU). + endmenu endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 5243e2d1c207..fbcda637d5e1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -92,7 +92,6 @@ obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o -obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o @@ -166,6 +165,7 @@ obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o +obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index a99ece15db95..10f303d15225 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -17,37 +17,30 @@ #include <linux/spinlock.h> #include <linux/string.h> -/* - * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie, - * slots within the clocked serial GPIO data). Since each HW GPIO is both an - * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip - * device. - * - * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and - * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET. - */ -#define MAX_NR_HW_SGPIO 80 -#define SGPIO_OUTPUT_OFFSET MAX_NR_HW_SGPIO - #define ASPEED_SGPIO_CTRL 0x54 -#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6) #define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) #define ASPEED_SGPIO_ENABLE BIT(0) +#define ASPEED_SGPIO_PINS_SHIFT 6 + +struct aspeed_sgpio_pdata { + const u32 pin_mask; +}; struct aspeed_sgpio { struct gpio_chip chip; + struct irq_chip intc; struct clk *pclk; spinlock_t lock; void __iomem *base; int irq; - int n_sgpio; }; struct aspeed_sgpio_bank { - uint16_t val_regs; - uint16_t rdata_reg; - uint16_t irq_regs; + u16 val_regs; + u16 rdata_reg; + u16 irq_regs; + u16 tolerance_regs; const char names[4][3]; }; @@ -63,19 +56,29 @@ static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { .val_regs = 0x0000, .rdata_reg = 0x0070, .irq_regs = 0x0004, + .tolerance_regs = 0x0018, .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x001C, .rdata_reg = 0x0074, .irq_regs = 0x0020, + .tolerance_regs = 0x0034, .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0038, .rdata_reg = 0x0078, .irq_regs = 0x003C, - .names = { "I", "J" }, + .tolerance_regs = 0x0050, + .names = { "I", "J", "K", "L" }, + }, + { + .val_regs = 0x0090, + .rdata_reg = 0x007C, + .irq_regs = 0x0094, + .tolerance_regs = 0x00A8, + .names = { "M", "N", "O", "P" }, }, }; @@ -87,6 +90,7 @@ enum aspeed_sgpio_reg { reg_irq_type1, reg_irq_type2, reg_irq_status, + reg_tolerance, }; #define GPIO_VAL_VALUE 0x00 @@ -115,15 +119,17 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio, return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; case reg_irq_status: return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; + case reg_tolerance: + return gpio->base + bank->tolerance_regs; default: /* acturally if code runs to here, it's an error case */ BUG(); } } -#define GPIO_BANK(x) ((x % SGPIO_OUTPUT_OFFSET) >> 5) -#define GPIO_OFFSET(x) ((x % SGPIO_OUTPUT_OFFSET) & 0x1f) -#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) +#define GPIO_BANK(x) ((x) >> 6) +#define GPIO_OFFSET(x) ((x) & GENMASK(5, 0)) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1) static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) { @@ -138,39 +144,25 @@ static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc, unsigned long *valid_mask, unsigned int ngpios) { - struct aspeed_sgpio *sgpio = gpiochip_get_data(gc); - int n = sgpio->n_sgpio; - int c = SGPIO_OUTPUT_OFFSET - n; - - WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2); - - /* input GPIOs in the lower range */ - bitmap_set(valid_mask, 0, n); - bitmap_clear(valid_mask, n, c); - - /* output GPIOS above SGPIO_OUTPUT_OFFSET */ - bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n); - bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c); - + bitmap_set(valid_mask, 0, ngpios); return 0; } static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc, unsigned long *valid_mask, unsigned int ngpios) { - struct aspeed_sgpio *sgpio = gpiochip_get_data(gc); - int n = sgpio->n_sgpio; + unsigned int i; - WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2); - - /* input GPIOs in the lower range */ - bitmap_set(valid_mask, 0, n); - bitmap_clear(valid_mask, n, ngpios - n); + /* input GPIOs are even bits */ + for (i = 0; i < ngpios; i++) { + if (i % 2) + clear_bit(i, valid_mask); + } } static bool aspeed_sgpio_is_input(unsigned int offset) { - return offset < SGPIO_OUTPUT_OFFSET; + return !(offset % 2); } static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) @@ -409,14 +401,6 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc) chained_irq_exit(ic, desc); } -static struct irq_chip aspeed_sgpio_irqchip = { - .name = "aspeed-sgpio", - .irq_ack = aspeed_sgpio_irq_ack, - .irq_mask = aspeed_sgpio_irq_mask, - .irq_unmask = aspeed_sgpio_irq_unmask, - .irq_set_type = aspeed_sgpio_set_type, -}; - static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, struct platform_device *pdev) { @@ -439,8 +423,14 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); } + gpio->intc.name = dev_name(&pdev->dev); + gpio->intc.irq_ack = aspeed_sgpio_irq_ack; + gpio->intc.irq_mask = aspeed_sgpio_irq_mask; + gpio->intc.irq_unmask = aspeed_sgpio_irq_unmask; + gpio->intc.irq_set_type = aspeed_sgpio_set_type; + irq = &gpio->chip.irq; - irq->chip = &aspeed_sgpio_irqchip; + irq->chip = &gpio->intc; irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask; irq->handler = handle_bad_irq; irq->default_type = IRQ_TYPE_NONE; @@ -463,9 +453,56 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, return 0; } +static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { + .pin_mask = GENMASK(9, 6), +}; + +static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, + unsigned int offset, bool enable) +{ + struct aspeed_sgpio *gpio = gpiochip_get_data(chip); + unsigned long flags; + void __iomem *reg; + u32 val; + + reg = bank_reg(gpio, to_bank(offset), reg_tolerance); + + spin_lock_irqsave(&gpio->lock, flags); + + val = readl(reg); + + if (enable) + val |= GPIO_BIT(offset); + else + val &= ~GPIO_BIT(offset); + + writel(val, reg); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + unsigned long param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + if (param == PIN_CONFIG_PERSIST_STATE) + return aspeed_sgpio_reset_tolerance(chip, offset, arg); + + return -ENOTSUPP; +} + +static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { + .pin_mask = GENMASK(10, 6), +}; + static const struct of_device_id aspeed_sgpio_of_table[] = { - { .compatible = "aspeed,ast2400-sgpio" }, - { .compatible = "aspeed,ast2500-sgpio" }, + { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, }, + { .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, }, + { .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, }, {} }; @@ -473,10 +510,11 @@ MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); static int __init aspeed_sgpio_probe(struct platform_device *pdev) { + u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask; + const struct aspeed_sgpio_pdata *pdata; struct aspeed_sgpio *gpio; - u32 nr_gpios, sgpio_freq, sgpio_clk_div; - int rc; unsigned long apb_freq; + int rc; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); if (!gpio) @@ -486,18 +524,23 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) if (IS_ERR(gpio->base)) return PTR_ERR(gpio->base); - rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios); + pdata = device_get_match_data(&pdev->dev); + if (!pdata) + return -EINVAL; + + pin_mask = pdata->pin_mask; + + rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); if (rc < 0) { dev_err(&pdev->dev, "Could not read ngpios property\n"); return -EINVAL; - } else if (nr_gpios > MAX_NR_HW_SGPIO) { - dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n", - MAX_NR_HW_SGPIO, nr_gpios); + } else if (nr_gpios % 8) { + dev_err(&pdev->dev, "Number of GPIOs not multiple of 8: %d\n", + nr_gpios); return -EINVAL; } - gpio->n_sgpio = nr_gpios; - rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq); + rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); if (rc < 0) { dev_err(&pdev->dev, "Could not read bus-frequency property\n"); return -EINVAL; @@ -528,15 +571,14 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) if (sgpio_clk_div > (1 << 16) - 1) return -EINVAL; - iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | - FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) | - ASPEED_SGPIO_ENABLE, - gpio->base + ASPEED_SGPIO_CTRL); + gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; + iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | + ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL); spin_lock_init(&gpio->lock); gpio->chip.parent = &pdev->dev; - gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2; + gpio->chip.ngpio = nr_gpios * 2; gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask; gpio->chip.direction_input = aspeed_sgpio_dir_in; gpio->chip.direction_output = aspeed_sgpio_dir_out; @@ -545,7 +587,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) gpio->chip.free = NULL; gpio->chip.get = aspeed_sgpio_get; gpio->chip.set = aspeed_sgpio_set; - gpio->chip.set_config = NULL; + gpio->chip.set_config = aspeed_sgpio_set_config; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 74b7c91c3d1a..895a79936248 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -602,49 +602,6 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = { .resume_noirq = brcmstb_gpio_resume, }; -static void brcmstb_gpio_set_names(struct device *dev, - struct brcmstb_gpio_bank *bank) -{ - struct device_node *np = dev->of_node; - const char **names; - int nstrings, base; - unsigned int i; - - base = bank->id * MAX_GPIO_PER_BANK; - - nstrings = of_property_count_strings(np, "gpio-line-names"); - if (nstrings <= base) - /* Line names not present */ - return; - - names = devm_kcalloc(dev, MAX_GPIO_PER_BANK, sizeof(*names), - GFP_KERNEL); - if (!names) - return; - - /* - * Make sure to not index beyond the end of the number of descriptors - * of the GPIO device. - */ - for (i = 0; i < bank->width; i++) { - const char *name; - int ret; - - ret = of_property_read_string_index(np, "gpio-line-names", - base + i, &name); - if (ret) { - if (ret != -ENODATA) - dev_err(dev, "unable to name line %d: %d\n", - base + i, ret); - break; - } - if (*name) - names[i] = name; - } - - bank->gc.names = names; -} - static int brcmstb_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -758,6 +715,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) gc->of_xlate = brcmstb_gpio_of_xlate; /* not all ngpio lines are valid, will use bank width later */ gc->ngpio = MAX_GPIO_PER_BANK; + gc->offset = bank->id * MAX_GPIO_PER_BANK; if (priv->parent_irq > 0) gc->to_irq = brcmstb_gpio_to_irq; @@ -768,7 +726,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); gc->write_reg(reg_base + GIO_MASK(bank->id), 0); - brcmstb_gpio_set_names(dev, bank); err = gpiochip_add_data(gc, bank); if (err) { dev_err(dev, "Could not add gpiochip for bank %d\n", diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 3eb13d6d31ef..f98fa33e1679 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -16,7 +16,6 @@ #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/platform_data/gpio-dwapb.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/reset.h> @@ -48,6 +47,7 @@ #define DWAPB_DRIVER_NAME "gpio-dwapb" #define DWAPB_MAX_PORTS 4 +#define DWAPB_MAX_GPIOS 32 #define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */ #define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */ @@ -65,6 +65,19 @@ struct dwapb_gpio; +struct dwapb_port_property { + struct fwnode_handle *fwnode; + unsigned int idx; + unsigned int ngpio; + unsigned int gpio_base; + int irq[DWAPB_MAX_GPIOS]; +}; + +struct dwapb_platform_data { + struct dwapb_port_property *properties; + unsigned int nports; +}; + #ifdef CONFIG_PM_SLEEP /* Store GPIO context across system-wide suspend/resume transitions */ struct dwapb_context { @@ -436,21 +449,17 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, pirq->irqchip.irq_set_wake = dwapb_irq_set_wake; #endif - if (!pp->irq_shared) { - girq->num_parents = pirq->nr_irqs; - girq->parents = pirq->irq; - girq->parent_handler_data = gpio; - girq->parent_handler = dwapb_irq_handler; - } else { - /* This will let us handle the parent IRQ in the driver */ + /* + * Intel ACPI-based platforms mostly have the DesignWare APB GPIO + * IRQ lane shared between several devices. In that case the parental + * IRQ has to be handled in the shared way so to be properly delivered + * to all the connected devices. + */ + if (has_acpi_companion(gpio->dev)) { girq->num_parents = 0; girq->parents = NULL; girq->parent_handler = NULL; - /* - * Request a shared IRQ since where MFD would have devices - * using the same irq pin - */ err = devm_request_irq(gpio->dev, pp->irq[0], dwapb_irq_handler_mfd, IRQF_SHARED, DWAPB_DRIVER_NAME, gpio); @@ -458,6 +467,11 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, dev_err(gpio->dev, "error requesting IRQ\n"); goto err_kfree_pirq; } + } else { + girq->num_parents = pirq->nr_irqs; + girq->parents = pirq->irq; + girq->parent_handler_data = gpio; + girq->parent_handler = dwapb_irq_handler; } girq->chip = &pirq->irqchip; @@ -581,9 +595,12 @@ static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) pp->ngpio = DWAPB_MAX_GPIOS; } - pp->irq_shared = false; pp->gpio_base = -1; + /* For internal use only, new platforms mustn't exercise this */ + if (is_software_node(fwnode)) + fwnode_property_read_u32(fwnode, "gpio-base", &pp->gpio_base); + /* * Only port A can provide interrupts in all configurations of * the IP. @@ -670,17 +687,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev) unsigned int i; struct dwapb_gpio *gpio; int err; + struct dwapb_platform_data *pdata; struct device *dev = &pdev->dev; - struct dwapb_platform_data *pdata = dev_get_platdata(dev); - - if (!pdata) { - pdata = dwapb_gpio_get_pdata(dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - } - if (!pdata->nports) - return -ENODEV; + pdata = dwapb_gpio_get_pdata(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); if (!gpio) diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c deleted file mode 100644 index a9f17cebd5ed..000000000000 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. - * - * Author: Wu Guoxing <b39297@freescale.com> - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/gpio/driver.h> - -#define GPIO_GROUP_NUM 2 -#define GPIO_NUM_PER_GROUP 8 -#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP) - -struct mc9s08dz60 { - struct i2c_client *client; - struct gpio_chip chip; -}; - -static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit) -{ - *reg = 0x20 + offset / GPIO_NUM_PER_GROUP; - *bit = offset % GPIO_NUM_PER_GROUP; -} - -static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset) -{ - u8 reg, bit; - s32 value; - struct mc9s08dz60 *mc9s = gpiochip_get_data(gc); - - mc9s_gpio_to_reg_and_bit(offset, ®, &bit); - value = i2c_smbus_read_byte_data(mc9s->client, reg); - - return (value >= 0) ? (value >> bit) & 0x1 : 0; -} - -static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val) -{ - u8 reg, bit; - s32 value; - - mc9s_gpio_to_reg_and_bit(offset, ®, &bit); - value = i2c_smbus_read_byte_data(mc9s->client, reg); - if (value >= 0) { - if (val) - value |= 1 << bit; - else - value &= ~(1 << bit); - - return i2c_smbus_write_byte_data(mc9s->client, reg, value); - } else - return value; - -} - - -static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val) -{ - struct mc9s08dz60 *mc9s = gpiochip_get_data(gc); - - mc9s08dz60_set(mc9s, offset, val); -} - -static int mc9s08dz60_direction_output(struct gpio_chip *gc, - unsigned offset, int val) -{ - struct mc9s08dz60 *mc9s = gpiochip_get_data(gc); - - return mc9s08dz60_set(mc9s, offset, val); -} - -static int mc9s08dz60_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mc9s08dz60 *mc9s; - - mc9s = devm_kzalloc(&client->dev, sizeof(*mc9s), GFP_KERNEL); - if (!mc9s) - return -ENOMEM; - - mc9s->chip.label = client->name; - mc9s->chip.base = -1; - mc9s->chip.parent = &client->dev; - mc9s->chip.owner = THIS_MODULE; - mc9s->chip.ngpio = GPIO_NUM; - mc9s->chip.can_sleep = true; - mc9s->chip.get = mc9s08dz60_get_value; - mc9s->chip.set = mc9s08dz60_set_value; - mc9s->chip.direction_output = mc9s08dz60_direction_output; - mc9s->client = client; - i2c_set_clientdata(client, mc9s); - - return devm_gpiochip_add_data(&client->dev, &mc9s->chip, mc9s); -} - -static const struct i2c_device_id mc9s08dz60_id[] = { - {"mc9s08dz60", 0}, - {}, -}; - -static struct i2c_driver mc9s08dz60_i2c_driver = { - .driver = { - .name = "mc9s08dz60", - }, - .probe = mc9s08dz60_probe, - .id_table = mc9s08dz60_id, -}; -builtin_i2c_driver(mc9s08dz60_i2c_driver); diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 53d4abefa6ff..efa9acdc320a 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -155,11 +155,10 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) return 0; } -#ifdef CONFIG_PM /* * Save register configuration and disable interrupts. */ -static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) +static void __maybe_unused ioh_gpio_save_reg_conf(struct ioh_gpio *chip) { int i; @@ -185,7 +184,7 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) /* * This function restores the register configuration of the GPIO device. */ -static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) +static void __maybe_unused ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) { int i; @@ -207,7 +206,6 @@ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) &chip->reg->ioh_sel_reg[i]); } } -#endif static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset) { @@ -522,47 +520,23 @@ static void ioh_gpio_remove(struct pci_dev *pdev) kfree(chip); } -#ifdef CONFIG_PM -static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused ioh_gpio_suspend(struct device *dev) { - s32 ret; - struct ioh_gpio *chip = pci_get_drvdata(pdev); + struct ioh_gpio *chip = dev_get_drvdata(dev); unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); ioh_gpio_save_reg_conf(chip); spin_unlock_irqrestore(&chip->spinlock, flags); - ret = pci_save_state(pdev); - if (ret) { - dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret); - return ret; - } - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_wake(pdev, PCI_D0, 1); - if (ret) - dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret); - return 0; } -static int ioh_gpio_resume(struct pci_dev *pdev) +static int __maybe_unused ioh_gpio_resume(struct device *dev) { - s32 ret; - struct ioh_gpio *chip = pci_get_drvdata(pdev); + struct ioh_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - ret = pci_enable_wake(pdev, PCI_D0, 0); - - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret); - return ret; - } - pci_restore_state(pdev); - spin_lock_irqsave(&chip->spinlock, flags); iowrite32(0x01, &chip->reg->srst); iowrite32(0x00, &chip->reg->srst); @@ -571,10 +545,8 @@ static int ioh_gpio_resume(struct pci_dev *pdev) return 0; } -#else -#define ioh_gpio_suspend NULL -#define ioh_gpio_resume NULL -#endif + +static SIMPLE_DEV_PM_OPS(ioh_gpio_pm_ops, ioh_gpio_suspend, ioh_gpio_resume); static const struct pci_device_id ioh_gpio_pcidev_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, @@ -587,8 +559,9 @@ static struct pci_driver ioh_gpio_driver = { .id_table = ioh_gpio_pcidev_id, .probe = ioh_gpio_probe, .remove = ioh_gpio_remove, - .suspend = ioh_gpio_suspend, - .resume = ioh_gpio_resume + .driver = { + .pm = &ioh_gpio_pm_ops, + }, }; module_pci_driver(ioh_gpio_driver); diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index befa5e109943..177d03ef4529 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/acpi.h> #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/device.h> @@ -8,6 +7,7 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm.h> @@ -47,12 +47,10 @@ #define YU_GPIO_MODE0_SET 0x54 #define YU_GPIO_MODE0_CLEAR 0x58 -#ifdef CONFIG_PM struct mlxbf2_gpio_context_save_regs { u32 gpio_mode0; u32 gpio_mode1; }; -#endif /* BlueField-2 gpio block context structure. */ struct mlxbf2_gpio_context { @@ -61,9 +59,7 @@ struct mlxbf2_gpio_context { /* YU GPIO blocks address */ void __iomem *gpio_io; -#ifdef CONFIG_PM struct mlxbf2_gpio_context_save_regs *csave_regs; -#endif }; /* BlueField-2 gpio shared structure. */ @@ -73,11 +69,8 @@ struct mlxbf2_gpio_param { struct mutex *lock; }; -static struct resource yu_arm_gpio_lock_res = { - .start = YU_ARM_GPIO_LOCK_ADDR, - .end = YU_ARM_GPIO_LOCK_ADDR + YU_ARM_GPIO_LOCK_SIZE - 1, - .name = "YU_ARM_GPIO_LOCK", -}; +static struct resource yu_arm_gpio_lock_res = + DEFINE_RES_MEM_NAMED(YU_ARM_GPIO_LOCK_ADDR, YU_ARM_GPIO_LOCK_SIZE, "YU_ARM_GPIO_LOCK"); static DEFINE_MUTEX(yu_arm_gpio_lock_mutex); @@ -232,7 +225,6 @@ mlxbf2_gpio_probe(struct platform_device *pdev) struct mlxbf2_gpio_context *gs; struct device *dev = &pdev->dev; struct gpio_chip *gc; - struct resource *res; unsigned int npins; int ret; @@ -241,13 +233,9 @@ mlxbf2_gpio_probe(struct platform_device *pdev) return -ENOMEM; /* YU GPIO block address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - gs->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); - if (!gs->gpio_io) - return -ENOMEM; + gs->gpio_io = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(gs->gpio_io)) + return PTR_ERR(gs->gpio_io); ret = mlxbf2_gpio_get_lock_res(pdev); if (ret) { @@ -284,11 +272,9 @@ mlxbf2_gpio_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int mlxbf2_gpio_suspend(struct platform_device *pdev, - pm_message_t state) +static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev) |