コード例 #1
0
static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd)
{
    struct snd_soc_codec *codec = rtd->codec;
    struct snd_soc_dapm_context *dapm = &codec->dapm;
    struct snd_soc_card *card = codec->card;
    struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
    struct tegra_asoc_platform_data *pdata = machine->pdata;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
    struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai);
#endif
    int ret;

#ifndef CONFIG_ARCH_TEGRA_2x_SOC
    if (machine->codec_info[BASEBAND].i2s_id != -1)
        i2s->is_dam_used = true;
#endif

    if (machine->init_done)
        return 0;

    machine->init_done = true;

    machine->pcard = card;
    machine->bias_level = SND_SOC_BIAS_STANDBY;

    if (gpio_is_valid(pdata->gpio_spkr_en)) {
        ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
        if (ret) {
            dev_err(card->dev, "cannot get spkr_en gpio\n");
            return ret;
        }
        machine->gpio_requested |= GPIO_SPKR_EN;

        gpio_direction_output(pdata->gpio_spkr_en, 0);
    }

    if (gpio_is_valid(pdata->gpio_hp_mute)) {
        ret = gpio_request(pdata->gpio_hp_mute, "hp_mute");
        if (ret) {
            dev_err(card->dev, "cannot get hp_mute gpio\n");
            return ret;
        }
        machine->gpio_requested |= GPIO_HP_MUTE;

        gpio_direction_output(pdata->gpio_hp_mute, 0);
    }

    if (gpio_is_valid(pdata->gpio_int_mic_en)) {
        ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
        if (ret) {
            dev_err(card->dev, "cannot get int_mic_en gpio\n");
            return ret;
        }
        machine->gpio_requested |= GPIO_INT_MIC_EN;

        /* Disable int mic; enable signal is active-high */
        gpio_direction_output(pdata->gpio_int_mic_en, 0);
    }

    if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
        ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
        if (ret) {
            dev_err(card->dev, "cannot get ext_mic_en gpio\n");
            return ret;
        }
        machine->gpio_requested |= GPIO_EXT_MIC_EN;

        /* Enable ext mic; enable signal is active-low */
        gpio_direction_output(pdata->gpio_ext_mic_en, 0);
    }

    ret = snd_soc_add_controls(codec, tegra_max98088_controls,
                               ARRAY_SIZE(tegra_max98088_controls));
    if (ret < 0)
        return ret;

    snd_soc_dapm_new_controls(dapm, tegra_max98088_dapm_widgets,
                              ARRAY_SIZE(tegra_max98088_dapm_widgets));

    snd_soc_dapm_add_routes(dapm, enterprise_audio_map,
                            ARRAY_SIZE(enterprise_audio_map));

    ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
                           &tegra_max98088_hp_jack);
    if (ret < 0)
        return ret;

#ifdef CONFIG_SWITCH
    snd_soc_jack_notifier_register(&tegra_max98088_hp_jack,
                                   &headset_switch_nb);
#else /*gpio based headset detection*/
    snd_soc_jack_add_pins(&tegra_max98088_hp_jack,
                          ARRAY_SIZE(tegra_max98088_hp_jack_pins),
                          tegra_max98088_hp_jack_pins);
