ASoC: wcd9310: Prevent from going suspend while accessing codec registers
The wcd9310 codec driver which is slimbus slave can access codec registers when slimbus is suspended. This can cause register read/write failure. Fix to make sure slimbus is awake before accessing wcd9310 codec's registers through slimbus. CRs-fixed: 331338 Change-Id: Iddbdb1614c18dab4bee4f0cc7951884f34cb7173 Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
This commit is contained in:
@@ -370,6 +370,13 @@ static int tabla_device_init(struct tabla *tabla, int irq)
|
||||
|
||||
mutex_init(&tabla->io_lock);
|
||||
mutex_init(&tabla->xfer_lock);
|
||||
|
||||
mutex_init(&tabla->pm_lock);
|
||||
tabla->wlock_holders = 0;
|
||||
tabla->pm_state = TABLA_PM_SLEEPABLE;
|
||||
init_waitqueue_head(&tabla->pm_wq);
|
||||
wake_lock_init(&tabla->wlock, WAKE_LOCK_IDLE, "wcd9310-irq");
|
||||
|
||||
dev_set_drvdata(tabla->dev, tabla);
|
||||
|
||||
tabla_bring_up(tabla);
|
||||
@@ -397,19 +404,22 @@ err_irq:
|
||||
tabla_irq_exit(tabla);
|
||||
err:
|
||||
tabla_bring_down(tabla);
|
||||
wake_lock_destroy(&tabla->wlock);
|
||||
mutex_destroy(&tabla->pm_lock);
|
||||
mutex_destroy(&tabla->io_lock);
|
||||
mutex_destroy(&tabla->xfer_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tabla_device_exit(struct tabla *tabla)
|
||||
{
|
||||
tabla_irq_exit(tabla);
|
||||
tabla_bring_down(tabla);
|
||||
tabla_free_reset(tabla);
|
||||
mutex_destroy(&tabla->pm_lock);
|
||||
wake_lock_destroy(&tabla->wlock);
|
||||
mutex_destroy(&tabla->io_lock);
|
||||
mutex_destroy(&tabla->xfer_lock);
|
||||
slim_remove_device(tabla->slim_slave);
|
||||
kfree(tabla);
|
||||
}
|
||||
|
||||
|
||||
@@ -707,13 +717,13 @@ int tabla_i2c_read_device(unsigned short reg,
|
||||
}
|
||||
|
||||
int tabla_i2c_read(struct tabla *tabla, unsigned short reg,
|
||||
int bytes, void *dest, bool interface_reg)
|
||||
int bytes, void *dest, bool interface_reg)
|
||||
{
|
||||
return tabla_i2c_read_device(reg, bytes, dest);
|
||||
}
|
||||
|
||||
int tabla_i2c_write(struct tabla *tabla, unsigned short reg,
|
||||
int bytes, void *src, bool interface_reg)
|
||||
int bytes, void *src, bool interface_reg)
|
||||
{
|
||||
return tabla_i2c_write_device(reg, src, bytes);
|
||||
}
|
||||
@@ -799,7 +809,13 @@ fail:
|
||||
|
||||
static int __devexit tabla_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tabla *tabla;
|
||||
|
||||
pr_debug("exit\n");
|
||||
tabla = dev_get_drvdata(&client->dev);
|
||||
tabla_device_exit(tabla);
|
||||
tabla_disable_supplies(tabla);
|
||||
kfree(tabla);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -935,6 +951,7 @@ err_tabla:
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tabla_slim_remove(struct slim_device *pdev)
|
||||
{
|
||||
struct tabla *tabla;
|
||||
@@ -948,14 +965,103 @@ static int tabla_slim_remove(struct slim_device *pdev)
|
||||
tabla = slim_get_devicedata(pdev);
|
||||
tabla_device_exit(tabla);
|
||||
tabla_disable_supplies(tabla);
|
||||
slim_remove_device(tabla->slim_slave);
|
||||
kfree(tabla);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tabla_resume(struct tabla *tabla)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
mutex_lock(&tabla->pm_lock);
|
||||
if (tabla->pm_state == TABLA_PM_ASLEEP) {
|
||||
pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
|
||||
tabla->pm_state, tabla->wlock_holders);
|
||||
tabla->pm_state = TABLA_PM_SLEEPABLE;
|
||||
} else {
|
||||
pr_warn("%s: system is already awake, state %d wlock %d\n",
|
||||
__func__, tabla->pm_state, tabla->wlock_holders);
|
||||
}
|
||||
mutex_unlock(&tabla->pm_lock);
|
||||
wake_up_all(&tabla->pm_wq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tabla_slim_resume(struct slim_device *sldev)
|
||||
{
|
||||
struct tabla *tabla = slim_get_devicedata(sldev);
|
||||
return tabla_resume(tabla);
|
||||
}
|
||||
|
||||
static int tabla_i2c_resume(struct i2c_client *i2cdev)
|
||||
{
|
||||
struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
|
||||
return tabla_resume(tabla);
|
||||
}
|
||||
|
||||
static int tabla_suspend(struct tabla *tabla, pm_message_t pmesg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
/* wake_lock() can be called after this suspend chain call started.
|
||||
* thus suspend can be called while wlock is being held */
|
||||
mutex_lock(&tabla->pm_lock);
|
||||
if (tabla->pm_state == TABLA_PM_SLEEPABLE) {
|
||||
pr_debug("%s: suspending system, state %d, wlock %d\n",
|
||||
__func__, tabla->pm_state, tabla->wlock_holders);
|
||||
tabla->pm_state = TABLA_PM_ASLEEP;
|
||||
} else if (tabla->pm_state == TABLA_PM_AWAKE) {
|
||||
/* unlock to wait for pm_state == TABLA_PM_SLEEPABLE
|
||||
* then set to TABLA_PM_ASLEEP */
|
||||
pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
|
||||
__func__, tabla->pm_state, tabla->wlock_holders);
|
||||
mutex_unlock(&tabla->pm_lock);
|
||||
if (!(wait_event_timeout(tabla->pm_wq,
|
||||
tabla_pm_cmpxchg(tabla,
|
||||
TABLA_PM_SLEEPABLE,
|
||||
TABLA_PM_ASLEEP) ==
|
||||
TABLA_PM_SLEEPABLE,
|
||||
HZ))) {
|
||||
pr_debug("%s: suspend failed state %d, wlock %d\n",
|
||||
__func__, tabla->pm_state,
|
||||
tabla->wlock_holders);
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
pr_debug("%s: done, state %d, wlock %d\n", __func__,
|
||||
tabla->pm_state, tabla->wlock_holders);
|
||||
}
|
||||
mutex_lock(&tabla->pm_lock);
|
||||
} else if (tabla->pm_state == TABLA_PM_ASLEEP) {
|
||||
pr_warn("%s: system is already suspended, state %d, wlock %dn",
|
||||
__func__, tabla->pm_state, tabla->wlock_holders);
|
||||
}
|
||||
mutex_unlock(&tabla->pm_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tabla_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
|
||||
{
|
||||
struct tabla *tabla = slim_get_devicedata(sldev);
|
||||
return tabla_suspend(tabla, pmesg);
|
||||
}
|
||||
|
||||
static int tabla_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
|
||||
{
|
||||
struct tabla *tabla = dev_get_drvdata(&i2cdev->dev);
|
||||
return tabla_suspend(tabla, pmesg);
|
||||
}
|
||||
|
||||
static const struct slim_device_id slimtest_id[] = {
|
||||
{"tabla-slim", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct slim_driver tabla_slim_driver = {
|
||||
.driver = {
|
||||
.name = "tabla-slim",
|
||||
@@ -964,6 +1070,8 @@ static struct slim_driver tabla_slim_driver = {
|
||||
.probe = tabla_slim_probe,
|
||||
.remove = tabla_slim_remove,
|
||||
.id_table = slimtest_id,
|
||||
.resume = tabla_slim_resume,
|
||||
.suspend = tabla_slim_suspend,
|
||||
};
|
||||
|
||||
static const struct slim_device_id slimtest2x_id[] = {
|
||||
@@ -979,6 +1087,8 @@ static struct slim_driver tabla2x_slim_driver = {
|
||||
.probe = tabla_slim_probe,
|
||||
.remove = tabla_slim_remove,
|
||||
.id_table = slimtest2x_id,
|
||||
.resume = tabla_slim_resume,
|
||||
.suspend = tabla_slim_suspend,
|
||||
};
|
||||
|
||||
#define TABLA_I2C_TOP_LEVEL 0
|
||||
@@ -996,13 +1106,15 @@ static struct i2c_device_id tabla_id_table[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, tabla_id_table);
|
||||
|
||||
static struct i2c_driver tabla_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "tabla-i2c-core",
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "tabla-i2c-core",
|
||||
},
|
||||
.id_table = tabla_id_table,
|
||||
.probe = tabla_i2c_probe,
|
||||
.remove = __devexit_p(tabla_i2c_remove),
|
||||
.id_table = tabla_id_table,
|
||||
.probe = tabla_i2c_probe,
|
||||
.remove = __devexit_p(tabla_i2c_remove),
|
||||
.resume = tabla_i2c_resume,
|
||||
.suspend = tabla_i2c_suspend,
|
||||
};
|
||||
|
||||
static int __init tabla_init(void)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
/* 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
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/wcd9310/core.h>
|
||||
@@ -83,6 +84,60 @@ static struct irq_chip tabla_irq_chip = {
|
||||
.irq_enable = tabla_irq_enable,
|
||||
};
|
||||
|
||||
enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
|
||||
enum tabla_pm_state n)
|
||||
{
|
||||
enum tabla_pm_state old;
|
||||
mutex_lock(&tabla->pm_lock);
|
||||
old = tabla->pm_state;
|
||||
if (old == o)
|
||||
tabla->pm_state = n;
|
||||
mutex_unlock(&tabla->pm_lock);
|
||||
return old;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tabla_pm_cmpxchg);
|
||||
|
||||
void tabla_lock_sleep(struct tabla *tabla)
|
||||
{
|
||||
enum tabla_pm_state os;
|
||||
|
||||
/* tabla_{lock/unlock}_sleep will be called by tabla_irq_thread
|
||||
* and its subroutines only motly.
|
||||
* but btn0_lpress_fn is not tabla_irq_thread's subroutine and
|
||||
* it can race with tabla_irq_thread.
|
||||
* so need to embrace wlock_holders with mutex.
|
||||
*/
|
||||
mutex_lock(&tabla->pm_lock);
|
||||
if (tabla->wlock_holders++ == 0)
|
||||
wake_lock(&tabla->wlock);
|
||||
mutex_unlock(&tabla->pm_lock);
|
||||
while (!wait_event_timeout(tabla->pm_wq,
|
||||
((os = tabla_pm_cmpxchg(tabla, TABLA_PM_SLEEPABLE,
|
||||
TABLA_PM_AWAKE)) ==
|
||||
TABLA_PM_SLEEPABLE ||
|
||||
(os == TABLA_PM_AWAKE)),
|
||||
5 * HZ)) {
|
||||
pr_err("%s: system didn't resume within 5000ms, state %d, "
|
||||
"wlock %d\n", __func__, tabla->pm_state,
|
||||
tabla->wlock_holders);
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
wake_up_all(&tabla->pm_wq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tabla_lock_sleep);
|
||||
|
||||
void tabla_unlock_sleep(struct tabla *tabla)
|
||||
{
|
||||
mutex_lock(&tabla->pm_lock);
|
||||
if (--tabla->wlock_holders == 0) {
|
||||
tabla->pm_state = TABLA_PM_SLEEPABLE;
|
||||
wake_unlock(&tabla->wlock);
|
||||
}
|
||||
mutex_unlock(&tabla->pm_lock);
|
||||
wake_up_all(&tabla->pm_wq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tabla_unlock_sleep);
|
||||
|
||||
static irqreturn_t tabla_irq_thread(int irq, void *data)
|
||||
{
|
||||
int ret;
|
||||
@@ -90,11 +145,13 @@ static irqreturn_t tabla_irq_thread(int irq, void *data)
|
||||
u8 status[TABLA_NUM_IRQ_REGS];
|
||||
unsigned int i;
|
||||
|
||||
tabla_lock_sleep(tabla);
|
||||
ret = tabla_bulk_read(tabla, TABLA_A_INTR_STATUS0,
|
||||
TABLA_NUM_IRQ_REGS, status);
|
||||
if (ret < 0) {
|
||||
dev_err(tabla->dev, "Failed to read interrupt status: %d\n",
|
||||
ret);
|
||||
tabla_unlock_sleep(tabla);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
/* Apply masking */
|
||||
@@ -127,6 +184,7 @@ static irqreturn_t tabla_irq_thread(int irq, void *data)
|
||||
break;
|
||||
}
|
||||
}
|
||||
tabla_unlock_sleep(tabla);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define __MFD_TABLA_CORE_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wakelock.h>
|
||||
|
||||
#define TABLA_NUM_IRQ_REGS 3
|
||||
|
||||
@@ -55,6 +56,12 @@ enum {
|
||||
TABLA_NUM_IRQS,
|
||||
};
|
||||
|
||||
enum tabla_pm_state {
|
||||
TABLA_PM_SLEEPABLE,
|
||||
TABLA_PM_AWAKE,
|
||||
TABLA_PM_ASLEEP,
|
||||
};
|
||||
|
||||
struct tabla {
|
||||
struct device *dev;
|
||||
struct slim_device *slim;
|
||||
@@ -78,23 +85,33 @@ struct tabla {
|
||||
int bytes, void *src, bool interface_reg);
|
||||
|
||||
struct regulator_bulk_data *supplies;
|
||||
|
||||
enum tabla_pm_state pm_state;
|
||||
struct mutex pm_lock;
|
||||
/* pm_wq notifies change of pm_state */
|
||||
wait_queue_head_t pm_wq;
|
||||
struct wake_lock wlock;
|
||||
int wlock_holders;
|
||||
};
|
||||
|
||||
int tabla_reg_read(struct tabla *tabla, unsigned short reg);
|
||||
int tabla_reg_write(struct tabla *tabla, unsigned short reg,
|
||||
u8 val);
|
||||
int tabla_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
|
||||
int tabla_interface_reg_read(struct tabla *tabla, unsigned short reg);
|
||||
int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg,
|
||||
u8 val);
|
||||
int tabla_bulk_read(struct tabla *tabla, unsigned short reg,
|
||||
int count, u8 *buf);
|
||||
int tabla_bulk_write(struct tabla *tabla, unsigned short reg,
|
||||
int count, u8 *buf);
|
||||
int tabla_interface_reg_write(struct tabla *tabla, unsigned short reg, u8 val);
|
||||
int tabla_bulk_read(struct tabla *tabla, unsigned short reg, int count,
|
||||
u8 *buf);
|
||||
int tabla_bulk_write(struct tabla *tabla, unsigned short reg, int count,
|
||||
u8 *buf);
|
||||
int tabla_irq_init(struct tabla *tabla);
|
||||
void tabla_irq_exit(struct tabla *tabla);
|
||||
int tabla_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
|
||||
int tabla_get_intf_type(void);
|
||||
|
||||
void tabla_lock_sleep(struct tabla *tabla);
|
||||
void tabla_unlock_sleep(struct tabla *tabla);
|
||||
enum tabla_pm_state tabla_pm_cmpxchg(struct tabla *tabla, enum tabla_pm_state o,
|
||||
enum tabla_pm_state n);
|
||||
|
||||
static inline int tabla_request_irq(struct tabla *tabla, int irq,
|
||||
irq_handler_t handler, const char *name,
|
||||
void *data)
|
||||
|
||||
@@ -185,11 +185,6 @@ struct tabla_priv {
|
||||
struct work_struct hphlocp_work; /* reporting left hph ocp off */
|
||||
struct work_struct hphrocp_work; /* reporting right hph ocp off */
|
||||
|
||||
/* pm_cnt holds number of sleep lock holders + 1
|
||||
* so if pm_cnt is 1 system is sleep-able. */
|
||||
atomic_t pm_cnt;
|
||||
wait_queue_head_t pm_wq;
|
||||
|
||||
u8 hphlocp_cnt; /* headphone left ocp retry */
|
||||
u8 hphrocp_cnt; /* headphone right ocp retry */
|
||||
|
||||
@@ -3331,24 +3326,6 @@ static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tabla_lock_sleep(struct tabla_priv *tabla)
|
||||
{
|
||||
int ret;
|
||||
while (!(ret = wait_event_timeout(tabla->pm_wq,
|
||||
atomic_inc_not_zero(&tabla->pm_cnt),
|
||||
2 * HZ))) {
|
||||
pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
|
||||
__func__, ret, atomic_read(&tabla->pm_cnt));
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void tabla_unlock_sleep(struct tabla_priv *tabla)
|
||||
{
|
||||
atomic_dec(&tabla->pm_cnt);
|
||||
wake_up(&tabla->pm_wq);
|
||||
}
|
||||
|
||||
static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
|
||||
s16 vin_mv)
|
||||
{
|
||||
@@ -3403,11 +3380,13 @@ static void btn0_lpress_fn(struct work_struct *work)
|
||||
struct tabla_priv *tabla;
|
||||
short bias_value;
|
||||
int dce_mv, sta_mv;
|
||||
struct tabla *core;
|
||||
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
delayed_work = to_delayed_work(work);
|
||||
tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
|
||||
core = dev_get_drvdata(tabla->codec->dev->parent);
|
||||
|
||||
if (tabla) {
|
||||
if (tabla->button_jack) {
|
||||
@@ -3428,7 +3407,7 @@ static void btn0_lpress_fn(struct work_struct *work)
|
||||
pr_err("%s: Bad tabla private data\n", __func__);
|
||||
}
|
||||
|
||||
tabla_unlock_sleep(tabla);
|
||||
tabla_unlock_sleep(core);
|
||||
}
|
||||
|
||||
void tabla_mbhc_cal(struct snd_soc_codec *codec)
|
||||
@@ -3877,10 +3856,10 @@ static irqreturn_t tabla_dce_handler(int irq, void *data)
|
||||
TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
|
||||
short btnmeas[d->n_btn_meas + 1];
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
|
||||
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
bias_value_dce = tabla_codec_read_dce_result(codec);
|
||||
bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
|
||||
@@ -3926,11 +3905,12 @@ static irqreturn_t tabla_dce_handler(int irq, void *data)
|
||||
|
||||
/* XXX: assuming button 0 has the lowest micbias voltage */
|
||||
if (btn == 0) {
|
||||
tabla_lock_sleep(core);
|
||||
if (schedule_delayed_work(&priv->btn0_dwork,
|
||||
msecs_to_jiffies(400)) == 0) {
|
||||
WARN(1, "Button pressed twice without release"
|
||||
"event\n");
|
||||
tabla_unlock_sleep(priv);
|
||||
tabla_unlock_sleep(core);
|
||||
}
|
||||
} else {
|
||||
pr_debug("%s: Reporting short button %d(0x%x) press\n",
|
||||
@@ -3938,23 +3918,24 @@ static irqreturn_t tabla_dce_handler(int irq, void *data)
|
||||
tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
|
||||
mask);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
pr_debug("%s: bogus button press, too short press?\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t tabla_release_handler(int irq, void *data)
|
||||
{
|
||||
struct tabla_priv *priv = data;
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
int ret;
|
||||
short mb_v;
|
||||
struct tabla_priv *priv = data;
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
if (priv->buttons_pressed & SND_JACK_BTN_0) {
|
||||
ret = cancel_delayed_work(&priv->btn0_dwork);
|
||||
@@ -3968,7 +3949,7 @@ static irqreturn_t tabla_release_handler(int irq, void *data)
|
||||
} else {
|
||||
/* if scheduled btn0_dwork is canceled from here,
|
||||
* we have to unlock from here instead btn0_work */
|
||||
tabla_unlock_sleep(priv);
|
||||
tabla_unlock_sleep(core);
|
||||
mb_v = tabla_codec_sta_dce(codec, 0);
|
||||
pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
|
||||
__func__, mb_v,
|
||||
@@ -4006,7 +3987,6 @@ static irqreturn_t tabla_release_handler(int irq, void *data)
|
||||
}
|
||||
|
||||
tabla_codec_start_hs_polling(codec);
|
||||
tabla_unlock_sleep(priv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -4157,7 +4137,6 @@ static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
|
||||
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
|
||||
@@ -4229,7 +4208,6 @@ static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
|
||||
}
|
||||
tabla_codec_shutdown_hs_removal_detect(codec);
|
||||
tabla_codec_enable_hs_detect(codec, 1);
|
||||
tabla_unlock_sleep(priv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -4308,7 +4286,6 @@ static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
|
||||
tabla_sync_hph_state(priv);
|
||||
}
|
||||
|
||||
tabla_unlock_sleep(priv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -4326,7 +4303,6 @@ static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
|
||||
tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
usleep_range(generic->t_shutdown_plug_rem,
|
||||
generic->t_shutdown_plug_rem);
|
||||
@@ -4364,7 +4340,6 @@ static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
|
||||
tabla_codec_enable_hs_detect(codec, 1);
|
||||
}
|
||||
|
||||
tabla_unlock_sleep(priv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -4377,8 +4352,6 @@ static irqreturn_t tabla_slimbus_irq(int irq, void *data)
|
||||
int i, j;
|
||||
u8 val;
|
||||
|
||||
tabla_lock_sleep(priv);
|
||||
|
||||
for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
|
||||
slimbus_value = tabla_interface_reg_read(codec->control_data,
|
||||
TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
|
||||
@@ -4396,7 +4369,6 @@ static irqreturn_t tabla_slimbus_irq(int irq, void *data)
|
||||
TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
|
||||
}
|
||||
|
||||
tabla_unlock_sleep(priv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -4742,8 +4714,6 @@ static int tabla_codec_probe(struct snd_soc_codec *codec)
|
||||
tabla->codec = codec;
|
||||
tabla->pdata = dev_get_platdata(codec->dev->parent);
|
||||
tabla->intf_type = tabla_get_intf_type();
|
||||
atomic_set(&tabla->pm_cnt, 1);
|
||||
init_waitqueue_head(&tabla->pm_wq);
|
||||
|
||||
tabla_update_reg_address(tabla);
|
||||
tabla_update_reg_defaults(codec);
|
||||
@@ -4941,7 +4911,6 @@ static ssize_t codec_debug_write(struct file *filp,
|
||||
buf = (char *)lbuf;
|
||||
debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
|
||||
? false : true;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4954,53 +4923,14 @@ static const struct file_operations codec_debug_ops = {
|
||||
#ifdef CONFIG_PM
|
||||
static int tabla_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0, cnt;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct tabla_priv *tabla = platform_get_drvdata(pdev);
|
||||
|
||||
cnt = atomic_read(&tabla->pm_cnt);
|
||||
if (cnt > 0) {
|
||||
if (wait_event_timeout(tabla->pm_wq,
|
||||
(atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
|
||||
== 1), 5 * HZ)) {
|
||||
dev_dbg(dev, "system suspend pm_cnt %d\n",
|
||||
atomic_read(&tabla->pm_cnt));
|
||||
} else {
|
||||
dev_err(dev, "%s timed out pm_cnt = %d\n",
|
||||
__func__, atomic_read(&tabla->pm_cnt));
|
||||
WARN_ON_ONCE(1);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
} else if (cnt == 0)
|
||||
dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
|
||||
atomic_read(&tabla->pm_cnt));
|
||||
else {
|
||||
WARN(1, "unexpected pm_cnt %d\n", cnt);
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
dev_dbg(dev, "%s: system suspend\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tabla_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0, cnt;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct tabla_priv *tabla = platform_get_drvdata(pdev);
|
||||
|
||||
cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
|
||||
if (cnt == 0) {
|
||||
dev_dbg(dev, "system resume, pm_cnt %d\n",
|
||||
atomic_read(&tabla->pm_cnt));
|
||||
wake_up_all(&tabla->pm_wq);
|
||||
} else if (cnt > 0)
|
||||
dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
|
||||
else {
|
||||
WARN(1, "unexpected pm_cnt %d\n", cnt);
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
dev_dbg(dev, "%s: system resume\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tabla_pm_ops = {
|
||||
|
||||
Reference in New Issue
Block a user