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