From: Lucas Tanure tanureal@opensource.cirrus.com
Only disable I2C clock 25 ms after not being used
Signed-off-by: Lucas Tanure tanureal@opensource.cirrus.com Signed-off-by: Vitaly Rodionov vitalyr@opensource.cirrus.com --- sound/pci/hda/patch_cs8409.c | 42 +++++++++++++++++++++++------------- sound/pci/hda/patch_cs8409.h | 4 ++++ 2 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c index 08205c19698c..335bcdc69106 100644 --- a/sound/pci/hda/patch_cs8409.c +++ b/sound/pci/hda/patch_cs8409.c @@ -53,6 +53,7 @@ static struct cs8409_spec *cs8409_alloc_spec(struct hda_codec *codec) if (!spec) return NULL; codec->spec = spec; + spec->codec = codec; codec->power_save_node = 1; snd_hda_gen_spec_init(&spec->gen);
@@ -72,21 +73,34 @@ static inline void cs8409_vendor_coef_set(struct hda_codec *codec, unsigned int snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_PROC_COEF, coef); }
-/** +/* + * cs8409_disable_i2c_clock - Worker that disable the I2C Clock after 25ms without use + */ +static void cs8409_disable_i2c_clock(struct work_struct *work) +{ + struct cs8409_spec *spec = container_of(work, struct cs8409_spec, i2c_clk_work.work); + + cs8409_vendor_coef_set(spec->codec, 0x0, + cs8409_vendor_coef_get(spec->codec, 0x0) & 0xfffffff7); + spec->i2c_clck_enabled = 0; +} + +/* * cs8409_enable_i2c_clock - Enable I2C clocks * @codec: the codec instance - * @enable: Enable or disable I2C clocks - * * Enable or Disable I2C clocks. */ -static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int enable) +static void cs8409_enable_i2c_clock(struct hda_codec *codec) { - unsigned int retval; - unsigned int newval; + struct cs8409_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->i2c_clk_work);
- retval = cs8409_vendor_coef_get(codec, 0x0); - newval = (enable) ? (retval | 0x8) : (retval & 0xfffffff7); - cs8409_vendor_coef_set(codec, 0x0, newval); + if (!spec->i2c_clck_enabled) { + cs8409_vendor_coef_set(codec, 0x0, cs8409_vendor_coef_get(codec, 0x0) | 0x8); + spec->i2c_clck_enabled = 1; + } + queue_delayed_work(system_power_efficient_wq, &spec->i2c_clk_work, msecs_to_jiffies(25)); }
/** @@ -134,7 +148,7 @@ static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, un if (spec->cs42l42_suspended) return -EPERM;
- cs8409_enable_i2c_clock(codec, 1); + cs8409_enable_i2c_clock(codec); cs8409_vendor_coef_set(codec, CS8409_I2C_ADDR, i2c_address);
if (paged) { @@ -157,8 +171,6 @@ static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, un /* Register in bits 15-8 and the data in 7-0 */ read_data = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD);
- cs8409_enable_i2c_clock(codec, 0); - return read_data & 0x0ff; }
@@ -182,7 +194,7 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u if (spec->cs42l42_suspended) return -EPERM;
- cs8409_enable_i2c_clock(codec, 1); + cs8409_enable_i2c_clock(codec); cs8409_vendor_coef_set(codec, CS8409_I2C_ADDR, i2c_address);
if (paged) { @@ -203,8 +215,6 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u return -EIO; }
- cs8409_enable_i2c_clock(codec, 0); - return 0; }
@@ -705,6 +715,8 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, spec->cs42l42_mic_jack_in = 0; spec->cs42l42_suspended = 1;
+ INIT_DELAYED_WORK(&spec->i2c_clk_work, cs8409_disable_i2c_clock); + /* Basic initial sequence for specific hw configuration */ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h index bf0e8a4cc4cc..542582c213d2 100644 --- a/sound/pci/hda/patch_cs8409.h +++ b/sound/pci/hda/patch_cs8409.h @@ -11,6 +11,7 @@
#include <linux/pci.h> #include <sound/tlv.h> +#include <linux/workqueue.h> #include <sound/hda_codec.h> #include "hda_local.h" #include "hda_auto_parser.h" @@ -267,6 +268,7 @@ struct cs8409_cir_param {
struct cs8409_spec { struct hda_gen_spec gen; + struct hda_codec *codec;
unsigned int gpio_mask; unsigned int gpio_dir; @@ -278,6 +280,8 @@ struct cs8409_spec { s8 vol[CS42L42_VOLUMES];
struct mutex cs8409_i2c_mux; + unsigned int i2c_clck_enabled; + struct delayed_work i2c_clk_work;
/* verb exec op override */ int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,