]>
Commit | Line | Data |
---|---|---|
14c32614 TS |
1 | /* |
2 | * (C) Copyright 2011 | |
3 | * egnite GmbH <info@egnite.de> | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
14c32614 TS |
6 | */ |
7 | ||
8 | /* | |
9 | * Ethernut 5 power management support | |
10 | * | |
11 | * This board may be supplied via USB, IEEE 802.3af PoE or an | |
12 | * auxiliary DC input. An on-board ATmega168 microcontroller, | |
13 | * the so called power management controller or PMC, is used | |
14 | * to select the supply source and to switch on and off certain | |
15 | * energy consuming board components. This allows to reduce the | |
16 | * total stand-by consumption to less than 70mW. | |
17 | * | |
18 | * The main CPU communicates with the PMC via I2C. When | |
19 | * CONFIG_CMD_BSP is defined in the board configuration file, | |
20 | * then the board specific command 'pwrman' becomes available, | |
21 | * which allows to manually deal with the PMC. | |
22 | * | |
23 | * Two distinct registers are provided by the PMC for enabling | |
24 | * and disabling specific features. This avoids the often seen | |
25 | * read-modify-write cycle or shadow register requirement. | |
26 | * Additional registers are available to query the board | |
27 | * status and temperature, the auxiliary voltage and to control | |
28 | * the green user LED that is integrated in the reset switch. | |
29 | * | |
30 | * Note, that the AVR firmware of the PMC is released under BSDL. | |
31 | * | |
32 | * For additional information visit the project home page at | |
33 | * http://www.ethernut.de/ | |
34 | */ | |
35 | #include <common.h> | |
36 | #include <asm/arch/at91sam9260.h> | |
37 | #include <asm/arch/at91_common.h> | |
38 | #include <asm/arch/gpio.h> | |
39 | #include <asm/io.h> | |
40 | #include <i2c.h> | |
41 | ||
42 | #include "ethernut5_pwrman.h" | |
43 | ||
44 | /* PMC firmware version */ | |
45 | static int pwrman_major; | |
46 | static int pwrman_minor; | |
47 | ||
48 | /* | |
49 | * Enable Ethernut 5 power management. | |
50 | * | |
51 | * This function must be called during board initialization. | |
52 | * While we are using u-boot's I2C subsystem, it may be required | |
53 | * to enable the serial port before calling this function, | |
54 | * in particular when debugging is enabled. | |
55 | * | |
56 | * If board specific commands are not available, we will activate | |
57 | * all board components. | |
58 | */ | |
59 | void ethernut5_power_init(void) | |
60 | { | |
61 | pwrman_minor = i2c_reg_read(PWRMAN_I2C_ADDR, PWRMAN_REG_VERS); | |
62 | pwrman_major = pwrman_minor >> 4; | |
63 | pwrman_minor &= 15; | |
64 | ||
65 | #ifndef CONFIG_CMD_BSP | |
66 | /* Do not modify anything, if we do not have a known version. */ | |
67 | if (pwrman_major == 2) { | |
68 | /* Without board specific commands we enable all features. */ | |
69 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_ENA, ~PWRMAN_ETHRST); | |
70 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_DIS, PWRMAN_ETHRST); | |
71 | } | |
72 | #endif | |
73 | } | |
74 | ||
75 | /* | |
76 | * Reset Ethernet PHY. | |
77 | * | |
78 | * This function allows the re-configure the PHY after | |
79 | * changing its strap pins. | |
80 | */ | |
81 | void ethernut5_phy_reset(void) | |
82 | { | |
83 | /* Do not modify anything, if we do not have a known version. */ | |
84 | if (pwrman_major != 2) | |
85 | return; | |
86 | ||
87 | /* | |
88 | * Make sure that the Ethernet clock is enabled and the PHY reset | |
89 | * is disabled for at least 100 us. | |
90 | */ | |
91 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_ENA, PWRMAN_ETHCLK); | |
92 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_DIS, PWRMAN_ETHRST); | |
93 | udelay(100); | |
94 | ||
95 | /* | |
96 | * LAN8710 strap pins are | |
97 | * PA14 => PHY MODE0 | |
98 | * PA15 => PHY MODE1 | |
99 | * PA17 => PHY MODE2 => 111b all capable | |
100 | * PA18 => PHY ADDR0 => 0b | |
101 | */ | |
102 | at91_set_pio_input(AT91_PIO_PORTA, 14, 1); | |
103 | at91_set_pio_input(AT91_PIO_PORTA, 15, 1); | |
104 | at91_set_pio_input(AT91_PIO_PORTA, 17, 1); | |
105 | at91_set_pio_input(AT91_PIO_PORTA, 18, 0); | |
106 | ||
107 | /* Activate PHY reset for 100 us. */ | |
108 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_ENA, PWRMAN_ETHRST); | |
109 | udelay(100); | |
110 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_DIS, PWRMAN_ETHRST); | |
111 | ||
112 | at91_set_pio_input(AT91_PIO_PORTA, 14, 1); | |
113 | } | |
114 | ||
115 | /* | |
116 | * Output the firmware version we got during initialization. | |
117 | */ | |
118 | void ethernut5_print_version(void) | |
119 | { | |
120 | printf("%u.%u\n", pwrman_major, pwrman_minor); | |
121 | } | |
122 | ||
123 | /* | |
124 | * All code below this point is optional and implements | |
125 | * the 'pwrman' command. | |
126 | */ | |
127 | #ifdef CONFIG_CMD_BSP | |
128 | ||
129 | /* Human readable names of PMC features */ | |
130 | char *pwrman_feat[8] = { | |
131 | "board", "vbin", "vbout", "mmc", | |
132 | "rs232", "ethclk", "ethrst", "wakeup" | |
133 | }; | |
134 | ||
135 | /* | |
136 | * Print all feature names, that have its related flags enabled. | |
137 | */ | |
138 | static void print_flagged_features(u8 flags) | |
139 | { | |
140 | int i; | |
141 | ||
142 | for (i = 0; i < 8; i++) { | |
143 | if (flags & (1 << i)) | |
144 | printf("%s ", pwrman_feat[i]); | |
145 | } | |
146 | } | |
147 | ||
148 | /* | |
149 | * Return flags of a given list of feature names. | |
150 | * | |
151 | * The function stops at the first unknown list entry and | |
152 | * returns the number of detected names as a function result. | |
153 | */ | |
154 | static int feature_flags(char * const names[], int num, u8 *flags) | |
155 | { | |
156 | int i, j; | |
157 | ||
158 | *flags = 0; | |
159 | for (i = 0; i < num; i++) { | |
160 | for (j = 0; j < 8; j++) { | |
161 | if (strcmp(pwrman_feat[j], names[i]) == 0) { | |
162 | *flags |= 1 << j; | |
163 | break; | |
164 | } | |
165 | } | |
166 | if (j > 7) | |
167 | break; | |
168 | } | |
169 | return i; | |
170 | } | |
171 | ||
172 | void ethernut5_print_power(void) | |
173 | { | |
174 | u8 flags; | |
175 | int i; | |
176 | ||
177 | flags = i2c_reg_read(PWRMAN_I2C_ADDR, PWRMAN_REG_ENA); | |
178 | for (i = 0; i < 2; i++) { | |
179 | if (flags) { | |
180 | print_flagged_features(flags); | |
181 | printf("%s\n", i ? "off" : "on"); | |
182 | } | |
183 | flags = ~flags; | |
184 | } | |
185 | } | |
186 | ||
187 | void ethernut5_print_celsius(void) | |
188 | { | |
189 | int val; | |
190 | ||
191 | /* Read ADC value from LM50 and return Celsius degrees. */ | |
192 | val = i2c_reg_read(PWRMAN_I2C_ADDR, PWRMAN_REG_TEMP); | |
193 | val *= 5000; /* 100mV/degree with 5V reference */ | |
194 | val += 128; /* 8 bit resolution */ | |
195 | val /= 256; | |
196 | val -= 450; /* Celsius offset, still x10 */ | |
197 | /* Output full degrees. */ | |
198 | printf("%d\n", (val + 5) / 10); | |
199 | } | |
200 | ||
201 | void ethernut5_print_voltage(void) | |
202 | { | |
203 | int val; | |
204 | ||
205 | /* Read ADC value from divider and return voltage. */ | |
206 | val = i2c_reg_read(PWRMAN_I2C_ADDR, PWRMAN_REG_VAUX); | |
207 | /* Resistors are 100k and 12.1k */ | |
208 | val += 5; | |
209 | val *= 180948; | |
210 | val /= 100000; | |
211 | val++; | |
212 | /* Calculation was done in 0.1V units. */ | |
213 | printf("%d\n", (val + 5) / 10); | |
214 | } | |
215 | ||
216 | /* | |
217 | * Process the board specific 'pwrman' command. | |
218 | */ | |
219 | int do_pwrman(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
220 | { | |
221 | u8 val; | |
222 | int i; | |
223 | ||
224 | if (argc == 1) { | |
225 | ethernut5_print_power(); | |
226 | } else if (argc == 2 && strcmp(argv[1], "reset") == 0) { | |
227 | at91_set_pio_output(AT91_PIO_PORTB, 8, 1); | |
228 | udelay(100); | |
229 | at91_set_pio_output(AT91_PIO_PORTB, 8, 0); | |
230 | udelay(100000); | |
231 | } else if (argc == 2 && strcmp(argv[1], "temp") == 0) { | |
232 | ethernut5_print_celsius(); | |
233 | } else if (argc == 2 && strcmp(argv[1], "vaux") == 0) { | |
234 | ethernut5_print_voltage(); | |
235 | } else if (argc == 2 && strcmp(argv[1], "version") == 0) { | |
236 | ethernut5_print_version(); | |
237 | } else if (strcmp(argv[1], "led") == 0) { | |
238 | /* Control the green status LED. Blink frequency unit | |
239 | ** is 0.1s, very roughly. */ | |
240 | if (argc == 2) { | |
241 | /* No more arguments, output current settings. */ | |
242 | val = i2c_reg_read(PWRMAN_I2C_ADDR, PWRMAN_REG_LEDCTL); | |
243 | printf("led %u %u\n", val >> 4, val & 15); | |
244 | } else { | |
245 | /* First argument specifies the on-time. */ | |
246 | val = (u8) simple_strtoul(argv[2], NULL, 0); | |
247 | val <<= 4; | |
248 | if (argc > 3) { | |
249 | /* Second argument specifies the off-time. */ | |
250 | val |= (u8) (simple_strtoul(argv[3], NULL, 0) | |
251 | & 15); | |
252 | } | |
253 | /* Update the LED control register. */ | |
254 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_LEDCTL, val); | |
255 | } | |
256 | } else { | |
257 | /* We expect a list of features followed an optional status. */ | |
258 | argc--; | |
259 | i = feature_flags(&argv[1], argc, &val); | |
260 | if (argc == i) { | |
261 | /* We got a list only, print status. */ | |
262 | val &= i2c_reg_read(PWRMAN_I2C_ADDR, PWRMAN_REG_STA); | |
263 | if (val) { | |
264 | if (i > 1) | |
265 | print_flagged_features(val); | |
266 | printf("active\n"); | |
267 | } else { | |
268 | printf("inactive\n"); | |
269 | } | |
270 | } else { | |
271 | /* More arguments. */ | |
272 | if (i == 0) { | |
273 | /* No given feature, use despensibles. */ | |
274 | val = PWRMAN_DISPENSIBLE; | |
275 | } | |
276 | if (strcmp(argv[i + 1], "on") == 0) { | |
277 | /* Enable features. */ | |
278 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_ENA, | |
279 | val); | |
280 | } else if (strcmp(argv[i + 1], "off") == 0) { | |
281 | /* Disable features. */ | |
282 | i2c_reg_write(PWRMAN_I2C_ADDR, PWRMAN_REG_DIS, | |
283 | val); | |
284 | } else { | |
285 | printf("Bad parameter %s\n", argv[i + 1]); | |
286 | return 1; | |
287 | } | |
288 | } | |
289 | } | |
290 | return 0; | |
291 | } | |
292 | ||
293 | U_BOOT_CMD( | |
294 | pwrman, CONFIG_SYS_MAXARGS, 1, do_pwrman, | |
295 | "power management", | |
296 | "- print settings\n" | |
297 | "pwrman feature ...\n" | |
298 | " - print status\n" | |
299 | "pwrman [feature ...] on|off\n" | |
300 | " - enable/disable specified or all dispensible features\n" | |
301 | "pwrman led [on-time [off-time]]\n" | |
302 | " - print or set led blink timer\n" | |
303 | "pwrman temp\n" | |
304 | " - print board temperature (Celsius)\n" | |
305 | "pwrman vaux\n" | |
306 | " - print auxiliary input voltage\n" | |
307 | "pwrman reset\n" | |
308 | " - reset power management controller\n" | |
309 | "pwrman version\n" | |
310 | " - print firmware version\n" | |
311 | "\n" | |
312 | " features, (*)=dispensible:\n" | |
313 | " board - 1.8V and 3.3V supply\n" | |
314 | " vbin - supply via USB device connector\n" | |
315 | " vbout - USB host connector supply(*)\n" | |
316 | " mmc - MMC slot supply(*)\n" | |
317 | " rs232 - RS232 driver\n" | |
318 | " ethclk - Ethernet PHY clock(*)\n" | |
319 | " ethrst - Ethernet PHY reset\n" | |
320 | " wakeup - RTC alarm" | |
321 | ); | |
322 | #endif /* CONFIG_CMD_BSP */ |