]>
Commit | Line | Data |
---|---|---|
a7c93104 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 DS4510, a CPU supervisor with integrated EEPROM, SRAM, | |
21 | * and 4 programmable non-volatile GPIO pins. | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <i2c.h> | |
26 | #include <command.h> | |
27 | #include <ds4510.h> | |
28 | ||
29 | /* Default to an address that hopefully won't corrupt other i2c devices */ | |
30 | #ifndef CONFIG_SYS_I2C_DS4510_ADDR | |
31 | #define CONFIG_SYS_I2C_DS4510_ADDR (~0) | |
32 | #endif | |
33 | ||
34 | enum { | |
35 | DS4510_CMD_INFO, | |
36 | DS4510_CMD_DEVICE, | |
37 | DS4510_CMD_NV, | |
38 | DS4510_CMD_RSTDELAY, | |
39 | DS4510_CMD_OUTPUT, | |
40 | DS4510_CMD_INPUT, | |
41 | DS4510_CMD_PULLUP, | |
42 | DS4510_CMD_EEPROM, | |
43 | DS4510_CMD_SEEPROM, | |
44 | DS4510_CMD_SRAM, | |
45 | }; | |
46 | ||
47 | /* | |
48 | * Write to DS4510, taking page boundaries into account | |
49 | */ | |
50 | int ds4510_mem_write(uint8_t chip, int offset, uint8_t *buf, int count) | |
51 | { | |
52 | int wrlen; | |
53 | int i = 0; | |
54 | ||
55 | do { | |
56 | wrlen = DS4510_EEPROM_PAGE_SIZE - | |
57 | DS4510_EEPROM_PAGE_OFFSET(offset); | |
58 | if (count < wrlen) | |
59 | wrlen = count; | |
60 | if (i2c_write(chip, offset, 1, &buf[i], wrlen)) | |
61 | return -1; | |
62 | ||
63 | /* | |
64 | * This delay isn't needed for SRAM writes but shouldn't delay | |
65 | * things too much, so do it unconditionally for simplicity | |
66 | */ | |
67 | udelay(DS4510_EEPROM_PAGE_WRITE_DELAY_MS * 1000); | |
68 | count -= wrlen; | |
69 | offset += wrlen; | |
70 | i += wrlen; | |
71 | } while (count > 0); | |
72 | ||
73 | return 0; | |
74 | } | |
75 | ||
76 | /* | |
77 | * General read from DS4510 | |
78 | */ | |
79 | int ds4510_mem_read(uint8_t chip, int offset, uint8_t *buf, int count) | |
80 | { | |
81 | return i2c_read(chip, offset, 1, buf, count); | |
82 | } | |
83 | ||
84 | /* | |
85 | * Write SEE bit in config register. | |
86 | * nv = 0 - Writes to SEEPROM registers behave like EEPROM | |
87 | * nv = 1 - Writes to SEEPROM registers behave like SRAM | |
88 | */ | |
89 | int ds4510_see_write(uint8_t chip, uint8_t nv) | |
90 | { | |
91 | uint8_t data; | |
92 | ||
93 | if (i2c_read(chip, DS4510_CFG, 1, &data, 1)) | |
94 | return -1; | |
95 | ||
96 | if (nv) /* Treat SEEPROM bits as EEPROM */ | |
97 | data &= ~DS4510_CFG_SEE; | |
98 | else /* Treat SEEPROM bits as SRAM */ | |
99 | data |= DS4510_CFG_SEE; | |
100 | ||
101 | return ds4510_mem_write(chip, DS4510_CFG, &data, 1); | |
102 | } | |
103 | ||
104 | /* | |
105 | * Write de-assertion of reset signal delay | |
106 | */ | |
107 | int ds4510_rstdelay_write(uint8_t chip, uint8_t delay) | |
108 | { | |
109 | uint8_t data; | |
110 | ||
111 | if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1)) | |
112 | return -1; | |
113 | ||
114 | data &= ~DS4510_RSTDELAY_MASK; | |
115 | data |= delay & DS4510_RSTDELAY_MASK; | |
116 | ||
117 | return ds4510_mem_write(chip, DS4510_RSTDELAY, &data, 1); | |
118 | } | |
119 | ||
120 | /* | |
121 | * Write pullup characteristics of IO pins | |
122 | */ | |
123 | int ds4510_pullup_write(uint8_t chip, uint8_t val) | |
124 | { | |
125 | val &= DS4510_IO_MASK; | |
126 | ||
127 | return ds4510_mem_write(chip, DS4510_PULLUP, (uint8_t *)&val, 1); | |
128 | } | |
129 | ||
130 | /* | |
131 | * Read pullup characteristics of IO pins | |
132 | */ | |
133 | int ds4510_pullup_read(uint8_t chip) | |
134 | { | |
135 | uint8_t val; | |
136 | ||
137 | if (i2c_read(chip, DS4510_PULLUP, 1, &val, 1)) | |
138 | return -1; | |
139 | ||
140 | return val & DS4510_IO_MASK; | |
141 | } | |
142 | ||
143 | /* | |
144 | * Write drive level of IO pins | |
145 | */ | |
146 | int ds4510_gpio_write(uint8_t chip, uint8_t val) | |
147 | { | |
148 | uint8_t data; | |
149 | int i; | |
150 | ||
151 | for (i = 0; i < DS4510_NUM_IO; i++) { | |
152 | if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1)) | |
153 | return -1; | |
154 | ||
155 | if (val & (0x1 << i)) | |
156 | data |= 0x1; | |
157 | else | |
158 | data &= ~0x1; | |
159 | ||
160 | if (ds4510_mem_write(chip, DS4510_IO0 - i, &data, 1)) | |
161 | return -1; | |
162 | } | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
167 | /* | |
168 | * Read drive level of IO pins | |
169 | */ | |
170 | int ds4510_gpio_read(uint8_t chip) | |
171 | { | |
172 | uint8_t data; | |
173 | int val = 0; | |
174 | int i; | |
175 | ||
176 | for (i = 0; i < DS4510_NUM_IO; i++) { | |
177 | if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1)) | |
178 | return -1; | |
179 | ||
180 | if (data & 1) | |
181 | val |= (1 << i); | |
182 | } | |
183 | ||
184 | return val; | |
185 | } | |
186 | ||
187 | /* | |
188 | * Read physical level of IO pins | |
189 | */ | |
190 | int ds4510_gpio_read_val(uint8_t chip) | |
191 | { | |
192 | uint8_t val; | |
193 | ||
194 | if (i2c_read(chip, DS4510_IO_STATUS, 1, &val, 1)) | |
195 | return -1; | |
196 | ||
197 | return val & DS4510_IO_MASK; | |
198 | } | |
199 | ||
200 | #ifdef CONFIG_CMD_DS4510 | |
201 | #ifdef CONFIG_CMD_DS4510_INFO | |
202 | /* | |
203 | * Display DS4510 information | |
204 | */ | |
205 | static int ds4510_info(uint8_t chip) | |
206 | { | |
207 | int i; | |
208 | int tmp; | |
209 | uint8_t data; | |
210 | ||
211 | printf("DS4510 @ 0x%x:\n\n", chip); | |
212 | ||
213 | if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1)) | |
214 | return -1; | |
215 | printf("rstdelay = 0x%x\n\n", data & DS4510_RSTDELAY_MASK); | |
216 | ||
217 | if (i2c_read(chip, DS4510_CFG, 1, &data, 1)) | |
218 | return -1; | |
219 | printf("config = 0x%x\n", data); | |
220 | printf(" /ready = %d\n", data & DS4510_CFG_READY ? 1 : 0); | |
221 | printf(" trip pt = %d\n", data & DS4510_CFG_TRIP_POINT ? 1 : 0); | |
222 | printf(" rst sts = %d\n", data & DS4510_CFG_RESET ? 1 : 0); | |
223 | printf(" /see = %d\n", data & DS4510_CFG_SEE ? 1 : 0); | |
224 | printf(" swrst = %d\n\n", data & DS4510_CFG_SWRST ? 1 : 0); | |
225 | ||
226 | printf("gpio pins: 3210\n"); | |
227 | printf("---------------\n"); | |
228 | printf("pullup "); | |
229 | ||
230 | tmp = ds4510_pullup_read(chip); | |
231 | if (tmp == -1) | |
232 | return tmp; | |
233 | for (i = DS4510_NUM_IO - 1; i >= 0; i--) | |
234 | printf("%d", (tmp & (1 << i)) ? 1 : 0); | |
235 | printf("\n"); | |
236 | ||
237 | printf("driven "); | |
238 | tmp = ds4510_gpio_read(chip); | |
239 | if (tmp == -1) | |
240 | return -1; | |
241 | for (i = DS4510_NUM_IO - 1; i >= 0; i--) | |
242 | printf("%d", (tmp & (1 << i)) ? 1 : 0); | |
243 | printf("\n"); | |
244 | ||
245 | printf("read "); | |
246 | tmp = ds4510_gpio_read_val(chip); | |
247 | if (tmp == -1) | |
248 | return -1; | |
249 | for (i = DS4510_NUM_IO - 1; i >= 0; i--) | |
250 | printf("%d", (tmp & (1 << i)) ? 1 : 0); | |
251 | printf("\n"); | |
252 | ||
253 | return 0; | |
254 | } | |
255 | #endif /* CONFIG_CMD_DS4510_INFO */ | |
256 | ||
257 | cmd_tbl_t cmd_ds4510[] = { | |
258 | U_BOOT_CMD_MKENT(device, 3, 0, (void *)DS4510_CMD_DEVICE, "", ""), | |
259 | U_BOOT_CMD_MKENT(nv, 3, 0, (void *)DS4510_CMD_NV, "", ""), | |
260 | U_BOOT_CMD_MKENT(output, 4, 0, (void *)DS4510_CMD_OUTPUT, "", ""), | |
261 | U_BOOT_CMD_MKENT(input, 3, 0, (void *)DS4510_CMD_INPUT, "", ""), | |
262 | U_BOOT_CMD_MKENT(pullup, 4, 0, (void *)DS4510_CMD_PULLUP, "", ""), | |
263 | #ifdef CONFIG_CMD_DS4510_INFO | |
264 | U_BOOT_CMD_MKENT(info, 2, 0, (void *)DS4510_CMD_INFO, "", ""), | |
265 | #endif | |
266 | #ifdef CONFIG_CMD_DS4510_RST | |
267 | U_BOOT_CMD_MKENT(rstdelay, 3, 0, (void *)DS4510_CMD_RSTDELAY, "", ""), | |
268 | #endif | |
269 | #ifdef CONFIG_CMD_DS4510_MEM | |
270 | U_BOOT_CMD_MKENT(eeprom, 6, 0, (void *)DS4510_CMD_EEPROM, "", ""), | |
271 | U_BOOT_CMD_MKENT(seeprom, 6, 0, (void *)DS4510_CMD_SEEPROM, "", ""), | |
272 | U_BOOT_CMD_MKENT(sram, 6, 0, (void *)DS4510_CMD_SRAM, "", ""), | |
273 | #endif | |
274 | }; | |
275 | ||
276 | int do_ds4510(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
277 | { | |
278 | static uint8_t chip = CONFIG_SYS_I2C_DS4510_ADDR; | |
279 | cmd_tbl_t *c; | |
280 | ulong ul_arg2 = 0; | |
281 | ulong ul_arg3 = 0; | |
282 | int tmp; | |
283 | #ifdef CONFIG_CMD_DS4510_MEM | |
284 | ulong addr; | |
285 | ulong off; | |
286 | ulong cnt; | |
287 | int end; | |
288 | int (*rw_func)(uint8_t, int, uint8_t *, int); | |
289 | #endif | |
290 | ||
291 | c = find_cmd_tbl(argv[1], cmd_ds4510, ARRAY_SIZE(cmd_ds4510)); | |
292 | ||
293 | /* All commands but "device" require 'maxargs' arguments */ | |
294 | if (!c || !((argc == (c->maxargs)) || | |
295 | (((int)c->cmd == DS4510_CMD_DEVICE) && | |
296 | (argc == (c->maxargs - 1))))) { | |
62c3ae7c | 297 | cmd_usage(cmdtp); |
a7c93104 PT |
298 | return 1; |
299 | } | |
300 | ||
301 | /* arg2 used as chip addr and pin number */ | |
302 | if (argc > 2) | |
303 | ul_arg2 = simple_strtoul(argv[2], NULL, 16); | |
304 | ||
305 | /* arg3 used as output/pullup value */ | |
306 | if (argc > 3) | |
307 | ul_arg3 = simple_strtoul(argv[3], NULL, 16); | |
308 | ||
309 | switch ((int)c->cmd) { | |
310 | case DS4510_CMD_DEVICE: | |
311 | if (argc == 3) | |
312 | chip = ul_arg2; | |
313 | printf("Current device address: 0x%x\n", chip); | |
314 | return 0; | |
315 | case DS4510_CMD_NV: | |
316 | return ds4510_see_write(chip, ul_arg2); | |
317 | case DS4510_CMD_OUTPUT: | |
318 | tmp = ds4510_gpio_read(chip); | |
319 | if (tmp == -1) | |
320 | return -1; | |
321 | if (ul_arg3) | |
322 | tmp |= (1 << ul_arg2); | |
323 | else | |
324 | tmp &= ~(1 << ul_arg2); | |
325 | return ds4510_gpio_write(chip, tmp); | |
326 | case DS4510_CMD_INPUT: | |
327 | tmp = ds4510_gpio_read_val(chip); | |
328 | if (tmp == -1) | |
329 | return -1; | |
330 | return (tmp & (1 << ul_arg2)) != 0; | |
331 | case DS4510_CMD_PULLUP: | |
332 | tmp = ds4510_pullup_read(chip); | |
333 | if (tmp == -1) | |
334 | return -1; | |
335 | if (ul_arg3) | |
336 | tmp |= (1 << ul_arg2); | |
337 | else | |
338 | tmp &= ~(1 << ul_arg2); | |
339 | return ds4510_pullup_write(chip, tmp); | |
340 | #ifdef CONFIG_CMD_DS4510_INFO | |
341 | case DS4510_CMD_INFO: | |
342 | return ds4510_info(chip); | |
343 | #endif | |
344 | #ifdef CONFIG_CMD_DS4510_RST | |
345 | case DS4510_CMD_RSTDELAY: | |
346 | return ds4510_rstdelay_write(chip, ul_arg2); | |
347 | #endif | |
348 | #ifdef CONFIG_CMD_DS4510_MEM | |
349 | case DS4510_CMD_EEPROM: | |
350 | end = DS4510_EEPROM + DS4510_EEPROM_SIZE; | |
351 | off = DS4510_EEPROM; | |
352 | break; | |
353 | case DS4510_CMD_SEEPROM: | |
354 | end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE; | |
355 | off = DS4510_SEEPROM; | |
356 | break; | |
357 | case DS4510_CMD_SRAM: | |
358 | end = DS4510_SRAM + DS4510_SRAM_SIZE; | |
359 | off = DS4510_SRAM; | |
360 | break; | |
361 | #endif | |
362 | default: | |
363 | /* We should never get here... */ | |
364 | return 1; | |
365 | } | |
366 | ||
367 | #ifdef CONFIG_CMD_DS4510_MEM | |
368 | /* Only eeprom, seeprom, and sram commands should make it here */ | |
369 | if (strcmp(argv[2], "read") == 0) { | |
370 | rw_func = ds4510_mem_read; | |
371 | } else if (strcmp(argv[2], "write") == 0) { | |
372 | rw_func = ds4510_mem_write; | |
373 | } else { | |
62c3ae7c | 374 | cmd_usage(cmdtp); |
a7c93104 PT |
375 | return 1; |
376 | } | |
377 | ||
378 | addr = simple_strtoul(argv[3], NULL, 16); | |
379 | off += simple_strtoul(argv[4], NULL, 16); | |
380 | cnt = simple_strtoul(argv[5], NULL, 16); | |
381 | ||
382 | if ((off + cnt) > end) { | |
383 | printf("ERROR: invalid len\n"); | |
384 | return -1; | |
385 | } | |
386 | ||
387 | return rw_func(chip, off, (uint8_t *)addr, cnt); | |
388 | #endif | |
389 | } | |
390 | ||
391 | U_BOOT_CMD( | |
392 | ds4510, 6, 1, do_ds4510, | |
2fb2604d | 393 | "ds4510 eeprom/seeprom/sram/gpio access", |
a7c93104 PT |
394 | "device [dev]\n" |
395 | " - show or set current device address\n" | |
396 | #ifdef CONFIG_CMD_DS4510_INFO | |
397 | "ds4510 info\n" | |
398 | " - display ds4510 info\n" | |
399 | #endif | |
400 | "ds4510 output pin 0|1\n" | |
401 | " - set pin low or high-Z\n" | |
402 | "ds4510 input pin\n" | |
403 | " - read value of pin\n" | |
404 | "ds4510 pullup pin 0|1\n" | |
405 | " - disable/enable pullup on specified pin\n" | |
406 | "ds4510 nv 0|1\n" | |
407 | " - make gpio and seeprom writes volatile/non-volatile\n" | |
408 | #ifdef CONFIG_CMD_DS4510_RST | |
409 | "ds4510 rstdelay 0-3\n" | |
410 | " - set reset output delay\n" | |
411 | #endif | |
412 | #ifdef CONFIG_CMD_DS4510_MEM | |
413 | "ds4510 eeprom read addr off cnt\n" | |
414 | "ds4510 eeprom write addr off cnt\n" | |
415 | " - read/write 'cnt' bytes at EEPROM offset 'off'\n" | |
416 | "ds4510 seeprom read addr off cnt\n" | |
417 | "ds4510 seeprom write addr off cnt\n" | |
418 | " - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n" | |
419 | "ds4510 sram read addr off cnt\n" | |
420 | "ds4510 sram write addr off cnt\n" | |
421 | " - read/write 'cnt' bytes at SRAM offset 'off'\n" | |
422 | #endif | |
423 | ); | |
424 | #endif /* CONFIG_CMD_DS4510 */ |