Skip to content

Commit 2c05a0f

Browse files
William Breathitt Graybrgl
authored andcommitted
gpio: ws16c48: Implement and utilize register structures
Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Cc: Paul Demetrotion <pdemetrotion@winsystems.com> Signed-off-by: William Breathitt Gray <william.gray@linaro.org> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
1 parent c4371c5 commit 2c05a0f

1 file changed

Lines changed: 84 additions & 36 deletions

File tree

drivers/gpio/gpio-ws16c48.c

Lines changed: 84 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* Copyright (C) 2016 William Breathitt Gray
55
*/
66
#include <linux/bitmap.h>
7-
#include <linux/bitops.h>
87
#include <linux/device.h>
98
#include <linux/errno.h>
109
#include <linux/gpio/driver.h>
@@ -17,8 +16,9 @@
1716
#include <linux/module.h>
1817
#include <linux/moduleparam.h>
1918
#include <linux/spinlock.h>
19+
#include <linux/types.h>
2020

21-
#define WS16C48_EXTENT 16
21+
#define WS16C48_EXTENT 10
2222
#define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)
2323

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

33+
/**
34+
* struct ws16c48_reg - device register structure
35+
* @port: Port 0 through 5 I/O
36+
* @int_pending: Interrupt Pending
37+
* @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0)
38+
* @pol_enab_int_id: Interrupt polarity, enable, and ID
39+
*/
40+
struct ws16c48_reg {
41+
u8 port[6];
42+
u8 int_pending;
43+
u8 page_lock;
44+
u8 pol_enab_int_id[3];
45+
};
46+
3347
/**
3448
* struct ws16c48_gpio - GPIO device private data structure
3549
* @chip: instance of the gpio_chip
@@ -38,7 +52,7 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
3852
* @lock: synchronization lock to prevent I/O race conditions
3953
* @irq_mask: I/O bits affected by interrupts
4054
* @flow_mask: IRQ flow type mask for the respective I/O bits
41-
* @base: base port address of the GPIO device
55+
* @reg: I/O address offset for the device registers
4256
*/
4357
struct ws16c48_gpio {
4458
struct gpio_chip chip;
@@ -47,7 +61,7 @@ struct ws16c48_gpio {
4761
raw_spinlock_t lock;
4862
unsigned long irq_mask;
4963
unsigned long flow_mask;
50-
void __iomem *base;
64+
struct ws16c48_reg __iomem *reg;
5165
};
5266

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

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

7892
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
7993

@@ -95,7 +109,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
95109
ws16c48gpio->out_state[port] |= mask;
96110
else
97111
ws16c48gpio->out_state[port] &= ~mask;
98-
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
112+
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
99113

100114
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
101115

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

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

123137
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
124138

@@ -131,14 +145,16 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
131145
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
132146
unsigned long offset;
133147
unsigned long gpio_mask;
134-
void __iomem *port_addr;
148+
size_t index;
149+
u8 __iomem *port_addr;
135150
unsigned long port_state;
136151

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

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

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

171187
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
172188
}
@@ -178,13 +194,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
178194
unsigned long offset;
179195
unsigned long gpio_mask;
180196
size_t index;
181-
void __iomem *port_addr;
197+
u8 __iomem *port_addr;
182198
unsigned long bitmask;
183199
unsigned long flags;
184200

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

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

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

222-
iowrite8(0x80, ws16c48gpio->base + 7);
223-
iowrite8(port_state & ~mask, ws16c48gpio->base + 8 + port);
224-
iowrite8(port_state | mask, ws16c48gpio->base + 8 + port);
225-
iowrite8(0xC0, ws16c48gpio->base + 7);
238+
/* Select Register Page 2; Unlock all I/O ports */
239+
iowrite8(0x80, &ws16c48gpio->reg->page_lock);
240+
241+
/* Clear pending interrupt */
242+
iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port);
243+
iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port);
244+
245+
/* Select Register Page 3; Unlock all I/O ports */
246+
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
226247

227248
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
228249
}
@@ -235,6 +256,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
235256
const unsigned long mask = BIT(offset);
236257
const unsigned port = offset / 8;
237258
unsigned long flags;
259+
unsigned long port_state;
238260

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

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

247-
iowrite8(0x80, ws16c48gpio->base + 7);
248-
iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
249-
iowrite8(0xC0, ws16c48gpio->base + 7);
273+
/* Disable interrupt */
274+
iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
275+
276+
/* Select Register Page 3; Unlock all I/O ports */
277+
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
250278

251279
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
252280
}
@@ -259,6 +287,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
259287
const unsigned long mask = BIT(offset);
260288
const unsigned port = offset / 8;
261289
unsigned long flags;
290+
unsigned long port_state;
262291

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

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

271-
iowrite8(0x80, ws16c48gpio->base + 7);
272-
iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
273-
iowrite8(0xC0, ws16c48gpio->base + 7);
304+
/* Enable interrupt */
305+
iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
306+
307+
/* Select Register Page 3; Unlock all I/O ports */
308+
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
274309

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

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

307-
iowrite8(0x40, ws16c48gpio->base + 7);
308-
iowrite8(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port);
309-
iowrite8(0xC0, ws16c48gpio->base + 7);
343+
port_state = ws16c48gpio->flow_mask >> (8 * port);
344+
345+
/* Select Register Page 1; Unlock all I/O ports */
346+
iowrite8(0x40, &ws16c48gpio->reg->page_lock);
347+
348+
/* Set interrupt polarity */
349+
iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
350+
351+
/* Select Register Page 3; Unlock all I/O ports */
352+
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
310353

311354
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
312355

@@ -325,25 +368,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
325368
{
326369
struct ws16c48_gpio *const ws16c48gpio = dev_id;
327370
struct gpio_chip *const chip = &ws16c48gpio->chip;
371+
struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg;
328372
unsigned long int_pending;
329373
unsigned long port;
330374
unsigned long int_id;
331375
unsigned long gpio;
332376

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

337381
/* loop until all pending interrupts are handled */
338382
do {
339383
for_each_set_bit(port, &int_pending, 3) {
340-
int_id = ioread8(ws16c48gpio->base + 8 + port);
384+
int_id = ioread8(reg->pol_enab_int_id + port);
341385
for_each_set_bit(gpio, &int_id, 8)
342386
generic_handle_domain_irq(chip->irq.domain,
343387
gpio + 8*port);
344388
}
345389

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

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

372-
/* Disable IRQ by default */
373-
iowrite8(0x80, ws16c48gpio->base + 7);
374-
iowrite8(0, ws16c48gpio->base + 8);
375-
iowrite8(0, ws16c48gpio->base + 9);
376-
iowrite8(0, ws16c48gpio->base + 10);
377-
iowrite8(0xC0, ws16c48gpio->base + 7);
416+
/* Select Register Page 2; Unlock all I/O ports */
417+
iowrite8(0x80, &ws16c48gpio->reg->page_lock);
418+
419+
/* Disable interrupts for all lines */
420+
iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]);
421+
iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]);
422+
iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]);
423+
424+
/* Select Register Page 3; Unlock all I/O ports */
425+
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
378426

379427
return 0;
380428
}
@@ -396,8 +444,8 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
396444
return -EBUSY;
397445
}
398446

399-
ws16c48gpio->base = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
400-
if (!ws16c48gpio->base)
447+
ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
448+
if (!ws16c48gpio->reg)
401449
return -ENOMEM;
402450

403451
ws16c48gpio->chip.label = name;

0 commit comments

Comments
 (0)