From patchwork Tue Aug 26 10:28:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sonic Zhang X-Patchwork-Id: 383036 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 4BBD814009B for ; Tue, 26 Aug 2014 20:29:01 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754431AbaHZK3A (ORCPT ); Tue, 26 Aug 2014 06:29:00 -0400 Received: from mail-bn1blp0181.outbound.protection.outlook.com ([207.46.163.181]:55924 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754345AbaHZK26 (ORCPT ); Tue, 26 Aug 2014 06:28:58 -0400 Received: from BN3PR0301CA0038.namprd03.prod.outlook.com (25.160.180.176) by DM2PR03MB368.namprd03.prod.outlook.com (10.141.55.22) with Microsoft SMTP Server (TLS) id 15.0.1010.18; Tue, 26 Aug 2014 10:28:55 +0000 Received: from BN1BFFO11FD052.protection.gbl (2a01:111:f400:7c10::1:164) by BN3PR0301CA0038.outlook.office365.com (2a01:111:e400:4000::48) with Microsoft SMTP Server (TLS) id 15.0.1015.19 via Frontend Transport; Tue, 26 Aug 2014 10:28:54 +0000 Received: from nwd2mta1.analog.com (137.71.25.55) by BN1BFFO11FD052.mail.protection.outlook.com (10.58.145.7) with Microsoft SMTP Server (TLS) id 15.0.1010.11 via Frontend Transport; Tue, 26 Aug 2014 10:28:54 +0000 Received: from NWD2HUBCAS9.ad.analog.com (nwd2hubcas9.ad.analog.com [10.64.72.142]) by nwd2mta1.analog.com (8.13.8/8.13.8) with ESMTP id s7QASJhV012165 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=FAIL); Tue, 26 Aug 2014 03:28:19 -0700 Received: from zeus.spd.analog.com (10.64.82.11) by NWD2HUBCAS9.ad.analog.com (10.64.72.142) with Microsoft SMTP Server id 14.3.158.1; Tue, 26 Aug 2014 06:27:53 -0400 Received: from linux.site ([10.99.22.20]) by zeus.spd.analog.com (8.14.6/8.14.6) with ESMTP id s7QARmRg006289; Tue, 26 Aug 2014 06:27:49 -0400 Received: from nine.ad.analog.com (unknown [10.99.24.98]) by linux.site (Postfix) with ESMTP id EC4873AEABF9; Mon, 25 Aug 2014 20:26:49 -0600 (MDT) From: Sonic Zhang To: Linus Walleij , Alexandre Courbot CC: , , Sonic Zhang Subject: [PATCH v2] gpio: make driver mcp23s08 to support both device tree and platform data Date: Tue, 26 Aug 2014 18:28:22 +0800 Message-ID: <1409048902-21316-1-git-send-email-sonic.adi@gmail.com> X-Mailer: git-send-email 1.8.2.3 MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-Matching-Connectors: 130535225350220671; (52f37747-95c3-483a-bd05-08d153b03fac); () X-Forefront-Antispam-Report: CIP:137.71.25.55; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(6009001)(199003)(189002)(87572001)(92566001)(20776003)(21056001)(102836001)(89996001)(92726001)(93916002)(87936001)(6806004)(82202001)(46102001)(55446002)(79102001)(47776003)(50466002)(229853001)(85852003)(74502001)(80022001)(81342001)(62966002)(87286001)(33646002)(81442001)(85306004)(88136002)(50986999)(31966008)(90102001)(86362001)(50226001)(36756003)(81542001)(77982001)(99396002)(105596002)(73972005)(19580405001)(107046002)(19580395003)(77156001)(48376002)(61266001)(83072002)(74662001)(44976005)(104166001)(95666004)(4396001)(73392001)(106466001)(64706001); DIR:OUT; SFP:; SCL:1; SRVR:DM2PR03MB368; H:nwd2mta1.analog.com; FPR:; MLV:sfv; PTR:nwd2mail10.analog.com; A:1; MX:1; LANG:en; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;UriScan:; X-Forefront-PRVS: 03152A99FF Received-SPF: SoftFail (protection.outlook.com: domain of transitioning gmail.com discourages use of 137.71.25.55 as permitted sender) Authentication-Results: spf=softfail (sender IP is 137.71.25.55) smtp.mailfrom=sonic.adi@gmail.com; Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Sonic Zhang Device tree is not enabled in some archtecture where gpio driver mcp23s08 is still required. Signed-off-by: Sonic Zhang v2-changes: - Parse device tree properties into platform data other than individual variables. Reviewed-by: Alexandre Courbot --- drivers/gpio/Kconfig | 1 - drivers/gpio/gpio-mcp23s08.c | 67 +++++++++++++++++++++++++------------------- include/linux/spi/mcp23s08.h | 18 ++++++++++++ 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9de1515..f155b6b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -796,7 +796,6 @@ config GPIO_MAX7301 config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" - depends on OF_GPIO depends on (SPI_MASTER && !I2C) || I2C help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 6f183d9..841815f 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -479,8 +479,13 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) mutex_init(&mcp->irq_lock); +#ifdef CONFIG_OF mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio, &irq_domain_simple_ops, mcp); +#else + mcp->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, + &irq_domain_simple_ops, mcp); +#endif if (!mcp->irq_domain) return -ENODEV; @@ -581,7 +586,7 @@ done: static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, void *data, unsigned addr, unsigned type, - unsigned base, unsigned pullups) + struct mcp23s08_platform_data *pdata, int cs) { int status; bool mirror = false; @@ -635,7 +640,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, return -EINVAL; } - mcp->chip.base = base; + mcp->chip.base = pdata->base; mcp->chip.can_sleep = true; mcp->chip.dev = dev; mcp->chip.owner = THIS_MODULE; @@ -648,11 +653,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (status < 0) goto fail; - mcp->irq_controller = of_property_read_bool(mcp->chip.of_node, - "interrupt-controller"); + mcp->irq_controller = pdata->irq_controller; if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017)) - mirror = of_property_read_bool(mcp->chip.of_node, - "microchip,irq-mirror"); + mirror = pdata->mirror; if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) { /* mcp23s17 has IOCON twice, make sure they are in sync */ @@ -668,7 +671,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } /* configure ~100K pullups */ - status = mcp->ops->write(mcp, MCP_GPPU, pullups); + status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups); if (status < 0) goto fail; @@ -768,25 +771,29 @@ MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match); static int mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct mcp23s08_platform_data *pdata; + struct mcp23s08_platform_data *pdata, local_pdata; struct mcp23s08 *mcp; - int status, base, pullups; + int status; const struct of_device_id *match; match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match), &client->dev); - pdata = dev_get_platdata(&client->dev); - if (match || !pdata) { - base = -1; - pullups = 0; + if (match) { + pdata = &local_pdata; + pdata->base = -1; + pdata->chip[0].pullups = 0; + pdata->irq_controller = of_property_read_bool( + client->dev.of_node, + "interrupt-controller"); + pdata->mirror = of_property_read_bool(client->dev.of_node, + "microchip,irq-mirror"); client->irq = irq_of_parse_and_map(client->dev.of_node, 0); } else { - if (!gpio_is_valid(pdata->base)) { + pdata = dev_get_platdata(&client->dev); + if (!pdata || !gpio_is_valid(pdata->base)) { dev_dbg(&client->dev, "invalid platform data\n"); return -EINVAL; } - base = pdata->base; - pullups = pdata->chip[0].pullups; } mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); @@ -795,7 +802,7 @@ static int mcp230xx_probe(struct i2c_client *client, mcp->irq = client->irq; status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, - id->driver_data, base, pullups); + id->driver_data, pdata, 0); if (status) goto fail; @@ -863,14 +870,12 @@ static void mcp23s08_i2c_exit(void) { } static int mcp23s08_probe(struct spi_device *spi) { - struct mcp23s08_platform_data *pdata; + struct mcp23s08_platform_data *pdata, local_pdata; unsigned addr; int chips = 0; struct mcp23s08_driver_data *data; int status, type; - unsigned base = -1, - ngpio = 0, - pullups[ARRAY_SIZE(pdata->chip)]; + unsigned ngpio = 0; const struct of_device_id *match; u32 spi_present_mask = 0; @@ -893,11 +898,18 @@ static int mcp23s08_probe(struct spi_device *spi) return -ENODEV; } + pdata = &local_pdata; + pdata->base = -1; for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { - pullups[addr] = 0; + pdata->chip[addr].pullups = 0; if (spi_present_mask & (1 << addr)) chips++; } + pdata->irq_controller = of_property_read_bool( + spi->dev.of_node, + "interrupt-controller"); + pdata->mirror = of_property_read_bool(spi->dev.of_node, + "microchip,irq-mirror"); } else { type = spi_get_device_id(spi)->driver_data; pdata = dev_get_platdata(&spi->dev); @@ -917,10 +929,7 @@ static int mcp23s08_probe(struct spi_device *spi) return -EINVAL; } spi_present_mask |= 1 << addr; - pullups[addr] = pdata->chip[addr].pullups; } - - base = pdata->base; } if (!chips) @@ -938,13 +947,13 @@ static int mcp23s08_probe(struct spi_device *spi) chips--; data->mcp[addr] = &data->chip[chips]; status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, - 0x40 | (addr << 1), type, base, - pullups[addr]); + 0x40 | (addr << 1), type, pdata, + addr); if (status < 0) goto fail; - if (base != -1) - base += (type == MCP_TYPE_S17) ? 16 : 8; + if (pdata->base != -1) + pdata->base += (type == MCP_TYPE_S17) ? 16 : 8; ngpio += (type == MCP_TYPE_S17) ? 16 : 8; } data->ngpio = ngpio; diff --git a/include/linux/spi/mcp23s08.h b/include/linux/spi/mcp23s08.h index 2d676d5..aa07d7b 100644 --- a/include/linux/spi/mcp23s08.h +++ b/include/linux/spi/mcp23s08.h @@ -22,4 +22,22 @@ struct mcp23s08_platform_data { * base to base+15 (or base+31 for s17 variant). */ unsigned base; + /* Marks the device as a interrupt controller. + * NOTE: The interrupt functionality is only supported for i2c + * versions of the chips. The spi chips can also do the interrupts, + * but this is not supported by the linux driver yet. + */ + bool irq_controller; + + /* Sets the mirror flag in the IOCON register. Devices + * with two interrupt outputs (these are the devices ending with 17 and + * those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and + * IO 8-15 are bank 2. These chips have two different interrupt outputs: + * One for bank 1 and another for bank 2. If irq-mirror is set, both + * interrupts are generated regardless of the bank that an input change + * occurred on. If it is not set, the interrupt are only generated for + * the bank they belong to. + * On devices with only one interrupt output this property is useless. + */ + bool mirror; };