Blame view

drivers/gpio/gpio-104-idio-16.c 8.18 KB
1802d0bee   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
2
3
4
5
  /*
   * GPIO driver for the ACCES 104-IDIO-16 family
   * Copyright (C) 2015 William Breathitt Gray
   *
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
6
7
   * This driver supports the following ACCES devices: 104-IDIO-16,
   * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
8
   */
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
9
  #include <linux/bitops.h>
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
10
11
12
13
14
  #include <linux/device.h>
  #include <linux/errno.h>
  #include <linux/gpio/driver.h>
  #include <linux/io.h>
  #include <linux/ioport.h>
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
15
16
  #include <linux/interrupt.h>
  #include <linux/irqdesc.h>
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
17
  #include <linux/isa.h>
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
18
19
20
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
21
  #include <linux/spinlock.h>
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
22
23
24
25
26
  #define IDIO_16_EXTENT 8
  #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
  
  static unsigned int base[MAX_NUM_IDIO_16];
  static unsigned int num_idio_16;
d759f9067   David Howells   Annotate hardware...
27
  module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
28
29
30
  MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
  
  static unsigned int irq[MAX_NUM_IDIO_16];
d759f9067   David Howells   Annotate hardware...
31
  module_param_hw_array(irq, uint, irq, NULL, 0);
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
32
  MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
33
34
35
36
  
  /**
   * struct idio_16_gpio - GPIO device private data structure
   * @chip:	instance of the gpio_chip
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
37
38
   * @lock:	synchronization lock to prevent I/O race conditions
   * @irq_mask:	I/O bits affected by interrupts
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
39
   * @base:	base port address of the GPIO device
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
40
41
42
43
   * @out_state:	output bits state
   */
  struct idio_16_gpio {
  	struct gpio_chip chip;
3906e8089   Julia Cartwright   gpio: 104-idio-16...
44
  	raw_spinlock_t lock;
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
45
  	unsigned long irq_mask;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
46
  	unsigned base;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
47
48
49
50
51
52
  	unsigned out_state;
  };
  
  static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
  {
  	if (offset > 15)
e42615ec2   Matti Vaittinen   gpio: Use new GPI...
53
  		return GPIO_LINE_DIRECTION_IN;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
54

e42615ec2   Matti Vaittinen   gpio: Use new GPI...
55
  	return GPIO_LINE_DIRECTION_OUT;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
56
57
58
59
60
61
62
63
64
65
66
67
68
  }
  
  static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  {
  	return 0;
  }
  
  static int idio_16_gpio_direction_output(struct gpio_chip *chip,
  	unsigned offset, int value)
  {
  	chip->set(chip, offset, value);
  	return 0;
  }
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
69
70
  static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
  {
d602ae90a   Linus Walleij   gpio: 104-idio-16...
71
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
72
  	const unsigned mask = BIT(offset-16);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
73
74
75
76
77
  
  	if (offset < 16)
  		return -EINVAL;
  
  	if (offset < 24)
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
78
  		return !!(inb(idio16gpio->base + 1) & mask);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
79

6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
80
  	return !!(inb(idio16gpio->base + 5) & (mask>>8));
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
81
  }
15f59cfff   William Breathitt Gray   gpio: 104-idio-16...
82
83
84
85
86
87
88
89
90
91
92
93
94
  static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
  	unsigned long *mask, unsigned long *bits)
  {
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
  
  	*bits = 0;
  	if (*mask & GENMASK(23, 16))
  		*bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
  	if (*mask & GENMASK(31, 24))
  		*bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
  
  	return 0;
  }
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
95
96
  static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  {
d602ae90a   Linus Walleij   gpio: 104-idio-16...
97
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
98
  	const unsigned mask = BIT(offset);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
99
100
101
102
  	unsigned long flags;
  
  	if (offset > 15)
  		return;
3906e8089   Julia Cartwright   gpio: 104-idio-16...
103
  	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
104
105
  
  	if (value)
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
106
  		idio16gpio->out_state |= mask;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
107
  	else
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
108
  		idio16gpio->out_state &= ~mask;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
109
110
111
112
113
  
  	if (offset > 7)
  		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
  	else
  		outb(idio16gpio->out_state, idio16gpio->base);
3906e8089   Julia Cartwright   gpio: 104-idio-16...
114
  	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
115
  }
