summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVijaya Kumar Kilari <vijay.kilari@stericsson.com>2011-05-30 16:38:32 +0530
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 15:15:32 +0200
commit1b0ff28a0a2392c75f4b6f7cf9cc2ef680399c5f (patch)
treeb652880a3a786e3457b33b3601b3a2ecae072faf
parentf89ebf3ef416dcdbe08e5ba97788a4587034b99c (diff)
U5500: Add support for PLL and EPOD Power mgmt
PLL and EPOD support added in PRCMU driver Regulator and clock framework driver updated ST-Ericsson Linux next: - ST-Ericsson ID: WP334772 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I134fe00df12788476e840a9c3f44dc0e39570fa9 Signed-off-by: Vijaya Kumar K <vijay.kilari@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/23962 Reviewed-by: Mattias NILSSON <mattias.i.nilsson@stericsson.com> Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/board-u5500-regulators.c52
-rw-r--r--arch/arm/mach-ux500/clock-db5500.c95
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-db5500.h41
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu.h9
-rw-r--r--arch/arm/mach-ux500/prcmu-db5500.c210
-rw-r--r--arch/arm/mach-ux500/regulator-u5500.c17
-rw-r--r--arch/arm/mach-ux500/regulator-u5500.h5
7 files changed, 313 insertions, 116 deletions
diff --git a/arch/arm/mach-ux500/board-u5500-regulators.c b/arch/arm/mach-ux500/board-u5500-regulators.c
index d4f6022b9cc..ce9586aadfe 100644
--- a/arch/arm/mach-ux500/board-u5500-regulators.c
+++ b/arch/arm/mach-ux500/board-u5500-regulators.c
@@ -164,6 +164,37 @@ static struct regulator_consumer_supply u5500_vape_consumers[] = {
REGULATOR_SUPPLY("v-uart", "uart3"),
};
+static struct regulator_consumer_supply u5500_sga_consumers[] = {
+ REGULATOR_SUPPLY("debug", "reg-virt-consumer.0"),
+};
+
+static struct regulator_consumer_supply u5500_hva_consumers[] = {
+ REGULATOR_SUPPLY("debug", "reg-virt-consumer.1"),
+};
+
+static struct regulator_consumer_supply u5500_sia_consumers[] = {
+ REGULATOR_SUPPLY("debug", "reg-virt-consumer.2"),
+};
+
+static struct regulator_consumer_supply u5500_disp_consumers[] = {
+ REGULATOR_SUPPLY("debug", "reg-virt-consumer.3"),
+};
+
+static struct regulator_consumer_supply u5500_esram12_consumers[] = {
+ REGULATOR_SUPPLY("debug", "reg-virt-consumer.6"),
+};
+
+#define U5500_REGULATOR_SWITCH(lower, upper) \
+[U5500_REGULATOR_SWITCH_##upper] = (struct regulator_init_data []) { \
+{ \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ }, \
+ .consumer_supplies = u5500_##lower##_consumers, \
+ .num_consumer_supplies = ARRAY_SIZE(u5500_##lower##_consumers),\
+} \
+}
+
static struct regulator_init_data *
u5500_regulator_init_data[U5500_NUM_REGULATORS] __initdata = {
[U5500_REGULATOR_VAPE] = (struct regulator_init_data []) {
@@ -175,11 +206,28 @@ u5500_regulator_init_data[U5500_NUM_REGULATORS] __initdata = {
.num_consumer_supplies = ARRAY_SIZE(u5500_vape_consumers),
}
},
+ U5500_REGULATOR_SWITCH(sga, SGA),
+ U5500_REGULATOR_SWITCH(hva, HVA),
+ U5500_REGULATOR_SWITCH(sia, SIA),
+ U5500_REGULATOR_SWITCH(disp, DISP),
+ U5500_REGULATOR_SWITCH(esram12, ESRAM12),
};
+static void __init u5500_regulators_init_debug(void)
+{
+ const char data[] = "debug";
+ int i;
+
+ for (i = 0; i < 10; i++)
+ platform_device_register_data(NULL, "reg-virt-consumer", i,
+ data, sizeof(data));
+}
+
void __init u5500_regulators_init(void)
{
+ u5500_regulators_init_debug();
+
platform_device_register_data(NULL, "u5500-regulators", -1,
- u5500_regulator_init_data,
- sizeof(u5500_regulator_init_data));
+ u5500_regulator_init_data,
+ sizeof(u5500_regulator_init_data));
}
diff --git a/arch/arm/mach-ux500/clock-db5500.c b/arch/arm/mach-ux500/clock-db5500.c
index f1e68441fae..a6463ce707e 100644
--- a/arch/arm/mach-ux500/clock-db5500.c
+++ b/arch/arm/mach-ux500/clock-db5500.c
@@ -31,27 +31,10 @@
#include "prcmu-regs-db5500.h"
static DEFINE_MUTEX(sysclk_mutex);
+static DEFINE_MUTEX(pll_mutex);
static DEFINE_MUTEX(ab_ulpclk_mutex);
static DEFINE_MUTEX(audioclk_mutex);
-/* PLL operations. */
-
-static int clk_pllsrc_enable(struct clk *clk)
-{
- /* To enable pll */
- return 0;
-}
-
-static void clk_pllsrc_disable(struct clk *clk)
-{
- /* To disable pll */
-}
-
-static struct clkops pll_clk_ops = {
- .enable = clk_pllsrc_enable,
- .disable = clk_pllsrc_disable,
-};
-
/* SysClk operations. */
static int request_sysclk(bool enable)
@@ -59,7 +42,7 @@ static int request_sysclk(bool enable)
static int requests;
if ((enable && (requests++ == 0)) || (!enable && (--requests == 0)))
- return prcmu_request_clock(DB5500_PRCMU_SYSCLK, enable);
+ return prcmu_request_clock(PRCMU_SYSCLK, enable);
return 0;
}
@@ -311,17 +294,23 @@ static struct clkops clkout1_ops = {
static struct clk soc0_pll = {
.name = "soc0_pll",
- .ops = &pll_clk_ops,
+ .ops = &prcmu_clk_ops,
+ .mutex = &pll_mutex,
+ .cg_sel = PRCMU_PLLSOC0,
};
static struct clk soc1_pll = {
.name = "soc1_pll",
- .ops = &pll_clk_ops,
+ .ops = &prcmu_clk_ops,
+ .mutex = &pll_mutex,
+ .cg_sel = PRCMU_PLLSOC1,
};
static struct clk ddr_pll = {
.name = "ddr_pll",
- .ops = &pll_clk_ops,
+ .ops = &prcmu_clk_ops,
+ .mutex = &pll_mutex,
+ .cg_sel = PRCMU_PLLDDR,
};
static struct clk ulp38m4 = {
@@ -413,29 +402,29 @@ static struct clk audioclk = {
.parents = audioclk_parents,
};
-static DEF_PRCMU_CLK(dmaclk, DB5500_PRCMU_DMACLK, 200000000);
-static DEF_PRCMU_CLK(b2r2clk, DB5500_PRCMU_B2R2CLK, 200000000);
-static DEF_PRCMU_CLK(sgaclk, DB5500_PRCMU_SGACLK, 199900000);
-static DEF_PRCMU_CLK(uartclk, DB5500_PRCMU_UARTCLK, 36360000);
-static DEF_PRCMU_CLK(msp02clk, DB5500_PRCMU_MSP02CLK, 13000000);
-static DEF_PRCMU_CLK(i2cclk, DB5500_PRCMU_I2CCLK, 24000000);
-static DEF_PRCMU_CLK(irdaclk, DB5500_PRCMU_IRDACLK, 48000000);
-static DEF_PRCMU_CLK(irrcclk, DB5500_PRCMU_IRRCCLK, 48000000);
-static DEF_PRCMU_CLK(rngclk, DB5500_PRCMU_RNGCLK, 26000000);
-static DEF_PRCMU_CLK(pwmclk, DB5500_PRCMU_PWMCLK, 26000000);
-static DEF_PRCMU_CLK(sdmmcclk, DB5500_PRCMU_SDMMCCLK, 100000000);
-static DEF_PRCMU_CLK(per1clk, DB5500_PRCMU_PER1CLK, 133330000);
-static DEF_PRCMU_CLK(per2clk, DB5500_PRCMU_PER2CLK, 133330000);
-static DEF_PRCMU_CLK(per3clk, DB5500_PRCMU_PER3CLK, 133330000);
-static DEF_PRCMU_CLK(per5clk, DB5500_PRCMU_PER5CLK, 133330000);
-static DEF_PRCMU_CLK(per6clk, DB5500_PRCMU_PER6CLK, 133330000);
-static DEF_PRCMU_CLK(hdmiclk, DB5500_PRCMU_HDMICLK, 26000000);
-static DEF_PRCMU_CLK(apeatclk, DB5500_PRCMU_APEATCLK, 200000000);
-static DEF_PRCMU_CLK(apetraceclk, DB5500_PRCMU_APETRACECLK, 266000000);
-static DEF_PRCMU_CLK(mcdeclk, DB5500_PRCMU_MCDECLK, 160000000);
-static DEF_PRCMU_CLK(tvclk, DB5500_PRCMU_TVCLK, 40000000);
-static DEF_PRCMU_CLK(dsialtclk, DB5500_PRCMU_DSIALTCLK, 400000000);
-static DEF_PRCMU_CLK(timclk, DB5500_PRCMU_TIMCLK, 3250000);
+static DEF_PRCMU_CLK(dmaclk, PRCMU_DMACLK, 200000000);
+static DEF_PRCMU_CLK(b2r2clk, PRCMU_B2R2CLK, 200000000);
+static DEF_PRCMU_CLK(sgaclk, PRCMU_SGACLK, 199900000);
+static DEF_PRCMU_CLK(uartclk, PRCMU_UARTCLK, 36360000);
+static DEF_PRCMU_CLK(msp02clk, PRCMU_MSP02CLK, 13000000);
+static DEF_PRCMU_CLK(i2cclk, PRCMU_I2CCLK, 24000000);
+static DEF_PRCMU_CLK(irdaclk, PRCMU_IRDACLK, 48000000);
+static DEF_PRCMU_CLK(irrcclk, PRCMU_IRRCCLK, 48000000);
+static DEF_PRCMU_CLK(rngclk, PRCMU_RNGCLK, 26000000);
+static DEF_PRCMU_CLK(pwmclk, PRCMU_PWMCLK, 26000000);
+static DEF_PRCMU_CLK(sdmmcclk, PRCMU_SDMMCCLK, 100000000);
+static DEF_PRCMU_CLK(per1clk, PRCMU_PER1CLK, 133330000);
+static DEF_PRCMU_CLK(per2clk, PRCMU_PER2CLK, 133330000);
+static DEF_PRCMU_CLK(per3clk, PRCMU_PER3CLK, 133330000);
+static DEF_PRCMU_CLK(per5clk, PRCMU_PER5CLK, 133330000);
+static DEF_PRCMU_CLK(per6clk, PRCMU_PER6CLK, 133330000);
+static DEF_PRCMU_CLK(hdmiclk, PRCMU_HDMICLK, 26000000);
+static DEF_PRCMU_CLK(apeatclk, PRCMU_APEATCLK, 200000000);
+static DEF_PRCMU_CLK(apetraceclk, PRCMU_APETRACECLK, 266000000);
+static DEF_PRCMU_CLK(mcdeclk, PRCMU_MCDECLK, 160000000);
+static DEF_PRCMU_CLK(tvclk, PRCMU_TVCLK, 40000000);
+static DEF_PRCMU_CLK(dsialtclk, PRCMU_DSIALTCLK, 400000000);
+static DEF_PRCMU_CLK(timclk, PRCMU_TIMCLK, 3250000);
/* PRCC PClocks */
@@ -796,27 +785,11 @@ static void __init db5500_boot_clk_enable(void)
}
}
-static int db5500_prcmu_clk_enable(struct clk *clk)
-{
- return prcmu_request_clock(clk->cg_sel, true);
-}
-
-static void db5500_prcmu_clk_disable(struct clk *clk)
-{
- if (prcmu_request_clock(clk->cg_sel, false)) {
- pr_err("clock: %s failed to disable %s.\n", __func__,
- clk->name);
- }
-}
-
int __init db5500_clk_init(void)
{
sysclk_ops.enable = NULL;
sysclk_ops.disable = NULL;
- prcmu_clk_ops.enable = db5500_prcmu_clk_enable;
- prcmu_clk_ops.disable = db5500_prcmu_clk_disable;
-
if (ux500_is_svp()) {
prcmu_clk_ops.enable = NULL;
prcmu_clk_ops.disable = NULL;
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-db5500.h b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h
index dc1f1fa8bb8..0d26f72230e 100644
--- a/arch/arm/mach-ux500/include/mach/prcmu-db5500.h
+++ b/arch/arm/mach-ux500/include/mach/prcmu-db5500.h
@@ -8,37 +8,6 @@
#ifndef __MACH_PRCMU_U5500_H
#define __MACH_PRCMU_U5500_H
-/*
- * Clock identifiers.
- */
-enum db5500_prcmu_clock {
- DB5500_PRCMU_SGACLK,
- DB5500_PRCMU_UARTCLK,
- DB5500_PRCMU_MSP02CLK,
- DB5500_PRCMU_I2CCLK,
- DB5500_PRCMU_SDMMCCLK,
- DB5500_PRCMU_PER1CLK,
- DB5500_PRCMU_PER2CLK,
- DB5500_PRCMU_PER3CLK,
- DB5500_PRCMU_PER5CLK,
- DB5500_PRCMU_PER6CLK,
- DB5500_PRCMU_PWMCLK,
- DB5500_PRCMU_IRDACLK,
- DB5500_PRCMU_IRRCCLK,
- DB5500_PRCMU_HDMICLK,
- DB5500_PRCMU_APEATCLK,
- DB5500_PRCMU_APETRACECLK,
- DB5500_PRCMU_MCDECLK,
- DB5500_PRCMU_DSIALTCLK,
- DB5500_PRCMU_DMACLK,
- DB5500_PRCMU_B2R2CLK,
- DB5500_PRCMU_TVCLK,
- DB5500_PRCMU_RNGCLK,
- DB5500_PRCMU_NUM_REG_CLOCKS,
- DB5500_PRCMU_SYSCLK = DB5500_PRCMU_NUM_REG_CLOCKS,
- DB5500_PRCMU_TIMCLK,
-};
-
#ifdef CONFIG_UX500_SOC_DB5500
void db5500_prcmu_early_init(void);
@@ -56,16 +25,6 @@ static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
return 0;
}
-static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
-{
- return 0;
-}
-
-static inline int prcmu_request_clock(u8 clock, bool enable)
-{
- return db5500_prcmu_request_clock(clock, enable);
-}
-
static inline void prcmu_system_reset(u16 reset_code) {}
#else /* !CONFIG_UX500_SOC_DB5500 */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h
index bc9defd3086..4e7c00a0b28 100644
--- a/arch/arm/mach-ux500/include/mach/prcmu.h
+++ b/arch/arm/mach-ux500/include/mach/prcmu.h
@@ -69,8 +69,6 @@ enum prcmu_wakeup_index {
#define DB5500_EPOD_ID_HVA (DB5500_EPOD_ID_BASE + 1)
#define DB5500_EPOD_ID_SIA (DB5500_EPOD_ID_BASE + 2)
#define DB5500_EPOD_ID_DISP (DB5500_EPOD_ID_BASE + 3)
-#define DB5500_EPOD_ID_B2R2 (DB5500_EPOD_ID_BASE + 4)
-#define DB5500_EPOD_ID_MODEM (DB5500_EPOD_ID_BASE + 5)
#define DB5500_EPOD_ID_ESRAM12 (DB5500_EPOD_ID_BASE + 6)
#define DB5500_NUM_EPOD_ID 7
@@ -143,10 +141,15 @@ enum prcmu_clock {
PRCMU_SSPCLK,
PRCMU_RNGCLK,
PRCMU_UICCCLK,
+ PRCMU_PWMCLK,
+ PRCMU_IRDACLK,
+ PRCMU_IRRCCLK,
PRCMU_NUM_REG_CLOCKS,
PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
- PRCMU_PLLSOC1,
PRCMU_TIMCLK,
+ PRCMU_PLLSOC0,
+ PRCMU_PLLSOC1,
+ PRCMU_PLLDDR,
};
/**
diff --git a/arch/arm/mach-ux500/prcmu-db5500.c b/arch/arm/mach-ux500/prcmu-db5500.c
index 7e7b02d2e8e..dde05c42d3f 100644
--- a/arch/arm/mach-ux500/prcmu-db5500.c
+++ b/arch/arm/mach-ux500/prcmu-db5500.c
@@ -66,6 +66,19 @@
#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
+/* Mailbox 2 REQs */
+#define PRCM_REQ_MB2_EPOD_CLIENT (PRCM_REQ_MB2 + 0x0)
+#define PRCM_REQ_MB2_EPOD_STATE (PRCM_REQ_MB2 + 0x1)
+#define PRCM_REQ_MB2_CLK_CLIENT (PRCM_REQ_MB2 + 0x2)
+#define PRCM_REQ_MB2_CLK_STATE (PRCM_REQ_MB2 + 0x3)
+#define PRCM_REQ_MB2_PLL_CLIENT (PRCM_REQ_MB2 + 0x4)
+#define PRCM_REQ_MB2_PLL_STATE (PRCM_REQ_MB2 + 0x5)
+
+/* Mailbox 2 ACKs */
+#define PRCM_ACK_MB2_EPOD_STATUS (PRCM_ACK_MB2 + 0x2)
+#define PRCM_ACK_MB2_CLK_STATUS (PRCM_ACK_MB2 + 0x6)
+#define PRCM_ACK_MB2_PLL_STATUS (PRCM_ACK_MB2 + 0xA)
+
enum mb_return_code {
RC_SUCCESS,
RC_FAIL,
@@ -81,12 +94,30 @@ enum mb0_header {
AMB0H_WAKE_UP = 1,
};
+/* Mailbox 2 headers. */
+enum mb2_header {
+ MB2H_EPOD_REQUEST = 1,
+ MB2H_CLK_REQUEST,
+ MB2H_PLL_REQUEST,
+};
+
/* Mailbox 5 headers. */
enum mb5_header {
MB5H_I2C_WRITE = 1,
MB5H_I2C_READ,
};
+enum epod_state {
+ EPOD_OFF,
+ EPOD_ON,
+};
+enum db5500_prcmu_pll {
+ DB5500_PLL_SOC0,
+ DB5500_PLL_SOC1,
+ DB5500_PLL_DDR,
+ DB5500_NUM_PLL_ID,
+};
+
/* Request mailbox 5 fields. */
#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
@@ -135,6 +166,26 @@ static struct {
} mb0_transfer;
/*
+ * mb2_transfer - state needed for mailbox 2 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @req: Request data that need to persist between requests.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 epod_states[DB5500_NUM_EPOD_ID];
+ u8 pll_states[DB5500_NUM_PLL_ID];
+ } req;
+ struct {
+ u8 header;
+ u8 status;
+ } ack;
+} mb2_transfer;
+
+/*
* mb5_transfer - state needed for mailbox 5 communication.
* @lock: The transaction lock.
* @work: The transaction completion structure.
@@ -160,10 +211,10 @@ struct clk_mgt {
static DEFINE_SPINLOCK(clk_mgt_lock);
-#define CLK_MGT_ENTRY(_name)[DB5500_PRCMU_##_name] = { \
+#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { \
(DB5500_PRCM_##_name##_MGT), 0 \
}
-static struct clk_mgt clk_mgt[DB5500_PRCMU_NUM_REG_CLOCKS] = {
+static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
CLK_MGT_ENTRY(SGACLK),
CLK_MGT_ENTRY(UARTCLK),
CLK_MGT_ENTRY(MSP02CLK),
@@ -229,21 +280,72 @@ static int request_reg_clock(u8 clock, bool enable)
return 0;
}
+/*
+ * request_pll() - Request for a pll to be enabled or disabled.
+ * @pll: The pll for which the request is made.
+ * @enable: Whether the clock should be enabled (true) or disabled (false).
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+static int request_pll(u8 pll, bool enable)
+{
+ int r = 0;
+
+ BUG_ON(pll >= DB5500_NUM_PLL_ID);
+ mutex_lock(&mb2_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
+ cpu_relax();
+
+ mb2_transfer.req.pll_states[pll] = enable;
+
+ /* fill in mailbox */
+ writeb(pll, PRCM_REQ_MB2_PLL_CLIENT);
+ writeb(mb2_transfer.req.pll_states[pll], PRCM_REQ_MB2_PLL_STATE);
+
+ writeb(MB2H_PLL_REQUEST, PRCM_REQ_MB2_HEADER);
+
+ writel(MBOX_BIT(2), _PRCMU_BASE + PRCM_MBOX_CPU_SET);
+ if (!wait_for_completion_timeout(&mb2_transfer.work,
+ msecs_to_jiffies(500))) {
+ pr_err("prcmu: set_pll() failed.\n"
+ "prcmu: Please check your firmware version.\n");
+ r = -EIO;
+ WARN(1, "Failed to set pll");
+ goto unlock_and_return;
+ }
+ if (mb2_transfer.ack.status != RC_SUCCESS ||
+ mb2_transfer.ack.header != MB2H_PLL_REQUEST)
+ r = -EIO;
+
+unlock_and_return:
+ mutex_unlock(&mb2_transfer.lock);
+
+ return r;
+}
+
/**
- * db5500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
+ * prcmu_request_clock() - Request for a clock to be enabled or disabled.
* @clock: The clock for which the request is made.
* @enable: Whether the clock should be enabled (true) or disabled (false).
*
* This function should only be used by the clock implementation.
* Do not use it from any other place!
*/
-int db5500_prcmu_request_clock(u8 clock, bool enable)
+int prcmu_request_clock(u8 clock, bool enable)
{
- if (clock < DB5500_PRCMU_NUM_REG_CLOCKS)
+ if (clock < PRCMU_NUM_REG_CLOCKS)
return request_reg_clock(clock, enable);
- else if (clock == DB5500_PRCMU_TIMCLK)
+ else if (clock == PRCMU_TIMCLK)
return request_timclk(enable);
- else if (clock == DB5500_PRCMU_SYSCLK)
+ else if (clock == PRCMU_PLLSOC0)
+ return request_pll(DB5500_PLL_SOC0, enable);
+ else if (clock == PRCMU_PLLSOC1)
+ return request_pll(DB5500_PLL_SOC1, enable);
+ else if (clock == PRCMU_PLLDDR)
+ return request_pll(DB5500_PLL_DDR, enable);
+ else if (clock == PRCMU_SYSCLK)
return -EINVAL;
else
return -EINVAL;
@@ -395,7 +497,7 @@ int db5500_prcmu_disable_dsipll(void)
writel(PRCMU_DISABLE_PLLDSI, _PRCMU_BASE + PRCM_PLLDSI_ENABLE);
/* Disable escapeclock */
writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV,
- _PRCMU_BASE + PRCM_DSITVCLK_DIV);
+ _PRCMU_BASE + PRCM_DSITVCLK_DIV);
return 0;
}
@@ -421,6 +523,72 @@ static void ack_dbb_wakeup(void)
spin_unlock_irqrestore(&mb0_transfer.lock, flags);
}
+int prcmu_set_epod(u16 epod_id, u8 epod_state)
+{
+ int r = 0;
+ bool ram_retention = false;
+
+ /* check argument */
+ BUG_ON(epod_id < DB5500_EPOD_ID_BASE);
+ BUG_ON(epod_state > EPOD_STATE_ON);
+
+ epod_id &= 0xFF;
+ BUG_ON(epod_id > DB5500_NUM_EPOD_ID);
+
+ /* TODO: FW does not take retention for ESRAM12?
+ set flag if retention is possible */
+ switch (epod_id) {
+ case DB5500_EPOD_ID_ESRAM12:
+ ram_retention = true;
+ break;
+ }
+
+ /* check argument */
+ /* BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention); */
+
+ /* get lock */
+ mutex_lock(&mb2_transfer.lock);
+
+ /* wait for mailbox */
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
+ cpu_relax();
+
+ /* PRCMU FW can only handle on or off */
+ if (epod_state == EPOD_STATE_ON)
+ mb2_transfer.req.epod_states[epod_id] = EPOD_ON;
+ else if (epod_state == EPOD_STATE_OFF)
+ mb2_transfer.req.epod_states[epod_id] = EPOD_OFF;
+ else {
+ r = -EINVAL;
+ goto unlock_and_return;
+ }
+
+ /* fill in mailbox */
+ writeb(epod_id, PRCM_REQ_MB2_EPOD_CLIENT);
+ writeb(mb2_transfer.req.epod_states[epod_id], PRCM_REQ_MB2_EPOD_STATE);
+
+ writeb(MB2H_EPOD_REQUEST, PRCM_REQ_MB2_HEADER);
+
+ writel(MBOX_BIT(2), _PRCMU_BASE + PRCM_MBOX_CPU_SET);
+
+ if (!wait_for_completion_timeout(&mb2_transfer.work,
+ msecs_to_jiffies(500))) {
+ pr_err("prcmu: set_epod() failed.\n"
+ "prcmu: Please check your firmware version.\n");
+ r = -EIO;
+ WARN(1, "Failed to set epod");
+ goto unlock_and_return;
+ }
+
+ if (mb2_transfer.ack.status != RC_SUCCESS ||
+ mb2_transfer.ack.header != MB2H_EPOD_REQUEST)
+ r = -EIO;
+
+unlock_and_return:
+ mutex_unlock(&mb2_transfer.lock);
+ return r;
+}
+
static inline void print_unknown_header_warning(u8 n, u8 header)
{
pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
@@ -454,7 +622,28 @@ static bool read_mailbox_1(void)
static bool read_mailbox_2(void)
{
+ u8 header;
+
+ header = readb(PRCM_ACK_MB2_HEADER);
+ mb2_transfer.ack.header = header;
+ switch (header) {
+ case MB2H_EPOD_REQUEST:
+ mb2_transfer.ack.status = readb(PRCM_ACK_MB2_EPOD_STATUS);
+ break;
+ case MB2H_CLK_REQUEST:
+ mb2_transfer.ack.status = readb(PRCM_ACK_MB2_CLK_STATUS);
+ break;
+ case MB2H_PLL_REQUEST:
+ mb2_transfer.ack.status = readb(PRCM_ACK_MB2_PLL_STATUS);
+ break;
+ default:
+ writel(MBOX_BIT(2), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
+ pr_err("prcmu: Wrong ACK received for MB2 request \n");
+ return false;
+ break;
+ }
writel(MBOX_BIT(2), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
+ complete(&mb2_transfer.work);
return false;
}
@@ -481,13 +670,14 @@ static bool read_mailbox_5(void)
case MB5H_I2C_WRITE:
mb5_transfer.ack.header = header;
mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
+ writel(MBOX_BIT(5), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
complete(&mb5_transfer.work);
break;
default:
+ writel(MBOX_BIT(5), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
print_unknown_header_warning(5, header);
break;
}
- writel(MBOX_BIT(5), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
return false;
}
@@ -545,7 +735,9 @@ void __init db5500_prcmu_early_init(void)
{
tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
spin_lock_init(&mb0_transfer.lock);
+ mutex_init(&mb2_transfer.lock);
mutex_init(&mb5_transfer.lock);
+ init_completion(&mb2_transfer.work);
init_completion(&mb5_transfer.work);
}
diff --git a/arch/arm/mach-ux500/regulator-u5500.c b/arch/arm/mach-ux500/regulator-u5500.c
index 513a7763dbc..4aca065d6e8 100644
--- a/arch/arm/mach-ux500/regulator-u5500.c
+++ b/arch/arm/mach-ux500/regulator-u5500.c
@@ -16,6 +16,18 @@
#include "regulator-ux500.h"
#include "regulator-u5500.h"
+#define U5500_REGULATOR_SWITCH(_name, reg) \
+ [U5500_REGULATOR_SWITCH_##reg] = { \
+ .desc = { \
+ .name = _name, \
+ .id = U5500_REGULATOR_SWITCH_##reg, \
+ .ops = &ux500_regulator_switch_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ .epod_id = DB5500_EPOD_ID_##reg, \
+}
+
static struct u8500_regulator_info
u5500_regulator_info[U5500_NUM_REGULATORS] = {
[U5500_REGULATOR_VAPE] = {
@@ -27,6 +39,11 @@ u5500_regulator_info[U5500_NUM_REGULATORS] = {
.owner = THIS_MODULE,
},
},
+ U5500_REGULATOR_SWITCH("u5500-sga", SGA),
+ U5500_REGULATOR_SWITCH("u5500-hva", HVA),
+ U5500_REGULATOR_SWITCH("u5500-sia", SIA),
+ U5500_REGULATOR_SWITCH("u5500-disp", DISP),
+ U5500_REGULATOR_SWITCH("u5500-esram12", ESRAM12),
};
static int __devinit u5500_regulator_probe(struct platform_device *pdev)
diff --git a/arch/arm/mach-ux500/regulator-u5500.h b/arch/arm/mach-ux500/regulator-u5500.h
index 2c363096d12..cf3eeed9366 100644
--- a/arch/arm/mach-ux500/regulator-u5500.h
+++ b/arch/arm/mach-ux500/regulator-u5500.h
@@ -9,6 +9,11 @@
enum u5500_regulator_id {
U5500_REGULATOR_VAPE,
+ U5500_REGULATOR_SWITCH_SGA,
+ U5500_REGULATOR_SWITCH_HVA,
+ U5500_REGULATOR_SWITCH_SIA,
+ U5500_REGULATOR_SWITCH_DISP,
+ U5500_REGULATOR_SWITCH_ESRAM12,
U5500_NUM_REGULATORS
};