Beispiel #1
0
/**
 * sta350_set_bias_level - DAPM callback
 * @codec: the codec device
 * @level: DAPM power level
 *
 * This is called by ALSA to put the codec into low power mode
 * or to wake it up.  If the codec is powered off completely
 * all registers must be restored after power on.
 */
static int sta350_set_bias_level(struct snd_soc_codec *codec,
				 enum snd_soc_bias_level level)
{
	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
	int ret;

	dev_dbg(codec->dev, "level = %d\n", level);
	switch (level) {
	case SND_SOC_BIAS_ON:
		break;

	case SND_SOC_BIAS_PREPARE:
		/* Full power on */
		regmap_update_bits(sta350->regmap, STA350_CONFF,
				   STA350_CONFF_PWDN | STA350_CONFF_EAPD,
				   STA350_CONFF_PWDN | STA350_CONFF_EAPD);
		break;

	case SND_SOC_BIAS_STANDBY:
		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
			ret = regulator_bulk_enable(
				ARRAY_SIZE(sta350->supplies),
				sta350->supplies);
			if (ret < 0) {
				dev_err(codec->dev,
					"Failed to enable supplies: %d\n",
					ret);
				return ret;
			}
			sta350_startup_sequence(sta350);
			sta350_cache_sync(codec);
		}

		/* Power down */
		regmap_update_bits(sta350->regmap, STA350_CONFF,
				   STA350_CONFF_PWDN | STA350_CONFF_EAPD,
				   0);

		break;

	case SND_SOC_BIAS_OFF:
		/* The chip runs through the power down sequence for us */
		regmap_update_bits(sta350->regmap, STA350_CONFF,
				   STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0);

		/* power down: low */
		if (sta350->gpiod_power_down)
			gpiod_set_value(sta350->gpiod_power_down, 0);

		if (sta350->gpiod_nreset)
			gpiod_set_value(sta350->gpiod_nreset, 0);

		regulator_bulk_disable(ARRAY_SIZE(sta350->supplies),
				       sta350->supplies);
		break;
	}
	codec->dapm.bias_level = level;
	return 0;
}
Beispiel #2
0
static int sta350_probe(struct snd_soc_codec *codec)
{
	struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
	struct sta350_platform_data *pdata = sta350->pdata;
	int i, ret = 0, thermal = 0;

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

	ret = sta350_startup_sequence(sta350);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to startup device\n");
		return ret;
	}

	/* CONFA */
	if (!pdata->thermal_warning_recovery)
		thermal |= STA350_CONFA_TWAB;
	if (!pdata->thermal_warning_adjustment)
		thermal |= STA350_CONFA_TWRB;
	if (!pdata->fault_detect_recovery)
		thermal |= STA350_CONFA_FDRB;
	regmap_update_bits(sta350->regmap, STA350_CONFA,
			   STA350_CONFA_TWAB | STA350_CONFA_TWRB |
			   STA350_CONFA_FDRB,
			   thermal);

	/* CONFC */
	regmap_update_bits(sta350->regmap, STA350_CONFC,
			   STA350_CONFC_OM_MASK,
			   pdata->ffx_power_output_mode
				<< STA350_CONFC_OM_SHIFT);
	regmap_update_bits(sta350->regmap, STA350_CONFC,
			   STA350_CONFC_CSZ_MASK,
			   pdata->drop_compensation_ns
				<< STA350_CONFC_CSZ_SHIFT);
	regmap_update_bits(sta350->regmap,
			   STA350_CONFC,
			   STA350_CONFC_OCRB,
			   pdata->oc_warning_adjustment ?
				STA350_CONFC_OCRB : 0);

	/* CONFE */
	regmap_update_bits(sta350->regmap, STA350_CONFE,
			   STA350_CONFE_MPCV,
			   pdata->max_power_use_mpcc ?
				STA350_CONFE_MPCV : 0);
	regmap_update_bits(sta350->regmap, STA350_CONFE,
			   STA350_CONFE_MPC,
			   pdata->max_power_correction ?
				STA350_CONFE_MPC : 0);
	regmap_update_bits(sta350->regmap, STA350_CONFE,
			   STA350_CONFE_AME,
			   pdata->am_reduction_mode ?
				STA350_CONFE_AME : 0);
	regmap_update_bits(sta350->regmap, STA350_CONFE,
			   STA350_CONFE_PWMS,
			   pdata->odd_pwm_speed_mode ?
				STA350_CONFE_PWMS : 0);
	regmap_update_bits(sta350->regmap, STA350_CONFE,
			   STA350_CONFE_DCCV,
			   pdata->distortion_compensation ?
				STA350_CONFE_DCCV : 0);
	/*  CONFF */
	regmap_update_bits(sta350->regmap, STA350_CONFF,
			   STA350_CONFF_IDE,
			   pdata->invalid_input_detect_mute ?
				STA350_CONFF_IDE : 0);
	regmap_update_bits(sta350->regmap, STA350_CONFF,
			   STA350_CONFF_OCFG_MASK,
			   pdata->output_conf
				<< STA350_CONFF_OCFG_SHIFT);

	/* channel to output mapping */
	regmap_update_bits(sta350->regmap, STA350_C1CFG,
			   STA350_CxCFG_OM_MASK,
			   pdata->ch1_output_mapping
				<< STA350_CxCFG_OM_SHIFT);
	regmap_update_bits(sta350->regmap, STA350_C2CFG,
			   STA350_CxCFG_OM_MASK,
			   pdata->ch2_output_mapping
				<< STA350_CxCFG_OM_SHIFT);
	regmap_update_bits(sta350->regmap, STA350_C3CFG,
			   STA350_CxCFG_OM_MASK,
			   pdata->ch3_output_mapping
				<< STA350_CxCFG_OM_SHIFT);

	/* miscellaneous registers */
	regmap_update_bits(sta350->regmap, STA350_MISC1,
			   STA350_MISC1_CPWMEN,
			   pdata->activate_mute_output ?
				STA350_MISC1_CPWMEN : 0);
	regmap_update_bits(sta350->regmap, STA350_MISC1,
			   STA350_MISC1_BRIDGOFF,
			   pdata->bridge_immediate_off ?
				STA350_MISC1_BRIDGOFF : 0);
	regmap_update_bits(sta350->regmap, STA350_MISC1,
			   STA350_MISC1_NSHHPEN,
			   pdata->noise_shape_dc_cut ?
				STA350_MISC1_NSHHPEN : 0);
	regmap_update_bits(sta350->regmap, STA350_MISC1,
			   STA350_MISC1_RPDNEN,
			   pdata->powerdown_master_vol ?
				STA350_MISC1_RPDNEN: 0);

	regmap_update_bits(sta350->regmap, STA350_MISC2,
			   STA350_MISC2_PNDLSL_MASK,
			   pdata->powerdown_delay_divider
				<< STA350_MISC2_PNDLSL_SHIFT);

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

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

	return 0;
}