Esempio n. 1
0
File: sta529.c Progetto: 3null/linux
static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	u8 mode = 0;

	/* interface format */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_LEFT_J:
		mode = LEFT_J_DATA_FORMAT;
		break;
	case SND_SOC_DAIFMT_I2S:
		mode = I2S_DATA_FORMAT;
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		mode = RIGHT_J_DATA_FORMAT;
		break;
	default:
		return -EINVAL;
	}

	snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);

	return 0;
}
Esempio n. 2
0
static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	unsigned int rate = params_rate(params);
	unsigned int val;

	switch (rate) {
	case 8000:
		val = 0;
		break;
	case 16000:
		val = AUDIO_CODEC_CDCFS8K16K;
		break;
	default:
		return -EINVAL;
	}

	snd_soc_update_bits(codec, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
			val);

	return 0;
}
Esempio n. 3
0
static void wcd9xxx_cfg_clsh_param_common(
		struct snd_soc_codec *codec)
{
	int i;
	const struct wcd9xxx_reg_mask_val reg_set[] = {
		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
	};

	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
						    reg_set[i].val);

	dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
			 __func__);
}
Esempio n. 4
0
int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
					struct list_head *list,
					uint16_t reg, uint8_t mask,
					uint8_t value, int delay)
{
	int rc;
	struct wcd9xxx_register_save_node *node;

	node = kmalloc(sizeof(*node), GFP_KERNEL);
	if (unlikely(!node)) {
		pr_err("%s: Not enough memory\n", __func__);
		return -ENOMEM;
	}
	node->reg = reg;
	node->value = snd_soc_read(codec, reg);
	list_add(&node->lh, list);
	if (mask == 0xFF)
		rc = snd_soc_write(codec, reg, value);
	else
		rc = snd_soc_update_bits(codec, reg, mask, value);
	if (delay)
		usleep_range(delay, delay + USLEEP_RANGE_MARGIN_US);
	return rc;
}
static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
				  int clk_id, unsigned int freq, int dir)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
	int i;

	dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
		__func__, clk_id, freq, dir);

	for (i = 0; aic31xx_divs[i].mclk != freq; i++)
		if (i == ARRAY_SIZE(aic31xx_divs)) {
			dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
				__func__, freq);
			return -EINVAL;
		}

	/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
	snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
			    clk_id << AIC31XX_PLL_CLKIN_SHIFT);

	aic31xx->sysclk = freq;
	return 0;
}
Esempio n. 6
0
void cs42l73_bp_detection(struct snd_soc_codec *codec,
			   struct snd_soc_jack *jack,
			   int plug_status)
{
	unsigned int status;
	unsigned int reg;
	unsigned int mask = SND_JACK_BTN_0 | SND_JACK_HEADSET;

	if (plug_status) {
		pr_err("%s: Invalid interrupt\n", __func__);
		return;
	} else {
		snd_soc_update_bits(codec, CS42L73_IM1, MIC2_SDET, MIC2_SDET);
		reg = snd_soc_read(codec, CS42L73_IS1);
		if (reg & MIC2_SDET) { /*button pressed */
			pr_debug("%s:Button Pressed\n", __func__);
			status = SND_JACK_HEADSET | SND_JACK_BTN_0;
		} else {
			pr_debug("%s:Button Released\n", __func__);
			status = SND_JACK_HEADSET;
		}
	}
	snd_soc_jack_report(jack, status, mask);
}
Esempio n. 7
0
void wcd9xxx_enable_high_perf_mode(struct snd_soc_codec *codec,
				struct wcd9xxx_clsh_cdc_data *clsh_d,
				u8 req_state, bool req_type)
{
	dev_dbg(codec->dev, "%s: users fclk8 %d, fclk5 %d", __func__,
			clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
			clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);

	if (req_type == WCD9XXX_CLSAB_REQ_ENABLE) {
		clsh_d->ncp_users[NCP_FCLK_LEVEL_8]++;
		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CHOP_CTL,
					0x20, 0x00);
		wcd9xxx_chargepump_request(codec, true);
		wcd9xxx_enable_anc_delay(codec, true);
		if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
						0x0F, 0x08);
		snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x30, 0x30);

		/* Enable NCP and wait until settles down */
		if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
			usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US+10);
	} else {
		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CHOP_CTL,
					0x20, 0x20);
		wcd9xxx_chargepump_request(codec, false);
		wcd9xxx_enable_anc_delay(codec, false);
		clsh_d->ncp_users[NCP_FCLK_LEVEL_8]--;
		if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
		    clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
			snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
						0x01, 0x00);
		else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
						0x0F, 0x05);
	}
	dev_dbg(codec->dev, "%s: leave\n", __func__);
}
int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
				  int lineout1_diff, int lineout2_diff,
				  int lineout1fb, int lineout2fb,
				  int jd_scthr, int jd_thr, int micbias1_lvl,
				  int micbias2_lvl)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);

	hubs->lineout1_se = !lineout1_diff;
	hubs->lineout2_se = !lineout2_diff;

	if (!lineout1_diff)
		snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
				    WM8993_LINEOUT1_MODE,
				    WM8993_LINEOUT1_MODE);
	if (!lineout2_diff)
		snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
				    WM8993_LINEOUT2_MODE,
				    WM8993_LINEOUT2_MODE);

	if (!lineout1_diff && !lineout2_diff)
		snd_soc_update_bits(codec, WM8993_ANTIPOP1,
				    WM8993_LINEOUT_VMID_BUF_ENA,
				    WM8993_LINEOUT_VMID_BUF_ENA);

	if (lineout1fb)
		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);

	if (lineout2fb)
		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);

	snd_soc_update_bits(codec, WM8993_MICBIAS,
			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
			    jd_thr << WM8993_JD_THR_SHIFT |
			    micbias1_lvl |
			    micbias2_lvl << WM8993_MICB2_LVL_SHIFT);

	return 0;
}
Esempio n. 9
0
static void enable_power_depop(struct snd_soc_codec *codec)
{
	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
				ALC5632_PWR_ADD1_SOFTGEN_EN,
				ALC5632_PWR_ADD1_SOFTGEN_EN);

	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
				ALC5632_ADD3_POWER_EN,
				ALC5632_ADD3_POWER_EN);

	snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
				ALC5632_MISC_HP_DEPOP_MODE2_EN,
				ALC5632_MISC_HP_DEPOP_MODE2_EN);

	/* "normal" mode: 0 @ 26 */
	/* set all PR0-7 mixers to 0 */
	snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
				0);

	msleep(500);

	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_ADD2_POWER_EN,
				ALC5632_ADD2_POWER_EN);

	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
				ALC5632_ADD1_POWER_EN,
				ALC5632_ADD1_POWER_EN);

	/* disable HP Depop2 */
	snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
				ALC5632_MISC_HP_DEPOP_MODE2_EN,
				0);

}
Esempio n. 10
0
static void enable_power_depop(struct snd_soc_codec *codec)
{
	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
				ALC5632_PWR_ADD1_SOFTGEN_EN,
				ALC5632_PWR_ADD1_SOFTGEN_EN);

	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
				ALC5632_ADD3_POWER_EN,
				ALC5632_ADD3_POWER_EN);

	snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
				ALC5632_MISC_HP_DEPOP_MODE2_EN,
				ALC5632_MISC_HP_DEPOP_MODE2_EN);

	/*                       */
	/*                           */
	snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
				0);

	msleep(500);

	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_ADD2_POWER_EN,
				ALC5632_ADD2_POWER_EN);

	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
				ALC5632_ADD1_POWER_EN,
				ALC5632_ADD1_POWER_EN);

	/*                   */
	snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
				ALC5632_MISC_HP_DEPOP_MODE2_EN,
				0);

}
Esempio n. 11
0
static int mic_event(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *k, int event)
{
    struct snd_soc_codec *codec = w->codec;
    pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));

    if (SND_SOC_DAPM_EVENT_ON(event)) {
        if (!strncmp(w->name, "MIC0", 4))
            snd_soc_update_bits(codec, ES_MIC0_CTRL,
                                ES_MIC0_ON_MASK, 1);
        else if (!strncmp(w->name, "MIC1", 4))
            snd_soc_update_bits(codec, ES_MIC1_CTRL,
                                ES_MIC1_ON_MASK, 1);
        else if (!strncmp(w->name, "MIC2", 4))
            snd_soc_update_bits(codec, ES_MIC2_CTRL,
                                ES_MIC2_ON_MASK, 1);
        else {
            pr_err("%s() Invalid Mic Widget ON = %s\n",
                   __func__, w->name);
            return -EINVAL;
        }

    } else {
        if (!strncmp(w->name, "MIC0", 4))
            snd_soc_update_bits(codec, ES_MIC0_CTRL,
                                ES_MIC0_ON_MASK, 0);
        else if (!strncmp(w->name, "MIC1", 4))
            snd_soc_update_bits(codec, ES_MIC1_CTRL,
                                ES_MIC1_ON_MASK, 0);
        else if (!strncmp(w->name, "MIC2", 4))
            snd_soc_update_bits(codec, ES_MIC2_CTRL,
                                ES_MIC2_ON_MASK, 0);
        else {
            pr_err("%s() Invalid Mic Widget OFF = %s\n",
                   __func__, w->name);
            return -EINVAL;
        }
    }
    return 0;
}
Esempio n. 12
0
static int spkdrv_ev(struct snd_soc_dapm_widget *w,
		struct snd_kcontrol *kcontrol, int event)
{
	dev_dbg(w->codec->dev, "%s called\n", __func__);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		snd_soc_update_bits(w->codec, COD3022X_32_VOL_EP_SPK,
				CTVOL_SPK_PGA_MASK, 0x3);

