All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API
@ 2022-11-03 11:20 William Breathitt Gray
  2022-11-03 11:20 ` [PATCH 1/3] gpio: 104-dio-48e: Migrate " William Breathitt Gray
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: William Breathitt Gray @ 2022-11-03 11:20 UTC (permalink / raw)
  To: linus.walleij, brgl
  Cc: andriy.shevchenko, linux-gpio, linux-kernel, William Breathitt Gray

The regmap API supports IO port accessors so we can take advantage of
regmap abstractions rather than handling access to the device registers
directly in the driver.

Precursor patches are provided for 104-dio-48e and 104-idi-48 to migrate
their respective device-specific registers first in order to simplify
the subsequent patch migrating the i8255 library and its dependents.

The struct i8255 control_state member serves as a cache of the i8255
device's control register. Does the regmap API support caching such that
we won't need to manually update a control_state member?

William Breathitt Gray (3):
  gpio: 104-dio-48e: Migrate to regmap API
  gpio: 104-idi-48: Migrate to regmap API
  gpio: i8255: Migrate to regmap API

 drivers/gpio/gpio-104-dio-48e.c | 200 +++++++++++++++++++----------
 drivers/gpio/gpio-104-idi-48.c  | 110 +++++++++++-----
 drivers/gpio/gpio-gpio-mm.c     |  97 ++++++++++----
 drivers/gpio/gpio-i8255.c       | 218 +++++++++++++++++++++-----------
 drivers/gpio/gpio-i8255.h       |  54 ++++----
 5 files changed, 451 insertions(+), 228 deletions(-)


base-commit: b8b80348c57b360019071e17380298619c5d8066
-- 
2.37.3


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] gpio: 104-dio-48e: Migrate to regmap API
  2022-11-03 11:20 [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API William Breathitt Gray
@ 2022-11-03 11:20 ` William Breathitt Gray
  2022-11-07 10:38   ` Andy Shevchenko
  2022-11-03 11:20 ` [PATCH 2/3] gpio: 104-idi-48: " William Breathitt Gray
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: William Breathitt Gray @ 2022-11-03 11:20 UTC (permalink / raw)
  To: linus.walleij, brgl
  Cc: andriy.shevchenko, linux-gpio, linux-kernel, William Breathitt Gray

The regmap API supports IO port accessors so we can take advantage of
regmap abstractions rather than handling access to the device registers
directly in the driver.

Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 drivers/gpio/gpio-104-dio-48e.c | 95 ++++++++++++++++++++++-----------
 1 file changed, 64 insertions(+), 31 deletions(-)

diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 7b8829c8e423..134e3dd12ae9 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -8,9 +8,9 @@
  */
 #include <linux/bits.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/gpio/driver.h>
-#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/irqdesc.h>
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
@@ -38,30 +39,25 @@ 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_NAME "104-dio-48e"
+
+#define DIO48E_REGS_OFFSET 0x8
+#define DIO48E_ENABLE_BUFFER_GRP0 0x0
+#define DIO48E_ENABLE_BUFFER_GRP1 0x1
+#define DIO48E_ENABLE_INTERRUPT 0x3
+#define DIO48E_DISABLE_INTERRUPT 0x3
+#define DIO48E_ENABLE_COUNTER 0x5
+#define DIO48E_DISABLE_COUNTER 0x5
+#define DIO48E_CLEAR_INTERRUPT 0x7
+
 #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;
 };
 
 /**
@@ -70,6 +66,7 @@ struct dio48e_reg {
  * @ppi_state:		PPI device states
  * @lock:		synchronization lock to prevent I/O race conditions
  * @reg:		I/O address offset for the device registers
+ * @map:		device register map
  * @irq_mask:		I/O bits affected by interrupts
  */
 struct dio48e_gpio {
@@ -77,6 +74,7 @@ struct dio48e_gpio {
 	struct i8255_state ppi_state[DIO48E_NUM_PPI];
 	raw_spinlock_t lock;
 	struct dio48e_reg __iomem *reg;
+	struct regmap *map;
 	unsigned char irq_mask;
 };
 
@@ -154,6 +152,7 @@ static void dio48e_irq_mask(struct irq_data *data)
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
 	const unsigned long offset = irqd_to_hwirq(data);
 	unsigned long flags;
+	unsigned int val;
 
 	/* only bit 3 on each respective Port C supports interrupts */
 	if (offset != 19 && offset != 43)
@@ -168,8 +167,7 @@ static void dio48e_irq_mask(struct irq_data *data)
 	gpiochip_disable_irq(chip, offset);
 
 	if (!dio48egpio->irq_mask)
-		/* disable interrupts */
-		ioread8(&dio48egpio->reg->enable_interrupt);
+		regmap_read(dio48egpio->map, DIO48E_DISABLE_INTERRUPT, &val);
 
 	raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
 }
@@ -188,9 +186,8 @@ static void dio48e_irq_unmask(struct irq_data *data)
 	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);
+		regmap_write(dio48egpio->map, DIO48E_CLEAR_INTERRUPT, 0x00);
+		regmap_write(dio48egpio->map, DIO48E_ENABLE_INTERRUPT, 0x00);
 	}
 
 	gpiochip_enable_irq(chip, offset);
@@ -217,7 +214,7 @@ static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type)
 }
 
 static const struct irq_chip dio48e_irqchip = {
-	.name = "104-dio-48e",
+	.name = DIO48E_NAME,
 	.irq_ack = dio48e_irq_ack,
 	.irq_mask = dio48e_irq_mask,
 	.irq_unmask = dio48e_irq_unmask,
@@ -239,7 +236,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
 
 	raw_spin_lock(&dio48egpio->lock);
 
-	iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
+	regmap_write(dio48egpio->map, DIO48E_CLEAR_INTERRUPT, 0x00);
 
 	raw_spin_unlock(&dio48egpio->lock);
 
@@ -269,11 +266,9 @@ static const char *dio48e_names[DIO48E_NGPIO] = {
 static int dio48e_irq_init_hw(struct gpio_chip *gc)
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc);
+	unsigned int val;
 
-	/* Disable IRQ by default */
-	ioread8(&dio48egpio->reg->enable_interrupt);
-
-	return 0;
+	return regmap_read(dio48egpio->map, DIO48E_DISABLE_INTERRUPT, &val);
 }
 
 static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
