diff options
-rw-r--r-- | drivers/gpio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-pcf857x.c | 121 |
2 files changed, 28 insertions, 94 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 09bc70b3875b..249845a47624 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -604,6 +604,7 @@ config GPIO_PCA953X_IRQ | |||
604 | config GPIO_PCF857X | 604 | config GPIO_PCF857X |
605 | tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" | 605 | tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" |
606 | depends on I2C | 606 | depends on I2C |
607 | select GPIOLIB_IRQCHIP | ||
607 | select IRQ_DOMAIN | 608 | select IRQ_DOMAIN |
608 | help | 609 | help |
609 | Say yes here to provide access to most "quasi-bidirectional" I2C | 610 | Say yes here to provide access to most "quasi-bidirectional" I2C |
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 236708ad0a5b..126c93732101 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c | |||
@@ -88,11 +88,9 @@ struct pcf857x { | |||
88 | struct gpio_chip chip; | 88 | struct gpio_chip chip; |
89 | struct i2c_client *client; | 89 | struct i2c_client *client; |
90 | struct mutex lock; /* protect 'out' */ | 90 | struct mutex lock; /* protect 'out' */ |
91 | struct irq_domain *irq_domain; /* for irq demux */ | ||
92 | spinlock_t slock; /* protect irq demux */ | 91 | spinlock_t slock; /* protect irq demux */ |
93 | unsigned out; /* software latch */ | 92 | unsigned out; /* software latch */ |
94 | unsigned status; /* current status */ | 93 | unsigned status; /* current status */ |
95 | unsigned irq_mapped; /* mapped gpio irqs */ | ||
96 | 94 | ||
97 | int (*write)(struct i2c_client *client, unsigned data); | 95 | int (*write)(struct i2c_client *client, unsigned data); |
98 | int (*read)(struct i2c_client *client); | 96 | int (*read)(struct i2c_client *client); |
@@ -182,18 +180,6 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) | |||
182 | 180 | ||
183 | /*-------------------------------------------------------------------------*/ | 181 | /*-------------------------------------------------------------------------*/ |
184 | 182 | ||
185 | static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) | ||
186 | { | ||
187 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); | ||
188 | int ret; | ||
189 | |||
190 | ret = irq_create_mapping(gpio->irq_domain, offset); | ||
191 | if (ret > 0) | ||
192 | gpio->irq_mapped |= (1 << offset); | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static irqreturn_t pcf857x_irq(int irq, void *data) | 183 | static irqreturn_t pcf857x_irq(int irq, void *data) |
198 | { | 184 | { |
199 | struct pcf857x *gpio = data; | 185 | struct pcf857x *gpio = data; |
@@ -208,9 +194,9 @@ static irqreturn_t pcf857x_irq(int irq, void *data) | |||
208 | * interrupt source, just to avoid bad irqs | 194 | * interrupt source, just to avoid bad irqs |
209 | */ | 195 | */ |
210 | 196 | ||
211 | change = ((gpio->status ^ status) & gpio->irq_mapped); | 197 | change = (gpio->status ^ status); |
212 | for_each_set_bit(i, &change, gpio->chip.ngpio) | 198 | for_each_set_bit(i, &change, gpio->chip.ngpio) |
213 | generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); | 199 | handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); |
214 | gpio->status = status; | 200 | gpio->status = status; |
215 | 201 | ||
216 | spin_unlock_irqrestore(&gpio->slock, flags); | 202 | spin_unlock_irqrestore(&gpio->slock, flags); |
@@ -218,66 +204,6 @@ static irqreturn_t pcf857x_irq(int irq, void *data) | |||
218 | return IRQ_HANDLED; | 204 | return IRQ_HANDLED; |
219 | } | 205 | } |
220 | 206 | ||
221 | static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq, | ||
222 | irq_hw_number_t hw) | ||
223 | { | ||
224 | struct pcf857x *gpio = domain->host_data; | ||
225 | |||
226 | irq_set_chip_and_handler(irq, | ||
227 | &dummy_irq_chip, | ||
228 | handle_level_irq); | ||
229 | #ifdef CONFIG_ARM | ||
230 | set_irq_flags(irq, IRQF_VALID); | ||
231 | #else | ||
232 | irq_set_noprobe(irq); | ||
233 | #endif | ||
234 | gpio->irq_mapped |= (1 << hw); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct irq_domain_ops pcf857x_irq_domain_ops = { | ||
240 | .map = pcf857x_irq_domain_map, | ||
241 | }; | ||
242 | |||
243 | static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) | ||
244 | { | ||
245 | if (gpio->irq_domain) | ||
246 | irq_domain_remove(gpio->irq_domain); | ||
247 | |||
248 | } | ||
249 | |||
250 | static int pcf857x_irq_domain_init(struct pcf857x *gpio, | ||
251 | struct i2c_client *client) | ||
252 | { | ||
253 | int status; | ||
254 | |||
255 | gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, | ||
256 | gpio->chip.ngpio, | ||
257 | &pcf857x_irq_domain_ops, | ||
258 | gpio); | ||
259 | if (!gpio->irq_domain) | ||
260 | goto fail; | ||
261 | |||
262 | /* enable real irq */ | ||
263 | status = devm_request_threaded_irq(&client->dev, client->irq, | ||
264 | NULL, pcf857x_irq, IRQF_ONESHOT | | ||
265 | IRQF_TRIGGER_FALLING | IRQF_SHARED, | ||
266 | dev_name(&client->dev), gpio); | ||
267 | |||
268 | if (status) | ||
269 | goto fail; | ||
270 | |||
271 | /* enable gpio_to_irq() */ | ||
272 | gpio->chip.to_irq = pcf857x_to_irq; | ||
273 | |||
274 | return 0; | ||
275 | |||
276 | fail: | ||
277 | pcf857x_irq_domain_cleanup(gpio); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | /*-------------------------------------------------------------------------*/ | 207 | /*-------------------------------------------------------------------------*/ |
282 | 208 | ||
283 | static int pcf857x_probe(struct i2c_client *client, | 209 | static int pcf857x_probe(struct i2c_client *client, |
@@ -314,15 +240,6 @@ static int pcf857x_probe(struct i2c_client *client, | |||
314 | gpio->chip.direction_output = pcf857x_output; | 240 | gpio->chip.direction_output = pcf857x_output; |
315 | gpio->chip.ngpio = id->driver_data; | 241 | gpio->chip.ngpio = id->driver_data; |
316 | 242 | ||
317 | /* enable gpio_to_irq() if platform has settings */ | ||
318 | if (client->irq) { | ||
319 | status = pcf857x_irq_domain_init(gpio, client); | ||
320 | if (status < 0) { | ||
321 | dev_err(&client->dev, "irq_domain init failed\n"); | ||
322 | goto fail_irq_domain; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | /* NOTE: the OnSemi jlc1562b is also largely compatible with | 243 | /* NOTE: the OnSemi jlc1562b is also largely compatible with |
327 | * these parts, notably for output. It has a low-resolution | 244 | * these parts, notably for output. It has a low-resolution |
328 | * DAC instead of pin change IRQs; and its inputs can be the | 245 | * DAC instead of pin change IRQs; and its inputs can be the |
@@ -398,6 +315,26 @@ static int pcf857x_probe(struct i2c_client *client, | |||
398 | if (status < 0) | 315 | if (status < 0) |
399 | goto fail; | 316 | goto fail; |
400 | 317 | ||
318 | /* Enable irqchip if we have an interrupt */ | ||
319 | if (client->irq) { | ||
320 | status = gpiochip_irqchip_add(&gpio->chip, &dummy_irq_chip, 0, | ||
321 | handle_level_irq, IRQ_TYPE_NONE); | ||
322 | if (status) { | ||
323 | dev_err(&client->dev, "cannot add irqchip\n"); | ||
324 | goto fail_irq; | ||
325 | } | ||
326 | |||
327 | status = devm_request_threaded_irq(&client->dev, client->irq, | ||
328 | NULL, pcf857x_irq, IRQF_ONESHOT | | ||
329 | IRQF_TRIGGER_FALLING | IRQF_SHARED, | ||
330 | dev_name(&client->dev), gpio); | ||
331 | if (status) | ||
332 | goto fail_irq; | ||
333 | |||
334 | gpiochip_set_chained_irqchip(&gpio->chip, &dummy_irq_chip, | ||
335 | client->irq, NULL); | ||
336 | } | ||
337 | |||
401 | /* Let platform code set up the GPIOs and their users. | 338 | /* Let platform code set up the GPIOs and their users. |
402 | * Now is the first time anyone could use them. | 339 | * Now is the first time anyone could use them. |
403 | */ | 340 | */ |
@@ -413,13 +350,12 @@ static int pcf857x_probe(struct i2c_client *client, | |||
413 | 350 | ||
414 | return 0; | 351 | return 0; |
415 | 352 | ||
416 | fail: | 353 | fail_irq: |
417 | if (client->irq) | 354 | gpiochip_remove(&gpio->chip); |
418 | pcf857x_irq_domain_cleanup(gpio); | ||
419 | 355 | ||
420 | fail_irq_domain: | 356 | fail: |
421 | dev_dbg(&client->dev, "probe error %d for '%s'\n", | 357 | dev_dbg(&client->dev, "probe error %d for '%s'\n", status, |
422 | status, client->name); | 358 | client->name); |
423 | 359 | ||
424 | return status; | 360 | return status; |
425 | } | 361 | } |
@@ -441,9 +377,6 @@ static int pcf857x_remove(struct i2c_client *client) | |||
441 | } | 377 | } |
442 | } | 378 | } |
443 | 379 | ||
444 | if (client->irq) | ||
445 | pcf857x_irq_domain_cleanup(gpio); | ||
446 | |||
447 | gpiochip_remove(&gpio->chip); | 380 | gpiochip_remove(&gpio->chip); |
448 | return status; | 381 | return status; |
449 | } | 382 | } |