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