@@ -291,10 +286,42 @@ static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
 	}
 }
 
+static const struct regmap_range dio48e_wr_ranges[] = {
+	regmap_reg_range(0x0, 0x1),
+	regmap_reg_range(0x3, 0x3),
+	regmap_reg_range(0x5, 0x5),
+	regmap_reg_range(0x7, 0x7),
+};
+static const struct regmap_range dio48e_rd_ranges[] = {
+	regmap_reg_range(0x3, 0x3),
+	regmap_reg_range(0x5, 0x5),
+	regmap_reg_range(0x7, 0x7),
+};
+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_config dio48e_regmap_config = {
+	.name = DIO48E_NAME,
+	.reg_bits = 8,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.io_port = true,
+	.max_register = 0x7,
+	.wr_table = &dio48e_wr_table,
+	.rd_table = &dio48e_rd_table,
+};
+
 static int dio48e_probe(struct device *dev, unsigned int id)
 {
 	struct dio48e_gpio *dio48egpio;
 	const char *const name = dev_name(dev);
+	void __iomem *regs;
 	struct gpio_irq_chip *girq;
 	int err;
 
@@ -308,9 +335,15 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 		return -EBUSY;
 	}
 
-	dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
-	if (!dio48egpio->reg)
+	regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
+	if (!regs)
 		return -ENOMEM;
+	dio48egpio->reg = regs;
+
+	dio48egpio->map = devm_regmap_init_mmio(dev, regs + DIO48E_REGS_OFFSET,
+						&dio48e_regmap_config);
+	if (IS_ERR(dio48egpio->map))
+		return PTR_ERR(dio48egpio->map);
 
 	dio48egpio->chip.label = name;
 	dio48egpio->chip.parent = dev;
