Merge "msm: pil-q6v4-lpass: Combine SSR and PIL drivers"
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 9d4ef05..7c3d5b0 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -49,6 +49,7 @@
CONFIG_MSM_SUBSYSTEM_RESTART=y
# CONFIG_MSM_SYSMON_COMM is not set
CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_PIL_LPASS_QDSP6V4=y
CONFIG_MSM_PIL_MODEM_QDSP6V4=y
CONFIG_MSM_LPASS_8960=y
CONFIG_MSM_RPM_LOG=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index ac4aeba..9f0c30b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1935,7 +1935,7 @@
config MSM_PIL_LPASS_QDSP6V4
tristate "LPASS QDSP6v4 (Hexagon) Boot Support"
- depends on MSM_PIL
+ depends on MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down QDSP6v4 processors (hexagon)
in low power audio subsystems. If you would like to record or
@@ -2033,14 +2033,6 @@
bool "Secure Channel Manager (SCM) support"
default n
-config MSM_LPASS_8960
- tristate "MSM 8960 Lpass driver"
- depends on (ARCH_MSM8960 || ARCH_MSM9615)
- help
- This option enables the lpass driver for the MSM8960 and MSM9615. This monitors
- lpass hardware watchdog interrupt lines and plugs into the subsystem
- restart and PIL drivers. For MSM9615, it only supports a full chip reset.
-
config MSM_MODEM_SSR_8974
bool "MSM 8974 Modem restart driver"
depends on (ARCH_MSM8974)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 76972ec..9073bc1 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -201,7 +201,6 @@
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
-obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
ifdef CONFIG_CPU_IDLE
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index fb94ac0..ed5e2b7 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -870,6 +870,7 @@
#ifdef CONFIG_LTC4088_CHARGER
&msm_device_charger,
#endif
+ &msm_9615_q6_lpass,
&msm_9615_q6_mss,
&msm_device_otg,
&msm_device_hsic_peripheral,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 433ed31..5b04fa7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1341,6 +1341,11 @@
.end = 0x28800000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = LPASS_Q6SS_WDOG_EXPIRED,
+ .end = LPASS_Q6SS_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct pil_q6v4_pdata msm_8960_q6_lpass_data = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index b8c5a1f..8e8fa83 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -705,6 +705,21 @@
.id = -1,
};
+static struct resource msm_9615_q6_lpass_resources[] = {
+ {
+ .start = LPASS_Q6SS_WDOG_EXPIRED,
+ .end = LPASS_Q6SS_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_9615_q6_lpass = {
+ .name = "pil-q6v4-lpass",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_9615_q6_lpass_resources),
+ .resource = msm_9615_q6_lpass_resources,
+};
+
static struct resource msm_9615_q6_mss_resources[] = {
{
.start = Q6FW_WDOG_EXPIRED_IRQ,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 744db1d..950a1be 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -251,6 +251,7 @@
extern struct platform_device msm_pil_dsps;
extern struct platform_device msm_pil_vidc;
extern struct platform_device msm_8960_q6_lpass;
+extern struct platform_device msm_9615_q6_lpass;
extern struct platform_device msm_8960_q6_mss;
extern struct platform_device msm_9615_q6_mss;
extern struct platform_device msm_8960_riva;
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
deleted file mode 100644
index b714a7f..0000000
--- a/arch/arm/mach-msm/lpass-8960.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "ramdump.h"
-#include "sysmon.h"
-
-#define SCM_Q6_NMI_CMD 0x1
-#define MODULE_NAME "lpass_8960"
-#define MAX_BUF_SIZE 0x51
-
-/* Subsystem restart: QDSP6 data, functions */
-static void lpass_fatal_fn(struct work_struct *);
-static DECLARE_WORK(lpass_fatal_work, lpass_fatal_fn);
-struct lpass_ssr {
- void *lpass_ramdump_dev;
-} lpass_ssr;
-
-static struct lpass_ssr lpass_ssr_8960;
-static int q6_crash_shutdown;
-
-static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: R-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_notif_hdle;
-static struct notifier_block rnb = {
- .notifier_call = riva_notifier_cb,
-};
-
-static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: M-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_modem_notif_hdle;
-static struct notifier_block mnb = {
- .notifier_call = modem_notifier_cb,
-};
-
-static void lpass_log_failure_reason(void)
-{
- char *reason;
- char buffer[MAX_BUF_SIZE];
- unsigned size;
-
- reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
-
- if (!reason) {
- pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
- MODULE_NAME);
- return;
- }
-
- if (reason[0] == '\0') {
- pr_err("%s: subsystem failure reason: (unknown, init value found)",
- MODULE_NAME);
- return;
- }
-
- size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
- memcpy(buffer, reason, size);
- buffer[size] = '\0';
- pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
- memset((void *)reason, 0x0, size);
- wmb();
-}
-
-static void lpass_fatal_fn(struct work_struct *work)
-{
- pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
- __func__);
- lpass_log_failure_reason();
- panic(MODULE_NAME ": Resetting the SoC");
-}
-
-static void lpass_smsm_state_cb(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (q6_crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_err("%s: LPASS SMSM state changed to SMSM_RESET,"
- " new_state = 0x%x, old_state = 0x%x\n", __func__,
- new_state, old_state);
- lpass_log_failure_reason();
- panic(MODULE_NAME ": Resetting the SoC");
- }
-}
-
-static void send_q6_nmi(void)
-{
- /* Send NMI to QDSP6 via an SCM call. */
- uint32_t cmd = 0x1;
-
- scm_call(SCM_SVC_UTIL, SCM_Q6_NMI_CMD,
- &cmd, sizeof(cmd), NULL, 0);
-
- /* Q6 requires worstcase 100ms to dump caches etc.*/
- mdelay(100);
- pr_debug("%s: Q6 NMI was sent.\n", __func__);
-}
-
-static int lpass_shutdown(const struct subsys_desc *subsys)
-{
- send_q6_nmi();
- pil_force_shutdown("q6");
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
- return 0;
-}
-
-static int lpass_powerup(const struct subsys_desc *subsys)
-{
- int ret = pil_force_boot("q6");
- enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
- return ret;
-}
-/* RAM segments - address and size for 8960 */
-static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
- 0x8da00000}, {0x28400000, 0x20000} };
-static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
-{
- pr_debug("%s: enable[%d]\n", __func__, enable);
- if (enable)
- return do_ramdump(lpass_ssr_8960.lpass_ramdump_dev,
- q6_segments,
- ARRAY_SIZE(q6_segments));
- else
- return 0;
-}
-
-static void lpass_crash_shutdown(const struct subsys_desc *subsys)
-{
- q6_crash_shutdown = 1;
- send_q6_nmi();
-}
-
-static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- pr_debug("%s: rxed irq[0x%x]", __func__, irq);
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
- ret = schedule_work(&lpass_fatal_work);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_device *lpass_8960_dev;
-
-static struct subsys_desc lpass_8960 = {
- .name = "lpass",
- .shutdown = lpass_shutdown,
- .powerup = lpass_powerup,
- .ramdump = lpass_ramdump,
- .crash_shutdown = lpass_crash_shutdown
-};
-
-static int __init lpass_restart_init(void)
-{
- lpass_8960_dev = subsys_register(&lpass_8960);
- if (IS_ERR(lpass_8960_dev))
- return PTR_ERR(lpass_8960_dev);
- return 0;
-}
-
-static int __init lpass_fatal_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
- lpass_smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
- ret = lpass_restart_init();
- if (ret < 0) {
- pr_err("%s: Unable to reg with lpass ssr. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- lpass_ssr_8960.lpass_ramdump_dev = create_ramdump_device("lpass");
-
- if (!lpass_ssr_8960.lpass_ramdump_dev) {
- pr_err("%s: Unable to create ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
- ssr_notif_hdle = subsys_notif_register_notifier("riva",
- &rnb);
- if (IS_ERR(ssr_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_notif_hdle);
- pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
- __func__, ret);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
- &mnb);
- if (IS_ERR(ssr_modem_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_modem_notif_hdle);
- pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
- __func__, ret);
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- pr_info("%s: lpass SSR driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-static void __exit lpass_fatal_exit(void)
-{
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
- subsys_unregister(lpass_8960_dev);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-module_init(lpass_fatal_init);
-module_exit(lpass_fatal_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index 222bd10..a0432550 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -17,11 +17,34 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "ramdump.h"
+#include "sysmon.h"
#include "peripheral-loader.h"
#include "pil-q6v4.h"
#include "scm-pas.h"
+struct lpass_q6v4 {
+ struct q6v4_data q6;
+ void *riva_notif_hdle;
+ void *modem_notif_hdle;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash_shutdown;
+ void *ramdump_dev;
+ struct work_struct work;
+ int loadable;
+};
+
static int pil_q6v4_lpass_boot(struct pil_desc *pil)
{
struct q6v4_data *drv = pil_to_q6v4_data(pil);
@@ -62,59 +85,295 @@
.proxy_unvote = pil_q6v4_remove_proxy_votes,
};
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rnb = {
+ .notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+ .notifier_call = modem_notifier_cb,
+};
+
+static void lpass_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[81];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("LPASS subsystem failure reason: (unknown, smem_get_entry failed).");
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("LPASS subsystem failure reason: (unknown, init value found)");
+ return;
+ }
+
+ size = min(size, sizeof(buffer) - 1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("LPASS subsystem failure reason: %s", buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
+static void lpass_fatal_fn(struct work_struct *work)
+{
+ pr_err("Watchdog bite received from lpass Q6!\n");
+ lpass_log_failure_reason();
+ panic("Q6 Resetting the SoC");
+}
+
+static void lpass_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct lpass_q6v4 *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("%s: LPASS SMSM state changed to SMSM_RESET, new_state = %#x, old_state = %#x\n",
+ __func__, new_state, old_state);
+ lpass_log_failure_reason();
+ panic("Q6 Resetting the SoC");
+ }
+}
+
+#define SCM_Q6_NMI_CMD 0x1
+
+static void send_q6_nmi(void)
+{
+ /* Send NMI to QDSP6 via an SCM call. */
+ uint32_t cmd = 0x1;
+
+ scm_call(SCM_SVC_UTIL, SCM_Q6_NMI_CMD,
+ &cmd, sizeof(cmd), NULL, 0);
+
+ /* Q6 requires worstcase 100ms to dump caches etc.*/
+ mdelay(100);
+ pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+#define subsys_to_lpass(d) container_of(d, struct lpass_q6v4, subsys_desc)
+
+static int lpass_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+
+ send_q6_nmi();
+ if (drv->loadable)
+ pil_force_shutdown("q6");
+ disable_irq_nosync(drv->q6.wdog_irq);
+
+ return 0;
+}
+
+static int lpass_powerup(const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+ int ret = 0;
+
+ if (drv->loadable)
+ ret = pil_force_boot("q6");
+ enable_irq(drv->q6.wdog_irq);
+
+ return ret;
+}
+
+static struct ramdump_segment segments[] = {
+ {0x8da00000, 0x8f200000 - 0x8da00000},
+ {0x28400000, 0x20000}
+};
+
+static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+
+ if (!enable)
+ return 0;
+ return do_ramdump(drv->ramdump_dev, segments, ARRAY_SIZE(segments));
+}
+
+static void lpass_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+
+ drv->crash_shutdown = 1;
+ send_q6_nmi();
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct lpass_q6v4 *drv = dev_id;
+
+ disable_irq_nosync(drv->q6.wdog_irq);
+ schedule_work(&drv->work);
+
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_q6v4_lpass_driver_probe(struct platform_device *pdev)
{
const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
- struct q6v4_data *drv;
+ struct lpass_q6v4 *drv;
+ struct q6v4_data *q6;
struct pil_desc *desc;
struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
+ int ret;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
+ q6 = &drv->q6;
+ desc = &q6->desc;
- drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!drv->base)
- return -ENOMEM;
+ q6->wdog_irq = platform_get_irq(pdev, 0);
+ if (q6->wdog_irq < 0)
+ return q6->wdog_irq;
- drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
- if (IS_ERR(drv->vreg))
- return PTR_ERR(drv->vreg);
+ drv->loadable = !!pdata; /* No pdata = don't use PIL */
+ if (drv->loadable) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+ q6->base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!q6->base)
+ return -ENOMEM;
- drv->xo = devm_clk_get(&pdev->dev, "xo");
- if (IS_ERR(drv->xo))
- return PTR_ERR(drv->xo);
+ q6->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
+ if (IS_ERR(q6->vreg))
+ return PTR_ERR(q6->vreg);
- desc = &drv->desc;
- desc->name = pdata->name;
- desc->dev = &pdev->dev;
- desc->owner = THIS_MODULE;
- desc->proxy_timeout = 10000;
- pil_q6v4_init(drv, pdata);
+ q6->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(q6->xo))
+ return PTR_ERR(q6->xo);
- if (pas_supported(pdata->pas_id) > 0) {
- desc->ops = &pil_q6v4_lpass_ops_trusted;
- dev_info(&pdev->dev, "using secure boot\n");
- } else {
- desc->ops = &pil_q6v4_lpass_ops;
- dev_info(&pdev->dev, "using non-secure boot\n");
+ desc->name = pdata->name;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
+ pil_q6v4_init(q6, pdata);
+
+ if (pas_supported(pdata->pas_id) > 0) {
+ desc->ops = &pil_q6v4_lpass_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_q6v4_lpass_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
+ q6->pil = msm_pil_register(desc);
+ if (IS_ERR(q6->pil))
+ return PTR_ERR(q6->pil);
}
- drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil))
- return PTR_ERR(drv->pil);
+ drv->subsys_desc.name = "lpass";
+ drv->subsys_desc.shutdown = lpass_shutdown;
+ drv->subsys_desc.powerup = lpass_powerup;
+ drv->subsys_desc.ramdump = lpass_ramdump;
+ drv->subsys_desc.crash_shutdown = lpass_crash_shutdown;
+
+ INIT_WORK(&drv->work, lpass_fatal_fn);
+
+ drv->ramdump_dev = create_ramdump_device("lpass");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, q6->wdog_irq, lpass_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
+ if (ret)
+ goto err_irq;
+
+ ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->riva_notif_hdle = subsys_notif_register_notifier("riva", &rnb);
+ if (IS_ERR(drv->riva_notif_hdle)) {
+ ret = PTR_ERR(drv->riva_notif_hdle);
+ goto err_notif_riva;
+ }
+
+ drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
+ if (IS_ERR(drv->modem_notif_hdle)) {
+ ret = PTR_ERR(drv->modem_notif_hdle);
+ goto err_notif_modem;
+ }
return 0;
+err_notif_modem:
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+err_notif_riva:
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, drv);
+err_smsm:
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ if (drv->loadable)
+ msm_pil_unregister(q6->pil);
+ return ret;
}
static int __devexit pil_q6v4_lpass_driver_exit(struct platform_device *pdev)
{
- struct q6v4_data *drv = platform_get_drvdata(pdev);
- msm_pil_unregister(drv->pil);
+ struct lpass_q6v4 *drv = platform_get_drvdata(pdev);
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+ subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
+ if (drv->loadable)
+ msm_pil_unregister(drv->q6.pil);
return 0;
}