#endif

    max98088_headset_detect(codec, &tegra_max98088_hp_jack,
                            SND_JACK_HEADSET);

    /* Add call mode switch control */
    ret = snd_ctl_add(codec->card->snd_card,
                      snd_ctl_new1(&tegra_call_mode_control, machine));
    if (ret < 0)
        return ret;

    snd_soc_dapm_nc_pin(dapm, "INA1");
    snd_soc_dapm_nc_pin(dapm, "INA2");
    snd_soc_dapm_nc_pin(dapm, "INB1");
    snd_soc_dapm_nc_pin(dapm, "INB2");
    snd_soc_dapm_sync(dapm);

    return 0;
}
コード例 #2
0
ファイル: cs4270.c プロジェクト: 454053205/linux
/**
 * 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_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;
}
コード例 #3
0
static int wm8350_probe(struct platform_device *pdev)
{
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec;
	struct wm8350 *wm8350;
	struct wm8350_data *priv;
	int ret;
	struct wm8350_output *out1;
	struct wm8350_output *out2;

	BUG_ON(!wm8350_codec);

	socdev->card->codec = wm8350_codec;
	codec = socdev->card->codec;
	wm8350 = codec->control_data;
	priv = snd_soc_codec_get_drvdata(codec);

	/* Enable the codec */
	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

	/* Enable robust clocking mode in ADC */
	wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
	wm8350_codec_write(codec, 0xde, 0x13);
	wm8350_codec_write(codec, WM8350_SECURITY, 0);

	/* read OUT1 & OUT2 volumes */
	out1 = &priv->out1;
	out2 = &priv->out2;
	out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) &
			  WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
	out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) &
			   WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
	out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) &
			  WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
	out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) &
			   WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
	wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);

	/* Latch VU bits & mute */
	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME,
			WM8350_OUT1_VU | WM8350_OUT1L_MUTE);
	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME,
			WM8350_OUT2_VU | WM8350_OUT2L_MUTE);
	wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME,
			WM8350_OUT1_VU | WM8350_OUT1R_MUTE);
	wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
			WM8350_OUT2_VU | WM8350_OUT2R_MUTE);

	/* Make sure jack detect is disabled to start off with */
	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
			  WM8350_JDL_ENA | WM8350_JDR_ENA);

	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
			    wm8350_hp_jack_handler, 0, "Left jack detect",
			    priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
			    wm8350_hp_jack_handler, 0, "Right jack detect",
			    priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
			    wm8350_mic_handler, 0, "Microphone short", priv);
	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
			    wm8350_mic_handler, 0, "Microphone detect", priv);

	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to create pcms\n");
		return ret;
	}

	snd_soc_add_controls(codec, wm8350_snd_controls,
				ARRAY_SIZE(wm8350_snd_controls));
	wm8350_add_widgets(codec);

	wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	return 0;
}
コード例 #4
0
ファイル: adau1373.c プロジェクト: GerardGarcia/linux
static int adau1373_probe(struct snd_soc_codec *codec)
{
	struct adau1373_platform_data *pdata = codec->dev->platform_data;
	bool lineout_differential = false;
	unsigned int val;
	int ret;
	int i;

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

	codec->dapm.idle_bias_off = true;

	if (pdata) {
		if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
			return -EINVAL;

		if (!adau1373_valid_micbias(pdata->micbias1) ||
			!adau1373_valid_micbias(pdata->micbias2))
			return -EINVAL;

		for (i = 0; i < pdata->num_drc; ++i) {
			adau1373_load_drc_settings(codec, i,
				pdata->drc_setting[i]);
		}

		snd_soc_add_controls(codec, adau1373_drc_controls,
			pdata->num_drc);

		val = 0;
		for (i = 0; i < 4; ++i) {
			if (pdata->input_differential[i])
				val |= BIT(i);
		}
		snd_soc_write(codec, ADAU1373_INPUT_MODE, val);

		val = 0;
		if (pdata->lineout_differential)
			val |= ADAU1373_OUTPUT_CTRL_LDIFF;
		if (pdata->lineout_ground_sense)
			val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
		snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val);

		lineout_differential = pdata->lineout_differential;

		snd_soc_write(codec, ADAU1373_EP_CTRL,
			(pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
			(pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
	}

	if (!lineout_differential) {
		snd_soc_add_controls(codec, adau1373_lineout2_controls,
			ARRAY_SIZE(adau1373_lineout2_controls));
	}

	snd_soc_write(codec, ADAU1373_ADC_CTRL,
	    ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT);

	return 0;
}
コード例 #5
0
ファイル: ad1980.c プロジェクト: 3sOx/asuswrt-merlin
static int ad1980_soc_probe(struct platform_device *pdev)
{
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec;
	int ret = 0;
	u16 vendor_id2;
	u16 ext_status;

	printk(KERN_INFO "AD1980 SoC Audio Codec\n");

	socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
	if (socdev->card->codec == NULL)
		return -ENOMEM;
	codec = socdev->card->codec;
	mutex_init(&codec->mutex);

	codec->reg_cache =
		kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
	if (codec->reg_cache == NULL) {
		ret = -ENOMEM;
		goto cache_err;
	}
	memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
			ARRAY_SIZE(ad1980_reg));
	codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
	codec->reg_cache_step = 2;
	codec->name = "AD1980";
	codec->owner = THIS_MODULE;
	codec->dai = &ad1980_dai;
	codec->num_dai = 1;
	codec->write = ac97_write;
	codec->read = ac97_read;
	INIT_LIST_HEAD(&codec->dapm_widgets);
	INIT_LIST_HEAD(&codec->dapm_paths);

	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
	if (ret < 0) {
		printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
		goto codec_err;
	}

	/* register pcms */
	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	if (ret < 0)
		goto pcm_err;


	ret = ad1980_reset(codec, 0);
	if (ret < 0) {
		printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
		goto reset_err;
	}

	/* Read out vendor ID to make sure it is ad1980 */
	if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144)
		goto reset_err;

	vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);

	if (vendor_id2 != 0x5370) {
		if (vendor_id2 != 0x5374)
			goto reset_err;
		else
			printk(KERN_WARNING "ad1980: "
				"Found AD1981 - only 2/2 IN/OUT Channels "
				"supported\n");
	}

	/* unmute captures and playbacks volume */
	ac97_write(codec, AC97_MASTER, 0x0000);
	ac97_write(codec, AC97_PCM, 0x0000);
	ac97_write(codec, AC97_REC_GAIN, 0x0000);
	ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
	ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);

	/*power on LFE/CENTER/Surround DACs*/
	ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
	ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);

	snd_soc_add_controls(codec, ad1980_snd_ac97_controls,
				ARRAY_SIZE(ad1980_snd_ac97_controls));

	return 0;

