diff options
Diffstat (limited to 'drivers/gpio')
36 files changed, 691 insertions, 1458 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ec7cfd4f52b1..13be729710f2 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -354,16 +354,6 @@ config GPIO_IMX_SCU def_bool y depends on IMX_SCU -config GPIO_IOP - tristate "Intel IOP GPIO" - depends on ARCH_IOP32X || COMPILE_TEST - select GPIO_GENERIC - help - Say yes here to support the GPIO functionality of a number of Intel - IOP32X or IOP33X series of chips. - - If unsure, say N. - config GPIO_IXP4XX bool "Intel IXP4xx GPIO" depends on ARCH_IXP4XX @@ -762,7 +752,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. @@ -831,6 +821,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 @@ -845,6 +836,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 @@ -870,8 +863,10 @@ 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 + 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 @@ -893,6 +888,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. @@ -1438,13 +1434,6 @@ config GPIO_TWL6040 Say yes here to access the GPO signals of twl6040 audio chip from Texas Instruments. -config GPIO_UCB1400 - tristate "Philips UCB1400 GPIO" - depends on UCB1400_CORE - help - This enables support for the Philips UCB1400 GPIO pins. - The UCB1400 is an AC97 audio codec. - config GPIO_WHISKEY_COVE tristate "GPIO support for Whiskey Cove PMIC" depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC_BXTWC @@ -1531,6 +1520,7 @@ config GPIO_MLXBF2 tristate "Mellanox BlueField 2 SoC GPIO" depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST) select GPIO_GENERIC + select GPIOLIB_IRQCHIP help Say Y here if you want GPIO support on Mellanox BlueField 2 SoC. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 010587025fc8..c048ba003367 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -72,7 +72,6 @@ obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IDIO_16) += gpio-idio-16.o obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.o -obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT87) += gpio-it87.o obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o @@ -166,7 +165,6 @@ obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o -obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o 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 <linux/of_gpio.h> to #include <linux/gpio/consumer.h> and stop doing custom parsing of the diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 7b8829c8e423..a3846faf3780 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -8,17 +8,14 @@ */ #include <linux/bits.h> #include <linux/device.h> -#include <linux/errno.h> -#include <linux/gpio/driver.h> -#include <linux/io.h> +#include <linux/err.h> #include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/irqdesc.h> +#include <linux/irq.h> #include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/spinlock.h> +#include <linux/regmap.h> #include <linux/types.h> #include "gpio-i8255.h" @@ -38,212 +35,101 @@ 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; +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), }; - -/** - * 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 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, }; -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 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); - - 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,41 +152,24 @@ 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; -} - -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); - } + return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val); } 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; + struct i8255_regmap_config config = {}; + void __iomem *regs; + struct regmap *map; int err; - - dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); - if (!dio48egpio) - return -ENOMEM; + struct regmap_irq_chip *chip; + unsigned int irq_mask; + struct regmap_irq_chip_data *chip_data; if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -308,53 +177,52 @@ 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->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; - - 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); - - err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } + 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"); - 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); + 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; - } - return 0; + 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"); + + 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 devm_i8255_regmap_register(dev, &config); } static struct isa_driver dio48e_driver = { diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index c5e231fde1af..ca2175b84e24 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -8,23 +8,18 @@ */ #include <linux/bits.h> #include <linux/device.h> -#include <linux/errno.h> -#include <linux/gpio/driver.h> -#include <linux/io.h> -#include <linux/ioport.h> +#include <linux/err.h> +#include <linux/gpio/regmap.h> #include <linux/interrupt.h> -#include <linux/irqdesc.h> +#include <linux/ioport.h> +#include <linux/irq.h> #include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/spinlock.h> +#include <linux/regmap.h> #include <linux/types.h> -#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) @@ -38,185 +33,83 @@ 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"); -/** - * 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; -}; +#define IDI48_IRQ_STATUS 0x7 +#define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS -/** - * 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) +static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) { - return GPIO_LINE_DIRECTION_IN; -} + 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; -static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - 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; - - 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; } -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,75 +121,58 @@ 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; + 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); 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->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; - - 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); + 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"); - 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; - } + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; - return 0; + 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"); + + 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 PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config)); } static struct isa_driver idi_48_driver = { diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index fa51a91afa54..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; @@ -534,7 +533,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. diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 2e1779709113..6cedf46efec6 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/gpio/driver.h> #include <linux/bitops.h> +#include <linux/seq_file.h> #define EP93XX_GPIO_F_INT_STATUS 0x5c #define EP93XX_GPIO_A_INT_STATUS 0xa0 @@ -40,7 +41,6 @@ #define EP93XX_GPIO_F_IRQ_BASE 80 struct ep93xx_gpio_irq_chip { - struct irq_chip ic; u8 irq_offset; u8 int_unmasked; u8 int_enabled; @@ -148,7 +148,7 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) */ struct irq_chip *irqchip = irq_desc_get_chip(desc); unsigned int irq = irq_desc_get_irq(desc); - int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ + int port_f_idx = (irq & 7) ^ 4; /* {20..23,48..51} -> {0..7} */ int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx; chained_irq_enter(irqchip, desc); @@ -185,6 +185,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) ep93xx_gpio_update_int_params(epg, eic); writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void ep93xx_gpio_irq_mask(struct irq_data *d) @@ -195,6 +196,7 @@ static void ep93xx_gpio_irq_mask(struct irq_data *d) eic->int_unmasked &= ~BIT(d->irq & 7); ep93xx_gpio_update_int_params(epg, eic); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void ep93xx_gpio_irq_unmask(struct irq_data *d) @@ -203,6 +205,7 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d) struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); struct ep93xx_gpio *epg = gpiochip_get_data(gc); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); eic->int_unmasked |= BIT(d->irq & 7); ep93xx_gpio_update_int_params(epg, eic); } @@ -320,15 +323,25 @@ static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, return 0; } -static void ep93xx_init_irq_chip(struct device *dev, struct irq_chip *ic) +static void ep93xx_irq_print_chip(struct irq_data *data, struct seq_file *p) { - ic->irq_ack = ep93xx_gpio_irq_ack; - ic->irq_mask_ack = ep93xx_gpio_irq_mask_ack; - ic->irq_mask = ep93xx_gpio_irq_mask; - ic->irq_unmask = ep93xx_gpio_irq_unmask; - ic->irq_set_type = ep93xx_gpio_irq_type; + struct gpio_chip *gc = irq_data_get_irq_chip_data(data); + + seq_printf(p, dev_name(gc->parent)); } +static const struct irq_chip gpio_eic_irq_chip = { + .name = "ep93xx-gpio-eic", + .irq_ack = ep93xx_gpio_irq_ack, + .irq_mask = ep93xx_gpio_irq_mask, + .irq_unmask = ep93xx_gpio_irq_unmask, + .irq_mask_ack = ep93xx_gpio_irq_mask_ack, + .irq_set_type = ep93xx_gpio_irq_type, + .irq_print_chip = ep93xx_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, struct platform_device *pdev, struct ep93xx_gpio *epg, @@ -350,8 +363,6 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, girq = &gc->irq; if (bank->has_irq || bank->has_hierarchical_irq) { - struct irq_chip *ic; - gc->set_config = ep93xx_gpio_set_config; egc->eic = devm_kcalloc(dev, 1, sizeof(*egc->eic), @@ -359,12 +370,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, if (!egc->eic) return -ENOMEM; egc->eic->irq_offset = bank->irq; - ic = &egc->eic->ic; - ic->name = devm_kasprintf(dev, GFP_KERNEL, "gpio-irq-%s", bank->label); - if (!ic->name) - return -ENOMEM; - ep93xx_init_irq_chip(dev, ic); - girq->chip = ic; + gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip); } if (bank->has_irq) { 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); 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 <linux/device.h> #include <linux/errno.h> -#include <linux/gpio/driver.h> -#include <linux/io.h> #include <linux/ioport.h> #include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/regmap.h> +#include <linux/types.h> #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 = { diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c index 9b97db418df1..64ab80fc4a1e 100644 --- a/drivers/gpio/gpio-i8255.c +++ b/drivers/gpio/gpio-i8255.c @@ -3,48 +3,43 @@ * Intel 8255 Programmable Peripheral Interface * Copyright (C) 2022 William Breathitt Gray */ -#include <linux/bitmap.h> +#include <linux/bits.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/export.h> -#include <linux/io.h> +#include <linux/gpio/regmap.h> #include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/types.h> +#include <linux/regmap.h> #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 - -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 u8 i8255_direction_mask(const unsigned long offset) +#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_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,234 +48,93 @@ static u8 i8255_direction_mask(const unsigned long offset) } } -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) +static int i8255_ppi_init(struct regmap *const map, const unsigned int base) { - 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); + 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); } -/** - * 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) +static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base, + unsigned int offset, unsigned int *reg, + unsigned int *mask) { - 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); - - 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); - - 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)); -} -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); + 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; } } -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 + * devm_i8255_regmap_register - Register an i8255 GPIO controller + * @dev: device that is registering this i8255 GPIO device + * @config: configuration for i8255_regmap_config * - * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to - * MODE 0 (Basic Input/Output) output mode. + * Registers an Intel 8255 Programmable Peripheral Interface GPIO controller. + * Returns 0 on success and negative error number on failure. */ -void i8255_mode0_output(struct i8255 __iomem *const ppi) +int devm_i8255_regmap_register(struct device *const dev, + const struct i8255_regmap_config *const config) { - iowrite8(I8255_CONTROL_MODE_SET, &ppi->control); -} -EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255); + struct gpio_regmap_config gpio_config = {0}; + unsigned long i; + int err; -/** - * 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; + if (!config->parent) + return -EINVAL; - i8255_set_port(ppi, state, io_port, mask, bits); -} -EXPORT_SYMBOL_NS_GPL(i8255_set, I8255); + if (!config->map) + return -EINVAL; -/** - * 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; + if (!config->num_ppi) + return -EINVAL; - 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); + for (i = 0; i < config->num_ppi; i++) { + err = i8255_ppi_init(config->map, i * 4); + if (err) + return err; } -} -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); + 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(i8255_state_init, I8255); +EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, I8255); MODULE_AUTHOR("William Breathitt Gray"); MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h index d9084aae9446..9dcf639b94df 100644 --- a/drivers/gpio/gpio-i8255.h +++ b/drivers/gpio/gpio-i8255.h @@ -3,44 +3,32 @@ #ifndef _I8255_H_ #define _I8255_H_ -#include <linux/spinlock.h> -#include <linux/types.h> +struct device; +struct irq_domain; +struct regmap; -/** - * struct i8255 - Intel 8255 register structure - * @port: Port A, B, and C - * @control: Control register - */ -struct i8255 { - u8 port[3]; - u8 control; -}; +#define i8255_volatile_regmap_range(_base) regmap_reg_range(_base, _base + 0x2) /** - * struct i8255_state - Intel 8255 state structure - * @lock: synchronization lock for accessing device state - * @control_state: Control register state + * 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_state { - spinlock_t lock; - u8 control_state; +struct i8255_regmap_config { + struct device *parent; + struct regmap *map; + int num_ppi; + const char *const *names; + struct irq_domain *domain; }; -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); +int devm_i8255_regmap_register(struct device *dev, + const struct i8255_regmap_config *config); #endif /* _I8255_H_ */ diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c deleted file mode 100644 index 7390b5ca09e3..000000000000 --- a/drivers/gpio/gpio-iop.c +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/plat-iop/gpio.c - * GPIO handling for Intel IOP3xx processors. - * - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - */ - -#include <linux/err.h> -#include <linux/module.h> -#include <linux/gpio/driver.h> -#include <linux/platform_device.h> - -#define IOP3XX_GPOE 0x0000 -#define IOP3XX_GPID 0x0004 -#define IOP3XX_GPOD 0x0008 - -static int iop3xx_gpio_probe(struct platform_device *pdev) -{ - struct gpio_chip *gc; - void __iomem *base; - int err; - - gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); - if (!gc) - return -ENOMEM; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - err = bgpio_init(gc, &pdev->dev, 1, base + IOP3XX_GPID, - base + IOP3XX_GPOD, NULL, NULL, base + IOP3XX_GPOE, 0); - if (err) - return err; - - gc->base = 0; - gc->owner = THIS_MODULE; - gc->label = "gpio-iop"; - - return devm_gpiochip_add_data(&pdev->dev, gc, NULL); -} - -static struct platform_driver iop3xx_gpio_driver = { - .driver = { - .name = "gpio-iop", - }, - .probe = iop3xx_gpio_probe, -}; - -static int __init iop3xx_gpio_init(void) -{ - return platform_driver_register(&iop3xx_gpio_driver); -} -arch_initcall(iop3xx_gpio_init); - -MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors"); -MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); -MODULE_LICENSE("GPL"); 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); 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; diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 6f673b2f2a1b..9d0cec4b82a3 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -249,10 +249,11 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) } else { pr_err("mxc: invalid configuration for GPIO %d: %x\n", gpio, edge); - return; + goto unlock; } writel(val | (edge << (bit << 1)), reg); +unlock: raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); } 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; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5299e5bb76d6..1286b22ef23a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -306,34 +306,31 @@ 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; - 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; - } else if (reg >= 0x54) { + if (reg >= 0x54) { /* * 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. + */ + 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; @@ -464,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: 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, }; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index cec2f2c78255..3de1d3ad7472 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -7,18 +7,16 @@ #include <linux/gpio/driver.h> #include <linux/i2c.h> -#include <linux/platform_data/pcf857x.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/spinlock.h> - static const struct i2c_device_id pcf857x_id[] = { { "pcf8574", 8 }, { "pcf8574a", 8 }, @@ -37,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" }, @@ -55,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 @@ -73,11 +69,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,19 +81,19 @@ 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); } 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 */ -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,10 +115,10 @@ 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; + struct pcf857x *gpio = gpiochip_get_data(chip); + int status; mutex_lock(&gpio->lock); gpio->out |= (1 << offset); @@ -132,20 +128,35 @@ 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; + struct pcf857x *gpio = gpiochip_get_data(chip); + int value; value = gpio->read(gpio->client); return (value < 0) ? value : !!(value & (1 << offset)); } -static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value) +static int pcf857x_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) { - struct pcf857x *gpio = gpiochip_get_data(chip); - unsigned bit = 1 << offset; - int status; + 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); + unsigned int bit = 1 << offset; + int status; mutex_lock(&gpio->lock); if (value) @@ -158,16 +169,28 @@ 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); } +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) { - struct pcf857x *gpio = data; + struct pcf857x *gpio = data; unsigned long change, i, status; status = gpio->read(gpio->client); @@ -250,18 +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 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"); + struct pcf857x *gpio; + unsigned int n_latch = 0; + int status; + + 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); @@ -270,12 +286,14 @@ 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; 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; @@ -377,17 +395,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; @@ -399,16 +406,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); @@ -420,10 +417,9 @@ 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, - .remove = pcf857x_remove, .shutdown = pcf857x_shutdown, .id_table = pcf857x_id, }; diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 6383136cbe59..fca17d478984 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; @@ -249,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) @@ -265,8 +262,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; } 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) diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 60514bc5454f..e5dfd636c63c 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; } @@ -736,7 +736,7 @@ static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) gpiod_remove_hogs(dev->hogs); - for (hog = dev->hogs; !hog->chip_label; hog++) { + for (hog = dev->hogs; hog->chip_label; hog++) { kfree(hog->chip_label); kfree(hog->line_name); } @@ -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; diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index fdc5bdcd5638..14c872b6ad05 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -670,13 +670,14 @@ 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 */ } }; 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++) { @@ -698,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); } } } diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c deleted file mode 100644 index 676adf1f198a..000000000000 --- a/drivers/gpio/gpio-ucb1400.c +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Philips UCB1400 GPIO driver - * - * Author: Marek Vasut <marek.vasut@gmail.com> - */ - -#include <linux/module.h> -#include <linux/ucb1400.h> -#include <linux/gpio/driver.h> - -static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off) -{ - struct ucb1400_gpio *gpio; - gpio = gpiochip_get_data(gc); - ucb1400_gpio_set_direction(gpio->ac97, off, 0); - return 0; -} - -static int ucb1400_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val) -{ - struct ucb1400_gpio *gpio; - gpio = gpiochip_get_data(gc); - ucb1400_gpio_set_direction(gpio->ac97, off, 1); - ucb1400_gpio_set_value(gpio->ac97, off, val); - return 0; -} - -static int ucb1400_gpio_get(struct gpio_chip *gc, unsigned off) -{ - struct ucb1400_gpio *gpio; - - gpio = gpiochip_get_data(gc); - return !!ucb1400_gpio_get_value(gpio->ac97, off); -} - -static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val) -{ - struct ucb1400_gpio *gpio; - gpio = gpiochip_get_data(gc); - ucb1400_gpio_set_value(gpio->ac97, off, val); -} - -static int ucb1400_gpio_probe(struct platform_device *dev) -{ - struct ucb1400_gpio *ucb = dev_get_platdata(&dev->dev); - int err = 0; - - if (!(ucb && ucb->gpio_offset)) { - err = -EINVAL; - goto err; - } - - platform_set_drvdata(dev, ucb); - - ucb->gc.label = "ucb1400_gpio"; - ucb->gc.base = ucb->gpio_offset; - ucb->gc.ngpio = 10; - ucb->gc.owner = THIS_MODULE; - - ucb->gc.direction_input = ucb1400_gpio_dir_in; - ucb->gc.direction_output = ucb1400_gpio_dir_out; - ucb->gc.get = ucb1400_gpio_get; - ucb->gc.set = ucb1400_gpio_set; - ucb->gc.can_sleep = true; - - err = devm_gpiochip_add_data(&dev->dev, &ucb->gc, ucb); - -err: - return err; - -} - -static struct platform_driver ucb1400_gpio_driver = { - .probe = ucb1400_gpio_probe, - .driver = { - .name = "ucb1400_gpio" - }, -}; - -module_platform_driver(ucb1400_gpio_driver); - -MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ucb1400_gpio"); diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 9db42f6a2043..d3f3a69d4907 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -30,7 +30,6 @@ struct fsl_gpio_soc_data { struct vf610_gpio_port { struct gpio_chip gc; - struct irq_chip ic; void __iomem *base; void __iomem *gpio_base; const struct fsl_gpio_soc_data *sdata; @@ -207,20 +206,24 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type) static void vf610_gpio_irq_mask(struct irq_data *d) { - struct vf610_gpio_port *port = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + void __iomem *pcr_base = port->base + PORT_PCR(gpio_num); vf610_gpio_writel(0, pcr_base); + gpiochip_disable_irq(gc, gpio_num); } static void vf610_gpio_irq_unmask(struct irq_data *d) { - struct vf610_gpio_port *port = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct vf610_gpio_port *port = gpiochip_get_data(gc); + irq_hw_number_t gpio_num = irqd_to_hwirq(d); + void __iomem *pcr_base = port->base + PORT_PCR(gpio_num); - vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET, + gpiochip_enable_irq(gc, gpio_num); + vf610_gpio_writel(port->irqc[gpio_num] << PORT_PCR_IRQC_OFFSET, pcr_base); } @@ -237,6 +240,17 @@ static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable) return 0; } +static const struct irq_chip vf610_irqchip = { + .name = "gpio-vf610", + .irq_ack = vf610_gpio_irq_ack, + .irq_mask = vf610_gpio_irq_mask, + .irq_unmask = vf610_gpio_irq_unmask, + .irq_set_type = vf610_gpio_irq_set_type, + .irq_set_wake = vf610_gpio_irq_set_wake, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static void vf610_gpio_disable_clk(void *data) { clk_disable_unprepare(data); @@ -249,7 +263,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) struct vf610_gpio_port *port; struct gpio_chip *gc; struct gpio_irq_chip *girq; - struct irq_chip *ic; int i; int ret; @@ -304,7 +317,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; @@ -315,14 +328,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) gc->direction_output = vf610_gpio_direction_output; gc->set = vf610_gpio_set; - ic = &port->ic; - ic->name = "gpio-vf610"; - ic->irq_ack = vf610_gpio_irq_ack; - ic->irq_mask = vf610_gpio_irq_mask; - ic->irq_unmask = vf610_gpio_irq_unmask; - ic->irq_set_type = vf610_gpio_irq_set_type; - ic->irq_set_wake = vf610_gpio_irq_set_wake; - /* Mask all GPIO interrupts */ for (i = 0; i < gc->ngpio; i++) vf610_gpio_writel(0, port->base + PORT_PCR(i)); @@ -331,7 +336,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) vf610_gpio_writel(~0, port->base + PORT_ISFR); girq = &gc->irq; - girq->chip = ic; + gpio_irq_chip_set_chip(girq, &vf610_irqchip); girq->parent_handler = vf610_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, 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); 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; diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index ce9d1282165c..f0f571b323f2 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -5,13 +5,15 @@ * Author: Fabian Vogt <fabian@ritter-vogt.de> */ -#include <linux/spinlock.h> +#include <linux/bitops.h> #include <linux/errno.h> #include <linux/init.h> -#include <linux/bitops.h> #include <linux/io.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/spinlock.h> + #include <linux/gpio/driver.h> /* @@ -162,7 +164,6 @@ static const struct gpio_chip zevio_gpio_chip = { .base = 0, .owner = THIS_MODULE, .ngpio = 32, - .of_gpio_n_cells = 2, }; /* Initialization */ diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 9ef0f5641b52..d8a421ce26a8 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1104,7 +1104,8 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in dev_dbg(&adev->dev, "IRQ %d already in use\n", irq); } - if (wake_capable) + /* avoid suspend issues with GPIOs when systems are using S3 */ + if (wake_capable && acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) *wake_capable = info.wake_capable; return irq; @@ -1387,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; @@ -1636,6 +1627,18 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_wake = "ELAN0415:00@9", }, }, + { + /* + * Spurious wakeups from TP_ATTN# pin + * Found in BIOS 1.7.7 + */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "SYNA1202:00@16", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h index 9475f99a9694..90fd6b04f24d 100644 --- a/drivers/gpio/gpiolib-acpi.h +++ b/drivers/gpio/gpiolib-acpi.h @@ -14,7 +14,6 @@ #include <linux/gpio/consumer.h> -struct acpi_device; struct device; struct fwnode_handle; @@ -26,8 +25,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 +39,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-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-devres.c b/drivers/gpio/gpiolib-devres.c index 16a696249229..fe9ce6b19f15 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -130,61 +130,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 * @fwnode: firmware node containing GPIO reference diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 4fff7258ee41..266352b1a966 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -23,6 +23,47 @@ #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 + * @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 @@ -50,12 +91,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 <linux/of_gpio.h> - * - * 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; @@ -345,19 +380,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) @@ -389,52 +433,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, @@ -668,7 +666,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); @@ -760,7 +758,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; @@ -970,22 +968,18 @@ 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; - if (!of_property_read_bool(np, "gpio-ranges") && - chip->of_gpio_ranges_fallback) { - return chip->of_gpio_ranges_fallback(chip, np); - } - group_names = of_find_property(np, group_names_propname, NULL); for (;; index++) { @@ -1063,7 +1057,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; @@ -1092,19 +1086,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 bdb9493857eb..19bd23044b01 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,34 +1,35 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/acpi.h> #include <linux/bitmap.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/spinlock.h> -#include <linux/list.h> +#include <linux/compat.h> +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/err.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> +#include <linux/file.h> +#include <linux/fs.h> #include <linux/gpio.h> -#include <linux/idr.h> -#include <linux/slab.h> -#include <linux/acpi.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> +#include <linux/idr.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> #include <linux/pinctrl/consumer.h> -#include <linux/fs.h> -#include <linux/compat.h> -#include <linux/file.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + #include <uapi/linux/gpio.h> -#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 <trace/events/gpio.h> @@ -531,6 +532,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gc) static int gpiochip_add_pin_ranges(struct gpio_chip *gc) { + /* + * Device Tree platforms are supposed to use "gpio-ranges" + * property. This check ensures that the ->add_pin_ranges() + * won't be called for them. + */ + if (device_property_present(&gc->gpiodev->dev, "gpio-ranges")) + return 0; + if (gc->add_pin_ranges) return gc->add_pin_ranges(gc); @@ -666,10 +675,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 @@ -683,14 +694,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) { @@ -889,7 +893,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: @@ -979,7 +983,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); @@ -1133,14 +1137,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", @@ -2070,17 +2068,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) @@ -2141,7 +2137,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" }; |