[alsa-devel] [PATCH 001/001] ASoC: Replace max98090 Device Driver

Mark Brown broonie at opensource.wolfsonmicro.com
Thu Dec 27 18:26:30 CET 2012


On Thu, Dec 13, 2012 at 11:19:29AM -0800, Jerry Wong wrote:

For legibility please submit future revisions as a two stage patch
series, one removing the old driver and another adding the new one.

> +/* codec platform data */
> +struct max98090_pdata {
> +
> +       int irq;

This should be passed in using the normal mechanism provided by the bus,
not custom implemented.

> +       int power_over_performance;

This doesn't look like platform data to me, it looks like something that
should be configured dynamically at runtime.

> +       /* Equalizers for DAC */
> +       struct max98090_eq_cfg *eq_cfg;
> +       unsigned int eq_cfgcnt;

Coefficients should be configured using SND_SOC_BYTES().  Some older
drivers use this method but it's deprecated.

> +       { 0xE0, 0x00 }, /* E0 */
> +       { 0xE1, 0x00 }, /* E1 */
> +       { 0xE2, 0x00 }, /* E2 */

Do these number-only registers actually exist in the published register
map or are they undefined?  If they're undefined and not used by
software there's no need to include them here.

> +       switch (reg) {
> +       case M98090_REG_01_IRQ_STATUS:
> +       case M98090_REG_02_JACK_STATUS:
> +       case M98090_REG_FF_REV_ID:

Including the register number in the constants seems to rather defeat
the point of having symbolic names for the registers; it means people
still have to remember the register numbers.

> +static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
> +                               struct snd_ctl_elem_value *ucontrol)

What's the relevance of _tlv here?  It looks like these are normal get
and sets.

> +static const char * max98090_dsts_text[] =
> +       { "None", "Left", "Right", "Left and Right" };
> +
> +static const struct soc_enum max98090_dsts_enum =
> +       SOC_ENUM_SINGLE(M98090_REG_1A_LVL_SIDETONE, M98090_DSTS_SHIFT,
> +               ARRAY_SIZE(max98090_dsts_text), max98090_dsts_text);


> +static const struct snd_kcontrol_new max98090_snd_controls[] = {

> +       SOC_SINGLE("DMIC MIC Left Enable", M98090_REG_13_MIC_CFG1,
> +               M98090_DIGMICL_SHIFT, M98090_DIGMICL_NUM - 1, 0),
> +       SOC_SINGLE("DMIC MIC Right Enable", M98090_REG_13_MIC_CFG1,
> +               M98090_DIGMICR_SHIFT, M98090_DIGMICR_NUM - 1, 0),

This looks like it should be DAPM.

> +       SOC_ENUM_EXT("External MIC Mux", max98090_extmic_mux_enum,
> +               max98090_extmic_mux_get, max98090_extmic_mux_set),

Likewise.

> +       SOC_ENUM("Digital Sidetone Source", max98090_dsts_enum),

DAPM.

> +       SOC_SINGLE_EXT_TLV("Digital Sidetone Level Volume",
> +               M98090_REG_1A_LVL_SIDETONE, M98090_DVST_SHIFT,
> +               M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv,
> +               max98090_put_enab_tlv, max98090_micboost_tlv),

Level Volume?

> +       SOC_SINGLE_TLV("Digital Gain Volume", M98090_REG_27_DAI_LVL,
> +               M98090_DAI_LVL_DVG_SHIFT, M98090_DAI_LVL_DVG_NUM - 1, 0,
> +               max98090_dvg_tlv),

Gain Volume?

> +       SOC_SINGLE("Digital EQ 3 Band Enable", M98090_REG_41_DSP_EQ_EN,
> +               M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0),

Switch.

> +       SOC_SINGLE("DAC HP Playback Performance Mode", M98090_REG_43_DAC_CFG,
> +               M98090_DAC_PERFMODE_SHIFT, M98090_DAC_PERFMODE_NUM - 1, 0),
> +       SOC_SINGLE("DAC High Performance Mode", M98090_REG_43_DAC_CFG,
> +               M98090_DACHP_SHIFT, M98090_DACHP_NUM - 1, 0),

These should either be enumerations with real names of Switches if it's
just an on/off (looks like the former).

> +       SOC_SINGLE_TLV("Headphone Left Volume", M98090_REG_2C_LVL_HP_LEFT,
> +               M98090_HPVOLL_SHIFT, M98090_HPVOLL_NUM - 1, 0,
> +               max98090_hp_tlv),
> +       SOC_SINGLE_TLV("Headphone Right Volume", M98090_REG_2D_LVL_HP_RIGHT,
> +               M98090_HPVOLR_SHIFT, M98090_HPVOLR_NUM - 1, 0,
> +               max98090_hp_tlv),

Should be a single stereo control (and similarly for the other output
controls).

> +       SOC_SINGLE("Quick Setup System Clock", M98090_REG_04_QCFG_SYS_CLK,
> +               M98090_CLK_ALL_SHIFT, M98090_CLK_ALL_NUM - 1, 0),

What do these controls do?


> +       if (val >= 1) {
> +               if (w->reg == M98090_REG_10_LVL_MIC1)
> +                       max98090->mic1pre = val - 1; /* Update for volatile */
> +               else
> +                       max98090->mic2pre = val - 1; /* Update for volatile */
> +       }

Use braces consistently within an if statemeent - if you use them for
the outer one use them for the inner one too.

> +static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
> +
> +       {"MIC1 Input", NULL, "MIC1"},
> +       {"MIC2 Input", NULL, "MIC2"},
> +       {"MIC1 Input", NULL, "MICBIAS"},
> +       {"MIC2 Input", NULL, "MICBIAS"},

Unless this chip is *very* unusual I expect the bias is something that's
connected externally and therefore these connections should be being
made by the machine driver.

> +
> +       /* Check for user calculated MI and NI ratios */
> +       for (i = 0; i < ARRAY_SIZE(user_pclk_rates); i++) {
> +               if ((user_pclk_rates[i] == max98090->sysclk) &&
> +                       (user_lrclk_rates[i] == max98090->lrclk)) {
> +                       dev_info(codec->dev,
> +                               "Found user supported PCLK to LRCLK rates\n");
> +                       dev_info(codec->dev, "i %d ni %lld mi %lld\n",
> +                               i, ni_value[i], mi_value[i]);

dev_dbg() would be fine but dev_info() is too loud.

> +/*
> + * This accommodates an inverted logic in the MAX98090 chip
> + * for Bit Clock Invert (BCI). The inverted logic is only seen
> + * for the case of TDM mode. The remaining cases have normal logic.
> + */
> +               if (max98090->tdm_slots > 1) {
> +                       regval ^= M98090_DAI_BCI_MASK;
> +               }

Coding style, the indentation is inconsistent here and no braces for
single line if () statements.

> +               if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
> +                       /*
> +                        * Set to normal bias level.
> +                        */
> +                       snd_soc_update_bits(codec, M98090_REG_12_MIC_BIAS,
> +                               M98090_MBVSEL_MASK, M98090_MBVSEL_2V4);
> +
> +                       snd_soc_update_bits(codec, M98090_REG_3E_PWR_EN_IN,
> +                               M98090_PWR_MBEN_MASK, M98090_PWR_MBEN_MASK);
> +               }

This looks suspicous, why does the headset state have any bearing here?

> +static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
> +{
> +       struct snd_soc_codec *codec = codec_dai->codec;
> +       int regval;
> +
> +       dev_info(codec->dev, "max98090_dai_digital_mute\n");

Drop this, it's not conveying any useful information.

> +static void max98090_dmic_switch(struct snd_soc_codec *codec, int state)
> +{

I have no idea what this function is supposed to do...

> +static void max98090_headset_button_event(struct snd_soc_codec *codec)
> +{
> +       dev_info(codec->dev, "max98090_headset_button_event\n");
> +}

Delete this, it doesn't do anything except log.

> +       switch (reg & (M98090_LSNS_MASK | M98090_JKSNS_MASK)) {
> +               case M98090_LSNS_MASK | M98090_JKSNS_MASK:
> +               {
> +                       dev_info(codec->dev, "No Headset Detected\n");
> +
> +                       max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
> +
> +                       max98090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
> +
> +                       snd_soc_dapm_disable_pin(&codec->dapm, "HPL");
> +                       snd_soc_dapm_disable_pin(&codec->dapm, "HPR");
> +                       snd_soc_dapm_force_enable_pin(&codec->dapm, "SPKL");
> +                       snd_soc_dapm_force_enable_pin(&codec->dapm, "SPKR");
> +                       snd_soc_dapm_disable_pin(&codec->dapm, "MIC1");
> +                       snd_soc_dapm_disable_pin(&codec->dapm, "MIC2");
> +                       snd_soc_dapm_force_enable_pin(&codec->dapm, "DMIC1");
> +                       snd_soc_dapm_force_enable_pin(&codec->dapm, "DMIC2");
> +                       max98090_dmic_switch(codec, 1);
> +
> +                       break;
> +               }

This doesn't look obviously sensible...  calling set_bias_level()
outside of DAPM is going to get overridden in pretty short order,
none of the DAPM pin setting looks like a good idea (especially not
forcing on the speakers whenever there's no headset) and there's no DAPM
sync to make any of this take effect.  I'm a bit confused about the
intended effect.  I also can't see any interaction with soc-jack...

What is this code actually intended to do?

> +       dev_info(codec->dev, "***** max98090_interrupt *****\n");
> +

There's lots of these noisy, uninformative prints at info level
throughout the driver.

> +       /* Send work to be scheduled */
> +       if (active & M98090_IRQ_CLD_MASK) {
> +               dev_info(codec->dev, "M98090_IRQ_CLD_MASK\n");
> +       }

This doesn't actually schedule anything...

> +       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
> +       if (ret != 0) {
> +               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
> +               return ret;
> +       }

SND_SOC_REGMAP.

> +       if ( (request_threaded_irq(pdata->irq, NULL,
> +               max98090_interrupt, IRQF_TRIGGER_FALLING,
> +               "max98090_interrupt", codec)) < 0) {
> +               dev_info(codec->dev, "request_irq failed\n");
> +       }
> +       /*
> +        * Clear any old interrupts.

Coding style and it's not terribly helpful to hide the return code from
users.

> +       /* Turn on VCM bandgap reference */
> +       snd_soc_write(codec, M98090_REG_42_BIAS_CNTL,
> +               M98090_VCM_MODE_MASK);

This shouldn't be managed at runtime?

> +/*
> + * Driver revision
> + */
> +#define MAX98090_REVISION                      "0.01.00"

The kernel already has perfectly good versioning.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://mailman.alsa-project.org/pipermail/alsa-devel/attachments/20121227/422e8dab/attachment-0001.sig>


More information about the Alsa-devel mailing list