Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * I2C multiplexer using pinctrl API
0004  *
0005  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
0006  */
0007 
0008 #include <linux/i2c.h>
0009 #include <linux/i2c-mux.h>
0010 #include <linux/module.h>
0011 #include <linux/pinctrl/consumer.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/slab.h>
0014 #include <linux/of.h>
0015 #include "../../pinctrl/core.h"
0016 
0017 struct i2c_mux_pinctrl {
0018     struct pinctrl *pinctrl;
0019     struct pinctrl_state *states[];
0020 };
0021 
0022 static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
0023 {
0024     struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
0025 
0026     return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
0027 }
0028 
0029 static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
0030 {
0031     return i2c_mux_pinctrl_select(muxc, muxc->num_adapters);
0032 }
0033 
0034 static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
0035     struct pinctrl_state *state)
0036 {
0037     struct i2c_adapter *root = NULL;
0038     struct pinctrl_setting *setting;
0039     struct i2c_adapter *pin_root;
0040 
0041     list_for_each_entry(setting, &state->settings, node) {
0042         pin_root = i2c_root_adapter(setting->pctldev->dev);
0043         if (!pin_root)
0044             return NULL;
0045         if (!root)
0046             root = pin_root;
0047         else if (root != pin_root)
0048             return NULL;
0049     }
0050 
0051     return root;
0052 }
0053 
0054 static struct i2c_adapter *i2c_mux_pinctrl_parent_adapter(struct device *dev)
0055 {
0056     struct device_node *np = dev->of_node;
0057     struct device_node *parent_np;
0058     struct i2c_adapter *parent;
0059 
0060     parent_np = of_parse_phandle(np, "i2c-parent", 0);
0061     if (!parent_np) {
0062         dev_err(dev, "Cannot parse i2c-parent\n");
0063         return ERR_PTR(-ENODEV);
0064     }
0065     parent = of_find_i2c_adapter_by_node(parent_np);
0066     of_node_put(parent_np);
0067     if (!parent)
0068         return ERR_PTR(-EPROBE_DEFER);
0069 
0070     return parent;
0071 }
0072 
0073 static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
0074 {
0075     struct device *dev = &pdev->dev;
0076     struct device_node *np = dev->of_node;
0077     struct i2c_mux_core *muxc;
0078     struct i2c_mux_pinctrl *mux;
0079     struct i2c_adapter *parent;
0080     struct i2c_adapter *root;
0081     int num_names, i, ret;
0082     const char *name;
0083 
0084     num_names = of_property_count_strings(np, "pinctrl-names");
0085     if (num_names < 0) {
0086         dev_err(dev, "Cannot parse pinctrl-names: %d\n",
0087             num_names);
0088         return num_names;
0089     }
0090 
0091     parent = i2c_mux_pinctrl_parent_adapter(dev);
0092     if (IS_ERR(parent))
0093         return PTR_ERR(parent);
0094 
0095     muxc = i2c_mux_alloc(parent, dev, num_names,
0096                  struct_size(mux, states, num_names),
0097                  0, i2c_mux_pinctrl_select, NULL);
0098     if (!muxc) {
0099         ret = -ENOMEM;
0100         goto err_put_parent;
0101     }
0102     mux = i2c_mux_priv(muxc);
0103 
0104     platform_set_drvdata(pdev, muxc);
0105 
0106     mux->pinctrl = devm_pinctrl_get(dev);
0107     if (IS_ERR(mux->pinctrl)) {
0108         ret = PTR_ERR(mux->pinctrl);
0109         dev_err(dev, "Cannot get pinctrl: %d\n", ret);
0110         goto err_put_parent;
0111     }
0112 
0113     for (i = 0; i < num_names; i++) {
0114         ret = of_property_read_string_index(np, "pinctrl-names", i,
0115                             &name);
0116         if (ret < 0) {
0117             dev_err(dev, "Cannot parse pinctrl-names: %d\n", ret);
0118             goto err_put_parent;
0119         }
0120 
0121         mux->states[i] = pinctrl_lookup_state(mux->pinctrl, name);
0122         if (IS_ERR(mux->states[i])) {
0123             ret = PTR_ERR(mux->states[i]);
0124             dev_err(dev, "Cannot look up pinctrl state %s: %d\n",
0125                 name, ret);
0126             goto err_put_parent;
0127         }
0128 
0129         if (strcmp(name, "idle"))
0130             continue;
0131 
0132         if (i != num_names - 1) {
0133             dev_err(dev, "idle state must be last\n");
0134             ret = -EINVAL;
0135             goto err_put_parent;
0136         }
0137         muxc->deselect = i2c_mux_pinctrl_deselect;
0138     }
0139 
0140     root = i2c_root_adapter(&muxc->parent->dev);
0141 
0142     muxc->mux_locked = true;
0143     for (i = 0; i < num_names; i++) {
0144         if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
0145             muxc->mux_locked = false;
0146             break;
0147         }
0148     }
0149     if (muxc->mux_locked)
0150         dev_info(dev, "mux-locked i2c mux\n");
0151 
0152     /* Do not add any adapter for the idle state (if it's there at all). */
0153     for (i = 0; i < num_names - !!muxc->deselect; i++) {
0154         ret = i2c_mux_add_adapter(muxc, 0, i, 0);
0155         if (ret)
0156             goto err_del_adapter;
0157     }
0158 
0159     return 0;
0160 
0161 err_del_adapter:
0162     i2c_mux_del_adapters(muxc);
0163 err_put_parent:
0164     i2c_put_adapter(parent);
0165 
0166     return ret;
0167 }
0168 
0169 static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
0170 {
0171     struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
0172 
0173     i2c_mux_del_adapters(muxc);
0174     i2c_put_adapter(muxc->parent);
0175 
0176     return 0;
0177 }
0178 
0179 static const struct of_device_id i2c_mux_pinctrl_of_match[] = {
0180     { .compatible = "i2c-mux-pinctrl", },
0181     {},
0182 };
0183 MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
0184 
0185 static struct platform_driver i2c_mux_pinctrl_driver = {
0186     .driver = {
0187         .name   = "i2c-mux-pinctrl",
0188         .of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
0189     },
0190     .probe  = i2c_mux_pinctrl_probe,
0191     .remove = i2c_mux_pinctrl_remove,
0192 };
0193 module_platform_driver(i2c_mux_pinctrl_driver);
0194 
0195 MODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver");
0196 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
0197 MODULE_LICENSE("GPL v2");
0198 MODULE_ALIAS("platform:i2c-mux-pinctrl");