summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-22 11:01:17 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-22 11:01:17 -0800
commit17bbc46fc9d5128756dc9f36063836eaede06b0b (patch)
tree915ed1db2033a65fee3a2c9c0f105b67cd19af88 /drivers
parent13e574b4941ee1931f8c70f33c3011f74e5fbd30 (diff)
parent4827aae061337251bb91801b316157a78b845ec7 (diff)
downloadlinux-17bbc46fc9d5128756dc9f36063836eaede06b0b.tar.gz
linux-17bbc46fc9d5128756dc9f36063836eaede06b0b.tar.bz2
linux-17bbc46fc9d5128756dc9f36063836eaede06b0b.zip
Merge tag 'gpio-updates-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "A rather small update, there are no new drivers, just improvements and refactoring in existing ones. Thanks to migrating of several drivers to using generalized APIs and dropping of OF interfaces in favor of using software nodes we're actually removing more code than we're adding. Core GPIOLIB: - drop several OF interfaces after moving a significant part of the code to using software nodes - remove more interfaces referring to the global GPIO numberspace that we're getting rid of - improvements in the gpio-regmap library - add helper for GPIO device reference counting - remove unused APIs - minor tweaks like sorting headers alphabetically Extended support in existing drivers: - add support for Tegra 234 PMC to gpio-tegra186 Driver improvements: - migrate the 104-dio/idi family of drivers to using the regmap-irq API - migrate gpio-i8255 and gpio-mm to the GPIO regmap API - clean-ups in gpio-pca953x - remove duplicate assignments of of_gpio_n_cells in gpio-davinci, gpio-ge, gpio-xilinx, gpio-zevio and gpio-wcd934x - improvements to gpio-pcf857x: implement get/set_multiple callbacks, use generic device properties instead of OF + minor tweaks - fix OF-related header includes and Kconfig dependencies in gpio-zevio - dynamically allocate the GPIO base in gpio-omap - use a dedicated printf specifier for printing fwnode info in gpio-sim - use dev_name() for the GPIO chip label in gpio-vf610 - other minor tweaks and fixes Documentation: - remove mentions of legacy API from comments in various places - convert the DT binding documents to YAML schema for Fujitsu MB86S7x, Unisoc GPIO and Unisoc EIC - document the Unisoc UMS512 controller in DT bindings" * tag 'gpio-updates-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (54 commits) gpio: sim: Use %pfwP specifier instead of calling fwnode API directly gpio: tegra186: remove unneeded loop in tegra186_gpio_init_route_mapping() gpiolib: of: Move enum of_gpio_flags to its only user gpio: mvebu: Use IS_REACHABLE instead of IS_ENABLED for CONFIG_PWM gpio: zevio: Add missing header gpio: Get rid of gpio_to_chip() gpio: pcf857x: Drop unneeded explicit casting gpio: pcf857x: Make use of device properties gpio: pcf857x: Get rid of legacy platform data gpio: rockchip: Do not mention legacy API in the code gpio: wcd934x: Remove duplicate assignment of of_gpio_n_cells gpio: zevio: Use proper headers and drop OF_GPIO dependency gpio: zevio: Remove duplicate assignment of of_gpio_n_cells gpio: xilinx: Remove duplicate assignment of of_gpio_n_cells dt-bindings: gpio: Add compatible string for Unisoc UMS512 dt-bindings: gpio: Convert Unisoc EIC controller binding to yaml dt-bindings: gpio: Convert Unisoc GPIO controller binding to yaml gpio: ge: Remove duplicate assignment of of_gpio_n_cells gpio: davinci: Remove duplicate assignment of of_gpio_n_cells gpio: omap: use dynamic allocation of base ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig10
-rw-r--r--drivers/gpio/TODO4
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c398
-rw-r--r--drivers/gpio/gpio-104-idi-48.c336
-rw-r--r--drivers/gpio/gpio-davinci.c3
-rw-r--r--drivers/gpio/gpio-ge.c1
-rw-r--r--drivers/gpio/gpio-gpio-mm.c154
-rw-r--r--drivers/gpio/gpio-i8255.c320
-rw-r--r--drivers/gpio/gpio-i8255.h54
-rw-r--r--drivers/gpio/gpio-msc313.c6
-rw-r--r--drivers/gpio/gpio-mvebu.c6
-rw-r--r--drivers/gpio/gpio-omap.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c34
-rw-r--r--drivers/gpio/gpio-pca9570.c24
-rw-r--r--drivers/gpio/gpio-pcf857x.c118
-rw-r--r--drivers/gpio/gpio-regmap.c17
-rw-r--r--drivers/gpio/gpio-rockchip.c2
-rw-r--r--drivers/gpio/gpio-sim.c9
-rw-r--r--drivers/gpio/gpio-tegra186.c41
-rw-r--r--drivers/gpio/gpio-vf610.c2
-rw-r--r--drivers/gpio/gpio-wcd934x.c1
-rw-r--r--drivers/gpio/gpio-xilinx.c11
-rw-r--r--drivers/gpio/gpio-zevio.c9
-rw-r--r--drivers/gpio/gpiolib-acpi.c10
-rw-r--r--drivers/gpio/gpiolib-acpi.h4
-rw-r--r--drivers/gpio/gpiolib-cdev.c21
-rw-r--r--drivers/gpio/gpiolib-devres.c55
-rw-r--r--drivers/gpio/gpiolib-of.c135
-rw-r--r--drivers/gpio/gpiolib-of.h5
-rw-r--r--drivers/gpio/gpiolib.c70
-rw-r--r--drivers/gpio/gpiolib.h10
-rw-r--r--drivers/pinctrl/core.c14
32 files changed, 632 insertions, 1254 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c85726a6831f..13be729710f2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -752,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.
@@ -821,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
@@ -835,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
@@ -860,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
@@ -883,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.
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_r