9d7ae8127   William Breathitt Gray   gpio: 104-idio-16...
116
117
118
119
120
  static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
  	unsigned long *mask, unsigned long *bits)
  {
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
  	unsigned long flags;
3906e8089   Julia Cartwright   gpio: 104-idio-16...
121
  	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
9d7ae8127   William Breathitt Gray   gpio: 104-idio-16...
122
123
124
125
126
127
128
129
  
  	idio16gpio->out_state &= ~*mask;
  	idio16gpio->out_state |= *mask & *bits;
  
  	if (*mask & 0xFF)
  		outb(idio16gpio->out_state, idio16gpio->base);
  	if ((*mask >> 8) & 0xFF)
  		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
3906e8089   Julia Cartwright   gpio: 104-idio-16...
130
  	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
9d7ae8127   William Breathitt Gray   gpio: 104-idio-16...
131
  }
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
132
133
  static void idio_16_irq_ack(struct irq_data *data)
  {
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
134
135
136
137
138
  }
  
  static void idio_16_irq_mask(struct irq_data *data)
  {
  	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
d602ae90a   Linus Walleij   gpio: 104-idio-16...
139
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
140
141
142
143
144
145
  	const unsigned long mask = BIT(irqd_to_hwirq(data));
  	unsigned long flags;
  
  	idio16gpio->irq_mask &= ~mask;
  
  	if (!idio16gpio->irq_mask) {
3906e8089   Julia Cartwright   gpio: 104-idio-16...
146
  		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
147
148
  
  		outb(0, idio16gpio->base + 2);
3906e8089   Julia Cartwright   gpio: 104-idio-16...
149
  		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
150
151
152
153
154
155
  	}
  }
  
  static void idio_16_irq_unmask(struct irq_data *data)
  {
  	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
d602ae90a   Linus Walleij   gpio: 104-idio-16...
156
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
157
158
159
160
161
162
163
  	const unsigned long mask = BIT(irqd_to_hwirq(data));
  	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
  	unsigned long flags;
  
  	idio16gpio->irq_mask |= mask;
  
  	if (!prev_irq_mask) {
3906e8089   Julia Cartwright   gpio: 104-idio-16...
164
  		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
165

a11841477   William Breathitt Gray   gpio: Add IRQ sup...
166
  		inb(idio16gpio->base + 2);
3906e8089   Julia Cartwright   gpio: 104-idio-16...
167
  		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  	}
  }
  
  static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
  {
  	/* The only valid irq types are none and both-edges */
  	if (flow_type != IRQ_TYPE_NONE &&
  		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
  		return -EINVAL;
  
  	return 0;
  }
  
  static struct irq_chip idio_16_irqchip = {
  	.name = "104-idio-16",
  	.irq_ack = idio_16_irq_ack,
  	.irq_mask = idio_16_irq_mask,
  	.irq_unmask = idio_16_irq_unmask,
  	.irq_set_type = idio_16_irq_set_type
  };
  
  static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
  {
  	struct idio_16_gpio *const idio16gpio = dev_id;
  	struct gpio_chip *const chip = &idio16gpio->chip;
  	int gpio;
  
  	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
f0fbe7bce   Thierry Reding   gpio: Move irqdom...
196
  		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
197

3906e8089   Julia Cartwright   gpio: 104-idio-16...
198
  	raw_spin_lock(&idio16gpio->lock);
12b61c9d7   William Breathitt Gray   gpio: 104-idio-16...
199
200
  
  	outb(0, idio16gpio->base + 1);
3906e8089   Julia Cartwright   gpio: 104-idio-16...
201
  	raw_spin_unlock(&idio16gpio->lock);
12b61c9d7   William Breathitt Gray   gpio: 104-idio-16...
202

a11841477   William Breathitt Gray   gpio: Add IRQ sup...
203
204
  	return IRQ_HANDLED;
  }
e0af4b5e2   William Breathitt Gray   gpio: 104-idio-16...
205
206
207
208
209
210
211
  #define IDIO_16_NGPIO 32
  static const char *idio_16_names[IDIO_16_NGPIO] = {
  	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
  	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
  	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
  	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
  };
82e4613d3   Linus Walleij   gpio: 104-idio-16...
212
213
214
215
216
217
218
219
220
221
  static int idio_16_irq_init_hw(struct gpio_chip *gc)
  {
  	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
  
  	/* Disable IRQ by default */
  	outb(0, idio16gpio->base + 2);
  	outb(0, idio16gpio->base + 1);
  
  	return 0;
  }
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
222
  static int idio_16_probe(struct device *dev, unsigned int id)
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
223
  {
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
224
  	struct idio_16_gpio *idio16gpio;
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
225
  	const char *const name = dev_name(dev);
82e4613d3   Linus Walleij   gpio: 104-idio-16...
226
  	struct gpio_irq_chip *girq;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
227
  	int err;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
228
229
230
231
  
  	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
  	if (!idio16gpio)
  		return -ENOMEM;
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
232
  	if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
cb32389cb   William Breathitt Gray   gpio: 104-idio-16...
233
234
  		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)
  ",
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
235
  			base[id], base[id] + IDIO_16_EXTENT);
