aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2014-08-31 23:19:52 -0400
committerLinus Walleij <linus.walleij@linaro.org>2014-09-04 12:59:15 -0400
commit3af0dbd592fe0a92002f16e341519ba03e92adf7 (patch)
tree2e9d28522004ab8a16283fc8cc33d6de13cbdbc6
parent59e22114b253aaa7caf14221df4dcf924d067922 (diff)
gpio: mcp23s08 to support both device tree and platform data
Device tree is not enabled in some architecture where gpio driver mcp23s08 is still required. v2-changes: - Parse device tree properties into platform data other than individual variables. v3-changes: - Use of_node in gpio_chip device structure, because the struct device * always has an of_node which is NULL when OF is not used. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/Kconfig1
-rw-r--r--drivers/gpio/gpio-mcp23s08.c64
-rw-r--r--include/linux/spi/mcp23s08.h18
3 files changed, 52 insertions, 31 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ec27ec0be8c2..ec398bee7c60 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -806,7 +806,6 @@ config GPIO_MAX7301
806 806
807config GPIO_MCP23S08 807config GPIO_MCP23S08
808 tristate "Microchip MCP23xxx I/O expander" 808 tristate "Microchip MCP23xxx I/O expander"
809 depends on OF_GPIO
810 depends on (SPI_MASTER && !I2C) || I2C 809 depends on (SPI_MASTER && !I2C) || I2C
811 help 810 help
812 SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 811 SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 6f183d9b487e..8488e2fd307c 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -479,7 +479,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
479 479
480 mutex_init(&mcp->irq_lock); 480 mutex_init(&mcp->irq_lock);
481 481
482 mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio, 482 mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio,
483 &irq_domain_simple_ops, mcp); 483 &irq_domain_simple_ops, mcp);
484 if (!mcp->irq_domain) 484 if (!mcp->irq_domain)
485 return -ENODEV; 485 return -ENODEV;
@@ -581,7 +581,7 @@ done:
581 581
582static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, 582static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
583 void *data, unsigned addr, unsigned type, 583 void *data, unsigned addr, unsigned type,
584 unsigned base, unsigned pullups) 584 struct mcp23s08_platform_data *pdata, int cs)
585{ 585{
586 int status; 586 int status;
587 bool mirror = false; 587 bool mirror = false;
@@ -635,7 +635,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
635 return -EINVAL; 635 return -EINVAL;
636 } 636 }
637 637
638 mcp->chip.base = base; 638 mcp->chip.base = pdata->base;
639 mcp->chip.can_sleep = true; 639 mcp->chip.can_sleep = true;
640 mcp->chip.dev = dev; 640 mcp->chip.dev = dev;
641 mcp->chip.owner = THIS_MODULE; 641 mcp->chip.owner = THIS_MODULE;
@@ -648,11 +648,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
648 if (status < 0) 648 if (status < 0)
649 goto fail; 649 goto fail;
650 650
651 mcp->irq_controller = of_property_read_bool(mcp->chip.of_node, 651 mcp->irq_controller = pdata->irq_controller;
652 "interrupt-controller");
653 if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017)) 652 if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
654 mirror = of_property_read_bool(mcp->chip.of_node, 653 mirror = pdata->mirror;
655 "microchip,irq-mirror");
656 654
657 if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) { 655 if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
658 /* mcp23s17 has IOCON twice, make sure they are in sync */ 656 /* mcp23s17 has IOCON twice, make sure they are in sync */
@@ -668,7 +666,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
668 } 666 }
669 667
670 /* configure ~100K pullups */ 668 /* configure ~100K pullups */
671 status = mcp->ops->write(mcp, MCP_GPPU, pullups); 669 status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups);
672 if (status < 0) 670 if (status < 0)
673 goto fail; 671 goto fail;
674 672
@@ -768,25 +766,29 @@ MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
768static int mcp230xx_probe(struct i2c_client *client, 766static int mcp230xx_probe(struct i2c_client *client,
769 const struct i2c_device_id *id) 767 const struct i2c_device_id *id)
770{ 768{
771 struct mcp23s08_platform_data *pdata; 769 struct mcp23s08_platform_data *pdata, local_pdata;
772 struct mcp23s08 *mcp; 770 struct mcp23s08 *mcp;
773 int status, base, pullups; 771 int status;
774 const struct of_device_id *match; 772 const struct of_device_id *match;
775 773
776 match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), 774 match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
777 &client->dev); 775 &client->dev);
778 pdata = dev_get_platdata(&client->dev); 776 if (match) {
779 if (match || !pdata) { 777 pdata = &local_pdata;
780 base = -1; 778 pdata->base = -1;
781 pullups = 0; 779 pdata->chip[0].pullups = 0;
780 pdata->irq_controller = of_property_read_bool(
781 client->dev.of_node,
782 "interrupt-controller");
783 pdata->mirror = of_property_read_bool(client->dev.of_node,
784 "microchip,irq-mirror");
782 client->irq = irq_of_parse_and_map(client->dev.of_node, 0); 785 client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
783 } else { 786 } else {
784 if (!gpio_is_valid(pdata->base)) { 787 pdata = dev_get_platdata(&client->dev);
788 if (!pdata || !gpio_is_valid(pdata->base)) {
785 dev_dbg(&client->dev, "invalid platform data\n"); 789 dev_dbg(&client->dev, "invalid platform data\n");
786 return -EINVAL; 790 return -EINVAL;
787 } 791 }
788 base = pdata->base;
789 pullups = pdata->chip[0].pullups;
790 } 792 }
791 793
792 mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); 794 mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
@@ -795,7 +797,7 @@ static int mcp230xx_probe(struct i2c_client *client,
795 797
796 mcp->irq = client->irq; 798 mcp->irq = client->irq;
797 status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, 799 status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
798 id->driver_data, base, pullups); 800 id->driver_data, pdata, 0);
799 if (status) 801 if (status)
800 goto fail; 802 goto fail;
801 803
@@ -863,14 +865,12 @@ static void mcp23s08_i2c_exit(void) { }
863 865
864static int mcp23s08_probe(struct spi_device *spi) 866static int mcp23s08_probe(struct spi_device *spi)
865{ 867{
866 struct mcp23s08_platform_data *pdata; 868 struct mcp23s08_platform_data *pdata, local_pdata;
867 unsigned addr; 869 unsigned addr;
868 int chips = 0; 870 int chips = 0;
869 struct mcp23s08_driver_data *data; 871 struct mcp23s08_driver_data *data;
870 int status, type; 872 int status, type;
871 unsigned base = -1, 873 unsigned ngpio = 0;
872 ngpio = 0,
873 pullups[ARRAY_SIZE(pdata->chip)];
874 const struct of_device_id *match; 874 const struct of_device_id *match;
875 u32 spi_present_mask = 0; 875 u32 spi_present_mask = 0;
876 876
@@ -893,11 +893,18 @@ static int mcp23s08_probe(struct spi_device *spi)
893 return -ENODEV; 893 return -ENODEV;
894 } 894 }
895 895
896 pdata = &local_pdata;
897 pdata->base = -1;
896 for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { 898 for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
897 pullups[addr] = 0; 899 pdata->chip[addr].pullups = 0;
898 if (spi_present_mask & (1 << addr)) 900 if (spi_present_mask & (1 << addr))
899 chips++; 901 chips++;
900 } 902 }
903 pdata->irq_controller = of_property_read_bool(
904 spi->dev.of_node,
905 "interrupt-controller");
906 pdata->mirror = of_property_read_bool(spi->dev.of_node,
907 "microchip,irq-mirror");
901 } else { 908 } else {
902 type = spi_get_device_id(spi)->driver_data; 909 type = spi_get_device_id(spi)->driver_data;
903 pdata = dev_get_platdata(&spi->dev); 910 pdata = dev_get_platdata(&spi->dev);
@@ -917,10 +924,7 @@ static int mcp23s08_probe(struct spi_device *spi)
917 return -EINVAL; 924 return -EINVAL;
918 } 925 }
919 spi_present_mask |= 1 << addr; 926 spi_present_mask |= 1 << addr;
920 pullups[addr] = pdata->chip[addr].pullups;
921 } 927 }
922
923 base = pdata->base;
924 } 928 }
925 929
926 if (!chips) 930 if (!chips)
@@ -938,13 +942,13 @@ static int mcp23s08_probe(struct spi_device *spi)
938 chips--; 942 chips--;
939 data->mcp[addr] = &data->chip[chips]; 943 data->mcp[addr] = &data->chip[chips];
940 status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, 944 status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
941 0x40 | (addr << 1), type, base, 945 0x40 | (addr << 1), type, pdata,
942 pullups[addr]); 946 addr);
943 if (status < 0) 947 if (status < 0)
944 goto fail; 948 goto fail;
945 949
946 if (base != -1) 950 if (pdata->base != -1)
947 base += (type == MCP_TYPE_S17) ? 16 : 8; 951 pdata->base += (type == MCP_TYPE_S17) ? 16 : 8;
948 ngpio += (type == MCP_TYPE_S17) ? 16 : 8; 952 ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
949 } 953 }
950 data->ngpio = ngpio; 954 data->ngpio = ngpio;
diff --git a/include/linux/spi/mcp23s08.h b/include/linux/spi/mcp23s08.h
index 2d676d5aaa89..aa07d7b32568 100644
--- a/include/linux/spi/mcp23s08.h
+++ b/include/linux/spi/mcp23s08.h
@@ -22,4 +22,22 @@ struct mcp23s08_platform_data {
22 * base to base+15 (or base+31 for s17 variant). 22 * base to base+15 (or base+31 for s17 variant).
23 */ 23 */
24 unsigned base; 24 unsigned base;
25 /* Marks the device as a interrupt controller.
26 * NOTE: The interrupt functionality is only supported for i2c
27 * versions of the chips. The spi chips can also do the interrupts,
28 * but this is not supported by the linux driver yet.
29 */
30 bool irq_controller;
31
32 /* Sets the mirror flag in the IOCON register. Devices
33 * with two interrupt outputs (these are the devices ending with 17 and
34 * those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and
35 * IO 8-15 are bank 2. These chips have two different interrupt outputs:
36 * One for bank 1 and another for bank 2. If irq-mirror is set, both
37 * interrupts are generated regardless of the bank that an input change
38 * occurred on. If it is not set, the interrupt are only generated for
39 * the bank they belong to.
40 * On devices with only one interrupt output this property is useless.
41 */
42 bool mirror;
25}; 43};