1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * NCA9539 I2C Port Expander I/O
4 *
5 * Copyright (C) 2023 Cody Xie <cody.xie@rock-chips.com>
6 *
7 */
8 #include <common.h>
9 #include <errno.h>
10 #include <dm.h>
11 #include <fdtdec.h>
12 #include <i2c.h>
13 #include <malloc.h>
14 #include <asm/gpio.h>
15 #include <asm/io.h>
16 #include <dt-bindings/gpio/gpio.h>
17 #include <linux/bitops.h>
18
19 #define NCA9539_REG_INPUT_PORT_BASE 0x00
20 #define NCA9539_REG_INPUT_PORT0 (NCA9539_REG_INPUT_PORT_BASE + 0x0)
21 #define NCA9539_REG_INPUT_PORT1 (NCA9539_REG_INPUT_PORT_BASE + 0x1)
22 #define NCA9539_REG_OUTPUT_PORT_BASE 0x02
23 #define NCA9539_REG_OUTPUT_PORT0 (NCA9539_REG_OUTPUT_PORT_BASE + 0x0)
24 #define NCA9539_REG_OUTPUT_PORT1 (NCA9539_REG_OUTPUT_PORT_BASE + 0x1)
25 #define NCA9539_REG_POLARITY_BASE 0x04
26 #define NCA9539_REG_POLARITY_PORT0 (NCA9539_REG_POLARITY_BASE + 0x0)
27 #define NCA9539_REG_POLARITY_PORT1 (NCA9539_REG_POLARITY_BASE + 0x1)
28 #define NCA9539_REG_CONFIG_BASE 0x06
29 #define NCA9539_REG_CONFIG_PORT0 (NCA9539_REG_CONFIG_BASE + 0x0)
30 #define NCA9539_REG_CONFIG_PORT1 (NCA9539_REG_CONFIG_BASE + 0x1)
31
32 #define NCA9539_BANK_SZ 8
33 #define NCA9539_MAX_BANK 2
34
35 #define NCA9539_CHIP_ADDR 0x74
36
37 #ifndef BIT
38 #define BIT(nr) (1UL << (nr))
39 #endif
40
41 struct nca9539_info {
42 struct udevice *dev;
43 int addr;
44 unsigned int ngpio;
45 };
46
nca9539_write_reg(struct udevice * dev,int reg,u8 val)47 static int nca9539_write_reg(struct udevice *dev, int reg, u8 val)
48 {
49 int ret = 0;
50
51 ret = dm_i2c_write(dev, reg, &val, 1);
52 if (ret) {
53 dev_err(dev, "%s error\n", __func__);
54 return ret;
55 }
56
57 return 0;
58 }
59
nca9539_read_reg(struct udevice * dev,int reg,u8 * val)60 static int nca9539_read_reg(struct udevice *dev, int reg, u8 *val)
61 {
62 int ret;
63 u8 byte;
64
65 ret = dm_i2c_read(dev, reg, &byte, 1);
66 if (ret) {
67 dev_err(dev, "%s error\n", __func__);
68 return ret;
69 }
70
71 *val = byte;
72
73 return 0;
74 }
75
nca9539_gpio_get_direction(struct udevice * dev,unsigned int offset)76 static int nca9539_gpio_get_direction(struct udevice *dev, unsigned int offset)
77 {
78 unsigned int port = offset / NCA9539_BANK_SZ;
79 unsigned int pin = offset % NCA9539_BANK_SZ;
80 u8 value;
81 int ret;
82
83 dev_dbg(dev, "%s offset(%d)\n", __func__, offset);
84 ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
85 if (ret < 0) {
86 dev_err(dev, "%s offset(%d) read config failed\n", __func__,
87 offset);
88 return ret;
89 }
90
91 if (value & BIT(pin))
92 return GPIOF_INPUT;
93
94 return GPIOF_OUTPUT;
95 }
96
nca9539_gpio_direction_input(struct udevice * dev,unsigned int offset)97 static int nca9539_gpio_direction_input(struct udevice *dev,
98 unsigned int offset)
99 {
100 unsigned int port = offset / NCA9539_BANK_SZ;
101 unsigned int pin = offset % NCA9539_BANK_SZ;
102 u8 val;
103 int ret = 0;
104
105 dev_dbg(dev, "%s offset(%d)\n", __func__, offset);
106
107 ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &val);
108 if (!ret) {
109 val &= ~BIT(pin);
110 val |= BIT(pin);
111 ret = nca9539_write_reg(dev, NCA9539_REG_CONFIG_BASE + port,
112 val);
113 }
114
115 if (ret < 0) {
116 dev_err(dev, "%s offset(%d) read config failed\n", __func__,
117 offset);
118 }
119
120 return ret;
121 }
122
nca9539_gpio_direction_output(struct udevice * dev,unsigned int offset,int val)123 static int nca9539_gpio_direction_output(struct udevice *dev,
124 unsigned int offset, int val)
125 {
126 unsigned int port = offset / NCA9539_BANK_SZ;
127 unsigned int pin = offset % NCA9539_BANK_SZ;
128 u8 value;
129 int ret;
130
131 dev_dbg(dev, "%s offset(%d) val(%d)\n", __func__, offset, val);
132
133 ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
134 if (!ret) {
135 value &= ~BIT(pin);
136 ret = nca9539_write_reg(dev, NCA9539_REG_CONFIG_BASE + port,
137 value);
138 }
139 if (ret < 0) {
140 dev_warn(dev, "%s offset(%d) read config failed\n", __func__,
141 offset);
142 }
143
144 ret = nca9539_read_reg(dev, NCA9539_REG_OUTPUT_PORT_BASE + port,
145 &value);
146 if (!ret) {
147 value &= ~BIT(pin);
148 value |= val ? BIT(pin) : 0;
149 ret = nca9539_write_reg(
150 dev, NCA9539_REG_OUTPUT_PORT_BASE + port, value);
151 }
152 if (ret < 0) {
153 dev_err(dev, "%s offset(%d) val(%d) update output failed\n",
154 __func__, offset, val);
155 }
156
157 return ret;
158 }
159
nca9539_gpio_get(struct udevice * dev,unsigned int offset)160 static int nca9539_gpio_get(struct udevice *dev, unsigned int offset)
161 {
162 unsigned int port = offset / NCA9539_BANK_SZ;
163 unsigned int pin = offset % NCA9539_BANK_SZ;
164 int reg;
165 u8 value;
166 int ret;
167
168 dev_dbg(dev, "%s offset(%d)\n", __func__, offset);
169 ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
170 if (ret < 0) {
171 dev_err(dev, "%s offset(%d) check config failed\n", __func__,
172 offset);
173 return ret;
174 }
175 if (!(BIT(pin) & value))
176 reg = NCA9539_REG_OUTPUT_PORT_BASE + port;
177 else
178 reg = NCA9539_REG_INPUT_PORT_BASE + port;
179 ret = nca9539_read_reg(dev, reg, &value);
180 if (ret < 0) {
181 dev_err(dev, "%s offset(%d) read value failed\n", __func__,
182 offset);
183 return -EIO;
184 }
185
186 return !!(BIT(pin) & value);
187 }
188
nca9539_gpio_set(struct udevice * dev,unsigned int offset,int val)189 static int nca9539_gpio_set(struct udevice *dev, unsigned int offset, int val)
190 {
191 unsigned int port = offset / NCA9539_BANK_SZ;
192 unsigned int pin = offset % NCA9539_BANK_SZ;
193 u8 value;
194 int ret;
195
196 dev_dbg(dev, "%s offset(%d) val(%d)\n", __func__, offset, val);
197 ret = nca9539_read_reg(dev, NCA9539_REG_CONFIG_BASE + port, &value);
198 if (ret < 0 || !!(BIT(pin) & value)) {
199 dev_warn(dev, "%s offset(%d) val(%d) check config failed\n",
200 __func__, offset, val);
201 }
202
203 ret = nca9539_read_reg(dev, NCA9539_REG_OUTPUT_PORT_BASE + port,
204 &value);
205 if (!ret) {
206 value &= ~BIT(pin);
207 value |= val ? BIT(pin) : 0;
208 ret = nca9539_write_reg(
209 dev, NCA9539_REG_OUTPUT_PORT_BASE + port, value);
210 }
211 if (ret < 0) {
212 dev_err(dev, "%s offset(%d) val(%d) read input failed\n",
213 __func__, offset, val);
214 }
215
216 return ret;
217 }
218
nca9539_get_function(struct udevice * dev,unsigned offset)219 static int nca9539_get_function(struct udevice *dev, unsigned offset)
220 {
221 return nca9539_gpio_get_direction(dev, offset);
222 }
223
nca9539_xlate(struct udevice * dev,struct gpio_desc * desc,struct ofnode_phandle_args * args)224 static int nca9539_xlate(struct udevice *dev, struct gpio_desc *desc,
225 struct ofnode_phandle_args *args)
226 {
227 desc->offset = args->args[0];
228 desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
229
230 return 0;
231 }
232
233 static const struct dm_gpio_ops nca9539_ops = {
234 .direction_input = nca9539_gpio_direction_input,
235 .direction_output = nca9539_gpio_direction_output,
236 .get_value = nca9539_gpio_get,
237 .set_value = nca9539_gpio_set,
238 .get_function = nca9539_get_function,
239 .xlate = nca9539_xlate,
240 };
241
nca9539_probe(struct udevice * dev)242 static int nca9539_probe(struct udevice *dev)
243 {
244 struct nca9539_info *info = dev_get_platdata(dev);
245 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
246 struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
247 char name[32], *str;
248 ulong driver_data;
249
250 if (!info) {
251 dev_err(dev, "platdata not ready\n");
252 return -ENOMEM;
253 }
254
255 if (!chip) {
256 dev_err(dev, "i2c not ready\n");
257 return -ENODEV;
258 }
259
260 #if CONFIG_IS_ENABLED(OF_CONTROL)
261 info->addr = chip->chip_addr;
262 #else
263 info->addr = NCA9539_CHIP_ADDR;
264 #endif
265
266 driver_data = dev_get_driver_data(dev);
267 info->ngpio = driver_data;
268 if (info->ngpio > NCA9539_MAX_BANK * NCA9539_BANK_SZ) {
269 dev_err(dev, "Max support %d pins now\n",
270 NCA9539_MAX_BANK * NCA9539_BANK_SZ);
271 return -EINVAL;
272 }
273
274 snprintf(name, sizeof(name), "gpio@%x_", info->addr);
275 str = strdup(name);
276 if (!str)
277 return -ENOMEM;
278 uc_priv->bank_name = str;
279 uc_priv->gpio_count = info->ngpio;
280
281 dev_dbg(dev, "%s is ready\n", str);
282
283 return 0;
284 }
285
286 static const struct udevice_id nca9539_ids[] = {
287 {
288 .compatible = "novo,nca9539-gpio",
289 .data = (ulong)16,
290 },
291 { /* sentinel */ },
292 };
293
294 U_BOOT_DRIVER(nca9539) = {
295 .name = "nca9539",
296 .id = UCLASS_GPIO,
297 .ops = &nca9539_ops,
298 .probe = nca9539_probe,
299 .platdata_auto_alloc_size = sizeof(struct nca9539_info),
300 .of_match = nca9539_ids,
301 };
302