[1/3] gpio: 104-dio-48e: Migrate to regmap API

Message ID 523cfe2bfbf804e64e8c9f6ed38339e850e6d9d9.1667472555.git.william.gray@linaro.org
State New
Headers
Series Migrate i8255 GPIO drivers to regmap API |

Commit Message

William Breathitt Gray Nov. 3, 2022, 11:20 a.m. UTC
  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(-)
  

Comments

Andy Shevchenko Nov. 7, 2022, 10:38 a.m. UTC | #1
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...
  
William Breathitt Gray Nov. 9, 2022, 8:47 p.m. UTC | #2
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
  

Patch

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);