lkml.org 
[lkml]   [2022]   [Jul]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 6/6] gpio: ws16c48: Implement and utilize register structures
    Date
    Reduce magic numbers and improve code readability by implementing and
    utilizing named register data structures.

    Cc: Paul Demetrotion <pdemetrotion@winsystems.com>
    Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
    ---
    drivers/gpio/gpio-ws16c48.c | 119 +++++++++++++++++++++++++-----------
    1 file changed, 84 insertions(+), 35 deletions(-)

    diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
    index 5078631d8014..663d4491b90f 100644
    --- a/drivers/gpio/gpio-ws16c48.c
    +++ b/drivers/gpio/gpio-ws16c48.c
    @@ -17,8 +17,9 @@
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/spinlock.h>
    +#include <linux/types.h>

    -#define WS16C48_EXTENT 16
    +#define WS16C48_EXTENT 10
    #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)

    static unsigned int base[MAX_NUM_WS16C48];
    @@ -30,6 +31,20 @@ static unsigned int irq[MAX_NUM_WS16C48];
    module_param_hw_array(irq, uint, irq, NULL, 0);
    MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");

    +/**
    + * struct ws16c48_reg - device register structure
    + * @port: Port 0 through 5 I/O
    + * @int_pending: Interrupt Pending
    + * @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0)
    + * @pol_enab_int_id: Interrupt polarity, enable, and ID
    + */
    +struct ws16c48_reg {
    + u8 port[6];
    + u8 int_pending;
    + u8 page_lock;
    + u8 pol_enab_int_id[3];
    +};
    +
    /**
    * struct ws16c48_gpio - GPIO device private data structure
    * @chip: instance of the gpio_chip
    @@ -38,7 +53,7 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
    * @lock: synchronization lock to prevent I/O race conditions
    * @irq_mask: I/O bits affected by interrupts
    * @flow_mask: IRQ flow type mask for the respective I/O bits
    - * @base: base port address of the GPIO device
    + * @reg: I/O address offset for the device registers
    */
    struct ws16c48_gpio {
    struct gpio_chip chip;
    @@ -47,7 +62,7 @@ struct ws16c48_gpio {
    raw_spinlock_t lock;
    unsigned long irq_mask;
    unsigned long flow_mask;
    - void __iomem *base;
    + struct ws16c48_reg __iomem *reg;
    };

    static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
    @@ -73,7 +88,7 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)

    ws16c48gpio->io_state[port] |= mask;
    ws16c48gpio->out_state[port] &= ~mask;
    - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
    + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);

    @@ -95,7 +110,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
    ws16c48gpio->out_state[port] |= mask;
    else
    ws16c48gpio->out_state[port] &= ~mask;
    - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
    + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);

    @@ -118,7 +133,7 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
    return -EINVAL;
    }

    - port_state = ioread8(ws16c48gpio->base + port);
    + port_state = ioread8(ws16c48gpio->reg->port + port);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);

    @@ -131,14 +146,16 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
    struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
    unsigned long offset;
    unsigned long gpio_mask;
    - void __iomem *port_addr;
    + size_t index;
    + u8 __iomem *port_addr;
    unsigned long port_state;

    /* clear bits array to a clean slate */
    bitmap_zero(bits, chip->ngpio);

    for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
    - port_addr = ws16c48gpio->base + offset / 8;
    + index = offset / 8;
    + port_addr = ws16c48gpio->reg->port + index;
    port_state = ioread8(port_addr) & gpio_mask;

    bitmap_set_value8(bits, port_state, offset);
    @@ -166,7 +183,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
    ws16c48gpio->out_state[port] |= mask;
    else
    ws16c48gpio->out_state[port] &= ~mask;
    - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
    + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
    }
    @@ -178,13 +195,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
    unsigned long offset;
    unsigned long gpio_mask;
    size_t index;
    - void __iomem *port_addr;
    + u8 __iomem *port_addr;
    unsigned long bitmask;
    unsigned long flags;

    for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
    index = offset / 8;
    - port_addr = ws16c48gpio->base + index;
    + port_addr = ws16c48gpio->reg->port + index;

    /* mask out GPIO configured for input */
    gpio_mask &= ~ws16c48gpio->io_state[index];
    @@ -219,10 +236,15 @@ static void ws16c48_irq_ack(struct irq_data *data)

    port_state = ws16c48gpio->irq_mask >> (8*port);

    - iowrite8(0x80, ws16c48gpio->base + 7);
    - iowrite8(port_state & ~mask, ws16c48gpio->base + 8 + port);
    - iowrite8(port_state | mask, ws16c48gpio->base + 8 + port);
    - iowrite8(0xC0, ws16c48gpio->base + 7);
    + /* Select Register Page 2; Unlock all I/O ports */
    + iowrite8(0x80, &ws16c48gpio->reg->page_lock);
    +
    + /* Clear pending interrupt */
    + iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port);
    + iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port);
    +
    + /* Select Register Page 3; Unlock all I/O ports */
    + iowrite8(0xC0, &ws16c48gpio->reg->page_lock);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
    }
    @@ -235,6 +257,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
    const unsigned long mask = BIT(offset);
    const unsigned port = offset / 8;
    unsigned long flags;
    + unsigned long port_state;

    /* only the first 3 ports support interrupts */
    if (port > 2)
    @@ -243,10 +266,16 @@ static void ws16c48_irq_mask(struct irq_data *data)
    raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);

    ws16c48gpio->irq_mask &= ~mask;
    + port_state = ws16c48gpio->irq_mask >> (8 * port);
    +
    + /* Select Register Page 2; Unlock all I/O ports */
    + iowrite8(0x80, &ws16c48gpio->reg->page_lock);

    - iowrite8(0x80, ws16c48gpio->base + 7);
    - iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
    - iowrite8(0xC0, ws16c48gpio->base + 7);
    + /* Disable interrupt */
    + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
    +
    + /* Select Register Page 3; Unlock all I/O ports */
    + iowrite8(0xC0, &ws16c48gpio->reg->page_lock);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
    }
    @@ -259,6 +288,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
    const unsigned long mask = BIT(offset);
    const unsigned port = offset / 8;
    unsigned long flags;
    + unsigned long port_state;

    /* only the first 3 ports support interrupts */
    if (port > 2)
    @@ -267,10 +297,16 @@ static void ws16c48_irq_unmask(struct irq_data *data)
    raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);

    ws16c48gpio->irq_mask |= mask;
    + port_state = ws16c48gpio->irq_mask >> (8 * port);
    +
    + /* Select Register Page 2; Unlock all I/O ports */
    + iowrite8(0x80, &ws16c48gpio->reg->page_lock);

    - iowrite8(0x80, ws16c48gpio->base + 7);
    - iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
    - iowrite8(0xC0, ws16c48gpio->base + 7);
    + /* Enable interrupt */
    + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
    +
    + /* Select Register Page 3; Unlock all I/O ports */
    + iowrite8(0xC0, &ws16c48gpio->reg->page_lock);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
    }
    @@ -283,6 +319,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
    const unsigned long mask = BIT(offset);
    const unsigned port = offset / 8;
    unsigned long flags;
    + unsigned long port_state;

    /* only the first 3 ports support interrupts */
    if (port > 2)
    @@ -304,9 +341,16 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
    return -EINVAL;
    }

    - iowrite8(0x40, ws16c48gpio->base + 7);
    - iowrite8(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port);
    - iowrite8(0xC0, ws16c48gpio->base + 7);
    + port_state = ws16c48gpio->flow_mask >> (8 * port);
    +
    + /* Select Register Page 1; Unlock all I/O ports */
    + iowrite8(0x40, &ws16c48gpio->reg->page_lock);
    +
    + /* Set interrupt polarity */
    + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
    +
    + /* Select Register Page 3; Unlock all I/O ports */
    + iowrite8(0xC0, &ws16c48gpio->reg->page_lock);

    raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);

    @@ -325,25 +369,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
    {
    struct ws16c48_gpio *const ws16c48gpio = dev_id;
    struct gpio_chip *const chip = &ws16c48gpio->chip;
    + struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg;
    unsigned long int_pending;
    unsigned long port;
    unsigned long int_id;
    unsigned long gpio;

    - int_pending = ioread8(ws16c48gpio->base + 6) & 0x7;
    + int_pending = ioread8(&reg->int_pending) & 0x7;
    if (!int_pending)
    return IRQ_NONE;

    /* loop until all pending interrupts are handled */
    do {
    for_each_set_bit(port, &int_pending, 3) {
    - int_id = ioread8(ws16c48gpio->base + 8 + port);
    + int_id = ioread8(reg->pol_enab_int_id + port);
    for_each_set_bit(gpio, &int_id, 8)
    generic_handle_domain_irq(chip->irq.domain,
    gpio + 8*port);
    }

    - int_pending = ioread8(ws16c48gpio->base + 6) & 0x7;
    + int_pending = ioread8(&reg->int_pending) & 0x7;
    } while (int_pending);

    return IRQ_HANDLED;
    @@ -369,12 +414,16 @@ static int ws16c48_irq_init_hw(struct gpio_chip *gc)
    {
    struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc);

    - /* Disable IRQ by default */
    - iowrite8(0x80, ws16c48gpio->base + 7);
    - iowrite8(0, ws16c48gpio->base + 8);
    - iowrite8(0, ws16c48gpio->base + 9);
    - iowrite8(0, ws16c48gpio->base + 10);
    - iowrite8(0xC0, ws16c48gpio->base + 7);
    + /* Select Register Page 2; Unlock all I/O ports */
    + iowrite8(0x80, &ws16c48gpio->reg->page_lock);
    +
    + /* Disable interrupts for all lines */
    + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]);
    + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]);
    + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]);
    +
    + /* Select Register Page 3; Unlock all I/O ports */
    + iowrite8(0xC0, &ws16c48gpio->reg->page_lock);

    return 0;
    }
    @@ -396,8 +445,8 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
    return -EBUSY;
    }

    - ws16c48gpio->base = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
    - if (!ws16c48gpio->base)
    + ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
    + if (!ws16c48gpio->reg)
    return -ENOMEM;

    ws16c48gpio->chip.label = name;
    --
    2.36.1
    \
     
     \ /
      Last update: 2022-07-08 01:18    [W:3.965 / U:0.904 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site