msm: mdm: Add shutdown ioctl and send poweroff request to the mdm

When the whole phone is being powered off, a poweroff request needs
to be sent to the external modem so that it can shutdown gracefully.
This request needs to be triggered from userspace before kernel drivers
start unloading so that other drivers needed to send the request are
still available. The shutdown ioctl is provided for this purpose.
The request is sent over system monitor.

Crs-Fixed: 401598
Signed-off-by: Joel King <joelking@codeaurora.org>
This commit is contained in:
agathon.jung
2012-09-26 11:36:51 -07:00
committed by Iliyan Malchev
parent d44697e328
commit 613e3b6f4c
6 changed files with 47 additions and 1 deletions

View File

@@ -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. */ /* Wait for the modem to complete its power down actions. */
for (i = 20; i > 0; i--) { 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; break;
}
msleep(100); msleep(100);
} }
if (i == 0) { if (i == 0) {

View File

@@ -290,6 +290,15 @@ long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
} else } else
pr_debug("%s Image upgrade not supported\n", __func__); pr_debug("%s Image upgrade not supported\n", __func__);
break; 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: default:
pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd)); pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
ret = -EINVAL; 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); 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__); pr_debug("%s: mdm sent status change interrupt\n", __func__);
if (value == 0 && mdm_drv->mdm_ready == 1) { if (value == 0 && mdm_drv->mdm_ready == 1) {
pr_info("%s: unexpected reset external modem\n", __func__); pr_info("%s: unexpected reset external modem\n", __func__);

View File

@@ -14,6 +14,7 @@
#define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H #define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
#define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002) #define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002)
#define MDM_DEBUG_MASK_SHDN_LOG (0x00000004)
#define GPIO_IS_VALID(gpio) \ #define GPIO_IS_VALID(gpio) \
(gpio != -1) (gpio != -1)
struct mdm_modem_drv; struct mdm_modem_drv;

View File

@@ -158,6 +158,33 @@ out:
return ret; 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. * sysmon_get_reason() - Retrieve failure reason from a subsystem.
* @dest_ss: ID of subsystem to query * @dest_ss: ID of subsystem to query

View File

@@ -38,6 +38,7 @@ enum subsys_id {
int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss, int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
enum subsys_notif_type notif); enum subsys_notif_type notif);
int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len); int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
int sysmon_send_shutdown(enum subsys_id dest_ss);
#else #else
static inline int sysmon_send_event(enum subsys_id dest_ss, static inline int sysmon_send_event(enum subsys_id dest_ss,
const char *event_ss, const char *event_ss,

View File

@@ -12,6 +12,7 @@
#define WAIT_FOR_RESTART _IOR(CHARM_CODE, 7, int) #define WAIT_FOR_RESTART _IOR(CHARM_CODE, 7, int)
#define GET_DLOAD_STATUS _IOR(CHARM_CODE, 8, int) #define GET_DLOAD_STATUS _IOR(CHARM_CODE, 8, int)
#define IMAGE_UPGRADE _IOW(CHARM_CODE, 9, int) #define IMAGE_UPGRADE _IOW(CHARM_CODE, 9, int)
#define SHUTDOWN_CHARM _IOW(CHARM_CODE, 10, int)
enum charm_boot_type { enum charm_boot_type {
CHARM_NORMAL_BOOT = 0, CHARM_NORMAL_BOOT = 0,