misc: pmic8058-xoadc: request's done late into suspend
-Add checks in the driver for suspend_noirq/resume_noirq
to prevent clients from invoking the driver for ADC requests
after suspend has begun. This will lead to interrupts being
lost since the request is done very late into suspend.
-Obtain a wakelock when an ADC request is occuring.
CRs-Fixed: 295261
Change-Id: I610e1fbcd25f5ff947cb7e5e7738100ac86015a9
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
diff --git a/drivers/misc/pmic8058-xoadc.c b/drivers/misc/pmic8058-xoadc.c
index d2d8cba..f21668a 100644
--- a/drivers/misc/pmic8058-xoadc.c
+++ b/drivers/misc/pmic8058-xoadc.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/delay.h>
+#include <linux/wakelock.h>
#include <mach/mpp.h>
#include <mach/msm_xo.h>
@@ -65,6 +66,9 @@
struct adc_conv_slot conv_queue_elements[MAX_QUEUE_LENGTH];
int xoadc_num;
struct msm_xo_voter *adc_voter;
+ struct wake_lock adc_wakelock;
+ /* flag to warn/bug if wakelocks are taken after suspend_noirq */
+ int msm_suspend_check;
};
static struct pmic8058_adc *pmic_adc[XOADC_PMIC_0 + 1];
@@ -117,7 +121,7 @@
EXPORT_SYMBOL(pm8058_xoadc_slot_request);
static int32_t pm8058_xoadc_arb_cntrl(uint32_t arb_cntrl,
- uint32_t adc_instance)
+ uint32_t adc_instance, uint32_t channel)
{
struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
int i, rc;
@@ -128,9 +132,13 @@
ADC_ARB_USRP_CNTRL_RSV4;
if (arb_cntrl) {
+ if (adc_pmic->msm_suspend_check)
+ pr_err("XOADC request being made after suspend irq "
+ "with channel id:%d\n", channel);
data_arb_cntrl |= ADC_ARB_USRP_CNTRL_EN_ARB;
msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
adc_pmic->pdata->xoadc_mpp_config();
+ wake_lock(&adc_pmic->adc_wakelock);
}
/* Write twice to the CNTRL register for the arbiter settings
@@ -144,8 +152,10 @@
}
}
- if (!arb_cntrl)
+ if (!arb_cntrl) {
msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
+ wake_unlock(&adc_pmic->adc_wakelock);
+ }
return 0;
}
@@ -159,7 +169,7 @@
u8 data_dig_param, data_ana_param2;
int rc;
- rc = pm8058_xoadc_arb_cntrl(1, adc_instance);
+ rc = pm8058_xoadc_arb_cntrl(1, adc_instance, slot->chan_path);
if (rc < 0) {
pr_debug("%s: Configuring ADC Arbiter"
"enable failed\n", __func__);
@@ -461,7 +471,7 @@
/* Default value for switching off the arbiter after reading
the ADC value. Bit 0 set to 0. */
if (adc_pmic->xoadc_queue_count == 0) {
- rc = pm8058_xoadc_arb_cntrl(0, adc_instance);
+ rc = pm8058_xoadc_arb_cntrl(0, adc_instance, CHANNEL_MUXOFF);
if (rc < 0) {
pr_debug("%s: Configuring ADC Arbiter disable"
"failed\n", __func__);
@@ -607,6 +617,37 @@
}
EXPORT_SYMBOL(pm8058_xoadc_calibrate);
+#ifdef CONFIG_PM
+static int pm8058_xoadc_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
+
+ adc_pmic->msm_suspend_check = 1;
+
+ return 0;
+}
+
+static int pm8058_xoadc_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
+
+ adc_pmic->msm_suspend_check = 0;
+
+ return 0;
+}
+
+static const struct dev_pm_ops pm8058_xoadc_dev_pm_ops = {
+ .suspend_noirq = pm8058_xoadc_suspend_noirq,
+ .resume_noirq = pm8058_xoadc_resume_noirq,
+};
+
+#define PM8058_XOADC_DEV_PM_OPS (&pm8058_xoadc_dev_pm_ops)
+#else
+#define PM8058_XOADC_DEV_PM_OPS NULL
+#endif
+
static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
{
struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
@@ -614,6 +655,7 @@
if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
adc_pmic->pdata->xoadc_vreg_shutdown();
+ wake_lock_destroy(&adc_pmic->adc_wakelock);
msm_xo_put(adc_pmic->adc_voter);
platform_set_drvdata(pdev, adc_pmic->pm_chip);
device_init_wakeup(&pdev->dev, 0);
@@ -728,6 +770,9 @@
}
}
+ wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
+ "pmic8058_xoadc_wakelock");
+
pmic_adc[adc_pmic->xoadc_num] = adc_pmic;
if (pdata->xoadc_vreg_setup != NULL)
@@ -750,6 +795,7 @@
.driver = {
.name = "pm8058-xoadc",
.owner = THIS_MODULE,
+ .pm = PM8058_XOADC_DEV_PM_OPS,
},
};