From 908334ab0be334cd268e2bf6a2384e7f5ffd4aa2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 13 Dec 2022 14:52:27 +0100 Subject: gpiolib: use irq_domain_alloc_irqs() Use the irq_domain_alloc_irqs() wrapper instead of the full __irq_domain_alloc_irqs() interface, which was only intended for some legacy (x86) use cases. Signed-off-by: Johan Hovold Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 939c776b9488..54baf074a830 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1126,14 +1126,8 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc, /* Just pick something */ fwspec.param[1] = IRQ_TYPE_EDGE_RISING; fwspec.param_count = 2; - ret = __irq_domain_alloc_irqs(gc->irq.domain, - /* just pick something */ - -1, - 1, - NUMA_NO_NODE, - &fwspec, - false, - NULL); + ret = irq_domain_alloc_irqs(gc->irq.domain, 1, + NUMA_NO_NODE, &fwspec); if (ret < 0) { chip_err(gc, "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", -- cgit v1.2.3 From 29f5c6e69f6198219c966acc91f99eb7f2669d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 12 Dec 2022 23:04:57 +0100 Subject: gpio: msc313: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Reviewed-by: Romain Perier Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-msc313.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c index 52d7b8d99170..b0773e5652fa 100644 --- a/drivers/gpio/gpio-msc313.c +++ b/drivers/gpio/gpio-msc313.c @@ -655,11 +655,6 @@ static int msc313_gpio_probe(struct platform_device *pdev) return devm_gpiochip_add_data(dev, gpiochip, gpio); } -static int msc313_gpio_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct of_device_id msc313_gpio_of_match[] = { #ifdef CONFIG_MACH_INFINITY { @@ -710,6 +705,5 @@ static struct platform_driver msc313_gpio_driver = { .pm = &msc313_gpio_ops, }, .probe = msc313_gpio_probe, - .remove = msc313_gpio_remove, }; builtin_platform_driver(msc313_gpio_driver); -- cgit v1.2.3 From b1453d1eb93fd34848082fd181ff247f19c0ee86 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Sun, 11 Dec 2022 00:05:59 +0200 Subject: gpio: pca953x: avoid logically dead code The current code logic make the condition "else if (reg >= 0x54)" can't be true, cause the dead code. So fix it to match the coder expectation. This is reported by Coverity. Fixes: 13c5d4ce8060 ("gpio: pca953x: Add support for PCAL6534") Signed-off-by: Haibo Chen Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5299e5bb76d6..2c8586b3191f 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -309,26 +309,26 @@ static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg, int bank; int offset; - if (reg >= 0x30) { + if (reg >= 0x54) { /* - * Reserved block between 14h and 2Fh does not align on - * expected bank boundaries like other devices. + * Handle lack of reserved registers after output port + * configuration register to form a bank. */ - int temp = reg - 0x30; + int temp = reg - 0x54; bank = temp / NBANK(chip); offset = temp - (bank * NBANK(chip)); - bank += 8; - } else if (reg >= 0x54) { + bank += 16; + } else if (reg >= 0x30) { /* - * Handle lack of reserved registers after output port - * configuration register to form a bank. + * Reserved block between 14h and 2Fh does not align on + * expected bank boundaries like other devices. */ - int temp = reg - 0x54; + int temp = reg - 0x30; bank = temp / NBANK(chip); offset = temp - (bank * NBANK(chip)); - bank += 16; + bank += 8; } else { bank = reg / NBANK(chip); offset = reg - (bank * NBANK(chip)); -- cgit v1.2.3 From a87f901b59326c12313dbf224cc4591ae2c63785 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 11 Dec 2022 00:06:00 +0200 Subject: gpio: pca953x: Clean up pcal6534_check_register() The pcal6534_check_register() is a bit too verbose. Clean up it, by deduplicating some operations and switching to the modulo operation as on some architectures / and % can become a single assembly instruction. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 2c8586b3191f..8aba8df393bd 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -306,6 +306,7 @@ static bool pca953x_check_register(struct pca953x_chip *chip, unsigned int reg, static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg, u32 checkbank) { + int bank_shift; int bank; int offset; @@ -314,26 +315,22 @@ static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg, * Handle lack of reserved registers after output port * configuration register to form a bank. */ - int temp = reg - 0x54; - - bank = temp / NBANK(chip); - offset = temp - (bank * NBANK(chip)); - bank += 16; + reg -= 0x54; + bank_shift = 16; } else if (reg >= 0x30) { /* * Reserved block between 14h and 2Fh does not align on * expected bank boundaries like other devices. */ - int temp = reg - 0x30; - - bank = temp / NBANK(chip); - offset = temp - (bank * NBANK(chip)); - bank += 8; + reg -= 0x30; + bank_shift = 8; } else { - bank = reg / NBANK(chip); - offset = reg - (bank * NBANK(chip)); + bank_shift = 0; } + bank = bank_shift + reg / NBANK(chip); + offset = reg % NBANK(chip); + /* Register is not in the matching bank. */ if (!(BIT(bank) & checkbank)) return false; -- cgit v1.2.3 From 9eeaa60ead4b6dc84cef012aa9aee3eb48dc4930 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 11 Dec 2022 00:06:01 +0200 Subject: gpio: pca953x: Remove unused PCAL953X_OUT_CONF from pcal6534_recalc_addr() First of all, PCAL953X_OUT_CONF is not used in the driver. Second, it's not a per-bank register, it's a single for the chip and should be handled differently anyway. To avoid confusion, drop PCAL953X_OUT_CONF from pcal6534_recalc_addr(). Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 8aba8df393bd..1286b22ef23a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -461,7 +461,6 @@ static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off) case PCAL953X_PULL_SEL: case PCAL953X_INT_MASK: case PCAL953X_INT_STAT: - case PCAL953X_OUT_CONF: pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x20; break; case PCAL6524_INT_EDGE: -- cgit v1.2.3 From 8978277c229b9502aba4654b1d6ec59c819e82ea Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:39 -0500 Subject: gpio: regmap: Always set gpio_chip get_direction If you only have reg_dat_base set, then it is input-only; if you only have reg_set_base set, then it is output-only. Thus, we can always set gpio_chip get_direction to gpio_regmap_get_direction and return GPIO_LINE_DIRECTION_IN/GPIO_LINE_DIRECTION_OUT given the respective register base addresses configuration. Reviewed-by: Andy Shevchenko Acked-by: Michael Walle Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-regmap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 6383136cbe59..f907c9c19fce 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -111,6 +111,11 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip, unsigned int base, val, reg, mask; int invert, ret; + if (gpio->reg_dat_base && !gpio->reg_set_base) + return GPIO_LINE_DIRECTION_IN; + if (gpio->reg_set_base && !gpio->reg_dat_base) + return GPIO_LINE_DIRECTION_OUT; + if (gpio->reg_dir_out_base) { base = gpio_regmap_addr(gpio->reg_dir_out_base); invert = 0; @@ -265,8 +270,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config else if (gpio->reg_set_base) chip->set = gpio_regmap_set; + chip->get_direction = gpio_regmap_get_direction; if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) { - chip->get_direction = gpio_regmap_get_direction; chip->direction_input = gpio_regmap_direction_input; chip->direction_output = gpio_regmap_direction_output; } -- cgit v1.2.3 From 2f7e845f512fdcdafdc922f23a91e560ef33ce4a Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:40 -0500 Subject: gpio: 104-dio-48e: Migrate to the regmap-irq API The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. For the 104-dio-48e we have the following IRQ registers (0xB and 0xF): Base Address +B (Write): Enable Interrupt Base Address +B (Read): Disable Interrupt Base Address +F (Read/Write): Clear Interrupt Any write to 0xB will enable interrupts, while any read will disable interrupts. Interrupts are cleared by a write to 0xF. There's no IRQ status register, so software has to assume that if an interrupt is raised then it was for the 104-DIO-48E device. Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 + drivers/gpio/gpio-104-dio-48e.c | 275 +++++++++++++++++++--------------------- 2 files changed, 135 insertions(+), 142 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ec7cfd4f52b1..2f8cb03bd975 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -845,6 +845,8 @@ config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" depends on PC104 select ISA_BUS_API + select REGMAP_MMIO + select REGMAP_IRQ select GPIOLIB_IRQCHIP select GPIO_I8255 help diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 7b8829c8e423..e053a4e46b27 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -8,17 +8,15 @@ */ #include #include -#include +#include #include -#include #include -#include -#include +#include #include #include #include #include -#include +#include #include #include "gpio-i8255.h" @@ -38,46 +36,30 @@ static unsigned int num_irq; module_param_hw_array(irq, uint, irq, &num_irq, 0); MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); +#define DIO48E_ENABLE_INTERRUPT 0xB +#define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT +#define DIO48E_CLEAR_INTERRUPT 0xF + #define DIO48E_NUM_PPI 2 /** * struct dio48e_reg - device register structure * @ppi: Programmable Peripheral Interface groups - * @enable_buffer: Enable/Disable Buffer groups - * @unused1: Unused - * @enable_interrupt: Write: Enable Interrupt - * Read: Disable Interrupt - * @unused2: Unused - * @enable_counter: Write: Enable Counter/Timer Addressing - * Read: Disable Counter/Timer Addressing - * @unused3: Unused - * @clear_interrupt: Clear Interrupt */ struct dio48e_reg { struct i8255 ppi[DIO48E_NUM_PPI]; - u8 enable_buffer[DIO48E_NUM_PPI]; - u8 unused1; - u8 enable_interrupt; - u8 unused2; - u8 enable_counter; - u8 unused3; - u8 clear_interrupt; }; /** * struct dio48e_gpio - GPIO device private data structure * @chip: instance of the gpio_chip * @ppi_state: PPI device states - * @lock: synchronization lock to prevent I/O race conditions * @reg: I/O address offset for the device registers - * @irq_mask: I/O bits affected by interrupts */ struct dio48e_gpio { struct gpio_chip chip; struct i8255_state ppi_state[DIO48E_NUM_PPI]; - raw_spinlock_t lock; struct dio48e_reg __iomem *reg; - unsigned char irq_mask; }; static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) @@ -144,106 +126,95 @@ static void dio48e_gpio_set_multiple(struct gpio_chip *chip, bits, chip->ngpio); } -static void dio48e_irq_ack(struct irq_data *data) -{ -} - -static void dio48e_irq_mask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned long offset = irqd_to_hwirq(data); - unsigned long flags; - - /* only bit 3 on each respective Port C supports interrupts */ - if (offset != 19 && offset != 43) - return; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - if (offset == 19) - dio48egpio->irq_mask &= ~BIT(0); - else - dio48egpio->irq_mask &= ~BIT(1); - gpiochip_disable_irq(chip, offset); - - if (!dio48egpio->irq_mask) - /* disable interrupts */ - ioread8(&dio48egpio->reg->enable_interrupt); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); -} - -static void dio48e_irq_unmask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned long offset = irqd_to_hwirq(data); - unsigned long flags; - - /* only bit 3 on each respective Port C supports interrupts */ - if (offset != 19 && offset != 43) - return; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); +static const struct regmap_range dio48e_wr_ranges[] = { + regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB), + regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_range dio48e_rd_ranges[] = { + regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x6), + regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), + regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_range dio48e_volatile_ranges[] = { + i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4), + regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), + regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_range dio48e_precious_ranges[] = { + regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), + regmap_reg_range(0xF, 0xF), +}; +static const struct regmap_access_table dio48e_wr_table = { + .yes_ranges = dio48e_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_wr_ranges), +}; +static const struct regmap_access_table dio48e_rd_table = { + .yes_ranges = dio48e_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_rd_ranges), +}; +static const struct regmap_access_table dio48e_volatile_table = { + .yes_ranges = dio48e_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_volatile_ranges), +}; +static const struct regmap_access_table dio48e_precious_table = { + .yes_ranges = dio48e_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(dio48e_precious_ranges), +}; +static const struct regmap_config dio48e_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0xF, + .wr_table = &dio48e_wr_table, + .rd_table = &dio48e_rd_table, + .volatile_table = &dio48e_volatile_table, + .precious_table = &dio48e_precious_table, + .cache_type = REGCACHE_FLAT, +}; - if (!dio48egpio->irq_mask) { - /* enable interrupts */ - iowrite8(0x00, &dio48egpio->reg->clear_interrupt); - iowrite8(0x00, &dio48egpio->reg->enable_interrupt); +/* only bit 3 on each respective Port C supports interrupts */ +#define DIO48E_REGMAP_IRQ(_ppi) \ + [19 + (_ppi) * 24] = { \ + .mask = BIT(_ppi), \ + .type = { .types_supported = IRQ_TYPE_EDGE_RISING }, \ } - gpiochip_enable_irq(chip, offset); - if (offset == 19) - dio48egpio->irq_mask |= BIT(0); - else - dio48egpio->irq_mask |= BIT(1); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); -} - -static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type) -{ - const unsigned long offset = irqd_to_hwirq(data); - - /* only bit 3 on each respective Port C supports interrupts */ - if (offset != 19 && offset != 43) - return -EINVAL; - - if (flow_type != IRQ_TYPE_NONE && flow_type != IRQ_TYPE_EDGE_RISING) - return -EINVAL; - - return 0; -} - -static const struct irq_chip dio48e_irqchip = { - .name = "104-dio-48e", - .irq_ack = dio48e_irq_ack, - .irq_mask = dio48e_irq_mask, - .irq_unmask = dio48e_irq_unmask, - .irq_set_type = dio48e_irq_set_type, - .flags = IRQCHIP_IMMUTABLE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, +static const struct regmap_irq dio48e_regmap_irqs[] = { + DIO48E_REGMAP_IRQ(0), DIO48E_REGMAP_IRQ(1), }; -static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) +static int dio48e_handle_mask_sync(struct regmap *const map, const int index, + const unsigned int mask_buf_def, + const unsigned int mask_buf, + void *const irq_drv_data) { - struct dio48e_gpio *const dio48egpio = dev_id; - struct gpio_chip *const chip = &dio48egpio->chip; - const unsigned long irq_mask = dio48egpio->irq_mask; - unsigned long gpio; + unsigned int *const irq_mask = irq_drv_data; + const unsigned int prev_mask = *irq_mask; + const unsigned int all_masked = GENMASK(1, 0); + int err; + unsigned int val; - for_each_set_bit(gpio, &irq_mask, 2) - generic_handle_domain_irq(chip->irq.domain, - 19 + gpio*24); + /* exit early if no change since the previous mask */ + if (mask_buf == prev_mask) + return 0; - raw_spin_lock(&dio48egpio->lock); + /* remember the current mask for the next mask sync */ + *irq_mask = mask_buf; - iowrite8(0x00, &dio48egpio->reg->clear_interrupt); + /* if all previously masked, enable interrupts when unmasking */ + if (prev_mask == all_masked) { + err = regmap_write(map, DIO48E_CLEAR_INTERRUPT, 0x00); + if (err) + return err; + return regmap_write(map, DIO48E_ENABLE_INTERRUPT, 0x00); + } - raw_spin_unlock(&dio48egpio->lock); + /* if all are currently masked, disable interrupts */ + if (mask_buf == all_masked) + return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val); - return IRQ_HANDLED; + return 0; } #define DIO48E_NGPIO 48 @@ -266,14 +237,12 @@ static const char *dio48e_names[DIO48E_NGPIO] = { "PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7" }; -static int dio48e_irq_init_hw(struct gpio_chip *gc) +static int dio48e_irq_init_hw(struct regmap *const map) { - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc); + unsigned int val; /* Disable IRQ by default */ - ioread8(&dio48egpio->reg->enable_interrupt); - - return 0; + return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val); } static void dio48e_init_ppi(struct i8255 __iomem *const ppi, @@ -295,8 +264,12 @@ static int dio48e_probe(struct device *dev, unsigned int id) { struct dio48e_gpio *dio48egpio; const char *const name = dev_name(dev); - struct gpio_irq_chip *girq; + void __iomem *regs; + struct regmap *map; int err; + struct regmap_irq_chip *chip; + unsigned int irq_mask; + struct regmap_irq_chip_data *chip_data; dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); if (!dio48egpio) @@ -308,10 +281,46 @@ static int dio48e_probe(struct device *dev, unsigned int id) return -EBUSY; } - dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT); - if (!dio48egpio->reg) + regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT); + if (!regs) + return -ENOMEM; + dio48egpio->reg = regs; + + map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "Unable to initialize register map\n"); + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->irq_drv_data = devm_kzalloc(dev, sizeof(irq_mask), GFP_KERNEL); + if (!chip->irq_drv_data) return -ENOMEM; + chip->name = name; + /* No IRQ status register so use CLEAR_INTERRUPT register instead */ + chip->status_base = DIO48E_CLEAR_INTERRUPT; + chip->mask_base = DIO48E_ENABLE_INTERRUPT; + chip->ack_base = DIO48E_CLEAR_INTERRUPT; + /* CLEAR_INTERRUPT doubles as status register so we need it cleared */ + chip->clear_ack = true; + chip->status_invert = true; + chip->num_regs = 1; + chip->irqs = dio48e_regmap_irqs; + chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs); + chip->handle_mask_sync = dio48e_handle_mask_sync; + + /* Initialize to prevent spurious interrupts before we're ready */ + err = dio48e_irq_init_hw(map); + if (err) + return err; + + err = devm_regmap_add_irq_chip(dev, map, irq[id], 0, 0, chip, &chip_data); + if (err) + return dev_err_probe(dev, err, "IRQ registration failed\n"); + dio48egpio->chip.label = name; dio48egpio->chip.parent = dev; dio48egpio->chip.owner = THIS_MODULE; @@ -326,18 +335,6 @@ static int dio48e_probe(struct device *dev, unsigned int id) dio48egpio->chip.set = dio48e_gpio_set; dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; - girq = &dio48egpio->chip.irq; - gpio_irq_chip_set_chip(girq, &dio48e_irqchip); - /* This will let us handle the parent IRQ in the driver */ - girq->parent_handler = NULL; - girq->num_parents = 0; - girq->parents = NULL; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_edge_irq; - girq->init_hw = dio48e_irq_init_hw; - - raw_spin_lock_init(&dio48egpio->lock); - i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI); dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state); @@ -347,14 +344,8 @@ static int dio48e_probe(struct device *dev, unsigned int id) return err; } - err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name, - dio48egpio); - if (err) { - dev_err(dev, "IRQ handler registering failed (%d)\n", err); - return err; - } - - return 0; + return gpiochip_irqchip_add_domain(&dio48egpio->chip, + regmap_irq_get_domain(chip_data)); } static struct isa_driver dio48e_driver = { -- cgit v1.2.3 From e28432a773651b753445b1aec927224664156d79 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:41 -0500 Subject: gpio: 104-idi-48: Migrate to the regmap-irq API The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. For the 104-idi-48, we get an IRQ register with some status information and basic masking, but it's broken down by banks rather than individual GPIO. There are six banks (8 GPIO lines each) that correspond to the lower six bits of the IRQ register (bits 0-5): Base Address + 7 (Read): IRQ Status Register/IRQ Clear Bit 0-5: Respective Bank IRQ Statuses Bit 6: IRQ Status (Active Low) Bit 7: IRQ Enable Status Base Address + 7 (Write): IRQ Enable/Disable Bit 0-5: Respective Bank IRQ Enable/Disable Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 + drivers/gpio/gpio-104-idi-48.c | 249 +++++++++++++++-------------------------- 2 files changed, 93 insertions(+), 158 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2f8cb03bd975..30f9e3f48559 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -872,6 +872,8 @@ config GPIO_104_IDI_48 tristate "ACCES 104-IDI-48 GPIO support" depends on PC104 select ISA_BUS_API + select REGMAP_MMIO + select REGMAP_IRQ select GPIOLIB_IRQCHIP select GPIO_I8255 help diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index c5e231fde1af..f936e3e0ff12 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -8,17 +8,16 @@ */ #include #include -#include +#include #include -#include -#include #include -#include +#include +#include #include #include #include #include -#include +#include #include #include "gpio-i8255.h" @@ -38,6 +37,9 @@ static unsigned int num_irq; module_param_hw_array(irq, uint, irq, &num_irq, 0); MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); +#define IDI48_IRQ_STATUS 0x7 +#define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS + /** * struct idi_48_reg - device register structure * @port0: Port 0 Inputs @@ -56,17 +58,11 @@ struct idi_48_reg { /** * struct idi_48_gpio - GPIO device private data structure * @chip: instance of the gpio_chip - * @lock: synchronization lock to prevent I/O race conditions - * @irq_mask: input bits affected by interrupts * @reg: I/O address offset for the device registers - * @cos_enb: Change-Of-State IRQ enable boundaries mask */ struct idi_48_gpio { struct gpio_chip chip; - spinlock_t lock; - unsigned char irq_mask[6]; struct idi_48_reg __iomem *reg; - unsigned char cos_enb; }; static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) @@ -98,125 +94,65 @@ static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, return 0; } -static void idi_48_irq_ack(struct irq_data *data) -{ -} - -static void idi_48_irq_mask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - const unsigned int offset = irqd_to_hwirq(data); - const unsigned long boundary = offset / 8; - const unsigned long mask = BIT(offset % 8); - unsigned long flags; - - spin_lock_irqsave(&idi48gpio->lock, flags); - - idi48gpio->irq_mask[boundary] &= ~mask; - gpiochip_disable_irq(chip, offset); - - /* Exit early if there are still input lines with IRQ unmasked */ - if (idi48gpio->irq_mask[boundary]) - goto exit; - - idi48gpio->cos_enb &= ~BIT(boundary); - - iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); - -exit: - spin_unlock_irqrestore(&idi48gpio->lock, flags); -} - -static void idi_48_irq_unmask(struct irq_data *data) -{ - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - const unsigned int offset = irqd_to_hwirq(data); - const unsigned long boundary = offset / 8; - const unsigned long mask = BIT(offset % 8); - unsigned int prev_irq_mask; - unsigned long flags; - - spin_lock_irqsave(&idi48gpio->lock, flags); - - prev_irq_mask = idi48gpio->irq_mask[boundary]; - - gpiochip_enable_irq(chip, offset); - idi48gpio->irq_mask[boundary] |= mask; - - /* Exit early if IRQ was already unmasked for this boundary */ - if (prev_irq_mask) - goto exit; - - idi48gpio->cos_enb |= BIT(boundary); - - iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); - -exit: - spin_unlock_irqrestore(&idi48gpio->lock, flags); -} - -static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type) -{ - /* The only valid irq types are none and both-edges */ - if (flow_type != IRQ_TYPE_NONE && - (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) - return -EINVAL; - - return 0; -} - -static const struct irq_chip idi_48_irqchip = { - .name = "104-idi-48", - .irq_ack = idi_48_irq_ack, - .irq_mask = idi_48_irq_mask, - .irq_unmask = idi_48_irq_unmask, - .irq_set_type = idi_48_irq_set_type, - .flags = IRQCHIP_IMMUTABLE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, +static const struct regmap_range idi_48_wr_ranges[] = { + regmap_reg_range(0x0, 0x6), +}; +static const struct regmap_range idi_48_rd_ranges[] = { + regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x7), +}; +static const struct regmap_range idi_48_precious_ranges[] = { + regmap_reg_range(0x7, 0x7), +}; +static const struct regmap_access_table idi_48_wr_table = { + .no_ranges = idi_48_wr_ranges, + .n_no_ranges = ARRAY_SIZE(idi_48_wr_ranges), +}; +static const struct regmap_access_table idi_48_rd_table = { + .yes_ranges = idi_48_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(idi_48_rd_ranges), +}; +static const struct regmap_access_table idi_48_precious_table = { + .yes_ranges = idi_48_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(idi_48_precious_ranges), +}; +static const struct regmap_config idi48_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0x6, + .wr_table = &idi_48_wr_table, + .rd_table = &idi_48_rd_table, + .precious_table = &idi_48_precious_table, }; -static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) -{ - struct idi_48_gpio *const idi48gpio = dev_id; - unsigned long cos_status; - unsigned long boundary; - unsigned long irq_mask; - unsigned long bit_num; - unsigned long gpio; - struct gpio_chip *const chip = &idi48gpio->chip; - - spin_lock(&idi48gpio->lock); - - cos_status = ioread8(&idi48gpio->reg->irq); - - /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */ - if (cos_status & BIT(6)) { - spin_unlock(&idi48gpio->lock); - return IRQ_NONE; - } - - /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */ - cos_status &= 0x3F; - - for_each_set_bit(boundary, &cos_status, 6) { - irq_mask = idi48gpio->irq_mask[boundary]; - - for_each_set_bit(bit_num, &irq_mask, 8) { - gpio = bit_num + boundary * 8; +#define IDI48_NGPIO 48 - generic_handle_domain_irq(chip->irq.domain, - gpio); - } +#define IDI48_REGMAP_IRQ(_id) \ + [_id] = { \ + .mask = BIT((_id) / 8), \ + .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \ } - spin_unlock(&idi48gpio->lock); - - return IRQ_HANDLED; -} +static const struct regmap_irq idi48_regmap_irqs[IDI48_NGPIO] = { + IDI48_REGMAP_IRQ(0), IDI48_REGMAP_IRQ(1), IDI48_REGMAP_IRQ(2), /* 0-2 */ + IDI48_REGMAP_IRQ(3), IDI48_REGMAP_IRQ(4), IDI48_REGMAP_IRQ(5), /* 3-5 */ + IDI48_REGMAP_IRQ(6), IDI48_REGMAP_IRQ(7), IDI48_REGMAP_IRQ(8), /* 6-8 */ + IDI48_REGMAP_IRQ(9), IDI48_REGMAP_IRQ(10), IDI48_REGMAP_IRQ(11), /* 9-11 */ + IDI48_REGMAP_IRQ(12), IDI48_REGMAP_IRQ(13), IDI48_REGMAP_IRQ(14), /* 12-14 */ + IDI48_REGMAP_IRQ(15), IDI48_REGMAP_IRQ(16), IDI48_REGMAP_IRQ(17), /* 15-17 */ + IDI48_REGMAP_IRQ(18), IDI48_REGMAP_IRQ(19), IDI48_REGMAP_IRQ(20), /* 18-20 */ + IDI48_REGMAP_IRQ(21), IDI48_REGMAP_IRQ(22), IDI48_REGMAP_IRQ(23), /* 21-23 */ + IDI48_REGMAP_IRQ(24), IDI48_REGMAP_IRQ(25), IDI48_REGMAP_IRQ(26), /* 24-26 */ + IDI48_REGMAP_IRQ(27), IDI48_REGMAP_IRQ(28), IDI48_REGMAP_IRQ(29), /* 27-29 */ + IDI48_REGMAP_IRQ(30), IDI48_REGMAP_IRQ(31), IDI48_REGMAP_IRQ(32), /* 30-32 */ + IDI48_REGMAP_IRQ(33), IDI48_REGMAP_IRQ(34), IDI48_REGMAP_IRQ(35), /* 33-35 */ + IDI48_REGMAP_IRQ(36), IDI48_REGMAP_IRQ(37), IDI48_REGMAP_IRQ(38), /* 36-38 */ + IDI48_REGMAP_IRQ(39), IDI48_REGMAP_IRQ(40), IDI48_REGMAP_IRQ(41), /* 39-41 */ + IDI48_REGMAP_IRQ(42), IDI48_REGMAP_IRQ(43), IDI48_REGMAP_IRQ(44), /* 42-44 */ + IDI48_REGMAP_IRQ(45), IDI48_REGMAP_IRQ(46), IDI48_REGMAP_IRQ(47), /* 45-47 */ +}; -#define IDI48_NGPIO 48 static const char *idi48_names[IDI48_NGPIO] = { "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A", "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A", @@ -228,22 +164,14 @@ static const char *idi48_names[IDI48_NGPIO] = { "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B" }; -static int idi_48_irq_init_hw(struct gpio_chip *gc) -{ - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc); - - /* Disable IRQ by default */ - iowrite8(0, &idi48gpio->reg->irq); - ioread8(&idi48gpio->reg->irq); - - return 0; -} - static int idi_48_probe(struct device *dev, unsigned int id) { struct idi_48_gpio *idi48gpio; const char *const name = dev_name(dev); - struct gpio_irq_chip *girq; + void __iomem *regs; + struct regmap *map; + struct regmap_irq_chip *chip; + struct regmap_irq_chip_data *chip_data; int err; idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL); @@ -256,9 +184,32 @@ static int idi_48_probe(struct device *dev, unsigned int id) return -EBUSY; } - idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT); - if (!idi48gpio->reg) + regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT); + if (!regs) return -ENOMEM; + idi48gpio->reg = regs; + + map = devm_regmap_init_mmio(dev, regs, &idi48_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "Unable to initialize register map\n"); + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->name = name; + chip->status_base = IDI48_IRQ_STATUS; + chip->unmask_base = IDI48_IRQ_ENABLE; + chip->clear_on_unmask = true; + chip->num_regs = 1; + chip->irqs = idi48_regmap_irqs; + chip->num_irqs = ARRAY_SIZE(idi48_regmap_irqs); + + err = devm_regmap_add_irq_chip(dev, map, irq[id], IRQF_SHARED, 0, chip, + &chip_data); + if (err) + return dev_err_probe(dev, err, "IRQ registration failed\n"); idi48gpio->chip.label = name; idi48gpio->chip.parent = dev; @@ -271,32 +222,14 @@ static int idi_48_probe(struct device *dev, unsigned int id) idi48gpio->chip.get = idi_48_gpio_get; idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple; - girq = &idi48gpio->chip.irq; - gpio_irq_chip_set_chip(girq, &idi_48_irqchip); - /* This will let us handle the parent IRQ in the driver */ - girq->parent_handler = NULL; - girq->num_parents = 0; - girq->parents = NULL; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_edge_irq; - girq->init_hw = idi_48_irq_init_hw; - - spin_lock_init(&idi48gpio->lock); - err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; } - err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED, - name, idi48gpio); - if (err) { - dev_err(dev, "IRQ handler registering failed (%d)\n", err); - return err; - } - - return 0; + return gpiochip_irqchip_add_domain(&idi48gpio->chip, + regmap_irq_get_domain(chip_data)); } static struct isa_driver idi_48_driver = { -- cgit v1.2.3 From 59e2131accfd1f4964c766fabdcd19419f1c551b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:42 -0500 Subject: gpio: 104-idi-48: Migrate to gpio-regmap API The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. Despite the underlying interface being based on i8255, it is simpler to use the gpio-regmap API directly because the 104-IDI-48 device features only input signals. Therefore, the dependence on the i8255 GPIO library is removed in this patch. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-104-idi-48.c | 97 +++++++++--------------------------------- 2 files changed, 21 insertions(+), 78 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 30f9e3f48559..84316924574f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -875,7 +875,7 @@ config GPIO_104_IDI_48 select REGMAP_MMIO select REGMAP_IRQ select GPIOLIB_IRQCHIP - select GPIO_I8255 + select GPIO_REGMAP help Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, 104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index f936e3e0ff12..ca2175b84e24 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -20,10 +20,6 @@ #include #include -#include "gpio-i8255.h" - -MODULE_IMPORT_NS(I8255); - #define IDI_48_EXTENT 8 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) @@ -40,56 +36,17 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); #define IDI48_IRQ_STATUS 0x7 #define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS -/** - * struct idi_48_reg - device register structure - * @port0: Port 0 Inputs - * @unused: Unused - * @port1: Port 1 Inputs - * @irq: Read: IRQ Status Register/IRQ Clear - * Write: IRQ Enable/Disable - */ -struct idi_48_reg { - u8 port0[3]; - u8 unused; - u8 port1[3]; - u8 irq; -}; - -/** - * struct idi_48_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @reg: I/O address offset for the device registers - */ -struct idi_48_gpio { - struct gpio_chip chip; - struct idi_48_reg __iomem *reg; -}; - -static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -{ - return GPIO_LINE_DIRECTION_IN; -} - -static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) { - return 0; -} - -static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - void __iomem *const ppi = idi48gpio->reg; + const unsigned int line = offset % 8; + const unsigned int stride = offset / 8; + const unsigned int port = (stride / 3) * 4; + const unsigned int port_stride = stride % 3; - return i8255_get(ppi, offset); -} - -static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - void __iomem *const ppi = idi48gpio->reg; - - i8255_get_multiple(ppi, mask, bits, chip->ngpio); + *reg = base + port + port_stride; + *mask = BIT(line); return 0; } @@ -166,18 +123,14 @@ static const char *idi48_names[IDI48_NGPIO] = { static int idi_48_probe(struct device *dev, unsigned int id) { - struct idi_48_gpio *idi48gpio; const char *const name = dev_name(dev); + struct gpio_regmap_config config = {}; void __iomem *regs; struct regmap *map; struct regmap_irq_chip *chip; struct regmap_irq_chip_data *chip_data; int err; - idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL); - if (!idi48gpio) - return -ENOMEM; - if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", base[id], base[id] + IDI_48_EXTENT); @@ -187,7 +140,6 @@ static int idi_48_probe(struct device *dev, unsigned int id) regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT); if (!regs) return -ENOMEM; - idi48gpio->reg = regs; map = devm_regmap_init_mmio(dev, regs, &idi48_regmap_config); if (IS_ERR(map)) @@ -211,25 +163,16 @@ static int idi_48_probe(struct device *dev, unsigned int id) if (err) return dev_err_probe(dev, err, "IRQ registration failed\n"); - idi48gpio->chip.label = name; - idi48gpio->chip.parent = dev; - idi48gpio->chip.owner = THIS_MODULE; - idi48gpio->chip.base = -1; - idi48gpio->chip.ngpio = IDI48_NGPIO; - idi48gpio->chip.names = idi48_names; - idi48gpio->chip.get_direction = idi_48_gpio_get_direction; - idi48gpio->chip.direction_input = idi_48_gpio_direction_input; - idi48gpio->chip.get = idi_48_gpio_get; - idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple; - - err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } + config.parent = dev; + config.regmap = map; + config.ngpio = IDI48_NGPIO; + config.names = idi48_names; + config.reg_dat_base = GPIO_REGMAP_ADDR(0x0); + config.ngpio_per_reg = 8; + config.reg_mask_xlate = idi_48_reg_mask_xlate; + config.irq_domain = regmap_irq_get_domain(chip_data); - return gpiochip_irqchip_add_domain(&idi48gpio->chip, - regmap_irq_get_domain(chip_data)); + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config)); } static struct isa_driver idi_48_driver = { -- cgit v1.2.3 From 0b7c490d7de3255ad1db82000b42f3f021f6dbf0 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:43 -0500 Subject: gpio: i8255: Migrate to gpio-regmap API The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. By leveraging the gpio-regmap API, the i8255 library is reduced to simply a devm_i8255_regmap_register() function, a configuration structure struct i8255_regmap_config, and a helper macro i8255_volatile_regmap_range() provided to simplify volatile PPI register hinting for the regmap. Legacy functions and code will be removed once all consumers have migrated to the new i8255 library interface. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-i8255.c | 119 +++++++++++++++++++++++++++++++++++++++++----- drivers/gpio/gpio-i8255.h | 28 +++++++++++ 3 files changed, 136 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 84316924574f..63acb9cb4c58 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -831,6 +831,7 @@ menu "Port-mapped I/O GPIO drivers" config GPIO_I8255 tristate + select GPIO_REGMAP help Enables support for the i8255 interface library functions. The i8255 interface library provides functions to facilitate communication with diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c index 9b97db418df1..9ecb2e9b97f9 100644 --- a/drivers/gpio/gpio-i8255.c +++ b/drivers/gpio/gpio-i8255.c @@ -4,23 +4,31 @@ * Copyright (C) 2022 William Breathitt Gray */ #include +#include #include #include +#include #include #include +#include #include #include #include "gpio-i8255.h" +#define I8255_NGPIO 24 +#define I8255_NGPIO_PER_REG 8 #define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0) #define I8255_CONTROL_PORTB_DIRECTION BIT(1) #define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3) #define I8255_CONTROL_PORTA_DIRECTION BIT(4) #define I8255_CONTROL_MODE_SET BIT(7) -#define I8255_PORTA 0 -#define I8255_PORTB 1 -#define I8255_PORTC 2 +#define I8255_PORTA 0x0 +#define I8255_PORTB 0x1 +#define I8255_PORTC 0x2 +#define I8255_CONTROL 0x3 +#define I8255_REG_DAT_BASE I8255_PORTA +#define I8255_REG_DIR_IN_BASE I8255_CONTROL static int i8255_get_port(struct i8255 __iomem *const ppi, const unsigned long io_port, const unsigned long mask) @@ -31,20 +39,19 @@ static int i8255_get_port(struct i8255 __iomem *const ppi, return ioread8(&ppi[bank].port[ppi_port]) & mask; } -static u8 i8255_direction_mask(const unsigned long offset) +static int i8255_direction_mask(const unsigned int offset) { - const unsigned long port_offset = offset % 8; - const unsigned long io_port = offset / 8; - const unsigned long ppi_port = io_port % 3; + const unsigned int stride = offset / I8255_NGPIO_PER_REG; + const unsigned int line = offset % I8255_NGPIO_PER_REG; - switch (ppi_port) { + switch (stride) { case I8255_PORTA: return I8255_CONTROL_PORTA_DIRECTION; case I8255_PORTB: return I8255_CONTROL_PORTB_DIRECTION; case I8255_PORTC: /* Port C can be configured by nibble */ - if (port_offset >= 4) + if (line >= 4) return I8255_CONTROL_PORTC_UPPER_DIRECTION; return I8255_CONTROL_PORTC_LOWER_DIRECTION; default: @@ -53,6 +60,49 @@ static u8 i8255_direction_mask(const unsigned long offset) } } +static int i8255_ppi_init(struct regmap *const map, const unsigned int base) +{ + int err; + + /* Configure all ports to MODE 0 output mode */ + err = regmap_write(map, base + I8255_CONTROL, I8255_CONTROL_MODE_SET); + if (err) + return err; + + /* Initialize all GPIO to output 0 */ + err = regmap_write(map, base + I8255_PORTA, 0x00); + if (err) + return err; + err = regmap_write(map, base + I8255_PORTB, 0x00); + if (err) + return err; + return regmap_write(map, base + I8255_PORTC, 0x00); +} + +static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) +{ + const unsigned int ppi = offset / I8255_NGPIO; + const unsigned int ppi_offset = offset % I8255_NGPIO; + const unsigned int stride = ppi_offset / I8255_NGPIO_PER_REG; + const unsigned int line = ppi_offset % I8255_NGPIO_PER_REG; + + switch (base) { + case I8255_REG_DAT_BASE: + *reg = base + stride + ppi * 4; + *mask = BIT(line); + return 0; + case I8255_REG_DIR_IN_BASE: + *reg = base + ppi * 4; + *mask = i8255_direction_mask(ppi_offset); + return 0; + default: + /* Should never reach this path */ + return -EINVAL; + } +} + static void i8255_set_port(struct i8255 __iomem *const ppi, struct i8255_state *const state, const unsigned long io_port, @@ -93,7 +143,7 @@ void i8255_direction_input(struct i8255 __iomem *const ppi, spin_lock_irqsave(&state[bank].lock, flags); state[bank].control_state |= I8255_CONTROL_MODE_SET; - state[bank].control_state |= i8255_direction_mask(offset); + state[bank].control_state |= i8255_direction_mask(offset % 24); iowrite8(state[bank].control_state, &ppi[bank].control); @@ -125,7 +175,7 @@ void i8255_direction_output(struct i8255 __iomem *const ppi, spin_lock_irqsave(&state[bank].lock, flags); state[bank].control_state |= I8255_CONTROL_MODE_SET; - state[bank].control_state &= ~i8255_direction_mask(offset); + state[bank].control_state &= ~i8255_direction_mask(offset % 24); iowrite8(state[bank].control_state, &ppi[bank].control); @@ -165,7 +215,7 @@ int i8255_get_direction(const struct i8255_state *const state, const unsigned long io_port = offset / 8; const unsigned long bank = io_port / 3; - return !!(state[bank].control_state & i8255_direction_mask(offset)); + return !!(state[bank].control_state & i8255_direction_mask(offset % 24)); } EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255); @@ -282,6 +332,51 @@ void i8255_state_init(struct i8255_state *const state, } EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255); +/** + * devm_i8255_regmap_register - Register an i8255 GPIO controller + * @dev: device that is registering this i8255 GPIO device + * @config: configuration for i8255_regmap_config + * + * Registers an Intel 8255 Programmable Peripheral Interface GPIO controller. + * Returns 0 on success and negative error number on failure. + */ +int devm_i8255_regmap_register(struct device *const dev, + const struct i8255_regmap_config *const config) +{ + struct gpio_regmap_config gpio_config = {0}; + unsigned long i; + int err; + + if (!config->parent) + return -EINVAL; + + if (!config->map) + return -EINVAL; + + if (!config->num_ppi) + return -EINVAL; + + for (i = 0; i < config->num_ppi; i++) { + err = i8255_ppi_init(config->map, i * 4); + if (err) + return err; + } + + gpio_config.parent = config->parent; + gpio_config.regmap = config->map; + gpio_config.ngpio = I8255_NGPIO * config->num_ppi; + gpio_config.names = config->names; + gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE); + gpio_config.reg_set_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE); + gpio_config.reg_dir_in_base = GPIO_REGMAP_ADDR(I8255_REG_DIR_IN_BASE); + gpio_config.ngpio_per_reg = I8255_NGPIO_PER_REG; + gpio_config.irq_domain = config->domain; + gpio_config.reg_mask_xlate = i8255_reg_mask_xlate; + + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); +} +EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, I8255); + MODULE_AUTHOR("William Breathitt Gray"); MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h index d9084aae9446..3daa0b145890 100644 --- a/drivers/gpio/gpio-i8255.h +++ b/drivers/gpio/gpio-i8255.h @@ -26,6 +26,34 @@ struct i8255_state { u8 control_state; }; +struct device; +struct irq_domain; +struct regmap; + +#define i8255_volatile_regmap_range(_base) regmap_reg_range(_base, _base + 0x2) + +/** + * struct i8255_regmap_config - Configuration for the register map of an i8255 + * @parent: parent device + * @map: regmap for the i8255 + * @num_ppi: number of i8255 Programmable Peripheral Interface + * @names: (optional) array of names for gpios + * @domain: (optional) IRQ domain if the controller is interrupt-capable + * + * Note: The regmap is expected to have cache enabled and i8255 control + * registers not marked as volatile. + */ +struct i8255_regmap_config { + struct device *parent; + struct regmap *map; + int num_ppi; + const char *const *names; + struct irq_domain *domain; +}; + +int devm_i8255_regmap_register(struct device *dev, + const struct i8255_regmap_config *config); + void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state, unsigned long offset); void i8255_direction_output(struct i8255 __iomem *ppi, -- cgit v1.2.3 From 0b4243406897d819daddc06f5efc793f84d3824c Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:44 -0500 Subject: gpio: 104-dio-48e: Migrate to regmap API The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. The 104-dio-48e module is migrated to the new i8255 library interface leveraging the gpio-regmap API. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-104-dio-48e.c | 137 ++-------------------------------------- 1 file changed, 7 insertions(+), 130 deletions(-) diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index e053a4e46b27..a3846faf3780 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -42,90 +41,6 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); #define DIO48E_NUM_PPI 2 -/** - * struct dio48e_reg - device register structure - * @ppi: Programmable Peripheral Interface groups - */ -struct dio48e_reg { - struct i8255 ppi[DIO48E_NUM_PPI]; -}; - -/** - * struct dio48e_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @ppi_state: PPI device states - * @reg: I/O address offset for the device registers - */ -struct dio48e_gpio { - struct gpio_chip chip; - struct i8255_state ppi_state[DIO48E_NUM_PPI]; - struct dio48e_reg __iomem *reg; -}; - -static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - if (i8255_get_direction(dio48egpio->ppi_state, offset)) - return GPIO_LINE_DIRECTION_IN; - - return GPIO_LINE_DIRECTION_OUT; -} - -static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state, - offset); - - return 0; -} - -static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state, - offset, value); - - return 0; -} - -static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - return i8255_get(dio48egpio->reg->ppi, offset); -} - -static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio); - - return 0; -} - -static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value); -} - -static void dio48e_gpio_set_multiple(struct gpio_chip *chip, - unsigned long *mask, unsigned long *bits) -{ - struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - - i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask, - bits, chip->ngpio); -} - static const struct regmap_range dio48e_wr_ranges[] = { regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF), @@ -245,25 +160,10 @@ static int dio48e_irq_init_hw(struct regmap *const map) return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val); } -static void dio48e_init_ppi(struct i8255 __iomem *const ppi, - struct i8255_state *const ppi_state) -{ - const unsigned long ngpio = 24; - const unsigned long mask = GENMASK(ngpio - 1, 0); - const unsigned long bits = 0; - unsigned long i; - - /* Initialize all GPIO to output 0 */ - for (i = 0; i < DIO48E_NUM_PPI; i++) { - i8255_mode0_output(&ppi[i]); - i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); - } -} - static int dio48e_probe(struct device *dev, unsigned int id) { - struct dio48e_gpio *dio48egpio; const char *const name = dev_name(dev); + struct i8255_regmap_config config = {}; void __iomem *regs; struct regmap *map; int err; @@ -271,10 +171,6 @@ static int dio48e_probe(struct device *dev, unsigned int id) unsigned int irq_mask; struct regmap_irq_chip_data *chip_data; - dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); - if (!dio48egpio) - return -ENOMEM; - if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", base[id], base[id] + DIO48E_EXTENT); @@ -284,7 +180,6 @@ static int dio48e_probe(struct device *dev, unsigned int id) regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT); if (!regs) return -ENOMEM; - dio48egpio->reg = regs; map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config); if (IS_ERR(map)) @@ -321,31 +216,13 @@ static int dio48e_probe(struct device *dev, unsigned int id) if (err) return dev_err_probe(dev, err, "IRQ registration failed\n"); - dio48egpio->chip.label = name; - dio48egpio->chip.parent = dev; - dio48egpio->chip.owner = THIS_MODULE; - dio48egpio->chip.base = -1; - dio48egpio->chip.ngpio = DIO48E_NGPIO; - dio48egpio->chip.names = dio48e_names; - dio48egpio->chip.get_direction = dio48e_gpio_get_direction; - dio48egpio->chip.direction_input = dio48e_gpio_direction_input; - dio48egpio->chip.direction_output = dio48e_gpio_direction_output; - dio48egpio->chip.get = dio48e_gpio_get; - dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple; - dio48egpio->chip.set = dio48e_gpio_set; - dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; - - i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI); - dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state); - - err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } + config.parent = dev; + config.map = map; + config.num_ppi = DIO48E_NUM_PPI; + config.names = dio48e_names; + config.domain = regmap_irq_get_domain(chip_data); - return gpiochip_irqchip_add_domain(&dio48egpio->chip, - regmap_irq_get_domain(chip_data)); + return devm_i8255_regmap_register(dev, &config); } static struct isa_driver dio48e_driver = { -- cgit v1.2.3 From 1c05004f99af222fc1bf3eb7fab817efbb1da4d6 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:45 -0500 Subject: gpio: gpio-mm: Migrate to regmap API The regmap API supports IO port accessors so we can take advantage of regmap abstractions rather than handling access to the device registers directly in the driver. The gpio-mm module is migrated to the new i8255 library interface leveraging the gpio-regmap API. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-gpio-mm.c | 154 +++++++++----------------------------------- 2 files changed, 31 insertions(+), 124 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 63acb9cb4c58..525b911b4ac7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -898,6 +898,7 @@ config GPIO_GPIO_MM tristate "Diamond Systems GPIO-MM GPIO support" depends on PC104 select ISA_BUS_API + select REGMAP_MMIO select GPIO_I8255 help Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 2689671b6b01..43d823a56e59 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -8,13 +8,13 @@ */ #include #include -#include -#include #include #include #include #include #include +#include +#include #include "gpio-i8255.h" @@ -30,83 +30,22 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); #define GPIOMM_NUM_PPI 2 -/** - * struct gpiomm_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @ppi_state: Programmable Peripheral Interface group states - * @ppi: Programmable Peripheral Interface groups - */ -struct gpiomm_gpio { - struct gpio_chip chip; - struct i8255_state ppi_state[GPIOMM_NUM_PPI]; - struct i8255 __iomem *ppi; +static const struct regmap_range gpiomm_volatile_ranges[] = { + i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4), +}; +static const struct regmap_access_table gpiomm_volatile_table = { + .yes_ranges = gpiomm_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(gpiomm_volatile_ranges), +}; +static const struct regmap_config gpiomm_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0x7, + .volatile_table = &gpiomm_volatile_table, + .cache_type = REGCACHE_FLAT, }; - -static int gpiomm_gpio_get_direction(struct gpio_chip *chip, - unsigned int offset) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - if (i8255_get_direction(gpiommgpio->ppi_state, offset)) - return GPIO_LINE_DIRECTION_IN; - - return GPIO_LINE_DIRECTION_OUT; -} - -static int gpiomm_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset); - - return 0; -} - -static int gpiomm_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, - value); - - return 0; -} - -static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - return i8255_get(gpiommgpio->ppi, offset); -} - -static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio); - - return 0; -} - -static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value); -} - -static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, - unsigned long *mask, unsigned long *bits) -{ - struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - - i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits, - chip->ngpio); -} #define GPIOMM_NGPIO 48 static const char *gpiomm_names[GPIOMM_NGPIO] = { @@ -120,30 +59,11 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = { "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7", }; -static void gpiomm_init_dio(struct i8255 __iomem *const ppi, - struct i8255_state *const ppi_state) -{ - const unsigned long ngpio = 24; - const unsigned long mask = GENMASK(ngpio - 1, 0); - const unsigned long bits = 0; - unsigned long i; - - /* Initialize all GPIO to output 0 */ - for (i = 0; i < GPIOMM_NUM_PPI; i++) { - i8255_mode0_output(&ppi[i]); - i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); - } -} - static int gpiomm_probe(struct device *dev, unsigned int id) { - struct gpiomm_gpio *gpiommgpio; const char *const name = dev_name(dev); - int err; - - gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); - if (!gpiommgpio) - return -ENOMEM; + struct i8255_regmap_config config = {}; + void __iomem *regs; if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -151,34 +71,20 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return -EBUSY; } - gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); - if (!gpiommgpio->ppi) + regs = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); + if (!regs) return -ENOMEM; - gpiommgpio->chip.label = name; - gpiommgpio->chip.parent = dev; - gpiommgpio->chip.owner = THIS_MODULE; - gpiommgpio->chip.base = -1; - gpiommgpio->chip.ngpio = GPIOMM_NGPIO; - gpiommgpio->chip.names = gpiomm_names; - gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; - gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; - gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; - gpiommgpio->chip.get = gpiomm_gpio_get; - gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple; - gpiommgpio->chip.set = gpiomm_gpio_set; - gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; - - i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI); - gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state); - - err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } + config.map = devm_regmap_init_mmio(dev, regs, &gpiomm_regmap_config); + if (IS_ERR(config.map)) + return dev_err_probe(dev, PTR_ERR(config.map), + "Unable to initialize register map\n"); + + config.parent = dev; + config.num_ppi = GPIOMM_NUM_PPI; + config.names = gpiomm_names; - return 0; + return devm_i8255_regmap_register(dev, &config); } static struct isa_driver gpiomm_driver = { -- cgit v1.2.3 From 6ecb741e349a909bc4c0430867d2e21bec56714e Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 27 Dec 2022 09:09:46 -0500 Subject: gpio: i8255: Remove unused legacy interface All i8255 library consumers have migrated to the new interface leveraging the gpio-regmap API. Legacy interface functions and code are removed as no longer needed. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-i8255.c | 243 +--------------------------------------------- drivers/gpio/gpio-i8255.h | 40 -------- 2 files changed, 1 insertion(+), 282 deletions(-) diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c index 9ecb2e9b97f9..64ab80fc4a1e 100644 --- a/drivers/gpio/gpio-i8255.c +++ b/drivers/gpio/gpio-i8255.c @@ -3,16 +3,13 @@ * Intel 8255 Programmable Peripheral Interface * Copyright (C) 2022 William Breathitt Gray */ -#include +#include #include #include #include #include -#include #include #include -#include -#include #include "gpio-i8255.h" @@ -30,15 +27,6 @@ #define I8255_REG_DAT_BASE I8255_PORTA #define I8255_REG_DIR_IN_BASE I8255_CONTROL -static int i8255_get_port(struct i8255 __iomem *const ppi, - const unsigned long io_port, const unsigned long mask) -{ - const unsigned long bank = io_port / 3; - const unsigned long ppi_port = io_port % 3; - - return ioread8(&ppi[bank].port[ppi_port]) & mask; -} - static int i8255_direction_mask(const unsigned int offset) { const unsigned int stride = offset / I8255_NGPIO_PER_REG; @@ -103,235 +91,6 @@ static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, } } -static void i8255_set_port(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long io_port, - const unsigned long mask, const unsigned long bits) -{ - const unsigned long bank = io_port / 3; - const unsigned long ppi_port = io_port % 3; - unsigned long flags; - unsigned long out_state; - - spin_lock_irqsave(&state[bank].lock, flags); - - out_state = ioread8(&ppi[bank].port[ppi_port]); - out_state = (out_state & ~mask) | (bits & mask); - iowrite8(out_state, &ppi[bank].port[ppi_port]); - - spin_unlock_irqrestore(&state[bank].lock, flags); -} - -/** - * i8255_direction_input - configure signal offset as input - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @offset: signal offset to configure as input - * - * Configures a signal @offset as input for the respective Intel 8255 - * Programmable Peripheral Interface (@ppi) banks. The @state control_state - * values are updated to reflect the new configuration. - */ -void i8255_direction_input(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long offset) -{ - const unsigned long io_port = offset / 8; - const unsigned long bank = io_port / 3; - unsigned long flags; - - spin_lock_irqsave(&state[bank].lock, flags); - - state[bank].control_state |= I8255_CONTROL_MODE_SET; - state[bank].control_state |= i8255_direction_mask(offset % 24); - - iowrite8(state[bank].control_state, &ppi[bank].control); - - spin_unlock_irqrestore(&state[bank].lock, flags); -} -EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255); - -/** - * i8255_direction_output - configure signal offset as output - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @offset: signal offset to configure as output - * @value: signal value to output - * - * Configures a signal @offset as output for the respective Intel 8255 - * Programmable Peripheral Interface (@ppi) banks and sets the respective signal - * output to the desired @value. The @state control_state values are updated to - * reflect the new configuration. - */ -void i8255_direction_output(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long offset, - const unsigned long value) -{ - const unsigned long io_port = offset / 8; - const unsigned long bank = io_port / 3; - unsigned long flags; - - spin_lock_irqsave(&state[bank].lock, flags); - - state[bank].control_state |= I8255_CONTROL_MODE_SET; - state[bank].control_state &= ~i8255_direction_mask(offset % 24); - - iowrite8(state[bank].control_state, &ppi[bank].control); - - spin_unlock_irqrestore(&state[bank].lock, flags); - - i8255_set(ppi, state, offset, value); -} -EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255); - -/** - * i8255_get - get signal value at signal offset - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @offset: offset of signal to get - * - * Returns the signal value (0=low, 1=high) for the signal at @offset for the - * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. - */ -int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset) -{ - const unsigned long io_port = offset / 8; - const unsigned long offset_mask = BIT(offset % 8); - - return !!i8255_get_port(ppi, io_port, offset_mask); -} -EXPORT_SYMBOL_NS_GPL(i8255_get, I8255); - -/** - * i8255_get_direction - get the I/O direction for a signal offset - * @state: devices states of the respective PPI banks - * @offset: offset of signal to get direction - * - * Returns the signal direction (0=output, 1=input) for the signal at @offset. - */ -int i8255_get_direction(const struct i8255_state *const state, - const unsigned long offset) -{ - const unsigned long io_port = offset / 8; - const unsigned long bank = io_port / 3; - - return !!(state[bank].control_state & i8255_direction_mask(offset % 24)); -} -EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255); - -/** - * i8255_get_multiple - get multiple signal values at multiple signal offsets - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @mask: mask of signals to get - * @bits: bitmap to store signal values - * @ngpio: number of GPIO signals of the respective PPI banks - * - * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask - * for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. - */ -void i8255_get_multiple(struct i8255 __iomem *const ppi, - const unsigned long *const mask, - unsigned long *const bits, const unsigned long ngpio) -{ - unsigned long offset; - unsigned long port_mask; - unsigned long io_port; - unsigned long port_state; - - bitmap_zero(bits, ngpio); - - for_each_set_clump8(offset, port_mask, mask, ngpio) { - io_port = offset / 8; - port_state = i8255_get_port(ppi, io_port, port_mask); - - bitmap_set_value8(bits, port_state, offset); - } -} -EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255); - -/** - * i8255_mode0_output - configure all PPI ports to MODE 0 output mode - * @ppi: Intel 8255 Programmable Peripheral Interface bank - * - * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to - * MODE 0 (Basic Input/Output) output mode. - */ -void i8255_mode0_output(struct i8255 __iomem *const ppi) -{ - iowrite8(I8255_CONTROL_MODE_SET, &ppi->control); -} -EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255); - -/** - * i8255_set - set signal value at signal offset - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @offset: offset of signal to set - * @value: value of signal to set - * - * Assigns output @value for the signal at @offset for the respective Intel 8255 - * Programmable Peripheral Interface (@ppi) banks. - */ -void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state, - const unsigned long offset, const unsigned long value) -{ - const unsigned long io_port = offset / 8; - const unsigned long port_offset = offset % 8; - const unsigned long mask = BIT(port_offset); - const unsigned long bits = value << port_offset; - - i8255_set_port(ppi, state, io_port, mask, bits); -} -EXPORT_SYMBOL_NS_GPL(i8255_set, I8255); - -/** - * i8255_set_multiple - set signal values at multiple signal offsets - * @ppi: Intel 8255 Programmable Peripheral Interface banks - * @state: devices states of the respective PPI banks - * @mask: mask of signals to set - * @bits: bitmap of signal output values - * @ngpio: number of GPIO signals of the respective PPI banks - * - * Assigns output values defined by @bits for the signals defined by @mask for - * the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. - */ -void i8255_set_multiple(struct i8255 __iomem *const ppi, - struct i8255_state *const state, - const unsigned long *const mask, - const unsigned long *const bits, - const unsigned long ngpio) -{ - unsigned long offset; - unsigned long port_mask; - unsigned long io_port; - unsigned long value; - - for_each_set_clump8(offset, port_mask, mask, ngpio) { - io_port = offset / 8; - value = bitmap_get_value8(bits, offset); - i8255_set_port(ppi, state, io_port, port_mask, value); - } -} -EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255); - -/** - * i8255_state_init - initialize i8255_state structure - * @state: devices states of the respective PPI banks - * @nbanks: number of Intel 8255 Programmable Peripheral Interface banks - * - * Initializes the @state of each Intel 8255 Programmable Peripheral Interface - * bank for use in i8255 library functions. - */ -void i8255_state_init(struct i8255_state *const state, - const unsigned long nbanks) -{ - unsigned long bank; - - for (bank = 0; bank < nbanks; bank++) - spin_lock_init(&state[bank].lock); -} -EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255); - /** * devm_i8255_regmap_register - Register an i8255 GPIO controller * @dev: device that is registering this i8255 GPIO device diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h index 3daa0b145890..9dcf639b94df 100644 --- a/drivers/gpio/gpio-i8255.h +++ b/drivers/gpio/gpio-i8255.h @@ -3,29 +3,6 @@ #ifndef _I8255_H_ #define _I8255_H_ -#include -#include - -/** - * struct i8255 - Intel 8255 register structure - * @port: Port A, B, and C - * @control: Control register - */ -struct i8255 { - u8 port[3]; - u8 control; -}; - -/** - * struct i8255_state - Intel 8255 state structure - * @lock: synchronization lock for accessing device state - * @control_state: Control register state - */ -struct i8255_state { - spinlock_t lock; - u8 control_state; -}; - struct device; struct irq_domain; struct regmap; @@ -54,21 +31,4 @@ struct i8255_regmap_config { int devm_i8255_regmap_register(struct device *dev, const struct i8255_regmap_config *config); -void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state, - unsigned long offset); -void i8255_direction_output(struct i8255 __iomem *ppi, - struct i8255_state *state, unsigned long offset, - unsigned long value); -int i8255_get(struct i8255 __iomem *ppi, unsigned long offset); -int i8255_get_direction(const struct i8255_state *state, unsigned long offset); -void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask, - unsigned long *bits, unsigned long ngpio); -void i8255_mode0_output(struct i8255 __iomem *const ppi); -void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state, - unsigned long offset, unsigned long value); -void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state, - const unsigned long *mask, const unsigned long *bits, - unsigned long ngpio); -void i8255_state_init(struct i8255_state *const state, unsigned long nbanks); - #endif /* _I8255_H_ */ -- cgit v1.2.3 From 1da5aa27bec5defc4f4550edce4b41f80e7accd1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 9 Dec 2022 11:16:28 -0600 Subject: dt-bindings: gpio: Convert Fujitsu MB86S7x GPIO to DT schema Convert the Fujitsu MB86S7x GPIO binding to DT schema format. The "socionext,synquacer-gpio" compatible was not documented, but is compatible with "fujitsu,mb86s70-gpio" and is in use (in u-boot Synquacer dts). Signed-off-by: Rob Herring Acked-by: Jassi Brar Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- .../bindings/gpio/fujitsu,mb86s70-gpio.txt | 20 --------- .../bindings/gpio/fujitsu,mb86s70-gpio.yaml | 50 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt create mode 100644 Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt deleted file mode 100644 index bef353f370d8..000000000000 --- a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt +++ /dev/null @@ -1,20 +0,0 @@ -Fujitsu MB86S7x GPIO Controller -------------------------------- - -Required properties: -- compatible: Should be "fujitsu,mb86s70-gpio" -- reg: Base address and length of register space -- clocks: Specify the clock -- gpio-controller: Marks the device node as a gpio controller. -- #gpio-cells: Should be <2>. The first cell is the pin number and the - second cell is used to specify optional parameters: - - bit 0 specifies polarity (0 for normal, 1 for inverted). - -Examples: - gpio0: gpio@31000000 { - compatible = "fujitsu,mb86s70-gpio"; - reg = <0 0x31000000 0x10000>; - gpio-controller; - #gpio-cells = <2>; - clocks = <&clk 0 2 1>; - }; diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.yaml b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.yaml new file mode 100644 index 000000000000..d18d95285465 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/fujitsu,mb86s70-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Fujitsu MB86S7x GPIO Controller + +maintainers: + - Jassi Brar + +properties: + compatible: + oneOf: + - items: + - const: socionext,synquacer-gpio + - const: fujitsu,mb86s70-gpio + - const: fujitsu,mb86s70-gpio + + reg: + maxItems: 1 + + '#gpio-cells': + const: 2 + + gpio-controller: true + gpio-line-names: true + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - '#gpio-cells' + - gpio-controller + - clocks + +additionalProperties: false + +examples: + - | + gpio@31000000 { + compatible = "fujitsu,mb86s70-gpio"; + reg = <0x31000000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&clk 0 2 1>; + }; +... -- cgit v1.2.3 From 45e888ef99d9f378c2cbadc3caa4eee1aaf09eac Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Dec 2022 11:20:12 -0800 Subject: gpiolib: of: remove of_gpio_count() There are no more users of of_gpio_count() in the mainline kernel, remove it. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- include/linux/of_gpio.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 6db627257a7b..39f16a960565 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -105,17 +105,6 @@ static inline int of_gpio_named_count(const struct device_node *np, return of_count_phandle_with_args(np, propname, "#gpio-cells"); } -/** - * of_gpio_count() - Count GPIOs for a device - * @np: device node to count GPIOs for - * - * Same as of_gpio_named_count, but hard coded to use the 'gpios' property - */ -static inline int of_gpio_count(const struct device_node *np) -{ - return of_gpio_named_count(np, "gpios"); -} - static inline int of_get_gpio_flags(const struct device_node *np, int index, enum of_gpio_flags *flags) { -- cgit v1.2.3 From c7835652a85df183c967f574d1999505ebf80b88 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Dec 2022 11:20:13 -0800 Subject: gpiolib: of: stop exporting of_gpio_named_count() The only user of this function is gpiolib-of.c so move it there. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 26 ++++++++++++++++++++++++++ include/linux/of_gpio.h | 26 -------------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 4fff7258ee41..6724e375678d 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -23,6 +23,32 @@ #include "gpiolib.h" #include "gpiolib-of.h" +/** + * of_gpio_named_count() - Count GPIOs for a device + * @np: device node to count GPIOs for + * @propname: property name containing gpio specifier(s) + * + * The function returns the count of GPIOs specified for a node. + * Note that the empty GPIO specifiers count too. Returns either + * Number of gpios defined in property, + * -EINVAL for an incorrectly formed gpios property, or + * -ENOENT for a missing gpios property + * + * Example: + * gpios = <0 + * &gpio1 1 2 + * 0 + * &gpio2 3 4>; + * + * The above example defines four GPIOs, two of which are not specified. + * This function will return '4' + */ +static int of_gpio_named_count(const struct device_node *np, + const char *propname) +{ + return of_count_phandle_with_args(np, propname, "#gpio-cells"); +} + /** * of_gpio_spi_cs_get_count() - special GPIO counting for SPI * @dev: Consuming device diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 39f16a960565..680025c1a55b 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -79,32 +79,6 @@ static inline int of_get_named_gpio_flags(const struct device_node *np, #endif /* CONFIG_OF_GPIO */ -/** - * of_gpio_named_count() - Count GPIOs for a device - * @np: device node to count GPIOs for - * @propname: property name containing gpio specifier(s) - * - * The function returns the count of GPIOs specified for a node. - * Note that the empty GPIO specifiers count too. Returns either - * Number of gpios defined in property, - * -EINVAL for an incorrectly formed gpios property, or - * -ENOENT for a missing gpios property - * - * Example: - * gpios = <0 - * &gpio1 1 2 - * 0 - * &gpio2 3 4>; - * - * The above example defines four GPIOs, two of which are not specified. - * This function will return '4' - */ -static inline int of_gpio_named_count(const struct device_node *np, - const char *propname) -{ - return of_count_phandle_with_args(np, propname, "#gpio-cells"); -} - static inline int of_get_gpio_flags(const struct device_node *np, int index, enum of_gpio_flags *flags) { -- cgit v1.2.3 From f9792ba054f86b9eee1fab017294554914837ab5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Dec 2022 11:20:14 -0800 Subject: gpiolib: of: remove obsolete comment for of_gpio_get_count() The function is only being called form the main gpiolib module, so remove comment saying that it is also used by external callers. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 6724e375678d..6114c5b3d2ce 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -76,12 +76,6 @@ static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id) return of_gpio_named_count(np, "gpios"); } -/* - * This is used by external users of of_gpio_count() from - * - * FIXME: get rid of those external users by converting them to GPIO - * descriptors and let them all use gpiod_count() - */ int of_gpio_get_count(struct device *dev, const char *con_id) { int ret; -- cgit v1.2.3 From 40fc56ee608cdb20022c225ac6f1e4b7ba63f8f1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Dec 2022 11:20:15 -0800 Subject: gpiolib: of: remove of_get_gpio[_flags]() and of_get_named_gpio_flags() There are no more users of these APIs in the mainline kernel, remove them. This leaves of_get_named_gpio() as the only legacy OF-specific API. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 17 +++++++++++++---- include/linux/of_gpio.h | 45 ++++----------------------------------------- 2 files changed, 17 insertions(+), 45 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 6114c5b3d2ce..fdf443310442 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -365,19 +365,28 @@ out: return desc; } -int of_get_named_gpio_flags(const struct device_node *np, const char *list_name, - int index, enum of_gpio_flags *flags) +/** + * of_get_named_gpio() - Get a GPIO number to use with GPIO API + * @np: device node to get GPIO from + * @propname: Name of property containing gpio specifier(s) + * @index: index of the GPIO + * + * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * value on the error condition. + */ +int of_get_named_gpio(const struct device_node *np, const char *propname, + int index) { struct gpio_desc *desc; - desc = of_get_named_gpiod_flags(np, list_name, index, flags); + desc = of_get_named_gpiod_flags(np, propname, index, NULL); if (IS_ERR(desc)) return PTR_ERR(desc); else return desc_to_gpio(desc); } -EXPORT_SYMBOL_GPL(of_get_named_gpio_flags); +EXPORT_SYMBOL_GPL(of_get_named_gpio); /* Converts gpio_lookup_flags into bitmask of GPIO_* values */ static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags) diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 680025c1a55b..e27a9187c0c6 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -50,8 +50,8 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc) return container_of(gc, struct of_mm_gpio_chip, gc); } -extern int of_get_named_gpio_flags(const struct device_node *np, - const char *list_name, int index, enum of_gpio_flags *flags); +extern int of_get_named_gpio(const struct device_node *np, + const char *list_name, int index); extern int of_mm_gpiochip_add_data(struct device_node *np, struct of_mm_gpio_chip *mm_gc, @@ -68,49 +68,12 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); #include /* Drivers may not strictly depend on the GPIO support, so let them link. */ -static inline int of_get_named_gpio_flags(const struct device_node *np, - const char *list_name, int index, enum of_gpio_flags *flags) -{ - if (flags) - *flags = 0; - - return -ENOSYS; -} - -#endif /* CONFIG_OF_GPIO */ - -static inline int of_get_gpio_flags(const struct device_node *np, int index, - enum of_gpio_flags *flags) -{ - return of_get_named_gpio_flags(np, "gpios", index, flags); -} - -/** - * of_get_named_gpio() - Get a GPIO number to use with GPIO API - * @np: device node to get GPIO from - * @propname: Name of property containing gpio specifier(s) - * @index: index of the GPIO - * - * Returns GPIO number to use with Linux generic GPIO API, or one of the errno - * value on the error condition. - */ static inline int of_get_named_gpio(const struct device_node *np, const char *propname, int index) { - return of_get_named_gpio_flags(np, propname, index, NULL); + return -ENOSYS; } -/** - * of_get_gpio() - Get a GPIO number to use with GPIO API - * @np: device node to get GPIO from - * @index: index of the GPIO - * - * Returns GPIO number to use with Linux generic GPIO API, or one of the errno - * value on the error condition. - */ -static inline int of_get_gpio(const struct device_node *np, int index) -{ - return of_get_gpio_flags(np, index, NULL); -} +#endif /* CONFIG_OF_GPIO */ #endif /* __LINUX_OF_GPIO_H */ -- cgit v1.2.3 From 650f2dc970539b3344a98c4bd18efa309e66623b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Dec 2022 11:20:16 -0800 Subject: gpiolib: of: remove [devm_]gpiod_get_from_of_node() APIs Now that everyone is using [devm_]fwnode_gpiod_get[_index]() APIs, remove OF-specific [devm_]gpiod_get_from_of_node(). Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-devres.c | 55 ------------------------------------------- drivers/gpio/gpiolib-of.c | 46 ------------------------------------ include/linux/gpio/consumer.h | 48 ------------------------------------- 3 files changed, 149 deletions(-) diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 16a696249229..fe9ce6b19f15 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -129,61 +129,6 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, } EXPORT_SYMBOL_GPL(devm_gpiod_get_index); -/** - * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node - * @dev: device for lifecycle management - * @node: handle of the OF node - * @propname: name of the DT property representing the GPIO - * @index: index of the GPIO to obtain for the consumer - * @dflags: GPIO initialization flags - * @label: label to attach to the requested GPIO - * - * Returns: - * On successful request the GPIO pin is configured in accordance with - * provided @dflags. - * - * In case of error an ERR_PTR() is returned. - */ -struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, - const struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) -{ - struct gpio_desc **dr; - struct gpio_desc *desc; - - desc = gpiod_get_from_of_node(node, propname, index, dflags, label); - if (IS_ERR(desc)) - return desc; - - /* - * For non-exclusive GPIO descriptors, check if this descriptor is - * already under resource management by this device. - */ - if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { - struct devres *dres; - - dres = devres_find(dev, devm_gpiod_release, - devm_gpiod_match, &desc); - if (dres) - return desc; - } - - dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), - GFP_KERNEL); - if (!dr) { - gpiod_put(desc); - return ERR_PTR(-ENOMEM); - } - - *dr = desc; - devres_add(dev, dr); - - return desc; -} -EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node); - /** * devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node * @dev: GPIO consumer diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index fdf443310442..4a47e71782f3 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -418,52 +418,6 @@ static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags) return lflags; } -/** - * gpiod_get_from_of_node() - obtain a GPIO from an OF node - * @node: handle of the OF node - * @propname: name of the DT property representing the GPIO - * @index: index of the GPIO to obtain for the consumer - * @dflags: GPIO initialization flags - * @label: label to attach to the requested GPIO - * - * Returns: - * On successful request the GPIO pin is configured in accordance with - * provided @dflags. - * - * In case of error an ERR_PTR() is returned. - */ -struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) -{ - unsigned long lflags; - struct gpio_desc *desc; - enum of_gpio_flags of_flags; - int ret; - - desc = of_get_named_gpiod_flags(node, propname, index, &of_flags); - if (!desc || IS_ERR(desc)) - return desc; - - ret = gpiod_request(desc, label); - if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE)) - return desc; - if (ret) - return ERR_PTR(ret); - - lflags = of_convert_gpio_flags(of_flags); - - ret = gpiod_configure_flags(desc, propname, lflags, dflags); - if (ret < 0) { - gpiod_put(desc); - return ERR_PTR(ret); - } - - return desc; -} -EXPORT_SYMBOL_GPL(gpiod_get_from_of_node); - static struct gpio_desc *of_find_gpio_rename(struct device_node *np, const char *con_id, unsigned int idx, diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 45da8f137fe5..59cb20cfac3d 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -581,54 +581,6 @@ struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev, flags, label); } -#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO) -struct device_node; - -struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label); - -#else /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */ - -struct device_node; - -static inline -struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) -{ - return ERR_PTR(-ENOSYS); -} - -#endif /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */ - -#ifdef CONFIG_GPIOLIB -struct device_node; - -struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, - const struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label); - -#else /* CONFIG_GPIOLIB */ - -struct device_node; - -static inline -struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, - const struct device_node *node, - const char *propname, int index, - enum gpiod_flags dflags, - const char *label) -{ - return ERR_PTR(-ENOSYS); -} - -#endif /* CONFIG_GPIOLIB */ - struct acpi_gpio_params { unsigned int crs_entry_index; unsigned int line_index; -- cgit v1.2.3 From a3f7c1d6ddcbd487964c58ff246506a781e5be8f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 30 Dec 2022 11:00:44 +0100 Subject: gpio: pca9570: rename platform_data to chip_data By convention platform_data refers to structures passed to drivers by code that registers devices. When talking about model-specific data structures associated with OF compatibles, we usually call them chip_data. In order to avoid confusion rename all mentions of platform_data to chip_data. Fixes: fbb19fe17eae ("gpio: pca9570: add slg7xl45106 support") Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpio-pca9570.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c index 6c07a8811a7a..6a5a8e593ed5 100644 --- a/drivers/gpio/gpio-pca9570.c +++ b/drivers/gpio/gpio-pca9570.c @@ -18,11 +18,11 @@ #define SLG7XL45106_GPO_REG 0xDB /** - * struct pca9570_platform_data - GPIO platformdata + * struct pca9570_chip_data - GPIO platformdata * @ngpio: no of gpios * @command: Command to be sent */ -struct pca9570_platform_data { +struct pca9570_chip_data { u16 ngpio; u32 command; }; @@ -36,7 +36,7 @@ struct pca9570_platform_data { */ struct pca9570 { struct gpio_chip chip; - const struct pca9570_platform_data *p_data; + const struct pca9570_chip_data *chip_data; struct mutex lock; u8 out; }; @@ -46,8 +46,8 @@ static int pca9570_read(struct pca9570 *gpio, u8 *value) struct i2c_client *client = to_i2c_client(gpio->chip.parent); int ret; - if (gpio->p_data->command != 0) - ret = i2c_smbus_read_byte_data(client, gpio->p_data->command); + if (gpio->chip_data->command != 0) + ret = i2c_smbus_read_byte_data(client, gpio->chip_data->command); else ret = i2c_smbus_read_byte(client); @@ -62,8 +62,8 @@ static int pca9570_write(struct pca9570 *gpio, u8 value) { struct i2c_client *client = to_i2c_client(gpio->chip.parent); - if (gpio->p_data->command != 0) - return i2c_smbus_write_byte_data(client, gpio->p_data->command, value); + if (gpio->chip_data->command != 0) + return i2c_smbus_write_byte_data(client, gpio->chip_data->command, value); return i2c_smbus_write_byte(client, value); } @@ -127,8 +127,8 @@ static int pca9570_probe(struct i2c_client *client) gpio->chip.get = pca9570_get; gpio->chip.set = pca9570_set; gpio->chip.base = -1; - gpio->p_data = device_get_match_data(&client->dev); - gpio->chip.ngpio = gpio->p_data->ngpio; + gpio->chip_data = device_get_match_data(&client->dev); + gpio->chip.ngpio = gpio->chip_data->ngpio; gpio->chip.can_sleep = true; mutex_init(&gpio->lock); @@ -141,15 +141,15 @@ static int pca9570_probe(struct i2c_client *client) return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio); } -static const struct pca9570_platform_data pca9570_gpio = { +static const struct pca9570_chip_data pca9570_gpio = { .ngpio = 4, }; -static const struct pca9570_platform_data pca9571_gpio = { +static const struct pca9570_chip_data pca9571_gpio = { .ngpio = 8, }; -static const struct pca9570_platform_data slg7xl45106_gpio = { +static const struct pca9570_chip_data slg7xl45106_gpio = { .ngpio = 8, .command = SLG7XL45106_GPO_REG, }; -- cgit v1.2.3 From 6f8ecb7f85f441eb7d78ba2a4df45ee8a821934e Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 20 Dec 2022 17:02:47 +0800 Subject: gpio: vf610: connect GPIO label to dev name Current GPIO label is fixed, so can't distinguish different GPIO controllers through labels. Use dev name instead. Fixes: 7f2691a19627 ("gpio: vf610: add gpiolib/IRQ chip driver for Vybrid") Signed-off-by: Clark Wang Signed-off-by: Haibo Chen Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-vf610.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 9db42f6a2043..a429176673e7 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -304,7 +304,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) gc = &port->gc; gc->parent = dev; - gc->label = "vf610-gpio"; + gc->label = dev_name(dev); gc->ngpio = VF610_GPIO_PER_PORT; gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT; -- cgit v1.2.3 From f2527d8f566a45fa00ee5abd04d1c9476d4d704f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2023 23:08:50 +0200 Subject: gpio: Remove unused and obsoleted gpio_export_link() gpio_export_link() is legacy and unused API, remove it for good. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Reviewed-by: Yanteng Si Signed-off-by: Bartosz Golaszewski --- Documentation/driver-api/gpio/legacy.rst | 9 --------- Documentation/translations/zh_CN/driver-api/gpio/legacy.rst | 8 -------- Documentation/translations/zh_TW/gpio.txt | 9 --------- include/asm-generic/gpio.h | 6 ------ include/linux/gpio.h | 8 -------- 5 files changed, 40 deletions(-) diff --git a/Documentation/driver-api/gpio/legacy.rst b/Documentation/driver-api/gpio/legacy.rst index e17910cc3271..e3e9d26a60ce 100644 --- a/Documentation/driver-api/gpio/legacy.rst +++ b/Documentation/driver-api/gpio/legacy.rst @@ -735,10 +735,6 @@ requested using gpio_request():: /* reverse gpio_export() */ void gpio_unexport(); - /* create a sysfs link to an exported GPIO node */ - int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) - After a kernel driver requests a GPIO, it may only be made available in the sysfs interface by gpio_export(). The driver can control whether the signal direction may change. This helps drivers prevent userspace code @@ -748,11 +744,6 @@ This explicit exporting can help with debugging (by making some kinds of experiments easier), or can provide an always-there interface that's suitable for documenting as part of a board support package. -After the GPIO has been exported, gpio_export_link() allows creating -symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can -use this to provide the interface under their own device in sysfs with -a descriptive name. - API Reference ============= diff --git a/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst index 6399521d0548..8599e253fcc5 100644 --- a/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst +++ b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst @@ -672,10 +672,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO /* gpio_export()的逆操作 */ void gpio_unexport(); - /* 创建一个 sysfs 连接到已导出的 GPIO 节点 */ - int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) - 在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs 接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间 破坏重要的系统状态。 @@ -683,10 +679,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO 这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口, 与文档配合作为板级支持包的一部分。 -在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方 -创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的 -名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。 - API参考 ======= diff --git a/Documentation/translations/zh_TW/gpio.txt b/Documentation/translations/zh_TW/gpio.txt index e3c076dd75a5..abd8e4c0973e 100644 --- a/Documentation/translations/zh_TW/gpio.txt +++ b/Documentation/translations/zh_TW/gpio.txt @@ -634,18 +634,9 @@ GPIO 控制器的路徑類似 /sys/class/gpio/gpiochip42/ (對於從#42 GPIO /* gpio_export()的逆操作 */ void gpio_unexport(); - /* 創建一個 sysfs 連接到已導出的 GPIO 節點 */ - int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) - 在一個內核驅動申請一個 GPIO 之後,它可以通過 gpio_export()使其在 sysfs 接口中可見。該驅動可以控制信號方向是否可修改。這有助於防止用戶空間代碼無意間 破壞重要的系統狀態。 這個明確的導出有助於(通過使某些實驗更容易來)調試,也可以提供一個始終存在的接口, 與文檔配合作爲板級支持包的一部分。 - -在 GPIO 被導出之後,gpio_export_link()允許在 sysfs 文件系統的任何地方 -創建一個到這個 GPIO sysfs 節點的符號連結。這樣驅動就可以通過一個描述性的 -名字,在 sysfs 中他們所擁有的設備下提供一個(到這個 GPIO sysfs 節點的)接口。 - diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a7752cf152ce..f79220f614aa 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -103,12 +103,6 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change) return gpiod_export(gpio_to_desc(gpio), direction_may_change); } -static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) -{ - return gpiod_export_link(dev, name, gpio_to_desc(gpio)); -} - static inline void gpio_unexport(unsigned gpio) { gpiod_unexport(gpio_to_desc(gpio)); diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 346f60bbab30..e94815b3ce1d 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -197,14 +197,6 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change) return -EINVAL; } -static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) -{ - /* GPIO can never have been exported */ - WARN_ON(1); - return -EINVAL; -} - static inline void gpio_unexport(unsigned gpio) { /* GPIO can never have been exported */ -- cgit v1.2.3 From dc0989e3aa58dc424a18baf85639248ce9baf818 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 28 Dec 2022 11:20:43 +0200 Subject: gpiolib: Introduce gpio_device_get() and gpio_device_put() Introduce gpio_device_get() and gpio_device_put() helpers and convert existing users. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 21 +++++++++------------ drivers/gpio/gpiolib.c | 14 ++++++-------- drivers/gpio/gpiolib.h | 10 ++++++++++ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index e878e3f22b0e..0a33971c964c 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -321,7 +321,7 @@ static void linehandle_free(struct linehandle_state *lh) if (lh->descs[i]) gpiod_free(lh->descs[i]); kfree(lh->label); - put_device(&lh->gdev->dev); + gpio_device_put(lh->gdev); kfree(lh); } @@ -363,8 +363,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) lh = kzalloc(sizeof(*lh), GFP_KERNEL); if (!lh) return -ENOMEM; - lh->gdev = gdev; - get_device(&gdev->dev); + lh->gdev = gpio_device_get(gdev); if (handlereq.consumer_label[0] != '\0') { /* label is only initialized if consumer_label is set */ @@ -1576,7 +1575,7 @@ static void linereq_free(struct linereq *lr) } kfifo_free(&lr->events); kfree(lr->label); - put_device(&lr->gdev->dev); + gpio_device_put(lr->gdev); kfree(lr); } @@ -1646,8 +1645,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) if (!lr) return -ENOMEM; - lr->gdev = gdev; - get_device(&gdev->dev); + lr->gdev = gpio_device_get(gdev); for (i = 0; i < ulr.num_lines; i++) { lr->lines[i].req = lr; @@ -1916,7 +1914,7 @@ static void lineevent_free(struct lineevent_state *le) if (le->desc) gpiod_free(le->desc); kfree(le->label); - put_device(&le->gdev->dev); + gpio_device_put(le->gdev); kfree(le); } @@ -2094,8 +2092,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) le = kzalloc(sizeof(*le), GFP_KERNEL); if (!le) return -ENOMEM; - le->gdev = gdev; - get_device(&gdev->dev); + le->gdev = gpio_device_get(gdev); if (eventreq.consumer_label[0] != '\0') { /* label is only initialized if consumer_label is set */ @@ -2671,7 +2668,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) init_waitqueue_head(&cdev->wait); INIT_KFIFO(cdev->events); - cdev->gdev = gdev; + cdev->gdev = gpio_device_get(gdev); cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify; ret = blocking_notifier_chain_register(&gdev->notifier, @@ -2679,7 +2676,6 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) if (ret) goto out_free_bitmap; - get_device(&gdev->dev); file->private_data = cdev; ret = nonseekable_open(inode, file); @@ -2694,6 +2690,7 @@ out_unregister_notifier: blocking_notifier_chain_unregister(&gdev->notifier, &cdev->lineinfo_changed_nb); out_free_bitmap: + gpio_device_put(gdev); bitmap_free(cdev->watched_lines); out_free_cdev: kfree(cdev); @@ -2716,7 +2713,7 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file) bitmap_free(cdev->watched_lines); blocking_notifier_chain_unregister(&gdev->notifier, &cdev->lineinfo_changed_nb); - put_device(&gdev->dev); + gpio_device_put(gdev); kfree(cdev); return 0; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 54baf074a830..ebc2da15ae4e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -882,7 +882,7 @@ err_free_gpiochip_mask: gpiochip_free_valid_mask(gc); if (gdev->dev.release) { /* release() has been registered by gpiochip_setup_dev() */ - put_device(&gdev->dev); + gpio_device_put(gdev); goto err_print_message; } err_remove_from_list: @@ -972,7 +972,7 @@ void gpiochip_remove(struct gpio_chip *gc) */ gcdev_unregister(gdev); up_write(&gdev->sem); - put_device(&gdev->dev); + gpio_device_put(gdev); } EXPORT_SYMBOL_GPL(gpiochip_remove); @@ -2057,17 +2057,15 @@ static int validate_desc(const struct gpio_desc *desc, const char *func) int gpiod_request(struct gpio_desc *desc, const char *label) { int ret = -EPROBE_DEFER; - struct gpio_device *gdev; VALIDATE_DESC(desc); - gdev = desc->gdev; - if (try_module_get(gdev->owner)) { + if (try_module_get(desc->gdev->owner)) { ret = gpiod_request_commit(desc, label); if (ret) - module_put(gdev->owner); + module_put(desc->gdev->owner); else - get_device(&gdev->dev); + gpio_device_get(desc->gdev); } if (ret) @@ -2128,7 +2126,7 @@ void gpiod_free(struct gpio_desc *desc) { if (desc && desc->gdev && gpiod_free_commit(desc)) { module_put(desc->gdev->owner); - put_device(&desc->gdev->dev); + gpio_device_put(desc->gdev); } else { WARN_ON(extra_checks); } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index b3c2db6eba80..cca81375f127 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -82,6 +82,16 @@ static inline struct gpio_device *to_gpio_device(struct device *dev) return container_of(dev, struct gpio_device, dev); } +static inline struct gpio_device *gpio_device_get(struct gpio_device *gdev) +{ + return to_gpio_device(get_device(&gdev->dev)); +} + +static inline void gpio_device_put(struct gpio_device *gdev) +{ + put_device(&gdev->dev); +} + /* gpio suffixes used for ACPI and device tree lookup */ static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; -- cgit v1.2.3 From 70d0fc4288dabd65025fde7774b4f9262afa9034 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 28 Dec 2022 11:20:44 +0200 Subject: gpiolib: Get rid of not used of_node member All new drivers should use fwnode and / or parent to provide the necessary information to the GPIO library. Cc: Thierry Reding Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-acpi.c | 10 ---------- drivers/gpio/gpiolib-acpi.h | 4 ---- drivers/gpio/gpiolib-of.c | 25 +++++-------------------- drivers/gpio/gpiolib-of.h | 5 ----- drivers/gpio/gpiolib.c | 11 +++-------- include/linux/gpio/driver.h | 7 ------- 6 files changed, 8 insertions(+), 54 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 17c53f484280..bb583cea366c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1388,16 +1388,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) kfree(acpi_gpio); } -void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) -{ - /* Set default fwnode to parent's one if present */ - if (gc->parent) - ACPI_COMPANION_SET(&gdev->dev, ACPI_COMPANION(gc->parent)); - - if (gc->fwnode) - device_set_node(&gdev->dev, gc->fwnode); -} - static int acpi_gpio_package_count(const union acpi_object *obj) { const union acpi_object *element = obj->package.elements; diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h index 9475f99a9694..5fa315b3c912 100644 --- a/drivers/gpio/gpiolib-acpi.h +++ b/drivers/gpio/gpiolib-acpi.h @@ -26,8 +26,6 @@ struct gpio_device; void acpi_gpiochip_add(struct gpio_chip *chip); void acpi_gpiochip_remove(struct gpio_chip *chip); -void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev); - void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); @@ -42,8 +40,6 @@ int acpi_gpio_count(struct device *dev, const char *con_id); static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } -static inline void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) { } - static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 4a47e71782f3..edc769d2d338 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -651,7 +651,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, u32 tmp; int ret; - chip_np = chip->of_node; + chip_np = dev_of_node(&chip->gpiodev->dev); if (!chip_np) return ERR_PTR(-EINVAL); @@ -743,7 +743,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip) struct device_node *np; int ret; - for_each_available_child_of_node(chip->of_node, np) { + for_each_available_child_of_node(dev_of_node(&chip->gpiodev->dev), np) { if (!of_property_read_bool(np, "gpio-hog")) continue; @@ -953,14 +953,15 @@ EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove); #ifdef CONFIG_PINCTRL static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { - struct device_node *np = chip->of_node; struct of_phandle_args pinspec; struct pinctrl_dev *pctldev; + struct device_node *np; int index = 0, ret; const char *name; static const char group_names_propname[] = "gpio-ranges-group-names"; struct property *group_names; + np = dev_of_node(&chip->gpiodev->dev); if (!np) return 0; @@ -1046,7 +1047,7 @@ int of_gpiochip_add(struct gpio_chip *chip) struct device_node *np; int ret; - np = to_of_node(dev_fwnode(&chip->gpiodev->dev)); + np = dev_of_node(&chip->gpiodev->dev); if (!np) return 0; @@ -1075,19 +1076,3 @@ void of_gpiochip_remove(struct gpio_chip *chip) { fwnode_handle_put(chip->fwnode); } - -void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) -{ - /* Set default OF node to parent's one if present */ - if (gc->parent) - gdev->dev.of_node = gc->parent->of_node; - - if (gc->fwnode) - gc->of_node = to_of_node(gc->fwnode); - - /* If the gpiochip has an assigned OF node this takes precedence */ - if (gc->of_node) - gdev->dev.of_node = gc->of_node; - else - gc->of_node = gdev->dev.of_node; -} diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h index a6c593e6766c..e5bb065d82ef 100644 --- a/drivers/gpio/gpiolib-of.h +++ b/drivers/gpio/gpiolib-of.h @@ -23,7 +23,6 @@ struct gpio_desc *of_find_gpio(struct device_node *np, int of_gpiochip_add(struct gpio_chip *gc); void of_gpiochip_remove(struct gpio_chip *gc); int of_gpio_get_count(struct device *dev, const char *con_id); -void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev); #else static inline struct gpio_desc *of_find_gpio(struct device_node *np, const char *con_id, @@ -38,10 +37,6 @@ static inline int of_gpio_get_count(struct device *dev, const char *con_id) { return 0; } -static inline void of_gpio_dev_init(struct gpio_chip *gc, - struct gpio_device *gdev) -{ -} #endif /* CONFIG_OF_GPIO */ extern struct notifier_block gpio_of_notifier; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index ebc2da15ae4e..3650f4bd9213 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -659,10 +659,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, int base = 0; int ret = 0; + /* If the calling driver did not initialize firmware node, do it here */ if (gc->fwnode) fwnode = gc->fwnode; else if (gc->parent) fwnode = dev_fwnode(gc->parent); + gc->fwnode = fwnode; /* * First: allocate and populate the internal stat container, and @@ -676,14 +678,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gdev->chip = gc; gc->gpiodev = gdev; - of_gpio_dev_init(gc, gdev); - acpi_gpio_dev_init(gc, gdev); - - /* - * Assign fwnode depending on the result of the previous calls, - * if none of them succeed, assign it to the parent's one. - */ - gc->fwnode = gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode; + device_set_node(&gdev->dev, gc->fwnode); gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL); if (gdev->id < 0) { diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 44783fc16125..2316cb7fa667 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -503,13 +503,6 @@ struct gpio_chip { * the device tree automatically may have an OF translation */ - /** - * @of_node: - * - * Pointer to a device tree node representing this GPIO controller. - */ - struct device_node *of_node; - /** * @of_gpio_n_cells: * -- cgit v1.2.3 From 79aabb1ece8104b114516b059a2e42b33ed38be1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 28 Dec 2022 11:20:45 +0200 Subject: gpiolib: sort header inclusion alphabetically Sort header inclusion alphabetically. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 3650f4bd9213..2db68ed3a29f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,34 +1,35 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include -#include -#include -#include -#include -#include -#include +#include +#include #include #include -#include -#include +#include +#include #include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include + #include -#include "gpiolib.h" -#include "gpiolib-of.h" #include "gpiolib-acpi.h" -#include "gpiolib-swnode.h" #include "gpiolib-cdev.h" +#include "gpiolib-of.h" +#include "gpiolib-swnode.h" #include "gpiolib-sysfs.h" +#include "gpiolib.h" #define CREATE_TRACE_POINTS #include -- cgit v1.2.3 From 297a44f664a8ac2139c25c51ba0064cc12a6f1e5 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 5 Jan 2023 16:06:03 +0100 Subject: gpio: regmap: use new regmap_might_sleep() Now that the regmap can be queried whether it might sleep, we can get rid of the conservative setting "can_sleep = true". New drivers which want to use gpio-regmap and can access the registers memory-mapped won't have the restriction that their consumers have to use the gpiod_*cansleep() variants anymore. Signed-off-by: Michael Walle Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-regmap.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index f907c9c19fce..fca17d478984 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -254,15 +254,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config chip->ngpio = config->ngpio; chip->names = config->names; chip->label = config->label ?: dev_name(config->parent); - - /* - * If our regmap is fast_io we should probably set can_sleep to false. - * Right now, the regmap doesn't save this property, nor is there any - * access function for it. - * The only regmap type which uses fast_io is regmap-mmio. For now, - * assume a safe default of true here. - */ - chip->can_sleep = true; + chip->can_sleep = regmap_might_sleep(config->regmap); chip->get = gpio_regmap_get; if (gpio->reg_set_base && gpio->reg_clr_base) -- cgit v1.2.3 From 0c27537ad07c178bb2023f1e4e5c49cfcb1a3747 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Tue, 16 Aug 2022 15:57:25 +0530 Subject: gpio: tegra186: add Tegra234 PMC compatible in GPIO driver Using this patch we are adding PMC compatible string for Tegra234 in GPIO driver so the IRQ hierarchy can be set. Signed-off-by: Manish Bhardwaj Signed-off-by: Prathamesh Shete Reviewed-by: Linus Walleij Acked-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index fdc5bdcd5638..9941f35af823 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -670,6 +670,7 @@ static unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip, static const struct of_device_id tegra186_pmc_of_match[] = { { .compatible = "nvidia,tegra186-pmc" }, { .compatible = "nvidia,tegra194-pmc" }, + { .compatible = "nvidia,tegra234-pmc" }, { /* sentinel */ } }; -- cgit v1.2.3 From 4628cb0d8e0639e13a36af96f99a0f26dec42d99 Mon Sep 17 00:00:00 2001 From: Radu Rendec Date: Fri, 6 Jan 2023 11:04:17 -0500 Subject: gpio: pcf857x: Replace 'unsigned' with 'unsigned int' Cosmetic change only to improve the coding style. No functional change, since 'unsigned' and 'unsigned int' are identical as far as the compiler is concerned. Signed-off-by: Radu Rendec Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index cec2f2c78255..14656d4f3a3d 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -73,11 +73,11 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - unsigned out; /* software latch */ - unsigned status; /* current status */ - unsigned irq_enabled; /* enabled irqs */ + unsigned int out; /* software latch */ + unsigned int status; /* current status */ + unsigned int irq_enabled; /* enabled irqs */ - int (*write)(struct i2c_client *client, unsigned data); + int (*write)(struct i2c_client *client, unsigned int data); int (*read)(struct i2c_client *client); }; @@ -85,7 +85,7 @@ struct pcf857x { /* Talk to 8-bit I/O expander */ -static int i2c_write_le8(struct i2c_client *client, unsigned data) +static int i2c_write_le8(struct i2c_client *client, unsigned int data) { return i2c_smbus_write_byte(client, data); } @@ -97,7 +97,7 @@ static int i2c_read_le8(struct i2c_client *client) /* Talk to 16-bit I/O expander */ -static int i2c_write_le16(struct i2c_client *client, unsigned word) +static int i2c_write_le16(struct i2c_client *client, unsigned int word) { u8 buf[2] = { word & 0xff, word >> 8, }; int status; @@ -119,7 +119,7 @@ static int i2c_read_le16(struct i2c_client *client) /*-------------------------------------------------------------------------*/ -static int pcf857x_input(struct gpio_chip *chip, unsigned offset) +static int pcf857x_input(struct gpio_chip *chip, unsigned int offset) { struct pcf857x *gpio = gpiochip_get_data(chip); int status; @@ -132,7 +132,7 @@ static int pcf857x_input(struct gpio_chip *chip, unsigned offset) return status; } -static int pcf857x_get(struct gpio_chip *chip, unsigned offset) +static int pcf857x_get(struct gpio_chip *chip, unsigned int offset) { struct pcf857x *gpio = gpiochip_get_data(chip); int value; @@ -141,10 +141,10 @@ static int pcf857x_get(struct gpio_chip *chip, unsigned offset) return (value < 0) ? value : !!(value & (1 << offset)); } -static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value) +static int pcf857x_output(struct gpio_chip *chip, unsigned int offset, int value) { struct pcf857x *gpio = gpiochip_get_data(chip); - unsigned bit = 1 << offset; + unsigned int bit = 1 << offset; int status; mutex_lock(&gpio->lock); @@ -158,7 +158,7 @@ static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value) return status; } -static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) +static void pcf857x_set(struct gpio_chip *chip, unsigned int offset, int value) { pcf857x_output(chip, offset, value); } -- cgit v1.2.3 From 17a5f49b49fdd9a5b8b2ed6a30d0b8efc9b1e9b9 Mon Sep 17 00:00:00 2001 From: Radu Rendec Date: Fri, 6 Jan 2023 11:04:18 -0500 Subject: gpio: pcf857x: Fix indentation of variable declarations No functional changes. This is a whitespace change only. Signed-off-by: Radu Rendec Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 14656d4f3a3d..1026973bc998 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -121,8 +121,8 @@ static int i2c_read_le16(struct i2c_client *client) static int pcf857x_input(struct gpio_chip *chip, unsigned int offset) { - struct pcf857x *gpio = gpiochip_get_data(chip); - int status; + struct pcf857x *gpio = gpiochip_get_data(chip); + int status; mutex_lock(&gpio->lock); gpio->out |= (1 << offset); @@ -134,8 +134,8 @@ static int pcf857x_input(struct gpio_chip *chip, unsigned int offset) static int pcf857x_get(struct gpio_chip *chip, unsigned int offset) { - struct pcf857x *gpio = gpiochip_get_data(chip); - int value; + struct pcf857x *gpio = gpiochip_get_data(chip); + int value; value = gpio->read(gpio->client); return (value < 0) ? value : !!(value & (1 << offset)); @@ -143,9 +143,9 @@ static int pcf857x_get(struct gpio_chip *chip, unsigned int offset) static int pcf857x_output(struct gpio_chip *chip, unsigned int offset, int value) { - struct pcf857x *gpio = gpiochip_get_data(chip); - unsigned int bit = 1 << offset; - int status; + struct pcf857x *gpio = gpiochip_get_data(chip); + unsigned int bit = 1 << offset; + int status; mutex_lock(&gpio->lock); if (value) @@ -167,7 +167,7 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned int offset, int value) static irqreturn_t pcf857x_irq(int irq, void *data) { - struct pcf857x *gpio = data; + struct pcf857x *gpio = data; unsigned long change, i, status; status = gpio->read(gpio->client); @@ -250,11 +250,11 @@ static const struct irq_chip pcf857x_irq_chip = { static int pcf857x_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; - struct pcf857x *gpio; - unsigned int n_latch = 0; - int status; + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device_node *np = client->dev.of_node; + struct pcf857x *gpio; + unsigned int n_latch = 0; + int status; if (IS_ENABLED(CONFIG_OF) && np) of_property_read_u32(np, "lines-initial-states", &n_latch); @@ -401,8 +401,8 @@ fail: static void pcf857x_remove(struct i2c_client *client) { - struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); - struct pcf857x *gpio = i2c_get_clientdata(client); + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); + struct pcf857x *gpio = i2c_get_clientdata(client); if (pdata && pdata->teardown) pdata->teardown(client, gpio->chip.base, gpio->chip.ngpio, -- cgit v1.2.3 From 64d2f4594e33b84d4e091efb8b2c3282fe82e72f Mon Sep 17 00:00:00 2001 From: Radu Rendec Date: Fri, 6 Jan 2023 11:04:19 -0500 Subject: gpio: pcf857x: Implement get_multiple/set_multiple methods This change allows the GPIO core to read/change multiple pins in a single driver call and subsequent I2C transfer. It helps a lot with PCF857x devices, since their I2C protocol always reads/changes all existing pins anyway. Therefore, when the GPIO client code does a bulk operation on multiple pins, the driver makes a single I2C transfer. Signed-off-by: Radu Rendec Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 1026973bc998..d9db878802b7 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -141,6 +141,21 @@ static int pcf857x_get(struct gpio_chip *chip, unsigned int offset) return (value < 0) ? value : !!(value & (1 << offset)); } +static int pcf857x_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct pcf857x *gpio = gpiochip_get_data(chip); + int value = gpio->read(gpio->client); + + if (value < 0) + return value; + + *bits &= ~*mask; + *bits |= value & *mask; + + return 0; +} + static int pcf857x_output(struct gpio_chip *chip, unsigned int offset, int value) { struct pcf857x *gpio = gpiochip_get_data(chip); @@ -163,6 +178,18 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned int offset, int value) pcf857x_output(chip, offset, value); } +static void pcf857x_set_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct pcf857x *gpio = gpiochip_get_data(chip); + + mutex_lock(&gpio->lock); + gpio->out &= ~*mask; + gpio->out |= *bits & *mask; + gpio->write(gpio->client, gpio->out); + mutex_unlock(&gpio->lock); +} + /*-------------------------------------------------------------------------*/ static irqreturn_t pcf857x_irq(int irq, void *data) @@ -275,7 +302,9 @@ static int pcf857x_probe(struct i2c_client *client) gpio->chip.parent = &client->dev; gpio->chip.owner = THIS_MODULE; gpio->chip.get = pcf857x_get; + gpio->chip.get_multiple = pcf857x_get_multiple; gpio->chip.set = pcf857x_set; + gpio->chip.set_multiple = pcf857x_set_multiple; gpio->chip.direction_input = pcf857x_input; gpio->chip.direction_output = pcf857x_output; gpio->chip.ngpio = id->driver_data; -- cgit v1.2.3 From 9a7dcaefdb8ab1c2f8558e3a66261165c86c5059 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 16:17:43 +0200 Subject: gpiolib: Do not mention legacy API in the code Replace mentioning of legacy API by the latest one. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- include/linux/gpio/driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 2316cb7fa667..26a808fb8a25 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -336,7 +336,7 @@ struct gpio_irq_chip { * @set_multiple: assigns output values for multiple signals defined by "mask" * @set_config: optional hook for all kinds of settings. Uses the same * packed config format as generic pinconf. - * @to_irq: optional hook supporting non-static gpio_to_irq() mappings; + * @to_irq: optional hook supporting non-static gpiod_to_irq() mappings; * implementation may not sleep * @dbg_show: optional routine to show contents in debugfs; default code * will be used when this is omitted, but custom code can show extra -- cgit v1.2.3 From 149a028a5134ab740079bc88ee58c24a7d072ab9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 16:45:26 +0200 Subject: gpiolib: Remove unused of_mm_gpiochip_add() of_mm_gpiochip_add() is unused API, remove it for good. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/TODO | 4 ++-- include/linux/of_gpio.h | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 76560744587a..68ada1066941 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -61,8 +61,8 @@ Work items: - Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO GPIO for all current users (see below). Delete struct of_mm_gpio_chip, - to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_add() - of_mm_gpiochip_remove() from the kernel. + to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_remove() + from the kernel. - Change all consumer drivers that #include to #include and stop doing custom parsing of the diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index e27a9187c0c6..935225caf70d 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -56,11 +56,6 @@ extern int of_get_named_gpio(const struct device_node *np, extern int of_mm_gpiochip_add_data(struct device_node *np, struct of_mm_gpio_chip *mm_gc, void *data); -static inline int of_mm_gpiochip_add(struct device_node *np, - struct of_mm_gpio_chip *mm_gc) -{ - return of_mm_gpiochip_add_data(np, mm_gc, NULL); -} extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); #else /* CONFIG_OF_GPIO */ -- cgit v1.2.3 From 029d14e900e7766eb2330bd4912dc28c0466db06 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 15:46:45 +0200 Subject: gpio: davinci: Do not mention legacy API in the code Replace mentioning of legacy API by the latest one. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index fa51a91afa54..e1c1b9a527db 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -534,7 +534,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) } /* - * Arrange gpio_to_irq() support, handling either direct IRQs or + * Arrange gpiod_to_irq() support, handling either direct IRQs or * banked IRQs. Having GPIOs in the first GPIO bank use direct * IRQs, while the others use banked IRQs, would need some setup * tweaks to recognize hardware which can do that. -- cgit v1.2.3 From a5ec171efdc6151d3a51c4e1a59abb3ab9d8b710 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 15:39:42 +0200 Subject: gpio: Remove unused and obsoleted irq_to_gpio() irq_to_gpio() is legacy and unused API, remove it for good. This leaves gpio_to_irq() as it's used yet in many places. Nevertheless, removal of its counterpart is a good signal to whoever even trying to consider using them that do not. Signed-off-by: Andy Shevchenko Acked-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- Documentation/driver-api/gpio/legacy.rst | 8 -------- Documentation/translations/zh_CN/driver-api/gpio/legacy.rst | 7 ------- Documentation/translations/zh_TW/gpio.txt | 7 ------- arch/m68k/include/asm/gpio.h | 7 ------- arch/sh/include/asm/gpio.h | 5 ----- include/linux/gpio.h | 12 ------------ 6 files changed, 46 deletions(-) diff --git a/Documentation/driver-api/gpio/legacy.rst b/Documentation/driver-api/gpio/legacy.rst index e3e9d26a60ce..a0559d93efd1 100644 --- a/Documentation/driver-api/gpio/legacy.rst +++ b/Documentation/driver-api/gpio/legacy.rst @@ -387,9 +387,6 @@ map between them using calls like:: /* map GPIO numbers to IRQ numbers */ int gpio_to_irq(unsigned gpio); - /* map IRQ numbers to GPIO numbers (avoid using this) */ - int irq_to_gpio(unsigned irq); - Those return either the corresponding number in the other namespace, or else a negative errno code if the mapping can't be done. (For example, some GPIOs can't be used as IRQs.) It is an unchecked error to use a GPIO @@ -405,11 +402,6 @@ devices, by the board-specific initialization code. Note that IRQ trigger options are part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup capabilities. -Non-error values returned from irq_to_gpio() would most commonly be used -with gpio_get_value(), for example to initialize or update driver state -when the IRQ is edge-triggered. Note that some platforms don't support -this reverse mapping, so you should avoid using it. - Emulating Open Drain Signals ---------------------------- diff --git a/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst index 8599e253fcc5..74fa473bb504 100644 --- a/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst +++ b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst @@ -358,9 +358,6 @@ GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上 /* 映射 GPIO 编号到 IRQ 编号 */ int gpio_to_irq(unsigned gpio); - /* 映射 IRQ 编号到 GPIO 编号 (尽量避免使用) */ - int irq_to_gpio(unsigned irq); - 它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。 (例如,某些 GPIO 无法做为 IRQ 使用。)以下的编号错误是未经检测的:使用一个 未通过 gpio_direction_input()配置为输入的 GPIO 编号,或者使用一个 @@ -373,10 +370,6 @@ gpio_to_irq()返回的非错误值可以传递给 request_irq()或者 free_irq() 触发选项是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力 也是如此。 -irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所使用, -比如在 IRQ 是沿触发时初始化或更新驱动状态。注意某些平台不支持反映射,所以 -你应该尽量避免使用它。 - 模拟开漏信号 ------------ diff --git a/Documentation/translations/zh_TW/gpio.txt b/Documentation/translations/zh_TW/gpio.txt index abd8e4c0973e..1b986bbb0909 100644 --- a/Documentation/translations/zh_TW/gpio.txt +++ b/Documentation/translations/zh_TW/gpio.txt @@ -363,9 +363,6 @@ GPIO 編號是無符號整數;IRQ 編號也是。這些構成了兩個邏輯上 /* 映射 GPIO 編號到 IRQ 編號 */ int gpio_to_irq(unsigned gpio); - /* 映射 IRQ 編號到 GPIO 編號 (儘量避免使用) */ - int irq_to_gpio(unsigned irq); - 它們的返回值爲對應命名空間的相關編號,或是負的錯誤代碼(如果無法映射)。 (例如,某些 GPIO 無法做爲 IRQ 使用。)以下的編號錯誤是未經檢測的:使用一個 未通過 gpio_direction_input()配置爲輸入的 GPIO 編號,或者使用一個 @@ -378,10 +375,6 @@ gpio_to_irq()返回的非錯誤值可以傳遞給 request_irq()或者 free_irq() 觸發選項是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系統喚醒能力 也是如此。 -irq_to_gpio()返回的非錯誤值大多數通常可以被 gpio_get_value()所使用, -比如在 IRQ 是沿觸發時初始化或更新驅動狀態。注意某些平台不支持反映射,所以 -你應該儘量避免使用它。 - 模擬開漏信號 ---------------------------- diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h index a50b27719a58..5cfc0996ba94 100644 --- a/arch/m68k/include/asm/gpio.h +++ b/arch/m68k/include/asm/gpio.h @@ -66,13 +66,6 @@ static inline int gpio_to_irq(unsigned gpio) return __gpio_to_irq(gpio); } -static inline int irq_to_gpio(unsigned irq) -{ - return (irq >= MCFGPIO_IRQ_VECBASE && - irq < (MCFGPIO_IRQ_VECBASE + MCFGPIO_IRQ_MAX)) ? - irq - MCFGPIO_IRQ_VECBASE : -ENXIO; -} - static inline int gpio_cansleep(unsigned gpio) { return gpio < MCFGPIO_PIN_MAX ? 0 : __gpio_cansleep(gpio); diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h index d643250f0a0f..588c1380e4cb 100644 --- a/arch/sh/include/asm/gpio.h +++ b/arch/sh/include/asm/gpio.h @@ -40,11 +40,6 @@ static inline int gpio_to_irq(unsigned gpio) return __gpio_to_irq(gpio); } -static inline int irq_to_gpio(unsigned int irq) -{ - return -ENOSYS; -} - #endif /* CONFIG_GPIOLIB */ #endif /* __ASM_SH_GPIO_H */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index e94815b3ce1d..85beb236c925 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -81,11 +81,6 @@ static inline int gpio_to_irq(unsigned int gpio) return __gpio_to_irq(gpio); } -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - #endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */ /* CONFIG_GPIOLIB: bindings for managed devices that want to request gpios */ @@ -210,13 +205,6 @@ static inline int gpio_to_irq(unsigned gpio) return -EINVAL; } -static inline int irq_to_gpio(unsigned irq) -{ - /* irq can never have been returned from gpio_to_irq() */ - WARN_ON(1); - return -EINVAL; -} - static inline int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) { -- cgit v1.2.3 From 92bf78b33b0b463b00c6b0203b49aea845daecc8 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Fri, 13 Jan 2023 21:59:22 +0100 Subject: gpio: omap: use dynamic allocation of base Static allocatin is deprecated and may cause probe mess, if probe order is unusual. like this example [ 2.553833] twl4030_gpio twl4030-gpio: gpio (irq 145) chaining IRQs 161..178 [ 2.561401] gpiochip_find_base: found new base at 160 [ 2.564392] gpio gpiochip5: (twl4030): added GPIO chardev (254:5) [ 2.564544] gpio gpiochip5: registered GPIOs 160 to 177 on twl4030 [...] [ 2.692169] omap-gpmc 6e000000.gpmc: GPMC revision 5.0 [ 2.697357] gpmc_mem_init: disabling cs 0 mapped at 0x0-0x1000000 [ 2.703643] gpiochip_find_base: found new base at 178 [ 2.704376] gpio gpiochip6: (omap-gpmc): added GPIO chardev (254:6) [ 2.704589] gpio gpiochip6: registered GPIOs 178 to 181 on omap-gpmc [...] [ 2.840393] gpio gpiochip7: Static allocation of GPIO base is deprecated, use dynamic allocation. [ 2.849365] gpio gpiochip7: (gpio-160-191): GPIO integer space overlap, cannot add chip [ 2.857513] gpiochip_add_data_with_key: GPIOs 160..191 (gpio-160-191) failed to register, -16 [ 2.866149] omap_gpio 48310000.gpio: error -EBUSY: Could not register gpio chip So probing was done in an unusual order, causing mess and chips not getting their gpio in the end. Signed-off-by: Andreas Kemnade Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 80ddc43fd875..f5f3d4b22452 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1020,7 +1020,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc, if (!label) return -ENOMEM; bank->chip.label = label; - bank->chip.base = gpio; + bank->chip.base = -1; } bank->chip.ngpio = bank->width; -- cgit v1.2.3 From e226cb199c3d5bde57a4439cdc0360d900270816 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 18:38:55 +0200 Subject: gpio: davinci: Remove duplicate assignment of of_gpio_n_cells The of_gpio_n_cells default is 2 when ->of_xlate() callback is not defined. No need to assign it explicitly in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-davinci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index e1c1b9a527db..26b1f7465e09 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -252,7 +252,6 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.base = pdata->no_auto_base ? pdata->base : -1; #ifdef CONFIG_OF_GPIO - chips->chip.of_gpio_n_cells = 2; chips->chip.parent = dev; chips->chip.request = gpiochip_generic_request; chips->chip.free = gpiochip_generic_free; -- cgit v1.2.3 From 83b9e0fc9ed6129aeb1ac18bee85f17fa32e91e2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 18:39:05 +0200 Subject: gpio: ge: Remove duplicate assignment of of_gpio_n_cells The of_gpio_n_cells default is 2 when ->of_xlate() callback is not defined. No need to assign it explicitly in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ge.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index f6a3de99f7db..7bd4c2a4cc11 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -81,7 +81,6 @@ static int __init gef_gpio_probe(struct platform_device *pdev) gc->base = -1; gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev); - gc->of_gpio_n_cells = 2; /* This function adds a memory mapped GPIO chip */ ret = devm_gpiochip_add_data(&pdev->dev, gc, NULL); -- cgit v1.2.3 From 59184e1273ebb4cf32c28086faeb12725e417c9f Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Tue, 10 Jan 2023 09:49:41 +0800 Subject: dt-bindings: gpio: Convert Unisoc GPIO controller binding to yaml Convert the Unisoc gpio controller binding to DT schema format. Signed-off-by: Chunyan Zhang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/gpio-sprd.txt | 28 --------- .../devicetree/bindings/gpio/sprd,gpio.yaml | 70 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 28 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio-sprd.txt create mode 100644 Documentation/devicetree/bindings/gpio/sprd,gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/gpio-sprd.txt b/Documentation/devicetree/bindings/gpio/gpio-sprd.txt deleted file mode 100644 index eca97d45388f..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-sprd.txt +++ /dev/null @@ -1,28 +0,0 @@ -Spreadtrum GPIO controller bindings - -The controller's registers are organized as sets of sixteen 16-bit -registers with each set controlling a bank of up to 16 pins. A single -interrupt is shared for all of the banks handled by the controller. - -Required properties: -- compatible: Should be "sprd,sc9860-gpio". -- reg: Define the base and range of the I/O address space containing -the GPIO controller registers. -- gpio-controller: Marks the device node as a GPIO controller. -- #gpio-cells: Should be <2>. The first cell is the gpio number and -the second cell is used to specify optional parameters. -- interrupt-controller: Marks the device node as an interrupt controller. -- #interrupt-cells: Should be <2>. Specifies the number of cells needed -to encode interrupt source. -- interrupts: Should be the port interrupt shared by all the gpios. - -Example: - ap_gpio: gpio@40280000 { - compatible = "sprd,sc9860-gpio"; - reg = <0 0x40280000 0 0x1000>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = ; - }; diff --git a/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml b/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml new file mode 100644 index 000000000000..40924123d184 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2022 Unisoc Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/sprd,gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc GPIO controller + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +description: | + The controller's registers are organized as sets of sixteen 16-bit + registers with each set controlling a bank of up to 16 pins. A single + interrupt is shared for all of the banks handled by the controller. + +properties: + compatible: + const: sprd,sc9860-gpio + + reg: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + maxItems: 1 + description: The interrupt shared by all GPIO lines for this controller. + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + - interrupt-controller + - "#interrupt-cells" + - interrupts + +additionalProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + ap_gpio: gpio@40280000 { + compatible = "sprd,sc9860-gpio"; + reg = <0 0x40280000 0 0x1000>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; +... -- cgit v1.2.3 From bf26a472a26ea286d8d48810989bbc5af613c581 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Tue, 10 Jan 2023 09:49:42 +0800 Subject: dt-bindings: gpio: Convert Unisoc EIC controller binding to yaml Convert the Unisoc EIC controller binding to DT schema format. Update the maxItems of 'reg' property, since the current gpio-eic-sprd driver supports 3 reg items. Also removed a few similar examples. Signed-off-by: Chunyan Zhang Reviewed-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/gpio-eic-sprd.txt | 97 ------------------- .../devicetree/bindings/gpio/sprd,gpio-eic.yaml | 103 +++++++++++++++++++++ 2 files changed, 103 insertions(+), 97 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio-eic-sprd.txt create mode 100644 Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml diff --git a/Documentation/devicetree/bindings/gpio/gpio-eic-sprd.txt b/Documentation/devicetree/bindings/gpio/gpio-eic-sprd.txt deleted file mode 100644 index 54040a2bfe3a..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-eic-sprd.txt +++ /dev/null @@ -1,97 +0,0 @@ -Spreadtrum EIC controller bindings - -The EIC is the abbreviation of external interrupt controller, which can -be used only in input mode. The Spreadtrum platform has 2 EIC controllers, -one is in digital chip, and another one is in PMIC. The digital chip EIC -controller contains 4 sub-modules: EIC-debounce, EIC-latch, EIC-async and -EIC-sync. But the PMIC EIC controller contains only one EIC-debounce sub- -module. - -The EIC-debounce sub-module provides up to 8 source input signal -connections. A debounce mechanism is used to capture the input signals' -stable status (millisecond resolution) and a single-trigger mechanism -is introduced into this sub-module to enhance the input event detection -reliability. In addition, this sub-module's clock can be shut off -automatically to reduce power dissipation. Moreover the debounce range -is from 1ms to 4s with a step size of 1ms. The input signal will be -ignored if it is asserted for less than 1 ms. - -The EIC-latch sub-module is used to latch some special power down signals -and generate interrupts, since the EIC-latch does not depend on the APB -clock to capture signals. - -The EIC-async sub-module uses a 32kHz clock to capture the short signals -(microsecond resolution) to generate interrupts by level or edge trigger. - -The EIC-sync is similar with GPIO's input function, which is a synchronized -signal input register. It can generate interrupts by level or edge trigger -when detecting input signals. - -Required properties: -- compatible: Should be one of the following: - "sprd,sc9860-eic-debounce", - "sprd,sc9860-eic-latch", - "sprd,sc9860-eic-async", - "sprd,sc9860-eic-sync", - "sprd,sc2731-eic". -- reg: Define the base and range of the I/O address space containing - the GPIO controller registers. -- gpio-controller: Marks the device node as a GPIO controller. -- #gpio-cells: Should be <2>. The first cell is the gpio number and - the second cell is used to specify optional parameters. -- interrupt-controller: Marks the device node as an interrupt controller. -- #interrupt-cells: Should be <2>. Specifies the number of cells needed - to encode interrupt source. -- interrupts: Should be the port interrupt shared by all the gpios. - -Example: - eic_debounce: gpio@40210000 { - compatible = "sprd,sc9860-eic-debounce"; - reg = <0 0x40210000 0 0x80>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = ; - }; - - eic_latch: gpio@40210080 { - compatible = "sprd,sc9860-eic-latch"; - reg = <0 0x40210080 0 0x20>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = ; - }; - - eic_async: gpio@402100a0 { - compatible = "sprd,sc9860-eic-async"; - reg = <0 0x402100a0 0 0x20>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = ; - }; - - eic_sync: gpio@402100c0 { - compatible = "sprd,sc9860-eic-sync"; - reg = <0 0x402100c0 0 0x20>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = ; - }; - - pmic_eic: gpio@300 { - compatible = "sprd,sc2731-eic"; - reg = <0x300>; - interrupt-parent = <&sc2731_pmic>; - interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; diff --git a/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml b/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml new file mode 100644 index 000000000000..a21350bd0f2c --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2022 Unisoc Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/sprd,gpio-eic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Unisoc EIC controller + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +description: | + The EIC is the abbreviation of external interrupt controller, which can + be used only in input mode. The Spreadtrum platform has 2 EIC controllers, + one is in digital chip, and another one is in PMIC. The digital chip EIC + controller contains 4 sub-modules, i.e. EIC-debounce, EIC-latch, EIC-async and + EIC-sync. But the PMIC EIC controller contains only one EIC-debounce sub- + module. + + The EIC-debounce sub-module provides up to 8 source input signal + connections. A debounce mechanism is used to capture the input signals' + stable status (millisecond resolution) and a single-trigger mechanism + is introduced into this sub-module to enhance the input event detection + reliability. In addition, this sub-module's clock can be shut off + automatically to reduce power dissipation. Moreover the debounce range + is from 1ms to 4s with a step size of 1ms. The input signal will be + ignored if it is asserted for less than 1 ms. + + The EIC-latch sub-module is used to latch some special power down signals + and generate interrupts, since the EIC-latch does not depend on the APB + clock to capture signals. + + The EIC-async sub-module uses a 32kHz clock to capture the short signals + (microsecond resolution) to generate interrupts by level or edge trigger. + + The EIC-sync is similar with GPIO's input function, which is a synchronized + signal input register. It can generate interrupts by level or edge trigger + when detecting input signals. + +properties: + compatible: + enum: + - sprd,sc9860-eic-debounce + - sprd,sc9860-eic-latch + - sprd,sc9860-eic-async + - sprd,sc9860-eic-sync + - sprd,sc2731-eic + + reg: + minItems: 1 + maxItems: 3 + description: + EIC controller can support maximum 3 banks which has its own + address base. + + gpio-controller: true + + "#gpio-cells": + const: 2 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + maxItems: 1 + description: + The interrupt shared by all GPIO lines for this controller. + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + - interrupt-controller + - "#interrupt-cells" + - interrupts + +additionalProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + eic_debounce: gpio@40210000 { + compatible = "sprd,sc9860-eic-debounce"; + reg = <0 0x40210000 0 0x80>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; +... -- cgit v1.2.3 From 3c0c7b1dc686529f0ab32c6a70c74b694b59bb39 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Tue, 10 Jan 2023 09:49:43 +0800 Subject: dt-bindings: gpio: Add compatible string for Unisoc UMS512 UMS512 use the same GPIO and EIC controller with SC9860. Signed-off-by: Chunyan Zhang Reviewed-by: Krzysztof Kozlowski Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/sprd,gpio-eic.yaml | 33 ++++++++++++++++++---- .../devicetree/bindings/gpio/sprd,gpio.yaml | 7 ++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml b/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml index a21350bd0f2c..99fcf970773a 100644 --- a/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml +++ b/Documentation/devicetree/bindings/gpio/sprd,gpio-eic.yaml @@ -42,12 +42,33 @@ description: | properties: compatible: - enum: - - sprd,sc9860-eic-debounce - - sprd,sc9860-eic-latch - - sprd,sc9860-eic-async - - sprd,sc9860-eic-sync - - sprd,sc2731-eic + oneOf: + - enum: + - sprd,sc9860-eic-debounce + - sprd,sc9860-eic-latch + - sprd,sc9860-eic-async + - sprd,sc9860-eic-sync + - sprd,sc2731-eic + - items: + - enum: + - sprd,ums512-eic-debounce + - const: sprd,sc9860-eic-debounce + - items: + - enum: + - sprd,ums512-eic-latch + - const: sprd,sc9860-eic-latch + - items: + - enum: + - sprd,ums512-eic-async + - const: sprd,sc9860-eic-async + - items: + - enum: + - sprd,ums512-eic-sync + - const: sprd,sc9860-eic-sync + - items: + - enum: + - sprd,sc2730-eic + - const: sprd,sc2731-eic reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml b/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml index 40924123d184..483168838128 100644 --- a/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/sprd,gpio.yaml @@ -19,7 +19,12 @@ description: | properties: compatible: - const: sprd,sc9860-gpio + oneOf: + - const: sprd,sc9860-gpio + - items: + - enum: + - sprd,ums512-gpio + - const: sprd,sc9860-gpio reg: maxItems: 1 -- cgit v1.2.3 From 13e856b8dfca9d75dc201829445e44b647d469b4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 18:39:51 +0200 Subject: gpio: xilinx: Remove duplicate assignment of of_gpio_n_cells The of_gpio_n_cells default is 2 when ->of_xlate() callback is not defined. No need to assign it explicitly in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 2fc6b6ff7f16..e248809965ca 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -558,7 +558,6 @@ static int xgpio_probe(struct platform_device *pdev) int status = 0; struct device_node *np = pdev->dev.of_node; u32 is_dual = 0; - u32 cells = 2; u32 width[2]; u32 state[2]; u32 dir[2]; @@ -591,15 +590,6 @@ static int xgpio_probe(struct platform_device *pdev) bitmap_from_arr32(chip->dir, dir, 64); - /* Update cells with gpio-cells value */ - if (of_property_read_u32(np, "#gpio-cells", &cells)) - dev_dbg(&pdev->dev, "Missing gpio-cells property\n"); - - if (cells != 2) { - dev_err(&pdev->dev, "#gpio-cells mismatch\n"); - return -EINVAL; - } - /* * Check device node and parent device node for device width * and assume default width of 32 @@ -630,7 +620,6 @@ static int xgpio_probe(struct platform_device *pdev) chip->gc.parent = &pdev->dev; chip->gc.direction_input = xgpio_dir_in; chip->gc.direction_output = xgpio_dir_out; - chip->gc.of_gpio_n_cells = cells; chip->gc.get = xgpio_get; chip->gc.set = xgpio_set; chip->gc.request = xgpio_request; -- cgit v1.2.3 From a25d1dfdfcad505c49cc19e8ac64d0fcb8d12fa6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 18:39:40 +0200 Subject: gpio: zevio: Remove duplicate assignment of of_gpio_n_cells The of_gpio_n_cells default is 2 when ->of_xlate() callback is not defined. No need to assign it explicitly in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-zevio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index ce9d1282165c..c9f4c26cae3d 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -162,7 +162,6 @@ static const struct gpio_chip zevio_gpio_chip = { .base = 0, .owner = THIS_MODULE, .ngpio = 32, - .of_gpio_n_cells = 2, }; /* Initialization */ -- cgit v1.2.3 From 9c8224d04b2ee0c5b9cc6f536fdc23aefff63257 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 18:39:41 +0200 Subject: gpio: zevio: Use proper headers and drop OF_GPIO dependency The driver doesn't depend on the OF_GPIO to be compiled. Hence the proper header to use is mod_devicetable.h. Replace of*.h with the above mentioned and drop redundant dependency. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-zevio.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 525b911b4ac7..406e8bda487f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -762,7 +762,7 @@ config GPIO_XTENSA config GPIO_ZEVIO bool "LSI ZEVIO SoC memory mapped GPIOs" - depends on ARM && OF_GPIO + depends on ARM help Say yes here to support the GPIO controller in LSI ZEVIO SoCs. diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index c9f4c26cae3d..61e47456c33a 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -5,13 +5,14 @@ * Author: Fabian Vogt */ -#include +#include #include #include -#include #include -#include +#include #include +#include + #include /* -- cgit v1.2.3 From a060dc6620c13435b78e92cd2ebdbb6d11af237a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 13 Jan 2023 20:26:18 +0200 Subject: gpio: wcd934x: Remove duplicate assignment of of_gpio_n_cells The of_gpio_n_cells default is 2 when ->of_xlate() callback is not defined. No need to assign it explicitly in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-wcd934x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c index 97e6caedf1f3..817750e4e033 100644 --- a/drivers/gpio/gpio-wcd934x.c +++ b/drivers/gpio/gpio-wcd934x.c @@ -98,7 +98,6 @@ static int wcd_gpio_probe(struct platform_device *pdev) chip->base = -1; chip->ngpio = WCD934X_NPINS; chip->label = dev_name(dev); - chip->of_gpio_n_cells = 2; chip->can_sleep = false; return devm_gpiochip_add_data(dev, chip, data); -- cgit v1.2.3 From b0047b90db71d0d555d645745b40f0170e5ff4c7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 15:46:53 +0200 Subject: gpio: rockchip: Do not mention legacy API in the code Replace mentioning of legacy API by the latest one. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index 200e43a6f4b4..e5de15a2ab9a 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -299,7 +299,7 @@ static int rockchip_gpio_set_config(struct gpio_chip *gc, unsigned int offset, } /* - * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin + * gpiod_to_irq() callback function. Creates a mapping between a GPIO pin * and a virtual IRQ, if not already present. */ static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) -- cgit v1.2.3 From 91a0192e90e9df40d4b63c4ce11126114ed5d79d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2023 14:47:02 +0200 Subject: gpio: pcf857x: Get rid of legacy platform data Platform data is a legacy interface to supply device properties to the driver. In this case we don't have in-kernel users for it. Moreover it uses plain GPIO numbers which is no-no for a new code. Just remove it for good. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 34 ++------------------------ include/linux/platform_data/pcf857x.h | 45 ----------------------------------- 2 files changed, 2 insertions(+), 77 deletions(-) delete mode 100644 include/linux/platform_data/pcf857x.h diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index d9db878802b7..dfa15444a24a 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -18,7 +17,6 @@ #include #include - static const struct i2c_device_id pcf857x_id[] = { { "pcf8574", 8 }, { "pcf8574a", 8 }, @@ -277,18 +275,12 @@ static const struct irq_chip pcf857x_irq_chip = { static int pcf857x_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *np = client->dev.of_node; struct pcf857x *gpio; unsigned int n_latch = 0; int status; - if (IS_ENABLED(CONFIG_OF) && np) - of_property_read_u32(np, "lines-initial-states", &n_latch); - else if (pdata) - n_latch = pdata->n_latch; - else - dev_dbg(&client->dev, "no platform data\n"); + of_property_read_u32(np, "lines-initial-states", &n_latch); /* Allocate, initialize, and register this gpio_chip. */ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); @@ -297,7 +289,7 @@ static int pcf857x_probe(struct i2c_client *client) mutex_init(&gpio->lock); - gpio->chip.base = pdata ? pdata->gpio_base : -1; + gpio->chip.base = -1; gpio->chip.can_sleep = true; gpio->chip.parent = &client->dev; gpio->chip.owner = THIS_MODULE; @@ -406,17 +398,6 @@ static int pcf857x_probe(struct i2c_client *client) if (status < 0) goto fail; - /* Let platform code set up the GPIOs and their users. - * Now is the first time anyone could use them. - */ - if (pdata && pdata->setup) { - status = pdata->setup(client, - gpio->chip.base, gpio->chip.ngpio, - pdata->context); - if (status < 0) - dev_warn(&client->dev, "setup --> %d\n", status); - } - dev_info(&client->dev, "probed\n"); return 0; @@ -428,16 +409,6 @@ fail: return status; } -static void pcf857x_remove(struct i2c_client *client) -{ - struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); - struct pcf857x *gpio = i2c_get_clientdata(client); - - if (pdata && pdata->teardown) - pdata->teardown(client, gpio->chip.base, gpio->chip.ngpio, - pdata->context); -} - static void pcf857x_shutdown(struct i2c_client *client) { struct pcf857x *gpio = i2c_get_clientdata(client); @@ -452,7 +423,6 @@ static struct i2c_driver pcf857x_driver = { .of_match_table = of_match_ptr(pcf857x_of_table), }, .probe_new = pcf857x_probe, - .remove = pcf857x_remove, .shutdown = pcf857x_shutdown, .id_table = pcf857x_id, }; diff --git a/include/linux/platform_data/pcf857x.h b/include/linux/platform_data/pcf857x.h deleted file mode 100644 index 01d0a3ea3aef..000000000000 --- a/include/linux/platform_data/pcf857x.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_PCF857X_H -#define __LINUX_PCF857X_H - -/** - * struct pcf857x_platform_data - data to set up pcf857x driver - * @gpio_base: number of the chip's first GPIO - * @n_latch: optional bit-inverse of initial register value; if - * you leave this initialized to zero the driver will act - * like the chip was just reset - * @setup: optional callback issued once the GPIOs are valid - * @teardown: optional callback issued before the GPIOs are invalidated - * @context: optional parameter passed to setup() and teardown() - * - * In addition to the I2C_BOARD_INFO() state appropriate to each chip, - * the i2c_board_info used with the pcf875x driver must provide its - * platform_data (pointer to one of these structures) with at least - * the gpio_base value initialized. - * - * The @setup callback may be used with the kind of board-specific glue - * which hands the (now-valid) GPIOs to other drivers, or which puts - * devices in their initial states using these GPIOs. - * - * These GPIO chips are only "quasi-bidirectional"; read the chip specs - * to understand the behavior. They don't have separate registers to - * record which pins are used for input or output, record which output - * values are driven, or provide access to input values. That must be - * inferred by reading the chip's value and knowing the last value written - * to it. If you leave n_latch initialized to zero, that last written - * value is presumed to be all ones (as if the chip were just reset). - */ -struct pcf857x_platform_data { - unsigned gpio_base; - unsigned n_latch; - - int (*setup)(struct i2c_client *client, - int gpio, unsigned ngpio, - void *context); - void (*teardown)(struct i2c_client *client, - int gpio, unsigned ngpio, - void *context); - void *context; -}; - -#endif /* __LINUX_PCF857X_H */ -- cgit v1.2.3 From e2d181211641598103bcc8a06bade63121b9be49 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2023 14:47:03 +0200 Subject: gpio: pcf857x: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Add mod_devicetable.h include. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index dfa15444a24a..9d34776109db 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -11,9 +11,9 @@ #include #include #include +#include #include -#include -#include +#include #include #include @@ -35,7 +35,6 @@ static const struct i2c_device_id pcf857x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); -#ifdef CONFIG_OF static const struct of_device_id pcf857x_of_table[] = { { .compatible = "nxp,pcf8574" }, { .compatible = "nxp,pcf8574a" }, @@ -53,7 +52,6 @@ static const struct of_device_id pcf857x_of_table[] = { { } }; MODULE_DEVICE_TABLE(of, pcf857x_of_table); -#endif /* * The pcf857x, pca857x, and pca967x chips only expose one read and one @@ -275,12 +273,11 @@ static const struct irq_chip pcf857x_irq_chip = { static int pcf857x_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct device_node *np = client->dev.of_node; struct pcf857x *gpio; unsigned int n_latch = 0; int status; - of_property_read_u32(np, "lines-initial-states", &n_latch); + device_property_read_u32(&client->dev, "lines-initial-states", &n_latch); /* Allocate, initialize, and register this gpio_chip. */ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); @@ -420,7 +417,7 @@ static void pcf857x_shutdown(struct i2c_client *client) static struct i2c_driver pcf857x_driver = { .driver = { .name = "pcf857x", - .of_match_table = of_match_ptr(pcf857x_of_table), + .of_match_table = pcf857x_of_table, }, .probe_new = pcf857x_probe, .shutdown = pcf857x_shutdown, -- cgit v1.2.3 From 51435300df229cab06c3efdd80a303b79278e7a7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2023 14:47:04 +0200 Subject: gpio: pcf857x: Drop unneeded explicit casting The s32 is compatible with int, no need to cast. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 9d34776109db..3de1d3ad7472 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -88,7 +88,7 @@ static int i2c_write_le8(struct i2c_client *client, unsigned int data) static int i2c_read_le8(struct i2c_client *client) { - return (int)i2c_smbus_read_byte(client); + return i2c_smbus_read_byte(client); } /* Talk to 16-bit I/O expander */ -- cgit v1.2.3 From e3863fa123c8fd9647782bc560216c6b910711e8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 20 Jan 2023 10:38:00 +0100 Subject: gpio: Get rid of gpio_to_chip() The gpio_to_chip() function refers to the global GPIO numberspace which is a problem we want to get rid of. Get this function out of the header and open code it into gpiolib with appropriate FIXME notices so no new users appear in the kernel. Signed-off-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/pinctrl/core.c | 14 ++++++++++++-- include/asm-generic/gpio.h | 6 ------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 41fd84738707..d6e6c751255f 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -325,7 +325,12 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio) { struct pinctrl_dev *pctldev; struct pinctrl_gpio_range *range = NULL; - struct gpio_chip *chip = gpio_to_chip(gpio); + /* + * FIXME: "gpio" here is a number in the global GPIO numberspace. + * get rid of this from the ranges eventually and get the GPIO + * descriptor from the gpio_chip. + */ + struct gpio_chip *chip = gpiod_to_chip(gpio_to_desc(gpio)); if (WARN(!chip, "no gpio_chip for gpio%i?", gpio)) return false; @@ -1657,7 +1662,12 @@ static int pinctrl_pins_show(struct seq_file *s, void *what) } } if (gpio_num >= 0) - chip = gpio_to_chip(gpio_num); + /* + * FIXME: gpio_num comes from the global GPIO numberspace. + * we need to get rid of the range->base eventually and + * get the descriptor directly from the gpio_chip. + */ + chip = gpiod_to_chip(gpio_to_desc(gpio_num)); else chip = NULL; if (chip) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index f79220f614aa..22cb8c9efc1d 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -31,12 +31,6 @@ struct module; struct device_node; struct gpio_desc; -/* caller holds gpio_lock *OR* gpio is marked as requested */ -static inline struct gpio_chip *gpio_to_chip(unsigned gpio) -{ - return gpiod_to_chip(gpio_to_desc(gpio)); -} - /* Always use the library code for GPIO management calls, * or when sleeping may be involved. */ -- cgit v1.2.3 From fd648e1010b1c6f248ae5ed089808f031fedcfba Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 21 Jan 2023 13:18:35 +0200 Subject: gpio: zevio: Add missing header The commit 899f6a9c4364 ("gpio: zevio: Use proper headers and drop OF_GPIO dependency") missed one header this driver depends on. Add it. Fixes: 899f6a9c4364 ("gpio: zevio: Use proper headers and drop OF_GPIO dependency") Reported-by: kernel test robot Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-zevio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index 61e47456c33a..f0f571b323f2 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 3101b1e4ba3874a7dbcc4da6d788e1408a69a5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 20 Jan 2023 08:53:33 +0100 Subject: gpio: mvebu: Use IS_REACHABLE instead of IS_ENABLED for CONFIG_PWM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To check if a certain function (here e.g. pwmchip_add()) can be called IS_REACHABLE is the better check. The relevant difference to IS_ENABLED is that IS_REACHABLE evaluates to 0 if the current code is builtin but the checked symbol is =m and so must not be used. Today there is no practical impact as CONFIG_PWM is a bool. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 91a4232ee58c..a68f682aec01 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) BUG(); } - if (IS_ENABLED(CONFIG_PWM)) + if (IS_REACHABLE(CONFIG_PWM)) mvebu_pwm_suspend(mvchip); return 0; @@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev) BUG(); } - if (IS_ENABLED(CONFIG_PWM)) + if (IS_REACHABLE(CONFIG_PWM)) mvebu_pwm_resume(mvchip); return 0; @@ -1228,7 +1228,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); /* Some MVEBU SoCs have simple PWM support for GPIO lines */ - if (IS_ENABLED(CONFIG_PWM)) { + if (IS_REACHABLE(CONFIG_PWM)) { err = mvebu_pwm_probe(pdev, mvchip, id); if (err) return err; -- cgit v1.2.3 From eed5a3bfafe6840494f7752b5cecd2a610b54fef Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jan 2023 16:51:40 +0200 Subject: gpiolib: of: Move enum of_gpio_flags to its only user GPIO library for OF is the only user for enum of_gpio_flags. Move it there. Signed-off-by: Andy Shevchenko Acked-by: Rob Herring Reviewed-by: Arnd Bergmann Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 15 +++++++++++++++ include/linux/of_gpio.h | 15 --------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index edc769d2d338..72d8a3da31e3 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -23,6 +23,21 @@ #include "gpiolib.h" #include "gpiolib-of.h" +/* + * This is Linux-specific flags. By default controllers' and Linux' mapping + * match, but GPIO controllers are free to translate their own flags to + * Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended. + */ +enum of_gpio_flags { + OF_GPIO_ACTIVE_LOW = 0x1, + OF_GPIO_SINGLE_ENDED = 0x2, + OF_GPIO_OPEN_DRAIN = 0x4, + OF_GPIO_TRANSITORY = 0x8, + OF_GPIO_PULL_UP = 0x10, + OF_GPIO_PULL_DOWN = 0x20, + OF_GPIO_PULL_DISABLE = 0x40, +}; + /** * of_gpio_named_count() - Count GPIOs for a device * @np: device node to count GPIOs for diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 935225caf70d..5d58b3b0a97e 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -17,21 +17,6 @@ struct device_node; -/* - * This is Linux-specific flags. By default controllers' and Linux' mapping - * match, but GPIO controllers are free to translate their own flags to - * Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended. - */ -enum of_gpio_flags { - OF_GPIO_ACTIVE_LOW = 0x1, - OF_GPIO_SINGLE_ENDED = 0x2, - OF_GPIO_OPEN_DRAIN = 0x4, - OF_GPIO_TRANSITORY = 0x8, - OF_GPIO_PULL_UP = 0x10, - OF_GPIO_PULL_DOWN = 0x20, - OF_GPIO_PULL_DISABLE = 0x40, -}; - #ifdef CONFIG_OF_GPIO #include -- cgit v1.2.3 From 2e539b735d8683097846b486c0fb093da5f27fbb Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Wed, 25 Jan 2023 13:26:31 -0800 Subject: gpio: tegra186: remove unneeded loop in tegra186_gpio_init_route_mapping() Reviewing the j loop over num_irqs_per_bank, in the code previous to the fixes: commit, every j was used. now only when j == 0. If only j == 0 is used, there is no need for the loop. Fixes: 210386804745 ("gpio: tegra186: Support multiple interrupts per bank") Signed-off-by: Tom Rix Acked-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 9941f35af823..14c872b6ad05 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -677,7 +677,7 @@ static const struct of_device_id tegra186_pmc_of_match[] = { static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) { struct device *dev = gpio->gpio.parent; - unsigned int i, j; + unsigned int i; u32 value; for (i = 0; i < gpio->soc->num_ports; i++) { @@ -699,27 +699,23 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) * On Tegra194 and later, each pin can be routed to one or more * interrupts. */ - for (j = 0; j < gpio->num_irqs_per_bank; j++) { - dev_dbg(dev, "programming default interrupt routing for port %s\n", - port->name); - - offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j); - - /* - * By default we only want to route GPIO pins to IRQ 0. This works - * only under the assumption that we're running as the host kernel - * and hence all GPIO pins are owned by Linux. - * - * For cases where Linux is the guest OS, the hypervisor will have - * to configure the interrupt routing and pass only the valid - * interrupts via device tree. - */ - if (j == 0) { - value = readl(base + offset); - value = BIT(port->pins) - 1; - writel(value, base + offset); - } - } + dev_dbg(dev, "programming default interrupt routing for port %s\n", + port->name); + + offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, 0); + + /* + * By default we only want to route GPIO pins to IRQ 0. This works + * only under the assumption that we're running as the host kernel + * and hence all GPIO pins are owned by Linux. + * + * For cases where Linux is the guest OS, the hypervisor will have + * to configure the interrupt routing and pass only the valid + * interrupts via device tree. + */ + value = readl(base + offset); + value = BIT(port->pins) - 1; + writel(value, base + offset); } } } -- cgit v1.2.3 From 4827aae061337251bb91801b316157a78b845ec7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 12 Feb 2023 16:13:55 +0200 Subject: gpio: sim: Use %pfwP specifier instead of calling fwnode API directly Instead of calling fwnode_get_name() and supply as %s, use %pfwP which will do the same inside printf() call. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sim.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 60514bc5454f..a51b5ea38ad5 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -377,8 +377,8 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label); if (ret) { - label = devm_kasprintf(dev, GFP_KERNEL, "%s-%s", - dev_name(dev), fwnode_get_name(swnode)); + label = devm_kasprintf(dev, GFP_KERNEL, "%s-%pfwP", + dev_name(dev), swnode); if (!label) return -ENOMEM; } @@ -784,10 +784,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev) GFP_KERNEL); else hog->chip_label = kasprintf(GFP_KERNEL, - "gpio-sim.%u-%s", + "gpio-sim.%u-%pfwP", dev->id, - fwnode_get_name( - bank->swnode)); + bank->swnode); if (!hog->chip_label) { gpio_sim_remove_hogs(dev); return -ENOMEM; -- cgit v1.2.3