aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Breathitt Gray <vilhelm.gray@gmail.com>2016-06-13 09:06:48 -0400
committerJonathan Cameron <jic23@kernel.org>2016-06-27 15:59:11 -0400
commit765550e4d98d8f5931a3863781acb7c6b995161c (patch)
treeb446cfd3985fd4d9a13f2dd710de481a61a55688
parent22ed1a1c1cceebff380b3f6f84d520a0b398509a (diff)
iio: stx104: Add GPIO support for the Apex Embedded Systems STX104
The Apex Embedded Systems STX104 device features eight lines of digital I/O (four digital inputs and four digital outputs). This patch adds GPIO support for these eight lines of digital I/O via GPIOLIB. Cc: Alexandre Courbot <gnurou@gmail.com> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/dac/Kconfig11
-rw-r--r--drivers/iio/dac/stx104.c125
2 files changed, 129 insertions, 7 deletions
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 61d5008bff5c..b3feb0bf3aa3 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -246,13 +246,14 @@ config MCP4922
246 will be called mcp4922. 246 will be called mcp4922.
247 247
248config STX104 248config STX104
249 tristate "Apex Embedded Systems STX104 DAC driver" 249 tristate "Apex Embedded Systems STX104 driver"
250 depends on ISA 250 depends on ISA
251 select GPIOLIB
251 help 252 help
252 Say yes here to build support for the 2-channel DAC on the Apex 253 Say yes here to build support for the 2-channel DAC and GPIO on the
253 Embedded Systems STX104 integrated analog PC/104 card. The base port 254 Apex Embedded Systems STX104 integrated analog PC/104 card. The base
254 addresses for the devices may be configured via the "base" module 255 port addresses for the devices may be configured via the base array
255 parameter array. 256 module parameter.
256 257
257config VF610_DAC 258config VF610_DAC
258 tristate "Vybrid vf610 DAC driver" 259 tristate "Vybrid vf610 DAC driver"
diff --git a/drivers/iio/dac/stx104.c b/drivers/iio/dac/stx104.c
index 174f4b75ceed..e0f31a12c87f 100644
--- a/drivers/iio/dac/stx104.c
+++ b/drivers/iio/dac/stx104.c
@@ -14,6 +14,7 @@
14#include <linux/bitops.h> 14#include <linux/bitops.h>
15#include <linux/device.h> 15#include <linux/device.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/gpio/driver.h>
17#include <linux/iio/iio.h> 18#include <linux/iio/iio.h>
18#include <linux/iio/types.h> 19#include <linux/iio/types.h>
19#include <linux/io.h> 20#include <linux/io.h>
@@ -21,6 +22,7 @@
21#include <linux/isa.h> 22#include <linux/isa.h>
22#include <linux/module.h> 23#include <linux/module.h>
23#include <linux/moduleparam.h> 24#include <linux/moduleparam.h>
25#include <linux/spinlock.h>
24 26
25#define STX104_NUM_CHAN 2 27#define STX104_NUM_CHAN 2
26 28
@@ -56,6 +58,20 @@ struct stx104_iio {
56 unsigned base; 58 unsigned base;
57}; 59};
58 60
61/**
62 * struct stx104_gpio - GPIO device private data structure
63 * @chip: instance of the gpio_chip
64 * @lock: synchronization lock to prevent I/O race conditions
65 * @base: base port address of the GPIO device
66 * @out_state: output bits state
67 */
68struct stx104_gpio {
69 struct gpio_chip chip;
70 spinlock_t lock;
71 unsigned int base;
72 unsigned int out_state;
73};
74
59static int stx104_read_raw(struct iio_dev *indio_dev, 75static int stx104_read_raw(struct iio_dev *indio_dev,
60 struct iio_chan_spec const *chan, int *val, int *val2, long mask) 76 struct iio_chan_spec const *chan, int *val, int *val2, long mask)
61{ 77{
@@ -95,15 +111,81 @@ static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
95 STX104_CHAN(1) 111 STX104_CHAN(1)
96}; 112};
97 113
114static int stx104_gpio_get_direction(struct gpio_chip *chip,
115 unsigned int offset)
116{
117 if (offset < 4)
118 return 1;
119
120 return 0;
121}
122
123static int stx104_gpio_direction_input(struct gpio_chip *chip,
124 unsigned int offset)
125{
126 if (offset >= 4)
127 return -EINVAL;
128
129 return 0;
130}
131
132static int stx104_gpio_direction_output(struct gpio_chip *chip,
133 unsigned int offset, int value)
134{
135 if (offset < 4)
136 return -EINVAL;
137
138 chip->set(chip, offset, value);
139 return 0;
140}
141
142static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
143{
144 struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
145
146 if (offset >= 4)
147 return -EINVAL;
148
149 return !!(inb(stx104gpio->base) & BIT(offset));
150}
151
152static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
153 int value)
154{
155 struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
156 const unsigned int mask = BIT(offset) >> 4;
157 unsigned long flags;
158
159 if (offset < 4)
160 return;
161
162 spin_lock_irqsave(&stx104gpio->lock, flags);
163
164 if (value)
165 stx104gpio->out_state |= mask;
166 else
167 stx104gpio->out_state &= ~mask;
168
169 outb(stx104gpio->out_state, stx104gpio->base);
170
171 spin_unlock_irqrestore(&stx104gpio->lock, flags);
172}
173
98static int stx104_probe(struct device *dev, unsigned int id) 174static int stx104_probe(struct device *dev, unsigned int id)
99{ 175{
100 struct iio_dev *indio_dev; 176 struct iio_dev *indio_dev;
101 struct stx104_iio *priv; 177 struct stx104_iio *priv;
178 struct stx104_gpio *stx104gpio;
179 int err;
102 180
103 indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); 181 indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
104 if (!indio_dev) 182 if (!indio_dev)
105 return -ENOMEM; 183 return -ENOMEM;
106 184
185 stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
186 if (!stx104gpio)
187 return -ENOMEM;
188
107 if (!devm_request_region(dev, base[id], STX104_EXTENT, 189 if (!devm_request_region(dev, base[id], STX104_EXTENT,
108 dev_name(dev))) { 190 dev_name(dev))) {
109 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 191 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -124,14 +206,53 @@ static int stx104_probe(struct device *dev, unsigned int id)
124 outw(0, base[id] + 4); 206 outw(0, base[id] + 4);
125 outw(0, base[id] + 6); 207 outw(0, base[id] + 6);
126 208
127 return devm_iio_device_register(dev, indio_dev); 209 err = devm_iio_device_register(dev, indio_dev);
210 if (err) {
211 dev_err(dev, "IIO device registering failed (%d)\n", err);
212 return err;
213 }
214
215 stx104gpio->chip.label = dev_name(dev);
216 stx104gpio->chip.parent = dev;
217 stx104gpio->chip.owner = THIS_MODULE;
218 stx104gpio->chip.base = -1;
219 stx104gpio->chip.ngpio = 8;
220 stx104gpio->chip.get_direction = stx104_gpio_get_direction;
221 stx104gpio->chip.direction_input = stx104_gpio_direction_input;
222 stx104gpio->chip.direction_output = stx104_gpio_direction_output;
223 stx104gpio->chip.get = stx104_gpio_get;
224 stx104gpio->chip.set = stx104_gpio_set;
225 stx104gpio->base = base[id] + 3;
226 stx104gpio->out_state = 0x0;
227
228 spin_lock_init(&stx104gpio->lock);
229
230 dev_set_drvdata(dev, stx104gpio);
231
232 err = gpiochip_add_data(&stx104gpio->chip, stx104gpio);
233 if (err) {
234 dev_err(dev, "GPIO registering failed (%d)\n", err);
235 return err;
236 }
237
238 return 0;
239}
240
241static int stx104_remove(struct device *dev, unsigned int id)
242{
243 struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev);
244
245 gpiochip_remove(&stx104gpio->chip);
246
247 return 0;
128} 248}
129 249
130static struct isa_driver stx104_driver = { 250static struct isa_driver stx104_driver = {
131 .probe = stx104_probe, 251 .probe = stx104_probe,
132 .driver = { 252 .driver = {
133 .name = "stx104" 253 .name = "stx104"
134 } 254 },
255 .remove = stx104_remove
135}; 256};
136 257
137static void __exit stx104_exit(void) 258static void __exit stx104_exit(void)