@@ -360,7 +393,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 static struct isa_driver dio48e_driver = {
 	.probe = dio48e_probe,
 	.driver = {
-		.name = "104-dio-48e"
+		.name = DIO48E_NAME,
 	},
 };
 module_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq);
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] gpio: 104-idi-48: Migrate to regmap API
  2022-11-03 11:20 [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API William Breathitt Gray
  2022-11-03 11:20 ` [PATCH 1/3] gpio: 104-dio-48e: Migrate " William Breathitt Gray
@ 2022-11-03 11:20 ` William Breathitt Gray
  2022-11-03 11:20 ` [PATCH 3/3] gpio: i8255: " William Breathitt Gray
  2022-11-07 10:37 ` [PATCH 0/3] Migrate i8255 GPIO drivers " Andy Shevchenko
  3 siblings, 0 replies; 8+ messages in thread
From: William Breathitt Gray @ 2022-11-03 11:20 UTC (permalink / raw)
  To: linus.walleij, brgl
  Cc: andriy.shevchenko, linux-gpio, linux-kernel, William Breathitt Gray

The regmap API supports IO port accessors so we can take advantage of
regmap abstractions rather than handling access to the device registers
directly in the driver.

Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 drivers/gpio/gpio-104-idi-48.c | 54 ++++++++++++++++++++++++----------
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index c5e231fde1af..5d9de5b5e7af 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -8,9 +8,9 @@
  */
 #include <linux/bits.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/gpio/driver.h>
-#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/irqdesc.h>
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
@@ -43,22 +44,27 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
  * @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_NAME "104-idi-48"
+
+#define IDI48_REGS_OFFSET 0x3
+#define IDI48_IRQ_STATUS 0x0
+#define IDI48_IRQ_CLEAR 0x0
+#define IDI48_IRQ_ENABLE 0x0
+
 /**
  * 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
+ * @map:	device register map
  * @cos_enb:	Change-Of-State IRQ enable boundaries mask
  */
 struct idi_48_gpio {
@@ -66,6 +72,7 @@ struct idi_48_gpio {
 	spinlock_t lock;
 	unsigned char irq_mask[6];
 	struct idi_48_reg __iomem *reg;
+	struct regmap *map;
 	unsigned char cos_enb;
 };
 
@@ -122,7 +129,7 @@ static void idi_48_irq_mask(struct irq_data *data)
 
 	idi48gpio->cos_enb &= ~BIT(boundary);
 
-	iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
+	regmap_write(idi48gpio->map, IDI48_IRQ_ENABLE, idi48gpio->cos_enb);
 
 exit:
 	spin_unlock_irqrestore(&idi48gpio->lock, flags);
@@ -151,7 +158,7 @@ static void idi_48_irq_unmask(struct irq_data *data)
 
 	idi48gpio->cos_enb |= BIT(boundary);
 
-	iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
+	regmap_write(idi48gpio->map, IDI48_IRQ_ENABLE, idi48gpio->cos_enb);
 
 exit:
 	spin_unlock_irqrestore(&idi48gpio->lock, flags);
@@ -168,7 +175,7 @@ static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
 }
 
 static const struct irq_chip idi_48_irqchip = {
-	.name = "104-idi-48",
+	.name = IDI48_NAME,
 	.irq_ack = idi_48_irq_ack,
 	.irq_mask = idi_48_irq_mask,
 	.irq_unmask = idi_48_irq_unmask,
@@ -180,6 +187,7 @@ static const struct irq_chip idi_48_irqchip = {
 static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
 {
 	struct idi_48_gpio *const idi48gpio = dev_id;
+	unsigned int irq_status;
 	unsigned long cos_status;
 	unsigned long boundary;
 	unsigned long irq_mask;
@@ -189,7 +197,8 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
 
 	spin_lock(&idi48gpio->lock);
 
-	cos_status = ioread8(&idi48gpio->reg->irq);
+	regmap_read(idi48gpio->map, IDI48_IRQ_STATUS, &irq_status);
+	cos_status = irq_status;
 
 	/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
 	if (cos_status & BIT(6)) {
@@ -231,18 +240,27 @@ static const char *idi48_names[IDI48_NGPIO] = {
 static int idi_48_irq_init_hw(struct gpio_chip *gc)
 {
 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
+	unsigned int val;
 
 	/* Disable IRQ by default */
-	iowrite8(0, &idi48gpio->reg->irq);
-	ioread8(&idi48gpio->reg->irq);
-
-	return 0;
+	regmap_write(idi48gpio->map, IDI48_IRQ_ENABLE, 0x00);
+	return regmap_read(idi48gpio->map, IDI48_IRQ_CLEAR, &val);
 }
 
+static const struct regmap_config idi48_regmap_config = {
+	.name = IDI48_NAME,
+	.reg_bits = 8,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.io_port = true,
+	.max_register = 0x0,
+};
+
 static int idi_48_probe(struct device *dev, unsigned int id)
 {
 	struct idi_48_gpio *idi48gpio;
 	const char *const name = dev_name(dev);
+	void __iomem *regs;
 	struct gpio_irq_chip *girq;
 	int err;
 
@@ -256,9 +274,15 @@ static int idi_48_probe(struct device *dev, unsigned int id)
 		return -EBUSY;
 	}
 
-	idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
-	if (!idi48gpio->reg)
+	regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
+	if (!regs)
 		return -ENOMEM;
+	idi48gpio->reg = regs;
+
+	idi48gpio->map = devm_regmap_init_mmio(dev, regs + IDI48_REGS_OFFSET,
+					       &idi48_regmap_config);
+	if (IS_ERR(idi48gpio->map))
+		return PTR_ERR(idi48gpio->map);
 
 	idi48gpio->chip.label = name;
 	idi48gpio->chip.parent = dev;
@@ -302,7 +326,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
 static struct isa_driver idi_48_driver = {
 	.probe = idi_48_probe,
 	.driver = {
-		.name = "104-idi-48"
+		.name = IDI48_NAME,
 	},
 };
 module_isa_driver_with_irq(idi_48_driver, num_idi_48, num_irq);
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] gpio: i8255: Migrate to regmap API
  2022-11-03 11:20 [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API William Breathitt Gray
  2022-11-03 11:20 ` [PATCH 1/3] gpio: 104-dio-48e: Migrate " William Breathitt Gray
  2022-11-03 11:20 ` [PATCH 2/3] gpio: 104-idi-48: " William Breathitt Gray
@ 2022-11-03 11:20 ` William Breathitt Gray
  2022-11-07 10:37 ` [PATCH 0/3] Migrate i8255 GPIO drivers " Andy Shevchenko
  3 siblings, 0 replies; 8+ messages in thread
From: William Breathitt Gray @ 2022-11-03 11:20 UTC (permalink / raw)
  To: linus.walleij, brgl
  Cc: andriy.shevchenko, linux-gpio, linux-kernel, William Breathitt Gray

The regmap API supports IO port accessors so we can take advantage of
regmap abstractions rather than handling access to the device registers
directly in the driver. The 104-dio-48e, 104-idi-48, and gpio-mm modules
depend on the i8255 library and are thus updated accordingly.

The struct i8255_state data structure is removed and its role merged
into the struct i8255 data structure which is updated to hold regmap
register maps. Similarly, the i8255_state_init() function is repurposed
to the i8255_init() function; the other i8255 library functions are
adjusted to utilize the regmap API. The I8255_REGMAP_CONFIG macro is
introduced to facilitate the initialization of struct regmap_config
data structures for i8255 register mappings.

Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
---
 drivers/gpio/gpio-104-dio-48e.c | 111 ++++++++++------
 drivers/gpio/gpio-104-idi-48.c  |  60 ++++++---
 drivers/gpio/gpio-gpio-mm.c     |  97 ++++++++++----
 drivers/gpio/gpio-i8255.c       | 218 +++++++++++++++++++++-----------
 drivers/gpio/gpio-i8255.h       |  54 ++++----
 5 files changed, 353 insertions(+), 187 deletions(-)

diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 134e3dd12ae9..e460d66800cb 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -52,28 +52,18 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
 
 #define DIO48E_NUM_PPI 2
 
-/**
- * struct dio48e_reg - device register structure
- * @ppi:		Programmable Peripheral Interface groups
- */
-struct dio48e_reg {
-	struct i8255 ppi[DIO48E_NUM_PPI];
-};
-
 /**
  * struct dio48e_gpio - GPIO device private data structure
  * @chip:		instance of the gpio_chip
- * @ppi_state:		PPI device states
+ * @ppi:		Programmable Peripheral Interface device structures
  * @lock:		synchronization lock to prevent I/O race conditions
- * @reg:		I/O address offset for the device registers
  * @map:		device register map
  * @irq_mask:		I/O bits affected by interrupts
  */
 struct dio48e_gpio {
 	struct gpio_chip chip;
-	struct i8255_state ppi_state[DIO48E_NUM_PPI];
+	struct i8255 ppi[DIO48E_NUM_PPI];
 	raw_spinlock_t lock;
-	struct dio48e_reg __iomem *reg;
 	struct regmap *map;
 	unsigned char irq_mask;
 };
@@ -82,7 +72,7 @@ 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))
+	if (i8255_get_direction(dio48egpio->ppi, offset))
 		return GPIO_LINE_DIRECTION_IN;
 
 	return GPIO_LINE_DIRECTION_OUT;
@@ -92,10 +82,7 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offs
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
 
-	i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state,
-			      offset);
-
-	return 0;
+	return i8255_direction_input(dio48egpio->ppi, offset);
 }
 
 static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
@@ -103,17 +90,20 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
 
-	i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state,
-			       offset, value);
-
-	return 0;
+	return i8255_direction_output(dio48egpio->ppi, offset, value);
 }
 
 static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
+	bool value;
+	int err;
 
-	return i8255_get(dio48egpio->reg->ppi, offset);
+	err = i8255_get(dio48egpio->ppi, offset, &value);
+	if (err)
+		return err;
+
+	return value;
 }
 
 static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
@@ -121,25 +111,32 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
 
-	i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio);
-
-	return 0;
+	return i8255_get_multiple(dio48egpio->ppi, mask, bits, chip->ngpio);
 }
 
 static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
+	int err;
 