reset_err:
	snd_soc_free_pcms(socdev);

pcm_err:
	snd_soc_free_ac97_codec(codec);

codec_err:
	kfree(codec->reg_cache);

cache_err:
	kfree(socdev->card->codec);
	socdev->card->codec = NULL;
	return ret;
}
コード例 #6
0
static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
	int err;
#ifdef CONFIG_PANTECH_SND //kdkim
#if defined(T_EF44S)
	int ret = 0; 
#elif defined(T_VEGAPVW)
	int ret = 0;
	int hw_rev;
#endif
#endif
	struct snd_soc_codec *codec = rtd->codec;
	struct snd_soc_dapm_context *dapm = &codec->dapm;
	
#if !(defined(T_EF44S) || defined(T_VEGAPVW)) //Qualcomm original...kdkim other model
	struct pm_gpio jack_gpio_cfg = {
		.direction = PM_GPIO_DIR_IN,
		.pull = PM_GPIO_PULL_DN,
		.function = PM_GPIO_FUNC_NORMAL,
		.vin_sel = 2,
		.inv_int_pol = 0,
	};
#endif
	pr_debug("%s()\n", __func__);

	if (machine_is_msm8960_liquid()) {
		top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
		bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
	}

	rtd->pmdown_time = 0;

	err = snd_soc_add_controls(codec, tabla_msm8960_controls,
				ARRAY_SIZE(tabla_msm8960_controls));
	if (err < 0)
		return err;

	snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
				ARRAY_SIZE(msm8960_dapm_widgets));

	snd_soc_dapm_add_routes(dapm, common_audio_map,
		ARRAY_SIZE(common_audio_map));

	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");

	snd_soc_dapm_sync(dapm);

	err = snd_soc_jack_new(codec, "Headset Jack",
			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
				SND_JACK_OC_HPHR),
			       &hs_jack);
	if (err) {
		pr_err("failed to create new jack\n");
		return err;
	}

	err = snd_soc_jack_new(codec, "Button Jack",
			       TABLA_JACK_BUTTON_MASK, &button_jack);
	if (err) {
		pr_err("failed to create new jack\n");
		return err;
	}

