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 <[email protected]>
---
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
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
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