		snd_soc_update_bits(w->codec, COD3022X_17_PWAUTO_DA,
				PW_AUTO_DA_MASK | APW_SPK_MASK,
				(0x1 << PW_AUTO_DA_SHIFT) |
				(0x1 << APW_SPK_SHIFT));

		snd_soc_update_bits(w->codec, COD3022X_37_MIX_DA2,
				EN_SPK_MIX_DCTL_MASK | EN_SPK_MIX_DCTR_MASK,
				(0x1 << EN_SPK_MIX_DCTL_SHIFT) |
				(0x1 << EN_SPK_MIX_DCTR_SHIFT));

		break;

	case SND_SOC_DAPM_PRE_PMD:
		snd_soc_update_bits(w->codec, COD3022X_32_VOL_EP_SPK,
				CTVOL_SPK_PGA_MASK, 0x3);

		snd_soc_update_bits(w->codec, COD3022X_37_MIX_DA2,
				EN_SPK_MIX_DCTL_MASK | EN_SPK_MIX_DCTR_MASK, 0);

		snd_soc_update_bits(w->codec, COD3022X_17_PWAUTO_DA,
				 APW_SPK_MASK, 0);
		break;
	default:
		break;
	}

	return 0;
}
Esempio n. 13
0
static int da7210_startup(struct snd_pcm_substream *substream,
			  struct snd_soc_dai *dai)
{
	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	struct snd_soc_codec *codec = dai->codec;