#if defined(T_VEGAPVW) //kdkim
	hw_rev = get_hw_revision();
	pr_debug("########### msm8960 hw_rev : %d\n", hw_rev); 

	if(hw_rev < 4) {
		mbhc_cfg.gpio = 0;
		mbhc_cfg.gpio_irq = 0;
	}
#endif

#ifdef CONFIG_PANTECH_SND //kdkim
#if defined(T_EF44S) || defined(T_VEGAPVW)
	if (mbhc_cfg.gpio) {
		ret = gpio_request(JACK_DETECT_GPIO, "headset_detect");
		if(ret){
			pr_err("%s: gpio_request failed %d\n", __func__,
			       ret);
			headset_gpio_config = false;
			gpio_free(JACK_DETECT_GPIO);
		}

		ret = gpio_direction_input(mbhc_cfg.gpio);
		if(ret){
			pr_err("%s: gpio_direction_input failed %d\n", __func__,
			       ret);
			headset_gpio_config = false;
			gpio_free(JACK_DETECT_GPIO);
		}

		mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
	}
#else //Qualcomm original and other model temp
	if (hs_detect_use_gpio) {
		mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
		mbhc_cfg.gpio_irq = JACK_DETECT_INT;
	}

#if defined(T_MAGNUS)
	mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
	mbhc_cfg.gpio_irq = JACK_DETECT_INT;
#endif

	if (mbhc_cfg.gpio) {
		err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
		if (err) {
			pr_err("%s: pm8xxx_gpio_config failed %d\n", __func__,
			       err);
			return err;
		}
	}
#endif
#endif

	mbhc_cfg.read_fw_bin = hs_detect_use_firmware;

	err = tabla_hs_detect(codec, &mbhc_cfg);

	return err;
}

static struct snd_soc_dsp_link lpa_fe_media = {
	.playback = true,
	.trigger = {
		SND_SOC_DSP_TRIGGER_POST,
		SND_SOC_DSP_TRIGGER_POST
	},
};

static struct snd_soc_dsp_link fe_media = {
	.playback = true,
	.capture = true,
	.trigger = {
		SND_SOC_DSP_TRIGGER_POST,
		SND_SOC_DSP_TRIGGER_POST
	},
};

/* bi-directional media definition for hostless PCM device */
static struct snd_soc_dsp_link bidir_hl_media = {
	.playback = true,
	.capture = true,
	.trigger = {
		SND_SOC_DSP_TRIGGER_POST,
		SND_SOC_DSP_TRIGGER_POST
	},
};

static struct snd_soc_dsp_link hdmi_rx_hl = {
	.playback = true,
	.trigger = {
		SND_SOC_DSP_TRIGGER_POST,
		SND_SOC_DSP_TRIGGER_POST
	},
};

static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
			struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
	SNDRV_PCM_HW_PARAM_RATE);

	struct snd_interval *channels = hw_param_interval(params,
			SNDRV_PCM_HW_PARAM_CHANNELS);

	pr_debug("%s()\n", __func__);
	rate->min = rate->max = 48000;
	channels->min = channels->max = msm8960_slim_0_rx_ch;

	return 0;
}

static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
			struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
	SNDRV_PCM_HW_PARAM_RATE);

	struct snd_interval *channels = hw_param_interval(params,
			SNDRV_PCM_HW_PARAM_CHANNELS);

	pr_debug("%s()\n", __func__);
	rate->min = rate->max = 48000;
	channels->min = channels->max = msm8960_slim_0_tx_ch;

	return 0;
}

static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
			struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
	SNDRV_PCM_HW_PARAM_RATE);

	pr_debug("%s()\n", __func__);
	rate->min = rate->max = 48000;

	return 0;
}

static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_RATE);

	struct snd_interval *channels = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_CHANNELS);

	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
			channels->min, channels->max);

	rate->min = rate->max = 48000;

	return 0;
}

