xref: /rk3399_rockchip-uboot/drivers/i2c/muxes/i2c-mux-gpio.c (revision cc0427d2695220961f43dfb5e110511a9cb8ae16)
1*a430556eSPeng Fan /*
2*a430556eSPeng Fan  * I2C multiplexer using GPIO API
3*a430556eSPeng Fan  *
4*a430556eSPeng Fan  * Copyright 2017 NXP
5*a430556eSPeng Fan  *
6*a430556eSPeng Fan  * Peng Fan <peng.fan@nxp.com>
7*a430556eSPeng Fan  *
8*a430556eSPeng Fan  * SPDX-License-Identifier:	GPL-2.0+
9*a430556eSPeng Fan  */
10*a430556eSPeng Fan 
11*a430556eSPeng Fan #include <asm/io.h>
12*a430556eSPeng Fan #include <asm-generic/gpio.h>
13*a430556eSPeng Fan #include <common.h>
14*a430556eSPeng Fan #include <dm.h>
15*a430556eSPeng Fan #include <dm/pinctrl.h>
16*a430556eSPeng Fan #include <fdtdec.h>
17*a430556eSPeng Fan #include <i2c.h>
18*a430556eSPeng Fan #include <linux/errno.h>
19*a430556eSPeng Fan 
20*a430556eSPeng Fan DECLARE_GLOBAL_DATA_PTR;
21*a430556eSPeng Fan 
22*a430556eSPeng Fan /**
23*a430556eSPeng Fan  * struct i2c_mux_gpio_priv - private data for i2c mux gpio
24*a430556eSPeng Fan  *
25*a430556eSPeng Fan  * @values: the reg value of each child node
26*a430556eSPeng Fan  * @n_values: num of regs
27*a430556eSPeng Fan  * @gpios: the mux-gpios array
28*a430556eSPeng Fan  * @n_gpios: num of gpios in mux-gpios
29*a430556eSPeng Fan  * @idle: the value of idle-state
30*a430556eSPeng Fan  */
31*a430556eSPeng Fan struct i2c_mux_gpio_priv {
32*a430556eSPeng Fan 	u32 *values;
33*a430556eSPeng Fan 	int n_values;
34*a430556eSPeng Fan 	struct gpio_desc *gpios;
35*a430556eSPeng Fan 	int n_gpios;
36*a430556eSPeng Fan 	u32 idle;
37*a430556eSPeng Fan };
38*a430556eSPeng Fan 
39*a430556eSPeng Fan 
i2c_mux_gpio_select(struct udevice * dev,struct udevice * bus,uint channel)40*a430556eSPeng Fan static int i2c_mux_gpio_select(struct udevice *dev, struct udevice *bus,
41*a430556eSPeng Fan 			       uint channel)
42*a430556eSPeng Fan {
43*a430556eSPeng Fan 	struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
44*a430556eSPeng Fan 	int i, ret;
45*a430556eSPeng Fan 
46*a430556eSPeng Fan 	for (i = 0; i < priv->n_gpios; i++) {
47*a430556eSPeng Fan 		ret = dm_gpio_set_value(&priv->gpios[i], (channel >> i) & 1);
48*a430556eSPeng Fan 		if (ret)
49*a430556eSPeng Fan 			return ret;
50*a430556eSPeng Fan 	}
51*a430556eSPeng Fan 
52*a430556eSPeng Fan 	return 0;
53*a430556eSPeng Fan }
54*a430556eSPeng Fan 
i2c_mux_gpio_deselect(struct udevice * dev,struct udevice * bus,uint channel)55*a430556eSPeng Fan static int i2c_mux_gpio_deselect(struct udevice *dev, struct udevice *bus,
56*a430556eSPeng Fan 				 uint channel)
57*a430556eSPeng Fan {
58*a430556eSPeng Fan 	struct i2c_mux_gpio_priv *priv = dev_get_priv(dev);
59*a430556eSPeng Fan 	int i, ret;
60*a430556eSPeng Fan 
61*a430556eSPeng Fan 	for (i = 0; i < priv->n_gpios; i++) {
62*a430556eSPeng Fan 		ret = dm_gpio_set_value(&priv->gpios[i], (priv->idle >> i) & 1);
63*a430556eSPeng Fan 		if (ret)
64*a430556eSPeng Fan 			return ret;
65*a430556eSPeng Fan 	}
66*a430556eSPeng Fan 
67*a430556eSPeng Fan 	return 0;
68*a430556eSPeng Fan }
69*a430556eSPeng Fan 
i2c_mux_gpio_probe(struct udevice * dev)70*a430556eSPeng Fan static int i2c_mux_gpio_probe(struct udevice *dev)
71*a430556eSPeng Fan {
72*a430556eSPeng Fan 	const void *fdt = gd->fdt_blob;
73*a430556eSPeng Fan 	int node = dev_of_offset(dev);
74*a430556eSPeng Fan 	struct i2c_mux_gpio_priv *mux = dev_get_priv(dev);
75*a430556eSPeng Fan 	struct gpio_desc *gpios;
76*a430556eSPeng Fan 	u32 *values;
77*a430556eSPeng Fan 	int i = 0, subnode, ret;
78*a430556eSPeng Fan 
79*a430556eSPeng Fan 	mux->n_values = fdtdec_get_child_count(fdt, node);
80*a430556eSPeng Fan 	values = devm_kzalloc(dev, sizeof(*mux->values) * mux->n_values,
81*a430556eSPeng Fan 			      GFP_KERNEL);
82*a430556eSPeng Fan 	if (!values) {
83*a430556eSPeng Fan 		dev_err(dev, "Cannot alloc values array");
84*a430556eSPeng Fan 		return -ENOMEM;
85*a430556eSPeng Fan 	}
86*a430556eSPeng Fan 
87*a430556eSPeng Fan 	fdt_for_each_subnode(subnode, fdt, node) {
88*a430556eSPeng Fan 		*(values + i) = fdtdec_get_uint(fdt, subnode, "reg", -1);
89*a430556eSPeng Fan 		i++;
90*a430556eSPeng Fan 	}
91*a430556eSPeng Fan 
92*a430556eSPeng Fan 	mux->values = values;
93*a430556eSPeng Fan 
94*a430556eSPeng Fan 	mux->idle = fdtdec_get_uint(fdt, node, "idle-state", -1);
95*a430556eSPeng Fan 
96*a430556eSPeng Fan 	mux->n_gpios = gpio_get_list_count(dev, "mux-gpios");
97*a430556eSPeng Fan 	if (mux->n_gpios < 0) {
98*a430556eSPeng Fan 		dev_err(dev, "Missing mux-gpios property\n");
99*a430556eSPeng Fan 		return -EINVAL;
100*a430556eSPeng Fan 	}
101*a430556eSPeng Fan 
102*a430556eSPeng Fan 	gpios = devm_kzalloc(dev, sizeof(struct gpio_desc) * mux->n_gpios,
103*a430556eSPeng Fan 			     GFP_KERNEL);
104*a430556eSPeng Fan 	if (!gpios) {
105*a430556eSPeng Fan 		dev_err(dev, "Cannot allocate gpios array\n");
106*a430556eSPeng Fan 		return -ENOMEM;
107*a430556eSPeng Fan 	}
108*a430556eSPeng Fan 
109*a430556eSPeng Fan 	ret = gpio_request_list_by_name(dev, "mux-gpios", gpios, mux->n_gpios,
110*a430556eSPeng Fan 					GPIOD_IS_OUT_ACTIVE);
111*a430556eSPeng Fan 	if (ret <= 0) {
112*a430556eSPeng Fan 		dev_err(dev, "Failed to request mux-gpios\n");
113*a430556eSPeng Fan 		return ret;
114*a430556eSPeng Fan 	}
115*a430556eSPeng Fan 
116*a430556eSPeng Fan 	mux->gpios = gpios;
117*a430556eSPeng Fan 
118*a430556eSPeng Fan 	return 0;
119*a430556eSPeng Fan }
120*a430556eSPeng Fan 
121*a430556eSPeng Fan static const struct i2c_mux_ops i2c_mux_gpio_ops = {
122*a430556eSPeng Fan 	.select = i2c_mux_gpio_select,
123*a430556eSPeng Fan 	.deselect = i2c_mux_gpio_deselect,
124*a430556eSPeng Fan };
125*a430556eSPeng Fan 
126*a430556eSPeng Fan static const struct udevice_id i2c_mux_gpio_ids[] = {
127*a430556eSPeng Fan 	{ .compatible = "i2c-mux-gpio", },
128*a430556eSPeng Fan 	{}
129*a430556eSPeng Fan };
130*a430556eSPeng Fan 
131*a430556eSPeng Fan U_BOOT_DRIVER(i2c_mux_gpio) = {
132*a430556eSPeng Fan 	.name = "i2c_mux_gpio",
133*a430556eSPeng Fan 	.id = UCLASS_I2C_MUX,
134*a430556eSPeng Fan 	.of_match = i2c_mux_gpio_ids,
135*a430556eSPeng Fan 	.ops = &i2c_mux_gpio_ops,
136*a430556eSPeng Fan 	.probe = i2c_mux_gpio_probe,
137*a430556eSPeng Fan 	.priv_auto_alloc_size = sizeof(struct i2c_mux_gpio_priv),
138*a430556eSPeng Fan };
139