aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-mcp23s08.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-21 12:40:46 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-21 13:09:12 -0500
commit8e5096607280d4e103389bfe8f8b7decbf538ff6 (patch)
tree60352a466e96c7b36d41263d7590ee79e0aaff35 /drivers/gpio/gpio-mcp23s08.c
parent02d0a752460ea5dab34ce36c9ddc9c682e846a0d (diff)
parentde755c330512364d3396c7da0c20b1c20b3b08b2 (diff)
Merge tag 'gpio-v3.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO tree bulk changes from Linus Walleij: "A big set this merge window, as we have much going on in this subsystem. The changes to other subsystems (notably a slew of ARM machines as I am doing away with their custom APIs) have all been ACKed to the extent possible. Major changes this time: - Some core improvements and cleanups to the new GPIO descriptor API. This seems to be working now so we can start the exodus to this API, moving gradually away from the global GPIO numberspace. - Incremental improvements to the ACPI GPIO core, and move the few GPIO ACPI clients we have to the GPIO descriptor API right *now* before we go any further. We actually managed to contain this *before* we started to litter the kernel with yet another hackish global numberspace for the ACPI GPIOs, which is a big win. - The RFkill GPIO driver and all platforms using it have been migrated to use the GPIO descriptors rather than fixed number assignments. Tegra machine has been migrated as part of this. - New drivers for MOXA ART, Xtensa GPIO32 and SMSC SCH311x. Those should be really good examples of how I expect a nice GPIO driver to look these days. - Do away with custom GPIO implementations on a major part of the ARM machines: ks8695, lpc32xx, mv78xx0. Make a first step towards the same in the horribly convoluted Samsung S3C include forest. We expect to continue to clean this up as we move forward. - Flag GPIO lines used for IRQ on adnp, bcm-kona, em, intel-mid and lynxpoint. This makes the GPIOlib core aware that a certain GPIO line is used for IRQs and can then enforce some semantics such as disallowing a GPIO line marked as in use for IRQ to be switched to output mode. - Drop all use of irq_set_chip_and_handler_name(). The name provided in these cases were just unhelpful tags like "mux" or "demux". - Extend the MCP23s08 driver to handle interrupts. - Minor incremental improvements for rcar, lynxpoint, em 74x164 and msm drivers. - Some non-urgent bug fixes here and there, duplicate #includes and that usual kind of cleanups" Fix up broken Kconfig file manually to make this all compile. * tag 'gpio-v3.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (71 commits) gpio: mcp23s08: fix casting caused build warning gpio: mcp23s08: depend on OF_GPIO gpio: mcp23s08: Add irq functionality for i2c chips ARM: S5P[v210|c100|64x0]: Fix build error gpio: pxa: clamp gpio get value to [0,1] ARM: s3c24xx: explicit dependency on <plat/gpio-cfg.h> ARM: S3C[24|64]xx: move includes back under <mach/> scope Documentation / ACPI: update to GPIO descriptor API gpio / ACPI: get rid of acpi_gpio.h gpio / ACPI: register to ACPI events automatically mmc: sdhci-acpi: convert to use GPIO descriptor API ARM: s3c24xx: fix build error gpio: f7188x: set can_sleep attribute gpio: samsung: Update documentation gpio: samsung: Remove hardware.h inclusion gpio: xtensa: depend on HAVE_XTENSA_GPIO32 gpio: clps711x: Enable driver compilation with COMPILE_TEST gpio: clps711x: Use of_match_ptr() net: rfkill: gpio: convert to descriptor-based GPIO interface leds: s3c24xx: Fix build failure ...
Diffstat (limited to 'drivers/gpio/gpio-mcp23s08.c')
-rw-r--r--drivers/gpio/gpio-mcp23s08.c252
1 files changed, 245 insertions, 7 deletions
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 2deb0c5e54a4..1ac288ea810d 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -1,5 +1,13 @@
1/* 1/*
2 * MCP23S08 SPI/GPIO gpio expander driver 2 * MCP23S08 SPI/I2C GPIO gpio expander driver
3 *
4 * The inputs and outputs of the mcp23s08, mcp23s17, mcp23008 and mcp23017 are
5 * supported.
6 * For the I2C versions of the chips (mcp23008 and mcp23017) generation of
7 * interrupts is also supported.
8 * The hardware of the SPI versions of the chips (mcp23s08 and mcp23s17) is
9 * also capable of generating interrupts, but the linux driver does not
10 * support that yet.
3 */ 11 */
4 12
5#include <linux/kernel.h> 13#include <linux/kernel.h>
@@ -12,7 +20,8 @@
12#include <linux/spi/mcp23s08.h> 20#include <linux/spi/mcp23s08.h>
13#include <linux/slab.h> 21#include <linux/slab.h>
14#include <asm/byteorder.h> 22#include <asm/byteorder.h>
15#include <linux/of.h> 23#include <linux/interrupt.h>
24#include <linux/of_irq.h>
16#include <linux/of_device.h> 25#include <linux/of_device.h>
17 26
18/** 27/**
@@ -34,6 +43,7 @@
34#define MCP_DEFVAL 0x03 43#define MCP_DEFVAL 0x03
35#define MCP_INTCON 0x04 44#define MCP_INTCON 0x04
36#define MCP_IOCON 0x05 45#define MCP_IOCON 0x05
46# define IOCON_MIRROR (1 << 6)
37# define IOCON_SEQOP (1 << 5) 47# define IOCON_SEQOP (1 << 5)
38# define IOCON_HAEN (1 << 3) 48# define IOCON_HAEN (1 << 3)
39# define IOCON_ODR (1 << 2) 49# define IOCON_ODR (1 << 2)
@@ -57,8 +67,14 @@ struct mcp23s08 {
57 u8 addr; 67 u8 addr;
58 68
59 u16 cache[11]; 69 u16 cache[11];
70 u16 irq_rise;
71 u16 irq_fall;
72 int irq;
73 bool irq_controller;
60 /* lock protects the cached values */ 74 /* lock protects the cached values */
61 struct mutex lock; 75 struct mutex lock;
76 struct mutex irq_lock;
77 struct irq_domain *irq_domain;
62 78
63 struct gpio_chip chip; 79 struct gpio_chip chip;
64 80
@@ -77,6 +93,11 @@ struct mcp23s08_driver_data {
77 struct mcp23s08 chip[]; 93 struct mcp23s08 chip[];
78}; 94};
79 95
96/* This lock class tells lockdep that GPIO irqs are in a different
97 * category than their parents, so it won't report false recursion.
98 */
99static struct lock_class_key gpio_lock_class;
100
80/*----------------------------------------------------------------------*/ 101/*----------------------------------------------------------------------*/
81 102
82#if IS_ENABLED(CONFIG_I2C) 103#if IS_ENABLED(CONFIG_I2C)
@@ -316,6 +337,195 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
316} 337}
317 338
318/*----------------------------------------------------------------------*/ 339/*----------------------------------------------------------------------*/
340static irqreturn_t mcp23s08_irq(int irq, void *data)
341{
342 struct mcp23s08 *mcp = data;
343 int intcap, intf, i;
344 unsigned int child_irq;
345
346 mutex_lock(&mcp->lock);
347 intf = mcp->ops->read(mcp, MCP_INTF);
348 if (intf < 0) {
349 mutex_unlock(&mcp->lock);
350 return IRQ_HANDLED;
351 }
352
353 mcp->cache[MCP_INTF] = intf;
354
355 intcap = mcp->ops->read(mcp, MCP_INTCAP);
356 if (intcap < 0) {
357 mutex_unlock(&mcp->lock);
358 return IRQ_HANDLED;
359 }
360
361 mcp->cache[MCP_INTCAP] = intcap;
362 mutex_unlock(&mcp->lock);
363
364
365 for (i = 0; i < mcp->chip.ngpio; i++) {
366 if ((BIT(i) & mcp->cache[MCP_INTF]) &&
367 ((BIT(i) & intcap & mcp->irq_rise) ||
368 (mcp->irq_fall & ~intcap & BIT(i)))) {
369 child_irq = irq_find_mapping(mcp->irq_domain, i);
370 handle_nested_irq(child_irq);
371 }
372 }
373
374 return IRQ_HANDLED;
375}
376
377static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
378{
379 struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
380
381 return irq_find_mapping(mcp->irq_domain, offset);
382}
383
384static void mcp23s08_irq_mask(struct irq_data *data)
385{
386 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
387 unsigned int pos = data->hwirq;
388
389 mcp->cache[MCP_GPINTEN] &= ~BIT(pos);
390}
391
392static void mcp23s08_irq_unmask(struct irq_data *data)
393{
394 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
395 unsigned int pos = data->hwirq;
396
397 mcp->cache[MCP_GPINTEN] |= BIT(pos);
398}
399
400static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)
401{
402 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
403 unsigned int pos = data->hwirq;
404 int status = 0;
405
406 if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
407 mcp->cache[MCP_INTCON] &= ~BIT(pos);
408 mcp->irq_rise |= BIT(pos);
409 mcp->irq_fall |= BIT(pos);
410 } else if (type & IRQ_TYPE_EDGE_RISING) {
411 mcp->cache[MCP_INTCON] &= ~BIT(pos);
412 mcp->irq_rise |= BIT(pos);
413 mcp->irq_fall &= ~BIT(pos);
414 } else if (type & IRQ_TYPE_EDGE_FALLING) {
415 mcp->cache[MCP_INTCON] &= ~BIT(pos);
416 mcp->irq_rise &= ~BIT(pos);
417 mcp->irq_fall |= BIT(pos);
418 } else
419 return -EINVAL;
420
421 return status;
422}
423
424static void mcp23s08_irq_bus_lock(struct irq_data *data)
425{
426 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
427
428 mutex_lock(&mcp->irq_lock);
429}
430
431static void mcp23s08_irq_bus_unlock(struct irq_data *data)
432{
433 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
434
435 mutex_lock(&mcp->lock);
436 mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]);
437 mcp->ops->write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]);
438 mcp->ops->write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]);
439 mutex_unlock(&mcp->lock);
440 mutex_unlock(&mcp->irq_lock);
441}
442
443static unsigned int mcp23s08_irq_startup(struct irq_data *data)
444{
445 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
446
447 if (gpio_lock_as_irq(&mcp->chip, data->hwirq))
448 dev_err(mcp->chip.dev,
449 "unable to lock HW IRQ %lu for IRQ usage\n",
450 data->hwirq);
451
452 mcp23s08_irq_unmask(data);
453 return 0;
454}
455
456static void mcp23s08_irq_shutdown(struct irq_data *data)
457{
458 struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
459
460 mcp23s08_irq_mask(data);
461 gpio_unlock_as_irq(&mcp->chip, data->hwirq);
462}
463
464static struct irq_chip mcp23s08_irq_chip = {
465 .name = "gpio-mcp23xxx",
466 .irq_mask = mcp23s08_irq_mask,
467 .irq_unmask = mcp23s08_irq_unmask,
468 .irq_set_type = mcp23s08_irq_set_type,
469 .irq_bus_lock = mcp23s08_irq_bus_lock,
470 .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock,
471 .irq_startup = mcp23s08_irq_startup,
472 .irq_shutdown = mcp23s08_irq_shutdown,
473};
474
475static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
476{
477 struct gpio_chip *chip = &mcp->chip;
478 int err, irq, j;
479
480 mutex_init(&mcp->irq_lock);
481
482 mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
483 &irq_domain_simple_ops, mcp);
484 if (!mcp->irq_domain)
485 return -ENODEV;
486
487 err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq,
488 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
489 dev_name(chip->dev), mcp);
490 if (err != 0) {
491 dev_err(chip->dev, "unable to request IRQ#%d: %d\n",
492 mcp->irq, err);
493 return err;
494 }
495
496 chip->to_irq = mcp23s08_gpio_to_irq;
497
498 for (j = 0; j < mcp->chip.ngpio; j++) {
499 irq = irq_create_mapping(mcp->irq_domain, j);
500 irq_set_lockdep_class(irq, &gpio_lock_class);
501 irq_set_chip_data(irq, mcp);
502 irq_set_chip(irq, &mcp23s08_irq_chip);
503 irq_set_nested_thread(irq, true);
504#ifdef CONFIG_ARM
505 set_irq_flags(irq, IRQF_VALID);
506#else
507 irq_set_noprobe(irq);
508#endif
509 }
510 return 0;
511}
512
513static void mcp23s08_irq_teardown(struct mcp23s08 *mcp)
514{
515 unsigned int irq, i;
516
517 free_irq(mcp->irq, mcp);
518
519 for (i = 0; i < mcp->chip.ngpio; i++) {
520 irq = irq_find_mapping(mcp->irq_domain, i);
521 if (irq > 0)
522 irq_dispose_mapping(irq);
523 }
524
525 irq_domain_remove(mcp->irq_domain);
526}
527
528/*----------------------------------------------------------------------*/
319 529
320#ifdef CONFIG_DEBUG_FS 530#ifdef CONFIG_DEBUG_FS
321 531
@@ -370,10 +580,11 @@ done:
370/*----------------------------------------------------------------------*/ 580/*----------------------------------------------------------------------*/
371 581
372static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, 582static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
373 void *data, unsigned addr, 583 void *data, unsigned addr, unsigned type,
374 unsigned type, unsigned base, unsigned pullups) 584 unsigned base, unsigned pullups)
375{ 585{
376 int status; 586 int status;
587 bool mirror = false;
377 588
378 mutex_init(&mcp->lock); 589 mutex_init(&mcp->lock);
379 590
@@ -425,20 +636,32 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
425 } 636 }
426 637
427 mcp->chip.base = base; 638 mcp->chip.base = base;
428 mcp->chip.can_sleep = 1; 639 mcp->chip.can_sleep = true;
429 mcp->chip.dev = dev; 640 mcp->chip.dev = dev;
430 mcp->chip.owner = THIS_MODULE; 641 mcp->chip.owner = THIS_MODULE;
431 642
432 /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, 643 /* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
433 * and MCP_IOCON.HAEN = 1, so we work with all chips. 644 * and MCP_IOCON.HAEN = 1, so we work with all chips.
434 */ 645 */
646
435 status = mcp->ops->read(mcp, MCP_IOCON); 647 status = mcp->ops->read(mcp, MCP_IOCON);
436 if (status < 0) 648 if (status < 0)
437 goto fail; 649 goto fail;
438 if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { 650
651 mcp->irq_controller = of_property_read_bool(mcp->chip.of_node,
652 "interrupt-controller");
653 if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
654 mirror = of_property_read_bool(mcp->chip.of_node,
655 "microchip,irq-mirror");
656
657 if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
439 /* mcp23s17 has IOCON twice, make sure they are in sync */ 658 /* mcp23s17 has IOCON twice, make sure they are in sync */
440 status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); 659 status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8));
441 status |= IOCON_HAEN | (IOCON_HAEN << 8); 660 status |= IOCON_HAEN | (IOCON_HAEN << 8);
661 status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8));
662 if (mirror)
663 status |= IOCON_MIRROR | (IOCON_MIRROR << 8);
664
442 status = mcp->ops->write(mcp, MCP_IOCON, status); 665 status = mcp->ops->write(mcp, MCP_IOCON, status);
443 if (status < 0) 666 if (status < 0)
444 goto fail; 667 goto fail;
@@ -470,6 +693,16 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
470 } 693 }
471 694
472 status = gpiochip_add(&mcp->chip); 695 status = gpiochip_add(&mcp->chip);
696 if (status < 0)
697 goto fail;
698
699 if (mcp->irq && mcp->irq_controller) {
700 status = mcp23s08_irq_setup(mcp);
701 if (status) {
702 mcp23s08_irq_teardown(mcp);
703 goto fail;
704 }
705 }
473fail: 706fail:
474 if (status < 0) 707 if (status < 0)
475 dev_dbg(dev, "can't setup chip %d, --> %d\n", 708 dev_dbg(dev, "can't setup chip %d, --> %d\n",
@@ -546,6 +779,7 @@ static int mcp230xx_probe(struct i2c_client *client,
546 if (match || !pdata) { 779 if (match || !pdata) {
547 base = -1; 780 base = -1;
548 pullups = 0; 781 pullups = 0;
782 client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
549 } else { 783 } else {
550 if (!gpio_is_valid(pdata->base)) { 784 if (!gpio_is_valid(pdata->base)) {
551 dev_dbg(&client->dev, "invalid platform data\n"); 785 dev_dbg(&client->dev, "invalid platform data\n");
@@ -559,6 +793,7 @@ static int mcp230xx_probe(struct i2c_client *client,
559 if (!mcp) 793 if (!mcp)
560 return -ENOMEM; 794 return -ENOMEM;
561 795
796 mcp->irq = client->irq;
562 status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, 797 status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
563 id->driver_data, base, pullups); 798 id->driver_data, base, pullups);
564 if (status) 799 if (status)
@@ -579,6 +814,9 @@ static int mcp230xx_remove(struct i2c_client *client)
579 struct mcp23s08 *mcp = i2c_get_clientdata(client); 814 struct mcp23s08 *mcp = i2c_get_clientdata(client);
580 int status; 815 int status;
581 816
817 if (client->irq && mcp->irq_controller)
818 mcp23s08_irq_teardown(mcp);
819
582 status = gpiochip_remove(&mcp->chip); 820 status = gpiochip_remove(&mcp->chip);
583 if (status == 0) 821 if (status == 0)
584 kfree(mcp); 822 kfree(mcp);
@@ -640,7 +878,7 @@ static int mcp23s08_probe(struct spi_device *spi)
640 878
641 match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev); 879 match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev);
642 if (match) { 880 if (match) {
643 type = (int)match->data; 881 type = (int)(uintptr_t)match->data;
644 status = of_property_read_u32(spi->dev.of_node, 882 status = of_property_read_u32(spi->dev.of_node,
645 "microchip,spi-present-mask", &spi_present_mask); 883 "microchip,spi-present-mask", &spi_present_mask);
646 if (status) { 884 if (status) {