static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_RATE);

	struct snd_interval *channels = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_CHANNELS);

	rate->min = rate->max = msm8960_btsco_rate;
	channels->min = channels->max = msm8960_btsco_ch;

	return 0;
}
static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
					struct snd_pcm_hw_params *params)
{
	struct snd_interval *rate = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_RATE);

	struct snd_interval *channels = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_CHANNELS);

	/* PCM only supports mono output with 8khz sample rate */
	rate->min = rate->max = 8000;
	channels->min = channels->max = 1;

	return 0;
}
static int msm8960_aux_pcm_get_gpios(void)
{
	int ret = 0;

	pr_debug("%s\n", __func__);

	ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
	if (ret < 0) {
		pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
				__func__, GPIO_AUX_PCM_DOUT);
		goto fail_dout;
	}

	ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
	if (ret < 0) {
		pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
				__func__, GPIO_AUX_PCM_DIN);
		goto fail_din;
	}

	ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
	if (ret < 0) {
		pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
				__func__, GPIO_AUX_PCM_SYNC);
		goto fail_sync;
	}
	ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
	if (ret < 0) {
		pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
				__func__, GPIO_AUX_PCM_CLK);
		goto fail_clk;
	}

	return 0;

fail_clk:
	gpio_free(GPIO_AUX_PCM_SYNC);
fail_sync:
	gpio_free(GPIO_AUX_PCM_DIN);
fail_din:
	gpio_free(GPIO_AUX_PCM_DOUT);
fail_dout:

	return ret;
}

static int msm8960_aux_pcm_free_gpios(void)
{
	gpio_free(GPIO_AUX_PCM_DIN);
	gpio_free(GPIO_AUX_PCM_DOUT);
	gpio_free(GPIO_AUX_PCM_SYNC);
	gpio_free(GPIO_AUX_PCM_CLK);

	return 0;
}
static int msm8960_startup(struct snd_pcm_substream *substream)
{
	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
		 substream->name, substream->stream);
	return 0;
}

static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
{
	int ret = 0;

	pr_debug("%s(): substream = %s\n", __func__, substream->name);
	ret = msm8960_aux_pcm_get_gpios();
	if (ret < 0) {
		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
		return -EINVAL;
	}
	return 0;
}

static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
{

	pr_debug("%s(): substream = %s\n", __func__, substream->name);
	msm8960_aux_pcm_free_gpios();
}
コード例 #7
0
static int midas_wm1811_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
	struct snd_soc_codec *codec = rtd->codec;
	struct wm1811_machine_priv *wm1811
		= snd_soc_card_get_drvdata(codec->card);
	struct snd_soc_dai *aif1_dai = rtd->codec_dai;
	struct wm8994 *control = codec->control_data;
	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
	int ret;

#ifdef SND_USE_BIAS_LEVEL
	midas_aif1_dai = aif1_dai;
#endif

#ifdef CONFIG_MACH_GC1
	wm1811_codec = codec;
#endif

	midas_snd_set_mclk(true, false);

	rtd->codec_dai->driver->playback.channels_max =
				rtd->cpu_dai->driver->playback.channels_max;

	ret = snd_soc_add_controls(codec, midas_controls,
					ARRAY_SIZE(midas_controls));

	ret = snd_soc_dapm_new_controls(&codec->dapm, midas_dapm_widgets,
					   ARRAY_SIZE(midas_dapm_widgets));
	if (ret != 0)
		dev_err(codec->dev, "Failed to add DAPM widgets: %d\n", ret);

	ret = snd_soc_dapm_add_routes(&codec->dapm, midas_dapm_routes,
					   ARRAY_SIZE(midas_dapm_routes));
	if (ret != 0)
		dev_err(codec->dev, "Failed to add DAPM routes: %d\n", ret);

	ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
				     MIDAS_DEFAULT_MCLK2, SND_SOC_CLOCK_IN);
	if (ret < 0)
		dev_err(codec->dev, "Failed to boot clocking\n");

	/* Force AIF1CLK on as it will be master for jack detection */
	if (wm8994->revision > 1) {
		ret = snd_soc_dapm_force_enable_pin(&codec->dapm, "AIF1CLK");
		if (ret < 0)
			dev_err(codec->dev, "Failed to enable AIF1CLK: %d\n",
					ret);
	}

	ret = snd_soc_dapm_disable_pin(&codec->dapm, "S5P RP");
	if (ret < 0)
		dev_err(codec->dev, "Failed to disable S5P RP: %d\n", ret);

	snd_soc_dapm_ignore_suspend(&codec->dapm, "RCV");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "SPK");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "HP");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "Headset Mic");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "Sub Mic");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "Main Mic");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "AIF1DACDAT");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "AIF2DACDAT");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "AIF3DACDAT");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "AIF1ADCDAT");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "AIF2ADCDAT");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "AIF3ADCDAT");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "FM In");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "LINE");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "HDMI");
	snd_soc_dapm_ignore_suspend(&codec->dapm, "Third Mic");

	wm1811->codec = codec;

	midas_micd_set_rate(codec);