	if (is_play) {
		/* Enable Out */
		snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
		snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);

	} else {
		/* Volume 7 */
		snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7);
		snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7);

		/* Enable Mic */
		snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1);
		snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1);
	}

	return 0;
}
Esempio n. 14
0
static int pmu3_probe(struct snd_soc_codec *codec)
{
	int ret = 0;

	printk("aml pmu3 codec probe\n");
	pmu3_audio_power_init(codec);
	pmu3_reset(codec);
	/* power on device */
	pmu3_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	/* Enable DAC soft mute by default */
	snd_soc_update_bits(codec, PMU3_SOFT_MUTE, 0x7800, 0x7800);

	/* Enable ZC */
	snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0x3c0, 0x0);
	
	snd_soc_add_codec_controls(codec, pmu3_snd_controls,
				ARRAY_SIZE(pmu3_snd_controls));
	/* ADC high pass filter Hi-fi mode */
	snd_soc_update_bits(codec, PMU3_ADC_DAC, 0xc00, 0xc00);

	snd_soc_write(codec, PMU3_MIXOUT_L, 0xe000);
	snd_soc_write(codec, PMU3_MIXOUT_R, 0xe000);
	snd_soc_write(codec, PMU3_MIXIN_L, 0xf000);
	snd_soc_write(codec, PMU3_MIXIN_R, 0xf000);
	snd_soc_write(codec, PMU3_PGA_IN, 0x1616);


	snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_1, 0xf0c, 0xf0c);
	snd_soc_update_bits(codec, PMU3_BLOCK_ENABLE_2, 0xf, 0xf);

	snd_soc_update_bits(codec, PMU3_LINEOUT_HP_DRV, 0x90, 0x90);
	snd_soc_write(codec, PMU3_DAC_VOLUME_CTL, 0xb9b9);
	snd_soc_write(codec, PMU3_ADC_VOLUME_CTL, 0x6a6a);

	return ret;
}
Esempio n. 15
0
static int es_dac_enable(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
{
    struct snd_soc_codec *codec = w->codec;
    pr_debug("%s DAC%d event %d\n", __func__, w->shift, event);

    switch (event) {
    case SND_SOC_DAPM_PRE_PMU:
        snd_soc_update_bits(codec, w->reg, 1<<w->shift, 1<<w->shift);
        snd_soc_update_bits(codec, ES_DAC_DIG_EN, ES_DIG_CLK_EN_MASK,
                            ES_DIG_CLK_EN);
        snd_soc_update_bits(codec, ES_DAC_DIG_EN, ES_DAC_CLK_EN_MASK,
                            ES_DAC_CLK_EN);
        break;
    case SND_SOC_DAPM_POST_PMD:
        snd_soc_update_bits(codec, w->reg, 1<<w->shift , 0);
        snd_soc_update_bits(codec, ES_DAC_DIG_EN, ES_DIG_CLK_EN_MASK,
                            0);
        snd_soc_update_bits(codec, ES_DAC_DIG_EN, ES_DAC_CLK_EN_MASK,
                            0);
        break;
    }
    return 0;
}
Esempio n. 16
0
static int alc5632_set_bias_level(struct snd_soc_codec *codec,
				      enum snd_soc_bias_level level)
{
	switch (level) {
	case SND_SOC_BIAS_ON:
		enable_power_depop(codec);
		break;
	case SND_SOC_BIAS_PREPARE:
		break;
	case SND_SOC_BIAS_STANDBY:
		/* everything off except vref/vmid, */
		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
				ALC5632_PWR_MANAG_ADD1_MASK,
				ALC5632_PWR_ADD1_MAIN_BIAS);
		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_PWR_MANAG_ADD2_MASK,
				ALC5632_PWR_ADD2_VREF);
		/* "normal" mode: 0 @ 26 */
		snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
				0xffff ^ (ALC5632_PWR_VREF_PR3
				| ALC5632_PWR_VREF_PR2));
		break;
	case SND_SOC_BIAS_OFF:
		/* everything off, dac mute, inactive */
		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_PWR_MANAG_ADD2_MASK, 0);
		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
				ALC5632_PWR_MANAG_ADD3_MASK, 0);
		snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
				ALC5632_PWR_MANAG_ADD1_MASK, 0);
		break;
	}
	codec->dapm.bias_level = level;
	return 0;
}
Esempio n. 17
0
/**
 * cs4270_probe - ASoC probe function
 * @pdev: platform device
 *
 * This function is called when ASoC has all the pieces it needs to
 * instantiate a sound driver.
 */
