Much improved version, thank you. See additional comments/questions below. > +static int es8326_set_bias_level(struct snd_soc_component *codec, > + enum snd_soc_bias_level level) > +{ > + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(codec); > + int ret; > + > + switch (level) { > + case SND_SOC_BIAS_ON: > + if (!IS_ERR(es8326->mclk)) { the IS_ERR case is taken care of in the probe, so should this be if (es8326->mclk) for symmetry with the BIAS_OFF case? > + ret = clk_prepare_enable(es8326->mclk); > + if (ret) > + return ret; > + } > + regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_PWRUP_SEQ_EN); > + regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45); > + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A, > + (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT)); > + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT); > + regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE_03, 0x05); > + regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x02); > + regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0x40); > + regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0xAA); > + regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON); > + break; > + case SND_SOC_BIAS_PREPARE: > + break; > + case SND_SOC_BIAS_STANDBY: > + break; > + case SND_SOC_BIAS_OFF: > + if (es8326->mclk)> + clk_disable_unprepare(es8326->mclk); > + regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x11); > + regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_OFF); > + regmap_write(es8326->regmap, ES8326_PGA_PDN_17, 0xF8); > + regmap_write(es8326->regmap, ES8326_VMIDSEL_18, 0x00); > + regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08); > + regmap_write(es8326->regmap, ES8326_SDINOUT1_IO_5A, ES8326_IO_INPUT); > + regmap_write(es8326->regmap, ES8326_SDINOUT23_IO_5B, ES8326_IO_INPUT); > + regmap_write(es8326->regmap, ES8326_RESET_00, > + ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN); > + break; > + } > + > + return 0; > +} > +static irqreturn_t es8326_irq(int irq, void *dev_id) > +{ > + struct es8326_priv *es8326 = dev_id; > + struct snd_soc_component *comp = es8326->component; > + > + if (!es8326->jack) > + goto out; > + > + es8326_enable_micbias(comp); > + > + queue_delayed_work(system_wq, &es8326->jack_detect_work, > + msecs_to_jiffies(300)); > + > +out: > + return IRQ_HANDLED; > +} > + > +static int es8326_resume(struct snd_soc_component *component) > +{ > + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); > + > + regcache_cache_only(es8326->regmap, false); > + regcache_sync(es8326->regmap); > + > + regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_ON); > + /* Two channel ADC */ > + regmap_write(es8326->regmap, ES8326_PULLUP_CTL_F9, 0x02); > + regmap_write(es8326->regmap, ES8326_CLK_INV_02, 0x00); > + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC_0C, 0x1F); > + regmap_write(es8326->regmap, ES8326_CLK_VMIDS1_10, 0xC8); > + regmap_write(es8326->regmap, ES8326_CLK_VMIDS2_11, 0x88); > + regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME_12, 0x20); > + regmap_write(es8326->regmap, ES8326_SYS_BIAS_1D, 0x08); > + regmap_write(es8326->regmap, ES8326_DAC2HPMIX_25, 0x22); > + regmap_write(es8326->regmap, ES8326_ADC1_SRC_2A, es8326->mic1_src); > + regmap_write(es8326->regmap, ES8326_ADC2_SRC_2B, es8326->mic2_src); > + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER_56, 0x88); > + regmap_write(es8326->regmap, ES8326_HP_DET_57, > + ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol); > + regmap_write(es8326->regmap, ES8326_INT_SOURCE_58, 0x08); > + regmap_write(es8326->regmap, ES8326_INTOUT_IO_59, 0x45); > + regmap_write(es8326->regmap, ES8326_RESET_00, ES8326_CSM_ON); > + snd_soc_component_update_bits(component, ES8326_PGAGAIN_23, > + ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL); > + > + es8326_irq(es8326->irq, es8326); > + return 0; > +} > + > +static int es8326_suspend(struct snd_soc_component *component) > +{ > + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); > + > + es8326_disable_micbias(component); > + cancel_delayed_work_sync(&es8326->jack_detect_work); I would have swapped the two lines above, first cancel the workqueue (which means let it run if it started already). > + > + regmap_write(es8326->regmap, ES8326_CLK_CTL_01, ES8326_CLK_OFF); > + regcache_cache_only(es8326->regmap, true); > + regcache_mark_dirty(es8326->regmap); > + > + return 0; > +} One question on the interrupt handling: should there be an interrupt disable on suspend and conversely an interrupt enable on resume? > + > +static int es8326_probe(struct snd_soc_component *component) > +{ > + struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); > + int ret; > + > + es8326->component = component; > + es8326->jd_inverted = device_property_read_bool(component->dev, > + "everest,jack-detect-inverted"); > + > + ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src); > + if (ret != 0) { > + dev_dbg(component->dev, "mic1-src return %d", ret); > + es8326->mic1_src = ES8326_ADC_AMIC; > + } > + dev_dbg(component->dev, "mic1-src %x", es8326->mic1_src); > + > + ret = device_property_read_u8(component->dev, "everest,mic2-src", &es8326->mic2_src); > + if (ret != 0) { > + dev_dbg(component->dev, "mic2-src return %d", ret); > + es8326->mic2_src = ES8326_ADC_DMIC; > + } > + dev_dbg(component->dev, "mic2-src %x", es8326->mic2_src); > + > + ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol); > + if (ret != 0) { > + dev_dbg(component->dev, "jack-pol return %d", ret); > + es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP; > + } > + dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol); > + > + es8326_resume(component); > + return 0; > +} > +static int es8326_i2c_probe(struct i2c_client *i2c, > + const struct i2c_device_id *id) > +{ > + struct es8326_priv *es8326; > + int ret; > + > + es8326 = devm_kzalloc(&i2c->dev, sizeof(struct es8326_priv), GFP_KERNEL); > + if (!es8326) > + return -ENOMEM; > + > + i2c_set_clientdata(i2c, es8326); > + es8326->i2c = i2c; > + mutex_init(&es8326->lock); > + es8326->regmap = devm_regmap_init_i2c(i2c, &es8326_regmap_config); > + if (IS_ERR(es8326->regmap)) { > + ret = PTR_ERR(es8326->regmap); > + dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); > + return ret; > + } > + > + es8326->irq = i2c->irq; > + INIT_DELAYED_WORK(&es8326->jack_detect_work, > + es8326_jack_detect_handler); > + /* ES8316 is level-based while ES8326 is edge-based */ > + ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq, > + IRQF_TRIGGER_RISING | IRQF_ONESHOT, > + "es8326", es8326); > + if (ret) { > + dev_warn(&i2c->dev, "Failed to reguest IRQ: %d: %d\n", typo: request > + es8326->irq, ret); > + es8326->irq = -ENXIO; > + } > + > + es8326->mclk = devm_clk_get_optional(&i2c->dev, "mclk"); > + if (IS_ERR(es8326->mclk)) { > + dev_err(&i2c->dev, "unable to get mclk\n"); > + return PTR_ERR(es8326->mclk); > + } > + if (!es8326->mclk) > + dev_warn(&i2c->dev, "assuming static mclk\n"); > + > + ret = clk_prepare_enable(es8326->mclk); > + if (ret) { > + dev_err(&i2c->dev, "unable to enable mclk\n"); > + return ret; > + } I am not really following what happens if es8326->mclk is NULL. Why would you call clk_prepare_enable() with a NULL pointer? If you look at the code in es8326_set_bias_level(), you do test for that case, so why not here? Something's not right here. Could it be that this is a scope issue? This block should be moved under the scope of the if (!es8236->mclk) test, no? > + return devm_snd_soc_register_component(&i2c->dev, > + &soc_component_dev_es8326, > + &es8326_dai, 1); > +}