wcnss: Notify Kernel suspend/resume to WCNSS
Notify WCNSS when the Kernel is suspended and also when it resumes.
Signed-off-by: Sameer Thalappil <sameert@codeaurora.org>
Signed-off-by: Jeff Johnson <jjohnson@codeaurora.org>
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3e26e23..6d3893e 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1980,7 +1980,8 @@
config MSM_WCNSS_SSR_8960
tristate "MSM 8960 WCNSS restart module"
- depends on (ARCH_MSM8960)
+ depends on ARCH_MSM8960
+ depends on WCNSS_CORE
help
This option enables the WCNSS restart module for MSM8960, which
monitors WCNSS hardware watchdog interrupt lines and plugs WCNSS
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 7e4bdb9..f569de4 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -31,12 +31,6 @@
#define MODULE_NAME "wcnss_8960"
#define MAX_BUF_SIZE 0x51
-static void __iomem *msm_riva_base;
-#define MSM_RIVA_PHYS 0x03204000
-#define RIVA_SSR_OUT (msm_riva_base + 0x0b4)
-#define RIVA_SSR_BIT BIT(23)
-
-
static struct delayed_work cancel_vote_work;
static void *riva_ramdump_dev;
static int riva_crash;
@@ -147,20 +141,9 @@
struct platform_device *pdev = wcnss_get_platform_device();
struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
int ret = -1;
- u32 reg = 0;
- msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
- if (!msm_riva_base) {
- pr_err("ioremap MSM_RIVA_PHYS failed\n");
- goto poweron;
- }
+ wcnss_ssr_boot_notify();
- reg = readl_relaxed(RIVA_SSR_OUT);
- reg |= RIVA_SSR_BIT;
- writel_relaxed(reg, RIVA_SSR_OUT);
- iounmap(msm_riva_base);
-
-poweron:
if (pdev && pwlanconfig)
ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
WCNSS_WLAN_SWITCH_ON);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index c0a4e0e..48620be 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
+#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -34,6 +35,14 @@
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
+static DEFINE_SPINLOCK(reg_spinlock);
+
+#define MSM_RIVA_PHYS 0x03204000
+
+#define RIVA_SPARE_OFFSET 0x0b4
+#define RIVA_SSR_BIT BIT(23)
+#define RIVA_SUSPEND_BIT BIT(24)
+
static struct {
struct platform_device *pdev;
void *pil;
@@ -50,6 +59,7 @@
struct wcnss_wlan_config wlan_config;
struct delayed_work wcnss_work;
struct wake_lock wcnss_wake_lock;
+ void __iomem *msm_wcnss_base;
} *penv = NULL;
static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -310,21 +320,99 @@
}
EXPORT_SYMBOL(wcnss_get_serial_number);
+void wcnss_ssr_boot_notify(void)
+{
+ void __iomem *pmu_spare_reg;
+ u32 reg = 0;
+ unsigned long flags;
+
+ pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
+
+ spin_lock_irqsave(®_spinlock, flags);
+ reg = readl_relaxed(pmu_spare_reg);
+ reg |= RIVA_SSR_BIT;
+ writel_relaxed(reg, pmu_spare_reg);
+ spin_unlock_irqrestore(®_spinlock, flags);
+}
+EXPORT_SYMBOL(wcnss_ssr_boot_notify);
+
+static int enable_wcnss_suspend_notify;
+
+static int enable_wcnss_suspend_notify_set(const char *val,
+ struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_int(val, kp);
+ if (ret)
+ return ret;
+
+ if (enable_wcnss_suspend_notify)
+ pr_info("Suspend notification activated for wcnss\n");
+
+ return 0;
+}
+module_param_call(enable_wcnss_suspend_notify, enable_wcnss_suspend_notify_set,
+ param_get_int, &enable_wcnss_suspend_notify, S_IRUGO | S_IWUSR);
+
+static void wcnss_suspend_notify(void)
+{
+ void __iomem *pmu_spare_reg;
+ u32 reg = 0;
+ unsigned long flags;
+
+ /* For Riva */
+ pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
+
+ spin_lock_irqsave(®_spinlock, flags);
+ reg = readl_relaxed(pmu_spare_reg);
+ reg |= RIVA_SUSPEND_BIT;
+ writel_relaxed(reg, pmu_spare_reg);
+ spin_unlock_irqrestore(®_spinlock, flags);
+}
+
+static void wcnss_resume_notify(void)
+{
+ void __iomem *pmu_spare_reg;
+ u32 reg = 0;
+ unsigned long flags;
+
+ /* For Riva */
+ pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
+ spin_lock_irqsave(®_spinlock, flags);
+ reg = readl_relaxed(pmu_spare_reg);
+ reg &= ~RIVA_SUSPEND_BIT;
+ writel_relaxed(reg, pmu_spare_reg);
+ spin_unlock_irqrestore(®_spinlock, flags);
+}
+
static int wcnss_wlan_suspend(struct device *dev)
{
+ int ret = 0;
+
if (penv && dev && (dev == &penv->pdev->dev) &&
penv->smd_channel_ready &&
- penv->pm_ops && penv->pm_ops->suspend)
- return penv->pm_ops->suspend(dev);
+ penv->pm_ops && penv->pm_ops->suspend) {
+ ret = penv->pm_ops->suspend(dev);
+ if (ret == 0 && enable_wcnss_suspend_notify)
+ wcnss_suspend_notify();
+ return ret;
+ }
return 0;
}
static int wcnss_wlan_resume(struct device *dev)
{
+ int ret = 0;
+
if (penv && dev && (dev == &penv->pdev->dev) &&
penv->smd_channel_ready &&
- penv->pm_ops && penv->pm_ops->resume)
- return penv->pm_ops->resume(dev);
+ penv->pm_ops && penv->pm_ops->resume) {
+ ret = penv->pm_ops->resume(dev);
+ if (ret == 0 && enable_wcnss_suspend_notify)
+ wcnss_resume_notify();
+ return ret;
+ }
return 0;
}
@@ -416,8 +504,17 @@
wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
+ penv->msm_wcnss_base = ioremap(MSM_RIVA_PHYS, SZ_256);
+ if (!penv->msm_wcnss_base) {
+ pr_err("%s: ioremap wcnss physical failed\n", __func__);
+ goto fail_wake;
+ }
+
return 0;
+fail_wake:
+ wake_lock_destroy(&penv->wcnss_wake_lock);
+
fail_sysfs:
fail_res:
if (penv->pil)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 295be8f..6f29b78 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -50,6 +50,7 @@
void wcnss_flush_delayed_boot_votes(void);
void wcnss_allow_suspend(void);
void wcnss_prevent_suspend(void);
+void wcnss_ssr_boot_notify(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))