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