1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ac8498f0SPeter Rosin /*
3ac8498f0SPeter Rosin * General Purpose I2C multiplexer
4ac8498f0SPeter Rosin *
5ac8498f0SPeter Rosin * Copyright (C) 2017 Axentia Technologies AB
6ac8498f0SPeter Rosin *
7ac8498f0SPeter Rosin * Author: Peter Rosin <peda@axentia.se>
8ac8498f0SPeter Rosin */
9ac8498f0SPeter Rosin
10ac8498f0SPeter Rosin #include <linux/i2c.h>
11ac8498f0SPeter Rosin #include <linux/i2c-mux.h>
12ac8498f0SPeter Rosin #include <linux/module.h>
13ac8498f0SPeter Rosin #include <linux/mux/consumer.h>
1459738ab2SRob Herring #include <linux/of.h>
15ac8498f0SPeter Rosin #include <linux/platform_device.h>
16ac8498f0SPeter Rosin
17ac8498f0SPeter Rosin struct mux {
18ac8498f0SPeter Rosin struct mux_control *control;
19ac8498f0SPeter Rosin
20ac8498f0SPeter Rosin bool do_not_deselect;
21ac8498f0SPeter Rosin };
22ac8498f0SPeter Rosin
i2c_mux_select(struct i2c_mux_core * muxc,u32 chan)23ac8498f0SPeter Rosin static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
24ac8498f0SPeter Rosin {
25ac8498f0SPeter Rosin struct mux *mux = i2c_mux_priv(muxc);
26ac8498f0SPeter Rosin int ret;
27ac8498f0SPeter Rosin
28ac8498f0SPeter Rosin ret = mux_control_select(mux->control, chan);
29ac8498f0SPeter Rosin mux->do_not_deselect = ret < 0;
30ac8498f0SPeter Rosin
31ac8498f0SPeter Rosin return ret;
32ac8498f0SPeter Rosin }
33ac8498f0SPeter Rosin
i2c_mux_deselect(struct i2c_mux_core * muxc,u32 chan)34ac8498f0SPeter Rosin static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
35ac8498f0SPeter Rosin {
36ac8498f0SPeter Rosin struct mux *mux = i2c_mux_priv(muxc);
37ac8498f0SPeter Rosin
38ac8498f0SPeter Rosin if (mux->do_not_deselect)
39ac8498f0SPeter Rosin return 0;
40ac8498f0SPeter Rosin
41ac8498f0SPeter Rosin return mux_control_deselect(mux->control);
42ac8498f0SPeter Rosin }
43ac8498f0SPeter Rosin
mux_parent_adapter(struct device * dev)44ac8498f0SPeter Rosin static struct i2c_adapter *mux_parent_adapter(struct device *dev)
45ac8498f0SPeter Rosin {
46ac8498f0SPeter Rosin struct device_node *np = dev->of_node;
47ac8498f0SPeter Rosin struct device_node *parent_np;
48ac8498f0SPeter Rosin struct i2c_adapter *parent;
49ac8498f0SPeter Rosin
50ac8498f0SPeter Rosin parent_np = of_parse_phandle(np, "i2c-parent", 0);
51ac8498f0SPeter Rosin if (!parent_np) {
52ac8498f0SPeter Rosin dev_err(dev, "Cannot parse i2c-parent\n");
53ac8498f0SPeter Rosin return ERR_PTR(-ENODEV);
54ac8498f0SPeter Rosin }
55*3dc0ec46SHerve Codina parent = of_get_i2c_adapter_by_node(parent_np);
56ac8498f0SPeter Rosin of_node_put(parent_np);
57ac8498f0SPeter Rosin if (!parent)
58ac8498f0SPeter Rosin return ERR_PTR(-EPROBE_DEFER);
59ac8498f0SPeter Rosin
60ac8498f0SPeter Rosin return parent;
61ac8498f0SPeter Rosin }
62ac8498f0SPeter Rosin
63ac8498f0SPeter Rosin static const struct of_device_id i2c_mux_of_match[] = {
64ac8498f0SPeter Rosin { .compatible = "i2c-mux", },
65ac8498f0SPeter Rosin {},
66ac8498f0SPeter Rosin };
67ac8498f0SPeter Rosin MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
68ac8498f0SPeter Rosin
i2c_mux_probe(struct platform_device * pdev)69ac8498f0SPeter Rosin static int i2c_mux_probe(struct platform_device *pdev)
70ac8498f0SPeter Rosin {
71ac8498f0SPeter Rosin struct device *dev = &pdev->dev;
72ac8498f0SPeter Rosin struct device_node *np = dev->of_node;
73ac8498f0SPeter Rosin struct device_node *child;
74ac8498f0SPeter Rosin struct i2c_mux_core *muxc;
75ac8498f0SPeter Rosin struct mux *mux;
76ac8498f0SPeter Rosin struct i2c_adapter *parent;
77ac8498f0SPeter Rosin int children;
78ac8498f0SPeter Rosin int ret;
79ac8498f0SPeter Rosin
80ac8498f0SPeter Rosin if (!np)
81ac8498f0SPeter Rosin return -ENODEV;
82ac8498f0SPeter Rosin
83ac8498f0SPeter Rosin mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
84ac8498f0SPeter Rosin if (!mux)
85ac8498f0SPeter Rosin return -ENOMEM;
86ac8498f0SPeter Rosin
87ac8498f0SPeter Rosin mux->control = devm_mux_control_get(dev, NULL);
88432d159aSKrzysztof Kozlowski if (IS_ERR(mux->control))
89432d159aSKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(mux->control),
90432d159aSKrzysztof Kozlowski "failed to get control-mux\n");
91ac8498f0SPeter Rosin
92ac8498f0SPeter Rosin parent = mux_parent_adapter(dev);
93432d159aSKrzysztof Kozlowski if (IS_ERR(parent))
94432d159aSKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(parent),
95432d159aSKrzysztof Kozlowski "failed to get i2c-parent adapter\n");
96ac8498f0SPeter Rosin
97ac8498f0SPeter Rosin children = of_get_child_count(np);
98ac8498f0SPeter Rosin
99ac8498f0SPeter Rosin muxc = i2c_mux_alloc(parent, dev, children, 0, 0,
100ac8498f0SPeter Rosin i2c_mux_select, i2c_mux_deselect);
101ac8498f0SPeter Rosin if (!muxc) {
102ac8498f0SPeter Rosin ret = -ENOMEM;
103ac8498f0SPeter Rosin goto err_parent;
104ac8498f0SPeter Rosin }
105ac8498f0SPeter Rosin muxc->priv = mux;
106ac8498f0SPeter Rosin
107ac8498f0SPeter Rosin platform_set_drvdata(pdev, muxc);
108ac8498f0SPeter Rosin
109ac8498f0SPeter Rosin muxc->mux_locked = of_property_read_bool(np, "mux-locked");
110ac8498f0SPeter Rosin
111ac8498f0SPeter Rosin for_each_child_of_node(np, child) {
112ac8498f0SPeter Rosin u32 chan;
113ac8498f0SPeter Rosin
114ac8498f0SPeter Rosin ret = of_property_read_u32(child, "reg", &chan);
115ac8498f0SPeter Rosin if (ret < 0) {
11649d54abeSRob Herring dev_err(dev, "no reg property for node '%pOFn'\n",
11749d54abeSRob Herring child);
118ac8498f0SPeter Rosin goto err_children;
119ac8498f0SPeter Rosin }
120ac8498f0SPeter Rosin
121ac8498f0SPeter Rosin if (chan >= mux_control_states(mux->control)) {
122ac8498f0SPeter Rosin dev_err(dev, "invalid reg %u\n", chan);
123ac8498f0SPeter Rosin ret = -EINVAL;
124ac8498f0SPeter Rosin goto err_children;
125ac8498f0SPeter Rosin }
126ac8498f0SPeter Rosin
127ac8498f0SPeter Rosin ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
128ac8498f0SPeter Rosin if (ret)
129ac8498f0SPeter Rosin goto err_children;
130ac8498f0SPeter Rosin }
131ac8498f0SPeter Rosin
132ac8498f0SPeter Rosin dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name);
133ac8498f0SPeter Rosin
134ac8498f0SPeter Rosin return 0;
135ac8498f0SPeter Rosin
136ac8498f0SPeter Rosin err_children:
1376435319cSLiang He of_node_put(child);
138ac8498f0SPeter Rosin i2c_mux_del_adapters(muxc);
139ac8498f0SPeter Rosin err_parent:
140ac8498f0SPeter Rosin i2c_put_adapter(parent);
141ac8498f0SPeter Rosin
142ac8498f0SPeter Rosin return ret;
143ac8498f0SPeter Rosin }
144ac8498f0SPeter Rosin
i2c_mux_remove(struct platform_device * pdev)145e190a0c3SUwe Kleine-König static void i2c_mux_remove(struct platform_device *pdev)
146ac8498f0SPeter Rosin {
147ac8498f0SPeter Rosin struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
148ac8498f0SPeter Rosin
149ac8498f0SPeter Rosin i2c_mux_del_adapters(muxc);
150ac8498f0SPeter Rosin i2c_put_adapter(muxc->parent);
151ac8498f0SPeter Rosin }
152ac8498f0SPeter Rosin
153ac8498f0SPeter Rosin static struct platform_driver i2c_mux_driver = {
154ac8498f0SPeter Rosin .probe = i2c_mux_probe,
155e190a0c3SUwe Kleine-König .remove_new = i2c_mux_remove,
156ac8498f0SPeter Rosin .driver = {
157ac8498f0SPeter Rosin .name = "i2c-mux-gpmux",
158ac8498f0SPeter Rosin .of_match_table = i2c_mux_of_match,
159ac8498f0SPeter Rosin },
160ac8498f0SPeter Rosin };
161ac8498f0SPeter Rosin module_platform_driver(i2c_mux_driver);
162ac8498f0SPeter Rosin
163ac8498f0SPeter Rosin MODULE_DESCRIPTION("General Purpose I2C multiplexer driver");
164ac8498f0SPeter Rosin MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
165ac8498f0SPeter Rosin MODULE_LICENSE("GPL v2");
166