ethernut5_pwrman.c 9.2 KB

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