-	i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value);
+	err = i8255_set(dio48egpio->ppi, offset, value);
+	if (err)
+		dev_warn(chip->parent,
+			 "Unable to set GPIO offset %u to value %d (errno %d)\n",
+			 offset, value, err);
 }
 
 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);
+	int err;
 
-	i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask,
-			   bits, chip->ngpio);
+	err = i8255_set_multiple(dio48egpio->ppi, mask, bits, chip->ngpio);
+	if (err)
+		dev_warn(chip->parent,
+			 "Unable to set GPIO with mask %lu and bits %lu (errno %d)\n",
+			 *mask, *bits, err);
 }
 
 static void dio48e_irq_ack(struct irq_data *data)
@@ -271,19 +268,52 @@ static int dio48e_irq_init_hw(struct gpio_chip *gc)
 	return regmap_read(dio48egpio->map, DIO48E_DISABLE_INTERRUPT, &val);
 }
 
-static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
-			    struct i8255_state *const ppi_state)
+static const struct regmap_range dio48e_ppi_rd_ranges[] = {
+	regmap_reg_range(0x0, 0x2),
+};
+static const struct regmap_access_table dio48e_ppi_rd_table = {
+	.yes_ranges = dio48e_ppi_rd_ranges,
+	.n_yes_ranges = ARRAY_SIZE(dio48e_ppi_rd_ranges),
+};
+
+static int devm_dio48e_init_ppi_maps(struct device *const dev,
+				     struct regmap **const maps,
+				     void __iomem *const regs)
+{
+	struct regmap_config config = I8255_REGMAP_CONFIG;
+	unsigned long i;
+
+	config.io_port = true;
+	config.rd_table = &dio48e_ppi_rd_table;
+
+	for (i = 0; i < DIO48E_NUM_PPI; i++) {
+		maps[i] = devm_regmap_init_mmio(dev, regs + i * 4, &config);
+		if (IS_ERR(maps[i]))
+			return PTR_ERR(maps[i]);
+	}
+
+	return 0;
+}
+
+static int dio48e_init_ppi(struct i8255 *const ppi)
 {
 	const unsigned long ngpio = 24;
 	const unsigned long mask = GENMASK(ngpio - 1, 0);
 	const unsigned long bits = 0;
 	unsigned long i;
+	int err;
 
 	/* 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);
+		err = i8255_mode0_output(&ppi[i]);
+		if (err)
+			return err;
+		err = i8255_set_multiple(&ppi[i], &mask, &bits, ngpio);
+		if (err)
+			return err;
 	}
+
+	return 0;
 }
 
 static const struct regmap_range dio48e_wr_ranges[] = {
@@ -322,6 +352,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 	struct dio48e_gpio *dio48egpio;
 	const char *const name = dev_name(dev);
 	void __iomem *regs;
+	struct regmap *ppi_maps[DIO48E_NUM_PPI];
 	struct gpio_irq_chip *girq;
 	int err;
 
@@ -338,7 +369,18 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 	regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
 	if (!regs)
 		return -ENOMEM;
-	dio48egpio->reg = regs;
+
+	err = devm_dio48e_init_ppi_maps(dev, ppi_maps, regs);
+	if (err) {
+		dev_err(dev, "Regmaps initialization failed (%d)\n", err);
+		return err;
+	}
+	i8255_init(dio48egpio->ppi, DIO48E_NUM_PPI, ppi_maps);
+	err = dio48e_init_ppi(dio48egpio->ppi);
+	if (err) {
+		dev_err(dev, "PPI initialization failed (%d)\n", err);
+		return err;
+	}
 
 	dio48egpio->map = devm_regmap_init_mmio(dev, regs + DIO48E_REGS_OFFSET,
 						&dio48e_regmap_config);
@@ -371,9 +413,6 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 
 	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);
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 5d9de5b5e7af..e44dfbb68142 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -39,18 +39,6 @@ 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
- */
-struct idi_48_reg {
-	u8 port0[3];
-	u8 unused;
-	u8 port1[3];
-};
-
 #define IDI48_NAME "104-idi-48"
 
 #define IDI48_REGS_OFFSET 0x3
@@ -58,12 +46,14 @@ struct idi_48_reg {
 #define IDI48_IRQ_CLEAR 0x0
 #define IDI48_IRQ_ENABLE 0x0
 
+#define IDI48_NUM_PPI 2
+
 /**
  * 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
+ * @ppi:	Programmable Peripheral Interface device structures
  * @map:	device register map
  * @cos_enb:	Change-Of-State IRQ enable boundaries mask
  */
@@ -71,7 +61,7 @@ struct idi_48_gpio {
 	struct gpio_chip chip;
 	spinlock_t lock;
 	unsigned char irq_mask[6];
-	struct idi_48_reg __iomem *reg;
+	struct i8255 ppi[IDI48_NUM_PPI];
 	struct regmap *map;
 	unsigned char cos_enb;
 };
@@ -89,20 +79,22 @@ static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offs
 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;
+	bool value;
+	int err;
 
-	return i8255_get(ppi, offset);
+	err = i8255_get(idi48gpio->ppi, offset, &value);
+	if (err)
+		return err;
+
+	return value;
 }
 
 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);
 
-	return 0;
+	return i8255_get_multiple(idi48gpio->ppi, mask, bits, chip->ngpio);
 }
 
 static void idi_48_irq_ack(struct irq_data *data)
