aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-05-18 11:29:34 -0400
committerWolfram Sang <w.sang@pengutronix.de>2012-06-04 10:49:43 -0400
commitae58d1e406986f31d1e88b32f5ac601506c196d8 (patch)
tree85f8973189b8e7bab81bdc235eeb1fb48176bb9d
parentf8f5701bdaf9134b1f90e5044a82c66324d2073f (diff)
i2c: Add generic I2C multiplexer using pinctrl API
This is useful for SoCs whose I2C module's signals can be routed to different sets of pins at run-time, using the pinctrl API. +-----+ +-----+ | dev | | dev | +------------------------+ +-----+ +-----+ | SoC | | | | /----|------+--------+ | +---+ +------+ | child bus A, on first set of pins | |I2C|---|Pinmux| | | +---+ +------+ | child bus B, on second set of pins | \----|------+--------+--------+ | | | | | +------------------------+ +-----+ +-----+ +-----+ | dev | | dev | | dev | +-----+ +-----+ +-----+ Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt93
-rw-r--r--drivers/i2c/muxes/Kconfig12
-rw-r--r--drivers/i2c/muxes/Makefile1
-rw-r--r--drivers/i2c/muxes/i2c-mux-pinctrl.c279
-rw-r--r--include/linux/i2c-mux-pinctrl.h41
5 files changed, 426 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
new file mode 100644
index 000000000000..ae8af1694e95
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
@@ -0,0 +1,93 @@
1Pinctrl-based I2C Bus Mux
2
3This binding describes an I2C bus multiplexer that uses pin multiplexing to
4route the I2C signals, and represents the pin multiplexing configuration
5using the pinctrl device tree bindings.
6
7 +-----+ +-----+
8 | dev | | dev |
9 +------------------------+ +-----+ +-----+
10 | SoC | | |
11 | /----|------+--------+
12 | +---+ +------+ | child bus A, on first set of pins
13 | |I2C|---|Pinmux| |
14 | +---+ +------+ | child bus B, on second set of pins
15 | \----|------+--------+--------+
16 | | | | |
17 +------------------------+ +-----+ +-----+ +-----+
18 | dev | | dev | | dev |
19 +-----+ +-----+ +-----+
20
21Required properties:
22- compatible: i2c-mux-pinctrl
23- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
24 port is connected to.
25
26Also required are:
27
28* Standard pinctrl properties that specify the pin mux state for each child
29 bus. See ../pinctrl/pinctrl-bindings.txt.
30
31* Standard I2C mux properties. See mux.txt in this directory.
32
33* I2C child bus nodes. See mux.txt in this directory.
34
35For each named state defined in the pinctrl-names property, an I2C child bus
36will be created. I2C child bus numbers are assigned based on the index into
37the pinctrl-names property.
38
39The only exception is that no bus will be created for a state named "idle". If
40such a state is defined, it must be the last entry in pinctrl-names. For
41example:
42
43 pinctrl-names = "ddc", "pta", "idle" -> ddc = bus 0, pta = bus 1
44 pinctrl-names = "ddc", "idle", "pta" -> Invalid ("idle" not last)
45 pinctrl-names = "idle", "ddc", "pta" -> Invalid ("idle" not last)
46
47Whenever an access is made to a device on a child bus, the relevant pinctrl
48state will be programmed into hardware.
49
50If an idle state is defined, whenever an access is not being made to a device
51on a child bus, the idle pinctrl state will be programmed into hardware.
52
53If an idle state is not defined, the most recently used pinctrl state will be
54left programmed into hardware whenever no access is being made of a device on
55a child bus.
56
57Example:
58
59 i2cmux {
60 compatible = "i2c-mux-pinctrl";
61 #address-cells = <1>;
62 #size-cells = <0>;
63
64 i2c-parent = <&i2c1>;
65
66 pinctrl-names = "ddc", "pta", "idle";
67 pinctrl-0 = <&state_i2cmux_ddc>;
68 pinctrl-1 = <&state_i2cmux_pta>;
69 pinctrl-2 = <&state_i2cmux_idle>;
70
71 i2c@0 {
72 reg = <0>;
73 #address-cells = <1>;
74 #size-cells = <0>;
75
76 eeprom {
77 compatible = "eeprom";
78 reg = <0x50>;
79 };
80 };
81
82 i2c@1 {
83 reg = <1>;
84 #address-cells = <1>;
85 #size-cells = <0>;
86
87 eeprom {
88 compatible = "eeprom";
89 reg = <0x50>;
90 };
91 };
92 };
93
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index beb2491db274..a0edd9854218 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -37,4 +37,16 @@ config I2C_MUX_PCA954x
37 This driver can also be built as a module. If so, the module 37 This driver can also be built as a module. If so, the module
38 will be called i2c-mux-pca954x. 38 will be called i2c-mux-pca954x.
39 39
40config I2C_MUX_PINCTRL
41 tristate "pinctrl-based I2C multiplexer"
42 depends on PINCTRL
43 help
44 If you say yes to this option, support will be included for an I2C
45 multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing.
46 This is useful for SoCs whose I2C module's signals can be routed to
47 different sets of pins at run-time.
48
49 This driver can also be built as a module. If so, the module will be
50 called pinctrl-i2cmux.
51
40endmenu 52endmenu
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index 5826249b29ca..76da8692afff 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -4,5 +4,6 @@
4obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o 4obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
5obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o 5obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
6obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o 6obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
7obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
7 8
8ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG 9ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
new file mode 100644
index 000000000000..46a669763476
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -0,0 +1,279 @@
1/*
2 * I2C multiplexer using pinctrl API
3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/i2c.h>
20#include <linux/i2c-mux.h>
21#include <linux/init.h>
22#include <linux/module.h>
23#include <linux/of_i2c.h>
24#include <linux/pinctrl/consumer.h>
25#include <linux/i2c-mux-pinctrl.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28
29struct i2c_mux_pinctrl {
30 struct device *dev;
31 struct i2c_mux_pinctrl_platform_data *pdata;
32 struct pinctrl *pinctrl;
33 struct pinctrl_state **states;
34 struct pinctrl_state *state_idle;
35 struct i2c_adapter *parent;
36 struct i2c_adapter **busses;
37};
38
39static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
40 u32 chan)
41{
42 struct i2c_mux_pinctrl *mux = data;
43
44 return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
45}
46
47static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
48 u32 chan)
49{
50 struct i2c_mux_pinctrl *mux = data;
51
52 return pinctrl_select_state(mux->pinctrl, mux->state_idle);
53}
54
55#ifdef CONFIG_OF
56static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
57 struct platform_device *pdev)
58{
59 struct device_node *np = pdev->dev.of_node;
60 int num_names, i, ret;
61 struct device_node *adapter_np;
62 struct i2c_adapter *adapter;
63
64 if (!np)
65 return 0;
66
67 mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
68 if (!mux->pdata) {
69 dev_err(mux->dev,
70 "Cannot allocate i2c_mux_pinctrl_platform_data\n");
71 return -ENOMEM;
72 }
73
74 num_names = of_property_count_strings(np, "pinctrl-names");
75 if (num_names < 0) {
76 dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
77 num_names);
78 return num_names;
79 }
80
81 mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
82 sizeof(*mux->pdata->pinctrl_states) * num_names,
83 GFP_KERNEL);
84 if (!mux->pdata->pinctrl_states) {
85 dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
86 return -ENOMEM;
87 }
88
89 for (i = 0; i < num_names; i++) {
90 ret = of_property_read_string_index(np, "pinctrl-names", i,
91 &mux->pdata->pinctrl_states[mux->pdata->bus_count]);
92 if (ret < 0) {
93 dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
94 ret);
95 return ret;
96 }
97 if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
98 "idle")) {
99 if (i != num_names - 1) {
100 dev_err(mux->dev, "idle state must be last\n");
101 return -EINVAL;
102 }
103 mux->pdata->pinctrl_state_idle = "idle";
104 } else {
105 mux->pdata->bus_count++;
106 }
107 }
108
109 adapter_np = of_parse_phandle(np, "i2c-parent", 0);
110 if (!adapter_np) {
111 dev_err(mux->dev, "Cannot parse i2c-parent\n");
112 return -ENODEV;
113 }
114 adapter = of_find_i2c_adapter_by_node(adapter_np);
115 if (!adapter) {
116 dev_err(mux->dev, "Cannot find parent bus\n");
117 return -ENODEV;
118 }
119 mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
120 put_device(&adapter->dev);
121
122 return 0;
123}
124#else
125static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
126 struct platform_device *pdev)
127{
128 return 0;
129}
130#endif
131
132static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev)
133{
134 struct i2c_mux_pinctrl *mux;
135 int (*deselect)(struct i2c_adapter *, void *, u32);
136 int i, ret;
137
138 mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
139 if (!mux) {
140 dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
141 ret = -ENOMEM;
142 goto err;
143 }
144 platform_set_drvdata(pdev, mux);
145
146 mux->dev = &pdev->dev;
147
148 mux->pdata = pdev->dev.platform_data;
149 if (!mux->pdata) {
150 ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
151 if (ret < 0)
152 goto err;
153 }
154 if (!mux->pdata) {
155 dev_err(&pdev->dev, "Missing platform data\n");
156 ret = -ENODEV;
157 goto err;
158 }
159
160 mux->states = devm_kzalloc(&pdev->dev,
161 sizeof(*mux->states) * mux->pdata->bus_count,
162 GFP_KERNEL);
163 if (!mux->states) {
164 dev_err(&pdev->dev, "Cannot allocate states\n");
165 ret = -ENOMEM;
166 goto err;
167 }
168
169 mux->busses = devm_kzalloc(&pdev->dev,
170 sizeof(mux->busses) * mux->pdata->bus_count,
171 GFP_KERNEL);
172 if (!mux->states) {
173 dev_err(&pdev->dev, "Cannot allocate busses\n");
174 ret = -ENOMEM;
175 goto err;
176 }
177
178 mux->pinctrl = devm_pinctrl_get(&pdev->dev);
179 if (IS_ERR(mux->pinctrl)) {
180 ret = PTR_ERR(mux->pinctrl);
181 dev_err(&pdev->dev, "Cannot get pinctrl: %d\n", ret);
182 goto err;
183 }
184 for (i = 0; i < mux->pdata->bus_count; i++) {
185 mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
186 mux->pdata->pinctrl_states[i]);
187 if (IS_ERR(mux->states[i])) {
188 ret = PTR_ERR(mux->states[i]);
189 dev_err(&pdev->dev,
190 "Cannot look up pinctrl state %s: %d\n",
191 mux->pdata->pinctrl_states[i], ret);
192 goto err;
193 }
194 }
195 if (mux->pdata->pinctrl_state_idle) {
196 mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
197 mux->pdata->pinctrl_state_idle);
198 if (IS_ERR(mux->state_idle)) {
199 ret = PTR_ERR(mux->state_idle);
200 dev_err(&pdev->dev,
201 "Cannot look up pinctrl state %s: %d\n",
202 mux->pdata->pinctrl_state_idle, ret);
203 goto err;
204 }
205
206 deselect = i2c_mux_pinctrl_deselect;
207 } else {
208 deselect = NULL;
209 }
210
211 mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
212 if (!mux->parent) {
213 dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
214 mux->pdata->parent_bus_num);
215 ret = -ENODEV;
216 goto err;
217 }
218
219 for (i = 0; i < mux->pdata->bus_count; i++) {
220 u32 bus = mux->pdata->base_bus_num ?
221 (mux->pdata->base_bus_num + i) : 0;
222
223 mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
224 mux, bus, i,
225 i2c_mux_pinctrl_select,
226 deselect);
227 if (!mux->busses[i]) {
228 ret = -ENODEV;
229 dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
230 goto err_del_adapter;
231 }
232 }
233
234 return 0;
235
236err_del_adapter:
237 for (; i > 0; i--)
238 i2c_del_mux_adapter(mux->busses[i - 1]);
239 i2c_put_adapter(mux->parent);
240err:
241 return ret;
242}
243
244static int __devexit i2c_mux_pinctrl_remove(struct platform_device *pdev)
245{
246 struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
247 int i;
248
249 for (i = 0; i < mux->pdata->bus_count; i++)
250 i2c_del_mux_adapter(mux->busses[i]);
251
252 i2c_put_adapter(mux->parent);
253
254 return 0;
255}
256
257#ifdef CONFIG_OF
258static const struct of_device_id i2c_mux_pinctrl_of_match[] __devinitconst = {
259 { .compatible = "i2c-mux-pinctrl", },
260 {},
261};
262MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
263#endif
264
265static struct platform_driver i2c_mux_pinctrl_driver = {
266 .driver = {
267 .name = "i2c-mux-pinctrl",
268 .owner = THIS_MODULE,
269 .of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
270 },
271 .probe = i2c_mux_pinctrl_probe,
272 .remove = __devexit_p(i2c_mux_pinctrl_remove),
273};
274module_platform_driver(i2c_mux_pinctrl_driver);
275
276MODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver");
277MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
278MODULE_LICENSE("GPL v2");
279MODULE_ALIAS("platform:i2c-mux-pinctrl");
diff --git a/include/linux/i2c-mux-pinctrl.h b/include/linux/i2c-mux-pinctrl.h
new file mode 100644
index 000000000000..a65c86429e84
--- /dev/null
+++ b/include/linux/i2c-mux-pinctrl.h
@@ -0,0 +1,41 @@
1/*
2 * i2c-mux-pinctrl platform data
3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _LINUX_I2C_MUX_PINCTRL_H
20#define _LINUX_I2C_MUX_PINCTRL_H
21
22/**
23 * struct i2c_mux_pinctrl_platform_data - Platform data for i2c-mux-pinctrl
24 * @parent_bus_num: Parent I2C bus number
25 * @base_bus_num: Base I2C bus number for the child busses. 0 for dynamic.
26 * @bus_count: Number of child busses. Also the number of elements in
27 * @pinctrl_states
28 * @pinctrl_states: The names of the pinctrl state to select for each child bus
29 * @pinctrl_state_idle: The pinctrl state to select when no child bus is being
30 * accessed. If NULL, the most recently used pinctrl state will be left
31 * selected.
32 */
33struct i2c_mux_pinctrl_platform_data {
34 int parent_bus_num;
35 int base_bus_num;
36 int bus_count;
37 const char **pinctrl_states;
38 const char *pinctrl_state_idle;
39};
40
41#endif