static int cs4270_probe(struct snd_soc_codec *codec)
{
	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
	int i, ret;

	/* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
	 * then do the I2C transactions itself.
	 */
	ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs4270->control_type);
	if (ret < 0) {
		dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
		return ret;
	}

	/* Disable auto-mute.  This feature appears to be buggy.  In some
	 * situations, auto-mute will not deactivate when it should, so we want
	 * this feature disabled by default.  An application (e.g. alsactl) can
	 * re-enabled it by using the controls.
	 */
	ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
	if (ret < 0) {
		dev_err(codec->dev, "i2c write failed\n");
		return ret;
	}

	/* Disable automatic volume control.  The hardware enables, and it
	 * causes volume change commands to be delayed, sometimes until after
	 * playback has started.  An application (e.g. alsactl) can
	 * re-enabled it by using the controls.
	 */
	ret = snd_soc_update_bits(codec, CS4270_TRANS,
		CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);
	if (ret < 0) {
		dev_err(codec->dev, "i2c write failed\n");
		return ret;
	}

	/* Add the non-DAPM controls */
	ret = snd_soc_add_codec_controls(codec, cs4270_snd_controls,
				ARRAY_SIZE(cs4270_snd_controls));
	if (ret < 0) {
		dev_err(codec->dev, "failed to add controls\n");
		return ret;
	}

	/* get the power supply regulators */
	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
		cs4270->supplies[i].supply = supply_names[i];

	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
				 cs4270->supplies);
	if (ret < 0)
		return ret;

	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
				    cs4270->supplies);
	if (ret < 0)
		goto error_free_regulators;

	return 0;

error_free_regulators:
	regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
			    cs4270->supplies);

	return ret;
}
Esempio n. 18
0
static int wm8523_probe(struct snd_soc_codec *codec)
{
	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
	int ret, i;

	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
	wm8523->rate_constraint.count =
		ARRAY_SIZE(wm8523->rate_constraint_list);

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

	for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
		wm8523->supplies[i].supply = wm8523_supply_names[i];

	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies),
				 wm8523->supplies);
	if (ret != 0) {
		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
		return ret;
	}

	ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
				    wm8523->supplies);
	if (ret != 0) {
		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
		goto err_get;
	}

	ret = snd_soc_read(codec, WM8523_DEVICE_ID);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to read ID register\n");
		goto err_enable;
	}
	if (ret != wm8523_reg[WM8523_DEVICE_ID]) {
		dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret);
		ret = -EINVAL;
		goto err_enable;
	}

	ret = snd_soc_read(codec, WM8523_REVISION);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to read revision register\n");
		goto err_enable;
	}
	dev_info(codec->dev, "revision %c\n",
		 (ret & WM8523_CHIP_REV_MASK) + 'A');

	ret = wm8523_reset(codec);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to issue reset\n");
		goto err_enable;
	}

	/* Change some default settings - latch VU and enable ZC */
	snd_soc_update_bits(codec, WM8523_DAC_GAINR,
			    WM8523_DACR_VU, WM8523_DACR_VU);
	snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);

	wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	/* Bias level configuration will have done an extra enable */
	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);

	return 0;

err_enable:
	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
err_get:
	regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);

	return ret;
}
Esempio n. 19
0
static int ak4641_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;

	return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0);
}
Esempio n. 20
0
static int wm8985_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *params,
			    struct snd_soc_dai *dai)
{
	int i;
	struct snd_soc_codec *codec;
	struct wm8985_priv *wm8985;
	u16 blen, srate_idx;
	unsigned int tmp;
	int srate_best;

	codec = dai->codec;
	wm8985 = snd_soc_codec_get_drvdata(codec);

