1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Pinctrl based I2C DeMultiplexer |
4 | * |
5 | * Copyright (C) 2015-16 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> |
6 | * Copyright (C) 2015-16 by Renesas Electronics Corporation |
7 | * |
8 | * See the bindings doc for DTS setup and the sysfs doc for usage information. |
9 | * (look for filenames containing 'i2c-demux-pinctrl' in Documentation/) |
10 | */ |
11 | |
12 | #include <linux/i2c.h> |
13 | #include <linux/init.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/pinctrl/consumer.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/pm_runtime.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/sysfs.h> |
21 | |
22 | struct i2c_demux_pinctrl_chan { |
23 | struct device_node *parent_np; |
24 | struct i2c_adapter *parent_adap; |
25 | struct of_changeset chgset; |
26 | }; |
27 | |
28 | struct i2c_demux_pinctrl_priv { |
29 | int cur_chan; |
30 | int num_chan; |
31 | struct device *dev; |
32 | const char *bus_name; |
33 | struct i2c_adapter cur_adap; |
34 | struct i2c_algorithm algo; |
35 | struct i2c_demux_pinctrl_chan chan[] __counted_by(num_chan); |
36 | }; |
37 | |
38 | static int i2c_demux_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) |
39 | { |
40 | struct i2c_demux_pinctrl_priv *priv = adap->algo_data; |
41 | struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap; |
42 | |
43 | return __i2c_transfer(adap: parent, msgs, num); |
44 | } |
45 | |
46 | static u32 i2c_demux_functionality(struct i2c_adapter *adap) |
47 | { |
48 | struct i2c_demux_pinctrl_priv *priv = adap->algo_data; |
49 | struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap; |
50 | |
51 | return parent->algo->functionality(parent); |
52 | } |
53 | |
54 | static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 new_chan) |
55 | { |
56 | struct i2c_adapter *adap; |
57 | struct pinctrl *p; |
58 | int ret; |
59 | |
60 | ret = of_changeset_apply(ocs: &priv->chan[new_chan].chgset); |
61 | if (ret) |
62 | goto err; |
63 | |
64 | adap = of_get_i2c_adapter_by_node(node: priv->chan[new_chan].parent_np); |
65 | if (!adap) { |
66 | ret = -ENODEV; |
67 | goto err_with_revert; |
68 | } |
69 | |
70 | /* |
71 | * Check if there are pinctrl states at all. Note: we cant' use |
72 | * devm_pinctrl_get_select() because we need to distinguish between |
73 | * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state(). |
74 | */ |
75 | p = devm_pinctrl_get(dev: adap->dev.parent); |
76 | if (IS_ERR(ptr: p)) { |
77 | ret = PTR_ERR(ptr: p); |
78 | /* continue if just no pinctrl states (e.g. i2c-gpio), otherwise exit */ |
79 | if (ret != -ENODEV) |
80 | goto err_with_put; |
81 | } else { |
82 | /* there are states. check and use them */ |
83 | struct pinctrl_state *s = pinctrl_lookup_state(p, name: priv->bus_name); |
84 | |
85 | if (IS_ERR(ptr: s)) { |
86 | ret = PTR_ERR(ptr: s); |
87 | goto err_with_put; |
88 | } |
89 | ret = pinctrl_select_state(p, s); |
90 | if (ret < 0) |
91 | goto err_with_put; |
92 | } |
93 | |
94 | priv->chan[new_chan].parent_adap = adap; |
95 | priv->cur_chan = new_chan; |
96 | |
97 | /* Now fill out current adapter structure. cur_chan must be up to date */ |
98 | priv->algo.master_xfer = i2c_demux_master_xfer; |
99 | if (adap->algo->master_xfer_atomic) |
100 | priv->algo.master_xfer_atomic = i2c_demux_master_xfer; |
101 | priv->algo.functionality = i2c_demux_functionality; |
102 | |
103 | snprintf(buf: priv->cur_adap.name, size: sizeof(priv->cur_adap.name), |
104 | fmt: "i2c-demux (master i2c-%d)" , i2c_adapter_id(adap)); |
105 | priv->cur_adap.owner = THIS_MODULE; |
106 | priv->cur_adap.algo = &priv->algo; |
107 | priv->cur_adap.algo_data = priv; |
108 | priv->cur_adap.dev.parent = &adap->dev; |
109 | priv->cur_adap.class = adap->class; |
110 | priv->cur_adap.retries = adap->retries; |
111 | priv->cur_adap.timeout = adap->timeout; |
112 | priv->cur_adap.quirks = adap->quirks; |
113 | priv->cur_adap.dev.of_node = priv->dev->of_node; |
114 | ret = i2c_add_adapter(adap: &priv->cur_adap); |
115 | if (ret < 0) |
116 | goto err_with_put; |
117 | |
118 | return 0; |
119 | |
120 | err_with_put: |
121 | i2c_put_adapter(adap); |
122 | err_with_revert: |
123 | of_changeset_revert(ocs: &priv->chan[new_chan].chgset); |
124 | err: |
125 | dev_err(priv->dev, "failed to setup demux-adapter %d (%d)\n" , new_chan, ret); |
126 | priv->cur_chan = -EINVAL; |
127 | return ret; |
128 | } |
129 | |
130 | static int i2c_demux_deactivate_master(struct i2c_demux_pinctrl_priv *priv) |
131 | { |
132 | int ret, cur = priv->cur_chan; |
133 | |
134 | if (cur < 0) |
135 | return 0; |
136 | |
137 | i2c_del_adapter(adap: &priv->cur_adap); |
138 | i2c_put_adapter(adap: priv->chan[cur].parent_adap); |
139 | |
140 | ret = of_changeset_revert(ocs: &priv->chan[cur].chgset); |
141 | |
142 | priv->chan[cur].parent_adap = NULL; |
143 | priv->cur_chan = -EINVAL; |
144 | |
145 | return ret; |
146 | } |
147 | |
148 | static int i2c_demux_change_master(struct i2c_demux_pinctrl_priv *priv, u32 new_chan) |
149 | { |
150 | int ret; |
151 | |
152 | if (new_chan == priv->cur_chan) |
153 | return 0; |
154 | |
155 | ret = i2c_demux_deactivate_master(priv); |
156 | if (ret) |
157 | return ret; |
158 | |
159 | return i2c_demux_activate_master(priv, new_chan); |
160 | } |
161 | |
162 | static ssize_t available_masters_show(struct device *dev, |
163 | struct device_attribute *attr, |
164 | char *buf) |
165 | { |
166 | struct i2c_demux_pinctrl_priv *priv = dev_get_drvdata(dev); |
167 | int count = 0, i; |
168 | |
169 | for (i = 0; i < priv->num_chan && count < PAGE_SIZE; i++) |
170 | count += sysfs_emit_at(buf, at: count, fmt: "%d:%pOF%c" , |
171 | i, priv->chan[i].parent_np, |
172 | i == priv->num_chan - 1 ? '\n' : ' '); |
173 | |
174 | return count; |
175 | } |
176 | static DEVICE_ATTR_RO(available_masters); |
177 | |
178 | static ssize_t current_master_show(struct device *dev, |
179 | struct device_attribute *attr, |
180 | char *buf) |
181 | { |
182 | struct i2c_demux_pinctrl_priv *priv = dev_get_drvdata(dev); |
183 | |
184 | return sprintf(buf, fmt: "%d\n" , priv->cur_chan); |
185 | } |
186 | |
187 | static ssize_t current_master_store(struct device *dev, |
188 | struct device_attribute *attr, |
189 | const char *buf, size_t count) |
190 | { |
191 | struct i2c_demux_pinctrl_priv *priv = dev_get_drvdata(dev); |
192 | unsigned int val; |
193 | int ret; |
194 | |
195 | ret = kstrtouint(s: buf, base: 0, res: &val); |
196 | if (ret < 0) |
197 | return ret; |
198 | |
199 | if (val >= priv->num_chan) |
200 | return -EINVAL; |
201 | |
202 | ret = i2c_demux_change_master(priv, new_chan: val); |
203 | |
204 | return ret < 0 ? ret : count; |
205 | } |
206 | static DEVICE_ATTR_RW(current_master); |
207 | |
208 | static int i2c_demux_pinctrl_probe(struct platform_device *pdev) |
209 | { |
210 | struct device_node *np = pdev->dev.of_node; |
211 | struct i2c_demux_pinctrl_priv *priv; |
212 | struct property *props; |
213 | int num_chan, i, j, err; |
214 | |
215 | num_chan = of_count_phandle_with_args(np, list_name: "i2c-parent" , NULL); |
216 | if (num_chan < 2) { |
217 | dev_err(&pdev->dev, "Need at least two I2C masters to switch\n" ); |
218 | return -EINVAL; |
219 | } |
220 | |
221 | priv = devm_kzalloc(dev: &pdev->dev, struct_size(priv, chan, num_chan), |
222 | GFP_KERNEL); |
223 | |
224 | props = devm_kcalloc(dev: &pdev->dev, n: num_chan, size: sizeof(*props), GFP_KERNEL); |
225 | |
226 | if (!priv || !props) |
227 | return -ENOMEM; |
228 | |
229 | priv->num_chan = num_chan; |
230 | |
231 | err = of_property_read_string(np, propname: "i2c-bus-name" , out_string: &priv->bus_name); |
232 | if (err) |
233 | return err; |
234 | |
235 | for (i = 0; i < num_chan; i++) { |
236 | struct device_node *adap_np; |
237 | |
238 | adap_np = of_parse_phandle(np, phandle_name: "i2c-parent" , index: i); |
239 | if (!adap_np) { |
240 | dev_err(&pdev->dev, "can't get phandle for parent %d\n" , i); |
241 | err = -ENOENT; |
242 | goto err_rollback; |
243 | } |
244 | priv->chan[i].parent_np = adap_np; |
245 | |
246 | props[i].name = devm_kstrdup(dev: &pdev->dev, s: "status" , GFP_KERNEL); |
247 | props[i].value = devm_kstrdup(dev: &pdev->dev, s: "ok" , GFP_KERNEL); |
248 | if (!props[i].name || !props[i].value) { |
249 | err = -ENOMEM; |
250 | goto err_rollback; |
251 | } |
252 | props[i].length = 3; |
253 | |
254 | of_changeset_init(ocs: &priv->chan[i].chgset); |
255 | of_changeset_update_property(ocs: &priv->chan[i].chgset, np: adap_np, prop: &props[i]); |
256 | } |
257 | |
258 | priv->dev = &pdev->dev; |
259 | platform_set_drvdata(pdev, data: priv); |
260 | |
261 | pm_runtime_no_callbacks(dev: &pdev->dev); |
262 | |
263 | /* switch to first parent as active master */ |
264 | i2c_demux_activate_master(priv, new_chan: 0); |
265 | |
266 | err = device_create_file(device: &pdev->dev, entry: &dev_attr_available_masters); |
267 | if (err) |
268 | goto err_rollback_activation; |
269 | |
270 | err = device_create_file(device: &pdev->dev, entry: &dev_attr_current_master); |
271 | if (err) |
272 | goto err_rollback_available; |
273 | |
274 | return 0; |
275 | |
276 | err_rollback_available: |
277 | device_remove_file(dev: &pdev->dev, attr: &dev_attr_available_masters); |
278 | err_rollback_activation: |
279 | i2c_demux_deactivate_master(priv); |
280 | err_rollback: |
281 | for (j = 0; j < i; j++) { |
282 | of_node_put(node: priv->chan[j].parent_np); |
283 | of_changeset_destroy(ocs: &priv->chan[j].chgset); |
284 | } |
285 | |
286 | return err; |
287 | } |
288 | |
289 | static void i2c_demux_pinctrl_remove(struct platform_device *pdev) |
290 | { |
291 | struct i2c_demux_pinctrl_priv *priv = platform_get_drvdata(pdev); |
292 | int i; |
293 | |
294 | device_remove_file(dev: &pdev->dev, attr: &dev_attr_current_master); |
295 | device_remove_file(dev: &pdev->dev, attr: &dev_attr_available_masters); |
296 | |
297 | i2c_demux_deactivate_master(priv); |
298 | |
299 | for (i = 0; i < priv->num_chan; i++) { |
300 | of_node_put(node: priv->chan[i].parent_np); |
301 | of_changeset_destroy(ocs: &priv->chan[i].chgset); |
302 | } |
303 | } |
304 | |
305 | static const struct of_device_id i2c_demux_pinctrl_of_match[] = { |
306 | { .compatible = "i2c-demux-pinctrl" , }, |
307 | {}, |
308 | }; |
309 | MODULE_DEVICE_TABLE(of, i2c_demux_pinctrl_of_match); |
310 | |
311 | static struct platform_driver i2c_demux_pinctrl_driver = { |
312 | .driver = { |
313 | .name = "i2c-demux-pinctrl" , |
314 | .of_match_table = i2c_demux_pinctrl_of_match, |
315 | }, |
316 | .probe = i2c_demux_pinctrl_probe, |
317 | .remove_new = i2c_demux_pinctrl_remove, |
318 | }; |
319 | module_platform_driver(i2c_demux_pinctrl_driver); |
320 | |
321 | MODULE_DESCRIPTION("pinctrl-based I2C demux driver" ); |
322 | MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>" ); |
323 | MODULE_LICENSE("GPL v2" ); |
324 | MODULE_ALIAS("platform:i2c-demux-pinctrl" ); |
325 | |