couple of nit-picks/typos/indentations, see below. On 8/23/21 11:16 PM, Seven Lee wrote: > The driver is for codec NAU88L21 of Nuvoton Technology Corporation. > The NAU88L21 is an ultra-low power high performance audio codec that > supportsboth analog and digital audio functions. supports both > diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig > index 82ee233a269d..11bcf17b5f91 100644 > --- a/sound/soc/codecs/Kconfig > +++ b/sound/soc/codecs/Kconfig > @@ -136,6 +136,7 @@ config SND_SOC_ALL_CODECS > imply SND_SOC_NAU8315 > imply SND_SOC_NAU8540 > imply SND_SOC_NAU8810 > + imply SND_SOC_NAU8821 indent looks off? > imply SND_SOC_NAU8822 > imply SND_SOC_NAU8824 > imply SND_SOC_NAU8825 > @@ -1904,6 +1905,10 @@ config SND_SOC_NAU8810 > tristate "Nuvoton Technology Corporation NAU88C10 CODEC" > depends on I2C > > +config SND_SOC_NAU8821 > + tristate "Nuvoton Technology Corporation NAU88L21 CODEC" > + depends on I2C > + and here indent is off as well? > +#include <linux/module.h> > +#include <linux/delay.h> > +#include <linux/init.h> > +#include <linux/i2c.h> > +#include <linux/regmap.h> > +#include <linux/slab.h> > +#include <linux/clk.h> > +#include <linux/acpi.h> > +#include <linux/math64.h> > +#include <linux/semaphore.h> > +#include <sound/initval.h> > +#include <sound/tlv.h> > +#include <sound/core.h> > +#include <sound/pcm.h> > +#include <sound/pcm_params.h> > +#include <sound/soc.h> > +#include <sound/jack.h> alphabetical order? > +/** > + * nau8821_sema_acquire - acquire the semaphore of nau8821 > + * @nau8821: component to register the codec private data with > + * @timeout: how long in jiffies to wait before failure or zero to wait > + * until release > + * > + * Attempts to acquire the semaphore with number of jiffies. If no more > + * tasks are allowed to acquire the semaphore, calling this function will > + * put the task to sleep. If the semaphore is not released within the > + * specified number of jiffies, this function returns. > + * If the semaphore is not released within the specified number of jiffies, > + * this function returns -ETIME. If the sleep is interrupted by a signal, > + * this function will return -EINTR. It returns 0 if the semaphore was > + * acquired successfully. > + * > + * Acquires the semaphore without jiffies. Try to acquire the semaphore > + * atomically. Returns 0 if the semaphore has been acquired successfully > + * or 1 if it cannot be acquired. > + */ > +static int nau8821_sema_acquire(struct nau8821 *nau8821, long timeout) > +{ > + int ret; > + > + if (!nau8821->irq) > + return 1; > + > + if (timeout) { > + ret = down_timeout(&nau8821->jd_sem, timeout); > + if (ret < 0) > + dev_dbg(nau8821->dev, "Acquire semaphore timeout\n"); > + } else { > + ret = down_trylock(&nau8821->jd_sem); > + if (ret) > + dev_dbg(nau8821->dev, "Acquire semaphore fail\n"); > + } > + > + return ret; > +} > + > +/** > + * nau8821_sema_release - release the semaphore of nau8821 > + * @nau8821: component to register the codec private data with > + * > + * Release the semaphore which may be called from any context and > + * even by tasks which have never called down(). > + */ > +static inline void nau8821_sema_release(struct nau8821 *nau8821) > +{ > + if (!nau8821->irq) > + return; > + up(&nau8821->jd_sem); > +} is there any specific reason why Nuvoton codec drivers use a semaphore? isn't a mutex good enough? > + > +/** > + * nau8821_sema_reset - reset the semaphore for nau8821 > + * @nau8821: component to register the codec private data with > + * > + * Reset the counter of the semaphore. Call this function to restart > + * a new round task management. > + */ > +static inline void nau8821_sema_reset(struct nau8821 *nau8821) > +{ > + nau8821->jd_sem.count = 1; > +} > +static int nau8821_left_adc_event(struct snd_soc_dapm_widget *w, > + struct snd_kcontrol *kcontrol, int event) > +{ > + struct snd_soc_component *component = > + snd_soc_dapm_to_component(w->dapm); > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + > + switch (event) { > + case SND_SOC_DAPM_POST_PMU: > + msleep(125); use a define to keep track of sleep times in a header file? > + regmap_update_bits(nau8821->regmap, NAU8821_R01_ENA_CTRL, > + NAU8821_EN_ADCL, NAU8821_EN_ADCL); > + break; > + case SND_SOC_DAPM_POST_PMD: > + regmap_update_bits(nau8821->regmap, > + NAU8821_R01_ENA_CTRL, NAU8821_EN_ADCL, 0); > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int nau8821_right_adc_event(struct snd_soc_dapm_widget *w, > + struct snd_kcontrol *kcontrol, int event) > +{ > + struct snd_soc_component *component = > + snd_soc_dapm_to_component(w->dapm); > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + > + switch (event) { > + case SND_SOC_DAPM_POST_PMU: > + msleep(125); #define? > + regmap_update_bits(nau8821->regmap, NAU8821_R01_ENA_CTRL, > + NAU8821_EN_ADCR, NAU8821_EN_ADCR); > + break; > + case SND_SOC_DAPM_POST_PMD: > + regmap_update_bits(nau8821->regmap, > + NAU8821_R01_ENA_CTRL, NAU8821_EN_ADCR, 0); > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int nau8821_pump_event(struct snd_soc_dapm_widget *w, > + struct snd_kcontrol *kcontrol, int event) > +{ > + struct snd_soc_component *component = > + snd_soc_dapm_to_component(w->dapm); > + struct nau8821 *nau8821 = > + snd_soc_component_get_drvdata(component); > + > + switch (event) { > + case SND_SOC_DAPM_POST_PMU: > + /* Prevent startup click by letting charge pump to ramp up */ > + msleep(20); #define? > + regmap_update_bits(nau8821->regmap, NAU8821_R80_CHARGE_PUMP, > + NAU8821_JAMNODCLOW, NAU8821_JAMNODCLOW); > + break; > + case SND_SOC_DAPM_PRE_PMD: > + regmap_update_bits(nau8821->regmap, NAU8821_R80_CHARGE_PUMP, > + NAU8821_JAMNODCLOW, 0); > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int nau8821_output_dac_event(struct snd_soc_dapm_widget *w, > + struct snd_kcontrol *kcontrol, int event) > +{ > + struct snd_soc_component *component = > + snd_soc_dapm_to_component(w->dapm); > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + > + switch (event) { > + case SND_SOC_DAPM_PRE_PMU: > + /* Disables the TESTDAC to let DAC signal pass through. */ > + regmap_update_bits(nau8821->regmap, NAU8821_R66_BIAS_ADJ, > + NAU8821_BIAS_TESTDAC_EN, 0); > + break; > + case SND_SOC_DAPM_POST_PMD: > + regmap_update_bits(nau8821->regmap, NAU8821_R66_BIAS_ADJ, > + NAU8821_BIAS_TESTDAC_EN, NAU8821_BIAS_TESTDAC_EN); > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > +static int nau8821_clock_check(struct nau8821 *nau8821, > + int stream, int rate, int osr) > +{ > + int osrate = 0; > + > + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { > + if (osr >= ARRAY_SIZE(osr_dac_sel)) > + return -EINVAL; > + osrate = osr_dac_sel[osr].osr; > + } else { > + if (osr >= ARRAY_SIZE(osr_adc_sel)) > + return -EINVAL; > + osrate = osr_adc_sel[osr].osr; > + } > + > + if (!osrate || rate * osrate > CLK_DA_AD_MAX) { > + dev_err(nau8821->dev, > + "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); odd indentation > + return -EINVAL; > + } > + > + return 0; > +} > +static int nau8821_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) > +{ > + struct snd_soc_component *component = codec_dai->component; > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + unsigned int ctrl1_val = 0, ctrl2_val = 0; > + > + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { > + case SND_SOC_DAIFMT_CBM_CFM: use CDP_CFP > + ctrl2_val |= NAU8821_I2S_MS_MASTER; > + break; > + case SND_SOC_DAIFMT_CBS_CFS: use CBC_CFC > + break; > + default: > + return -EINVAL; > + } > + > + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { > + case SND_SOC_DAIFMT_NB_NF: > + break; > + case SND_SOC_DAIFMT_IB_NF: > + ctrl1_val |= NAU8821_I2S_BP_INV; > + break; > + default: > + return -EINVAL; > + } > + > + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { > + case SND_SOC_DAIFMT_I2S: > + ctrl1_val |= NAU8821_I2S_DF_I2S; > + break; > + case SND_SOC_DAIFMT_LEFT_J: > + ctrl1_val |= NAU8821_I2S_DF_LEFT; > + break; > + case SND_SOC_DAIFMT_RIGHT_J: > + ctrl1_val |= NAU8821_I2S_DF_RIGTH; > + break; > + case SND_SOC_DAIFMT_DSP_A: > + ctrl1_val |= NAU8821_I2S_DF_PCM_AB; > + break; > + case SND_SOC_DAIFMT_DSP_B: > + ctrl1_val |= NAU8821_I2S_DF_PCM_AB; > + ctrl1_val |= NAU8821_I2S_PCMB_EN; > + break; > + default: > + return -EINVAL; > + } > + > + nau8821_sema_acquire(nau8821, HZ); > + > + regmap_update_bits(nau8821->regmap, NAU8821_R1C_I2S_PCM_CTRL1, > + NAU8821_I2S_DL_MASK | NAU8821_I2S_DF_MASK | > + NAU8821_I2S_BP_MASK | NAU8821_I2S_PCMB_MASK, ctrl1_val); > + regmap_update_bits(nau8821->regmap, NAU8821_R1D_I2S_PCM_CTRL2, > + NAU8821_I2S_MS_MASK, ctrl2_val); > + > + nau8821_sema_release(nau8821); > + > + return 0; > +} > + > +static int nau8821_digital_mute(struct snd_soc_dai *dai, int mute, > + int direction) indentation? > +{ > + struct snd_soc_component *component = dai->component; > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + unsigned int val = 0; > + > + if (mute) > + val = NAU8821_DAC_SOFT_MUTE; > + > + return regmap_update_bits(nau8821->regmap, > + NAU8821_R31_MUTE_CTRL, NAU8821_DAC_SOFT_MUTE, val); > +} > + > +static int nau8821_set_bias_level(struct snd_soc_component *component, > + enum snd_soc_bias_level level) > +{ > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + struct regmap *regmap = nau8821->regmap; > + > + switch (level) { > + case SND_SOC_BIAS_ON: > + break; > + > + case SND_SOC_BIAS_PREPARE: > + break; > + > + case SND_SOC_BIAS_STANDBY: > + /* Setup codec configuration after resume */ > + if (snd_soc_component_get_bias_level(component) == > + SND_SOC_BIAS_OFF) > + nau8821_resume_setup(nau8821); > + break; > + > + case SND_SOC_BIAS_OFF: > + /* HPL/HPR short to ground */ > + regmap_update_bits(regmap, NAU8821_R0D_JACK_DET_CTRL, > + NAU8821_SPKR_DWN1R | NAU8821_SPKR_DWN1L, 0); > + if (nau8821->irq) { > + /* Reset semaphore */ > + nau8821_sema_reset(nau8821); > + /* Reset the configuration of jack type for detection. > + * Detach 2kOhm Resistors from MICBIAS to MICGND1/2. > + */ > + regmap_update_bits(regmap, NAU8821_R74_MIC_BIAS, > + NAU8821_MICBIAS_JKR2, 0); > + /* Turn off all interruptions before system shutdown. > + * Keep theinterruption quiet before resume > + * setup completes. > + */ > + regmap_write(regmap, > + NAU8821_R12_INTERRUPT_DIS_CTRL, 0xffff); > + regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK, > + NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN, > + NAU8821_IRQ_EJECT_EN | NAU8821_IRQ_INSERT_EN); > + } > + break; default case? > + } > + > + return 0; > +} > + > +static int __maybe_unused nau8821_suspend(struct snd_soc_component *component) > +{ > + struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component); > + > + if (nau8821->irq) > + disable_irq(nau8821->irq); > + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); > + /* Power down codec power; don't suppoet button wakeup */ support? > + snd_soc_dapm_disable_pin(nau8821->dapm, "MICBIAS"); > + snd_soc_dapm_sync(nau8821->dapm); > + regcache_cache_only(nau8821->regmap, true); > + regcache_mark_dirty(nau8821->regmap); > + > + return 0; > +} > + > +MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL"); the license version is provided by the SPDX line