blob: 9dd26972703650e0e071f917f207af4dc83003fc [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Michal Simekd79ac322016-04-25 10:50:42 +02002/*
3 * Copyright (C) 2015 - 2016 Xilinx, Inc.
Moritz Fischer36bdeb72017-09-12 06:46:59 -07004 * Copyright (C) 2017 National Instruments Corp
Michal Simekd79ac322016-04-25 10:50:42 +02005 * Written by Michal Simek
Michal Simekd79ac322016-04-25 10:50:42 +02006 */
7
Michal Simekd79ac322016-04-25 10:50:42 +02008#include <dm.h>
9#include <errno.h>
10#include <i2c.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070012#include <malloc.h>
Moritz Fischer36bdeb72017-09-12 06:46:59 -070013
14#include <asm-generic/gpio.h>
Michal Simekd79ac322016-04-25 10:50:42 +020015
Marek Behún8e6eda72017-06-09 19:28:43 +020016enum pca_type {
Maksim Kiselevf7c98392024-09-19 19:06:56 +030017 MAX7356,
18 MAX7357,
19 MAX7358,
20 MAX7367,
21 MAX7368,
22 MAX7369,
Luca Ceresoli9985b742019-04-09 08:57:43 +020023 PCA9543,
Marek Behún8e6eda72017-06-09 19:28:43 +020024 PCA9544,
Chris Packham0b1d7b72020-04-01 15:55:27 +130025 PCA9546,
Marek Behún8e6eda72017-06-09 19:28:43 +020026 PCA9547,
Peng Fan16f513e2018-07-17 20:38:32 +080027 PCA9548,
Vladimir Oltean3285a572022-01-03 14:47:22 +020028 PCA9646,
29 PCA9847,
Marek Behún8e6eda72017-06-09 19:28:43 +020030};
31
32struct chip_desc {
Luca Ceresoli5995cdb2019-04-09 08:57:42 +020033 u8 enable; /* Enable mask in ctl register (used for muxes only) */
Marek Behún8e6eda72017-06-09 19:28:43 +020034 enum muxtype {
35 pca954x_ismux = 0,
36 pca954x_isswi,
37 } muxtype;
Chris Packham5bc90a82017-09-29 10:53:36 +130038 u32 width;
Marek Behún8e6eda72017-06-09 19:28:43 +020039};
40
Michal Simekd79ac322016-04-25 10:50:42 +020041struct pca954x_priv {
42 u32 addr; /* I2C mux address */
43 u32 width; /* I2C mux width - number of busses */
Moritz Fischer36bdeb72017-09-12 06:46:59 -070044 struct gpio_desc gpio_mux_reset;
Michal Simekd79ac322016-04-25 10:50:42 +020045};
46
Marek Behún8e6eda72017-06-09 19:28:43 +020047static const struct chip_desc chips[] = {
Maksim Kiselevf7c98392024-09-19 19:06:56 +030048 [MAX7356] = {
49 .muxtype = pca954x_isswi,
50 .width = 8,
51 },
52 [MAX7357] = {
53 .muxtype = pca954x_isswi,
54 .width = 8,
55 },
56 [MAX7358] = {
57 .muxtype = pca954x_isswi,
58 .width = 8,
59 },
60 [MAX7367] = {
61 .muxtype = pca954x_isswi,
62 .width = 4,
63 },
64 [MAX7368] = {
65 .muxtype = pca954x_isswi,
66 .width = 4,
67 },
68 [MAX7369] = {
69 .enable = 0x4,
70 .muxtype = pca954x_ismux,
71 .width = 4,
72 },
Luca Ceresoli9985b742019-04-09 08:57:43 +020073 [PCA9543] = {
74 .muxtype = pca954x_isswi,
75 .width = 2,
76 },
Marek Behún8e6eda72017-06-09 19:28:43 +020077 [PCA9544] = {
78 .enable = 0x4,
79 .muxtype = pca954x_ismux,
Chris Packham5bc90a82017-09-29 10:53:36 +130080 .width = 4,
Marek Behún8e6eda72017-06-09 19:28:43 +020081 },
Chris Packham0b1d7b72020-04-01 15:55:27 +130082 [PCA9546] = {
83 .muxtype = pca954x_isswi,
84 .width = 4,
85 },
Marek Behún8e6eda72017-06-09 19:28:43 +020086 [PCA9547] = {
87 .enable = 0x8,
88 .muxtype = pca954x_ismux,
Chris Packham5bc90a82017-09-29 10:53:36 +130089 .width = 8,
Marek Behún8e6eda72017-06-09 19:28:43 +020090 },
91 [PCA9548] = {
Marek Behún8e6eda72017-06-09 19:28:43 +020092 .muxtype = pca954x_isswi,
Chris Packham5bc90a82017-09-29 10:53:36 +130093 .width = 8,
Marek Behún8e6eda72017-06-09 19:28:43 +020094 },
Peng Fan16f513e2018-07-17 20:38:32 +080095 [PCA9646] = {
Peng Fan16f513e2018-07-17 20:38:32 +080096 .muxtype = pca954x_isswi,
97 .width = 4,
98 },
Vladimir Oltean3285a572022-01-03 14:47:22 +020099 [PCA9847] = {
100 .enable = 0x8,
101 .muxtype = pca954x_ismux,
102 .width = 8,
103 },
Marek Behún8e6eda72017-06-09 19:28:43 +0200104};
105
Michal Simekd79ac322016-04-25 10:50:42 +0200106static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
107 uint channel)
108{
109 struct pca954x_priv *priv = dev_get_priv(mux);
110 uchar byte = 0;
111
112 return dm_i2c_write(mux, priv->addr, &byte, 1);
113}
114
115static int pca954x_select(struct udevice *mux, struct udevice *bus,
116 uint channel)
117{
118 struct pca954x_priv *priv = dev_get_priv(mux);
Marek Behún8e6eda72017-06-09 19:28:43 +0200119 const struct chip_desc *chip = &chips[dev_get_driver_data(mux)];
120 uchar byte;
121
122 if (chip->muxtype == pca954x_ismux)
123 byte = channel | chip->enable;
124 else
125 byte = 1 << channel;
Michal Simekd79ac322016-04-25 10:50:42 +0200126
127 return dm_i2c_write(mux, priv->addr, &byte, 1);
128}
129
130static const struct i2c_mux_ops pca954x_ops = {
131 .select = pca954x_select,
132 .deselect = pca954x_deselect,
133};
134
135static const struct udevice_id pca954x_ids[] = {
Maksim Kiselevf7c98392024-09-19 19:06:56 +0300136 { .compatible = "maxim,max7356", .data = MAX7356 },
137 { .compatible = "maxim,max7357", .data = MAX7357 },
138 { .compatible = "maxim,max7358", .data = MAX7358 },
139 { .compatible = "maxim,max7367", .data = MAX7367 },
140 { .compatible = "maxim,max7368", .data = MAX7368 },
141 { .compatible = "maxim,max7369", .data = MAX7369 },
Luca Ceresoli9985b742019-04-09 08:57:43 +0200142 { .compatible = "nxp,pca9543", .data = PCA9543 },
Marek Behún8e6eda72017-06-09 19:28:43 +0200143 { .compatible = "nxp,pca9544", .data = PCA9544 },
Chris Packham0b1d7b72020-04-01 15:55:27 +1300144 { .compatible = "nxp,pca9546", .data = PCA9546 },
Marek Behún8e6eda72017-06-09 19:28:43 +0200145 { .compatible = "nxp,pca9547", .data = PCA9547 },
146 { .compatible = "nxp,pca9548", .data = PCA9548 },
Peng Fan16f513e2018-07-17 20:38:32 +0800147 { .compatible = "nxp,pca9646", .data = PCA9646 },
Vladimir Oltean3285a572022-01-03 14:47:22 +0200148 { .compatible = "nxp,pca9847", .data = PCA9847 },
Michal Simekd79ac322016-04-25 10:50:42 +0200149 { }
150};
151
Simon Glassd1998a92020-12-03 16:55:21 -0700152static int pca954x_of_to_plat(struct udevice *dev)
Michal Simekd79ac322016-04-25 10:50:42 +0200153{
154 struct pca954x_priv *priv = dev_get_priv(dev);
Chris Packham5bc90a82017-09-29 10:53:36 +1300155 const struct chip_desc *chip = &chips[dev_get_driver_data(dev)];
Michal Simekd79ac322016-04-25 10:50:42 +0200156
Michal Simek58dc4a92019-01-09 11:58:24 +0100157 priv->addr = dev_read_u32_default(dev, "reg", 0);
Michal Simekd79ac322016-04-25 10:50:42 +0200158 if (!priv->addr) {
159 debug("MUX not found\n");
160 return -ENODEV;
161 }
Chris Packham5bc90a82017-09-29 10:53:36 +1300162 priv->width = chip->width;
Michal Simekd79ac322016-04-25 10:50:42 +0200163
164 if (!priv->width) {
165 debug("No I2C MUX width specified\n");
166 return -EINVAL;
167 }
168
169 debug("Device %s at 0x%x with width %d\n",
170 dev->name, priv->addr, priv->width);
171
172 return 0;
173}
174
Moritz Fischer36bdeb72017-09-12 06:46:59 -0700175static int pca954x_probe(struct udevice *dev)
176{
Simon Glassbcee8d62019-12-06 21:41:35 -0700177 if (CONFIG_IS_ENABLED(DM_GPIO)) {
Moritz Fischer36bdeb72017-09-12 06:46:59 -0700178 struct pca954x_priv *priv = dev_get_priv(dev);
179 int err;
180
181 err = gpio_request_by_name(dev, "reset-gpios", 0,
182 &priv->gpio_mux_reset, GPIOD_IS_OUT);
183
184 /* it's optional so only bail if we get a real error */
185 if (err && (err != -ENOENT))
186 return err;
187
188 /* dm will take care of polarity */
189 if (dm_gpio_is_valid(&priv->gpio_mux_reset))
190 dm_gpio_set_value(&priv->gpio_mux_reset, 0);
191 }
192
193 return 0;
194}
195
196static int pca954x_remove(struct udevice *dev)
197{
Simon Glassbcee8d62019-12-06 21:41:35 -0700198 if (CONFIG_IS_ENABLED(DM_GPIO)) {
Moritz Fischer36bdeb72017-09-12 06:46:59 -0700199 struct pca954x_priv *priv = dev_get_priv(dev);
200
201 if (dm_gpio_is_valid(&priv->gpio_mux_reset))
202 dm_gpio_free(dev, &priv->gpio_mux_reset);
203 }
204
205 return 0;
206}
207
Michal Simekd79ac322016-04-25 10:50:42 +0200208U_BOOT_DRIVER(pca954x) = {
209 .name = "pca954x",
210 .id = UCLASS_I2C_MUX,
211 .of_match = pca954x_ids,
Moritz Fischer36bdeb72017-09-12 06:46:59 -0700212 .probe = pca954x_probe,
213 .remove = pca954x_remove,
Michal Simekd79ac322016-04-25 10:50:42 +0200214 .ops = &pca954x_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700215 .of_to_plat = pca954x_of_to_plat,
Simon Glass41575d82020-12-03 16:55:17 -0700216 .priv_auto = sizeof(struct pca954x_priv),
Michal Simekd79ac322016-04-25 10:50:42 +0200217};