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