	wm8985->bclk = snd_soc_params_to_bclk(params);
	if ((int)wm8985->bclk < 0)
		return wm8985->bclk;

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		blen = 0x0;
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		blen = 0x1;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		blen = 0x2;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		blen = 0x3;
		break;
	default:
		dev_err(dai->dev, "Unsupported word length %u\n",
			params_format(params));
		return -EINVAL;
	}

	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
			    WM8985_WL_MASK, blen << WM8985_WL_SHIFT);

	/*
	 * match to the nearest possible sample rate and rely
	 * on the array index to configure the SR register
	 */
	srate_idx = 0;
	srate_best = abs(srates[0] - params_rate(params));
	for (i = 1; i < ARRAY_SIZE(srates); ++i) {
		if (abs(srates[i] - params_rate(params)) >= srate_best)
			continue;
		srate_idx = i;
		srate_best = abs(srates[i] - params_rate(params));
	}

	dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
	snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
			    WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);

	dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
	dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);

	for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
		if (wm8985->sysclk / params_rate(params)
				== fs_ratios[i].ratio)
			break;
	}

	if (i == ARRAY_SIZE(fs_ratios)) {
		dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
			wm8985->sysclk, params_rate(params));
		return -EINVAL;
	}

	dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
	snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
			    WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);

	/* select the appropriate bclk divider */
	tmp = (wm8985->sysclk / fs_ratios[i].div) * 10;
	for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
		if (wm8985->bclk == tmp / bclk_divs[i])
			break;
	}

	if (i == ARRAY_SIZE(bclk_divs)) {
		dev_err(dai->dev, "No matching BCLK divider found\n");
		return -EINVAL;
	}

	dev_dbg(dai->dev, "BCLK div = %d\n", i);
	snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
			    WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
	return 0;
}
Esempio n. 21
0
static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
	struct snd_soc_codec *codec;
	u16 format, master, bcp, lrp;

	codec = dai->codec;

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		format = 0x2;
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		format = 0x0;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		format = 0x1;
		break;
	case SND_SOC_DAIFMT_DSP_A:
	case SND_SOC_DAIFMT_DSP_B:
		format = 0x3;
		break;
	default:
		dev_err(dai->dev, "Unknown dai format\n");
		return -EINVAL;
	}

	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
			    WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBM_CFM:
		master = 1;
		break;
	case SND_SOC_DAIFMT_CBS_CFS:
		master = 0;
		break;
	default:
		dev_err(dai->dev, "Unknown master/slave configuration\n");
		return -EINVAL;
	}

	snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
			    WM8985_MS_MASK, master << WM8985_MS_SHIFT);

	/* frame inversion is not valid for dsp modes */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_DSP_A:
	case SND_SOC_DAIFMT_DSP_B:
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_IB_IF:
		case SND_SOC_DAIFMT_NB_IF:
			return -EINVAL;
		default:
			break;
		}
		break;
	default:
		break;
	}

	bcp = lrp = 0;
	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		break;
	case SND_SOC_DAIFMT_IB_IF:
		bcp = lrp = 1;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		bcp = 1;
		break;
	case SND_SOC_DAIFMT_NB_IF:
		lrp = 1;
		break;
	default:
		dev_err(dai->dev, "Unknown polarity configuration\n");
		return -EINVAL;
	}

	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
			    WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
	snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
			    WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
	return 0;
}
Esempio n. 22
0
static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
		unsigned int fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
	unsigned int serictl = 0x00, seroctl = 0x00;
	bool invert_lrclk;

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBM_CFM:
		/* master, 64-bits per sample, 1 frame per sample */
		seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16
				| ADAU1701_SEROCTL_OLF1024;
		break;
	case SND_SOC_DAIFMT_CBS_CFS:
		break;
	default:
		return -EINVAL;
	}

	/* clock inversion */
	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		invert_lrclk = false;
		break;
	case SND_SOC_DAIFMT_NB_IF:
		invert_lrclk = true;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		invert_lrclk = false;
		serictl |= ADAU1701_SERICTL_INV_BCLK;
		seroctl |= ADAU1701_SEROCTL_INV_BCLK;
		break;
	case SND_SOC_DAIFMT_IB_IF:
		invert_lrclk = true;
		serictl |= ADAU1701_SERICTL_INV_BCLK;
		seroctl |= ADAU1701_SEROCTL_INV_BCLK;
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		serictl |= ADAU1701_SERICTL_LEFTJ;
		seroctl |= ADAU1701_SEROCTL_MSB_DEALY0;
		invert_lrclk = !invert_lrclk;
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		serictl |= ADAU1701_SERICTL_RIGHTJ_24;
		seroctl |= ADAU1701_SEROCTL_MSB_DEALY8;
		invert_lrclk = !invert_lrclk;
		break;
	default:
		return -EINVAL;
	}

	if (invert_lrclk) {
		seroctl |= ADAU1701_SEROCTL_INV_LRCLK;
		serictl |= ADAU1701_SERICTL_INV_LRCLK;
	}

	adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;

	snd_soc_write(codec, ADAU1701_SERICTL, serictl);
	snd_soc_update_bits(codec, ADAU1701_SEROCTL,
		~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);

	return 0;
}
Esempio n. 23
0
static int alc5632_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
		int source, unsigned int freq_in, unsigned int freq_out)
{
	int i;
	struct snd_soc_codec *codec = codec_dai->codec;
	int gbl_clk = 0, pll_div = 0;
	u16 reg;

	if (pll_id < ALC5632_PLL_FR_MCLK || pll_id > ALC5632_PLL_FR_VBCLK)
		return -EINVAL;

	/* Disable PLL power */
	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_PWR_ADD2_PLL1,
				0);
	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_PWR_ADD2_PLL2,
				0);

	/* pll is not used in slave mode */
	reg = snd_soc_read(codec, ALC5632_DAI_CONTROL);
	if (reg & ALC5632_DAI_SDP_SLAVE_MODE)
		return 0;

	if (!freq_in || !freq_out)
		return 0;

	switch (pll_id) {
	case ALC5632_PLL_FR_MCLK:
		for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) {
			if (codec_master_pll_div[i].pll_in == freq_in
			   && codec_master_pll_div[i].pll_out == freq_out) {
				/* PLL source from MCLK */
				pll_div  = codec_master_pll_div[i].regvalue;
				break;
			}
		}
		break;
	case ALC5632_PLL_FR_BCLK:
		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
			if (codec_slave_pll_div[i].pll_in == freq_in
			   && codec_slave_pll_div[i].pll_out == freq_out) {
				/* PLL source from Bitclk */
				gbl_clk = ALC5632_PLL_FR_BCLK;
				pll_div = codec_slave_pll_div[i].regvalue;
				break;
			}
		}
		break;
	case ALC5632_PLL_FR_VBCLK:
		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
			if (codec_slave_pll_div[i].pll_in == freq_in
			   && codec_slave_pll_div[i].pll_out == freq_out) {
				/* PLL source from voice clock */
				gbl_clk = ALC5632_PLL_FR_VBCLK;
				pll_div = codec_slave_pll_div[i].regvalue;
				break;
			}
		}
		break;
	default:
		return -EINVAL;
	}

	if (!pll_div)
		return -EINVAL;

	/* choose MCLK/BCLK/VBCLK */
	snd_soc_write(codec, ALC5632_GPCR2, gbl_clk);
	/* choose PLL1 clock rate */
	snd_soc_write(codec, ALC5632_PLL1_CTRL, pll_div);
	/* enable PLL1 */
	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_PWR_ADD2_PLL1,
				ALC5632_PWR_ADD2_PLL1);
	/* enable PLL2 */
	snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
				ALC5632_PWR_ADD2_PLL2,
				ALC5632_PWR_ADD2_PLL2);
	/* use PLL1 as main SYSCLK */
	snd_soc_update_bits(codec, ALC5632_GPCR1,
			ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1,
			ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1);

	return 0;
}
Esempio n. 24
0
static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
				    unsigned int fmt)
{
	struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev);
	int err;
	u16 format = 0;

	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
		return -EINVAL;

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_DSP_A:
		format |= SI476X_DAUDIO_MODE_DSP_A;
		break;
	case SND_SOC_DAIFMT_DSP_B:
		format |= SI476X_DAUDIO_MODE_DSP_B;
		break;
	case SND_SOC_DAIFMT_I2S:
		format |= SI476X_DAUDIO_MODE_I2S;
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		format |= SI476X_DAUDIO_MODE_RIGHT_J;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		format |= SI476X_DAUDIO_MODE_LEFT_J;
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_DSP_A:
	case SND_SOC_DAIFMT_DSP_B:
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_NB_NF:
			break;
		case SND_SOC_DAIFMT_IB_NF:
			format |= SI476X_DAUDIO_MODE_IB;
			break;
		default:
			return -EINVAL;
		}
		break;
	case SND_SOC_DAIFMT_I2S:
	case SND_SOC_DAIFMT_RIGHT_J:
	case SND_SOC_DAIFMT_LEFT_J:
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_NB_NF:
			break;
		case SND_SOC_DAIFMT_IB_IF:
			format |= SI476X_DAUDIO_MODE_IB |
				SI476X_DAUDIO_MODE_IF;
			break;
		case SND_SOC_DAIFMT_IB_NF:
			format |= SI476X_DAUDIO_MODE_IB;
			break;
		case SND_SOC_DAIFMT_NB_IF:
			format |= SI476X_DAUDIO_MODE_IF;
			break;
		default:
			return -EINVAL;
		}
		break;
	default:
		return -EINVAL;
	}

	si476x_core_lock(core);

	err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
				  SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,
				  format);

	si476x_core_unlock(core);

	if (err < 0) {
		dev_err(codec_dai->codec->dev, "Failed to set output format\n");
		return err;
	}

	return 0;
}
Esempio n. 25
0
static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
			       unsigned int fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	u8 iface_reg1 = 0;
	u8 iface_reg2 = 0;
	u8 dsp_a_val = 0;

	dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);

	/* set master/slave audio interface */
	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBM_CFM:
		iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
		break;
	default:
		dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
		return -EINVAL;
	}

	/* interface format */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		break;
	case SND_SOC_DAIFMT_DSP_A:
		dsp_a_val = 0x1;
	case SND_SOC_DAIFMT_DSP_B:
		/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_NB_NF:
			iface_reg2 |= AIC31XX_BCLKINV_MASK;
			break;
		case SND_SOC_DAIFMT_IB_NF:
			break;
		default:
			return -EINVAL;
		}
		iface_reg1 |= (AIC31XX_DSP_MODE <<
			       AIC31XX_IFACE1_DATATYPE_SHIFT);
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE <<
			       AIC31XX_IFACE1_DATATYPE_SHIFT);
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE <<
			       AIC31XX_IFACE1_DATATYPE_SHIFT);
		break;
	default:
		dev_err(codec->dev, "Invalid DAI interface format\n");
		return -EINVAL;
	}

	snd_soc_update_bits(codec, AIC31XX_IFACE1,
			    AIC31XX_IFACE1_DATATYPE_MASK |
			    AIC31XX_IFACE1_MASTER_MASK,
			    iface_reg1);
	snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET,
			    AIC31XX_DATA_OFFSET_MASK,
			    dsp_a_val);
	snd_soc_update_bits(codec, AIC31XX_IFACE2,
			    AIC31XX_BCLKINV_MASK,
			    iface_reg2);

	return 0;
}
static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
			  struct snd_kcontrol *kcontrol,
			  int event)
{
	struct snd_soc_codec *codec = w->codec;
	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
	bool manual_ena = false;
	int val;

	switch (arizona->type) {
	case WM5102:
		switch (arizona->rev) {
		case 0:
			break;
		default:
			manual_ena = true;
			break;
		}
	default:
		break;
	}

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		if (!priv->spk_ena && manual_ena) {
			snd_soc_write(codec, 0x4f5, 0x25a);
			priv->spk_ena_pending = true;
		}
		break;
	case SND_SOC_DAPM_POST_PMU:
		val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
		if (val & ARIZONA_SPK_SHUTDOWN_STS) {
			dev_crit(arizona->dev,
				 "Speaker not enabled due to temperature\n");
			return -EBUSY;
		}

		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
				    1 << w->shift, 1 << w->shift);

		if (priv->spk_ena_pending) {
			msleep(75);
			snd_soc_write(codec, 0x4f5, 0xda);
			priv->spk_ena_pending = false;
			priv->spk_ena++;
		}
		break;
	case SND_SOC_DAPM_PRE_PMD:
		if (manual_ena) {
			priv->spk_ena--;
			if (!priv->spk_ena)
				snd_soc_write(codec, 0x4f5, 0x25a);
		}

		snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
				    1 << w->shift, 0);
		break;
	case SND_SOC_DAPM_POST_PMD:
		if (manual_ena) {
			if (!priv->spk_ena)
				snd_soc_write(codec, 0x4f5, 0x0da);
		}
		break;
	}

	return 0;
}
static int arizona_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params,
			     struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
	struct arizona *arizona = priv->arizona;
	int base = dai->driver->base;
	const int *rates;
	int i, ret, val;
	int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
	int bclk, lrclk, wl, frame, bclk_target;

	if (params_rate(params) % 8000)
		rates = &arizona_44k1_bclk_rates[0];
	else
		rates = &arizona_48k_bclk_rates[0];

	bclk_target = snd_soc_params_to_bclk(params);
	if (chan_limit && chan_limit < params_channels(params)) {
		arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
		bclk_target /= params_channels(params);
		bclk_target *= chan_limit;
	}

	/* Force stereo for I2S mode */
	val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
	if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
		arizona_aif_dbg(dai, "Forcing stereo mode\n");
		bclk_target *= 2;
	}

	for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
		if (rates[i] >= bclk_target &&
		    rates[i] % params_rate(params) == 0) {
			bclk = i;
			break;
		}
	}
	if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
				params_rate(params));
		return -EINVAL;
	}

	lrclk = rates[bclk] / params_rate(params);

	arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
			rates[bclk], rates[bclk] / lrclk);

	wl = snd_pcm_format_width(params_format(params));
	frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;

	ret = arizona_hw_params_rate(substream, params, dai);
	if (ret != 0)
		return ret;

	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
			    ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
			    ARIZONA_AIF1TX_BCPF_MASK, lrclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
			    ARIZONA_AIF1RX_BCPF_MASK, lrclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
			    ARIZONA_AIF1TX_WL_MASK |
			    ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
			    ARIZONA_AIF1RX_WL_MASK |
			    ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);

	return 0;
}
Esempio n. 28
0
static int sta32x_probe(struct snd_soc_codec *codec)
{
	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
	int i, ret = 0, thermal = 0;

	sta32x->codec = codec;
	sta32x->pdata = dev_get_platdata(codec->dev);

	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
				    sta32x->supplies);
	if (ret != 0) {
		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
		return ret;
	}

	/* Chip documentation explicitly requires that the reset values
	 * of reserved register bits are left untouched.
	 * Write the register default value to cache for reserved registers,
	 * so the write to the these registers are suppressed by the cache
	 * restore code when it skips writes of default registers.
	 */
	regcache_cache_only(sta32x->regmap, true);
	snd_soc_write(codec, STA32X_CONFC, 0xc2);
	snd_soc_write(codec, STA32X_CONFE, 0xc2);
	snd_soc_write(codec, STA32X_CONFF, 0x5c);
	snd_soc_write(codec, STA32X_MMUTE, 0x10);
	snd_soc_write(codec, STA32X_AUTO1, 0x60);
	snd_soc_write(codec, STA32X_AUTO3, 0x00);
	snd_soc_write(codec, STA32X_C3CFG, 0x40);
	regcache_cache_only(sta32x->regmap, false);

	/* set thermal warning adjustment and recovery */
	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
		thermal |= STA32X_CONFA_TWAB;
	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE))
		thermal |= STA32X_CONFA_TWRB;
	snd_soc_update_bits(codec, STA32X_CONFA,
			    STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
			    thermal);

	/* select output configuration  */
	snd_soc_update_bits(codec, STA32X_CONFF,
			    STA32X_CONFF_OCFG_MASK,
			    sta32x->pdata->output_conf
			    << STA32X_CONFF_OCFG_SHIFT);

	/* channel to output mapping */
	snd_soc_update_bits(codec, STA32X_C1CFG,
			    STA32X_CxCFG_OM_MASK,
			    sta32x->pdata->ch1_output_mapping
			    << STA32X_CxCFG_OM_SHIFT);
	snd_soc_update_bits(codec, STA32X_C2CFG,
			    STA32X_CxCFG_OM_MASK,
			    sta32x->pdata->ch2_output_mapping
			    << STA32X_CxCFG_OM_SHIFT);
	snd_soc_update_bits(codec, STA32X_C3CFG,
			    STA32X_CxCFG_OM_MASK,
			    sta32x->pdata->ch3_output_mapping
			    << STA32X_CxCFG_OM_SHIFT);

	/* initialize coefficient shadow RAM with reset values */
	for (i = 4; i <= 49; i += 5)
		sta32x->coef_shadow[i] = 0x400000;
	for (i = 50; i <= 54; i++)
		sta32x->coef_shadow[i] = 0x7fffff;
	sta32x->coef_shadow[55] = 0x5a9df7;
	sta32x->coef_shadow[56] = 0x7fffff;
	sta32x->coef_shadow[59] = 0x7fffff;
	sta32x->coef_shadow[60] = 0x400000;
	sta32x->coef_shadow[61] = 0x400000;

	if (sta32x->pdata->needs_esd_watchdog)
		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);

	sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	/* Bias level configuration will have done an extra enable */
	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);

	return 0;
}
static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
	struct snd_soc_codec *codec = dai->codec;
	int lrclk, bclk, mode, base;

	base = dai->driver->base;

	lrclk = 0;
	bclk = 0;

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_DSP_A:
		mode = 0;
		break;
	case SND_SOC_DAIFMT_I2S:
		mode = 2;
		break;
	default:
		arizona_aif_err(dai, "Unsupported DAI format %d\n",
				fmt & SND_SOC_DAIFMT_FORMAT_MASK);
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		break;
	case SND_SOC_DAIFMT_CBS_CFM:
		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
		break;
	case SND_SOC_DAIFMT_CBM_CFS:
		bclk |= ARIZONA_AIF1_BCLK_MSTR;
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
		bclk |= ARIZONA_AIF1_BCLK_MSTR;
		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
		break;
	default:
		arizona_aif_err(dai, "Unsupported master mode %d\n",
				fmt & SND_SOC_DAIFMT_MASTER_MASK);
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		break;
	case SND_SOC_DAIFMT_IB_IF:
		bclk |= ARIZONA_AIF1_BCLK_INV;
		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		bclk |= ARIZONA_AIF1_BCLK_INV;
		break;
	case SND_SOC_DAIFMT_NB_IF:
		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
		break;
	default:
		return -EINVAL;
	}

	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
			    ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
			    bclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
			    ARIZONA_AIF1TX_LRCLK_INV |
			    ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
			    ARIZONA_AIF1RX_LRCLK_INV |
			    ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
			    ARIZONA_AIF1_FMT_MASK, mode);

	return 0;
}
Esempio n. 30
0
static int aic31xx_setup_pll(struct snd_soc_codec *codec,
			     struct snd_pcm_hw_params *params)
{
	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
	int bclk_score = snd_soc_params_to_frame_size(params);
	int mclk_p = aic31xx->sysclk / aic31xx->p_div;
	int bclk_n = 0;
	int match = -1;
	int i;