cb32389cb   William Breathitt Gray   gpio: 104-idio-16...
236
  		return -EBUSY;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
237
  	}
6e0171b40   William Breathitt Gray   gpio: 104-idio-16...
238
  	idio16gpio->chip.label = name;
58383c784   Linus Walleij   gpio: change memb...
239
  	idio16gpio->chip.parent = dev;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
240
241
  	idio16gpio->chip.owner = THIS_MODULE;
  	idio16gpio->chip.base = -1;
e0af4b5e2   William Breathitt Gray   gpio: 104-idio-16...
242
243
  	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
  	idio16gpio->chip.names = idio_16_names;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
244
245
246
247
  	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
  	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
  	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
  	idio16gpio->chip.get = idio_16_gpio_get;
15f59cfff   William Breathitt Gray   gpio: 104-idio-16...
248
  	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
249
  	idio16gpio->chip.set = idio_16_gpio_set;
9d7ae8127   William Breathitt Gray   gpio: 104-idio-16...
250
  	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
251
  	idio16gpio->base = base[id];
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
252
  	idio16gpio->out_state = 0xFFFF;
82e4613d3   Linus Walleij   gpio: 104-idio-16...
253
254
255
256
257
258
259
260
261
  	girq = &idio16gpio->chip.irq;
  	girq->chip = &idio_16_irqchip;
  	/* This will let us handle the parent IRQ in the driver */
  	girq->parent_handler = NULL;
  	girq->num_parents = 0;
  	girq->parents = NULL;
  	girq->default_type = IRQ_TYPE_NONE;
  	girq->handler = handle_edge_irq;
  	girq->init_hw = idio_16_irq_init_hw;
3906e8089   Julia Cartwright   gpio: 104-idio-16...
262
  	raw_spin_lock_init(&idio16gpio->lock);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
263

837143d35   William Breathitt Gray   gpio: 104-idio-16...
264
  	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
265
266
267
  	if (err) {
  		dev_err(dev, "GPIO registering failed (%d)
  ", err);
cb32389cb   William Breathitt Gray   gpio: 104-idio-16...
268
  		return err;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
269
  	}
837143d35   William Breathitt Gray   gpio: 104-idio-16...
270
271
  	err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
  		idio16gpio);
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
272
273
274
  	if (err) {
  		dev_err(dev, "IRQ handler registering failed (%d)
  ", err);
837143d35   William Breathitt Gray   gpio: 104-idio-16...
275
  		return err;
a11841477   William Breathitt Gray   gpio: Add IRQ sup...
276
  	}
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
277
  	return 0;
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
278
  }
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
279
280
  static struct isa_driver idio_16_driver = {
  	.probe = idio_16_probe,
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
281
282
283
  	.driver = {
  		.name = "104-idio-16"
  	},
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
284
  };
86ea8a95a   William Breathitt Gray   gpio: 104-idio-16...
285
  module_isa_driver(idio_16_driver, num_idio_16);
1ceacea22   William Breathitt Gray   gpio: Add GPIO su...
286
287
288
  
  MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
  MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
22aeddb58   William Breathitt Gray   gpio: misc: Pass ...
289
  MODULE_LICENSE("GPL v2");