@@ -237,6 +229,25 @@ 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 devm_idi_48_init_ppi_maps(struct device *const dev,
+				     struct regmap **const maps,
+				     void __iomem *const regs)
+{
+	struct regmap_config config = I8255_REGMAP_CONFIG;
+	unsigned long i;
+
+	config.io_port = true;
+	config.max_register = 0x2;
+
+	for (i = 0; i < IDI48_NUM_PPI; i++) {
+		maps[i] = devm_regmap_init_mmio(dev, regs + i * 4, &config);
+		if (IS_ERR(maps[i]))
+			return PTR_ERR(maps[i]);
+	}
+
+	return 0;
+}
+
 static int idi_48_irq_init_hw(struct gpio_chip *gc)
 {
 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
@@ -261,6 +272,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
 	struct idi_48_gpio *idi48gpio;
 	const char *const name = dev_name(dev);
 	void __iomem *regs;
+	struct regmap *ppi_maps[IDI48_NUM_PPI];
 	struct gpio_irq_chip *girq;
 	int err;
 
@@ -277,7 +289,13 @@ static int idi_48_probe(struct device *dev, unsigned int id)
 	regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
 	if (!regs)
 		return -ENOMEM;
-	idi48gpio->reg = regs;
+
+	err = devm_idi_48_init_ppi_maps(dev, ppi_maps, regs);
+	if (err) {
+		dev_err(dev, "Regmaps initialization failed (%d)\n", err);
+		return err;
+	}
+	i8255_init(idi48gpio->ppi, IDI48_NUM_PPI, ppi_maps);
 
 	idi48gpio->map = devm_regmap_init_mmio(dev, regs + IDI48_REGS_OFFSET,
 					       &idi48_regmap_config);
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
index 2689671b6b01..2efcf63fb0f6 100644
--- a/drivers/gpio/gpio-gpio-mm.c
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -33,13 +33,11 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
 /**
  * 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
+ * @ppi:		Programmable Peripheral Interface device structures
  */
 struct gpiomm_gpio {
 	struct gpio_chip chip;
-	struct i8255_state ppi_state[GPIOMM_NUM_PPI];
-	struct i8255 __iomem *ppi;
+	struct i8255 ppi[GPIOMM_NUM_PPI];
 };
 
 static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
@@ -47,7 +45,7 @@ static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
 {
 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
 
-	if (i8255_get_direction(gpiommgpio->ppi_state, offset))
+	if (i8255_get_direction(gpiommgpio->ppi, offset))
 		return GPIO_LINE_DIRECTION_IN;
 
 	return GPIO_LINE_DIRECTION_OUT;
@@ -58,9 +56,7 @@ static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
 {
 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
 
-	i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
-
-	return 0;
+	return i8255_direction_input(gpiommgpio->ppi, offset);
 }
 
 static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
@@ -68,17 +64,20 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
 {
 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
 
-	i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
-			       value);
-
-	return 0;
+	return i8255_direction_output(gpiommgpio->ppi, offset, value);
 }
 
 static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+	bool value;
+	int err;
+
+	err = i8255_get(gpiommgpio->ppi, offset, &value);
+	if (err)
+		return err;
 
-	return i8255_get(gpiommgpio->ppi, offset);
+	return value;
 }
 
 static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
@@ -86,26 +85,33 @@ static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
 {
 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
 
-	i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
-
-	return 0;
+	return i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
 }
 
 static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+	int err;
 
-	i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
+	err = i8255_set(gpiommgpio->ppi, offset, value);
+	if (err)
+		dev_warn(chip->parent,
+			 "Unable to set GPIO offset %u to value %d (errno %d)\n",
+			 offset, value, err);
 }
 
 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);
+	int err;
 
-	i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
-			   chip->ngpio);
+	err = i8255_set_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
+	if (err)
+		dev_warn(chip->parent,
+			 "Unable to set GPIO with mask %lu and bits %lu (errno %d)\n",
+			 *mask, *bits, err);
 }
 
 #define GPIOMM_NGPIO 48
