summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRajagopala V <rajagopala.v@stericsson.com>2011-12-14 15:36:15 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 10:59:24 +0200
commitd7285f989c8182e01922bed16683e36beec767bd (patch)
tree7e9c53d8a16dd2095b4d46c68b23c8c23d98fb8e
parentdb39c4b3e55e394aff1accaf4f4a632e6bc9ff22 (diff)
mfd: db5500-prcmu: Mbox4 support for watchdog
PRCMU driver interface for A9 watchdog management. - mbox4 for enabling and disabling wdog - interface for loading ang kicking wdog ST-Ericsson ID: 316540 ST-Ericsson FOSS-OUT ID: Trivial ST-Ericsson Linux next: NA Change-Id: Iea6d0887dd0432d5c2d20ef0ca15f3d534609fd3 Signed-off-by: Rajagopala V <rajagopala.v@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/42490 Reviewed-by: Rabin VINCENT <rabin.vincent@stericsson.com>
-rw-r--r--drivers/mfd/db5500-prcmu-regs.h9
-rw-r--r--drivers/mfd/db5500-prcmu.c120
-rw-r--r--include/linux/mfd/db5500-prcmu.h32
-rw-r--r--include/linux/mfd/dbx500-prcmu.h10
4 files changed, 165 insertions, 6 deletions
diff --git a/drivers/mfd/db5500-prcmu-regs.h b/drivers/mfd/db5500-prcmu-regs.h
index 30234a86263..0428b5e95ae 100644
--- a/drivers/mfd/db5500-prcmu-regs.h
+++ b/drivers/mfd/db5500-prcmu-regs.h
@@ -129,4 +129,13 @@
#define PRCM_HOSTACCESS_REQ_BIT BIT(0)
#define PRCM_APE_ACK 0x49c
#define PRCM_APE_ACK_BIT 0x01
+
+/* Watchdog - mtimer registers */
+#define PRCM_TIMER0_RTOS_COMP1_OFFSET 0x4C
+#define PRCM_TIMER0_RTOS_COUNTER_OFFSET 0x40
+#define PRCM_TIMER0_IRQ_EN_SET_OFFSET 0x70
+#define PRCM_TIMER0_IRQ_EN_CLR_OFFSET 0x6C
+#define PRCM_TIMER0_IRQ_RTOS1_SET 0x08
+#define PRCM_TIMER0_IRQ_RTOS1_CLR 0x08
+
#endif
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
index 9a944f08ef3..76d8a3132ae 100644
--- a/drivers/mfd/db5500-prcmu.c
+++ b/drivers/mfd/db5500-prcmu.c
@@ -164,6 +164,9 @@ enum mb4_header {
MB4H_CFG_HOTMON = 8,
MB4H_CFG_HOTPERIOD = 10,
MB4H_CGF_MODEM_RESET = 13,
+ MB4H_CGF_A9WDOG_EN_PREBARK = 14,
+ MB4H_CGF_A9WDOG_EN_NOPREBARK = 15,
+ MB4H_CGF_A9WDOG_DIS = 16,
};
/* Mailbox 4 ACK headers */
@@ -172,6 +175,9 @@ enum mb4_ack_header {
MB4H_ACK_CFG_HOTMON = 6,
MB4H_ACK_CFG_HOTPERIOD = 8,
MB4H_ACK_CFG_MODEM_RESET = 11,
+ MB4H_ACK_CGF_A9WDOG_EN_PREBARK = 12,
+ MB4H_ACK_CGF_A9WDOG_EN_NOPREBARK = 13,
+ MB4H_ACK_CGF_A9WDOG_DIS = 14,
};
/* Mailbox 5 headers. */
@@ -473,9 +479,12 @@ static struct {
/* Spinlocks */
static DEFINE_SPINLOCK(clkout_lock);
-/* PRCMU TCDM base IO address. */
+/* PRCMU TCDM base IO address */
static __iomem void *tcdm_base;
+/* PRCMU MTIMER base IO address */
+static __iomem void *mtimer_base;
+
struct clk_mgt {
unsigned int offset;
u32 pllsw;
@@ -491,6 +500,11 @@ static struct {
u8 api_version;
} prcmu_version;
+static struct {
+ u32 timeout;
+ bool enabled;
+} a9wdog_timer;
+
static DEFINE_SPINLOCK(clk_mgt_lock);
#define CLK_MGT_ENTRY(_name, _scalable)[PRCMU_##_name] = { \
@@ -1182,6 +1196,106 @@ int db5500_prcmu_stop_temp_sense(void)
return config_hot_period(0xFFFF);
}
+static int prcmu_a9wdog(u8 req, u8 ack)
+{
+ int r = 0;
+
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ r = mailbox4_request(req, ack);
+
+ mutex_unlock(&mb4_transfer.lock);
+
+ return r;
+}
+
+static void prcmu_a9wdog_set_interrupt(bool enable)
+{
+ if (enable) {
+ writel(PRCM_TIMER0_IRQ_RTOS1_SET,
+ (mtimer_base + PRCM_TIMER0_IRQ_EN_SET_OFFSET));
+ } else {
+ writel(PRCM_TIMER0_IRQ_RTOS1_CLR,
+ (mtimer_base + PRCM_TIMER0_IRQ_EN_CLR_OFFSET));
+ }
+}
+
+static void prcmu_a9wdog_set_timeout(u32 timeout)
+{
+ u32 comp_timeout;
+
+ comp_timeout = readl(mtimer_base + PRCM_TIMER0_RTOS_COUNTER_OFFSET) +
+ timeout;
+ writel(comp_timeout, mtimer_base + PRCM_TIMER0_RTOS_COMP1_OFFSET);
+}
+
+int db5500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+{
+ /*
+ * Sleep auto off feature is not supported. Resume and
+ * suspend will be handled by watchdog driver.
+ */
+ return 0;
+}
+
+int db5500_prcmu_enable_a9wdog(u8 id)
+{
+ int r = 0;
+
+ if (a9wdog_timer.enabled)
+ return -EPERM;
+
+ prcmu_a9wdog_set_interrupt(true);
+
+ r = prcmu_a9wdog(MB4H_CGF_A9WDOG_EN_PREBARK,
+ MB4H_ACK_CGF_A9WDOG_EN_PREBARK);
+ if (!r)
+ a9wdog_timer.enabled = true;
+ else
+ prcmu_a9wdog_set_interrupt(false);
+
+ return r;
+}
+
+int db5500_prcmu_disable_a9wdog(u8 id)
+{
+ if (!a9wdog_timer.enabled)
+ return -EPERM;
+
+ prcmu_a9wdog_set_interrupt(false);
+
+ a9wdog_timer.enabled = false;
+
+ return prcmu_a9wdog(MB4H_CGF_A9WDOG_DIS,
+ MB4H_ACK_CGF_A9WDOG_DIS);
+}
+
+int db5500_prcmu_kick_a9wdog(u8 id)
+{
+ int r = 0;
+
+ if (a9wdog_timer.enabled)
+ prcmu_a9wdog_set_timeout(a9wdog_timer.timeout);
+ else
+ r = -EPERM;
+
+ return r;
+}
+
+int db5500_prcmu_load_a9wdog(u8 id, u32 timeout)
+{
+ if (a9wdog_timer.enabled)
+ return -EPERM;
+
+ prcmu_a9wdog_set_timeout(timeout);
+ a9wdog_timer.timeout = timeout;
+
+ return 0;
+}
+
/**
* db5500_prcmu_abb_read() - Read register value(s) from the ABB.
* @slave: The I2C slave address.
@@ -1885,6 +1999,9 @@ static bool read_mailbox_4(void)
case MB4H_ACK_CFG_HOTMON:
case MB4H_ACK_CFG_HOTPERIOD:
case MB4H_ACK_CFG_MODEM_RESET:
+ case MB4H_ACK_CGF_A9WDOG_EN_PREBARK:
+ case MB4H_ACK_CGF_A9WDOG_EN_NOPREBARK:
+ case MB4H_ACK_CGF_A9WDOG_DIS:
mb4_transfer.ack.status = readb(PRCM_ACK_MB4_REQUESTS);
break;
default:
@@ -2059,6 +2176,7 @@ void __init db5500_prcmu_early_init(void)
}
tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
+ mtimer_base = __io_address(U5500_MTIMER_BASE);
spin_lock_init(&mb0_transfer.lock);
spin_lock_init(&mb0_transfer.dbb_irqs_lock);
mutex_init(&mb0_transfer.ac_wake_lock);
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
index cf97d25a913..681c8f99bf1 100644
--- a/include/linux/mfd/db5500-prcmu.h
+++ b/include/linux/mfd/db5500-prcmu.h
@@ -65,6 +65,13 @@ int db5500_prcmu_config_hotdog(u8 threshold);
int db5500_prcmu_config_hotmon(u8 low, u8 high);
int db5500_prcmu_start_temp_sense(u16 cycles32k);
int db5500_prcmu_stop_temp_sense(void);
+
+int db5500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
+int db5500_prcmu_enable_a9wdog(u8 id);
+int db5500_prcmu_disable_a9wdog(u8 id);
+int db5500_prcmu_kick_a9wdog(u8 id);
+int db5500_prcmu_load_a9wdog(u8 id, u32 timeout);
+
#else /* !CONFIG_UX500_SOC_DB5500 */
static inline void db5500_prcmu_early_init(void) {}
@@ -227,6 +234,31 @@ static inline int db5500_prcmu_stop_temp_sense(void)
return 0;
}
+static inline int db5500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+{
+ return 0;
+}
+
+static inline int db5500_prcmu_enable_a9wdog(u8 id)
+{
+ return 0;
+}
+
+static inline int db5500_prcmu_disable_a9wdog(u8 id)
+{
+ return 0;
+}
+
+static inline int db5500_prcmu_kick_a9wdog(u8 id)
+{
+ return 0;
+}
+
+static inline int db5500_prcmu_load_a9wdog(u8 id, u32 timeout)
+{
+ return 0;
+}
+
#endif /* CONFIG_MFD_DB5500_PRCMU */
#endif /* __MFD_DB5500_PRCMU_H */
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index 45a0ae0cc39..eb9cee31407 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -556,7 +556,7 @@ static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
static inline int prcmu_enable_a9wdog(u8 id)
{
if (cpu_is_u5500())
- return -EINVAL;
+ return db5500_prcmu_enable_a9wdog(id);
else
return db8500_prcmu_enable_a9wdog(id);
}
@@ -564,7 +564,7 @@ static inline int prcmu_enable_a9wdog(u8 id)
static inline int prcmu_disable_a9wdog(u8 id)
{
if (cpu_is_u5500())
- return -EINVAL;
+ return db5500_prcmu_disable_a9wdog(id);
else
return db8500_prcmu_disable_a9wdog(id);
}
@@ -572,7 +572,7 @@ static inline int prcmu_disable_a9wdog(u8 id)
static inline int prcmu_kick_a9wdog(u8 id)
{
if (cpu_is_u5500())
- return -EINVAL;
+ return db5500_prcmu_kick_a9wdog(id);
else
return db8500_prcmu_kick_a9wdog(id);
}
@@ -580,7 +580,7 @@ static inline int prcmu_kick_a9wdog(u8 id)
static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
{
if (cpu_is_u5500())
- return -EINVAL;
+ return db5500_prcmu_load_a9wdog(id, timeout);
else
return db8500_prcmu_load_a9wdog(id, timeout);
}
@@ -588,7 +588,7 @@ static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
{
if (cpu_is_u5500())
- return -EINVAL;
+ return db5500_prcmu_config_a9wdog(num, sleep_auto_off);
else
return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
}