	/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
	snd_soc_update_bits(codec, AIC31XX_CLKMUX,
			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
	snd_soc_update_bits(codec, AIC31XX_IFACE2,
			    AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);

	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
		if (aic31xx_divs[i].rate == params_rate(params) &&
		    aic31xx_divs[i].mclk_p == mclk_p) {
			int s =	(aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
				snd_soc_params_to_frame_size(params);
			int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
				snd_soc_params_to_frame_size(params);
			if (s < bclk_score && bn > 0) {
				match = i;
				bclk_n = bn;
				bclk_score = s;
			}
		}
	}

	if (match == -1) {
		dev_err(codec->dev,
			"%s: Sample rate (%u) and format not supported\n",
			__func__, params_rate(params));
		/* See bellow for details how fix this. */
		return -EINVAL;
	}
	if (bclk_score != 0) {
		dev_warn(codec->dev, "Can not produce exact bitclock");
		/* This is fine if using dsp format, but if using i2s
		   there may be trouble. To fix the issue edit the
		   aic31xx_divs table for your mclk and sample
		   rate. Details can be found from:
		   http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf
		   Section: 5.6 CLOCK Generation and PLL
		*/
	}
	i = match;

	/* PLL configuration */
	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
			    (aic31xx->p_div << 4) | 0x01);
	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);

	snd_soc_write(codec, AIC31XX_PLLDMSB,
		      aic31xx_divs[i].pll_d >> 8);
	snd_soc_write(codec, AIC31XX_PLLDLSB,
		      aic31xx_divs[i].pll_d & 0xff);

	/* DAC dividers configuration */
	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].ndac);
	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].mdac);

	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
	snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);

	/* ADC dividers configuration. Write reset value 1 if not used. */
	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);

	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);

	/* Bit clock divider configuration. */
	snd_soc_update_bits(codec, AIC31XX_BCLKN,
			    AIC31XX_PLL_MASK, bclk_n);

	aic31xx->rate_div_line = i;

	dev_dbg(codec->dev,
		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
		aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
		aic31xx->p_div, aic31xx_divs[i].dosr,
		aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
		aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
		aic31xx_divs[i].madc, bclk_n);

	return 0;
}