Loading sound/soc/codecs/tlv320aic3x.c +283 −216 Original line number Diff line number Diff line Loading @@ -61,15 +61,25 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { "DRVDD", /* ADC Analog and Output Driver Voltage */ }; struct aic3x_priv; struct aic3x_disable_nb { struct notifier_block nb; struct aic3x_priv *aic3x; }; /* codec private data */ struct aic3x_priv { struct snd_soc_codec *codec; struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; enum snd_soc_control_type control_type; struct aic3x_setup_data *setup; void *control_data; unsigned int sysclk; int master; int gpio_reset; int power; #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 Loading Loading @@ -112,62 +122,23 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { }; /* * read aic3x register cache * read from the aic3x register space. Only use for this function is if * wanting to read volatile bits from those registers that has both read-only * and read/write bits. All other cases should use snd_soc_read. */ static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { u8 *cache = codec->reg_cache; if (reg >= AIC3X_CACHEREGNUM) return -1; return cache[reg]; } /* * write aic3x register cache */ static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, u8 reg, u8 value) { u8 *cache = codec->reg_cache; if (codec->cache_only) return -EINVAL; if (reg >= AIC3X_CACHEREGNUM) return; cache[reg] = value; } /* * write to the aic3x register space */ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[2]; /* data is * D15..D8 aic3x register offset * D7...D0 register data */ data[0] = reg & 0xff; data[1] = value & 0xff; aic3x_write_reg_cache(codec, data[0], data[1]); if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; else return -EIO; } /* * read from the aic3x register space */ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { *value = reg & 0xff; return -1; value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]); *value = codec->hw_read(codec, reg); cache[reg] = *value; aic3x_write_reg_cache(codec, reg, *value); return 0; } Loading Loading @@ -646,6 +617,14 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINE1R"), SND_SOC_DAPM_INPUT("LINE2L"), SND_SOC_DAPM_INPUT("LINE2R"), /* * Virtual output pin to detection block inside codec. This can be * used to keep codec bias on if gpio or detection features are needed. * Force pin on or construct a path with an input jack and mic bias * widgets. */ SND_SOC_DAPM_OUTPUT("Detection"), }; static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { Loading Loading @@ -839,8 +818,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, int clk; /* select data word length */ data = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; Loading @@ -854,7 +832,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data |= (0x03 << 4); break; } aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data); /* Fsref can be 44100 or 48000 */ fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; Loading @@ -869,17 +847,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, if (bypass_pll) { pll_q &= 0xf; aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); /* disable PLL if it is bypassed */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); } else { aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); /* enable PLL when it is used */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); } /* Route Left DAC to left channel input and Loading @@ -888,7 +866,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; if (params_rate(params) >= 64000) data |= DUAL_RATE_MODE; aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data); /* codec sample rate select */ data = (fsref * 20) / params_rate(params); Loading @@ -897,7 +875,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data /= 5; data -= 2; data |= (data << 4); aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); if (bypass_pll) return 0; Loading Loading @@ -966,12 +944,15 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, } found: data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); aic3x_write(codec, AIC3X_PLL_PROGD_REG, data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGD_REG, (pll_d & 0x3F) << PLLD_LSB_SHIFT); return 0; Loading @@ -980,15 +961,15 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, static int aic3x_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON; u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON; if (mute) { aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); } else { aic3x_write(codec, LDAC_VOL, ldac_reg); aic3x_write(codec, RDAC_VOL, rdac_reg); snd_soc_write(codec, LDAC_VOL, ldac_reg); snd_soc_write(codec, RDAC_VOL, rdac_reg); } return 0; Loading @@ -1012,8 +993,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 iface_areg, iface_breg; int delay = 0; iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { Loading Loading @@ -1052,13 +1033,98 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); return 0; } static int aic3x_init_3007(struct snd_soc_codec *codec) { u8 tmp1, tmp2, *cache = codec->reg_cache; /* * There is no need to cache writes to undocumented page 0xD but * respective page 0 register cache entries must be preserved */ tmp1 = cache[0xD]; tmp2 = cache[0x8]; /* Class-D speaker driver init; datasheet p. 46 */ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); snd_soc_write(codec, 0xD, 0x0D); snd_soc_write(codec, 0x8, 0x5C); snd_soc_write(codec, 0x8, 0x5D); snd_soc_write(codec, 0x8, 0x5C); snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); cache[0xD] = tmp1; cache[0x8] = tmp2; return 0; } static int aic3x_regulator_event(struct notifier_block *nb, unsigned long event, void *data) { struct aic3x_disable_nb *disable_nb = container_of(nb, struct aic3x_disable_nb, nb); struct aic3x_priv *aic3x = disable_nb->aic3x; if (event & REGULATOR_EVENT_DISABLE) { /* * Put codec to reset and require cache sync as at least one * of the supplies was disabled */ if (aic3x->gpio_reset >= 0) gpio_set_value(aic3x->gpio_reset, 0); aic3x->codec->cache_sync = 1; } return 0; } static int aic3x_set_power(struct snd_soc_codec *codec, int power) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int i, ret; u8 *cache = codec->reg_cache; if (power) { ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret) goto out; aic3x->power = 1; /* * Reset release and cache sync is necessary only if some * supply was off or if there were cached writes */ if (!codec->cache_sync) goto out; if (aic3x->gpio_reset >= 0) { udelay(1); gpio_set_value(aic3x->gpio_reset, 1); } /* Sync reg_cache with the hardware */ codec->cache_only = 0; for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) snd_soc_write(codec, i, cache[i]); if (aic3x->model == AIC3X_MODEL_3007) aic3x_init_3007(codec); codec->cache_sync = 0; } else { aic3x->power = 0; /* HW writes are needless when bias is off */ codec->cache_only = 1; ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); } out: return ret; } static int aic3x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { Loading @@ -1069,23 +1135,29 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: if (aic3x->master) { if (codec->bias_level == SND_SOC_BIAS_STANDBY && aic3x->master) { /* enable pll */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); } break; case SND_SOC_BIAS_STANDBY: /* fall through and disable pll */ case SND_SOC_BIAS_OFF: if (aic3x->master) { if (!aic3x->power) aic3x_set_power(codec, 1); if (codec->bias_level == SND_SOC_BIAS_PREPARE && aic3x->master) { /* disable pll */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); } break; case SND_SOC_BIAS_OFF: if (aic3x->power) aic3x_set_power(codec, 0); break; } codec->bias_level = level; Loading @@ -1096,8 +1168,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) { u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; u8 bit = gpio ? 3: 0; u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); aic3x_write(codec, reg, val | (!!state << bit)); u8 val = snd_soc_read(codec, reg) & ~(1 << bit); snd_soc_write(codec, reg, val | (!!state << bit)); } EXPORT_SYMBOL_GPL(aic3x_set_gpio); Loading Loading @@ -1126,7 +1198,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, if (detect & AIC3X_HEADSET_DETECT_MASK) val |= AIC3X_HEADSET_DETECT_ENABLED; aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); } EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); Loading Loading @@ -1184,17 +1256,6 @@ static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) static int aic3x_resume(struct snd_soc_codec *codec) { int i; u8 data[2]; u8 *cache = codec->reg_cache; /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { data[0] = i; data[1] = cache[i]; codec->hw_write(codec->control_data, data, 2); } aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; Loading @@ -1209,103 +1270,132 @@ static int aic3x_init(struct snd_soc_codec *codec) struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int reg; aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); aic3x_write(codec, AIC3X_RESET, SOFT_RESET); snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); /* DAC default volume and mute */ aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); /* DAC to HP default volume and route to Output mixer */ aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); /* DAC to Line Out default volume and route to Output mixer */ aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); /* DAC to Mono Line Out default volume and route to Output mixer */ aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); /* unmute all outputs */ reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, LLOPM_CTRL); snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, RLOPM_CTRL); snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, MONOLOPM_CTRL); snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPLOUT_CTRL); snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPROUT_CTRL); snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPLCOM_CTRL); snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPRCOM_CTRL); snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE); /* ADC default volume and unmute */ aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN); snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN); /* By default route Line1 to ADC PGA mixer */ aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0); snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0); /* PGA to HP Bypass default volume, disconnect from Output Mixer */ aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); /* PGA to Line Out default volume, disconnect from Output Mixer */ aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); /* Line2 Line Out default volume, disconnect from Output Mixer */ aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); /* Line2 to Mono Out default volume, disconnect from Output Mixer */ aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); if (aic3x->model == AIC3X_MODEL_3007) { /* Class-D speaker driver init; datasheet p. 46 */ aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D); aic3x_write(codec, 0xD, 0x0D); aic3x_write(codec, 0x8, 0x5C); aic3x_write(codec, 0x8, 0x5D); aic3x_write(codec, 0x8, 0x5C); aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00); aic3x_write(codec, CLASSD_CTRL, 0); aic3x_init_3007(codec); snd_soc_write(codec, CLASSD_CTRL, 0); } /* off, with power on */ aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } static int aic3x_probe(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int ret, i; codec->hw_write = (hw_write_t) i2c_master_send; codec->control_data = aic3x->control_data; aic3x->codec = codec; codec->idle_bias_off = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } if (aic3x->gpio_reset >= 0) { ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); if (ret != 0) goto err_gpio; gpio_direction_output(aic3x->gpio_reset, 0); } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to request supplies: %d\n", ret); goto err_get; } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; ret = regulator_register_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); if (ret) { dev_err(codec->dev, "Failed to request regulator notifier: %d\n", ret); goto err_notif; } } codec->cache_only = 1; aic3x_init(codec); if (aic3x->setup) { /* setup GPIO functions */ aic3x_write(codec, AIC3X_GPIO1_REG, snd_soc_write(codec, AIC3X_GPIO1_REG, (aic3x->setup->gpio_func[0] & 0xf) << 4); aic3x_write(codec, AIC3X_GPIO2_REG, snd_soc_write(codec, AIC3X_GPIO2_REG, (aic3x->setup->gpio_func[1] & 0xf) << 4); } Loading @@ -1317,17 +1407,39 @@ static int aic3x_probe(struct snd_soc_codec *codec) aic3x_add_widgets(codec); return 0; err_notif: while (i--) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); err_get: if (aic3x->gpio_reset >= 0) gpio_free(aic3x->gpio_reset); err_gpio: kfree(aic3x); return ret; } static int aic3x_remove(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int i; aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); if (aic3x->gpio_reset >= 0) { gpio_set_value(aic3x->gpio_reset, 0); gpio_free(aic3x->gpio_reset); } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); return 0; } static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .read = aic3x_read_reg_cache, .write = aic3x_write, .set_bias_level = aic3x_set_bias_level, .reg_cache_size = ARRAY_SIZE(aic3x_reg), .reg_word_size = sizeof(u8), Loading Loading @@ -1361,7 +1473,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, { struct aic3x_pdata *pdata = i2c->dev.platform_data; struct aic3x_priv *aic3x; int ret, i; int ret; const struct i2c_device_id *tbl; aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); Loading @@ -1371,6 +1483,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, } aic3x->control_data = i2c; aic3x->control_type = SND_SOC_I2C; i2c_set_clientdata(i2c, aic3x); if (pdata) { aic3x->gpio_reset = pdata->gpio_reset; Loading @@ -1379,68 +1493,21 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, aic3x->gpio_reset = -1; } if (aic3x->gpio_reset >= 0) { ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); if (ret != 0) goto err_gpio; gpio_direction_output(aic3x->gpio_reset, 0); } for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { if (!strcmp(tbl->name, id->name)) break; } aic3x->model = tbl - aic3x_i2c_id; for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); goto err_get; } ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); goto err_enable; } if (aic3x->gpio_reset >= 0) { udelay(1); gpio_set_value(aic3x->gpio_reset, 1); } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); if (ret < 0) goto err_enable; return ret; err_enable: regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); err_get: if (aic3x->gpio_reset >= 0) gpio_free(aic3x->gpio_reset); err_gpio: kfree(aic3x); return ret; } static int aic3x_i2c_remove(struct i2c_client *client) { struct aic3x_priv *aic3x = i2c_get_clientdata(client); if (aic3x->gpio_reset >= 0) { gpio_set_value(aic3x->gpio_reset, 0); gpio_free(aic3x->gpio_reset); } regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); snd_soc_unregister_codec(&client->dev); kfree(i2c_get_clientdata(client)); return 0; Loading sound/soc/codecs/wl1273.c +3 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,9 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); if (wl1273->mode == ucontrol->value.integer.value[0]) return 0; /* Do not allow changes while stream is running */ if (codec->active) return -EPERM; Loading sound/soc/omap/omap-mcbsp.c +1 −1 Original line number Diff line number Diff line Loading @@ -759,7 +759,7 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = .ops = &mcbsp_dai_ops, }; int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct soc_mixer_control *mc = Loading Loading
sound/soc/codecs/tlv320aic3x.c +283 −216 Original line number Diff line number Diff line Loading @@ -61,15 +61,25 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { "DRVDD", /* ADC Analog and Output Driver Voltage */ }; struct aic3x_priv; struct aic3x_disable_nb { struct notifier_block nb; struct aic3x_priv *aic3x; }; /* codec private data */ struct aic3x_priv { struct snd_soc_codec *codec; struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; enum snd_soc_control_type control_type; struct aic3x_setup_data *setup; void *control_data; unsigned int sysclk; int master; int gpio_reset; int power; #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 Loading Loading @@ -112,62 +122,23 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { }; /* * read aic3x register cache * read from the aic3x register space. Only use for this function is if * wanting to read volatile bits from those registers that has both read-only * and read/write bits. All other cases should use snd_soc_read. */ static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { u8 *cache = codec->reg_cache; if (reg >= AIC3X_CACHEREGNUM) return -1; return cache[reg]; } /* * write aic3x register cache */ static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, u8 reg, u8 value) { u8 *cache = codec->reg_cache; if (codec->cache_only) return -EINVAL; if (reg >= AIC3X_CACHEREGNUM) return; cache[reg] = value; } /* * write to the aic3x register space */ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[2]; /* data is * D15..D8 aic3x register offset * D7...D0 register data */ data[0] = reg & 0xff; data[1] = value & 0xff; aic3x_write_reg_cache(codec, data[0], data[1]); if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; else return -EIO; } /* * read from the aic3x register space */ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { *value = reg & 0xff; return -1; value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]); *value = codec->hw_read(codec, reg); cache[reg] = *value; aic3x_write_reg_cache(codec, reg, *value); return 0; } Loading Loading @@ -646,6 +617,14 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINE1R"), SND_SOC_DAPM_INPUT("LINE2L"), SND_SOC_DAPM_INPUT("LINE2R"), /* * Virtual output pin to detection block inside codec. This can be * used to keep codec bias on if gpio or detection features are needed. * Force pin on or construct a path with an input jack and mic bias * widgets. */ SND_SOC_DAPM_OUTPUT("Detection"), }; static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { Loading Loading @@ -839,8 +818,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, int clk; /* select data word length */ data = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; Loading @@ -854,7 +832,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data |= (0x03 << 4); break; } aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data); /* Fsref can be 44100 or 48000 */ fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; Loading @@ -869,17 +847,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, if (bypass_pll) { pll_q &= 0xf; aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); /* disable PLL if it is bypassed */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); } else { aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); /* enable PLL when it is used */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); } /* Route Left DAC to left channel input and Loading @@ -888,7 +866,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; if (params_rate(params) >= 64000) data |= DUAL_RATE_MODE; aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data); /* codec sample rate select */ data = (fsref * 20) / params_rate(params); Loading @@ -897,7 +875,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data /= 5; data -= 2; data |= (data << 4); aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); if (bypass_pll) return 0; Loading Loading @@ -966,12 +944,15 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, } found: data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); aic3x_write(codec, AIC3X_PLL_PROGD_REG, data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); snd_soc_write(codec, AIC3X_PLL_PROGD_REG, (pll_d & 0x3F) << PLLD_LSB_SHIFT); return 0; Loading @@ -980,15 +961,15 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, static int aic3x_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON; u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON; if (mute) { aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); } else { aic3x_write(codec, LDAC_VOL, ldac_reg); aic3x_write(codec, RDAC_VOL, rdac_reg); snd_soc_write(codec, LDAC_VOL, ldac_reg); snd_soc_write(codec, RDAC_VOL, rdac_reg); } return 0; Loading @@ -1012,8 +993,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, u8 iface_areg, iface_breg; int delay = 0; iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { Loading Loading @@ -1052,13 +1033,98 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); return 0; } static int aic3x_init_3007(struct snd_soc_codec *codec) { u8 tmp1, tmp2, *cache = codec->reg_cache; /* * There is no need to cache writes to undocumented page 0xD but * respective page 0 register cache entries must be preserved */ tmp1 = cache[0xD]; tmp2 = cache[0x8]; /* Class-D speaker driver init; datasheet p. 46 */ snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); snd_soc_write(codec, 0xD, 0x0D); snd_soc_write(codec, 0x8, 0x5C); snd_soc_write(codec, 0x8, 0x5D); snd_soc_write(codec, 0x8, 0x5C); snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); cache[0xD] = tmp1; cache[0x8] = tmp2; return 0; } static int aic3x_regulator_event(struct notifier_block *nb, unsigned long event, void *data) { struct aic3x_disable_nb *disable_nb = container_of(nb, struct aic3x_disable_nb, nb); struct aic3x_priv *aic3x = disable_nb->aic3x; if (event & REGULATOR_EVENT_DISABLE) { /* * Put codec to reset and require cache sync as at least one * of the supplies was disabled */ if (aic3x->gpio_reset >= 0) gpio_set_value(aic3x->gpio_reset, 0); aic3x->codec->cache_sync = 1; } return 0; } static int aic3x_set_power(struct snd_soc_codec *codec, int power) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int i, ret; u8 *cache = codec->reg_cache; if (power) { ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret) goto out; aic3x->power = 1; /* * Reset release and cache sync is necessary only if some * supply was off or if there were cached writes */ if (!codec->cache_sync) goto out; if (aic3x->gpio_reset >= 0) { udelay(1); gpio_set_value(aic3x->gpio_reset, 1); } /* Sync reg_cache with the hardware */ codec->cache_only = 0; for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) snd_soc_write(codec, i, cache[i]); if (aic3x->model == AIC3X_MODEL_3007) aic3x_init_3007(codec); codec->cache_sync = 0; } else { aic3x->power = 0; /* HW writes are needless when bias is off */ codec->cache_only = 1; ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); } out: return ret; } static int aic3x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { Loading @@ -1069,23 +1135,29 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: if (aic3x->master) { if (codec->bias_level == SND_SOC_BIAS_STANDBY && aic3x->master) { /* enable pll */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); } break; case SND_SOC_BIAS_STANDBY: /* fall through and disable pll */ case SND_SOC_BIAS_OFF: if (aic3x->master) { if (!aic3x->power) aic3x_set_power(codec, 1); if (codec->bias_level == SND_SOC_BIAS_PREPARE && aic3x->master) { /* disable pll */ reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); } break; case SND_SOC_BIAS_OFF: if (aic3x->power) aic3x_set_power(codec, 0); break; } codec->bias_level = level; Loading @@ -1096,8 +1168,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) { u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; u8 bit = gpio ? 3: 0; u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); aic3x_write(codec, reg, val | (!!state << bit)); u8 val = snd_soc_read(codec, reg) & ~(1 << bit); snd_soc_write(codec, reg, val | (!!state << bit)); } EXPORT_SYMBOL_GPL(aic3x_set_gpio); Loading Loading @@ -1126,7 +1198,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, if (detect & AIC3X_HEADSET_DETECT_MASK) val |= AIC3X_HEADSET_DETECT_ENABLED; aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); } EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); Loading Loading @@ -1184,17 +1256,6 @@ static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) static int aic3x_resume(struct snd_soc_codec *codec) { int i; u8 data[2]; u8 *cache = codec->reg_cache; /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { data[0] = i; data[1] = cache[i]; codec->hw_write(codec->control_data, data, 2); } aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; Loading @@ -1209,103 +1270,132 @@ static int aic3x_init(struct snd_soc_codec *codec) struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int reg; aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); aic3x_write(codec, AIC3X_RESET, SOFT_RESET); snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); /* DAC default volume and mute */ aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); /* DAC to HP default volume and route to Output mixer */ aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); /* DAC to Line Out default volume and route to Output mixer */ aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); /* DAC to Mono Line Out default volume and route to Output mixer */ aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); /* unmute all outputs */ reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, LLOPM_CTRL); snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, RLOPM_CTRL); snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, MONOLOPM_CTRL); snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPLOUT_CTRL); snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPROUT_CTRL); snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPLCOM_CTRL); snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE); reg = snd_soc_read(codec, HPRCOM_CTRL); snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE); /* ADC default volume and unmute */ aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN); snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN); /* By default route Line1 to ADC PGA mixer */ aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0); snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0); /* PGA to HP Bypass default volume, disconnect from Output Mixer */ aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); /* PGA to Line Out default volume, disconnect from Output Mixer */ aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); /* Line2 Line Out default volume, disconnect from Output Mixer */ aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); /* Line2 to Mono Out default volume, disconnect from Output Mixer */ aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); if (aic3x->model == AIC3X_MODEL_3007) { /* Class-D speaker driver init; datasheet p. 46 */ aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D); aic3x_write(codec, 0xD, 0x0D); aic3x_write(codec, 0x8, 0x5C); aic3x_write(codec, 0x8, 0x5D); aic3x_write(codec, 0x8, 0x5C); aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00); aic3x_write(codec, CLASSD_CTRL, 0); aic3x_init_3007(codec); snd_soc_write(codec, CLASSD_CTRL, 0); } /* off, with power on */ aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } static int aic3x_probe(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int ret, i; codec->hw_write = (hw_write_t) i2c_master_send; codec->control_data = aic3x->control_data; aic3x->codec = codec; codec->idle_bias_off = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } if (aic3x->gpio_reset >= 0) { ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); if (ret != 0) goto err_gpio; gpio_direction_output(aic3x->gpio_reset, 0); } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to request supplies: %d\n", ret); goto err_get; } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; ret = regulator_register_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); if (ret) { dev_err(codec->dev, "Failed to request regulator notifier: %d\n", ret); goto err_notif; } } codec->cache_only = 1; aic3x_init(codec); if (aic3x->setup) { /* setup GPIO functions */ aic3x_write(codec, AIC3X_GPIO1_REG, snd_soc_write(codec, AIC3X_GPIO1_REG, (aic3x->setup->gpio_func[0] & 0xf) << 4); aic3x_write(codec, AIC3X_GPIO2_REG, snd_soc_write(codec, AIC3X_GPIO2_REG, (aic3x->setup->gpio_func[1] & 0xf) << 4); } Loading @@ -1317,17 +1407,39 @@ static int aic3x_probe(struct snd_soc_codec *codec) aic3x_add_widgets(codec); return 0; err_notif: while (i--) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); err_get: if (aic3x->gpio_reset >= 0) gpio_free(aic3x->gpio_reset); err_gpio: kfree(aic3x); return ret; } static int aic3x_remove(struct snd_soc_codec *codec) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int i; aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); if (aic3x->gpio_reset >= 0) { gpio_set_value(aic3x->gpio_reset, 0); gpio_free(aic3x->gpio_reset); } for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) regulator_unregister_notifier(aic3x->supplies[i].consumer, &aic3x->disable_nb[i].nb); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); return 0; } static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .read = aic3x_read_reg_cache, .write = aic3x_write, .set_bias_level = aic3x_set_bias_level, .reg_cache_size = ARRAY_SIZE(aic3x_reg), .reg_word_size = sizeof(u8), Loading Loading @@ -1361,7 +1473,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, { struct aic3x_pdata *pdata = i2c->dev.platform_data; struct aic3x_priv *aic3x; int ret, i; int ret; const struct i2c_device_id *tbl; aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); Loading @@ -1371,6 +1483,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, } aic3x->control_data = i2c; aic3x->control_type = SND_SOC_I2C; i2c_set_clientdata(i2c, aic3x); if (pdata) { aic3x->gpio_reset = pdata->gpio_reset; Loading @@ -1379,68 +1493,21 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, aic3x->gpio_reset = -1; } if (aic3x->gpio_reset >= 0) { ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); if (ret != 0) goto err_gpio; gpio_direction_output(aic3x->gpio_reset, 0); } for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { if (!strcmp(tbl->name, id->name)) break; } aic3x->model = tbl - aic3x_i2c_id; for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); goto err_get; } ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); goto err_enable; } if (aic3x->gpio_reset >= 0) { udelay(1); gpio_set_value(aic3x->gpio_reset, 1); } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1); if (ret < 0) goto err_enable; return ret; err_enable: regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); err_get: if (aic3x->gpio_reset >= 0) gpio_free(aic3x->gpio_reset); err_gpio: kfree(aic3x); return ret; } static int aic3x_i2c_remove(struct i2c_client *client) { struct aic3x_priv *aic3x = i2c_get_clientdata(client); if (aic3x->gpio_reset >= 0) { gpio_set_value(aic3x->gpio_reset, 0); gpio_free(aic3x->gpio_reset); } regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); snd_soc_unregister_codec(&client->dev); kfree(i2c_get_clientdata(client)); return 0; Loading
sound/soc/codecs/wl1273.c +3 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,9 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); if (wl1273->mode == ucontrol->value.integer.value[0]) return 0; /* Do not allow changes while stream is running */ if (codec->active) return -EPERM; Loading
sound/soc/omap/omap-mcbsp.c +1 −1 Original line number Diff line number Diff line Loading @@ -759,7 +759,7 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = .ops = &mcbsp_dai_ops, }; int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct soc_mixer_control *mc = Loading