ethernut5_pwrman.c 8.5 KB

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