aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/gpio-pcf857x.c122
-rw-r--r--include/linux/i2c/pcf857x.h3
2 files changed, 125 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 076e236d0da..12e3e484d70 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -23,7 +23,12 @@
23#include <linux/gpio.h> 23#include <linux/gpio.h>
24#include <linux/i2c.h> 24#include <linux/i2c.h>
25#include <linux/i2c/pcf857x.h> 25#include <linux/i2c/pcf857x.h>
26#include <linux/interrupt.h>
27#include <linux/irq.h>
28#include <linux/irqdomain.h>
26#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/spinlock.h>
31#include <linux/workqueue.h>
27 32
28 33
29static const struct i2c_device_id pcf857x_id[] = { 34static const struct i2c_device_id pcf857x_id[] = {
@@ -60,7 +65,12 @@ struct pcf857x {
60 struct gpio_chip chip; 65 struct gpio_chip chip;
61 struct i2c_client *client; 66 struct i2c_client *client;
62 struct mutex lock; /* protect 'out' */ 67 struct mutex lock; /* protect 'out' */
68 struct work_struct work; /* irq demux work */
69 struct irq_domain *irq_domain; /* for irq demux */
70 spinlock_t slock; /* protect irq demux */
63 unsigned out; /* software latch */ 71 unsigned out; /* software latch */
72 unsigned status; /* current status */
73 int irq; /* real irq number */
64 74
65 int (*write)(struct i2c_client *client, unsigned data); 75 int (*write)(struct i2c_client *client, unsigned data);
66 int (*read)(struct i2c_client *client); 76 int (*read)(struct i2c_client *client);
@@ -150,6 +160,100 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
150 160
151/*-------------------------------------------------------------------------*/ 161/*-------------------------------------------------------------------------*/
152 162
163static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset)
164{
165 struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
166
167 return irq_create_mapping(gpio->irq_domain, offset);
168}
169
170static void pcf857x_irq_demux_work(struct work_struct *work)
171{
172 struct pcf857x *gpio = container_of(work,
173 struct pcf857x,
174 work);
175 unsigned long change, i, status, flags;
176
177 status = gpio->read(gpio->client);
178
179 spin_lock_irqsave(&gpio->slock, flags);
180
181 change = gpio->status ^ status;
182 for_each_set_bit(i, &change, gpio->chip.ngpio)
183 generic_handle_irq(irq_find_mapping(gpio->irq_domain, i));
184 gpio->status = status;
185
186 spin_unlock_irqrestore(&gpio->slock, flags);
187}
188
189static irqreturn_t pcf857x_irq_demux(int irq, void *data)
190{
191 struct pcf857x *gpio = data;
192
193 /*
194 * pcf857x can't read/write data here,
195 * since i2c data access might go to sleep.
196 */
197 schedule_work(&gpio->work);
198
199 return IRQ_HANDLED;
200}
201
202static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq,
203 irq_hw_number_t hw)
204{
205 irq_set_chip_and_handler(virq,
206 &dummy_irq_chip,
207 handle_level_irq);
208 return 0;
209}
210
211static struct irq_domain_ops pcf857x_irq_domain_ops = {
212 .map = pcf857x_irq_domain_map,
213};
214
215static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
216{
217 if (gpio->irq_domain)
218 irq_domain_remove(gpio->irq_domain);
219
220 if (gpio->irq)
221 free_irq(gpio->irq, gpio);
222}
223
224static int pcf857x_irq_domain_init(struct pcf857x *gpio,
225 struct pcf857x_platform_data *pdata,
226 struct device *dev)
227{
228 int status;
229
230 gpio->irq_domain = irq_domain_add_linear(dev->of_node,
231 gpio->chip.ngpio,
232 &pcf857x_irq_domain_ops,
233 NULL);
234 if (!gpio->irq_domain)
235 goto fail;
236
237 /* enable real irq */
238 status = request_irq(pdata->irq, pcf857x_irq_demux, 0,
239 dev_name(dev), gpio);
240 if (status)
241 goto fail;
242
243 /* enable gpio_to_irq() */
244 INIT_WORK(&gpio->work, pcf857x_irq_demux_work);
245 gpio->chip.to_irq = pcf857x_to_irq;
246 gpio->irq = pdata->irq;
247
248 return 0;
249
250fail:
251 pcf857x_irq_domain_cleanup(gpio);
252 return -EINVAL;
253}
254
255/*-------------------------------------------------------------------------*/
256
153static int pcf857x_probe(struct i2c_client *client, 257static int pcf857x_probe(struct i2c_client *client,
154 const struct i2c_device_id *id) 258 const struct i2c_device_id *id)
155{ 259{
@@ -168,6 +272,7 @@ static int pcf857x_probe(struct i2c_client *client,
168 return -ENOMEM; 272 return -ENOMEM;
169 273
170 mutex_init(&gpio->lock); 274 mutex_init(&gpio->lock);
275 spin_lock_init(&gpio->slock);
171 276
172 gpio->chip.base = pdata ? pdata->gpio_base : -1; 277 gpio->chip.base = pdata ? pdata->gpio_base : -1;
173 gpio->chip.can_sleep = 1; 278 gpio->chip.can_sleep = 1;
@@ -179,6 +284,15 @@ static int pcf857x_probe(struct i2c_client *client,
179 gpio->chip.direction_output = pcf857x_output; 284 gpio->chip.direction_output = pcf857x_output;
180 gpio->chip.ngpio = id->driver_data; 285 gpio->chip.ngpio = id->driver_data;
181 286
287 /* enable gpio_to_irq() if platform has settings */
288 if (pdata->irq) {
289 status = pcf857x_irq_domain_init(gpio, pdata, &client->dev);
290 if (status < 0) {
291 dev_err(&client->dev, "irq_domain init failed\n");
292 goto fail;
293 }
294 }
295
182 /* NOTE: the OnSemi jlc1562b is also largely compatible with 296 /* NOTE: the OnSemi jlc1562b is also largely compatible with
183 * these parts, notably for output. It has a low-resolution 297 * these parts, notably for output. It has a low-resolution
184 * DAC instead of pin change IRQs; and its inputs can be the 298 * DAC instead of pin change IRQs; and its inputs can be the
@@ -248,6 +362,7 @@ static int pcf857x_probe(struct i2c_client *client,
248 * all-ones reset state. Otherwise it flags pins to be driven low. 362 * all-ones reset state. Otherwise it flags pins to be driven low.
249 */ 363 */
250 gpio->out = pdata ? ~pdata->n_latch : ~0; 364 gpio->out = pdata ? ~pdata->n_latch : ~0;
365 gpio->status = gpio->out;
251 366
252 status = gpiochip_add(&gpio->chip); 367 status = gpiochip_add(&gpio->chip);
253 if (status < 0) 368 if (status < 0)
@@ -278,6 +393,10 @@ static int pcf857x_probe(struct i2c_client *client,
278fail: 393fail:
279 dev_dbg(&client->dev, "probe error %d for '%s'\n", 394 dev_dbg(&client->dev, "probe error %d for '%s'\n",
280 status, client->name); 395 status, client->name);
396
397 if (pdata->irq)
398 pcf857x_irq_domain_cleanup(gpio);
399
281 kfree(gpio); 400 kfree(gpio);
282 return status; 401 return status;
283} 402}
@@ -299,6 +418,9 @@ static int pcf857x_remove(struct i2c_client *client)
299 } 418 }
300 } 419 }
301 420
421 if (pdata->irq)
422 pcf857x_irq_domain_cleanup(gpio);
423
302 status = gpiochip_remove(&gpio->chip); 424 status = gpiochip_remove(&gpio->chip);
303 if (status == 0) 425 if (status == 0)
304 kfree(gpio); 426 kfree(gpio);
diff --git a/include/linux/i2c/pcf857x.h b/include/linux/i2c/pcf857x.h
index 0767a2a6b2f..781e6bd06c3 100644
--- a/include/linux/i2c/pcf857x.h
+++ b/include/linux/i2c/pcf857x.h
@@ -10,6 +10,7 @@
10 * @setup: optional callback issued once the GPIOs are valid 10 * @setup: optional callback issued once the GPIOs are valid
11 * @teardown: optional callback issued before the GPIOs are invalidated 11 * @teardown: optional callback issued before the GPIOs are invalidated
12 * @context: optional parameter passed to setup() and teardown() 12 * @context: optional parameter passed to setup() and teardown()
13 * @irq: optional interrupt number
13 * 14 *
14 * In addition to the I2C_BOARD_INFO() state appropriate to each chip, 15 * In addition to the I2C_BOARD_INFO() state appropriate to each chip,
15 * the i2c_board_info used with the pcf875x driver must provide its 16 * the i2c_board_info used with the pcf875x driver must provide its
@@ -39,6 +40,8 @@ struct pcf857x_platform_data {
39 int gpio, unsigned ngpio, 40 int gpio, unsigned ngpio,
40 void *context); 41 void *context);
41 void *context; 42 void *context;
43
44 int irq;
42}; 45};
43 46
44#endif /* __LINUX_PCF857X_H */ 47#endif /* __LINUX_PCF857X_H */