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