summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Beisert <jbe@pengutronix.de>2011-06-23 19:34:58 +0200
committerRobert Schwebel <r.schwebel@pengutronix.de>2011-06-24 14:25:57 +0200
commit03394c3f85b3e6f66794401d913f03e3f75b8985 (patch)
tree67f3e0129e0833386db286eea9ae3c875bc7543b
parentfac880fb951cf744dcf01f2db94c99c493588599 (diff)
downloadbarebox-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/Makefile2
-rw-r--r--arch/arm/mach-mxs/bootlets/pmic-imx23.c31
-rw-r--r--arch/arm/mach-mxs/include/mach/imx23-regs.h1
-rw-r--r--arch/arm/mach-mxs/include/mach/pmic-imx23.h30
-rw-r--r--arch/arm/mach-mxs/pmic-imx23.c685
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)));
+}