Lines Matching +full:i2c +full:- +full:demux +full:- +full:pinctrl
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Pinctrl based I2C DeMultiplexer
5 * Copyright (C) 2015-16 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
6 * Copyright (C) 2015-16 by Renesas Electronics Corporation
9 * (look for filenames containing 'i2c-demux-pinctrl' in Documentation/)
12 #include <linux/i2c.h>
16 #include <linux/pinctrl/consumer.h>
40 struct i2c_demux_pinctrl_priv *priv = adap->algo_data; in i2c_demux_master_xfer()
41 struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap; in i2c_demux_master_xfer()
48 struct i2c_demux_pinctrl_priv *priv = adap->algo_data; in i2c_demux_functionality()
49 struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap; in i2c_demux_functionality()
51 return parent->algo->functionality(parent); in i2c_demux_functionality()
57 struct pinctrl *p; in i2c_demux_activate_master()
60 ret = of_changeset_apply(&priv->chan[new_chan].chgset); in i2c_demux_activate_master()
64 adap = of_get_i2c_adapter_by_node(priv->chan[new_chan].parent_np); in i2c_demux_activate_master()
66 ret = -ENODEV; in i2c_demux_activate_master()
71 * Check if there are pinctrl states at all. Note: we can't use in i2c_demux_activate_master()
73 * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state(). in i2c_demux_activate_master()
75 p = devm_pinctrl_get(adap->dev.parent); in i2c_demux_activate_master()
78 /* continue if just no pinctrl states (e.g. i2c-gpio), otherwise exit */ in i2c_demux_activate_master()
79 if (ret != -ENODEV) in i2c_demux_activate_master()
83 struct pinctrl_state *s = pinctrl_lookup_state(p, priv->bus_name); in i2c_demux_activate_master()
94 priv->chan[new_chan].parent_adap = adap; in i2c_demux_activate_master()
95 priv->cur_chan = new_chan; in i2c_demux_activate_master()
98 priv->algo.master_xfer = i2c_demux_master_xfer; in i2c_demux_activate_master()
99 if (adap->algo->master_xfer_atomic) in i2c_demux_activate_master()
100 priv->algo.master_xfer_atomic = i2c_demux_master_xfer; in i2c_demux_activate_master()
101 priv->algo.functionality = i2c_demux_functionality; in i2c_demux_activate_master()
103 snprintf(priv->cur_adap.name, sizeof(priv->cur_adap.name), in i2c_demux_activate_master()
104 "i2c-demux (master i2c-%d)", i2c_adapter_id(adap)); in i2c_demux_activate_master()
105 priv->cur_adap.owner = THIS_MODULE; in i2c_demux_activate_master()
106 priv->cur_adap.algo = &priv->algo; in i2c_demux_activate_master()
107 priv->cur_adap.algo_data = priv; in i2c_demux_activate_master()
108 priv->cur_adap.dev.parent = &adap->dev; in i2c_demux_activate_master()
109 priv->cur_adap.class = adap->class; in i2c_demux_activate_master()
110 priv->cur_adap.retries = adap->retries; in i2c_demux_activate_master()
111 priv->cur_adap.timeout = adap->timeout; in i2c_demux_activate_master()
112 priv->cur_adap.quirks = adap->quirks; in i2c_demux_activate_master()
113 priv->cur_adap.dev.of_node = priv->dev->of_node; in i2c_demux_activate_master()
114 ret = i2c_add_adapter(&priv->cur_adap); in i2c_demux_activate_master()
123 of_changeset_revert(&priv->chan[new_chan].chgset); in i2c_demux_activate_master()
125 dev_err(priv->dev, "failed to setup demux-adapter %d (%d)\n", new_chan, ret); in i2c_demux_activate_master()
126 priv->cur_chan = -EINVAL; in i2c_demux_activate_master()
132 int ret, cur = priv->cur_chan; in i2c_demux_deactivate_master()
137 i2c_del_adapter(&priv->cur_adap); in i2c_demux_deactivate_master()
138 i2c_put_adapter(priv->chan[cur].parent_adap); in i2c_demux_deactivate_master()
140 ret = of_changeset_revert(&priv->chan[cur].chgset); in i2c_demux_deactivate_master()
142 priv->chan[cur].parent_adap = NULL; in i2c_demux_deactivate_master()
143 priv->cur_chan = -EINVAL; in i2c_demux_deactivate_master()
152 if (new_chan == priv->cur_chan) in i2c_demux_change_master()
169 for (i = 0; i < priv->num_chan && count < PAGE_SIZE; i++) in available_masters_show()
171 i, priv->chan[i].parent_np, in available_masters_show()
172 i == priv->num_chan - 1 ? '\n' : ' '); in available_masters_show()
184 return sprintf(buf, "%d\n", priv->cur_chan); in current_master_show()
199 if (val >= priv->num_chan) in current_master_store()
200 return -EINVAL; in current_master_store()
210 struct device_node *np = pdev->dev.of_node; in i2c_demux_pinctrl_probe()
215 num_chan = of_count_phandle_with_args(np, "i2c-parent", NULL); in i2c_demux_pinctrl_probe()
217 dev_err(&pdev->dev, "Need at least two I2C masters to switch\n"); in i2c_demux_pinctrl_probe()
218 return -EINVAL; in i2c_demux_pinctrl_probe()
221 priv = devm_kzalloc(&pdev->dev, struct_size(priv, chan, num_chan), in i2c_demux_pinctrl_probe()
224 props = devm_kcalloc(&pdev->dev, num_chan, sizeof(*props), GFP_KERNEL); in i2c_demux_pinctrl_probe()
227 return -ENOMEM; in i2c_demux_pinctrl_probe()
229 priv->num_chan = num_chan; in i2c_demux_pinctrl_probe()
231 err = of_property_read_string(np, "i2c-bus-name", &priv->bus_name); in i2c_demux_pinctrl_probe()
238 adap_np = of_parse_phandle(np, "i2c-parent", i); in i2c_demux_pinctrl_probe()
240 dev_err(&pdev->dev, "can't get phandle for parent %d\n", i); in i2c_demux_pinctrl_probe()
241 err = -ENOENT; in i2c_demux_pinctrl_probe()
244 priv->chan[i].parent_np = adap_np; in i2c_demux_pinctrl_probe()
246 props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL); in i2c_demux_pinctrl_probe()
247 props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL); in i2c_demux_pinctrl_probe()
249 err = -ENOMEM; in i2c_demux_pinctrl_probe()
254 of_changeset_init(&priv->chan[i].chgset); in i2c_demux_pinctrl_probe()
255 of_changeset_update_property(&priv->chan[i].chgset, adap_np, &props[i]); in i2c_demux_pinctrl_probe()
258 priv->dev = &pdev->dev; in i2c_demux_pinctrl_probe()
261 pm_runtime_no_callbacks(&pdev->dev); in i2c_demux_pinctrl_probe()
268 err = device_create_file(&pdev->dev, &dev_attr_available_masters); in i2c_demux_pinctrl_probe()
272 err = device_create_file(&pdev->dev, &dev_attr_current_master); in i2c_demux_pinctrl_probe()
279 device_remove_file(&pdev->dev, &dev_attr_available_masters); in i2c_demux_pinctrl_probe()
284 of_node_put(priv->chan[j].parent_np); in i2c_demux_pinctrl_probe()
285 of_changeset_destroy(&priv->chan[j].chgset); in i2c_demux_pinctrl_probe()
296 device_remove_file(&pdev->dev, &dev_attr_current_master); in i2c_demux_pinctrl_remove()
297 device_remove_file(&pdev->dev, &dev_attr_available_masters); in i2c_demux_pinctrl_remove()
301 for (i = 0; i < priv->num_chan; i++) { in i2c_demux_pinctrl_remove()
302 of_node_put(priv->chan[i].parent_np); in i2c_demux_pinctrl_remove()
303 of_changeset_destroy(&priv->chan[i].chgset); in i2c_demux_pinctrl_remove()
308 { .compatible = "i2c-demux-pinctrl", },
315 .name = "i2c-demux-pinctrl",
323 MODULE_DESCRIPTION("pinctrl-based I2C demux driver");
324 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
326 MODULE_ALIAS("platform:i2c-demux-pinctrl");