diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c index 43c85bb5295..3364232215f 100644 --- a/arch/arm/mach-msm/mdm2.c +++ b/arch/arm/mach-msm/mdm2.c @@ -112,8 +112,12 @@ static void mdm_power_down_common(struct mdm_modem_drv *mdm_drv) /* Wait for the modem to complete its power down actions. */ for (i = 20; i > 0; i--) { - if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) + if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) { + if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) + pr_info("%s: mdm2ap_status went low, i = %d\n", + __func__, i); break; + } msleep(100); } if (i == 0) { diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c index 2ee6938cbfe..0597c62ce41 100644 --- a/arch/arm/mach-msm/mdm_common.c +++ b/arch/arm/mach-msm/mdm_common.c @@ -290,6 +290,15 @@ long mdm_modem_ioctl(struct file *filp, unsigned int cmd, } else pr_debug("%s Image upgrade not supported\n", __func__); break; + case SHUTDOWN_CHARM: + mdm_drv->mdm_ready = 0; + if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) + pr_info("Sending shutdown request to mdm\n"); + ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM); + if (ret) + pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n", + __func__, ret); + break; default: pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd)); ret = -EINVAL; @@ -382,6 +391,9 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id) { int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio); + if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0)) + pr_info("%s: mdm2ap_status went low\n", __func__); + pr_debug("%s: mdm sent status change interrupt\n", __func__); if (value == 0 && mdm_drv->mdm_ready == 1) { pr_info("%s: unexpected reset external modem\n", __func__); diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h index c406b89adc8..9e865c5adee 100644 --- a/arch/arm/mach-msm/mdm_private.h +++ b/arch/arm/mach-msm/mdm_private.h @@ -14,6 +14,7 @@ #define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H #define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002) +#define MDM_DEBUG_MASK_SHDN_LOG (0x00000004) #define GPIO_IS_VALID(gpio) \ (gpio != -1) struct mdm_modem_drv; diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c index 78290a26344..0d62e6ad875 100644 --- a/arch/arm/mach-msm/sysmon.c +++ b/arch/arm/mach-msm/sysmon.c @@ -158,6 +158,33 @@ out: return ret; } +/** + * sysmon_send_shutdown() - send shutdown command to a + * subsystem. + * @dest_ss: ID of subsystem to send to. + * + * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if + * the SMD transport channel is not open, -ETIMEDOUT if the destination + * subsystem does not respond, and -ENOSYS if the destination subsystem + * responds with something unexpected. + * + * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0). + */ +int sysmon_send_shutdown(enum subsys_id dest_ss) +{ + struct sysmon_subsys *ss = &subsys[dest_ss]; + const char tx_buf[] = "ssr:poweroff"; + int ret; + + if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS) + return -EINVAL; + + mutex_lock(&ss->lock); + ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf)); + mutex_unlock(&ss->lock); + return ret; +} + /** * sysmon_get_reason() - Retrieve failure reason from a subsystem. * @dest_ss: ID of subsystem to query diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h index 77c332932d0..439c61764e8 100644 --- a/arch/arm/mach-msm/sysmon.h +++ b/arch/arm/mach-msm/sysmon.h @@ -38,6 +38,7 @@ enum subsys_id { int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss, enum subsys_notif_type notif); int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len); +int sysmon_send_shutdown(enum subsys_id dest_ss); #else static inline int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss, diff --git a/include/linux/msm_charm.h b/include/linux/msm_charm.h index 44d25532f1e..1d1f3bb3dd4 100644 --- a/include/linux/msm_charm.h +++ b/include/linux/msm_charm.h @@ -12,6 +12,7 @@ #define WAIT_FOR_RESTART _IOR(CHARM_CODE, 7, int) #define GET_DLOAD_STATUS _IOR(CHARM_CODE, 8, int) #define IMAGE_UPGRADE _IOW(CHARM_CODE, 9, int) +#define SHUTDOWN_CHARM _IOW(CHARM_CODE, 10, int) enum charm_boot_type { CHARM_NORMAL_BOOT = 0,