@@ -120,25 +126,51 @@ 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)
+static int devm_gpiomm_init_ppi_maps(struct device *const dev,
+				     struct regmap **const maps,
+				     void __iomem *const regs)
+{
+	struct regmap_config config = I8255_REGMAP_CONFIG;
+	unsigned long i;
+
+	config.io_port = true;
+
+	for (i = 0; i < GPIOMM_NUM_PPI; i++) {
+		maps[i] = devm_regmap_init_mmio(dev, regs + i * 4, &config);
+		if (IS_ERR(maps[i]))
+			return PTR_ERR(maps[i]);
+	}
+
+	return 0;
+}
+
+static int gpiomm_init_dio(struct i8255 *const ppi)
 {
 	const unsigned long ngpio = 24;
 	const unsigned long mask = GENMASK(ngpio - 1, 0);
 	const unsigned long bits = 0;
 	unsigned long i;
+	int err;
 
 	/* 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);
+		err = i8255_mode0_output(&ppi[i]);
+		if (err)
+			return err;
+		err = i8255_set_multiple(&ppi[i], &mask, &bits, ngpio);
+		if (err)
+			return err;
 	}
+
+	return 0;
 }
 
 static int gpiomm_probe(struct device *dev, unsigned int id)
 {
 	struct gpiomm_gpio *gpiommgpio;
 	const char *const name = dev_name(dev);
+	void __iomem *regs;
+	struct regmap *ppi_maps[GPIOMM_NUM_PPI];
 	int err;
 
 	gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
@@ -151,10 +183,22 @@ 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;
 
+	err = devm_gpiomm_init_ppi_maps(dev, ppi_maps, regs);
+	if (err) {
+		dev_err(dev, "Regmaps initialization failed (%d)\n", err);
+		return err;
+	}
+	i8255_init(gpiommgpio->ppi, GPIOMM_NUM_PPI, ppi_maps);
+	err = gpiomm_init_dio(gpiommgpio->ppi);
+	if (err) {
+		dev_err(dev, "PPI initialization failed (%d)\n", err);
+		return err;
+	}
+
 	gpiommgpio->chip.label = name;
 	gpiommgpio->chip.parent = dev;
 	gpiommgpio->chip.owner = THIS_MODULE;
@@ -169,9 +213,6 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
 	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);
diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c
index 9b97db418df1..5ff8d90c0fe3 100644
--- a/drivers/gpio/gpio-i8255.c
+++ b/drivers/gpio/gpio-i8255.c
@@ -6,8 +6,8 @@
 #include <linux/bitmap.h>
 #include <linux/err.h>
 #include <linux/export.h>
-#include <linux/io.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
@@ -21,14 +21,22 @@
 #define I8255_PORTA 0
 #define I8255_PORTB 1
 #define I8255_PORTC 2
+#define I8255_CONTROL 3
 
-static int i8255_get_port(struct i8255 __iomem *const ppi,
-			  const unsigned long io_port, const unsigned long mask)
+static int i8255_get_port(struct i8255 *const ppi, const unsigned long io_port,
+			  const unsigned long mask, unsigned int *val)
 {
 	const unsigned long bank = io_port / 3;
 	const unsigned long ppi_port = io_port % 3;
+	int err;
 
-	return ioread8(&ppi[bank].port[ppi_port]) & mask;
+	err = regmap_read(ppi[bank].map, ppi_port, val);
+	if (err)
+		return err;
+
+	*val &= mask;
+
+	return 0;
 }
 
 static u8 i8255_direction_mask(const unsigned long offset)
@@ -53,85 +61,90 @@ 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_set_port(struct i8255 *const ppi, const unsigned long io_port,
+			  const unsigned long mask, const unsigned long bits)
 {
 	const unsigned long bank = io_port / 3;
 	const unsigned long ppi_port = io_port % 3;
-	unsigned long flags;
-	unsigned long out_state;
+	unsigned int out_state;
+	int err;
 
-	spin_lock_irqsave(&state[bank].lock, flags);
+	err = regmap_read(ppi[bank].map, ppi_port, &out_state);
+	if (err)
+		return err;
 
-	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);
+	return regmap_write(ppi[bank].map, ppi_port, out_state);
 }
 
 /**
  * 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.
+ * Programmable Peripheral Interface (@ppi) banks. Returns 0 on success and
+ * negative error number on failure.
  */
-void i8255_direction_input(struct i8255 __iomem *const ppi,
-			   struct i8255_state *const state,
-			   const unsigned long offset)
+int i8255_direction_input(struct i8255 *const ppi, const unsigned long offset)
 {
 	const unsigned long io_port = offset / 8;
 	const unsigned long bank = io_port / 3;
 	unsigned long flags;
+	int err;
 
-	spin_lock_irqsave(&state[bank].lock, flags);
+	spin_lock_irqsave(&ppi[bank].lock, flags);
 
-	state[bank].control_state |= I8255_CONTROL_MODE_SET;
-	state[bank].control_state |= i8255_direction_mask(offset);
+	ppi[bank].control_state |= I8255_CONTROL_MODE_SET;
+	ppi[bank].control_state |= i8255_direction_mask(offset);
 
-	iowrite8(state[bank].control_state, &ppi[bank].control);
+	err = regmap_write(ppi[bank].map, I8255_CONTROL,
+			   ppi[bank].control_state);
+	if (err) {
+		spin_unlock_irqrestore(&ppi[bank].lock, flags);
+		return err;
+	}
+
+	spin_unlock_irqrestore(&ppi[bank].lock, flags);
 
-	spin_unlock_irqrestore(&state[bank].lock, flags);
+	return 0;
 }
 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.
+ * output to the desired @value. Returns 0 on success and negative error number
+ * on failure.
  */
-void i8255_direction_output(struct i8255 __iomem *const ppi,
-			    struct i8255_state *const state,
-			    const unsigned long offset,
-			    const unsigned long value)
+int i8255_direction_output(struct i8255 *const ppi, 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;
+	int err;
 
-	spin_lock_irqsave(&state[bank].lock, flags);
+	spin_lock_irqsave(&ppi[bank].lock, flags);
 
-	state[bank].control_state |= I8255_CONTROL_MODE_SET;
-	state[bank].control_state &= ~i8255_direction_mask(offset);
+	ppi[bank].control_state |= I8255_CONTROL_MODE_SET;
+	ppi[bank].control_state &= ~i8255_direction_mask(offset);
 
-	iowrite8(state[bank].control_state, &ppi[bank].control);
+	err = regmap_write(ppi[bank].map, I8255_CONTROL,
+			   ppi[bank].control_state);
+	if (err) {
+		spin_unlock_irqrestore(&ppi[bank].lock, flags);
+		return err;
+	}
 
-	spin_unlock_irqrestore(&state[bank].lock, flags);
+	spin_unlock_irqrestore(&ppi[bank].lock, flags);
 
-	i8255_set(ppi, state, offset, value);
+	return i8255_set(ppi, offset, value);
 }
 EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255);
 
@@ -139,16 +152,28 @@ 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
+ * @value:	pointer to store read signal value
  *
- * Returns the signal value (0=low, 1=high) for the signal at @offset for the
- * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
+ * Gets the signal value for the signal at @offset for the
+ * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks and
+ * stores it at the location pointed to by @value. Returns 0 on success and
+ * negative error number on failure.
  */
-int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset)
+int i8255_get(struct i8255 *const ppi, const unsigned long offset,
+	      bool *const value)
 {
 	const unsigned long io_port = offset / 8;
 	const unsigned long offset_mask = BIT(offset % 8);
+	unsigned int port_val;
+	int err;
 
-	return !!i8255_get_port(ppi, io_port, offset_mask);
+	err = i8255_get_port(ppi, io_port, offset_mask, &port_val);
+	if (err)
+		return err;
+
+	*value = port_val;
+
+	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
 
@@ -159,13 +184,13 @@ EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
  *
  * Returns the signal direction (0=output, 1=input) for the signal at @offset.
  */
-int i8255_get_direction(const struct i8255_state *const state,
+int i8255_get_direction(const struct i8255 *const ppi,
 			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));
+	return !!(ppi[bank].control_state & i8255_direction_mask(offset));
 }
 EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
 
@@ -178,24 +203,29 @@ EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
  *
  * 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.
+ * Returns 0 on success and negative error number on failure.
  */
-void i8255_get_multiple(struct i8255 __iomem *const ppi,
-			const unsigned long *const mask,
-			unsigned long *const bits, const unsigned long ngpio)
+int i8255_get_multiple(struct i8255 *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;
+	unsigned int port_state;
+	int err;
 
 	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);
+		err = i8255_get_port(ppi, io_port, port_mask, &port_state);
+		if (err)
+			return err;
 
 		bitmap_set_value8(bits, port_state, offset);
 	}
+
+	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
 
@@ -204,83 +234,123 @@ EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
  * @ppi:	Intel 8255 Programmable Peripheral Interface bank
  *
  * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to
