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