i2c: muxes: pca954x: add PCA9546 variant
[oweals/u-boot.git] / drivers / i2c / muxes / pca954x.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 - 2016 Xilinx, Inc.
4  * Copyright (C) 2017 National Instruments Corp
5  * Written by Michal Simek
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <i2c.h>
12 #include <malloc.h>
13
14 #include <asm-generic/gpio.h>
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 enum pca_type {
19         PCA9543,
20         PCA9544,
21         PCA9546,
22         PCA9547,
23         PCA9548,
24         PCA9646
25 };
26
27 struct chip_desc {
28         u8 enable; /* Enable mask in ctl register (used for muxes only) */
29         enum muxtype {
30                 pca954x_ismux = 0,
31                 pca954x_isswi,
32         } muxtype;
33         u32 width;
34 };
35
36 struct pca954x_priv {
37         u32 addr; /* I2C mux address */
38         u32 width; /* I2C mux width - number of busses */
39         struct gpio_desc gpio_mux_reset;
40 };
41
42 static const struct chip_desc chips[] = {
43         [PCA9543] = {
44                 .muxtype = pca954x_isswi,
45                 .width = 2,
46         },
47         [PCA9544] = {
48                 .enable = 0x4,
49                 .muxtype = pca954x_ismux,
50                 .width = 4,
51         },
52         [PCA9546] = {
53                 .muxtype = pca954x_isswi,
54                 .width = 4,
55         },
56         [PCA9547] = {
57                 .enable = 0x8,
58                 .muxtype = pca954x_ismux,
59                 .width = 8,
60         },
61         [PCA9548] = {
62                 .muxtype = pca954x_isswi,
63                 .width = 8,
64         },
65         [PCA9646] = {
66                 .muxtype = pca954x_isswi,
67                 .width = 4,
68         },
69 };
70
71 static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
72                             uint channel)
73 {
74         struct pca954x_priv *priv = dev_get_priv(mux);
75         uchar byte = 0;
76
77         return dm_i2c_write(mux, priv->addr, &byte, 1);
78 }
79
80 static int pca954x_select(struct udevice *mux, struct udevice *bus,
81                           uint channel)
82 {
83         struct pca954x_priv *priv = dev_get_priv(mux);
84         const struct chip_desc *chip = &chips[dev_get_driver_data(mux)];
85         uchar byte;
86
87         if (chip->muxtype == pca954x_ismux)
88                 byte = channel | chip->enable;
89         else
90                 byte = 1 << channel;
91
92         return dm_i2c_write(mux, priv->addr, &byte, 1);
93 }
94
95 static const struct i2c_mux_ops pca954x_ops = {
96         .select = pca954x_select,
97         .deselect = pca954x_deselect,
98 };
99
100 static const struct udevice_id pca954x_ids[] = {
101         { .compatible = "nxp,pca9543", .data = PCA9543 },
102         { .compatible = "nxp,pca9544", .data = PCA9544 },
103         { .compatible = "nxp,pca9546", .data = PCA9546 },
104         { .compatible = "nxp,pca9547", .data = PCA9547 },
105         { .compatible = "nxp,pca9548", .data = PCA9548 },
106         { .compatible = "nxp,pca9646", .data = PCA9646 },
107         { }
108 };
109
110 static int pca954x_ofdata_to_platdata(struct udevice *dev)
111 {
112         struct pca954x_priv *priv = dev_get_priv(dev);
113         const struct chip_desc *chip = &chips[dev_get_driver_data(dev)];
114
115         priv->addr = dev_read_u32_default(dev, "reg", 0);
116         if (!priv->addr) {
117                 debug("MUX not found\n");
118                 return -ENODEV;
119         }
120         priv->width = chip->width;
121
122         if (!priv->width) {
123                 debug("No I2C MUX width specified\n");
124                 return -EINVAL;
125         }
126
127         debug("Device %s at 0x%x with width %d\n",
128               dev->name, priv->addr, priv->width);
129
130         return 0;
131 }
132
133 static int pca954x_probe(struct udevice *dev)
134 {
135         if (CONFIG_IS_ENABLED(DM_GPIO)) {
136                 struct pca954x_priv *priv = dev_get_priv(dev);
137                 int err;
138
139                 err = gpio_request_by_name(dev, "reset-gpios", 0,
140                                 &priv->gpio_mux_reset, GPIOD_IS_OUT);
141
142                 /* it's optional so only bail if we get a real error */
143                 if (err && (err != -ENOENT))
144                         return err;
145
146                 /* dm will take care of polarity */
147                 if (dm_gpio_is_valid(&priv->gpio_mux_reset))
148                         dm_gpio_set_value(&priv->gpio_mux_reset, 0);
149         }
150
151         return 0;
152 }
153
154 static int pca954x_remove(struct udevice *dev)
155 {
156         if (CONFIG_IS_ENABLED(DM_GPIO)) {
157                 struct pca954x_priv *priv = dev_get_priv(dev);
158
159                 if (dm_gpio_is_valid(&priv->gpio_mux_reset))
160                         dm_gpio_free(dev, &priv->gpio_mux_reset);
161         }
162
163         return 0;
164 }
165
166 U_BOOT_DRIVER(pca954x) = {
167         .name = "pca954x",
168         .id = UCLASS_I2C_MUX,
169         .of_match = pca954x_ids,
170         .probe = pca954x_probe,
171         .remove = pca954x_remove,
172         .ops = &pca954x_ops,
173         .ofdata_to_platdata = pca954x_ofdata_to_platdata,
174         .priv_auto_alloc_size = sizeof(struct pca954x_priv),
175 };