[alsa-devel] [PATCH] ASoC: rt5645: Add codec driver
Mark Brown
broonie at kernel.org
Mon Apr 14 22:28:37 CEST 2014
On Fri, Apr 11, 2014 at 06:34:19PM +0800, Oder Chiou wrote:
> This patch adds the Realtek ALC5645 codec driver. It is the base
> version that because the jack detect function is not implemented to
> it, the headphone and AMIC1 are not workable. We will fill up the
> further functions later.
This looks pretty good, a few things below but none of them too big.
> +static bool rt5645_readable_register(struct device *dev, unsigned int reg)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++)
> + if ((reg >= rt5645_ranges[i].window_start &&
> + reg <= rt5645_ranges[i].window_start +
> + rt5645_ranges[i].window_len) ||
> + (reg >= rt5645_ranges[i].range_min &&
> + reg <= rt5645_ranges[i].range_max))
> + return true;
Please include some braces in these loops for legibility.
> +static int rt5645_set_dmic1_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_codec *codec = w->codec;
> +
> + switch (event) {
> + case SND_SOC_DAPM_PRE_PMU:
> + snd_soc_update_bits(codec, RT5645_GPIO_CTRL1,
> + RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
> + snd_soc_update_bits(codec, RT5645_DMIC1, RT5645_DMIC_1_DP_MASK,
> + RT5645_DMIC_1_DP_IN2N);
> + break;
For rt5640 we've got this configued by platform data - why not do the
same here? In general I'm seeing some similarities again, though I
didn't check to see if the same driver can be used yet. Is that the
case?
> +static const struct snd_kcontrol_new hp_r_vol_control =
> + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL,
> +
> + RT5645_R_MUTE_SFT, 1, 1);
> +static void hp_amp_power(struct snd_soc_codec *codec, int on)
Coding style, your blank line is in the wrong place.
> +static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_codec *codec = w->codec;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + rt5645_pmu_depop(codec);
> + break;
> +
> + case SND_SOC_DAPM_PRE_PMD:
> + rt5645_pmd_depop(codec);
> + break;
May as well just inline the power up/down sequences?
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x1c, 0xfd20);
> + regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x20, 0x611f);
> + regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x21, 0x4040);
> + regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x23, 0x0004);
> + snd_soc_update_bits(codec, RT5645_PWR_DIG1,
> + RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
Either use snd_soc_ or regmap_ - either is fine but be consistent.
> + RT5645_PWR_CLS_D_L,
> + RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
> + RT5645_PWR_CLS_D_L);
> + break;
> +
> + case SND_SOC_DAPM_PRE_PMD:
> + snd_soc_update_bits(codec, RT5645_PWR_DIG1,
> + RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
> + RT5645_PWR_CLS_D_L, 0);
It's a bit odd that the first bank of writes done with regmap_write()
isn't undone here, can it be done once on init?
> +static int rt5645_pdm1_l_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_codec *codec = w->codec;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + snd_soc_update_bits(codec, RT5645_PDM_OUT_CTRL,
> + RT5645_M_PDM1_L, 0);
> + break;
Why are these done by an event - I'd expect this to be done using the
normal DAPM register update support?
> + bclk_ms = frame_size > 32 ? 1 : 0;
bclk_ms = frame_size > 32.
> +static int rt5645_set_bias_level(struct snd_soc_codec *codec,
> + enum snd_soc_bias_level level)
> +{
> + switch (level) {
> + case SND_SOC_BIAS_STANDBY:
> + if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
> + snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
> + RT5645_PWR_VREF1 | RT5645_PWR_MB |
> + RT5645_PWR_BG | RT5645_PWR_VREF2,
> + RT5645_PWR_VREF1 | RT5645_PWR_MB |
> + RT5645_PWR_BG | RT5645_PWR_VREF2);
> + mdelay(10);
> + snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
> + RT5645_PWR_FV1 | RT5645_PWR_FV2,
> + RT5645_PWR_FV1 | RT5645_PWR_FV2);
> + snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
> + RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
> + }
> + break;
Since the device can power up and down very quickly it should make sense
to set idle_bias_off for a power saving when idle.
> +#ifdef CONFIG_PM
> +static int rt5645_suspend(struct snd_soc_codec *codec)
> +{
> + rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
> + return 0;
> +}
> +
> +static int rt5645_resume(struct snd_soc_codec *codec)
> +{
> + return 0;
> +}
> +#else
> +#define rt5645_suspend NULL
> +#define rt5645_resume NULL
> +#endif
If you use idle_bias_off you can remove this.
> +#if defined(CONFIG_OF)
> +static const struct of_device_id rt5645_of_match[] = {
> + { .compatible = "realtek,rt5645", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, rt5645_of_match);
> +#endif
We need device tree binding documentation for any device with DT
bindings.
> +static int rt5645_i2c_remove(struct i2c_client *i2c)
> +{
> + snd_soc_unregister_codec(&i2c->dev);
> + kfree(i2c_get_clientdata(i2c));
> + return 0;
> +}
You used devm_kzalloc(), no need to free.
> +void rt5645_i2c_shutdown(struct i2c_client *client)
> +{
> + struct rt5645_priv *rt5645 = i2c_get_clientdata(client);
> + struct snd_soc_codec *codec = rt5645->codec;
> +
> + if (codec != NULL)
> + rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
> +}
The ASoC framework will do this for you.
-------------- 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/20140414/8e670262/attachment-0001.sig>
More information about the Alsa-devel
mailing list