xref: /OK3568_Linux_fs/u-boot/drivers/gpio/pca953x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2008 Extreme Engineering Solutions, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /*
8*4882a593Smuzhiyun  * Driver for NXP's 4, 8 and 16 bit I2C gpio expanders (eg pca9537, pca9557,
9*4882a593Smuzhiyun  * pca9539, etc)
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <i2c.h>
14*4882a593Smuzhiyun #include <pca953x.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* Default to an address that hopefully won't corrupt other i2c devices */
17*4882a593Smuzhiyun #ifndef CONFIG_SYS_I2C_PCA953X_ADDR
18*4882a593Smuzhiyun #define CONFIG_SYS_I2C_PCA953X_ADDR	(~0)
19*4882a593Smuzhiyun #endif
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun enum {
22*4882a593Smuzhiyun 	PCA953X_CMD_INFO,
23*4882a593Smuzhiyun 	PCA953X_CMD_DEVICE,
24*4882a593Smuzhiyun 	PCA953X_CMD_OUTPUT,
25*4882a593Smuzhiyun 	PCA953X_CMD_INPUT,
26*4882a593Smuzhiyun 	PCA953X_CMD_INVERT,
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #ifdef CONFIG_SYS_I2C_PCA953X_WIDTH
30*4882a593Smuzhiyun struct pca953x_chip_ngpio {
31*4882a593Smuzhiyun 	uint8_t chip;
32*4882a593Smuzhiyun 	uint8_t ngpio;
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static struct pca953x_chip_ngpio pca953x_chip_ngpios[] =
36*4882a593Smuzhiyun     CONFIG_SYS_I2C_PCA953X_WIDTH;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun  * Determine the number of GPIO pins supported. If we don't know we assume
40*4882a593Smuzhiyun  * 8 pins.
41*4882a593Smuzhiyun  */
pca953x_ngpio(uint8_t chip)42*4882a593Smuzhiyun static int pca953x_ngpio(uint8_t chip)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	int i;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(pca953x_chip_ngpios); i++)
47*4882a593Smuzhiyun 		if (pca953x_chip_ngpios[i].chip == chip)
48*4882a593Smuzhiyun 			return pca953x_chip_ngpios[i].ngpio;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	return 8;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun #else
pca953x_ngpio(uint8_t chip)53*4882a593Smuzhiyun static int pca953x_ngpio(uint8_t chip)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	return 8;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun  * Modify masked bits in register
61*4882a593Smuzhiyun  */
pca953x_reg_write(uint8_t chip,uint addr,uint mask,uint data)62*4882a593Smuzhiyun static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	uint8_t valb;
65*4882a593Smuzhiyun 	uint16_t valw;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (pca953x_ngpio(chip) <= 8) {
68*4882a593Smuzhiyun 		if (i2c_read(chip, addr, 1, &valb, 1))
69*4882a593Smuzhiyun 			return -1;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		valb &= ~mask;
72*4882a593Smuzhiyun 		valb |= data;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 		return i2c_write(chip, addr, 1, &valb, 1);
75*4882a593Smuzhiyun 	} else {
76*4882a593Smuzhiyun 		if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
77*4882a593Smuzhiyun 			return -1;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		valw = le16_to_cpu(valw);
80*4882a593Smuzhiyun 		valw &= ~mask;
81*4882a593Smuzhiyun 		valw |= data;
82*4882a593Smuzhiyun 		valw = cpu_to_le16(valw);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 		return i2c_write(chip, addr << 1, 1, (u8*)&valw, 2);
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
pca953x_reg_read(uint8_t chip,uint addr,uint * data)88*4882a593Smuzhiyun static int pca953x_reg_read(uint8_t chip, uint addr, uint *data)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	uint8_t valb;
91*4882a593Smuzhiyun 	uint16_t valw;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (pca953x_ngpio(chip) <= 8) {
94*4882a593Smuzhiyun 		if (i2c_read(chip, addr, 1, &valb, 1))
95*4882a593Smuzhiyun 			return -1;
96*4882a593Smuzhiyun 		*data = (int)valb;
97*4882a593Smuzhiyun 	} else {
98*4882a593Smuzhiyun 		if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2))
99*4882a593Smuzhiyun 			return -1;
100*4882a593Smuzhiyun 		*data = (uint)le16_to_cpu(valw);
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 	return 0;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /*
106*4882a593Smuzhiyun  * Set output value of IO pins in 'mask' to corresponding value in 'data'
107*4882a593Smuzhiyun  * 0 = low, 1 = high
108*4882a593Smuzhiyun  */
pca953x_set_val(uint8_t chip,uint mask,uint data)109*4882a593Smuzhiyun int pca953x_set_val(uint8_t chip, uint mask, uint data)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	return pca953x_reg_write(chip, PCA953X_OUT, mask, data);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun /*
115*4882a593Smuzhiyun  * Set read polarity of IO pins in 'mask' to corresponding value in 'data'
116*4882a593Smuzhiyun  * 0 = read pin value, 1 = read inverted pin value
117*4882a593Smuzhiyun  */
pca953x_set_pol(uint8_t chip,uint mask,uint data)118*4882a593Smuzhiyun int pca953x_set_pol(uint8_t chip, uint mask, uint data)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	return pca953x_reg_write(chip, PCA953X_POL, mask, data);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun /*
124*4882a593Smuzhiyun  * Set direction of IO pins in 'mask' to corresponding value in 'data'
125*4882a593Smuzhiyun  * 0 = output, 1 = input
126*4882a593Smuzhiyun  */
pca953x_set_dir(uint8_t chip,uint mask,uint data)127*4882a593Smuzhiyun int pca953x_set_dir(uint8_t chip, uint mask, uint data)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	return pca953x_reg_write(chip, PCA953X_CONF, mask, data);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun  * Read current logic level of all IO pins
134*4882a593Smuzhiyun  */
pca953x_get_val(uint8_t chip)135*4882a593Smuzhiyun int pca953x_get_val(uint8_t chip)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	uint val;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (pca953x_reg_read(chip, PCA953X_IN, &val) < 0)
140*4882a593Smuzhiyun 		return -1;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	return (int)val;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun #ifdef CONFIG_CMD_PCA953X
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun  * Display pca953x information
148*4882a593Smuzhiyun  */
pca953x_info(uint8_t chip)149*4882a593Smuzhiyun static int pca953x_info(uint8_t chip)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	int i;
152*4882a593Smuzhiyun 	uint data;
153*4882a593Smuzhiyun 	int nr_gpio = pca953x_ngpio(chip);
154*4882a593Smuzhiyun 	int msb = nr_gpio - 1;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	printf("pca953x@ 0x%x (%d pins):\n\n", chip, nr_gpio);
157*4882a593Smuzhiyun 	printf("gpio pins: ");
158*4882a593Smuzhiyun 	for (i = msb; i >= 0; i--)
159*4882a593Smuzhiyun 		printf("%x", i);
160*4882a593Smuzhiyun 	printf("\n");
161*4882a593Smuzhiyun 	for (i = 11 + nr_gpio; i > 0; i--)
162*4882a593Smuzhiyun 		printf("-");
163*4882a593Smuzhiyun 	printf("\n");
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (pca953x_reg_read(chip, PCA953X_CONF, &data) < 0)
166*4882a593Smuzhiyun 		return -1;
167*4882a593Smuzhiyun 	printf("conf:      ");
168*4882a593Smuzhiyun 	for (i = msb; i >= 0; i--)
169*4882a593Smuzhiyun 		printf("%c", data & (1 << i) ? 'i' : 'o');
170*4882a593Smuzhiyun 	printf("\n");
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (pca953x_reg_read(chip, PCA953X_POL, &data) < 0)
173*4882a593Smuzhiyun 		return -1;
174*4882a593Smuzhiyun 	printf("invert:    ");
175*4882a593Smuzhiyun 	for (i = msb; i >= 0; i--)
176*4882a593Smuzhiyun 		printf("%c", data & (1 << i) ? '1' : '0');
177*4882a593Smuzhiyun 	printf("\n");
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	if (pca953x_reg_read(chip, PCA953X_IN, &data) < 0)
180*4882a593Smuzhiyun 		return -1;
181*4882a593Smuzhiyun 	printf("input:     ");
182*4882a593Smuzhiyun 	for (i = msb; i >= 0; i--)
183*4882a593Smuzhiyun 		printf("%c", data & (1 << i) ? '1' : '0');
184*4882a593Smuzhiyun 	printf("\n");
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	if (pca953x_reg_read(chip, PCA953X_OUT, &data) < 0)
187*4882a593Smuzhiyun 		return -1;
188*4882a593Smuzhiyun 	printf("output:    ");
189*4882a593Smuzhiyun 	for (i = msb; i >= 0; i--)
190*4882a593Smuzhiyun 		printf("%c", data & (1 << i) ? '1' : '0');
191*4882a593Smuzhiyun 	printf("\n");
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun cmd_tbl_t cmd_pca953x[] = {
197*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""),
198*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""),
199*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""),
200*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""),
201*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""),
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun 
do_pca953x(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])204*4882a593Smuzhiyun int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR;
207*4882a593Smuzhiyun 	int ret = CMD_RET_USAGE, val;
208*4882a593Smuzhiyun 	ulong ul_arg2 = 0;
209*4882a593Smuzhiyun 	ulong ul_arg3 = 0;
210*4882a593Smuzhiyun 	cmd_tbl_t *c;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x));
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	/* All commands but "device" require 'maxargs' arguments */
215*4882a593Smuzhiyun 	if (!c || !((argc == (c->maxargs)) ||
216*4882a593Smuzhiyun 		(((long)c->cmd == PCA953X_CMD_DEVICE) &&
217*4882a593Smuzhiyun 		 (argc == (c->maxargs - 1))))) {
218*4882a593Smuzhiyun 		return CMD_RET_USAGE;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	/* arg2 used as chip number or pin number */
222*4882a593Smuzhiyun 	if (argc > 2)
223*4882a593Smuzhiyun 		ul_arg2 = simple_strtoul(argv[2], NULL, 16);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* arg3 used as pin or invert value */
226*4882a593Smuzhiyun 	if (argc > 3)
227*4882a593Smuzhiyun 		ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	switch ((long)c->cmd) {
230*4882a593Smuzhiyun 	case PCA953X_CMD_INFO:
231*4882a593Smuzhiyun 		ret = pca953x_info(chip);
232*4882a593Smuzhiyun 		if (ret)
233*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
234*4882a593Smuzhiyun 		break;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	case PCA953X_CMD_DEVICE:
237*4882a593Smuzhiyun 		if (argc == 3)
238*4882a593Smuzhiyun 			chip = (uint8_t)ul_arg2;
239*4882a593Smuzhiyun 		printf("Current device address: 0x%x\n", chip);
240*4882a593Smuzhiyun 		ret = CMD_RET_SUCCESS;
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	case PCA953X_CMD_INPUT:
244*4882a593Smuzhiyun 		ret = pca953x_set_dir(chip, (1 << ul_arg2),
245*4882a593Smuzhiyun 				PCA953X_DIR_IN << ul_arg2);
246*4882a593Smuzhiyun 		val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 		if (ret)
249*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
250*4882a593Smuzhiyun 		else
251*4882a593Smuzhiyun 			printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2,
252*4882a593Smuzhiyun 									val);
253*4882a593Smuzhiyun 		break;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	case PCA953X_CMD_OUTPUT:
256*4882a593Smuzhiyun 		ret = pca953x_set_dir(chip, (1 << ul_arg2),
257*4882a593Smuzhiyun 				(PCA953X_DIR_OUT << ul_arg2));
258*4882a593Smuzhiyun 		if (!ret)
259*4882a593Smuzhiyun 			ret = pca953x_set_val(chip, (1 << ul_arg2),
260*4882a593Smuzhiyun 						(ul_arg3 << ul_arg2));
261*4882a593Smuzhiyun 		if (ret)
262*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
263*4882a593Smuzhiyun 		break;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	case PCA953X_CMD_INVERT:
266*4882a593Smuzhiyun 		ret = pca953x_set_pol(chip, (1 << ul_arg2),
267*4882a593Smuzhiyun 					(ul_arg3 << ul_arg2));
268*4882a593Smuzhiyun 		if (ret)
269*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
270*4882a593Smuzhiyun 		break;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (ret == CMD_RET_FAILURE)
274*4882a593Smuzhiyun 		eprintf("Error talking to chip at 0x%x\n", chip);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return ret;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun U_BOOT_CMD(
280*4882a593Smuzhiyun 	pca953x,	5,	1,	do_pca953x,
281*4882a593Smuzhiyun 	"pca953x gpio access",
282*4882a593Smuzhiyun 	"device [dev]\n"
283*4882a593Smuzhiyun 	"	- show or set current device address\n"
284*4882a593Smuzhiyun 	"pca953x info\n"
285*4882a593Smuzhiyun 	"	- display info for current chip\n"
286*4882a593Smuzhiyun 	"pca953x output pin 0|1\n"
287*4882a593Smuzhiyun 	"	- set pin as output and drive low or high\n"
288*4882a593Smuzhiyun 	"pca953x invert pin 0|1\n"
289*4882a593Smuzhiyun 	"	- disable/enable polarity inversion for reads\n"
290*4882a593Smuzhiyun 	"pca953x input pin\n"
291*4882a593Smuzhiyun 	"	- set pin as input and read value"
292*4882a593Smuzhiyun );
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun #endif /* CONFIG_CMD_PCA953X */
295