xref: /OK3568_Linux_fs/u-boot/drivers/gpio/tca642x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2013 Texas Instruments, Inc.
3*4882a593Smuzhiyun  * Author: Dan Murphy <dmurphy@ti.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Derived work from the pca953x.c driver
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
8*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License as
9*4882a593Smuzhiyun  * published by the Free Software Foundation; either version 2 of
10*4882a593Smuzhiyun  * the License, or (at your option) any later version.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
13*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*4882a593Smuzhiyun  * GNU General Public License for more details.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License
18*4882a593Smuzhiyun  * along with this program; if not, write to the Free Software
19*4882a593Smuzhiyun  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20*4882a593Smuzhiyun  * MA 02111-1307 USA
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include <common.h>
24*4882a593Smuzhiyun #include <i2c.h>
25*4882a593Smuzhiyun #include <tca642x.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* tca642x register address definitions */
28*4882a593Smuzhiyun struct tca642x_bank_info tca642x_regs[] = {
29*4882a593Smuzhiyun 	{ .input_reg = 0x00,
30*4882a593Smuzhiyun 	  .output_reg = 0x04,
31*4882a593Smuzhiyun 	  .polarity_reg = 0x08,
32*4882a593Smuzhiyun 	  .configuration_reg = 0x0c },
33*4882a593Smuzhiyun 	{ .input_reg = 0x01,
34*4882a593Smuzhiyun 	  .output_reg = 0x05,
35*4882a593Smuzhiyun 	  .polarity_reg = 0x09,
36*4882a593Smuzhiyun 	  .configuration_reg = 0x0d },
37*4882a593Smuzhiyun 	{ .input_reg = 0x02,
38*4882a593Smuzhiyun 	  .output_reg = 0x06,
39*4882a593Smuzhiyun 	  .polarity_reg = 0x0a,
40*4882a593Smuzhiyun 	  .configuration_reg = 0x0e },
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun  * Modify masked bits in register
45*4882a593Smuzhiyun  */
tca642x_reg_write(uchar chip,uint8_t addr,uint8_t reg_bit,uint8_t data)46*4882a593Smuzhiyun static int tca642x_reg_write(uchar chip, uint8_t addr,
47*4882a593Smuzhiyun 		uint8_t reg_bit, uint8_t data)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	uint8_t valw;
50*4882a593Smuzhiyun 	int org_bus_num;
51*4882a593Smuzhiyun 	int ret;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	org_bus_num = i2c_get_bus_num();
54*4882a593Smuzhiyun 	i2c_set_bus_num(CONFIG_SYS_I2C_TCA642X_BUS_NUM);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	if (i2c_read(chip, addr, 1, (uint8_t *)&valw, 1)) {
57*4882a593Smuzhiyun 		printf("Could not read before writing\n");
58*4882a593Smuzhiyun 		ret = -1;
59*4882a593Smuzhiyun 		goto error;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 	valw &= ~reg_bit;
62*4882a593Smuzhiyun 	valw |= data;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	ret = i2c_write(chip, addr, 1, (u8 *)&valw, 1);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun error:
67*4882a593Smuzhiyun 	i2c_set_bus_num(org_bus_num);
68*4882a593Smuzhiyun 	return ret;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
tca642x_reg_read(uchar chip,uint8_t addr,uint8_t * data)71*4882a593Smuzhiyun static int tca642x_reg_read(uchar chip, uint8_t addr, uint8_t *data)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	uint8_t valw;
74*4882a593Smuzhiyun 	int org_bus_num;
75*4882a593Smuzhiyun 	int ret = 0;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	org_bus_num = i2c_get_bus_num();
78*4882a593Smuzhiyun 	i2c_set_bus_num(CONFIG_SYS_I2C_TCA642X_BUS_NUM);
79*4882a593Smuzhiyun 	if (i2c_read(chip, addr, 1, (u8 *)&valw, 1)) {
80*4882a593Smuzhiyun 		ret = -1;
81*4882a593Smuzhiyun 		goto error;
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	*data = valw;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun error:
87*4882a593Smuzhiyun 	i2c_set_bus_num(org_bus_num);
88*4882a593Smuzhiyun 	return ret;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /*
92*4882a593Smuzhiyun  * Set output value of IO pins in 'reg_bit' to corresponding value in 'data'
93*4882a593Smuzhiyun  * 0 = low, 1 = high
94*4882a593Smuzhiyun  */
tca642x_set_val(uchar chip,uint8_t gpio_bank,uint8_t reg_bit,uint8_t data)95*4882a593Smuzhiyun int tca642x_set_val(uchar chip, uint8_t gpio_bank,
96*4882a593Smuzhiyun 					uint8_t reg_bit, uint8_t data)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	uint8_t out_reg = tca642x_regs[gpio_bank].output_reg;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return tca642x_reg_write(chip, out_reg, reg_bit, data);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * Set read polarity of IO pins in 'reg_bit' to corresponding value in 'data'
105*4882a593Smuzhiyun  * 0 = read pin value, 1 = read inverted pin value
106*4882a593Smuzhiyun  */
tca642x_set_pol(uchar chip,uint8_t gpio_bank,uint8_t reg_bit,uint8_t data)107*4882a593Smuzhiyun int tca642x_set_pol(uchar chip, uint8_t gpio_bank,
108*4882a593Smuzhiyun 					uint8_t reg_bit, uint8_t data)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	uint8_t pol_reg = tca642x_regs[gpio_bank].polarity_reg;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	return tca642x_reg_write(chip, pol_reg, reg_bit, data);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /*
116*4882a593Smuzhiyun  * Set direction of IO pins in 'reg_bit' to corresponding value in 'data'
117*4882a593Smuzhiyun  * 0 = output, 1 = input
118*4882a593Smuzhiyun  */
tca642x_set_dir(uchar chip,uint8_t gpio_bank,uint8_t reg_bit,uint8_t data)119*4882a593Smuzhiyun int tca642x_set_dir(uchar chip, uint8_t gpio_bank,
120*4882a593Smuzhiyun 					uint8_t reg_bit, uint8_t data)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	uint8_t config_reg = tca642x_regs[gpio_bank].configuration_reg;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return tca642x_reg_write(chip, config_reg, reg_bit, data);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun  * Read current logic level of all IO pins
129*4882a593Smuzhiyun  */
tca642x_get_val(uchar chip,uint8_t gpio_bank)130*4882a593Smuzhiyun int tca642x_get_val(uchar chip, uint8_t gpio_bank)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	uint8_t val;
133*4882a593Smuzhiyun 	uint8_t in_reg = tca642x_regs[gpio_bank].input_reg;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (tca642x_reg_read(chip, in_reg, &val) < 0)
136*4882a593Smuzhiyun 		return -1;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	return (int)val;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /*
142*4882a593Smuzhiyun  * Set the inital register states for the tca642x gpio expander
143*4882a593Smuzhiyun  */
tca642x_set_inital_state(uchar chip,struct tca642x_bank_info init_data[])144*4882a593Smuzhiyun int tca642x_set_inital_state(uchar chip, struct tca642x_bank_info init_data[])
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	int i, ret;
147*4882a593Smuzhiyun 	uint8_t config_reg;
148*4882a593Smuzhiyun 	uint8_t polarity_reg;
149*4882a593Smuzhiyun 	uint8_t output_reg;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
152*4882a593Smuzhiyun 		config_reg = tca642x_regs[i].configuration_reg;
153*4882a593Smuzhiyun 		ret = tca642x_reg_write(chip, config_reg, 0xff,
154*4882a593Smuzhiyun 				init_data[i].configuration_reg);
155*4882a593Smuzhiyun 		polarity_reg = tca642x_regs[i].polarity_reg;
156*4882a593Smuzhiyun 		ret = tca642x_reg_write(chip, polarity_reg, 0xff,
157*4882a593Smuzhiyun 				init_data[i].polarity_reg);
158*4882a593Smuzhiyun 		output_reg = tca642x_regs[i].output_reg;
159*4882a593Smuzhiyun 		ret = tca642x_reg_write(chip, output_reg, 0xff,
160*4882a593Smuzhiyun 				init_data[i].output_reg);
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return ret;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun #ifdef CONFIG_CMD_TCA642X
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun  * Display tca642x information
169*4882a593Smuzhiyun  */
tca642x_info(uchar chip)170*4882a593Smuzhiyun static int tca642x_info(uchar chip)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	int i, j;
173*4882a593Smuzhiyun 	uint8_t data;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	printf("tca642x@ 0x%x (%d pins):\n", chip, 24);
176*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
177*4882a593Smuzhiyun 		printf("Bank %i\n", i);
178*4882a593Smuzhiyun 		if (tca642x_reg_read(chip,
179*4882a593Smuzhiyun 				     tca642x_regs[i].configuration_reg,
180*4882a593Smuzhiyun 				     &data) < 0)
181*4882a593Smuzhiyun 			return -1;
182*4882a593Smuzhiyun 		printf("\tConfiguration: ");
183*4882a593Smuzhiyun 		for (j = 7; j >= 0; j--)
184*4882a593Smuzhiyun 			printf("%c", data & (1 << j) ? 'i' : 'o');
185*4882a593Smuzhiyun 		printf("\n");
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 		if (tca642x_reg_read(chip,
188*4882a593Smuzhiyun 				     tca642x_regs[i].polarity_reg, &data) < 0)
189*4882a593Smuzhiyun 			return -1;
190*4882a593Smuzhiyun 		printf("\tPolarity: ");
191*4882a593Smuzhiyun 		for (j = 7; j >= 0; j--)
192*4882a593Smuzhiyun 			printf("%c", data & (1 << j) ? '1' : '0');
193*4882a593Smuzhiyun 		printf("\n");
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		if (tca642x_reg_read(chip,
196*4882a593Smuzhiyun 				     tca642x_regs[i].input_reg, &data) < 0)
197*4882a593Smuzhiyun 			return -1;
198*4882a593Smuzhiyun 		printf("\tInput value: ");
199*4882a593Smuzhiyun 		for (j = 7; j >= 0; j--)
200*4882a593Smuzhiyun 			printf("%c", data & (1 << j) ? '1' : '0');
201*4882a593Smuzhiyun 		printf("\n");
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 		if (tca642x_reg_read(chip,
204*4882a593Smuzhiyun 				     tca642x_regs[i].output_reg, &data) < 0)
205*4882a593Smuzhiyun 			return -1;
206*4882a593Smuzhiyun 		printf("\tOutput value: ");
207*4882a593Smuzhiyun 		for (j = 7; j >= 0; j--)
208*4882a593Smuzhiyun 			printf("%c", data & (1 << j) ? '1' : '0');
209*4882a593Smuzhiyun 		printf("\n");
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun cmd_tbl_t cmd_tca642x[] = {
216*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(device, 3, 0, (void *)TCA642X_CMD_DEVICE, "", ""),
217*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(output, 4, 0, (void *)TCA642X_CMD_OUTPUT, "", ""),
218*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(input, 3, 0, (void *)TCA642X_CMD_INPUT, "", ""),
219*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(invert, 4, 0, (void *)TCA642X_CMD_INVERT, "", ""),
220*4882a593Smuzhiyun 	U_BOOT_CMD_MKENT(info, 2, 0, (void *)TCA642X_CMD_INFO, "", ""),
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
do_tca642x(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])223*4882a593Smuzhiyun int do_tca642x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	static uchar chip = CONFIG_SYS_I2C_TCA642X_ADDR;
226*4882a593Smuzhiyun 	int ret = CMD_RET_USAGE, val;
227*4882a593Smuzhiyun 	uint8_t gpio_bank = 0;
228*4882a593Smuzhiyun 	uint8_t bank_shift;
229*4882a593Smuzhiyun 	ulong ul_arg2 = 0;
230*4882a593Smuzhiyun 	ulong ul_arg3 = 0;
231*4882a593Smuzhiyun 	cmd_tbl_t *c;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	c = find_cmd_tbl(argv[1], cmd_tca642x, ARRAY_SIZE(cmd_tca642x));
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/* All commands but "device" require 'maxargs' arguments */
236*4882a593Smuzhiyun 	if (!c ||
237*4882a593Smuzhiyun 	    !((argc == (c->maxargs)) ||
238*4882a593Smuzhiyun 	    (((int)c->cmd == TCA642X_CMD_DEVICE) &&
239*4882a593Smuzhiyun 	    (argc == (c->maxargs - 1))))) {
240*4882a593Smuzhiyun 		return CMD_RET_USAGE;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/* arg2 used as chip number or pin number */
244*4882a593Smuzhiyun 	if (argc > 2)
245*4882a593Smuzhiyun 		ul_arg2 = simple_strtoul(argv[2], NULL, 10);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* arg3 used as pin or invert value */
248*4882a593Smuzhiyun 	if (argc > 3) {
249*4882a593Smuzhiyun 		ul_arg3 = simple_strtoul(argv[3], NULL, 10) & 0x1;
250*4882a593Smuzhiyun 		if (ul_arg2 <= 7) {
251*4882a593Smuzhiyun 			gpio_bank = 0;
252*4882a593Smuzhiyun 		} else if ((ul_arg2 >= 10) && (ul_arg2 <= 17)) {
253*4882a593Smuzhiyun 			gpio_bank = 1;
254*4882a593Smuzhiyun 		} else if ((ul_arg2 >= 20) && (ul_arg2 <= 27)) {
255*4882a593Smuzhiyun 			gpio_bank = 2;
256*4882a593Smuzhiyun 		} else {
257*4882a593Smuzhiyun 			printf("Requested pin is not available\n");
258*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
259*4882a593Smuzhiyun 			goto error;
260*4882a593Smuzhiyun 		}
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	switch ((int)c->cmd) {
264*4882a593Smuzhiyun 	case TCA642X_CMD_INFO:
265*4882a593Smuzhiyun 		ret = tca642x_info(chip);
266*4882a593Smuzhiyun 		if (ret)
267*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	case TCA642X_CMD_DEVICE:
271*4882a593Smuzhiyun 		if (argc == 3)
272*4882a593Smuzhiyun 			chip = (uint8_t)ul_arg2;
273*4882a593Smuzhiyun 		printf("Current device address: 0x%x\n", chip);
274*4882a593Smuzhiyun 		ret = CMD_RET_SUCCESS;
275*4882a593Smuzhiyun 		break;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	case TCA642X_CMD_INPUT:
278*4882a593Smuzhiyun 		bank_shift = ul_arg2 - (gpio_bank * 10);
279*4882a593Smuzhiyun 		ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift),
280*4882a593Smuzhiyun 				TCA642X_DIR_IN << bank_shift);
281*4882a593Smuzhiyun 		val = (tca642x_get_val(chip, gpio_bank) &
282*4882a593Smuzhiyun 				(1 << bank_shift)) != 0;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		if (ret)
285*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
286*4882a593Smuzhiyun 		else
287*4882a593Smuzhiyun 			printf("chip 0x%02x, pin 0x%lx = %d\n", chip,
288*4882a593Smuzhiyun 			       ul_arg2, val);
289*4882a593Smuzhiyun 		break;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	case TCA642X_CMD_OUTPUT:
292*4882a593Smuzhiyun 		bank_shift = ul_arg2 - (gpio_bank * 10);
293*4882a593Smuzhiyun 		ret = tca642x_set_dir(chip, gpio_bank, (1 << bank_shift),
294*4882a593Smuzhiyun 				(TCA642X_DIR_OUT << bank_shift));
295*4882a593Smuzhiyun 		if (!ret)
296*4882a593Smuzhiyun 			ret = tca642x_set_val(chip,
297*4882a593Smuzhiyun 					      gpio_bank, (1 << bank_shift),
298*4882a593Smuzhiyun 					      (ul_arg3 << bank_shift));
299*4882a593Smuzhiyun 		if (ret)
300*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
301*4882a593Smuzhiyun 		break;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	case TCA642X_CMD_INVERT:
304*4882a593Smuzhiyun 		bank_shift = ul_arg2 - (gpio_bank * 10);
305*4882a593Smuzhiyun 		ret = tca642x_set_pol(chip, gpio_bank, (1 << bank_shift),
306*4882a593Smuzhiyun 					(ul_arg3 << bank_shift));
307*4882a593Smuzhiyun 		if (ret)
308*4882a593Smuzhiyun 			ret = CMD_RET_FAILURE;
309*4882a593Smuzhiyun 		break;
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun error:
312*4882a593Smuzhiyun 	if (ret == CMD_RET_FAILURE)
313*4882a593Smuzhiyun 		eprintf("Error talking to chip at 0x%x\n", chip);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return ret;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun U_BOOT_CMD(
319*4882a593Smuzhiyun 	tca642x,	5,	1,	do_tca642x,
320*4882a593Smuzhiyun 	"tca642x gpio access",
321*4882a593Smuzhiyun 	"device [dev]\n"
322*4882a593Smuzhiyun 	"	- show or set current device address\n"
323*4882a593Smuzhiyun 	"tca642x info\n"
324*4882a593Smuzhiyun 	"	- display info for current chip\n"
325*4882a593Smuzhiyun 	"tca642x output pin 0|1\n"
326*4882a593Smuzhiyun 	"	- set pin as output and drive low or high\n"
327*4882a593Smuzhiyun 	"tca642x invert pin 0|1\n"
328*4882a593Smuzhiyun 	"	- disable/enable polarity inversion for reads\n"
329*4882a593Smuzhiyun 	"tca642x input pin\n"
330*4882a593Smuzhiyun 	"	- set pin as input and read value"
331*4882a593Smuzhiyun );
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun #endif /* CONFIG_CMD_TCA642X */
334