]>
Commit | Line | Data |
---|---|---|
e92739d3 PT |
1 | /* |
2 | * Copyright 2008 Extreme Engineering Solutions, Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * Version 2 as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software | |
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
16 | * MA 02111-1307 USA | |
17 | */ | |
18 | ||
19 | /* | |
20 | * Driver for NXP's 4 and 8 bit I2C gpio expanders (eg pca9537, pca9557, etc) | |
21 | * TODO: support additional devices with more than 8-bits GPIO | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <i2c.h> | |
26 | #include <pca953x.h> | |
27 | ||
28 | /* Default to an address that hopefully won't corrupt other i2c devices */ | |
29 | #ifndef CONFIG_SYS_I2C_PCA953X_ADDR | |
30 | #define CONFIG_SYS_I2C_PCA953X_ADDR (~0) | |
31 | #endif | |
32 | ||
33 | enum { | |
34 | PCA953X_CMD_INFO, | |
35 | PCA953X_CMD_DEVICE, | |
36 | PCA953X_CMD_OUTPUT, | |
37 | PCA953X_CMD_INPUT, | |
38 | PCA953X_CMD_INVERT, | |
39 | }; | |
40 | ||
41 | /* | |
42 | * Modify masked bits in register | |
43 | */ | |
44 | static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data) | |
45 | { | |
46 | uint8_t val; | |
47 | ||
48 | if (i2c_read(chip, addr, 1, &val, 1)) | |
49 | return -1; | |
50 | ||
51 | val &= ~mask; | |
52 | val |= data; | |
53 | ||
54 | return i2c_write(chip, addr, 1, &val, 1); | |
55 | } | |
56 | ||
57 | /* | |
58 | * Set output value of IO pins in 'mask' to corresponding value in 'data' | |
59 | * 0 = low, 1 = high | |
60 | */ | |
61 | int pca953x_set_val(uint8_t chip, uint mask, uint data) | |
62 | { | |
63 | return pca953x_reg_write(chip, PCA953X_OUT, mask, data); | |
64 | } | |
65 | ||
66 | /* | |
67 | * Set read polarity of IO pins in 'mask' to corresponding value in 'data' | |
68 | * 0 = read pin value, 1 = read inverted pin value | |
69 | */ | |
70 | int pca953x_set_pol(uint8_t chip, uint mask, uint data) | |
71 | { | |
72 | return pca953x_reg_write(chip, PCA953X_POL, mask, data); | |
73 | } | |
74 | ||
75 | /* | |
76 | * Set direction of IO pins in 'mask' to corresponding value in 'data' | |
77 | * 0 = output, 1 = input | |
78 | */ | |
79 | int pca953x_set_dir(uint8_t chip, uint mask, uint data) | |
80 | { | |
81 | return pca953x_reg_write(chip, PCA953X_CONF, mask, data); | |
82 | } | |
83 | ||
84 | /* | |
85 | * Read current logic level of all IO pins | |
86 | */ | |
87 | int pca953x_get_val(uint8_t chip) | |
88 | { | |
89 | uint8_t val; | |
90 | ||
91 | if (i2c_read(chip, 0, 1, &val, 1)) | |
92 | return -1; | |
93 | ||
94 | return (int)val; | |
95 | } | |
96 | ||
97 | #ifdef CONFIG_CMD_PCA953X | |
98 | #ifdef CONFIG_CMD_PCA953X_INFO | |
99 | /* | |
100 | * Display pca953x information | |
101 | */ | |
102 | static int pca953x_info(uint8_t chip) | |
103 | { | |
104 | int i; | |
105 | uint8_t data; | |
106 | ||
107 | printf("pca953x@ 0x%x:\n\n", chip); | |
108 | printf("gpio pins: 76543210\n"); | |
109 | printf("-------------------\n"); | |
110 | ||
111 | if (i2c_read(chip, PCA953X_CONF, 1, &data, 1)) | |
112 | return -1; | |
113 | printf("conf: "); | |
114 | for (i = 7; i >= 0; i--) | |
115 | printf("%c", data & (1 << i) ? 'i' : 'o'); | |
116 | printf("\n"); | |
117 | ||
118 | if (i2c_read(chip, PCA953X_POL, 1, &data, 1)) | |
119 | return -1; | |
120 | printf("invert: "); | |
121 | for (i = 7; i >= 0; i--) | |
122 | printf("%c", data & (1 << i) ? '1' : '0'); | |
123 | printf("\n"); | |
124 | ||
125 | if (i2c_read(chip, PCA953X_IN, 1, &data, 1)) | |
126 | return -1; | |
127 | printf("input: "); | |
128 | for (i = 7; i >= 0; i--) | |
129 | printf("%c", data & (1 << i) ? '1' : '0'); | |
130 | printf("\n"); | |
131 | ||
132 | if (i2c_read(chip, PCA953X_OUT, 1, &data, 1)) | |
133 | return -1; | |
134 | printf("output: "); | |
135 | for (i = 7; i >= 0; i--) | |
136 | printf("%c", data & (1 << i) ? '1' : '0'); | |
137 | printf("\n"); | |
138 | ||
139 | return 0; | |
140 | } | |
141 | #endif /* CONFIG_CMD_PCA953X_INFO */ | |
142 | ||
143 | cmd_tbl_t cmd_pca953x[] = { | |
144 | U_BOOT_CMD_MKENT(device, 3, 0, (void *)PCA953X_CMD_DEVICE, "", ""), | |
145 | U_BOOT_CMD_MKENT(output, 4, 0, (void *)PCA953X_CMD_OUTPUT, "", ""), | |
146 | U_BOOT_CMD_MKENT(input, 3, 0, (void *)PCA953X_CMD_INPUT, "", ""), | |
147 | U_BOOT_CMD_MKENT(invert, 4, 0, (void *)PCA953X_CMD_INVERT, "", ""), | |
148 | #ifdef CONFIG_CMD_PCA953X_INFO | |
149 | U_BOOT_CMD_MKENT(info, 2, 0, (void *)PCA953X_CMD_INFO, "", ""), | |
150 | #endif | |
151 | }; | |
152 | ||
153 | int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
154 | { | |
155 | static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR; | |
156 | int val; | |
157 | ulong ul_arg2 = 0; | |
158 | ulong ul_arg3 = 0; | |
159 | cmd_tbl_t *c; | |
160 | ||
161 | c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x)); | |
162 | ||
163 | /* All commands but "device" require 'maxargs' arguments */ | |
164 | if (!c || !((argc == (c->maxargs)) || | |
165 | (((int)c->cmd == PCA953X_CMD_DEVICE) && | |
166 | (argc == (c->maxargs - 1))))) { | |
167 | printf("Usage:\n%s\n", cmdtp->usage); | |
168 | return 1; | |
169 | } | |
170 | ||
171 | /* arg2 used as chip number or pin number */ | |
172 | if (argc > 2) | |
173 | ul_arg2 = simple_strtoul(argv[2], NULL, 16); | |
174 | ||
175 | /* arg3 used as pin or invert value */ | |
176 | if (argc > 3) | |
177 | ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1; | |
178 | ||
179 | switch ((int)c->cmd) { | |
180 | #ifdef CONFIG_CMD_PCA953X_INFO | |
181 | case PCA953X_CMD_INFO: | |
182 | return pca953x_info(chip); | |
183 | #endif | |
184 | case PCA953X_CMD_DEVICE: | |
185 | if (argc == 3) | |
186 | chip = (uint8_t)ul_arg2; | |
187 | printf("Current device address: 0x%x\n", chip); | |
188 | return 0; | |
189 | case PCA953X_CMD_INPUT: | |
190 | pca953x_set_dir(chip, (1 << ul_arg2), | |
191 | PCA953X_DIR_IN << ul_arg2); | |
192 | val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0; | |
193 | ||
194 | printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, val); | |
195 | return val; | |
196 | case PCA953X_CMD_OUTPUT: | |
197 | pca953x_set_dir(chip, (1 << ul_arg2), | |
198 | (PCA953X_DIR_OUT << ul_arg2)); | |
199 | return pca953x_set_val(chip, (1 << ul_arg2), | |
200 | (ul_arg3 << ul_arg2)); | |
201 | case PCA953X_CMD_INVERT: | |
202 | return pca953x_set_pol(chip, (1 << ul_arg2), | |
203 | (ul_arg3 << ul_arg2)); | |
204 | default: | |
205 | /* We should never get here */ | |
206 | return 1; | |
207 | } | |
208 | } | |
209 | ||
210 | U_BOOT_CMD( | |
211 | pca953x, 5, 1, do_pca953x, | |
212 | "pca953x - pca953x gpio access\n", | |
213 | "device [dev]\n" | |
214 | " - show or set current device address\n" | |
215 | #ifdef CONFIG_CMD_PCA953X_INFO | |
216 | "pca953x info\n" | |
217 | " - display info for current chip\n" | |
218 | #endif | |
219 | "pca953x output pin 0|1\n" | |
220 | " - set pin as output and drive low or high\n" | |
221 | "pca953x invert pin 0|1\n" | |
222 | " - disable/enable polarity inversion for reads\n" | |
223 | "pca953x intput pin\n" | |
224 | " - set pin as input and read value\n" | |
225 | ); | |
226 | ||
227 | #endif /* CONFIG_CMD_PCA953X */ |