Merge "asoc: codecs: No I2C activity when EP92 is inactive"

This commit is contained in:
qctecmdr
2019-09-04 03:35:11 -07:00
committed by Gerrit - the friendly Code Review server
melakukan 9197a2e94a

Melihat File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/init.h>
@@ -25,6 +25,7 @@
#define EP92_POLL_INTERVAL_OFF_MSEC 200
#define EP92_POLL_INTERVAL_ON_MSEC 20
#define EP92_POLL_RUNOUT_MSEC 5000
#define EP92_SYSFS_ENTRY_MAX_LEN 64
#define EP92_HYST_CNT 5
@@ -68,6 +69,9 @@ struct ep92_pdata {
struct timer_list timer;
struct work_struct read_status_worker;
int irq;
int poll_trig;
int poll_rem;
int force_inactive;
int hyst_tx_plug;
int hyst_link_on0;
@@ -648,10 +652,8 @@ static int ep92_probe(struct snd_soc_component *component)
ep92_init(component, ep92);
/* start polling when codec is registered */
if (ep92->irq == 0) {
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
}
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
return 0;
}
@@ -690,6 +692,9 @@ void ep92_read_status(struct work_struct *work)
if (component == NULL)
return;
if (ep92->force_inactive)
return;
/* check ADO_CHF that is set when audio format has changed */
val = snd_soc_component_read32(component, EP92_BI_GENERAL_INFO_1);
if (val == 0xff) {
@@ -724,6 +729,10 @@ static irqreturn_t ep92_irq(int irq, void *data)
dev_dbg(component->dev, "ep92_interrupt\n");
ep92->poll_trig = 1;
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
schedule_work(&ep92->read_status_worker);
return IRQ_HANDLED;
@@ -732,14 +741,45 @@ static irqreturn_t ep92_irq(int irq, void *data)
void ep92_poll_status(struct timer_list *t)
{
struct ep92_pdata *ep92 = from_timer(ep92, t, timer);
u32 poll_msec;
struct snd_soc_component *component = ep92->component;
if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0)
poll_msec = EP92_POLL_INTERVAL_OFF_MSEC;
else
poll_msec = EP92_POLL_INTERVAL_ON_MSEC;
if (ep92->force_inactive)
return;
mod_timer(&ep92->timer, jiffies + msecs_to_jiffies(poll_msec));
/* if no IRQ is configured, always keep on polling */
if (ep92->irq == 0)
ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
/* on interrupt, start polling for some time */
if (ep92->poll_trig) {
if (ep92->poll_rem == 0)
dev_info(component->dev, "status checking activated\n");
ep92->poll_trig = 0;
ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
}
/*
* If power_on == 0, poll only until poll_rem reaches zero and stop.
* This allows to system to go to low power sleep mode.
* Otherwise (power_on == 1) always re-arm timer to keep on polling.
*/
if ((ep92->gc.ctl & EP92_GC_POWER_MASK) == 0) {
if (ep92->poll_rem) {
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC));
if (ep92->poll_rem > EP92_POLL_INTERVAL_OFF_MSEC) {
ep92->poll_rem -= EP92_POLL_INTERVAL_OFF_MSEC;
} else {
dev_info(component->dev, "status checking stopped\n");
ep92->poll_rem = 0;
}
}
} else {
ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
}
schedule_work(&ep92->read_status_worker);
}
@@ -1162,6 +1202,11 @@ static ssize_t ep92_sysfs_wta_power(struct device *dev,
ep92->gc.ctl &= ~EP92_GC_POWER_MASK;
ep92->gc.ctl |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK;
if (val == 1) {
ep92->poll_trig = 1;
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
}
rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
end:
return rc;
@@ -1321,12 +1366,12 @@ static ssize_t ep92_sysfs_wta_arc_enable(struct device *dev,
}
reg = snd_soc_component_read32(ep92->component, EP92_GENERAL_CONTROL_0);
reg &= ~EP92_GC_AUDIO_PATH_MASK;
reg |= (val << EP92_GC_AUDIO_PATH_SHIFT) & EP92_GC_AUDIO_PATH_MASK;
reg &= ~EP92_GC_ARC_EN_MASK;
reg |= (val << EP92_GC_ARC_EN_SHIFT) & EP92_GC_ARC_EN_MASK;
snd_soc_component_write(ep92->component, EP92_GENERAL_CONTROL_0, reg);
ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK;
ep92->gc.ctl |= (val << EP92_GC_AUDIO_PATH_SHIFT) &
EP92_GC_AUDIO_PATH_MASK;
ep92->gc.ctl &= ~EP92_GC_ARC_EN_MASK;
ep92->gc.ctl |= (val << EP92_GC_ARC_EN_SHIFT) &
EP92_GC_ARC_EN_MASK;
rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
end:
@@ -1440,6 +1485,83 @@ end:
return rc;
}
static ssize_t ep92_sysfs_rda_runout(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret;
int val;
struct ep92_pdata *ep92 = dev_get_drvdata(dev);
if (!ep92 || !ep92->component) {
dev_err(dev, "%s: device error\n", __func__);
return -ENODEV;
}
val = ep92->poll_rem;
ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
dev_dbg(dev, "%s: '%d'\n", __func__, val);
return ret;
}
static ssize_t ep92_sysfs_rda_force_inactive(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret;
int val;
struct ep92_pdata *ep92 = dev_get_drvdata(dev);
if (!ep92 || !ep92->component) {
dev_err(dev, "%s: device error\n", __func__);
return -ENODEV;
}
val = ep92->force_inactive;
ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val);
dev_dbg(dev, "%s: '%d'\n", __func__, val);
return ret;
}
static ssize_t ep92_sysfs_wta_force_inactive(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int val, rc;
struct ep92_pdata *ep92 = dev_get_drvdata(dev);
if (!ep92 || !ep92->component) {
dev_err(dev, "%s: device error\n", __func__);
return -ENODEV;
}
rc = kstrtoint(buf, 10, &val);
if (rc) {
dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc);
goto end;
}
if ((val < 0) || (val > 1)) {
dev_err(dev, "%s: value out of range.\n", __func__);
rc = -EINVAL;
goto end;
}
if (val == 0) {
ep92->force_inactive = 0;
ep92->poll_trig = 1;
mod_timer(&ep92->timer, jiffies +
msecs_to_jiffies(EP92_POLL_INTERVAL_ON_MSEC));
} else {
ep92->force_inactive = 1;
ep92->poll_rem = 0;
}
rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN);
end:
return rc;
}
static DEVICE_ATTR(chipid, 0444, ep92_sysfs_rda_chipid, NULL);
static DEVICE_ATTR(version, 0444, ep92_sysfs_rda_version, NULL);
static DEVICE_ATTR(audio_state, 0444, ep92_sysfs_rda_audio_state, NULL);
@@ -1467,6 +1589,9 @@ static DEVICE_ATTR(cec_mute, 0644, ep92_sysfs_rda_cec_mute,
ep92_sysfs_wta_cec_mute);
static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume,
ep92_sysfs_wta_cec_volume);
static DEVICE_ATTR(runout, 0444, ep92_sysfs_rda_runout, NULL);
static DEVICE_ATTR(force_inactive, 0644, ep92_sysfs_rda_force_inactive,
ep92_sysfs_wta_force_inactive);
static struct attribute *ep92_fs_attrs[] = {
&dev_attr_chipid.attr,
@@ -1490,6 +1615,8 @@ static struct attribute *ep92_fs_attrs[] = {
&dev_attr_arc_enable.attr,
&dev_attr_cec_mute.attr,
&dev_attr_cec_volume.attr,
&dev_attr_runout.attr,
&dev_attr_force_inactive.attr,
NULL,
};
@@ -1552,9 +1679,9 @@ static int ep92_i2c_probe(struct i2c_client *client,
ep92->irq = 0;
}
}
/* poll status if IRQ is not configured */
if (ep92->irq == 0)
timer_setup(&ep92->timer, ep92_poll_status, 0);
/* prepare timer */
timer_setup(&ep92->timer, ep92_poll_status, 0);
ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;
#if IS_ENABLED(CONFIG_DEBUG_FS)
/* debugfs interface */
@@ -1610,8 +1737,7 @@ static int ep92_i2c_probe(struct i2c_client *client,
err_sysfs:
snd_soc_unregister_component(&client->dev);
err_reg:
if (ep92->irq == 0)
del_timer(&ep92->timer);
del_timer(&ep92->timer);
return ret;
}
@@ -1622,8 +1748,7 @@ static int ep92_i2c_remove(struct i2c_client *client)
ep92 = i2c_get_clientdata(client);
if (ep92) {
if (ep92->irq == 0)
del_timer(&ep92->timer);
del_timer(&ep92->timer);
#if IS_ENABLED(CONFIG_DEBUG_FS)
debugfs_remove_recursive(ep92->debugfs_dir);