Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9197a2e9 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents a634c770 cf16dedb
Loading
Loading
Loading
Loading
+148 −23
Original line number Diff line number Diff line
// 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));
	}

	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;

	/* if no IRQ is configured, always keep on polling */
	if (ep92->irq == 0)
		ep92->poll_rem = EP92_POLL_RUNOUT_MSEC;

	mod_timer(&ep92->timer, jiffies + msecs_to_jiffies(poll_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 @@ static ssize_t ep92_sysfs_wta_cec_volume(struct device *dev,
	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)
	/* 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,7 +1737,6 @@ 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);

	return ret;
@@ -1622,7 +1748,6 @@ static int ep92_i2c_remove(struct i2c_client *client)

	ep92 = i2c_get_clientdata(client);
	if (ep92) {
		if (ep92->irq == 0)
		del_timer(&ep92->timer);

#if IS_ENABLED(CONFIG_DEBUG_FS)