- * MODE 0 (Basic Input/Output) output mode.
+ * MODE 0 (Basic Input/Output) output mode. Returns 0 on success and negative
+ * error number on failure.
  */
-void i8255_mode0_output(struct i8255 __iomem *const ppi)
+int i8255_mode0_output(struct i8255 *const ppi)
 {
-	iowrite8(I8255_CONTROL_MODE_SET, &ppi->control);
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&ppi->lock, flags);
+
+	err = regmap_write(ppi->map, I8255_CONTROL, I8255_CONTROL_MODE_SET);
+	if (err) {
+		spin_unlock_irqrestore(&ppi->lock, flags);
+		return err;
+	}
+
+	spin_unlock_irqrestore(&ppi->lock, flags);
+
+	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255);
 
 /**
  * i8255_set - set signal value at signal offset
  * @ppi:	Intel 8255 Programmable Peripheral Interface banks
- * @state:	devices states of the respective PPI banks
  * @offset:	offset of signal to set
  * @value:	value of signal to set
  *
  * Assigns output @value for the signal at @offset for the respective Intel 8255
- * Programmable Peripheral Interface (@ppi) banks.
+ * Programmable Peripheral Interface (@ppi) banks. Returns 0 on success and
+ * negative error number on failure.
  */
-void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state,
-	       const unsigned long offset, const unsigned long value)
+int i8255_set(struct i8255 *const ppi, 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;
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&ppi->lock, flags);
 
-	i8255_set_port(ppi, state, io_port, mask, bits);
+	err = i8255_set_port(ppi, io_port, mask, bits);
+	if (err) {
+		spin_unlock_irqrestore(&ppi->lock, flags);
+		return err;
+	}
+
+	spin_unlock_irqrestore(&ppi->lock, flags);
+
+	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(i8255_set, I8255);
 
 /**
  * i8255_set_multiple - set signal values at multiple signal offsets
  * @ppi:	Intel 8255 Programmable Peripheral Interface banks
- * @state:	devices states of the respective PPI banks
  * @mask:	mask of signals to set
  * @bits:	bitmap of signal output values
  * @ngpio:	number of GPIO signals of the respective PPI banks
  *
  * Assigns output values defined by @bits for the signals defined by @mask for
  * the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
+ * Returns 0 on success and negative error number on failure.
  */
-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)
+int i8255_set_multiple(struct i8255 *const ppi, 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;
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&ppi->lock, flags);
 
 	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);
+
+		err = i8255_set_port(ppi, io_port, port_mask, value);
+		if (err) {
+			spin_unlock_irqrestore(&ppi->lock, flags);
+			return err;
+		}
 	}
+
+	spin_unlock_irqrestore(&ppi->lock, flags);
+
+	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255);
 
 /**
- * i8255_state_init - initialize i8255_state structure
- * @state:	devices states of the respective PPI banks
+ * i8255_init - initialize i8255 device structures
+ * @ppi:	Intel 8255 Programmable Peripheral Interface banks
  * @nbanks:	number of Intel 8255 Programmable Peripheral Interface banks
+ * @maps:	array of regmaps for respective PPI banks
  *
- * Initializes the @state of each Intel 8255 Programmable Peripheral Interface
- * bank for use in i8255 library functions.
+ * Initializes the Intel 8255 Programmable Peripheral Interface device structure
+ * (@ppi) for use in i8255 library functions.
  */
-void i8255_state_init(struct i8255_state *const state,
-		      const unsigned long nbanks)
+void i8255_init(struct i8255 *const ppi, const unsigned long nbanks,
+		struct regmap **const maps)
 {
 	unsigned long bank;
 
-	for (bank = 0; bank < nbanks; bank++)
-		spin_lock_init(&state[bank].lock);
+	for (bank = 0; bank < nbanks; bank++) {
+		ppi[bank].map = maps[bank];
+		spin_lock_init(&ppi[bank].lock);
+	}
 }
-EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255);
+EXPORT_SYMBOL_NS_GPL(i8255_init, 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..f0773ae458c8 100644
--- a/drivers/gpio/gpio-i8255.h
+++ b/drivers/gpio/gpio-i8255.h
@@ -3,44 +3,42 @@
 #ifndef _I8255_H_
 #define _I8255_H_
 
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
 /**
- * struct i8255 - Intel 8255 register structure
- * @port:	Port A, B, and C
- * @control:	Control register
- */
-struct i8255 {
-	u8 port[3];
-	u8 control;
-};
-
-/**
- * struct i8255_state - Intel 8255 state structure
+ * struct i8255 - Intel 8255 device structure
+ * @map:		device register map
  * @lock:		synchronization lock for accessing device state
  * @control_state:	Control register state
  */
-struct i8255_state {
+struct i8255 {
+	struct regmap *map;
 	spinlock_t lock;
 	u8 control_state;
 };
 
-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 i8255_direction_input(struct i8255 *ppi, unsigned long offset);
+int i8255_direction_output(struct i8255 *ppi, unsigned long offset,
+			   unsigned long value);
+int i8255_get(struct i8255 *ppi, unsigned long offset, bool *value);
+int i8255_get_direction(const struct i8255 *ppi, unsigned long offset);
+int i8255_get_multiple(struct i8255 *ppi, const unsigned long *mask,
+		       unsigned long *bits, unsigned long ngpio);
+int i8255_mode0_output(struct i8255 *ppi);
+int i8255_set(struct i8255 *ppi, unsigned long offset, unsigned long value);
+int i8255_set_multiple(struct i8255 *ppi, const unsigned long *mask,
+		       const unsigned long *bits, unsigned long ngpio);
+void i8255_init(struct i8255 *ppi, unsigned long nbanks, struct regmap **maps);
+
+#define I8255_REGMAP_CONFIG \
+{ \
+	.name = "i8255", \
+	.reg_bits = 8, \
+	.val_bits = 8, \
+	.reg_stride = 1, \
+	.max_register = 0x3, \
+}
 
 #endif /* _I8255_H_ */
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API
  2022-11-03 11:20 [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API William Breathitt Gray
                   ` (2 preceding siblings ...)
  2022-11-03 11:20 ` [PATCH 3/3] gpio: i8255: " William Breathitt Gray
@ 2022-11-07 10:37 ` Andy Shevchenko
  2022-11-09 20:35   ` William Breathitt Gray
  3 siblings, 1 reply; 8+ messages in thread
From: Andy Shevchenko @ 2022-11-07 10:37 UTC (permalink / raw)
  To: William Breathitt Gray; +Cc: linus.walleij, brgl, linux-gpio, linux-kernel

On Thu, Nov 03, 2022 at 07:20:46AM -0400, William Breathitt Gray wrote:
> The regmap API supports IO port accessors so we can take advantage of
> regmap abstractions rather than handling access to the device registers
> directly in the driver.
> 
> Precursor patches are provided for 104-dio-48e and 104-idi-48 to migrate
> their respective device-specific registers first in order to simplify
> the subsequent patch migrating the i8255 library and its dependents.
> 
> The struct i8255 control_state member serves as a cache of the i8255
> device's control register. Does the regmap API support caching such that
> we won't need to manually update a control_state member?

Yes, regmap supports caching and IIRC it's opt-out.

> William Breathitt Gray (3):
>   gpio: 104-dio-48e: Migrate to regmap API
>   gpio: 104-idi-48: Migrate to regmap API
>   gpio: i8255: Migrate to regmap API
> 
>  drivers/gpio/gpio-104-dio-48e.c | 200 +++++++++++++++++++----------
>  drivers/gpio/gpio-104-idi-48.c  | 110 +++++++++++-----
>  drivers/gpio/gpio-gpio-mm.c     |  97 ++++++++++----
>  drivers/gpio/gpio-i8255.c       | 218 +++++++++++++++++++++-----------
>  drivers/gpio/gpio-i8255.h       |  54 ++++----
>  5 files changed, 451 insertions(+), 228 deletions(-)
> 
> 
> base-commit: b8b80348c57b360019071e17380298619c5d8066
> -- 
> 2.37.3
> 

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] gpio: 104-dio-48e: Migrate to regmap API
  2022-11-03 11:20 ` [PATCH 1/3] gpio: 104-dio-48e: Migrate " William Breathitt Gray
@ 2022-11-07 10:38   ` Andy Shevchenko
  2022-11-09 20:47     ` William Breathitt Gray
  0 siblings, 1 reply; 8+ messages in thread
From: Andy Shevchenko @ 2022-11-07 10:38 UTC (permalink / raw)
  To: William Breathitt Gray; +Cc: linus.walleij, brgl, linux-gpio, linux-kernel

On Thu, Nov 03, 2022 at 07:20:47AM -0400, William Breathitt Gray wrote:
> The regmap API supports IO port accessors so we can take advantage of
> regmap abstractions rather than handling access to the device registers
> directly in the driver.

I'm wondering if gpio-regmap can be used for these...

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API
  2022-11-07 10:37 ` [PATCH 0/3] Migrate i8255 GPIO drivers " Andy Shevchenko
@ 2022-11-09 20:35   ` William Breathitt Gray
  0 siblings, 0 replies; 8+ messages in thread
From: William Breathitt Gray @ 2022-11-09 20:35 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: linus.walleij, brgl, linux-gpio, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1121 bytes --]

On Mon, Nov 07, 2022 at 12:37:00PM +0200, Andy Shevchenko wrote:
> On Thu, Nov 03, 2022 at 07:20:46AM -0400, William Breathitt Gray wrote:
> > The regmap API supports IO port accessors so we can take advantage of
> > regmap abstractions rather than handling access to the device registers
> > directly in the driver.
> > 
> > Precursor patches are provided for 104-dio-48e and 104-idi-48 to migrate
> > their respective device-specific registers first in order to simplify
> > the subsequent patch migrating the i8255 library and its dependents.
> > 
> > The struct i8255 control_state member serves as a cache of the i8255
> > device's control register. Does the regmap API support caching such that
> > we won't need to manually update a control_state member?
> 
> Yes, regmap supports caching and IIRC it's opt-out.

Looks like it's disabled by default if I understand correctly: the
cache_type member of struct regmap_config has a default value of
REGCACHE_NONE if not explicitly set. I'll set cache_type to enable
caching and remove the control_state member in v2 then.

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] gpio: 104-dio-48e: Migrate to regmap API
  2022-11-07 10:38   ` Andy Shevchenko
@ 2022-11-09 20:47     ` William Breathitt Gray
  0 siblings, 0 replies; 8+ messages in thread
From: William Breathitt Gray @ 2022-11-09 20:47 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: linus.walleij, brgl, linux-gpio, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 809 bytes --]

On Mon, Nov 07, 2022 at 12:38:47PM +0200, Andy Shevchenko wrote:
> On Thu, Nov 03, 2022 at 07:20:47AM -0400, William Breathitt Gray wrote:
> > The regmap API supports IO port accessors so we can take advantage of
> > regmap abstractions rather than handling access to the device registers
> > directly in the driver.
> 
> I'm wondering if gpio-regmap can be used for these...
> 
> -- 
> With Best Regards,
> Andy Shevchenko

I might be able to update the gpio-i8255 functions to take advantage of
gpio-regmap, but the changes in the precursor patches are primarily to
handle the device interrupts. Currently, I call gpio_irq_chip_set_chip()
to assign the struct irq_chip structure to the struct gpio_irq_chip
structure. What would be the equivalent for gpio-regmap?

William Breathitt Gray

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-11-09 20:47 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-03 11:20 [PATCH 0/3] Migrate i8255 GPIO drivers to regmap API William Breathitt Gray
2022-11-03 11:20 ` [PATCH 1/3] gpio: 104-dio-48e: Migrate " William Breathitt Gray
2022-11-07 10:38   ` Andy Shevchenko
2022-11-09 20:47     ` William Breathitt Gray
2022-11-03 11:20 ` [PATCH 2/3] gpio: 104-idi-48: " William Breathitt Gray
2022-11-03 11:20 ` [PATCH 3/3] gpio: i8255: " William Breathitt Gray
2022-11-07 10:37 ` [PATCH 0/3] Migrate i8255 GPIO drivers " Andy Shevchenko
2022-11-09 20:35   ` William Breathitt Gray

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.