diff options
author | Jason Gunthorpe <jgg@mellanox.com> | 2018-08-16 23:13:03 +0300 |
---|---|---|
committer | Jason Gunthorpe <jgg@mellanox.com> | 2018-08-16 23:21:29 +0300 |
commit | 0a3173a5f09bc58a3638ecfd0a80bdbae55e123c (patch) | |
tree | d6c0bc84863cca54dfbde3b7463e5d49c82af9f1 /drivers/gpio | |
parent | 92f4e77c85918eab5e5803d7e28ab89a7e6bd3a2 (diff) | |
parent | 5c60a7389d795e001c8748b458eb76e3a5b6008c (diff) | |
download | linux-0a3173a5f09bc58a3638ecfd0a80bdbae55e123c.tar.xz |
Merge branch 'linus/master' into rdma.git for-next
rdma.git merge resolution for the 4.19 merge window
Conflicts:
drivers/infiniband/core/rdma_core.c
- Use the rdma code and revise with the new spelling for
atomic_fetch_add_unless
drivers/nvme/host/rdma.c
- Replace max_sge with max_send_sge in new blk code
drivers/nvme/target/rdma.c
- Use the blk code and revise to use NULL for ib_post_recv when
appropriate
- Replace max_sge with max_recv_sge in new blk code
net/rds/ib_send.c
- Use the net code and revise to use NULL for ib_post_recv when
appropriate
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Diffstat (limited to 'drivers/gpio')
43 files changed, 1381 insertions, 269 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 71c0ab46f216..f7a0f576f918 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -359,6 +359,15 @@ config GPIO_MPC8XXX Say Y here if you're going to use hardware that connects to the MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs. +config GPIO_MT7621 + bool "Mediatek MT7621 GPIO Support" + depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST + depends on OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say yes here to support the Mediatek MT7621 SoC GPIO device + config GPIO_MVEBU def_bool y depends on PLAT_ORION || ARCH_MVEBU @@ -684,7 +693,8 @@ config GPIO_IT87 Say yes here to support GPIO functionality of IT87xx Super I/O chips. This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and - supports the IT8761E, IT8620E and IT8628E Super I/O chip as well. + supports the IT8761E, IT8613, IT8620E, and IT8628E Super I/O chips as + well. To compile this driver as a module, choose M here: the module will be called gpio_it87 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1324c8f966a7..fc77989371be 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o +obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index b31ae16170e7..2342e154029b 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -12,6 +12,7 @@ #include <asm/div64.h> #include <linux/clk.h> #include <linux/gpio/driver.h> +#include <linux/gpio/aspeed.h> #include <linux/hashtable.h> #include <linux/init.h> #include <linux/io.h> @@ -22,6 +23,15 @@ #include <linux/spinlock.h> #include <linux/string.h> +/* + * These two headers aren't meant to be used by GPIO drivers. We need + * them in order to access gpio_chip_hwgpio() which we need to implement + * the aspeed specific API which allows the coprocessor to request + * access to some GPIOs and to arbitrate between coprocessor and ARM. + */ +#include <linux/gpio/consumer.h> +#include "gpiolib.h" + struct aspeed_bank_props { unsigned int bank; u32 input; @@ -56,83 +66,130 @@ struct aspeed_gpio { struct clk *clk; u32 *dcache; + u8 *cf_copro_bankmap; }; struct aspeed_gpio_bank { - uint16_t val_regs; + uint16_t val_regs; /* +0: Rd: read input value, Wr: set write latch + * +4: Rd/Wr: Direction (0=in, 1=out) + */ + uint16_t rdata_reg; /* Rd: read write latch, Wr: <none> */ uint16_t irq_regs; uint16_t debounce_regs; uint16_t tolerance_regs; + uint16_t cmdsrc_regs; const char names[4][3]; }; +/* + * Note: The "value" register returns the input value sampled on the + * line even when the GPIO is configured as an output. Since + * that input goes through synchronizers, writing, then reading + * back may not return the written value right away. + * + * The "rdata" register returns the content of the write latch + * and thus can be used to read back what was last written + * reliably. + */ + static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; +static const struct aspeed_gpio_copro_ops *copro_ops; +static void *copro_data; + static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs = 0x0000, + .rdata_reg = 0x00c0, .irq_regs = 0x0008, .debounce_regs = 0x0040, .tolerance_regs = 0x001c, + .cmdsrc_regs = 0x0060, .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x0020, + .rdata_reg = 0x00c4, .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c, + .cmdsrc_regs = 0x0068, .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0070, + .rdata_reg = 0x00c8, .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac, + .cmdsrc_regs = 0x0090, .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0078, + .rdata_reg = 0x00cc, .irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc, + .cmdsrc_regs = 0x00e0, .names = { "M", "N", "O", "P" }, }, { .val_regs = 0x0080, + .rdata_reg = 0x00d0, .irq_regs = 0x0118, .debounce_regs = 0x0130, .tolerance_regs = 0x012c, + .cmdsrc_regs = 0x0110, .names = { "Q", "R", "S", "T" }, }, { .val_regs = 0x0088, + .rdata_reg = 0x00d4, .irq_regs = 0x0148, .debounce_regs = 0x0160, .tolerance_regs = 0x015c, + .cmdsrc_regs = 0x0140, .names = { "U", "V", "W", "X" }, }, { .val_regs = 0x01E0, + .rdata_reg = 0x00d8, .irq_regs = 0x0178, .debounce_regs = 0x0190, .tolerance_regs = 0x018c, + .cmdsrc_regs = 0x0170, .names = { "Y", "Z", "AA", "AB" }, }, { .val_regs = 0x01e8, + .rdata_reg = 0x00dc, .irq_regs = 0x01a8, .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc, + .cmdsrc_regs = 0x01a0, .names = { "AC", "", "", "" }, }, }; -#define GPIO_BANK(x) ((x) >> 5) -#define GPIO_OFFSET(x) ((x) & 0x1f) -#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) +enum aspeed_gpio_reg { + reg_val, + reg_rdata, + reg_dir, + reg_irq_enable, + reg_irq_type0, + reg_irq_type1, + reg_irq_type2, + reg_irq_status, + reg_debounce_sel1, + reg_debounce_sel2, + reg_tolerance, + reg_cmdsrc0, + reg_cmdsrc1, +}; -#define GPIO_DATA 0x00 -#define GPIO_DIR 0x04 +#define GPIO_VAL_VALUE 0x00 +#define GPIO_VAL_DIR 0x04 #define GPIO_IRQ_ENABLE 0x00 #define GPIO_IRQ_TYPE0 0x04 @@ -143,6 +200,53 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { #define GPIO_DEBOUNCE_SEL1 0x00 #define GPIO_DEBOUNCE_SEL2 0x04 +#define GPIO_CMDSRC_0 0x00 +#define GPIO_CMDSRC_1 0x04 +#define GPIO_CMDSRC_ARM 0 +#define GPIO_CMDSRC_LPC 1 +#define GPIO_CMDSRC_COLDFIRE 2 +#define GPIO_CMDSRC_RESERVED 3 + +/* This will be resolved at compile time */ +static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + const enum aspeed_gpio_reg reg) +{ + switch (reg) { + case reg_val: + return gpio->base + bank->val_regs + GPIO_VAL_VALUE; + case reg_rdata: + return gpio->base + bank->rdata_reg; + case reg_dir: + return gpio->base + bank->val_regs + GPIO_VAL_DIR; + case reg_irq_enable: + return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; + case reg_irq_type0: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; + case reg_irq_type1: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; + case reg_irq_type2: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; + case reg_irq_status: + return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; + case reg_debounce_sel1: + return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL1; + case reg_debounce_sel2: + return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL2; + case reg_tolerance: + return gpio->base + bank->tolerance_regs; + case reg_cmdsrc0: + return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_0; + case reg_cmdsrc1: + return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_1; + } + BUG(); +} + +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_OFFSET(x) ((x) & 0x1f) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + #define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o)) #define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1) #define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0) @@ -201,18 +305,80 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset) return !props || (props->output & GPIO_BIT(offset)); } -static void __iomem *bank_val_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - unsigned int reg) +static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + int bindex, int cmdsrc) { - return gpio->base + bank->val_regs + reg; + void __iomem *c0 = bank_reg(gpio, bank, reg_cmdsrc0); + void __iomem *c1 = bank_reg(gpio, bank, reg_cmdsrc1); + u32 bit, reg; + + /* + * Each register controls 4 banks, so take the bottom 2 + * bits of the bank index, and use them to select the + * right control bit (0, 8, 16 or 24). + */ + bit = BIT((bindex & 3) << 3); + + /* Source 1 first to avoid illegal 11 combination */ + reg = ioread32(c1); + if (cmdsrc & 2) + reg |= bit; + else + reg &= ~bit; + iowrite32(reg, c1); + + /* Then Source 0 */ + reg = ioread32(c0); + if (cmdsrc & 1) + reg |= bit; + else + reg &= ~bit; + iowrite32(reg, c0); } -static void __iomem *bank_irq_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - unsigned int reg) +static bool aspeed_gpio_copro_request(struct aspeed_gpio *gpio, + unsigned int offset) { - return gpio->base + bank->irq_regs + reg; + const struct aspeed_gpio_bank *bank = to_bank(offset); + + if (!copro_ops || !gpio->cf_copro_bankmap) + return false; + if (!gpio->cf_copro_bankmap[offset >> 3]) + return false; + if (!copro_ops->request_access) + return false; + + /* Pause the coprocessor */ + copro_ops->request_access(copro_data); + + /* Change command source back to ARM */ + aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, GPIO_CMDSRC_ARM); + + /* Update cache */ + gpio->dcache[GPIO_BANK(offset)] = ioread32(bank_reg(gpio, bank, reg_rdata)); + + return true; +} + +static void aspeed_gpio_copro_release(struct aspeed_gpio *gpio, + unsigned int offset) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + + if (!copro_ops || !gpio->cf_copro_bankmap) + return; + if (!gpio->cf_copro_bankmap[offset >> 3]) + return; + if (!copro_ops->release_access) + return; + + /* Change command source back to ColdFire */ + aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, + GPIO_CMDSRC_COLDFIRE); + + /* Restart the coprocessor */ + copro_ops->release_access(copro_data); } static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) @@ -220,8 +386,7 @@ static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_gpio_bank *bank = to_bank(offset); - return !!(ioread32(bank_val_reg(gpio, bank, GPIO_DATA)) - & GPIO_BIT(offset)); + return !!(ioread32(bank_reg(gpio, bank, reg_val)) & GPIO_BIT(offset)); } static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, @@ -232,7 +397,7 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, void __iomem *addr; u32 reg; - addr = bank_val_reg(gpio, bank, GPIO_DATA); + addr = bank_reg(gpio, bank, reg_val); reg = gpio->dcache[GPIO_BANK(offset)]; if (val) @@ -249,11 +414,15 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, { struct aspeed_gpio *gpio = gpiochip_get_data(gc); unsigned long flags; + bool copro; 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); } @@ -261,7 +430,9 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = bank_reg(gpio, bank, reg_dir); unsigned long flags; + bool copro; u32 reg; if (!have_input(gpio, offset)) @@ -269,8 +440,13 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); - iowrite32(reg & ~GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); + reg = ioread32(addr); + reg &= ~GPIO_BIT(offset); + + copro = aspeed_gpio_copro_request(gpio, offset); + iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); @@ -282,7 +458,9 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, { struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = bank_reg(gpio, bank, reg_dir); unsigned long flags; + bool copro; u32 reg; if (!have_output(gpio, offset)) @@ -290,10 +468,15 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, spin_lock_irqsave(&gpio->lock, flags); + reg = ioread32(addr); + reg |= GPIO_BIT(offset); + + copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); - reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); - iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); + iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); return 0; @@ -314,7 +497,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) spin_lock_irqsave(&gpio->lock, flags); - val = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)) & GPIO_BIT(offset); + val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset); spin_unlock_irqrestore(&gpio->lock, flags); @@ -323,24 +506,23 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) } static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, - struct aspeed_gpio **gpio, - const struct aspeed_gpio_bank **bank, - u32 *bit) + struct aspeed_gpio **gpio, + const struct aspeed_gpio_bank **bank, + u32 *bit, int *offset) { - int offset; struct aspeed_gpio *internal; - offset = irqd_to_hwirq(d); + *offset = irqd_to_hwirq(d); internal = irq_data_get_irq_chip_data(d); /* This might be a bit of a questionable place to check */ - if (!have_irq(internal, offset)) + if (!have_irq(internal, *offset)) return -ENOTSUPP; *gpio = internal; - *bank = to_bank(offset); - *bit = GPIO_BIT(offset); + *bank = to_bank(*offset); + *bit = GPIO_BIT(*offset); return 0; } @@ -351,17 +533,23 @@ static void aspeed_gpio_irq_ack(struct irq_data *d) struct aspeed_gpio *gpio; unsigned long flags; void __iomem *status_addr; + int rc, offset; + bool copro; u32 bit; - int rc; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); if (rc) return; - status_addr = bank_irq_reg(gpio, bank, GPIO_IRQ_STATUS); + status_addr = bank_reg(gpio, bank, reg_irq_status); 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); } @@ -372,15 +560,17 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) unsigned long flags; u32 reg, bit; void __iomem *addr; - int rc; + int rc, offset; + bool copro; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); if (rc) return; - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_ENABLE); + addr = bank_reg(gpio, bank, reg_irq_enable); spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); reg = ioread32(addr); if (set) @@ -389,6 +579,8 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) reg &= ~bit; iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); } @@ -413,9 +605,10 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) struct aspeed_gpio *gpio; unsigned long flags; void __iomem *addr; - int rc; + int rc, offset; + bool copro; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); if (rc) return -EINVAL; @@ -441,22 +634,25 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) } spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE0); + addr = bank_reg(gpio, bank, reg_irq_type0); reg = ioread32(addr); reg = (reg & ~bit) | type0; iowrite32(reg, addr); - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE1); + addr = bank_reg(gpio, bank, reg_irq_type1); reg = ioread32(addr); reg = (reg & ~bit) | type1; iowrite32(reg, addr); - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE2); + addr = bank_reg(gpio, bank, reg_irq_type2); reg = ioread32(addr); reg = (reg & ~bit) | type2; iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); irq_set_handler_locked(d, handler); @@ -477,7 +673,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc) for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) { const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS)); + reg = ioread32(bank_reg(data, bank, reg_irq_status)); for_each_set_bit(p, ®, 32) { girq = irq_find_mapping(gc->irq.domain, i * 32 + p); @@ -549,21 +745,27 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) { struct aspeed_gpio *gpio = gpiochip_get_data(chip); - const struct aspeed_gpio_bank *bank; unsigned long flags; + void __iomem *treg; + bool copro; u32 val; - bank = to_bank(offset); + treg = bank_reg(gpio, to_bank(offset), reg_tolerance); spin_lock_irqsave(&gpio->lock, flags); - val = readl(gpio->base + bank->tolerance_regs); + copro = aspeed_gpio_copro_request(gpio, offset); + + val = readl(treg); if (enable) val |= GPIO_BIT(offset); else val &= ~GPIO_BIT(offset); - writel(val, gpio->base + bank->tolerance_regs); + writel(val, treg); + + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); return 0; @@ -582,13 +784,6 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset) pinctrl_gpio_free(chip->base + offset); } -static inline void __iomem *bank_debounce_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - unsigned int reg) -{ - return gpio->base + bank->debounce_regs + reg; -} - static int usecs_to_cycles(struct aspeed_gpio *gpio, unsigned long usecs, u32 *cycles) { @@ -666,11 +861,14 @@ static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, void __iomem *addr; u32 val; - addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL1); + /* Note: Debounce timer isn't under control of the command + * source registers, so no need to sync with the coprocessor + */ + addr = bank_reg(gpio, bank, reg_debounce_sel1); val = ioread32(addr); iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); - addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL2); + addr = bank_reg(gpio, bank, reg_debounce_sel2); val = ioread32(addr); iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr); } @@ -812,6 +1010,111 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, return -ENOTSUPP; } +/** + * aspeed_gpio_copro_set_ops - Sets the callbacks used for handhsaking with + * the coprocessor for shared GPIO banks + * @ops: The callbacks + * @data: Pointer passed back to the callbacks + */ +int aspeed_gpio_copro_set_ops(const struct aspeed_gpio_copro_ops *ops, void *data) +{ + copro_data = data; + copro_ops = ops; + + return 0; +} +EXPORT_SYMBOL_GPL(aspeed_gpio_copro_set_ops); + +/** + * aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire + * bank gets marked and any access from the ARM will + * result in handshaking via callbacks. + * @desc: The GPIO to be marked + * @vreg_offset: If non-NULL, returns the value register offset in the GPIO space + * @dreg_offset: If non-NULL, returns the data latch register offset in the GPIO space + * @bit: If non-NULL, returns the bit number of the GPIO in the registers + */ +int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, + u16 *vreg_offset, u16 *dreg_offset, u8 *bit) +{ + struct gpio_chip *chip = gpiod_to_chip(desc); + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + + if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL); + if (!gpio->cf_copro_bankmap) + return -ENOMEM; + if (offset < 0 || offset > gpio->config->nr_gpios) + return -EINVAL; + bindex = offset >> 3; + + spin_lock_irqsave(&gpio->lock, flags); + + /* Sanity check, this shouldn't happen */ + if (gpio->cf_copro_bankmap[bindex] == 0xff) { + rc = -EIO; + goto bail; + } + gpio->cf_copro_bankmap[bindex]++; + + /* Switch command source */ + if (gpio->cf_copro_bankmap[bindex] == 1) + aspeed_gpio_change_cmd_source(gpio, bank, bindex, + GPIO_CMDSRC_COLDFIRE); + + if (vreg_offset) + *vreg_offset = bank->val_regs; + if (dreg_offset) + *dreg_offset = bank->rdata_reg; + if (bit) + *bit = GPIO_OFFSET(offset); + bail: + spin_unlock_irqrestore(&gpio->lock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_gpio_copro_grab_gpio); + +/** + * aspeed_gpio_copro_release_gpio - Unmark a GPIO used by the coprocessor. + * @desc: The GPIO to be marked + */ +int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) +{ + struct gpio_chip *chip = gpiod_to_chip(desc); + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + + if (!gpio->cf_copro_bankmap) + return -ENXIO; + + if (offset < 0 || offset > gpio->config->nr_gpios) + return -EINVAL; + bindex = offset >> 3; + + spin_lock_irqsave(&gpio->lock, flags); + + /* Sanity check, this shouldn't happen */ + if (gpio->cf_copro_bankmap[bindex] == 0) { + rc = -EIO; + goto bail; + } + gpio->cf_copro_bankmap[bindex]--; + + /* Switch command source */ + if (gpio->cf_copro_bankmap[bindex] == 0) + aspeed_gpio_change_cmd_source(gpio, bank, bindex, + GPIO_CMDSRC_ARM); + bail: + spin_unlock_irqrestore(&gpio->lock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio); + /* * Any banks not specified in a struct aspeed_bank_props array are assumed to * have the properties: @@ -902,11 +1205,18 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) if (!gpio->dcache) return -ENOMEM; - /* Populate it with initial values read from the HW */ + /* + * Populate it with initial values read from the HW and switch + * all command sources to the ARM by default + */ for (i = 0; i < banks; i++) { const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - gpio->dcache[i] = ioread32(gpio->base + bank->val_regs + - GPIO_DATA); + void __iomem *addr = bank_reg(gpio, bank, reg_rdata); + gpio->dcache[i] = ioread32(addr); + aspeed_gpio_change_cmd_source(gpio, bank, 0, GPIO_CMDSRC_ARM); + aspeed_gpio_change_cmd_source(gpio, bank, 1, GPIO_CMDSRC_ARM); + aspeed_gpio_change_cmd_source(gpio, bank, 2, GPIO_CMDSRC_ARM); + aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM); } rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 684e9d6d6623..0a553d676042 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -51,7 +51,7 @@ static u32 ath79_gpio_read(struct ath79_gpio_ctrl *ctrl, unsigned reg) static void ath79_gpio_write(struct ath79_gpio_ctrl *ctrl, unsigned reg, u32 val) { - return writel(val, ctrl->base + reg); + writel(val, ctrl->base + reg); } static bool ath79_gpio_update_bits( diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 00272fa7cc4f..d0707fc23afd 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -485,12 +485,14 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc) static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); + int ret; - if (gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { + ret = gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq); + if (ret) { dev_err(kona_gpio->gpio_chip.parent, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - return -EINVAL; + return ret; } return 0; } diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 035a454eca43..a5ece8ea79bc 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -167,8 +167,8 @@ of_err: static int davinci_gpio_probe(struct platform_device *pdev) { static int ctrl_num, bank_base; - int gpio, bank, ret = 0; - unsigned ngpio, nbank; + int gpio, bank, i, ret = 0; + unsigned int ngpio, nbank, nirq; struct davinci_gpio_controller *chips; struct davinci_gpio_platform_data *pdata; struct device *dev = &pdev->dev; @@ -197,6 +197,16 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (WARN_ON(ARCH_NR_GPIOS < ngpio)) ngpio = ARCH_NR_GPIOS; + /* + * If there are unbanked interrupts then the number of + * interrupts is equal to number of gpios else all are banked so + * number of interrupts is equal to number of banks(each with 16 gpios) + */ + if (pdata->gpio_unbanked) + nirq = pdata->gpio_unbanked; + else + nirq = DIV_ROUND_UP(ngpio, 16); + nbank = DIV_ROUND_UP(ngpio, 32); chips = devm_kcalloc(dev, nbank, sizeof(struct davinci_gpio_controller), @@ -209,6 +219,15 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio_base)) return PTR_ERR(gpio_base); + for (i = 0; i < nirq; i++) { + chips->irqs[i] = platform_get_irq(pdev, i); + if (chips->irqs[i] < 0) { + dev_info(dev, "IRQ not populated, err = %d\n", + chips->irqs[i]); + return chips->irqs[i]; + } + } + snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++); chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL); if (!chips->chip.label) @@ -377,7 +396,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). */ if (offset < d->gpio_unbanked) - return d->base_irq + offset; + return d->irqs[offset]; else return -ENODEV; } @@ -386,11 +405,18 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) { struct davinci_gpio_controller *d; struct davinci_gpio_regs __iomem *g; - u32 mask; + u32 mask, i; d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs[0]; - mask = __gpio_mask(data->irq - d->base_irq); + for (i = 0; i < MAX_INT_PER_BANK; i++) + if (data->irq == d->irqs[i]) + break; + + if (i == MAX_INT_PER_BANK) + return -EINVAL; + + mask = __gpio_mask(i); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; @@ -459,9 +485,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) int ret; struct clk *clk; u32 binten = 0; - unsigned ngpio, bank_irq; + unsigned ngpio; struct device *dev = &pdev->dev; - struct resource *res; struct davinci_gpio_controller *chips = platform_get_drvdata(pdev); struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; @@ -481,24 +506,13 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; ngpio = pdata->ngpio; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Invalid IRQ resource\n"); - return -EBUSY; - } - - bank_irq = res->start; - - if (!bank_irq) { - dev_err(dev, "Invalid IRQ resource\n"); - return -ENODEV; - } clk = devm_clk_get(dev, "gpio"); if (IS_ERR(clk)) { dev_err(dev, "Error %ld getting gpio clock\n", PTR_ERR(clk)); return PTR_ERR(clk); } + ret = clk_prepare_enable(clk); if (ret) return ret; @@ -538,12 +552,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) if (pdata->gpio_unbanked) { /* pass "bank 0" GPIO IRQs to AINTC */ chips->chip.to_irq = gpio_to_irq_unbanked; - chips->base_irq = bank_irq; chips->gpio_unbanked = pdata->gpio_unbanked; binten = GENMASK(pdata->gpio_unbanked / 16, 0); /* AINTC handles mask/unmask; GPIO handles triggering */ - irq = bank_irq; + irq = chips->irqs[0]; irq_chip = gpio_get_irq_chip(irq); irq_chip->name = "GPIO-AINTC"; irq_chip->irq_set_type = gpio_irq_type_unbanked; @@ -554,10 +567,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) writel_relaxed(~0, &g->set_rising); /* set the direct IRQs up to use that irqchip */ - for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, irq_chip); - irq_set_handler_data(irq, chips); - irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); + for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++) { + irq_set_chip(chips->irqs[gpio], irq_chip); + irq_set_handler_data(chips->irqs[gpio], chips); + irq_set_status_flags(chips->irqs[gpio], + IRQ_TYPE_EDGE_BOTH); } goto done; @@ -567,7 +581,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we * then chain through our own handler. */ - for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) { + for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 16) { /* disabled by default, enabled only as needed * There are register sets for 32 GPIOs. 2 banks of 16 * GPIOs are covered by each set of registers hence divide by 2 @@ -594,8 +608,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) irqdata->bank_num = bank; irqdata->chip = chips; - irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, - irqdata); + irq_set_chained_handler_and_data(chips->irqs[bank], + gpio_irq_handler, irqdata); binten |= BIT(bank); } diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 7a2de3de6571..28da700f5f52 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -255,11 +255,13 @@ static int dwapb_irq_reqres(struct irq_data *d) struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct gpio_chip *gc = &gpio->ports[0].gc; + int ret; - if (gpiochip_lock_as_irq(gc, irqd_to_hwirq(d))) { + ret = gpiochip_lock_as_irq(gc, irqd_to_hwirq(d)); + if (ret) { dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - return -EINVAL; + return ret; } return 0; } diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 2b466b80e70a..982e699a5b81 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -101,12 +101,14 @@ static void em_gio_irq_enable(struct irq_data *d) static int em_gio_irq_reqres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); + int ret; - if (gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { + ret = gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); + if (ret) { dev_err(p->gpio_chip.parent, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - return -EINVAL; + return ret; } return 0; } diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 7cad14d3f127..389ecd8b7d26 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -35,12 +35,15 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff +#define IT8613_ID 0x8613 #define IT8620_ID 0x8620 #define IT8628_ID 0x8628 +#define IT8718_ID 0x8718 #define IT8728_ID 0x8728 #define IT8732_ID 0x8732 #define IT8761_ID 0x8761 #define IT8772_ID 0x8772 +#define IT8786_ID 0x8786 /* IO Ports */ #define REG 0x2e @@ -306,6 +309,14 @@ static int __init it87_gpio_init(void) it87_gpio->chip = it87_template_chip; switch (chip_type) { + case IT8613_ID: + gpio_ba_reg = 0x62; + it87_gpio->io_size = 8; /* it8613 only needs 6, use 8 for alignment */ + it87_gpio->output_base = 0xc8; + it87_gpio->simple_base = 0xc0; + it87_gpio->simple_size = 6; + it87_gpio->chip.ngpio = 64; /* has 48, use 64 for convenient calc */ + break; case IT8620_ID: case IT8628_ID: gpio_ba_reg = 0x62; @@ -314,9 +325,11 @@ static int __init it87_gpio_init(void) it87_gpio->simple_size = 0; it87_gpio->chip.ngpio = 64; break; + case IT8718_ID: case IT8728_ID: case IT8732_ID: case IT8772_ID: + case IT8786_ID: gpio_ba_reg = 0x62; it87_gpio->io_size = 8; it87_gpio->output_base = 0xc8; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 9d8bcc69f245..f03cb0ba7726 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -653,6 +653,12 @@ static int max732x_probe(struct i2c_client *client, chip->client_group_a = client; if (nr_port > 8) { c = i2c_new_dummy(client->adapter, addr_b); + if (!c) { + dev_err(&client->dev, + "Failed to allocate I2C device\n"); + ret = -ENODEV; + goto out_failed; + } chip->client_group_b = chip->client_dummy = c; } break; @@ -660,6 +666,12 @@ static int max732x_probe(struct i2c_client *client, chip->client_group_b = client; if (nr_port > 8) { c = i2c_new_dummy(client->adapter, addr_a); + if (!c) { + dev_err(&client->dev, + "Failed to allocate I2C device\n"); + ret = -ENODEV; + goto out_failed; + } chip->client_group_a = chip->client_dummy = c; } break; diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index e1037582e34d..b2635326546e 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -56,9 +56,9 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, rnd = fls(debounce) - 1; if (rnd && (debounce & BIT(rnd - 1))) - debounce = round_up(debounce, MEN_Z127_DB_MIN_US); + debounce = roundup(debounce, MEN_Z127_DB_MIN_US); else - debounce = round_down(debounce, MEN_Z127_DB_MIN_US); + debounce = rounddown(debounce, MEN_Z127_DB_MIN_US); if (debounce > MEN_Z127_DB_MAX_US) debounce = MEN_Z127_DB_MAX_US; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index b23d9a36be1f..51c7d1b84c2e 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -496,9 +496,10 @@ static int ioh_gpio_probe(struct pci_dev *pdev, return 0; err_gpiochip_add: + chip = chip_save; while (--i >= 0) { - chip--; gpiochip_remove(&chip->gpio); + chip++; } kfree(chip_save); diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 7b14d6280e44..935292a30c99 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -136,8 +136,20 @@ static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line) static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) { unsigned long pinmask = bgpio_line2mask(gc, gpio); + bool dir = !!(gc->bgpio_dir & pinmask); - if (gc->bgpio_dir & pinmask) + /* + * If the direction is OUT we read the value from the SET + * register, and if the direction is IN we read the value + * from the DAT register. + * + * If the direction bits are inverted, naturally this gets + * inverted too. + */ + if (gc->bgpio_dir_inverted) + dir = !dir; + + if (dir) return !!(gc->read_reg(gc->reg_set) & pinmask); else return !!(gc->read_reg(gc->reg_dat) & pinmask); @@ -157,8 +169,13 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, *bits &= ~*mask; /* Exploit the fact that we know which directions are set */ - set_mask = *mask & gc->bgpio_dir; - get_mask = *mask & ~gc->bgpio_dir; + if (gc->bgpio_dir_inverted) { + set_mask = *mask & ~gc->bgpio_dir; + get_mask = *mask & gc->bgpio_dir; + } else { + set_mask = *mask & gc->bgpio_dir; + get_mask = *mask & ~gc->bgpio_dir; + } if (set_mask) *bits |= gc->read_reg(gc->reg_set) & set_mask; @@ -359,7 +376,10 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) spin_lock_irqsave(&gc->bgpio_lock, flags); - gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); + if (gc->bgpio_dir_inverted) + gc->bgpio_dir |= bgpio_line2mask(gc, gpio); + else + gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); gc->write_reg(gc->reg_dir, gc->bgpio_dir); spin_unlock_irqrestore(&gc->bgpio_lock, flags); @@ -370,7 +390,10 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) { /* Return 0 if output, 1 of input */ - return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); + if (gc->bgpio_dir_inverted) + return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); + else + return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); } static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) @@ -381,37 +404,10 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) spin_lock_irqsave(&gc->bgpio_lock, flags); - gc->bgpio_dir |= bgpio_line2mask(gc, gpio); - gc->write_reg(gc->reg_dir, gc->bgpio_dir); - - spin_unlock_irqrestore(&gc->bgpio_lock, flags); - - return 0; -} - -static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio) -{ - unsigned long flags; - - spin_lock_irqsave(&gc->bgpio_lock, flags); - - gc->bgpio_dir |= bgpio_line2mask(gc, gpio); - gc->write_reg(gc->reg_dir, gc->bgpio_dir); - - spin_unlock_irqrestore(&gc->bgpio_lock, flags); - - return 0; -} - -static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) -{ - unsigned long flags; - - gc->set(gc, gpio, val); - - spin_lock_irqsave(&gc->bgpio_lock, flags); - - gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); + if (gc->bgpio_dir_inverted) + gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); + else + gc->bgpio_dir |= bgpio_line2mask(gc, gpio); gc->write_reg(gc->reg_dir, gc->bgpio_dir); spin_unlock_irqrestore(&gc->bgpio_lock, flags); @@ -419,12 +415,6 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } -static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio) -{ - /* Return 0 if output, 1 if input */ - return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); -} - static int bgpio_setup_accessors(struct device *dev, struct gpio_chip *gc, bool byte_be) @@ -560,9 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc, gc->get_direction = bgpio_get_dir; } else if (dirin) { gc->reg_dir = dirin; - gc->direction_output = bgpio_dir_out_inv; - gc->direction_input = bgpio_dir_in_inv; - gc->get_direction = bgpio_get_dir_inv; + gc->direction_output = bgpio_dir_out; + gc->direction_input = bgpio_dir_in; + gc->get_direction = bgpio_get_dir; + gc->bgpio_dir_inverted = true; } else { if (flags & BGPIOF_NO_OUTPUT) gc->direction_output = bgpio_dir_out_err; @@ -582,6 +573,33 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) return -EINVAL; } +/** + * bgpio_init() - Initialize generic GPIO accessor functions + * @gc: the GPIO chip to set up + * @dev: the parent device of the new GPIO chip (compulsory) + * @sz: the size (width) of the MMIO registers in bytes, typically 1, 2 or 4 + * @dat: MMIO address for the register to READ the value of the GPIO lines, it + * is expected that a 1 in the corresponding bit in this register means the + * line is asserted + * @set: MMIO address for the register to SET the value of the GPIO lines, it is + * expected that we write the line with 1 in this register to drive the GPIO line + * high. + * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, it is + * expected that we write the line with 1 in this register to drive the GPIO line + * low. It is allowed to leave this address as NULL, in that case the SET register + * will be assumed to also clear the GPIO lines, by actively writing the line + * with 0. + * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed + * that setting a line to 1 in this register will turn that line into an + * output line. Conversely, setting the line to 0 will turn that line into + * an input. Either this or @dirin can be defined, but never both. + * @dirin: MMIO address for the register to set this line as INPUT. It is assumed + * that setting a line to 1 in this register will turn that line into an + * input line. Conversely, setting the line to 0 will turn that line into + * an output. Either this or @dirout can be defined, but never both. + * @flags: Different flags that will affect the behaviour of the device, such as + * endianness etc. + */ int bgpio_init(struct gpio_chip *gc, struct device *dev, unsigned long sz, void __iomem *dat, void __iomem *set, void __iomem *clr, void __iomem *dirout, void __iomem *dirin, diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c new file mode 100644 index 000000000000..d72af6f6cdbd --- /dev/null +++ b/drivers/gpio/gpio-mt7621.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#define MTK_BANK_CNT 3 +#define MTK_BANK_WIDTH 32 + +#define GPIO_BANK_STRIDE 0x04 +#define GPIO_REG_CTRL 0x00 +#define GPIO_REG_POL 0x10 +#define GPIO_REG_DATA 0x20 +#define GPIO_REG_DSET 0x30 +#define GPIO_REG_DCLR 0x40 +#define GPIO_REG_REDGE 0x50 +#define GPIO_REG_FEDGE 0x60 +#define GPIO_REG_HLVL 0x70 +#define GPIO_REG_LLVL 0x80 +#define GPIO_REG_STAT 0x90 +#define GPIO_REG_EDGE 0xA0 + +struct mtk_gc { + struct gpio_chip chip; + spinlock_t lock; + int bank; + u32 rising; + u32 falling; + u32 hlevel; + u32 llevel; +}; + +/** + * struct mtk - state container for + * data of the platform driver. It is 3 + * separate gpio-chip each one with its + * own irq_chip. + * @dev: device instance + * @base: memory base address + * @gpio_irq: irq number from the device tree + * @gc_map: array of the gpio chips + */ +struct mtk { + struct device *dev; + void __iomem *base; + int gpio_irq; + struct mtk_gc gc_map[MTK_BANK_CNT]; +}; + +static inline struct mtk_gc * +to_mediatek_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct mtk_gc, chip); +} + +static inline void +mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val) +{ + struct gpio_chip *gc = &rg->chip; + struct mtk *mtk = gpiochip_get_data(gc); + + offset = (rg->bank * GPIO_BANK_STRIDE) + offset; + gc->write_reg(mtk->base + offset, val); +} + +static inline u32 +mtk_gpio_r32(struct mtk_gc *rg, u32 offset) +{ + struct gpio_chip *gc = &rg->chip; + struct mtk *mtk = gpiochip_get_data(gc); + + offset = (rg->bank * GPIO_BANK_STRIDE) + offset; + return gc->read_reg(mtk->base + offset); +} + +static irqreturn_t +mediatek_gpio_irq_handler(int irq, void *data) +{ + struct gpio_chip *gc = data; + struct mtk_gc *rg = to_mediatek_gpio(gc); + irqreturn_t ret = IRQ_NONE; + unsigned long pending; + int bit; + + pending = mtk_gpio_r32(rg, GPIO_REG_STAT); + + for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { + u32 map = irq_find_mapping(gc->irq.domain, bit); + + generic_handle_irq(map); + mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); + ret |= IRQ_HANDLED; + } + + return ret; +} + +static void +mediatek_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 rise, fall, high, low; + + spin_lock_irqsave(&rg->lock, flags); + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static void +mediatek_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 rise, fall, high, low; + + spin_lock_irqsave(&rg->lock, flags); + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static int +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + u32 mask = BIT(pin); + + if (type == IRQ_TYPE_PROBE) { + if ((rg->rising | rg->falling | + rg->hlevel | rg->llevel) & mask) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + rg->rising &= ~mask; + rg->falling &= ~mask; + rg->hlevel &= ~mask; + rg->llevel &= ~mask; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + rg->rising |= mask; + rg->falling |= mask; + break; + case IRQ_TYPE_EDGE_RISING: + rg->rising |= mask; + break; + case IRQ_TYPE_EDGE_FALLING: + rg->falling |= mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + rg->hlevel |= mask; + break; + case IRQ_TYPE_LEVEL_LOW: + rg->llevel |= mask; + break; + } + + return 0; +} + +static struct irq_chip mediatek_gpio_irq_chip = { + .irq_unmask = mediatek_gpio_irq_unmask, + .irq_mask = mediatek_gpio_irq_mask, + .irq_mask_ack = mediatek_gpio_irq_mask, + .irq_set_type = mediatek_gpio_irq_type, +}; + +static int +mediatek_gpio_xlate(struct gpio_chip *chip, + const struct of_phandle_args *spec, u32 *flags) +{ + int gpio = spec->args[0]; + struct mtk_gc *rg = to_mediatek_gpio(chip); + + if (rg->bank != gpio / MTK_BANK_WIDTH) + return -EINVAL; + + if (flags) + *flags = spec->args[1]; + + return gpio % MTK_BANK_WIDTH; +} + +static int +mediatek_gpio_bank_probe(struct device *dev, + struct device_node *node, int bank) +{ + struct mtk *mtk = dev_get_drvdata(dev); + struct mtk_gc *rg; + void __iomem *dat, *set, *ctrl, *diro; + int ret; + + rg = &mtk->gc_map[bank]; + 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); + set = mtk->base + GPIO_REG_DSET + (rg->bank * GPIO_BANK_STRIDE); + ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE); + diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE); + + ret = bgpio_init(&rg->chip, dev, 4, + dat, set, ctrl, diro, NULL, 0); + if (ret) { + dev_err(dev, "bgpio_init() failed\n"); + return ret; + } + + rg->chip.of_gpio_n_cells = 2; + rg->chip.of_xlate = mediatek_gpio_xlate; + rg->chip.label = devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d", + dev_name(dev), bank); + + ret = devm_gpiochip_add_data(dev, &rg->chip, mtk); + if (ret < 0) { + dev_err(dev, "Could not register gpio %d, ret=%d\n", + rg->chip.ngpio, ret); + return ret; + } + + if (mtk->gpio_irq) { + /* + * Manually request the irq here instead of passing + * a flow-handler to gpiochip_set_chained_irqchip, + * because the irq is shared. + */ + ret = devm_request_irq(dev, mtk->gpio_irq, + mediatek_gpio_irq_handler, IRQF_SHARED, + rg->chip.label, &rg->chip); + + if (ret) { + dev_err(dev, "Error requesting IRQ %d: %d\n", + mtk->gpio_irq, ret); + return ret; + } + + ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, + 0, handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "failed to add gpiochip_irqchip\n"); + return ret; + } + + gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, + mtk->gpio_irq, NULL); + } + + /* set polarity to low for all gpios */ + mtk_gpio_w32(rg, GPIO_REG_POL, 0); + + dev_info(dev, "registering %d gpios\n", rg->chip.ngpio); + + return 0; +} + +static int +mediatek_gpio_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct mtk *mtk; + int i; + + mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL); + if (!mtk) + return -ENOMEM; + + mtk->base = devm_ioremap_resource(dev, res); + if (IS_ERR(mtk->base)) + return PTR_ERR(mtk->base); + + mtk->gpio_irq = irq_of_parse_and_map(np, 0); + mtk->dev = dev; + platform_set_drvdata(pdev, mtk); + mediatek_gpio_irq_chip.name = dev_name(dev); + + for (i = 0; i < MTK_BANK_CNT; i++) + mediatek_gpio_bank_probe(dev, np, i); + + return 0; +} + +static const struct of_device_id mediatek_gpio_match[] = { + { .compatible = "mediatek,mt7621-gpio" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mediatek_gpio_match); + +static struct platform_driver mediatek_gpio_driver = { + .probe = mediatek_gpio_probe, + .driver = { + .name = "mt7621_gpio", + .of_match_table = mediatek_gpio_match, + }, +}; + +builtin_platform_driver(mediatek_gpio_driver); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 2f2829966d4c..995cf0b9e0b1 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -45,6 +45,15 @@ struct mxc_gpio_hwdata { unsigned fall_edge; }; +struct mxc_gpio_reg_saved { + u32 icr1; + u32 icr2; + u32 imr; + u32 gdir; + u32 edge_sel; + u32 dr; +}; + struct mxc_gpio_port { struct list_head node; void __iomem *base; @@ -55,6 +64,8 @@ struct mxc_gpio_port { struct gpio_chip gc; struct device *dev; u32 both_edges; + struct mxc_gpio_reg_saved gpio_saved_reg; + bool power_off; }; static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { @@ -143,6 +154,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, + { .compatible = "fsl,imx7d-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, { /* sentinel */ } }; @@ -434,6 +446,9 @@ static int mxc_gpio_probe(struct platform_device *pdev) return err; } + if (of_device_is_compatible(np, "fsl,imx7d-gpio")) + port->power_off = true; + /* disable the interrupt and clear the status */ writel(0, port->base + GPIO_IMR); writel(~0, port->base + GPIO_ISR); @@ -497,6 +512,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) list_add_tail(&port->node, &mxc_gpio_ports); + platform_set_drvdata(pdev, port); + return 0; out_irqdomain_remove: @@ -507,11 +524,67 @@ out_bgio: return err; } +static void mxc_gpio_save_regs(struct mxc_gpio_port *port) +{ + if (!port->power_off) + return; + + port->gpio_saved_reg.icr1 = readl(port->base + GPIO_ICR1); + port->gpio_saved_reg.icr2 = readl(port->base + GPIO_ICR2); + port->gpio_saved_reg.imr = readl(port->base + GPIO_IMR); + port->gpio_saved_reg.gdir = readl(port->base + GPIO_GDIR); + port->gpio_saved_reg.edge_sel = readl(port->base + GPIO_EDGE_SEL); + port->gpio_saved_reg.dr = readl(port->base + GPIO_DR); +} + +static void mxc_gpio_restore_regs(struct mxc_gpio_port *port) +{ + if (!port->power_off) + return; + + writel(port->gpio_saved_reg.icr1, port->base + GPIO_ICR1); + writel(port->gpio_saved_reg.icr2, port->base + GPIO_ICR2); + writel(port->gpio_saved_reg.imr, port->base + GPIO_IMR); + writel(port->gpio_saved_reg.gdir, port->base + GPIO_GDIR); + writel(port->gpio_saved_reg.edge_sel, port->base + GPIO_EDGE_SEL); + writel(port->gpio_saved_reg.dr, port->base + GPIO_DR); +} + +static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + + mxc_gpio_save_regs(port); + clk_disable_unprepare(port->clk); + + return 0; +} + +static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + int ret; + + ret = clk_prepare_enable(port->clk); + if (ret) + return ret; + mxc_gpio_restore_regs(port); + + return 0; +} + +static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) +}; + static struct platform_driver mxc_gpio_driver = { .driver = { .name = "gpio-mxc", .of_match_table = mxc_gpio_dt_ids, .suppress_bind_attrs = true, + .pm = &mxc_gpio_dev_pm_ops, }, .probe = mxc_gpio_probe, .id_table = mxc_gpio_devtype, diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index e2831ee70cdc..df30490da820 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -126,8 +126,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) else writel(pin_mask, pin_addr + MXS_CLR); - writel(pin_mask, - port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); + writel(pin_mask, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); return 0; } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d1afedf4dcbf..e81008678a38 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -77,6 +77,8 @@ struct gpio_bank { bool workaround_enabled; void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); + void (*set_dataout_multiple)(struct gpio_bank *bank, + unsigned long *mask, unsigned long *bits); int (*get_context_loss_count)(struct device *dev); struct omap_gpio_reg_offs *regs; @@ -161,6 +163,51 @@ static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset) return (readl_relaxed(reg) & (BIT(offset))) != 0; } +/* set multiple data out values using dedicate set/clear register */ +static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank, + unsigned long *mask, + unsigned long *bits) +{ + void __iomem *reg = bank->base; + u32 l; + + l = *bits & *mask; + writel_relaxed(l, reg + bank->regs->set_dataout); + bank->context.dataout |= l; + + l = ~*bits & *mask; + writel_relaxed(l, reg + bank->regs->clr_dataout); + bank->context.dataout &= ~l; +} + +/* set multiple data out values using mask register */ +static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank, + unsigned long *mask, + unsigned long *bits) +{ + void __iomem *reg = bank->base + bank->regs->dataout; + u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); + + writel_relaxed(l, reg); + bank->context.dataout = l; +} + +static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank, + unsigned long *mask) +{ + void __iomem *reg = bank->base + bank->regs->datain; + + return readl_relaxed(reg) & *mask; +} + +static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank, + unsigned long *mask) +{ + void __iomem *reg = bank->base + bank->regs->dataout; + + return readl_relaxed(reg) & *mask; +} + static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { int l = readl_relaxed(base + reg); @@ -968,6 +1015,26 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) return 0; } +static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); + void __iomem *reg = bank->base + bank->regs->direction; + unsigned long in = readl_relaxed(reg), l; + + *bits = 0; + + l = in & *mask; + if (l) + *bits |= omap_get_gpio_datain_multiple(bank, &l); + + l = ~in & *mask; + if (l) + *bits |= omap_get_gpio_dataout_multiple(bank, &l); + + return 0; +} + static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, unsigned debounce) { @@ -1012,6 +1079,17 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) raw_spin_unlock_irqrestore(&bank->lock, flags); } +static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); + unsigned long flags; + + raw_spin_lock_irqsave(&bank->lock, flags); + bank->set_dataout_multiple(bank, mask, bits); + raw_spin_unlock_irqrestore(&bank->lock, flags); +} + /*---------------------------------------------------------------------*/ static void omap_gpio_show_rev(struct gpio_bank *bank) @@ -1073,9 +1151,11 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) bank->chip.get_direction = omap_gpio_get_direction; bank->chip.direction_input = omap_gpio_input; bank->chip.get = omap_gpio_get; + bank->chip.get_multiple = omap_gpio_get_multiple; bank->chip.direction_output = omap_gpio_output; bank->chip.set_config = omap_gpio_set_config; bank->chip.set = omap_gpio_set; + bank->chip.set_multiple = omap_gpio_set_multiple; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1209,10 +1289,14 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } - if (bank->regs->set_dataout && bank->regs->clr_dataout) + if (bank->regs->set_dataout && bank->regs->clr_dataout) { bank->set_dataout = omap_set_gpio_dataout_reg; - else + bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple; + } else { bank->set_dataout = omap_set_gpio_dataout_mask; + bank->set_dataout_multiple = + omap_set_gpio_dataout_mask_multiple; + } raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->wa_lock); diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index c55ad157e820..023a32cfac42 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -708,7 +708,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, { struct i2c_client *client = chip->client; - if (irq_base != -1 && (chip->driver_data & PCA_INT)) + if (client->irq && irq_base != -1 && (chip->driver_data & PCA_INT)) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index f5545049c187..f809a5a8e9eb 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -12,6 +12,8 @@ * GNU General Public License version 2 for more details. */ +#include <linux/bitmap.h> +#include <linux/bitops.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> @@ -90,6 +92,25 @@ static int pisosr_gpio_get(struct gpio_chip *chip, unsigned offset) return (gpio->buffer[offset / 8] >> (offset % 8)) & 0x1; } +static int pisosr_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct pisosr_gpio *gpio = gpiochip_get_data(chip); + unsigned int nbytes = DIV_ROUND_UP(chip->ngpio, 8); + unsigned int i, j; + + pisosr_gpio_refresh(gpio); + + bitmap_zero(bits, chip->ngpio); + for (i = 0; i < nbytes; i++) { + j = i / sizeof(unsigned long); + bits[j] |= ((unsigned long) gpio->buffer[i]) + << (8 * (i % sizeof(unsigned long))); + } + + return 0; +} + static const struct gpio_chip template_chip = { .label = "pisosr-gpio", .owner = THIS_MODULE, @@ -97,6 +118,7 @@ static const struct gpio_chip template_chip = { .direction_input = pisosr_gpio_direction_input, .direction_output = pisosr_gpio_direction_output, .get = pisosr_gpio_get, + .get_multiple = pisosr_gpio_get_multiple, .base = -1, .ngpio = DEFAULT_NGPIO, .can_sleep = true, diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 1e66f808051c..c18712dabf93 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -241,6 +241,17 @@ int pxa_irq_to_gpio(int irq) return irq_gpio0; } +static bool pxa_gpio_has_pinctrl(void) +{ + switch (gpio_type) { + case PXA3XX_GPIO: + return false; + + default: + return true; + } +} + static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct pxa_gpio_chip *pchip = chip_to_pxachip(chip); @@ -255,9 +266,11 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) unsigned long flags; int ret; - ret = pinctrl_gpio_direction_input(chip->base + offset); - if (!ret) - return 0; + if (pxa_gpio_has_pinctrl()) { + ret = pinctrl_gpio_direction_input(chip->base + offset); + if (!ret) + return 0; + } spin_lock_irqsave(&gpio_lock, flags); @@ -282,9 +295,11 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip, writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); - ret = pinctrl_gpio_direction_output(chip->base + offset); - if (ret) - return ret; + if (pxa_gpio_has_pinctrl()) { + ret = pinctrl_gpio_direction_output(chip->base + offset); + if (ret) + return ret; + } spin_lock_irqsave(&gpio_lock, flags); @@ -348,8 +363,12 @@ static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, pchip->chip.set = pxa_gpio_set; pchip->chip.to_irq = pxa_gpio_to_irq; pchip->chip.ngpio = ngpio; - pchip->chip.request = gpiochip_generic_request; - pchip->chip.free = gpiochip_generic_free; + + if (pxa_gpio_has_pinctrl()) { + pchip->chip.request = gpiochip_generic_request; + pchip->chip.free = gpiochip_generic_free; + } + #ifdef CONFIG_OF_GPIO pchip->chip.of_node = np; pchip->chip.of_xlate = pxa_gpio_of_xlate; @@ -607,7 +626,7 @@ static int pxa_gpio_probe(struct platform_device *pdev) struct pxa_gpio_platform_data *info; void __iomem *gpio_reg_base; int gpio, ret; - int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; + int irq0 = 0, irq1 = 0, irq_mux; pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL); if (!pchip) @@ -646,14 +665,13 @@ static int pxa_gpio_probe(struct platform_device *pdev) pchip->irq0 = irq0; pchip->irq1 = irq1; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; gpio_reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!gpio_reg_base) return -EINVAL; - if (irq0 > 0) - gpio_offset = 2; - clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Error %ld to get gpio clock\n", diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 3b4dc1a9a68d..a499c633a6c5 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -25,7 +25,7 @@ #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/rc5t583.h> struct rc5t583_gpio { diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 350390c0b290..55cc61086d99 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -15,7 +15,7 @@ */ #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -278,6 +278,13 @@ static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) pm_runtime_put(&p->pdev->dev); } +static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct gpio_rcar_priv *p = gpiochip_get_data(chip); + + return !(gpio_rcar_read(p, INOUTSEL) & BIT(offset)); +} + static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) { gpio_rcar_config_general_input_output_mode(chip, offset, false); @@ -461,6 +468,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip = &p->gpio_chip; gpio_chip->request = gpio_rcar_request; gpio_chip->free = gpio_rcar_free; + gpio_chip->get_direction = gpio_rcar_get_direction; gpio_chip->direction_input = gpio_rcar_direction_input; gpio_chip->get = gpio_rcar_get; gpio_chip->direction_output = gpio_rcar_direction_output; diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index cbf0f9e6465b..2938217566d3 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -25,7 +25,7 @@ #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/pci.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/rdc321x.h> #include <linux/slab.h> diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 249f433aa62d..986eb3b231ac 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/module.h> #include <linux/io.h> diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 545004445846..e9878f6ede67 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -26,8 +26,7 @@ #include <linux/acpi.h> #include <linux/platform_device.h> #include <linux/pci_ids.h> - -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #define GEN 0x00 #define GIO 0x04 @@ -138,6 +137,13 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, return 0; } +static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num) +{ + struct sch_gpio *sch = gpiochip_get_data(gc); + + return sch_gpio_reg_get(sch, gpio_num, GIO); +} + static const struct gpio_chip sch_gpio_chip = { .label = "sch_gpio", .owner = THIS_MODULE, @@ -145,6 +151,7 @@ static const struct gpio_chip sch_gpio_chip = { .get = sch_gpio_get, .direction_output = sch_gpio_direction_out, .set = sch_gpio_set, + .get_direction = sch_gpio_get_direction, }; static int sch_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index b96990c262a1..5497f0a88cf0 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -17,16 +17,15 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/bitops.h> #include <linux/io.h> #define DRV_NAME "gpio-sch311x" -#define SCH311X_GPIO_CONF_OUT 0x00 -#define SCH311X_GPIO_CONF_IN 0x01 -#define SCH311X_GPIO_CONF_INVERT 0x02 -#define SCH311X_GPIO_CONF_OPEN_DRAIN 0x80 +#define SCH311X_GPIO_CONF_DIR BIT(0) +#define SCH311X_GPIO_CONF_INVERT BIT(1) +#define SCH311X_GPIO_CONF_OPEN_DRAIN BIT(7) #define SIO_CONFIG_KEY_ENTER 0x55 #define SIO_CONFIG_KEY_EXIT 0xaa @@ -163,7 +162,7 @@ static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset) static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); - unsigned char data; + u8 data; spin_lock(&block->lock); data = inb(block->runtime_reg + block->data_reg); @@ -175,7 +174,7 @@ static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) static void __sch311x_gpio_set(struct sch311x_gpio_block *block, unsigned offset, int value) { - unsigned char data = inb(block->runtime_reg + block->data_reg); + u8 data = inb(block->runtime_reg + block->data_reg); if (value) data |= BIT(offset); else @@ -196,10 +195,12 @@ static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset, static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); + u8 data; spin_lock(&block->lock); - outb(SCH311X_GPIO_CONF_IN, block->runtime_reg + - block->config_regs[offset]); + data = inb(block->runtime_reg + block->config_regs[offset]); + data |= SCH311X_GPIO_CONF_DIR; + outb(data, block->runtime_reg + block->config_regs[offset]); spin_unlock(&block->lock); return 0; @@ -209,18 +210,59 @@ static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); + u8 data; spin_lock(&block->lock); - outb(SCH311X_GPIO_CONF_OUT, block->runtime_reg + - block->config_regs[offset]); - + data = inb(block->runtime_reg + block->config_regs[offset]); + data &= ~SCH311X_GPIO_CONF_DIR; + outb(data, block->runtime_reg + block->config_regs[offset]); __sch311x_gpio_set(block, offset, value); spin_unlock(&block->lock); return 0; } +static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = gpiochip_get_data(chip); + u8 data; + + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->config_regs[offset]); + spin_unlock(&block->lock); + + return !!(data & SCH311X_GPIO_CONF_DIR); +} + +static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset, + unsigned long config) +{ + struct sch311x_gpio_block *block = gpiochip_get_data(chip); + enum pin_config_param param = pinconf_to_config_param(config); + u8 data; + + switch (param) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->config_regs[offset]); + data |= SCH311X_GPIO_CONF_OPEN_DRAIN; + outb(data, block->runtime_reg + block->config_regs[offset]); + spin_unlock(&block->lock); + return 0; + case PIN_CONFIG_DRIVE_PUSH_PULL: + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->config_regs[offset]); + data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN; + outb(data, block->runtime_reg + block->config_regs[offset]); + spin_unlock(&block->lock); + return 0; + default: + break; + } + return -ENOTSUPP; +} + static int sch311x_gpio_probe(struct platform_device *pdev) { struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev); @@ -253,6 +295,8 @@ static int sch311x_gpio_probe(struct platform_device *pdev) block->chip.free = sch311x_gpio_free; block->chip.direction_input = sch311x_gpio_direction_in; block->chip.direction_output = sch311x_gpio_direction_out; + block->chip.get_direction = sch311x_gpio_get_direction; + block->chip.set_config = sch311x_gpio_set_config; block->chip.get = sch311x_gpio_get; block->chip.set = sch311x_gpio_set; block->chip.ngpio = 8; @@ -309,7 +353,7 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr) { int err = 0, reg; unsigned short base_addr; - unsigned char dev_id; + u8 dev_id; err = sch311x_sio_enter(sio_config_port); if (err) diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index 22267479ba68..ee3039f091f4 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -10,7 +10,7 @@ */ #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/io.h> #include <linux/init.h> #include <linux/of.h> diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 407359da08f9..2283c869ad5d 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -23,7 +23,8 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/bitops.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/pci.h> @@ -58,16 +59,6 @@ struct gsta_gpio { unsigned irq_type[GSTA_NR_GPIO]; }; -static inline struct gsta_regs __iomem *__regs(struct gsta_gpio *chip, int nr) -{ - return chip->regs[nr / GSTA_GPIO_PER_BLOCK]; -} - -static inline u32 __bit(int nr) -{ - return 1U << (nr % GSTA_GPIO_PER_BLOCK); -} - /* * gpio methods */ @@ -75,8 +66,8 @@ static inline u32 __bit(int nr) static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); if (val) writel(bit, ®s->dats); @@ -87,8 +78,8 @@ static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); return !!(readl(®s->dat) & bit); } @@ -97,8 +88,8 @@ static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); writel(bit, ®s->dirs); /* Data register after direction, otherwise pullup/down is selected */ @@ -112,8 +103,8 @@ static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); writel(bit, ®s->dirc); return 0; @@ -165,9 +156,9 @@ static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */ */ static void gsta_set_config(struct gsta_gpio *chip, int nr, unsigned cfg) { - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; unsigned long flags; - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; int err = 0; @@ -234,8 +225,8 @@ static void gsta_irq_disable(struct irq_data *data) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); struct gsta_gpio *chip = gc->private; int nr = data->irq - chip->irq_base; - struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; unsigned long flags; @@ -257,8 +248,8 @@ static void gsta_irq_enable(struct irq_data *data) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); struct gsta_gpio *chip = gc->private; int nr = data->irq - chip->irq_base; - struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; int type; unsigned long flags; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 8d6a5a7e612d..65a2315f1673 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -8,7 +8,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/mfd/stmpe.h> diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index c07385b71403..19972084c45b 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -13,9 +13,8 @@ #include <linux/types.h> #include <linux/of_platform.h> #include <linux/mutex.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/io.h> -#include <linux/of_gpio.h> #include <linux/clk.h> #include <linux/err.h> @@ -91,6 +90,20 @@ struct xway_stp { }; /** + * xway_stp_get() - gpio_chip->get - get gpios. + * @gc: Pointer to gpio_chip device structure. + * @gpio: GPIO signal number. + * + * Gets the shadow value. + */ +static int xway_stp_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct xway_stp *chip = gpiochip_get_data(gc); + + return (xway_stp_r32(chip->virt, XWAY_STP_CPU0) & BIT(gpio)); +} + +/** * xway_stp_set() - gpio_chip->set - set gpios. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. @@ -215,6 +228,7 @@ static int xway_stp_probe(struct platform_device *pdev) chip->gc.parent = &pdev->dev; chip->gc.label = "stp-xway"; chip->gc.direction_output = xway_stp_dir_out; + chip->gc.get = xway_stp_get; chip->gc.set = xway_stp_set; chip->gc.request = xway_stp_request; chip->gc.base = -1; diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 8b0a69c5ba88..87c18a544513 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -10,7 +10,7 @@ */ #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> @@ -135,6 +135,33 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = { .dat_bit_offset = 0x40 * 8 + 8, }; +static void rockchip_gpio_set(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct syscon_gpio_priv *priv = gpiochip_get_data(chip); + unsigned int offs; + u8 bit; + u32 data; + int ret; + + offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; + bit = offs % SYSCON_REG_BITS; + data = (val ? BIT(bit) : 0) | BIT(bit + 16); + ret = regmap_write(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + data); + if (ret < 0) + dev_err(chip->parent, "gpio write failed ret(%d)\n", ret); +} + +static const struct syscon_gpio_data rockchip_rk3328_gpio_mute = { + /* RK3328 GPIO_MUTE is an output only pin at GRF_SOC_CON10[1] */ + .flags = GPIO_SYSCON_FEAT_OUT, + .bit_count = 1, + .dat_bit_offset = 0x0428 * 8 + 1, + .set = rockchip_gpio_set, +}; + #define KEYSTONE_LOCK_BIT BIT(0) static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val) @@ -175,6 +202,10 @@ static const struct of_device_id syscon_gpio_ids[] = { .compatible = "ti,keystone-dsp-gpio", .data = &keystone_dsp_gpio, }, + { + .compatible = "rockchip,rk3328-grf-gpio", + .data = &rockchip_rk3328_gpio_mute, + }, { } }; MODULE_DEVICE_TABLE(of, syscon_gpio_ids); diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index ac6f2a9841e5..a12cd0b5c972 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -22,7 +22,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/irq.h> #include <linux/irqdomain.h> @@ -30,7 +30,6 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/spinlock.h> #include <linux/bitops.h> #include <linux/pinctrl/consumer.h> diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 94396caaca75..47dbd19751d0 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -22,7 +22,7 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/module.h> @@ -207,7 +207,7 @@ static int tegra_gpio_get_direction(struct gpio_chip *chip, oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)); - return (oe & pin_mask) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; + return !(oe & pin_mask); } static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, @@ -323,13 +323,6 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - ret = gpiochip_lock_as_irq(&tgi->gc, gpio); - if (ret) { - dev_err(tgi->dev, - "unable to lock Tegra GPIO %u as IRQ\n", gpio); - return ret; - } - spin_lock_irqsave(&bank->lvl_lock[port], flags); val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio)); @@ -342,6 +335,14 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0); tegra_gpio_enable(tgi, gpio); + ret = gpiochip_lock_as_irq(&tgi->gc, gpio); + if (ret) { + dev_err(tgi->dev, + "unable to lock Tegra GPIO %u as IRQ\n", gpio); + tegra_gpio_disable(tgi, gpio); + return ret; + } + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) @@ -550,13 +551,6 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) }; -/* - * This lock class tells lockdep that GPIO irqs are in a different category - * than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; -static struct lock_class_key gpio_request_class; - static int tegra_gpio_probe(struct platform_device *pdev) { struct tegra_gpio_info *tgi; @@ -661,8 +655,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) bank = &tgi->bank_info[GPIO_BANK(gpio)]; - irq_set_lockdep_class(irq, &gpio_lock_class, - &gpio_request_class); irq_set_chip_data(irq, bank); irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq); } @@ -720,4 +712,4 @@ static int __init tegra_gpio_init(void) { return platform_driver_register(&tegra_gpio_driver); } -postcore_initcall(tegra_gpio_init); +subsys_initcall(tegra_gpio_init); diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 7f1aa4c21e0d..9d0292c8a199 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <dt-bindings/gpio/tegra186-gpio.h> +#include <dt-bindings/gpio/tegra194-gpio.h> #define TEGRA186_GPIO_ENABLE_CONFIG 0x00 #define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) @@ -593,6 +594,73 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .name = "tegra186-gpio-aon", }; +#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \ + [TEGRA194_MAIN_GPIO_PORT_##port] = { \ + .name = #port, \ + .offset = base, \ + .pins = count, \ + .irq = controller, \ + } + +static const struct tegra_gpio_port tegra194_main_ports[] = { + TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1), + TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4), + TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4), + TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4), + TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4), + TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4), + TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4), + TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4), + TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4), + TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5), + TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3), + TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3), + TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2), + TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2), + TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5), + TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2), + TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2), + TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2), + TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3), + TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3), + TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3), + TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1), + TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1), + TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2), + TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2), + TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2), + TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3), + TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0) +}; + +static const struct tegra_gpio_soc tegra194_main_soc = { + .num_ports = ARRAY_SIZE(tegra194_main_ports), + .ports = tegra194_main_ports, + .name = "tegra194-gpio", +}; + +#define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \ + [TEGRA194_AON_GPIO_PORT_##port] = { \ + .name = #port, \ + .offset = base, \ + .pins = count, \ + .irq = controller, \ + } + +static const struct tegra_gpio_port tegra194_aon_ports[] = { + TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0), + TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0), + TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0), + TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0), + TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0) +}; + +static const struct tegra_gpio_soc tegra194_aon_soc = { + .num_ports = ARRAY_SIZE(tegra194_aon_ports), + .ports = tegra194_aon_ports, + .name = "tegra194-gpio-aon", +}; + static const struct of_device_id tegra186_gpio_of_match[] = { { .compatible = "nvidia,tegra186-gpio", @@ -601,6 +669,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = { .compatible = "nvidia,tegra186-gpio-aon", .data = &tegra186_aon_soc }, { + .compatible = "nvidia,tegra194-gpio", + .data = &tegra194_main_soc + }, { + .compatible = "nvidia,tegra194-gpio-aon", + .data = &tegra194_aon_soc + }, { /* sentinel */ } }; diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 6520a8475910..314e300d6ba3 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -22,7 +22,7 @@ */ #include <linux/init.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/platform_device.h> #include <linux/irq.h> #include <linux/io.h> diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 58faeb1cef63..7fdac9060979 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -310,8 +310,7 @@ static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain, struct uniphier_gpio_priv *priv = domain->host_data; struct gpio_chip *chip = &priv->chip; - gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET); - return 0; + return gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET); } static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain, diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index ac8deb01f6f6..027699cec911 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -138,10 +138,16 @@ static void unmask_giuint_low(struct irq_data *d) static unsigned int startup_giuint(struct irq_data *data) { - if (gpiochip_lock_as_irq(&vr41xx_gpio_chip, data->hwirq)) + int ret; + + ret = gpiochip_lock_as_irq(&vr41xx_gpio_chip, irqd_to_hwirq(data)); + if (ret) { dev_err(vr41xx_gpio_chip.parent, "unable to lock HW IRQ %lu for IRQ\n", data->hwirq); + return ret; + } + /* Satisfy the .enable semantics by unmasking the line */ unmask_giuint_low(data); return 0; diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index acd59113e08b..2eb76f35aa7e 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -143,12 +143,14 @@ static int xgene_gpio_sb_domain_activate(struct irq_domain *d, { struct xgene_gpio_sb *priv = d->host_data; u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq); + int ret; - if (gpiochip_lock_as_irq(&priv->gc, gpio)) { + ret = gpiochip_lock_as_irq(&priv->gc, gpio); + if (ret) { dev_err(priv->gc.parent, "Unable to configure XGene GPIO standby pin %d as IRQ\n", gpio); - return -ENOSPC; + return ret; } xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO, diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index e8ec0e33a0a9..8f24478cc18b 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -20,7 +20,7 @@ #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> /* Register Offset Definitions */ diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index addd9fecc198..c48ed9d89ff5 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -389,7 +389,7 @@ EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, - struct acpi_reference_args *args, + struct fwnode_reference_args *args, unsigned int *quirks) { const struct acpi_gpio_mapping *gm; @@ -401,7 +401,7 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev, if (!strcmp(name, gm->name) && gm->data && index < gm->size) { const struct acpi_gpio_params *par = gm->data + index; - args->adev = adev; + args->fwnode = acpi_fwnode_handle(adev); args->args[0] = par->crs_entry_index; args->args[1] = par->line_index; args->args[2] = par->active_low; @@ -564,7 +564,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, const char *propname, int index, struct acpi_gpio_lookup *lookup) { - struct acpi_reference_args args; + struct fwnode_reference_args args; unsigned int quirks = 0; int ret; @@ -585,6 +585,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, * The property was found and resolved, so need to lookup the GPIO based * on returned args. */ + if (!to_acpi_device_node(args.fwnode)) + return -EINVAL; if (args.nargs != 3) return -EPROTO; @@ -592,8 +594,9 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, lookup->pin_index = args.args[1]; lookup->active_low = !!args.args[2]; - lookup->info.adev = args.adev; + lookup->info.adev = to_acpi_device_node(args.fwnode); lookup->info.quirks = quirks; + return 0; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 53a14ee8ad6d..a4f1157d6aa0 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -621,9 +621,6 @@ int of_gpiochip_add(struct gpio_chip *chip) { int status; - if ((!chip->of_node) && (chip->parent)) - chip->of_node = chip->parent->of_node; - if (!chip->of_node) return 0; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e11a3bb03820..e8f8a1999393 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -431,7 +431,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, int i; if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { - /* TODO: check if descriptors are really input */ + /* NOTE: It's ok to read values of output lines. */ int ret = gpiod_get_array_value_complex(false, true, lh->numdescs, @@ -449,7 +449,13 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, return 0; } else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) { - /* TODO: check if descriptors are really output */ + /* + * All line descriptors were created at once with the same + * flags so just check if the first one is really output. + */ + if (!test_bit(FLAG_IS_OUT, &lh->descs[0]->flags)) + return -EPERM; + if (copy_from_user(&ghd, ip, sizeof(ghd))) return -EFAULT; @@ -1256,6 +1262,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, /* If the gpiochip has an assigned OF node this takes precedence */ if (chip->of_node) gdev->dev.of_node = chip->of_node; + else + chip->of_node = gdev->dev.of_node; #endif gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL); @@ -1408,9 +1416,9 @@ err_free_descs: err_free_gdev: ida_simple_remove(&gpio_ida, gdev->id); /* failures here can mean systems won't boot... */ - pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, + pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__, gdev->base, gdev->base + gdev->ngpio - 1, - chip->label ? : "generic"); + chip->label ? : "generic", status); kfree(gdev); return status; } @@ -1664,8 +1672,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, if (parent_handler) { if (gpiochip->can_sleep) { chip_err(gpiochip, - "you cannot have chained interrupts on a " - "chip that may sleep\n"); + "you cannot have chained interrupts on a chip that may sleep\n"); return; } /* @@ -1800,16 +1807,18 @@ static const struct irq_domain_ops gpiochip_domain_ops = { static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + int ret; if (!try_module_get(chip->gpiodev->owner)) return -ENODEV; - if (gpiochip_lock_as_irq(chip, d->hwirq)) { + ret = gpiochip_lock_as_irq(chip, d->hwirq); + if (ret) { chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); module_put(chip->gpiodev->owner); - return -EINVAL; + return ret; } return 0; } @@ -1850,8 +1859,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, return 0; if (gpiochip->irq.parent_handler && gpiochip->can_sleep) { - chip_err(gpiochip, "you cannot have chained interrupts on a " - "chip that may sleep\n"); + chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); return -EINVAL; } @@ -2259,6 +2267,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) struct gpio_chip *chip = desc->gdev->chip; int status; unsigned long flags; + unsigned offset; spin_lock_irqsave(&gpio_lock, flags); @@ -2277,7 +2286,11 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (chip->request) { /* chip->request may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); - status = chip->request(chip, gpio_chip_hwgpio(desc)); + offset = gpio_chip_hwgpio(desc); + if (gpiochip_line_is_valid(chip, offset)) + status = chip->request(chip, offset); + else + status = -EINVAL; spin_lock_irqsave(&gpio_lock, flags); if (status < 0) { @@ -3194,6 +3207,19 @@ int gpiod_cansleep(const struct gpio_desc *desc) EXPORT_SYMBOL_GPL(gpiod_cansleep); /** + * gpiod_set_consumer_name() - set the consumer name for the descriptor + * @desc: gpio to set the consumer name on + * @name: the new consumer name + */ +void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) +{ + VALIDATE_DESC_VOID(desc); + /* Just overwrite whatever the previous name was */ + desc->label = name; +} +EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); + +/** * gpiod_to_irq() - return the IRQ corresponding to a GPIO * @desc: gpio whose IRQ will be returned (already requested) * @@ -3249,18 +3275,19 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) * behind our back */ if (!chip->can_sleep && chip->get_direction) { - int dir = chip->get_direction(chip, offset); + int dir = gpiod_get_direction(desc); - if (dir) - clear_bit(FLAG_IS_OUT, &desc->flags); - else - set_bit(FLAG_IS_OUT, &desc->flags); + if (dir < 0) { + chip_err(chip, "%s: cannot get GPIO direction\n", + __func__); + return dir; + } } if (test_bit(FLAG_IS_OUT, &desc->flags)) { chip_err(chip, - "%s: tried to flag a GPIO set as output for IRQ\n", - __func__); + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); return -EIO; } @@ -3639,9 +3666,16 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, chip = find_chip_by_name(p->chip_label); if (!chip) { - dev_err(dev, "cannot find GPIO chip %s\n", - p->chip_label); - return ERR_PTR(-ENODEV); + /* + * As the lookup table indicates a chip with + * p->chip_label should exist, assume it may + * still appear later and let the interested + * consumer be probed again or let the Deferred + * Probe infrastructure handle the error. + */ + dev_warn(dev, "cannot find GPIO chip %s, deferring\n", + p->chip_label); + return ERR_PTR(-EPROBE_DEFER); } if (chip->ngpio <= p->chip_hwnum) { @@ -4215,7 +4249,7 @@ static int __init gpiolib_dev_init(void) int ret; /* Register GPIO sysfs bus */ - ret = bus_register(&gpio_bus_type); + ret = bus_register(&gpio_bus_type); if (ret < 0) { pr_err("gpiolib: could not register GPIO bus type\n"); return ret; @@ -4259,9 +4293,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s", gpio, gdesc->name ? gdesc->name : "", gdesc->label, is_out ? "out" : "in ", - chip->get - ? (chip->get(chip, i) ? "hi" : "lo") - : "? ", + chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ", is_irq ? "IRQ" : " "); seq_printf(s, "\n"); } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 1a8e20363861..a7e49fef73d4 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -92,7 +92,7 @@ struct acpi_gpio_info { }; /* gpio suffixes used for ACPI and device tree lookup */ -static const char * const gpio_suffixes[] = { "gpios", "gpio" }; +static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; #ifdef CONFIG_OF_GPIO struct gpio_desc *of_find_gpio(struct device *dev, |