summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Murthy <arun.murthy@stericsson.com>2011-10-04 12:21:07 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 10:59:20 +0200
commit895997faaaff7ab9fb3f19cf9f6c981e5b337bc6 (patch)
tree16ecccceaa6473febfa2eae9e23ae69fd608ca2f
parentf6a20dd13d85196d2fd4f5a00c393c164bd99a62 (diff)
mfd: db5500-prcmu: add modem_req and modem_rel API
When APE has some messages to send to modem, APE will issue a modem_req and then start sending the messages to modem. Once APE is done with sending messages to modem, it will send modem_rel to free the ape-modem communication protocol. This protocol will be used to achieve APE-Modem power management. ST-Ericsson Linux next: NA ST-Ericsson ID: 350108 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I331654967ddd4b77818f7f4a8427ea8c63fd90a8 Signed-off-by: Arun Murthy <arun.murthy@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32722 Reviewed-by: QATOOLS Reviewed-by: Rabin VINCENT <rabin.vincent@stericsson.com>
-rw-r--r--drivers/mfd/db5500-prcmu-regs.h6
-rw-r--r--drivers/mfd/db5500-prcmu.c71
-rw-r--r--include/linux/mfd/db5500-prcmu.h15
-rw-r--r--include/linux/mfd/dbx500-prcmu.h2
4 files changed, 89 insertions, 5 deletions
diff --git a/drivers/mfd/db5500-prcmu-regs.h b/drivers/mfd/db5500-prcmu-regs.h
index e8aa2901478..30234a86263 100644
--- a/drivers/mfd/db5500-prcmu-regs.h
+++ b/drivers/mfd/db5500-prcmu-regs.h
@@ -123,4 +123,10 @@
#define PRCM_RESOUTN_SET_OFFSET 0x214
#define PRCM_RESOUTN_CLR_OFFSET 0x218
+/* APE - Modem Registers */
+#define PRCM_HOSTACCESS_REQ 0x334
+/* APE - Modem register bit maipulation */
+#define PRCM_HOSTACCESS_REQ_BIT BIT(0)
+#define PRCM_APE_ACK 0x49c
+#define PRCM_APE_ACK_BIT 0x01
#endif
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
index 4ab200498c5..3f1e481fb11 100644
--- a/drivers/mfd/db5500-prcmu.c
+++ b/drivers/mfd/db5500-prcmu.c
@@ -362,12 +362,14 @@ static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = {
* @lock The transaction lock.
* @dbb_irqs_lock lock used for (un)masking DBB wakeup interrupts
* @mask_work: Work structure used for (un)masking wakeup interrupts.
+ * @ac_wake_lock: mutex to lock modem_req and modem_rel
* @req: Request data that need to persist between requests.
*/
static struct {
spinlock_t lock;
spinlock_t dbb_irqs_lock;
struct work_struct mask_work;
+ struct mutex ac_wake_lock;
struct {
u32 dbb_irqs;
u32 dbb_wakeups;
@@ -532,9 +534,73 @@ static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
CLK_MGT_ENTRY(SVACLK, false),
};
-bool db5500_prcmu_is_ac_wake_requested(void)
+static atomic_t modem_req_state = ATOMIC_INIT(0);
+
+bool db5500_prcmu_is_modem_requested(void)
{
- return false;
+ return (atomic_read(&modem_req_state) != 0);
+}
+
+/**
+ * prcmu_modem_req - APE requests Modem to wake up
+ *
+ * Whenever APE wants to send message to the modem, it will have to call this
+ * function to make sure that modem is awake.
+ */
+void prcmu_modem_req(void)
+{
+ u32 val;
+
+ mutex_lock(&mb0_transfer.ac_wake_lock);
+
+ val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+ if (val & PRCM_HOSTACCESS_REQ_BIT)
+ goto unlock_and_return;
+
+ writel((val | PRCM_HOSTACCESS_REQ_BIT),
+ (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+ atomic_set(&modem_req_state, 1);
+
+unlock_and_return:
+ mutex_unlock(&mb0_transfer.ac_wake_lock);
+
+}
+
+/**
+ * prcmu_modem_rel - APE has no more messages to send and hence releases modem.
+ *
+ * APE to Modem communication is initiated by modem_req and once the
+ * communication is completed, APE sends modem_rel to complete the protocol.
+ */
+void prcmu_modem_rel(void)
+{
+ u32 val;
+
+ mutex_lock(&mb0_transfer.ac_wake_lock);
+
+ val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+ if (!(val & PRCM_HOSTACCESS_REQ_BIT))
+ goto unlock_and_return;
+
+ writel((val & ~PRCM_HOSTACCESS_REQ_BIT),
+ (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+ atomic_set(&modem_req_state, 0);
+
+unlock_and_return:
+ mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+/**
+ * prcm_ape_ack - send an acknowledgement to modem
+ *
+ * On ape receiving ape_req, APE will have to acknowledge for the interrupt
+ * received. This function will send the acknowledgement by writing to the
+ * prcmu register and an interrupt is trigerred to modem.
+ */
+void prcmu_ape_ack(void)
+{
+ writel(PRCM_APE_ACK_BIT, (_PRCMU_BASE + PRCM_APE_ACK));
}
/**
@@ -1933,6 +1999,7 @@ void __init db5500_prcmu_early_init(void)
tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
spin_lock_init(&mb0_transfer.lock);
spin_lock_init(&mb0_transfer.dbb_irqs_lock);
+ mutex_init(&mb0_transfer.ac_wake_lock);
mutex_init(&mb1_transfer.lock);
init_completion(&mb1_transfer.work);
mutex_init(&mb2_transfer.lock);
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
index ffbd415e6c7..8b8470cb24e 100644
--- a/include/linux/mfd/db5500-prcmu.h
+++ b/include/linux/mfd/db5500-prcmu.h
@@ -27,7 +27,12 @@ int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
int db5500_prcmu_config_esram0_deep_sleep(u8 state);
void db5500_prcmu_system_reset(u16 reset_code);
u16 db5500_prcmu_get_reset_code(void);
-bool db5500_prcmu_is_ac_wake_requested(void);
+#ifdef CONFIG_UX500_SOC_DB5500
+void prcmu_modem_req(void);
+void prcmu_modem_rel(void);
+void prcmu_ape_ack(void);
+#endif
+bool db5500_prcmu_is_modem_requested(void);
int db5500_prcmu_set_arm_opp(u8 opp);
int db5500_prcmu_get_arm_opp(void);
int db5500_prcmu_set_ape_opp(u8 opp);
@@ -136,11 +141,17 @@ static inline u16 db5500_prcmu_get_reset_code(void)
return 0;
}
-static inline bool db5500_prcmu_is_ac_wake_requested(void)
+static inline bool db5500_prcmu_is_modem_requested(void)
{
return 0;
}
+#ifdef CONFIG_UX500_SOC_DB5500
+static void prcmu_ape_ack(void) {}
+static void prcmu_modem_req(void) {}
+static void prcmu_modem_rel(void) {}
+#endif
+
static inline int db5500_prcmu_set_arm_opp(u8 opp)
{
return 0;
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index 39062eca535..4baf982fabf 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -460,7 +460,7 @@ static inline void prcmu_modem_reset(void)
static inline bool prcmu_is_ac_wake_requested(void)
{
if (cpu_is_u5500())
- return db5500_prcmu_is_ac_wake_requested();
+ return db5500_prcmu_is_modem_requested();
else
return db8500_prcmu_is_ac_wake_requested();
}