From patchwork Mon Sep 1 03:19:52 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sonic Zhang X-Patchwork-Id: 384653 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 B5ED71401DB for ; Mon, 1 Sep 2014 14:52:57 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750839AbaIAEwx (ORCPT ); Mon, 1 Sep 2014 00:52:53 -0400 Received: from mail-bn1on0091.outbound.protection.outlook.com ([157.56.110.91]:56146 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750749AbaIAEwx (ORCPT ); Mon, 1 Sep 2014 00:52:53 -0400 X-Greylist: delayed 5528 seconds by postgrey-1.27 at vger.kernel.org; Mon, 01 Sep 2014 00:52:52 EDT Received: from BN3PR0301CA0046.namprd03.prod.outlook.com (25.160.152.142) by BY2PR03MB363.namprd03.prod.outlook.com (10.242.237.16) with Microsoft SMTP Server (TLS) id 15.0.1015.17; Mon, 1 Sep 2014 03:20:42 +0000 Received: from BY2FFO11FD031.protection.gbl (2a01:111:f400:7c0c::128) by BN3PR0301CA0046.outlook.office365.com (2a01:111:e400:401e::14) with Microsoft SMTP Server (TLS) id 15.0.1019.16 via Frontend Transport; Mon, 1 Sep 2014 03:20:41 +0000 Received: from nwd2mta1.analog.com (137.71.25.55) by BY2FFO11FD031.mail.protection.outlook.com (10.1.14.196) with Microsoft SMTP Server (TLS) id 15.0.1010.11 via Frontend Transport; Mon, 1 Sep 2014 03:20:40 +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 s813K3t0003077 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=FAIL); Sun, 31 Aug 2014 20:20:03 -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; Sun, 31 Aug 2014 23:19:28 -0400 Received: from linux.site ([10.99.22.20]) by zeus.spd.analog.com (8.14.6/8.14.6) with ESMTP id s813JPvl021893; Sun, 31 Aug 2014 23:19:26 -0400 Received: from nine.ad.analog.com (unknown [10.99.24.98]) by linux.site (Postfix) with ESMTP id 469BD3AEABF9; Sun, 31 Aug 2014 13:18:36 -0600 (MDT) From: Sonic Zhang To: Linus Walleij , Alexandre Courbot CC: , , Sonic Zhang Subject: [PATCH v3] gpio: make driver mcp23s08 to support both device tree and platform data Date: Mon, 1 Sep 2014 11:19:52 +0800 Message-ID: <1409541592-27787-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: 130540152411015846; (52f37747-95c3-483a-bd05-08d153b03fac); () X-Forefront-Antispam-Report: CIP:137.71.25.55; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10009013)(6009001)(189002)(199003)(89996001)(47776003)(95666004)(105596002)(104166001)(80022001)(36756003)(61266001)(46102001)(6806004)(92726001)(62966002)(19580405001)(74502001)(50986999)(88136002)(81542001)(81442001)(82202001)(92566001)(83072002)(87936001)(107046002)(87572001)(87286001)(99396002)(86362001)(33646002)(79102001)(90102001)(73972005)(21056001)(50226001)(4396001)(50466002)(73392001)(64706001)(106466001)(229853001)(48376002)(77982001)(81342001)(55446002)(44976005)(74662001)(20776003)(77156001)(85852003)(31966008)(19580395003)(93916002)(102836001)(85306004); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR03MB363; H:nwd2mta1.analog.com; FPR:; MLV:sfv; PTR:nwd2mail10.analog.com; MX:1; A:1; LANG:en; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;UriScan:; X-Forefront-PRVS: 03218BFD9F 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 Reviewed-by: Alexandre Courbot 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. --- drivers/gpio/Kconfig | 1 - drivers/gpio/gpio-mcp23s08.c | 64 +++++++++++++++++++++++--------------------- include/linux/spi/mcp23s08.h | 18 +++++++++++++ 3 files changed, 52 insertions(+), 31 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..8488e2f 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) mutex_init(&mcp->irq_lock); - mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio, + mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio, &irq_domain_simple_ops, mcp); if (!mcp->irq_domain) return -ENODEV; @@ -581,7 +581,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 +635,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 +648,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 +666,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 +766,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 +797,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 +865,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 +893,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 +924,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 +942,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; };