From patchwork Mon Dec 15 01:25:18 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Sverdlin X-Patchwork-Id: 420938 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 1ED461400E2 for ; Mon, 15 Dec 2014 12:25:35 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751737AbaLOBZd (ORCPT ); Sun, 14 Dec 2014 20:25:33 -0500 Received: from demumfd002.nsn-inter.net ([93.183.12.31]:39859 "EHLO demumfd002.nsn-inter.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750702AbaLOBZd (ORCPT ); Sun, 14 Dec 2014 20:25:33 -0500 Received: from demuprx017.emea.nsn-intra.net ([10.150.129.56]) by demumfd002.nsn-inter.net (8.14.3/8.14.3) with ESMTP id sBF1PLHq002500 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 15 Dec 2014 01:25:21 GMT Received: from [10.150.176.217] ([10.150.176.217]) by demuprx017.emea.nsn-intra.net (8.12.11.20060308/8.12.11) with ESMTP id sBF1PI0p013706; Mon, 15 Dec 2014 02:25:18 +0100 Message-ID: <548E387E.2020502@nsn.com> Date: Mon, 15 Dec 2014 02:25:18 +0100 From: Alexander Sverdlin User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.1.2 MIME-Version: 1.0 To: Jean Delvare , devicetree@vger.kernel.org, linux-i2c@vger.kernel.org CC: Rob Herring , grant.likely@linaro.org, Laurent Pinchart , Lawnick Michael 61283229 , Maxime Ripard , Stephen Warren Subject: [PATCH] of: i2c: Add DT bindings for idle states to PCA954x mux driver X-purgate-type: clean X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: clean X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate-size: 4592 X-purgate-ID: 151667::1418606721-0000677A-FDB9FC9B/0/0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org of: i2c: Add DT bindings for idle states to PCA954x mux driver Introduce two new device tree bindings to specify idle state of PCA954x family of I2C multiplexors: - idle-state: specifies particular child bus to be selected in idle; - idle-disconnect: signals that mux should disconnect all child buses in idle; Signed-off-by: Alexander Sverdlin --- .../devicetree/bindings/i2c/i2c-mux-pca954x.txt | 3 + drivers/i2c/muxes/i2c-mux-pca954x.c | 51 +++++++++++++++++-- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt index 34a3fb6..1fbe287 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt @@ -16,6 +16,9 @@ Required Properties: Optional Properties: - reset-gpios: Reference to the GPIO connected to the reset input. + - idle-state: Child bus connected in idle state (specified by its "reg" value) + - idle-disconnect: Boolean; if defined, forces mux to disconnect all children + in idle state Example: diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index ec11b40..69cf603 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -43,6 +43,7 @@ #include #include #include +#include #define PCA954X_MAX_NCHANS 8 @@ -62,6 +63,8 @@ struct pca954x { struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS]; u8 last_chan; /* last register value */ + bool idle_disconnect; + s8 idle_chan; /* valid if not negative */ }; struct chip_desc { @@ -172,10 +175,20 @@ static int pca954x_deselect_mux(struct i2c_adapter *adap, void *client, u32 chan) { struct pca954x *data = i2c_get_clientdata(client); + struct pca954x_platform_data *pdata = + dev_get_platdata(&((struct i2c_client *)client)->dev); + + if ((pdata && pdata->modes[chan].deselect_on_exit) || + data->idle_disconnect) { + /* Deselect active channel */ + data->last_chan = 0; + return pca954x_reg_write(adap, client, data->last_chan); + } - /* Deselect active channel */ - data->last_chan = 0; - return pca954x_reg_write(adap, client, data->last_chan); + if (data->idle_chan >= 0) + return pca954x_select_chan(adap, client, data->idle_chan); + + return 0; } /* @@ -186,6 +199,7 @@ static int pca954x_probe(struct i2c_client *client, { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device_node *of_node = client->dev.of_node; struct gpio_desc *gpio; int num, force, class; struct pca954x *data; @@ -216,6 +230,27 @@ static int pca954x_probe(struct i2c_client *client, data->type = id->driver_data; data->last_chan = 0; /* force the first selection */ + data->idle_chan = -1; /* no forced idle state */ + + if (of_node) { + u32 ch; + + if (of_property_read_bool(of_node, "idle-disconnect")) + data->idle_disconnect = true; + + if (!of_property_read_u32_index(of_node, "idle-state", 0, &ch)) { + if (ch < PCA954X_MAX_NCHANS) { + data->idle_chan = ch; + /* Force idle state from the beginning */ + ret = pca954x_select_chan(adap, client, ch); + if (ret) + return ret; + } else { + dev_warn(&client->dev, + "Invalid idle-state property\n"); + } + } + } /* Now create an adapter for each channel */ for (num = 0; num < chips[data->type].nchans; num++) { @@ -234,8 +269,7 @@ static int pca954x_probe(struct i2c_client *client, data->virt_adaps[num] = i2c_add_mux_adapter(adap, &client->dev, client, force, num, class, pca954x_select_chan, - (pdata && pdata->modes[num].deselect_on_exit) - ? pca954x_deselect_mux : NULL); + pca954x_deselect_mux); if (data->virt_adaps[num] == NULL) { ret = -ENODEV; @@ -281,7 +315,12 @@ static int pca954x_resume(struct device *dev) struct pca954x *data = i2c_get_clientdata(client); data->last_chan = 0; - return i2c_smbus_write_byte(client, 0); + /* Restore idle state on resume */ + if (data->idle_chan >= 0) + return pca954x_select_chan(to_i2c_adapter(client->dev.parent), + client, data->idle_chan); + else + return i2c_smbus_write_byte(client, 0); } #endif