uboot/board/egnite/ethernut5/ethernut5_pwrman.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2011
   3 * egnite GmbH <info@egnite.de>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   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 */
  45static int pwrman_major;
  46static 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 */
  59void 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 */
  81void 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 */
 118void 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 */
 130char *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 */
 138static 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 */
 154static 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
 172void 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
 187void 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
 201void 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 */
 219int 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
 293U_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 */
 323