diff options
author | William Breathitt Gray <vilhelm.gray@gmail.com> | 2016-06-13 09:06:48 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2016-06-27 15:59:11 -0400 |
commit | 765550e4d98d8f5931a3863781acb7c6b995161c (patch) | |
tree | b446cfd3985fd4d9a13f2dd710de481a61a55688 | |
parent | 22ed1a1c1cceebff380b3f6f84d520a0b398509a (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/Kconfig | 11 | ||||
-rw-r--r-- | drivers/iio/dac/stx104.c | 125 |
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 | ||
248 | config STX104 | 248 | config 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 | ||
257 | config VF610_DAC | 258 | config 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 | */ | ||
68 | struct stx104_gpio { | ||
69 | struct gpio_chip chip; | ||
70 | spinlock_t lock; | ||
71 | unsigned int base; | ||
72 | unsigned int out_state; | ||
73 | }; | ||
74 | |||
59 | static int stx104_read_raw(struct iio_dev *indio_dev, | 75 | static 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 | ||
114 | static 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 | |||
123 | static 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 | |||
132 | static 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 | |||
142 | static 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 | |||
152 | static 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 | |||
98 | static int stx104_probe(struct device *dev, unsigned int id) | 174 | static 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 | |||
241 | static 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 | ||
130 | static struct isa_driver stx104_driver = { | 250 | static 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 | ||
137 | static void __exit stx104_exit(void) | 258 | static void __exit stx104_exit(void) |