diff options
author | Vijaya Kumar Kilari <vijay.kilari@stericsson.com> | 2011-05-30 16:38:32 +0530 |
---|---|---|
committer | said m bagheri <ebgheri@steludxu2848.(none)> | 2011-06-17 13:42:04 +0200 |
commit | 3d7540d58146ef26c78023620f3c5a0df532471a (patch) | |
tree | 0a8cfa5cc55fe6c8ed597a2f53527a6d3db046ae /arch | |
parent | e68e7db3952ae7298a82c2608e60231c7556bf65 (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-regulators.c | 52 | ||||
-rw-r--r-- | arch/arm/mach-ux500/clock-db5500.c | 95 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/prcmu-db5500.h | 41 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/prcmu.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-ux500/prcmu-db5500.c | 210 | ||||
-rw-r--r-- | arch/arm/mach-ux500/regulator-u5500.c | 17 | ||||
-rw-r--r-- | arch/arm/mach-ux500/regulator-u5500.h | 5 |
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 }; |