325 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Pinctrl based I2C DeMultiplexer4 *5 * Copyright (C) 2015-16 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>6 * Copyright (C) 2015-16 by Renesas Electronics Corporation7 *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 22struct i2c_demux_pinctrl_chan {23 struct device_node *parent_np;24 struct i2c_adapter *parent_adap;25 struct of_changeset chgset;26};27 28struct 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 38static 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(parent, msgs, num);44}45 46static 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 54static 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(&priv->chan[new_chan].chgset);61 if (ret)62 goto err;63 64 adap = of_get_i2c_adapter_by_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' use72 * devm_pinctrl_get_select() because we need to distinguish between73 * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state().74 */75 p = devm_pinctrl_get(adap->dev.parent);76 if (IS_ERR(p)) {77 ret = PTR_ERR(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, priv->bus_name);84 85 if (IS_ERR(s)) {86 ret = PTR_ERR(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(priv->cur_adap.name, sizeof(priv->cur_adap.name),104 "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(&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(&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 130static 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(&priv->cur_adap);138 i2c_put_adapter(priv->chan[cur].parent_adap);139 140 ret = of_changeset_revert(&priv->chan[cur].chgset);141 142 priv->chan[cur].parent_adap = NULL;143 priv->cur_chan = -EINVAL;144 145 return ret;146}147 148static 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 162static 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, count, "%d:%pOF%c",171 i, priv->chan[i].parent_np,172 i == priv->num_chan - 1 ? '\n' : ' ');173 174 return count;175}176static DEVICE_ATTR_RO(available_masters);177 178static 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, "%d\n", priv->cur_chan);185}186 187static 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(buf, 0, &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, val);203 204 return ret < 0 ? ret : count;205}206static DEVICE_ATTR_RW(current_master);207 208static 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, "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(&pdev->dev, struct_size(priv, chan, num_chan),222 GFP_KERNEL);223 224 props = devm_kcalloc(&pdev->dev, num_chan, 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, "i2c-bus-name", &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, "i2c-parent", 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(&pdev->dev, "status", GFP_KERNEL);247 props[i].value = devm_kstrdup(&pdev->dev, "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(&priv->chan[i].chgset);255 of_changeset_update_property(&priv->chan[i].chgset, adap_np, &props[i]);256 }257 258 priv->dev = &pdev->dev;259 platform_set_drvdata(pdev, priv);260 261 pm_runtime_no_callbacks(&pdev->dev);262 263 /* switch to first parent as active master */264 i2c_demux_activate_master(priv, 0);265 266 err = device_create_file(&pdev->dev, &dev_attr_available_masters);267 if (err)268 goto err_rollback_activation;269 270 err = device_create_file(&pdev->dev, &dev_attr_current_master);271 if (err)272 goto err_rollback_available;273 274 return 0;275 276err_rollback_available:277 device_remove_file(&pdev->dev, &dev_attr_available_masters);278err_rollback_activation:279 i2c_demux_deactivate_master(priv);280err_rollback:281 for (j = 0; j < i; j++) {282 of_node_put(priv->chan[j].parent_np);283 of_changeset_destroy(&priv->chan[j].chgset);284 }285 286 return err;287}288 289static 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(&pdev->dev, &dev_attr_current_master);295 device_remove_file(&pdev->dev, &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(priv->chan[i].parent_np);301 of_changeset_destroy(&priv->chan[i].chgset);302 }303}304 305static const struct of_device_id i2c_demux_pinctrl_of_match[] = {306 { .compatible = "i2c-demux-pinctrl", },307 {},308};309MODULE_DEVICE_TABLE(of, i2c_demux_pinctrl_of_match);310 311static 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};319module_platform_driver(i2c_demux_pinctrl_driver);320 321MODULE_DESCRIPTION("pinctrl-based I2C demux driver");322MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");323MODULE_LICENSE("GPL v2");324MODULE_ALIAS("platform:i2c-demux-pinctrl");325