i2c: allow adapter drivers to override the adapter locking
[deliverable/linux.git] / drivers / i2c / i2c-mux.c
CommitLineData
0826374b
ML
1/*
2 * Multiplexed I2C bus driver.
3 *
4 * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
5 * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
6 * Copyright (c) 2009-2010 NSN GmbH & Co KG <michael.lawnick.ext@nsn.com>
7 *
8 * Simplifies access to complex multiplexed I2C bus topologies, by presenting
9 * each multiplexed bus segment as an additional I2C adapter.
10 * Supports multi-level mux'ing (mux behind a mux).
11 *
12 * Based on:
13 * i2c-virt.c from Kumar Gala <galak@kernel.crashing.org>
14 * i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc.
15 * i2c-virtual.c from Brian Kuschak <bkuschak@yahoo.com>
16 *
17 * This file is licensed under the terms of the GNU General Public
18 * License version 2. This program is licensed "as is" without any
19 * warranty of any kind, whether express or implied.
20 */
21
51714932 22#include <linux/acpi.h>
0826374b
ML
23#include <linux/i2c.h>
24#include <linux/i2c-mux.h>
51714932
WS
25#include <linux/kernel.h>
26#include <linux/module.h>
bc45449b 27#include <linux/of.h>
51714932 28#include <linux/slab.h>
0826374b
ML
29
30/* multiplexer per channel data */
31struct i2c_mux_priv {
32 struct i2c_adapter adap;
33 struct i2c_algorithm algo;
a7ab7239 34 struct i2c_mux_core *muxc;
13377848 35 u32 chan_id;
0826374b
ML
36};
37
38static int i2c_mux_master_xfer(struct i2c_adapter *adap,
39 struct i2c_msg msgs[], int num)
40{
41 struct i2c_mux_priv *priv = adap->algo_data;
a7ab7239
PR
42 struct i2c_mux_core *muxc = priv->muxc;
43 struct i2c_adapter *parent = muxc->parent;
0826374b
ML
44 int ret;
45
46 /* Switch to the right mux port and perform the transfer. */
47
a7ab7239 48 ret = muxc->select(muxc, priv->chan_id);
0826374b 49 if (ret >= 0)
e766f338 50 ret = __i2c_transfer(parent, msgs, num);
a7ab7239
PR
51 if (muxc->deselect)
52 muxc->deselect(muxc, priv->chan_id);
0826374b
ML
53
54 return ret;
55}
56
57static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
58 u16 addr, unsigned short flags,
59 char read_write, u8 command,
60 int size, union i2c_smbus_data *data)
61{
62 struct i2c_mux_priv *priv = adap->algo_data;
a7ab7239
PR
63 struct i2c_mux_core *muxc = priv->muxc;
64 struct i2c_adapter *parent = muxc->parent;
0826374b
ML
65 int ret;
66
67 /* Select the right mux port and perform the transfer. */
68
a7ab7239 69 ret = muxc->select(muxc, priv->chan_id);
0826374b
ML
70 if (ret >= 0)
71 ret = parent->algo->smbus_xfer(parent, addr, flags,
72 read_write, command, size, data);
a7ab7239
PR
73 if (muxc->deselect)
74 muxc->deselect(muxc, priv->chan_id);
0826374b
ML
75
76 return ret;
77}
78
79/* Return the parent's functionality */
80static u32 i2c_mux_functionality(struct i2c_adapter *adap)
81{
82 struct i2c_mux_priv *priv = adap->algo_data;
a7ab7239 83 struct i2c_adapter *parent = priv->muxc->parent;
0826374b
ML
84
85 return parent->algo->functionality(parent);
86}
87
eee543e8
JD
88/* Return all parent classes, merged */
89static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
90{
91 unsigned int class = 0;
92
93 do {
94 class |= parent->class;
95 parent = i2c_parent_is_i2c_adapter(parent);
96 } while (parent);
97
98 return class;
99}
100
a7ab7239
PR
101struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
102 struct device *dev, int max_adapters,
103 int sizeof_priv, u32 flags,
104 int (*select)(struct i2c_mux_core *, u32),
105 int (*deselect)(struct i2c_mux_core *, u32))
106{
107 struct i2c_mux_core *muxc;
108
109 muxc = devm_kzalloc(dev, sizeof(*muxc)
110 + max_adapters * sizeof(muxc->adapter[0])
111 + sizeof_priv, GFP_KERNEL);
112 if (!muxc)
113 return NULL;
114 if (sizeof_priv)
115 muxc->priv = &muxc->adapter[max_adapters];
116
117 muxc->parent = parent;
118 muxc->dev = dev;
119 muxc->select = select;
120 muxc->deselect = deselect;
121 muxc->max_adapters = max_adapters;
122
123 return muxc;
124}
125EXPORT_SYMBOL_GPL(i2c_mux_alloc);
126
127int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
128 u32 force_nr, u32 chan_id,
129 unsigned int class)
130{
131 struct i2c_adapter *parent = muxc->parent;
0826374b 132 struct i2c_mux_priv *priv;
c9449aff 133 char symlink_name[20];
0826374b
ML
134 int ret;
135
a7ab7239
PR
136 if (muxc->num_adapters >= muxc->max_adapters) {
137 dev_err(muxc->dev, "No room for more i2c-mux adapters\n");
138 return -EINVAL;
139 }
140
141 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0826374b 142 if (!priv)
a7ab7239 143 return -ENOMEM;
0826374b
ML
144
145 /* Set up private adapter data */
a7ab7239 146 priv->muxc = muxc;
0826374b 147 priv->chan_id = chan_id;
0826374b
ML
148
149 /* Need to do algo dynamically because we don't know ahead
150 * of time what sort of physical adapter we'll be dealing with.
151 */
152 if (parent->algo->master_xfer)
153 priv->algo.master_xfer = i2c_mux_master_xfer;
154 if (parent->algo->smbus_xfer)
155 priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
156 priv->algo.functionality = i2c_mux_functionality;
157
158 /* Now fill out new adapter structure */
159 snprintf(priv->adap.name, sizeof(priv->adap.name),
160 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
161 priv->adap.owner = THIS_MODULE;
0826374b
ML
162 priv->adap.algo = &priv->algo;
163 priv->adap.algo_data = priv;
164 priv->adap.dev.parent = &parent->dev;
2212a852
EDB
165 priv->adap.retries = parent->retries;
166 priv->adap.timeout = parent->timeout;
dc362d50 167 priv->adap.quirks = parent->quirks;
0826374b 168
eee543e8
JD
169 /* Sanity check on class */
170 if (i2c_mux_parent_classes(parent) & class)
171 dev_err(&parent->dev,
172 "Segment %d behind mux can't share classes with ancestors\n",
173 chan_id);
174 else
175 priv->adap.class = class;
176
bc45449b
DD
177 /*
178 * Try to populate the mux adapter's of_node, expands to
179 * nothing if !CONFIG_OF.
180 */
a7ab7239 181 if (muxc->dev->of_node) {
bc45449b
DD
182 struct device_node *child;
183 u32 reg;
184
a7ab7239 185 for_each_child_of_node(muxc->dev->of_node, child) {
bc45449b
DD
186 ret = of_property_read_u32(child, "reg", &reg);
187 if (ret)
188 continue;
189 if (chan_id == reg) {
190 priv->adap.dev.of_node = child;
191 break;
192 }
193 }
194 }
195
8eb5c87a
DB
196 /*
197 * Associate the mux channel with an ACPI node.
198 */
a7ab7239
PR
199 if (has_acpi_companion(muxc->dev))
200 acpi_preset_companion(&priv->adap.dev,
201 ACPI_COMPANION(muxc->dev),
8eb5c87a
DB
202 chan_id);
203
0826374b
ML
204 if (force_nr) {
205 priv->adap.nr = force_nr;
206 ret = i2c_add_numbered_adapter(&priv->adap);
207 } else {
208 ret = i2c_add_adapter(&priv->adap);
209 }
210 if (ret < 0) {
211 dev_err(&parent->dev,
212 "failed to add mux-adapter (error=%d)\n",
213 ret);
214 kfree(priv);
a7ab7239 215 return ret;
0826374b
ML
216 }
217
a7ab7239
PR
218 WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj,
219 "mux_device"),
220 "can't create symlink to mux device\n");
51cf3b0e 221
c9449aff 222 snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
a7ab7239
PR
223 WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
224 symlink_name),
225 "can't create symlink for channel %u\n", chan_id);
0826374b
ML
226 dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
227 i2c_adapter_id(&priv->adap));
228
a7ab7239
PR
229 muxc->adapter[muxc->num_adapters++] = &priv->adap;
230 return 0;
0826374b 231}
a7ab7239 232EXPORT_SYMBOL_GPL(i2c_mux_add_adapter);
0826374b 233
a7ab7239 234void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
0826374b 235{
c9449aff
GF
236 char symlink_name[20];
237
a7ab7239
PR
238 while (muxc->num_adapters) {
239 struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters];
240 struct i2c_mux_priv *priv = adap->algo_data;
241
242 muxc->adapter[muxc->num_adapters] = NULL;
243
244 snprintf(symlink_name, sizeof(symlink_name),
245 "channel-%u", priv->chan_id);
246 sysfs_remove_link(&muxc->dev->kobj, symlink_name);
247
248 sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
249 i2c_del_adapter(adap);
250 kfree(priv);
251 }
252}
253EXPORT_SYMBOL_GPL(i2c_mux_del_adapters);
254
0826374b
ML
255MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
256MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
257MODULE_LICENSE("GPL v2");
This page took 0.320282 seconds and 5 git commands to generate.