1ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren/*
2ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * I2C multiplexer using pinctrl API
3ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren *
4ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
5ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren *
6ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * This program is free software; you can redistribute it and/or modify it
7ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * under the terms and conditions of the GNU General Public License,
8ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * version 2, as published by the Free Software Foundation.
9ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren *
10ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * This program is distributed in the hope it will be useful, but WITHOUT
11ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * more details.
14ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren *
15ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * You should have received a copy of the GNU General Public License
16ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren */
18ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
19ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/i2c.h>
20ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/i2c-mux.h>
21ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/module.h>
22ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/pinctrl/consumer.h>
23ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/i2c-mux-pinctrl.h>
24ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/platform_device.h>
25ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/slab.h>
264edd65e63fe4a998164a8d7d8c8c86f4300825d7Sachin Kamat#include <linux/of.h>
27ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
28ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstruct i2c_mux_pinctrl {
29ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct device *dev;
30ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl_platform_data *pdata;
31ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct pinctrl *pinctrl;
32ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct pinctrl_state **states;
33ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct pinctrl_state *state_idle;
34ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_adapter *parent;
35ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_adapter **busses;
36ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren};
37ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
38ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
39ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				  u32 chan)
40ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
41ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux = data;
42ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
43ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
44ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
45ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
46ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
47ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				    u32 chan)
48ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
49ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux = data;
50ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
51ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return pinctrl_select_state(mux->pinctrl, mux->state_idle);
52ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
53ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
54ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#ifdef CONFIG_OF
55ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
56ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				struct platform_device *pdev)
57ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
58ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct device_node *np = pdev->dev.of_node;
59ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int num_names, i, ret;
60ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct device_node *adapter_np;
61ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_adapter *adapter;
62ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
63ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!np)
64ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return 0;
65ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
66ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
67ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata) {
68ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev,
69ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			"Cannot allocate i2c_mux_pinctrl_platform_data\n");
70ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENOMEM;
71ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
72ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
73ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	num_names = of_property_count_strings(np, "pinctrl-names");
74ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (num_names < 0) {
75ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
76ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			num_names);
77ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return num_names;
78ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
79ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
80ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
81ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		sizeof(*mux->pdata->pinctrl_states) * num_names,
82ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		GFP_KERNEL);
83ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata->pinctrl_states) {
84ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
85ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENOMEM;
86ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
87ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
88ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < num_names; i++) {
89ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = of_property_read_string_index(np, "pinctrl-names", i,
90ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
91ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (ret < 0) {
92ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
93ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				ret);
94ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			return ret;
95ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
96ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
97ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			    "idle")) {
98ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			if (i != num_names - 1) {
99ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				dev_err(mux->dev, "idle state must be last\n");
100ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				return -EINVAL;
101ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			}
102ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			mux->pdata->pinctrl_state_idle = "idle";
103ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		} else {
104ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			mux->pdata->bus_count++;
105ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
106ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
107ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
108ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
109ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!adapter_np) {
110ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot parse i2c-parent\n");
111ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENODEV;
112ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
113ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	adapter = of_find_i2c_adapter_by_node(adapter_np);
114ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!adapter) {
115ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot find parent bus\n");
1162737de460e33df89461a59b247d3bfd477101785Wolfram Sang		return -EPROBE_DEFER;
117ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
118ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
119ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	put_device(&adapter->dev);
120ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
121ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
122ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
123ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#else
124ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
125ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren					   struct platform_device *pdev)
126ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
127ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
128ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
129ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#endif
130ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
1310b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pembertonstatic int i2c_mux_pinctrl_probe(struct platform_device *pdev)
132ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
133ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux;
134ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int (*deselect)(struct i2c_adapter *, void *, u32);
135ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int i, ret;
136ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
137ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
138ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux) {
139ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
140ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENOMEM;
141ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
142ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
143ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	platform_set_drvdata(pdev, mux);
144ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
145ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->dev = &pdev->dev;
146ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
1476d4028c644edc0a2e4a8c948ebf81e8f2f09726eJingoo Han	mux->pdata = dev_get_platdata(&pdev->dev);
148ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata) {
149ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
150ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (ret < 0)
151ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			goto err;
152ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
153ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata) {
154ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Missing platform data\n");
155ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENODEV;
156ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
157ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
158ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
159ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->states = devm_kzalloc(&pdev->dev,
160ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				   sizeof(*mux->states) * mux->pdata->bus_count,
161ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				   GFP_KERNEL);
162ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->states) {
163ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot allocate states\n");
164ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENOMEM;
165ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
166ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
167ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
168ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->busses = devm_kzalloc(&pdev->dev,
16943a2bd42d077de6ad40b00a2abfc4677e24d239cLaurent Navet				   sizeof(*mux->busses) * mux->pdata->bus_count,
170ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				   GFP_KERNEL);
171aa1e3e81e75ceb3d977c3292cefafcd5179eb8b8Guenter Roeck	if (!mux->busses) {
172ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot allocate busses\n");
173ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENOMEM;
174ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
175ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
176ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
177ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pinctrl = devm_pinctrl_get(&pdev->dev);
178ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (IS_ERR(mux->pinctrl)) {
179ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = PTR_ERR(mux->pinctrl);
180ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot get pinctrl: %d\n", ret);
181ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
182ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
183ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < mux->pdata->bus_count; i++) {
184ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
185ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						mux->pdata->pinctrl_states[i]);
186ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			if (IS_ERR(mux->states[i])) {
187ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				ret = PTR_ERR(mux->states[i]);
188ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				dev_err(&pdev->dev,
189ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren					"Cannot look up pinctrl state %s: %d\n",
190ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren					mux->pdata->pinctrl_states[i], ret);
191ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				goto err;
192ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			}
193ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
194ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (mux->pdata->pinctrl_state_idle) {
195ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
196ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						mux->pdata->pinctrl_state_idle);
197ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (IS_ERR(mux->state_idle)) {
198ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			ret = PTR_ERR(mux->state_idle);
199ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			dev_err(&pdev->dev,
200ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				"Cannot look up pinctrl state %s: %d\n",
201ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				mux->pdata->pinctrl_state_idle, ret);
202ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			goto err;
203ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
204ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
205ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		deselect = i2c_mux_pinctrl_deselect;
206ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	} else {
207ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		deselect = NULL;
208ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
209ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
210ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
211ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->parent) {
212ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
213ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			mux->pdata->parent_bus_num);
2142737de460e33df89461a59b247d3bfd477101785Wolfram Sang		ret = -EPROBE_DEFER;
215ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
216ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
217ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
218ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < mux->pdata->bus_count; i++) {
219ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		u32 bus = mux->pdata->base_bus_num ?
220ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				(mux->pdata->base_bus_num + i) : 0;
221ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
222ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
223eee543e8248150e8fb833943c71f40c7b1724600Jean Delvare						     mux, bus, i, 0,
224ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						     i2c_mux_pinctrl_select,
225ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						     deselect);
226ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (!mux->busses[i]) {
227ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			ret = -ENODEV;
228ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
229ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			goto err_del_adapter;
230ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
231ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
232ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
233ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
234ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
235ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenerr_del_adapter:
236ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (; i > 0; i--)
237ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		i2c_del_mux_adapter(mux->busses[i - 1]);
238ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	i2c_put_adapter(mux->parent);
239ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenerr:
240ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return ret;
241ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
242ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
2430b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pembertonstatic int i2c_mux_pinctrl_remove(struct platform_device *pdev)
244ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
245ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
246ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int i;
247ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
248ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < mux->pdata->bus_count; i++)
249ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		i2c_del_mux_adapter(mux->busses[i]);
250ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
251ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	i2c_put_adapter(mux->parent);
252ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
253ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
254ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
255ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
256ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#ifdef CONFIG_OF
2570b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pembertonstatic const struct of_device_id i2c_mux_pinctrl_of_match[] = {
258ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	{ .compatible = "i2c-mux-pinctrl", },
259ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	{},
260ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren};
261ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
262ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#endif
263ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
264ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic struct platform_driver i2c_mux_pinctrl_driver = {
265ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	.driver	= {
266ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		.name	= "i2c-mux-pinctrl",
267ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		.owner	= THIS_MODULE,
268ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		.of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
269ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	},
270ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	.probe	= i2c_mux_pinctrl_probe,
2710b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pemberton	.remove	= i2c_mux_pinctrl_remove,
272ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren};
273ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenmodule_platform_driver(i2c_mux_pinctrl_driver);
274ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
275ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver");
276ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
277ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_LICENSE("GPL v2");
278ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_ALIAS("platform:i2c-mux-pinctrl");
279