#ifdef CONFIG_SEC_DEV_JACK
	/* By default use idle_bias_off, will override for WM8994 */
	codec->dapm.idle_bias_off = 0;
#else /* CONFIG_SEC_DEV_JACK */
	wm1811->jack.status = 0;

	ret = snd_soc_jack_new(codec, "Midas Jack",
				SND_JACK_HEADSET | SND_JACK_BTN_0 |
				SND_JACK_BTN_1 | SND_JACK_BTN_2,
				&wm1811->jack);

	if (ret < 0)
		dev_err(codec->dev, "Failed to create jack: %d\n", ret);

	ret = snd_jack_set_key(wm1811->jack.jack, SND_JACK_BTN_0, KEY_MEDIA);

	if (ret < 0)
		dev_err(codec->dev, "Failed to set KEY_MEDIA: %d\n", ret);

	ret = snd_jack_set_key(wm1811->jack.jack, SND_JACK_BTN_1,
							KEY_VOLUMEDOWN);
	if (ret < 0)
		dev_err(codec->dev, "Failed to set KEY_VOLUMEUP: %d\n", ret);

	ret = snd_jack_set_key(wm1811->jack.jack, SND_JACK_BTN_2,
							KEY_VOLUMEUP);

	if (ret < 0)
		dev_err(codec->dev, "Failed to set KEY_VOLUMEDOWN: %d\n", ret);

	if (wm8994->revision > 1) {
		dev_info(codec->dev, "wm1811: Rev %c support mic detection\n",
			'A' + wm8994->revision);
		ret = wm8958_mic_detect(codec, &wm1811->jack, midas_micdet,
			wm1811);

		if (ret < 0)
			dev_err(codec->dev, "Failed start detection: %d\n",
				ret);
	} else {
		dev_info(codec->dev, "wm1811: Rev %c doesn't support mic detection\n",
			'A' + wm8994->revision);
		codec->dapm.idle_bias_off = 0;
	}
	/* To wakeup for earjack event in suspend mode */
	enable_irq_wake(control->irq);

	wake_lock_init(&wm1811->jackdet_wake_lock,
					WAKE_LOCK_SUSPEND, "midas_jackdet");

	/* To support PBA function test */
	jack_class = class_create(THIS_MODULE, "audio");

	if (IS_ERR(jack_class))
		pr_err("Failed to create class\n");

	jack_dev = device_create(jack_class, NULL, 0, codec, "earjack");

	if (device_create_file(jack_dev, &dev_attr_select_jack) < 0)
		pr_err("Failed to create device file (%s)!\n",
			dev_attr_select_jack.attr.name);

	if (device_create_file(jack_dev, &dev_attr_key_state) < 0)
		pr_err("Failed to create device file (%s)!\n",
			dev_attr_key_state.attr.name);

	if (device_create_file(jack_dev, &dev_attr_state) < 0)
		pr_err("Failed to create device file (%s)!\n",
			dev_attr_state.attr.name);

	if (device_create_file(jack_dev, &dev_attr_reselect_jack) < 0)
		pr_err("Failed to create device file (%s)!\n",
			dev_attr_reselect_jack.attr.name);

#endif /* CONFIG_SEC_DEV_JACK */
	return snd_soc_dapm_sync(&codec->dapm);
}