xref: /rk3399_rockchip-uboot/drivers/gpio/nca9539_gpio.c (revision 05c43c8510a7f6dfc7941939dc244f929da9b8ca)
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