i2c-mux-pinctrl.c revision 6d4028c644edc0a2e4a8c948ebf81e8f2f09726e
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/init.h>
22ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/module.h>
23ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/of_i2c.h>
24ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/pinctrl/consumer.h>
25ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/i2c-mux-pinctrl.h>
26ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/platform_device.h>
27ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#include <linux/slab.h>
28ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
29ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstruct i2c_mux_pinctrl {
30ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct device *dev;
31ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl_platform_data *pdata;
32ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct pinctrl *pinctrl;
33ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct pinctrl_state **states;
34ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct pinctrl_state *state_idle;
35ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_adapter *parent;
36ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_adapter **busses;
37ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren};
38ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
39ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
40ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				  u32 chan)
41ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
42ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux = data;
43ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
44ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
45ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
46ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
47ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
48ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				    u32 chan)
49ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
50ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux = data;
51ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
52ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return pinctrl_select_state(mux->pinctrl, mux->state_idle);
53ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
54ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
55ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#ifdef CONFIG_OF
56ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
57ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				struct platform_device *pdev)
58ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
59ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct device_node *np = pdev->dev.of_node;
60ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int num_names, i, ret;
61ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct device_node *adapter_np;
62ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_adapter *adapter;
63ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
64ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!np)
65ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return 0;
66ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
67ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
68ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata) {
69ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev,
70ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			"Cannot allocate i2c_mux_pinctrl_platform_data\n");
71ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENOMEM;
72ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
73ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
74ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	num_names = of_property_count_strings(np, "pinctrl-names");
75ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (num_names < 0) {
76ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
77ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			num_names);
78ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return num_names;
79ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
80ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
81ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
82ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		sizeof(*mux->pdata->pinctrl_states) * num_names,
83ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		GFP_KERNEL);
84ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata->pinctrl_states) {
85ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
86ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENOMEM;
87ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
88ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
89ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < num_names; i++) {
90ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = of_property_read_string_index(np, "pinctrl-names", i,
91ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
92ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (ret < 0) {
93ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
94ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				ret);
95ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			return ret;
96ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
97ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
98ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			    "idle")) {
99ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			if (i != num_names - 1) {
100ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				dev_err(mux->dev, "idle state must be last\n");
101ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				return -EINVAL;
102ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			}
103ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			mux->pdata->pinctrl_state_idle = "idle";
104ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		} else {
105ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			mux->pdata->bus_count++;
106ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
107ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
108ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
109ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
110ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!adapter_np) {
111ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot parse i2c-parent\n");
112ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENODEV;
113ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
114ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	adapter = of_find_i2c_adapter_by_node(adapter_np);
115ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!adapter) {
116ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(mux->dev, "Cannot find parent bus\n");
117ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		return -ENODEV;
118ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
119ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
120ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	put_device(&adapter->dev);
121ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
122ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
123ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
124ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#else
125ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
126ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren					   struct platform_device *pdev)
127ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
128ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
129ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
130ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#endif
131ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
1320b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pembertonstatic int i2c_mux_pinctrl_probe(struct platform_device *pdev)
133ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
134ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux;
135ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int (*deselect)(struct i2c_adapter *, void *, u32);
136ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int i, ret;
137ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
138ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
139ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux) {
140ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
141ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENOMEM;
142ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
143ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
144ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	platform_set_drvdata(pdev, mux);
145ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
146ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->dev = &pdev->dev;
147ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
1486d4028c644edc0a2e4a8c948ebf81e8f2f09726eJingoo Han	mux->pdata = dev_get_platdata(&pdev->dev);
149ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata) {
150ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
151ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (ret < 0)
152ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			goto err;
153ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
154ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->pdata) {
155ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Missing platform data\n");
156ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENODEV;
157ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
158ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
159ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
160ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->states = devm_kzalloc(&pdev->dev,
161ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				   sizeof(*mux->states) * mux->pdata->bus_count,
162ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				   GFP_KERNEL);
163ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->states) {
164ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot allocate states\n");
165ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENOMEM;
166ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
167ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
168ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
169ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->busses = devm_kzalloc(&pdev->dev,
17043a2bd42d077de6ad40b00a2abfc4677e24d239cLaurent Navet				   sizeof(*mux->busses) * mux->pdata->bus_count,
171ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				   GFP_KERNEL);
172aa1e3e81e75ceb3d977c3292cefafcd5179eb8b8Guenter Roeck	if (!mux->busses) {
173ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot allocate busses\n");
174ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENOMEM;
175ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
176ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
177ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
178ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->pinctrl = devm_pinctrl_get(&pdev->dev);
179ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (IS_ERR(mux->pinctrl)) {
180ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = PTR_ERR(mux->pinctrl);
181ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Cannot get pinctrl: %d\n", ret);
182ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
183ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
184ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < mux->pdata->bus_count; i++) {
185ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
186ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						mux->pdata->pinctrl_states[i]);
187ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			if (IS_ERR(mux->states[i])) {
188ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				ret = PTR_ERR(mux->states[i]);
189ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				dev_err(&pdev->dev,
190ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren					"Cannot look up pinctrl state %s: %d\n",
191ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren					mux->pdata->pinctrl_states[i], ret);
192ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				goto err;
193ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			}
194ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
195ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (mux->pdata->pinctrl_state_idle) {
196ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
197ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						mux->pdata->pinctrl_state_idle);
198ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (IS_ERR(mux->state_idle)) {
199ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			ret = PTR_ERR(mux->state_idle);
200ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			dev_err(&pdev->dev,
201ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				"Cannot look up pinctrl state %s: %d\n",
202ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				mux->pdata->pinctrl_state_idle, ret);
203ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			goto err;
204ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
205ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
206ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		deselect = i2c_mux_pinctrl_deselect;
207ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	} else {
208ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		deselect = NULL;
209ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
210ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
211ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
212ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	if (!mux->parent) {
213ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
214ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			mux->pdata->parent_bus_num);
215ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		ret = -ENODEV;
216ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		goto err;
217ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
218ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
219ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < mux->pdata->bus_count; i++) {
220ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		u32 bus = mux->pdata->base_bus_num ?
221ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren				(mux->pdata->base_bus_num + i) : 0;
222ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
223ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
224eee543e8248150e8fb833943c71f40c7b1724600Jean Delvare						     mux, bus, i, 0,
225ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						     i2c_mux_pinctrl_select,
226ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren						     deselect);
227ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		if (!mux->busses[i]) {
228ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			ret = -ENODEV;
229ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
230ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren			goto err_del_adapter;
231ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		}
232ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	}
233ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
234ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
235ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
236ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenerr_del_adapter:
237ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (; i > 0; i--)
238ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		i2c_del_mux_adapter(mux->busses[i - 1]);
239ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	i2c_put_adapter(mux->parent);
240ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenerr:
241ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return ret;
242ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
243ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
2440b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pembertonstatic int i2c_mux_pinctrl_remove(struct platform_device *pdev)
245ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren{
246ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
247ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	int i;
248ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
249ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	for (i = 0; i < mux->pdata->bus_count; i++)
250ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		i2c_del_mux_adapter(mux->busses[i]);
251ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
252ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	i2c_put_adapter(mux->parent);
253ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
254ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	return 0;
255ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren}
256ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
257ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#ifdef CONFIG_OF
2580b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pembertonstatic const struct of_device_id i2c_mux_pinctrl_of_match[] = {
259ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	{ .compatible = "i2c-mux-pinctrl", },
260ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	{},
261ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren};
262ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
263ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren#endif
264ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
265ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenstatic struct platform_driver i2c_mux_pinctrl_driver = {
266ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	.driver	= {
267ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		.name	= "i2c-mux-pinctrl",
268ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		.owner	= THIS_MODULE,
269ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren		.of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
270ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	},
271ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren	.probe	= i2c_mux_pinctrl_probe,
2720b255e927d47b550620dfd3475ee74b0f52e09c8Bill Pemberton	.remove	= i2c_mux_pinctrl_remove,
273ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren};
274ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warrenmodule_platform_driver(i2c_mux_pinctrl_driver);
275ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen Warren
276ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver");
277ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
278ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_LICENSE("GPL v2");
279ae58d1e406986f31d1e88b32f5ac601506c196d8Stephen WarrenMODULE_ALIAS("platform:i2c-mux-pinctrl");
280