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