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