diff options
author | Juergen Beisert <jbe@pengutronix.de> | 2011-06-23 19:34:58 +0200 |
---|---|---|
committer | Robert Schwebel <r.schwebel@pengutronix.de> | 2011-06-24 14:25:57 +0200 |
commit | 03394c3f85b3e6f66794401d913f03e3f75b8985 (patch) | |
tree | 67f3e0129e0833386db286eea9ae3c875bc7543b | |
parent | fac880fb951cf744dcf01f2db94c99c493588599 (diff) | |
download | barebox-03394c3f85b3e6f66794401d913f03e3f75b8985.tar.gz barebox-03394c3f85b3e6f66794401d913f03e3f75b8985.tar.xz |
arm/mxs: add mx23 pmic support
Add support for the PMIC integrated in the i.MX23.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
Signed-off-by: Robert Schwebel <r.schwebel@pengutronix.de>
-rw-r--r-- | arch/arm/mach-mxs/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-mxs/bootlets/pmic-imx23.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/imx23-regs.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/pmic-imx23.h | 30 | ||||
-rw-r--r-- | arch/arm/mach-mxs/pmic-imx23.c | 685 |
5 files changed, 733 insertions, 16 deletions
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile index 39df5014..ebd26e24 100644 --- a/arch/arm/mach-mxs/Makefile +++ b/arch/arm/mach-mxs/Makefile @@ -1,6 +1,6 @@ obj-y += imx.o iomux-imx.o reset-imx.o obj-$(CONFIG_DRIVER_VIDEO_STM) += imx_lcd_clk.o -obj-$(CONFIG_ARCH_IMX23) += speed-imx23.o clocksource-imx23.o usb.o +obj-$(CONFIG_ARCH_IMX23) += speed-imx23.o clocksource-imx23.o usb.o pmic-imx23.o obj-$(CONFIG_ARCH_IMX28) += speed-imx28.o clocksource-imx28.o subdir- := bootlets/ diff --git a/arch/arm/mach-mxs/bootlets/pmic-imx23.c b/arch/arm/mach-mxs/bootlets/pmic-imx23.c index d3ca1b73..9779c7c6 100644 --- a/arch/arm/mach-mxs/bootlets/pmic-imx23.c +++ b/arch/arm/mach-mxs/bootlets/pmic-imx23.c @@ -14,6 +14,7 @@ * GNU General Public License for more details. */ +#include <linux/compiler.h> #include <bootlets.h> #include <arch.h> #include <power.h> @@ -74,7 +75,7 @@ * @param[in] bin Binary setting * @return corresponding voltage value in mV */ -static unsigned vddd_bin_to_voltage(unsigned bin) +static __maybe_unused unsigned vddd_bin_to_voltage(unsigned bin) { /* each step is 25 mV, base is 800 mV */ return bin * 25 + 800; @@ -85,7 +86,7 @@ static unsigned vddd_bin_to_voltage(unsigned bin) * @param[in] bin Binary setting * @return corresponding voltage value in mV */ -static unsigned vdda_bin_to_voltage(unsigned bin) +static __maybe_unused unsigned vdda_bin_to_voltage(unsigned bin) { /* each step is 25 mV, base is 1.5 V */ return bin * 25 + 1500; @@ -96,7 +97,7 @@ static unsigned vdda_bin_to_voltage(unsigned bin) * @param[in] bin Binary setting * @return corresponding voltage value in mV */ -static unsigned vddio_bin_to_voltage(unsigned bin) +static __maybe_unused unsigned vddio_bin_to_voltage(unsigned bin) { /* each step is 25 mV, base is 2.9 V */ return bin * 25 + 2800; @@ -107,7 +108,7 @@ static unsigned vddio_bin_to_voltage(unsigned bin) * @param[in] bin Binary setting * @return corresponding voltage value in mV */ -static unsigned vddm_bin_to_voltage(unsigned bin) +static __maybe_unused unsigned vddm_bin_to_voltage(unsigned bin) { /* each step is 50 mV, base is 1.7 V */ return bin * 50 + 1700; @@ -118,7 +119,7 @@ static unsigned vddm_bin_to_voltage(unsigned bin) * @param[in] tgt Target voltage in mV * @return corresponding register bits */ -static unsigned vddm_voltage_to_bin(unsigned tgt) +static __maybe_unused unsigned vddm_voltage_to_bin(unsigned tgt) { /* each step is 50 mV, base is 1.7 V */ return DIV_ROUND_UP(tgt - 1700, 50); @@ -128,7 +129,7 @@ static unsigned vddm_voltage_to_bin(unsigned tgt) * Get current VDDD voltage setting * @return VDDD voltage im mV */ -static unsigned get_vddd(void) +static __maybe_unused unsigned get_vddd(void) { unsigned reg = readl(VDDDCTRL) & 0x1F; return vddd_bin_to_voltage(reg); @@ -138,7 +139,7 @@ static unsigned get_vddd(void) * Get current VDDD brown out voltage offset * @return Offset below main setting */ -static int get_vddd_bo(void) +static __maybe_unused int get_vddd_bo(void) { unsigned reg = (readl(VDDDCTRL) >> 8) & 0x07; return -(reg * 25); @@ -148,7 +149,7 @@ static int get_vddd_bo(void) * Get current VDDD linear regulator offset * @return Offset below main setting */ -static int get_vddd_lin_offset(void) +static __maybe_unused int get_vddd_lin_offset(void) { unsigned reg = (readl(VDDDCTRL) >> 16) & 0x03; if (reg == 0) @@ -162,7 +163,7 @@ static int get_vddd_lin_offset(void) * Get current VDDM voltage setting * @return VDDM voltage im mV */ -static unsigned get_vddm(void) +static __maybe_unused unsigned get_vddm(void) { unsigned reg = readl(VDDMEMCTRL) & 0x1F; return vddm_bin_to_voltage(reg); @@ -172,7 +173,7 @@ static unsigned get_vddm(void) * Get current VDDIO voltage setting * @return VDDIO voltage im mV */ -static unsigned get_vddio(void) +static __maybe_unused unsigned get_vddio(void) { unsigned reg = readl(VDDIOCTRL) & 0x1F; return vddio_bin_to_voltage(reg); @@ -182,7 +183,7 @@ static unsigned get_vddio(void) * Get current VDDIO brown out voltage offset * @return Offset below main setting */ -static int get_vddio_bo(void) +static __maybe_unused int get_vddio_bo(void) { unsigned reg = (readl(VDDIOCTRL) >> 8) & 0x07; return -(reg * 25); @@ -192,7 +193,7 @@ static int get_vddio_bo(void) * Get current VDDIO linear regulator offset * @return Offset below main setting */ -static int get_vddio_lin_offset(void) +static __maybe_unused int get_vddio_lin_offset(void) { unsigned reg = (readl(VDDIOCTRL) >> 12) & 0x03; if (reg == 0) @@ -206,7 +207,7 @@ static int get_vddio_lin_offset(void) * Get current VDDA voltage setting * @return VDDA voltage im mV */ -static unsigned get_vdda(void) +static __maybe_unused unsigned get_vdda(void) { unsigned reg = readl(VDDACTRL) & 0x1F; return vdda_bin_to_voltage(reg); @@ -216,7 +217,7 @@ static unsigned get_vdda(void) * Get current VDDA brown out voltage offset * @return Offset below main setting */ -static int get_vdda_bo(void) +static __maybe_unused int get_vdda_bo(void) { unsigned reg = (readl(VDDACTRL) >> 8) & 0x7; return -(reg * 25); @@ -226,7 +227,7 @@ static int get_vdda_bo(void) * Get current VDDA linear regulator offset * @return Offset below main setting */ -static int get_vdda_lin_offset(void) +static __maybe_unused int get_vdda_lin_offset(void) { unsigned reg = (readl(VDDACTRL) >> 12) & 0x3; if (reg == 0) diff --git a/arch/arm/mach-mxs/include/mach/imx23-regs.h b/arch/arm/mach-mxs/include/mach/imx23-regs.h index cc8c03e8..cbf6e872 100644 --- a/arch/arm/mach-mxs/include/mach/imx23-regs.h +++ b/arch/arm/mach-mxs/include/mach/imx23-regs.h @@ -34,6 +34,7 @@ #define IMX_IOMUXC_BASE 0x80018000 #define IMX_WDT_BASE 0x8005c000 #define IMX_CCM_BASE 0x80040000 +#define IMX_PMIC_BASE 0x80044000 #define IMX_I2C1_BASE 0x80058000 #define IMX_SSP1_BASE 0x80010000 #define IMX_FB_BASE 0x80030000 diff --git a/arch/arm/mach-mxs/include/mach/pmic-imx23.h b/arch/arm/mach-mxs/include/mach/pmic-imx23.h new file mode 100644 index 00000000..6fab9410 --- /dev/null +++ b/arch/arm/mach-mxs/include/mach/pmic-imx23.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2011 Juergen Beisert - Pengutronix + * + * Based on Chumby Falconwing Code, (C) 2010 Juergen Beisert + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/** all voltages in 'millivolt' [mV] */ +struct rail_voltage { + unsigned main_mV; /** line's main voltage */ + unsigned guard_mV; /** line's brownout voltage */ + unsigned lin_mV; /** voltage of the linear regulators, if the DC/DC converter is enabled */ +}; + +extern int switch_to_dcdc(void); +extern int setup_vddmem_voltage(const struct rail_voltage*); +extern int adjust_vddmem_voltage(const struct rail_voltage*); +extern int setup_vddio_voltage(const struct rail_voltage*); +extern int setup_vdda_voltage(const struct rail_voltage*); +extern int setup_vddd_voltage(const struct rail_voltage*); +extern void print_current_settings(void); diff --git a/arch/arm/mach-mxs/pmic-imx23.c b/arch/arm/mach-mxs/pmic-imx23.c new file mode 100644 index 00000000..ea79a951 --- /dev/null +++ b/arch/arm/mach-mxs/pmic-imx23.c @@ -0,0 +1,685 @@ +/* + * (C) Copyright 2011 Juergen Beisert - Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <common.h> +#include <errno.h> +#include <sizes.h> +#include <asm/io.h> +#include <mach/imx-regs.h> +#include <mach/pmic-imx23.h> + +#define PWR_CTL (IMX_PMIC_BASE + 0x00) + +#define POWER_5VCTRL (IMX_PMIC_BASE + 0x10) +# define DCDC_XFER (1 << 5) +# define VBUSVALID_5VDETECT (1 << 4) +# define PWRUP_VBUS_CMPS (1 << 1) +# define START_DCDC (1 << 0) + +#define POWER_MINPWR (IMX_PMIC_BASE + 0x20) + +#define POWER_CHARGE (IMX_PMIC_BASE + 0x30) +# define ENABLE_LOAD (1 << 22) +# define PWD_BATTCHRG (1 << 16) + +#define VDDDCTRL (IMX_PMIC_BASE + 0x40) + +#define VDDACTRL (IMX_PMIC_BASE + 0x50) + +#define VDDIOCTRL (IMX_PMIC_BASE + 0x60) + +#define VDDMEMCTRL (IMX_PMIC_BASE + 0x70) +# define PULLDOWN_ACTIVE (1 << 10) +# define ENABLE_LINREG (1 << 8) +# define ENABLE_ILIMIT (1 << 9) + +#define POWER_DCDC4P2 (IMX_PMIC_BASE + 0x80) +# define ENABLE_4P2 (1 << 23) +# define ENABLE_DCDC (1 << 22) + +#define POWER_MISC (IMX_PMIC_BASE + 0x90) +# define DOUBLE_FETS (1 <<6) + +#define POWER_DCLIMITS (PWR_CTL + 0xA0) +# define SET_NEGLIMIT(x) ((x) & 0x7f) +# define SET_POSLIMIT_BUCK(x) (((x) & 0x7f) << 8) + +#define POWER_LOOPCTRL (PWR_CTL + 0xB0) +# define TOGGLE_DIF (1 << 20) +# define EN_CM_HYST (1 << 18) +# define EN_DF_HYST (1 << 17) +# define RCSCALE_THRESH (1 << 14) +# define SET_EN_RCSCALE(x) (((x) & 0x3) << 12) +# define SET_DC_R(x) (((x) & 0xf) << 4) +# define SET_DC_C(x) ((x) & 0x3) + +#define POWER_STS (IMX_PMIC_BASE + 0xC0) + +#define POWER_BATTMONITOR (PWR_CTL + 0xE0) +# define EN_BATADJ (1 << 10) +# define PWDN_BATTBRNOUT (1 << 9) +# define SET_BRWNOUT_LVL(x) ((x) & 0x1f) + +/** + * Power supply: + * + * Internal rails are: + * + * VDDIO: Used to supply on chip IO drivers (max 3.63 V, can drive at least 175 mA) + * VDDM: Used to supply external SDRAM devices, derived from VDDIO (can drive at least 230 mA) + * VDDA: Used to supply analogue on chip components (min 1.62 V, max 2.1 V, should not exceed 1.95 V!) + * VDDD: Used to supply the digital on chip components, for example the CPU core (min 1.0 V, max 1.575 V) + * + * (VDDIO Load Current + VDDM Load Current + VDDA Load Current) < VDDIO Maximum Output Current + * (VDDA Load Current + VDDD Load Current) < VDDA Maximum Output Current + * + * + * 32.11.10 ist sehr interessant + * + * There are some limits: + * - to run the CPU at its highest speed (454 MHz) VDDD must be at least 1.55 V + * - to run the SDRAM controller at 133 MHz, VDDD must be at least 1.2 V + */ + +/** + * Convert VDDD register setting to target voltage + * @param[in] bin Binary setting + * @return corresponding voltage value in mV + */ +static unsigned vddd_bin_to_voltage(unsigned bin) +{ + /* each step is 25 mV, base is 800 mV */ + return bin * 25 + 800; +} + +/** + * Convert VDDA register setting to target voltage + * @param[in] bin Binary setting + * @return corresponding voltage value in mV + */ +static unsigned vdda_bin_to_voltage(unsigned bin) +{ + /* each step is 25 mV, base is 1,5 V */ + return bin * 25 + 1500; +} + +/** + * Convert VDDIO register setting to target voltage + * @param[in] bin Binary setting + * @return corresponding voltage value in mV + */ +static unsigned vddio_bin_to_voltage(unsigned bin) +{ + /* each step is 25 mV, base is 2,9 V */ + return bin * 25 + 2800; +} + +/** + * Convert VDDM register setting to target voltage + * @param[in] bin Binary setting + * @return corresponding voltage value in mV + */ +static unsigned vddm_bin_to_voltage(unsigned bin) +{ + /* each step is 50 mV, base is 1,7 V */ + return bin * 50 + 1700; +} + +/** + * Convert VDDM target voltage to register setting + * @param[in] tgt Target voltage in mV + * @return corresponding register bits + */ +static unsigned vddm_voltage_to_bin(unsigned tgt) +{ + /* each step is 50 mV, base is 1,7 V */ + return (tgt - 1700) / 50; /* FIMXE rounding? */ +} + +/** + * Get current VDDD voltage setting + * @return VDDD voltage im mV + */ +static unsigned get_vddd(void) +{ + unsigned reg = readl(VDDDCTRL) & 0x1F; + return vddd_bin_to_voltage(reg); +} + +/** + * Get current VDDD brown out voltage offset + * @return Offset below main setting + */ +static int get_vddd_bo(void) +{ + unsigned reg = (readl(VDDDCTRL) >> 8) & 0x07; + return -(reg * 25); +} + +/** + * Get current VDDD linear regulator offset + * @return Offset below main setting + */ +static int get_vddd_lin_offset(void) +{ + unsigned reg = (readl(VDDDCTRL) >> 16) & 0x03; + + switch (reg) { + case 0: + return 0; + case 1: + return 25; + } + return -25; +} + +/** + * Get current VDDM voltage setting + * @return VDDM voltage im mV + */ +static unsigned get_vddm(void) +{ + unsigned reg = readl(VDDMEMCTRL) & 0x1F; + return vddm_bin_to_voltage(reg); +} + +/** + * Get current VDDIO voltage setting + * @return VDDIO voltage im mV + */ +static unsigned get_vddio(void) +{ + unsigned reg = readl(VDDIOCTRL) & 0x1F; + return vddio_bin_to_voltage(reg); +} + +/** + * Get current VDDIO brown out voltage offset + * @return Offset below main setting + */ +static int get_vddio_bo(void) +{ + unsigned reg = (readl(VDDIOCTRL) >> 8) & 0x07; + return -(reg * 25); +} + +/** + * Get current VDDIO linear regulator offset + * @return Offset below main setting + */ +static int get_vddio_lin_offset(void) +{ + unsigned reg = (readl(VDDIOCTRL) >> 12) & 0x03; + + switch (reg) { + case 0: + return 0; + case 1: + return 25; + } + return -25; +} + +/** + * Get current VDDA voltage setting + * @return VDDA voltage im mV + */ +static unsigned get_vdda(void) +{ + unsigned reg = readl(VDDACTRL) & 0x1F; + return vdda_bin_to_voltage(reg); +} + +/** + * Get current VDDA brown out voltage offset + * @return Offset below main setting + */ +static int get_vdda_bo(void) +{ + unsigned reg = (readl(VDDACTRL) >> 8) & 0x7; + return -(reg * 25); +} + +/** + * Get current VDDA linear regulator offset + * @return Offset below main setting + */ +static int get_vdda_lin_offset(void) +{ + unsigned reg = (readl(VDDACTRL) >> 12) & 0x3; + + switch (reg) { + case 0: + return 0; + case 1: + return 25; + } + return -25; +} + +/** + * Set the voltage of the VDDM linear regulator + * @param[in] voltage New setting + * @return 0 on success + * + * We assume the SDRAM is not used yet, e.g. the clock is off! + * After a reset, VDDM is disabled completely! + */ +int setup_vddmem_voltage(const struct rail_voltage *voltage) +{ + unsigned vddm = readl(VDDMEMCTRL); + + /* mostly 1.8 V for mobile SDRAM and 2.5 V for regular SDRAM */ + + /* disable the linear regulator */ + vddm &= ~ENABLE_LINREG; + writel(vddm, VDDMEMCTRL); + udelay(10); + /* force supply to GND to send a real reset to the SDRAMs */ + writel(vddm | PULLDOWN_ACTIVE, VDDMEMCTRL); + udelay(100); + + /* activate rail's current limiter (about 10 mA) */ + vddm |= ENABLE_ILIMIT; + /* setup new target voltage */ + vddm &= ~0x1F; + vddm |= vddm_voltage_to_bin(voltage->main_mV); + writel(vddm, VDDMEMCTRL); + udelay(1); + + /* enable the linear regulator again */ + vddm |= ENABLE_LINREG; + writel(vddm, VDDMEMCTRL); + + /* wait 500 us to raise the rail */ + udelay(100); + + /* now disable rail's current limiter */ + vddm &= ~ENABLE_ILIMIT; + writel(vddm, VDDMEMCTRL); + + /* SDRAM power supply is now ready to be used */ + return 0; +} + +/** + * Adjust the VDDM voltage + * @param[in] voltage New setting + * @return 0 on success + */ +int adjust_vddmem_voltage(const struct rail_voltage *voltage) +{ + unsigned vddm = readl(VDDMEMCTRL); + + /* setup new target voltage */ + vddm &= ~0x1F; + vddm |= vddm_voltage_to_bin(voltage->main_mV); + writel(vddm, VDDMEMCTRL); + + return 0; +} + +struct rail_ctrl { + signed char dcdc_en; /** bit number to manipulate DC/DC regulator, -1 if not exist */ + signed char lin_en; /** bit number to manipulate linear regulator, -1 if not exist */ + unsigned char linear; /** bit shift to reach linear offset */ + unsigned char step; /** voltage step in [mV] */ + signed char brwnout; /** bit number to manipulate brown out detector */ + unsigned base; /** base voltage in [mV] */ + void __iomem *reg; /** address to the reach corresponding register */ +}; + +static const struct rail_ctrl vddio_ctrl = { + .dcdc_en = 16, + .lin_en = -1, /* cannot be disabled */ + .linear = 12, + .step = 25, + .brwnout = 18, + .base = 2800, + .reg = (void*)VDDIOCTRL, +}; + +static const struct rail_ctrl vdda_ctrl = { + .dcdc_en = 16, + .lin_en = 17, + .linear = 12, + .step = 25, + .base = 1500, + .brwnout = 19, + .reg = (void*)VDDACTRL, +}; + +static const struct rail_ctrl vddd_ctrl = { + .dcdc_en = 20, + .lin_en = 21, + .linear = 16, + .step = 25, + .base = 800, + .brwnout = 23, + .reg = (void*)VDDDCTRL, +}; + +/** + * Setup one rail to a new voltage + * @param[in] c Info about the rail we must know here + * @param[in] v New settting + * @param[in] fv Current voltage + * @return 0 on success + */ +static int setup_one_rail(const struct rail_ctrl *c, const struct rail_voltage *v, unsigned fv) +{ + unsigned reg = readl(c->reg); + unsigned bo_val; + int lin_val; + + reg &= ~(1 << c->dcdc_en); /* always enable the DC/DC converter */ + bo_val = v->main_mV - v->guard_mV; + if (v->lin_mV == 0) { + /* disable linear regulator, use only DC/DC converter */ + if (c->lin_en != -1) + reg &= ~(1 << c->lin_en); /* disable linear regulator */ + lin_val = 0; + } else { + lin_val = v->lin_mV - v->main_mV; + reg |= (1 << c->lin_en); /* enable linear regulator */ + } + + /* create the new register content */ + reg |= (1 << c->brwnout); /* power down the brown out detector FIXME: Why? */ + reg |= DIV_ROUND_UP(v->main_mV - c->base, c->step); + reg |= DIV_ROUND_UP(bo_val, c->step) << 8; + reg |= (lin_val & 0x03) << c->linear; + + if (v->main_mV > fv) { + pr_debug("Going to increase voltage\n"); + writel(reg, c->reg); + } else { + pr_debug("Going to decrease voltage\n"); + writel(reg, c->reg); + } + + return 0; +} + +/** + * Setup a new voltage setting for the VDDIO rail + * @param[in] voltage New setting + * @return 0 on success + */ +int setup_vddio_voltage(const struct rail_voltage *voltage) +{ + return setup_one_rail(&vddio_ctrl, voltage, get_vddio()); +} + +/** + * Setup a new voltage setting for the VDDA rail + * @param[in] voltage New setting + * @return 0 on success + * + * @todo check for the linear regulator case the VDDIO rail is above the + * new target voltage of VDDA + */ +int setup_vdda_voltage(const struct rail_voltage *voltage) +{ + return setup_one_rail(&vdda_ctrl, voltage, get_vdda()); +} + +/** + * Setup a new voltage setting for the VDDD rail + * @param[in] voltage New setting + * @return 0 on success + * + * @todo check for the linear regulator case the VDDA rail is above the + * new target voltage of VDDD + */ +int setup_vddd_voltage(const struct rail_voltage *voltage) +{ + return setup_one_rail(&vddd_ctrl, voltage, get_vddd()); +} + +/** + * Set a current limit from the 5 V source into the 4.2 V rail + * @param[in] v Current value (refer manual for bit values) + */ +static void set_4p2_limit(unsigned v) +{ + unsigned reg = readl(POWER_5VCTRL) & ~(0x3f << 12); + if (v < 0x40) + writel(reg | (v << 12), POWER_5VCTRL); + else + pr_debug("4P2 limit too large\n"); +} + +/** + * Switch the 5V brown-out detection to the more reliable VBUSVALID method + * + * TODO: Due to the fact, the brown-out circuits can be disabled, we maybe + * could omit this switching + */ +static void use_vbusvalid(void) +{ +#if 0 + /* enable the VBUS comparator */ + writel(PWRUP_VBUS_CMPS, POWER_5VCTRL + 4); + /* VBUS threshold is 4.0 V */ + writel((readl(POWER_5VCTRL) & ~(0x7 << 8)) | (1 << 8), POWER_5VCTRL); + + /* VBUSVALID should be used */ + writel(VBUSVALID_5VDETECT, POWER_5VCTRL /*+ 4*/); +#else + writel(0x00000000, POWER_5VCTRL /*+ 4*/); +#endif +} + +/** + * Enable the 4.2 V linear regulator + */ +static void enable_4p2(void) +{ + unsigned u; + + /* enable the internal 4P2 logic */ + writel(readl(POWER_DCDC4P2) | ENABLE_4P2, POWER_DCDC4P2); + + /* enable 100 Ohm at 4.2 V as load */ + writel(ENABLE_LOAD, POWER_CHARGE + 4); /* Dangerous !!!!!! adds 180 mW */ + + /* start with a current limit into the 4P2 rail */ + set_4p2_limit(1); + + /* enable the 4.2 linear regulator, now it drives the 4P2 rail */ + writel(readl(POWER_DCDC4P2) | ENABLE_DCDC, POWER_DCDC4P2); + + /* increase the current limit up to 780 mA */ + for (u = 2; u < 0x40; u++) { + udelay(10); + set_4p2_limit(u); + } +} + +/** + * Tweak like a Chumby. + * + * Don't ask what we are doing here + */ +static void tweak_dcdc_converter(void) +{ + writel(SET_NEGLIMIT(0x5f) | /* FIXME */ + SET_POSLIMIT_BUCK(0x30), /* FIXME */ + POWER_DCLIMITS); + writel(TOGGLE_DIF | /* FIXME */ + EN_CM_HYST | /* FIXME */ + EN_DF_HYST | /* FIXME */ + RCSCALE_THRESH | /* FIXME */ + SET_EN_RCSCALE(3) | /* FIXME */ + SET_DC_R(2) | /* reset value */ + SET_DC_C(1), /* reset value */ + POWER_LOOPCTRL); + writel(EN_BATADJ | /* FIXME */ + PWDN_BATTBRNOUT | /* FIXME */ + SET_BRWNOUT_LVL(0xf), /* FIXME */ + POWER_BATTMONITOR); +} + +/** + * Switch on the DC/DC converter + */ +static void enable_dcdc(void) +{ + /* 85 % ???? */ + writel(readl(POWER_DCDC4P2) & ~0x1f, POWER_DCDC4P2); + + /* use 4.2 V regardless of the battery voltage */ + writel(readl(POWER_DCDC4P2) & ~(0xf << 28), POWER_DCDC4P2); + + /* disable the automatic XFER when 5V is lost */ + writel(DCDC_XFER, POWER_5VCTRL + 4); + + /* double the FETs */ + writel(DOUBLE_FETS, POWER_MINPWR + 4); + + tweak_dcdc_converter(); + + /* enable the DC/DC converter */ + writel(START_DCDC, POWER_5VCTRL + 4); + + /* disable the additional load */ + writel(ENABLE_LOAD, POWER_CHARGE + 8); + + /* do not load the battery (there is none) */ + writel(PWD_BATTCHRG, POWER_CHARGE + 4); +} + +/** + * Enable the DC/DC converter regardless of the power source + */ +int switch_to_dcdc(void) +{ + use_vbusvalid(); + enable_4p2(); + enable_dcdc(); + + return 0; +} + +/** + * Read the power source of a rail + * @param[in] reg Register setting + * @return Name of source as string + * + * This routine can be used for VDDA and VDDD + */ +static const char *discover_source(const unsigned reg) +{ + unsigned tst = reg & ((1 << 20) | (1 << 21)); + + switch (tst) { + case (1 << 20) | (1 << 21): + return "lin"; + case (1 << 20): + return "ext"; /* both internal sources are disabled */ + case (1 << 21): + return "both"; + } + + return "DC"; +} + +/** + * Read the power source of the VDDIO rail + * @param[in] reg Register setting + * @return Name of source as string + */ +static const char *discover_source_vddio(void) +{ + unsigned tst = readl(VDDIOCTRL) & (1 << 16); + if (tst == (1 << 16)) + return "lin"; + return "both"; +} + +void print_current_settings(void) +{ + unsigned mv, reg; + + reg = readl(POWER_STS); + printf("Woken up on: "); + if (reg & (1 << 29)) + printf("5V wall plug "); + if (reg & (1 << 28)) + printf("RTC "); + if (reg & (1 << 27)) + printf("Unknown #1 "); + if (reg & (1 << 26)) + printf("Unknown #2 "); + if (reg & (1 << 25)) + printf("Highlevel PSW "); + if (reg & (1 << 24)) + printf("Middlevel PSW "); + printf("\n"); + + reg = readl(POWER_5VCTRL); + if (reg & 0x1) { + printf("DC/DC converter is active.\n Switching frequency: "); + + reg = readl(POWER_MISC); + if (!(reg & 0x1)) + printf("24 MHz\n"); + else { + printf("(from PLL) "); + switch ((reg >> 4) & 0x7) { + case 0x00: + printf("ILLEGAL!"); + break; + case 0x01: + printf("20 MHz"); + break; + case 0x02: + printf("24 MHz"); + break; + case 0x03: + printf("19.2 MHz"); + break; + case 0x04: + printf("14.4 MHz"); + break; + case 0x05: + printf("18 MHz"); + break; + case 0x06: + printf("21.6 MHz"); + break; + case 0x07: + printf("17.28 MHz"); + break; + } + printf("\n"); + } + } + + mv = get_vddio(); + printf("Main VDDIO is %d.%d V, BO %d mV, Linear Offset %d mV\n", mv / 1000, mv - ((mv / 1000) * 1000), get_vddio_bo(), get_vddio_lin_offset()); + printf(" Source is: %s\n", discover_source_vddio()); + + mv = get_vddm(); + printf("Memory VDDM is %d.%d V\n", mv / 1000, mv - ((mv / 1000) * 1000)); + printf(" Source is: lin\n"); /* always */ + + mv = get_vdda(); + printf("Analogue VDDA is %d.%d V, BO %d mV, Linear Offset %d mV\n", mv / 1000, mv - ((mv / 1000) * 1000), get_vdda_bo(), get_vdda_lin_offset()); + printf(" Source is: %s\n", discover_source(readl(VDDACTRL) << 4)); + + mv = get_vddd(); + printf("Digital VDDD is %d.%d V, BO %d mV, Linear Offset %d mV\n", mv / 1000, mv - ((mv / 1000) * 1000), get_vddd_bo(), get_vddd_lin_offset()); + printf(" Source is: %s\n", discover_source(readl(VDDDCTRL))); +} |