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