static int map_late_probe(struct snd_soc_card *card)
{
	int ret;
	struct snd_soc_codec *codec = card->rtd[0].codec;

	ret = snd_soc_jack_new(codec, "Headset", SND_JACK_HEADSET, &hs_jack);
	if (ret)
		return ret;

	if (headset_detect) {
		ret = headset_detect(&hs_jack);
		if (ret)
			return ret;
	}

	ret = snd_soc_jack_new(codec, "Hook", SND_JACK_HEADSET, &hk_jack);
	if (ret)
		return ret;

	snd_jack_set_key(hk_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
	snd_jack_set_key(hk_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
	snd_jack_set_key(hk_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);

	if (hook_detect) {
		ret = hook_detect(&hk_jack);
		if (ret)
			return ret;
	}

	return 0;
}
예제 #2
0
static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
{
	struct snd_soc_component *component;
	struct snd_soc_dai_link *dai_link = rtd->dai_link;
	struct snd_soc_card *card = rtd->card;
	struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
	int i, rval;

	if (!pdata->jack_setup) {
		struct snd_jack *jack;

		rval = snd_soc_card_jack_new(card, "Headset Jack",
				SND_JACK_HEADSET |
				SND_JACK_HEADPHONE |
				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
				SND_JACK_BTN_2 | SND_JACK_BTN_3,
				&pdata->jack, NULL, 0);

		if (rval < 0) {
			dev_err(card->dev, "Unable to add Headphone Jack\n");
			return rval;
		}

		jack = pdata->jack.jack;

		snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
		snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
		snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
		snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
		pdata->jack_setup = true;
	}

	for (i = 0 ; i < dai_link->num_codecs; i++) {
		struct snd_soc_dai *dai = rtd->codec_dais[i];

		component = dai->component;
		rval = snd_soc_component_set_jack(
				component, &pdata->jack, NULL);
		if (rval != 0 && rval != -ENOTSUPP) {
			dev_warn(card->dev, "Failed to set jack: %d\n", rval);
			return rval;
		}
	}

	return 0;
}
예제 #3
0
static int rt5512_headset_keys(struct snd_soc_jack *jack)
{
	int err = 0;

	err = snd_jack_set_key(jack->jack, SND_JACK_BTN_0, 0x80);
	if (err)
		return err;

	err = snd_jack_set_key(jack->jack, SND_JACK_BTN_1, 0x81);
	if (err)
		return err;

	err = snd_jack_set_key(jack->jack, SND_JACK_BTN_2, 0x82);
	if (err)
		return err;

	return 0;
}
예제 #4
0
파일: hda_jack.c 프로젝트: avagin/linux
/**
 * snd_hda_jack_add_kctl - Add a kctl for the given pin
 * @codec: the HDA codec
 * @nid: pin NID to assign
 * @name: string name for the jack
 * @phantom_jack: flag to deal as a phantom jack
 * @type: jack type bits to be reported, 0 for guessing from pincfg
 * @keymap: optional jack / key mapping
 *
 * This assigns a jack-detection kctl to the given pin.  The kcontrol
 * will have the given name and index.
 */
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
			  const char *name, bool phantom_jack,
			  int type, const struct hda_jack_keymap *keymap)
{
	struct hda_jack_tbl *jack;
	const struct hda_jack_keymap *map;
	int err, state, buttons;

	jack = snd_hda_jack_tbl_new(codec, nid);
	if (!jack)
		return 0;
	if (jack->jack)
		return 0; /* already created */

	if (!type)
		type = get_input_jack_type(codec, nid);

	buttons = 0;
	if (keymap) {
		for (map = keymap; map->type; map++)
			buttons |= map->type;
	}

	err = snd_jack_new(codec->card, name, type | buttons,
			   &jack->jack, true, phantom_jack);
	if (err < 0)
		return err;

	jack->phantom_jack = !!phantom_jack;
	jack->type = type;
	jack->button_state = 0;
	jack->jack->private_data = jack;
	jack->jack->private_free = hda_free_jack_priv;
	if (keymap) {
		for (map = keymap; map->type; map++)
			snd_jack_set_key(jack->jack, map->type, map->key);
	}

	state = snd_hda_jack_detect(codec, nid);
	snd_jack_report(jack->jack, state ? jack->type : 0);

	return 0;
}
static int snd_ctp_jack_init(struct snd_soc_pcm_runtime *runtime,
						bool jack_supported)
{
	int ret, irq;
	struct ctp_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
	struct snd_soc_jack_gpio *gpio = &hs_gpio[CTP_BTN_GPIO];
	struct snd_soc_codec *codec = runtime->codec;

	if (!jack_supported)
		return 0;

	/* Setup the HPDET timer */
	INIT_DELAYED_WORK(&ctx->jack_work_insert, headset_insert_poll);
	INIT_DELAYED_WORK(&ctx->jack_work_remove, headset_remove_poll);

	/* Headset and button jack detection */
	ret = snd_soc_jack_new(codec, "Intel MID Audio Jack",
			SND_JACK_HEADSET | SND_JACK_BTN_0, &ctx->ctp_jack);
	if (ret) {
		pr_err("jack creation failed\n");
		return ret;
	}
	snd_jack_set_key(ctx->ctp_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
	ret = snd_soc_jack_add_gpios(&ctx->ctp_jack, 2, ctx->hs_gpio_ops);
	if (ret) {
		pr_err("adding jack GPIO failed\n");
		return ret;
	}
	irq = gpio_to_irq(gpio->gpio);
	if (irq < 0) {
		pr_err("%d:Failed to map gpio_to_irq\n", irq);
		return irq;
	}

	/* Disable Button_press interrupt if no Headset */
	pr_err("Disable %d interrupt line\n", irq);
	disable_irq_nosync(irq);
	atomic_set(&ctx->bpirq_flag, 0);
	atomic_set(&ctx->hs_det_retry, HS_DET_RETRY);
	return 0;
}
예제 #6
0
/**
 * snd_intelmad_jack- to setup jack settings of the card
 *
 * @intelmaddata: pointer to internal context
 *
 * This function is called send jack events
 */
static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
{
	struct snd_jack *jack;
	int retval;

	pr_debug("snd_intelmad_jack called\n");
	jack = &intelmaddata->jack[0].jack;
	snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PHONE);
	retval = snd_jack_new(intelmaddata->card, "Intel(R) MID Audio Jack",
		SND_JACK_HEADPHONE | SND_JACK_HEADSET |
		SW_JACK_PHYSICAL_INSERT | SND_JACK_BTN_0
		| SND_JACK_BTN_1, &jack);
	pr_debug("snd_intelmad_jack called\n");
	if (retval < 0)
		return retval;
	snd_jack_report(jack, 0);

	jack->private_data = jack;
	intelmaddata->jack[0].jack = *jack;

	return retval;
}
예제 #7
0
static int msm8930_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
	int err, ret;
	struct snd_soc_codec *codec = rtd->codec;
	struct snd_soc_dapm_context *dapm = &codec->dapm;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

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

	snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
				ARRAY_SIZE(msm8930_dapm_widgets));

	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
		snd_soc_dapm_add_routes(dapm, common_audio_map_sglte,
			ARRAY_SIZE(common_audio_map_sglte));
	else
		snd_soc_dapm_add_routes(dapm, common_audio_map,
			ARRAY_SIZE(common_audio_map));

	snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
	snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Neg");

	snd_soc_dapm_sync(dapm);

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

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

	ret = snd_jack_set_key(button_jack.jack,
			       SND_JACK_BTN_0,
			       KEY_MEDIA);
	if (ret) {
		pr_err("%s: Failed to set code for btn-0\n", __func__);
		return err;
	}

	codec_clk = clk_get(cpu_dai->dev, "osr_clk");

	/*
	 * Switch is present only in 8930 CDP and SGLTE
	 */
	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE ||
		machine_is_msm8930_cdp())
		mbhc_cfg.swap_gnd_mic = msm8930_swap_gnd_mic;

	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
		mbhc_cfg.gpio = GPIO_HS_DET_SGLTE;
		mbhc_cfg.gpio_level_insert = 0;
	} else
		mbhc_cfg.gpio = GPIO_HS_DET;

	/*
	 * GPIO for headset detect is present in all devices
	 * MTP/Fluid/CDP/SGLTE
	 */
	err = gpio_request(mbhc_cfg.gpio, "HEADSET_DETECT");
	if (err) {
		pr_err("%s: Failed to request gpio %d\n",
				__func__, mbhc_cfg.gpio);
		return err;
	}

	mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
	sitar_hs_detect(codec, &mbhc_cfg);

	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
		/* Initialize default PMIC speaker gain */
		pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
	}

	return 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);
}
예제 #9
0
static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
{
	struct snd_soc_card *card = runtime->card;
	struct snd_soc_component *codec = runtime->codec_dai->component;
	struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
	const struct snd_soc_dapm_route *custom_map;
	int num_routes;
	int ret;

	card->dapm.idle_bias_off = true;

	/* Start with RC clk for jack-detect (we disable MCLK below) */
	if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
		snd_soc_component_update_bits(codec, RT5651_GLB_CLK,
			RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_RCCLK);

	switch (BYT_RT5651_MAP(byt_rt5651_quirk)) {
	case BYT_RT5651_IN1_MAP:
		custom_map = byt_rt5651_intmic_in1_map;
		num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map);
		break;
	case BYT_RT5651_IN2_MAP:
		custom_map = byt_rt5651_intmic_in2_map;
		num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
		break;
	case BYT_RT5651_IN1_IN2_MAP:
		custom_map = byt_rt5651_intmic_in1_in2_map;
		num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
		break;
	default:
		custom_map = byt_rt5651_intmic_dmic_map;
		num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
	}
	ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
	if (ret)
		return ret;

	if (byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2) {
		ret = snd_soc_dapm_add_routes(&card->dapm,
					byt_rt5651_ssp2_aif2_map,
					ARRAY_SIZE(byt_rt5651_ssp2_aif2_map));
	} else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1) {
		ret = snd_soc_dapm_add_routes(&card->dapm,
					byt_rt5651_ssp0_aif1_map,
					ARRAY_SIZE(byt_rt5651_ssp0_aif1_map));
	} else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2) {
		ret = snd_soc_dapm_add_routes(&card->dapm,
					byt_rt5651_ssp0_aif2_map,
					ARRAY_SIZE(byt_rt5651_ssp0_aif2_map));
	} else {
		ret = snd_soc_dapm_add_routes(&card->dapm,
					byt_rt5651_ssp2_aif1_map,
					ARRAY_SIZE(byt_rt5651_ssp2_aif1_map));
	}
	if (ret)
		return ret;

	ret = snd_soc_add_card_controls(card, byt_rt5651_controls,
					ARRAY_SIZE(byt_rt5651_controls));
	if (ret) {
		dev_err(card->dev, "unable to add card controls\n");
		return ret;
	}
	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");

	if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
		/*
		 * The firmware might enable the clock at
		 * boot (this information may or may not
		 * be reflected in the enable clock register).
		 * To change the rate we must disable the clock
		 * first to cover these cases. Due to common
		 * clock framework restrictions that do not allow
		 * to disable a clock that has not been enabled,
		 * we need to enable the clock first.
		 */
		ret = clk_prepare_enable(priv->mclk);
		if (!ret)
			clk_disable_unprepare(priv->mclk);

		if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ)
			ret = clk_set_rate(priv->mclk, 25000000);
		else
			ret = clk_set_rate(priv->mclk, 19200000);

		if (ret)
			dev_err(card->dev, "unable to set MCLK rate\n");
	}

	if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) {
		ret = snd_soc_card_jack_new(runtime->card, "Headset",
				    SND_JACK_HEADSET | SND_JACK_BTN_0,
				    &priv->jack, bytcr_jack_pins,
				    ARRAY_SIZE(bytcr_jack_pins));
		if (ret) {
			dev_err(runtime->dev, "jack creation failed %d\n", ret);
			return ret;
		}

		snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
				 KEY_PLAYPAUSE);

		ret = snd_soc_component_set_jack(codec, &priv->jack, NULL);
		if (ret)
			return ret;
	}

	return 0;
}
예제 #10
0
파일: msm8x60.c 프로젝트: veirs/UbuntuTouch
static int msm_soc_dai_init(struct snd_soc_codec *codec)
{
	int ret = 0;
	struct snd_soc_card *card = codec->socdev->card;
	struct wm8994_priv *wm8994;

	ret = msm_new_mixer(codec->card);
	if (ret < 0)
		pr_err("%s: ALSA MSM Mixer Fail\n", __func__);

	wm8994_add_controls(codec);
	// permanently disable pin
	snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
	snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
	snd_soc_dapm_nc_pin(codec, "SPKOUTLN");
	snd_soc_dapm_nc_pin(codec, "SPKOUTLP");
	snd_soc_dapm_nc_pin(codec, "HPOUT2P");
	snd_soc_dapm_nc_pin(codec, "HPOUT2N");
	snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
	snd_soc_dapm_nc_pin(codec, "IN2RN");
	snd_soc_dapm_nc_pin(codec, "IN2LN");
	snd_soc_dapm_nc_pin(codec, "IN1RN");
	snd_soc_dapm_nc_pin(codec, "IN1RP");
	snd_soc_dapm_nc_pin(codec, "IN1LN");

#if defined(CONFIG_MACH_TENDERLOIN)
	snd_soc_dapm_new_controls(codec, tenderloin_dapm_widgets,
				ARRAY_SIZE(tenderloin_dapm_widgets));

	snd_soc_dapm_add_routes(codec, tenderloin_dapm_routes,
				ARRAY_SIZE(tenderloin_dapm_routes));
#endif

	// Initially clock from MCLK1 - we will switch over to the FLLs
	// once we start playing audio but don't have BCLK yet to boot
	// them.
	ret = snd_soc_dai_set_sysclk(&codec->dai[0], WM8994_SYSCLK_MCLK1,
					WM_FLL, 0);
	if (ret != 0) {
		pr_err("Failed to set DAI sysclk: %d\n", ret);
		return ret;
	}
	ret = snd_soc_dai_set_sysclk(&codec->dai[1], WM8994_SYSCLK_MCLK1,
					WM_FLL, 0);
	if (ret != 0) {
		pr_err("Failed to set DAI sysclk: %d\n", ret);
		return ret;
	}

	/* Headphone jack detection */
	// If we have the HeadSet uart (hs_uart) then we DONT want to detect headphones
	if ( hs_uart == 1 ) {
		snd_soc_jack_new(card, "headset", SND_JACK_MICROPHONE | SND_JACK_BTN_0, &hp_jack);
	} else {
		snd_soc_jack_new(card, "headset", SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_BTN_0, &hp_jack);
	}
	snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),hp_jack_pins);
	snd_jack_set_key(hp_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); // mapping button 0 to KEY_PLAYPUASE

	// Register a notifier with snd_soc_jack
	jack_notifier.notifier_call = jack_notifier_event;

	snd_soc_jack_notifier_register(&hp_jack, &jack_notifier);

	ret = snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios);

	wm8994 = snd_soc_codec_get_drvdata(codec);

	if(wm8994)
		wm8994->soc_jack = &hp_jack;

	// add headphone switch
	headphone_switch = kzalloc(sizeof(struct switch_dev), GFP_KERNEL);
	if (headphone_switch) {
		headphone_switch->name = "h2w";
		headphone_switch->print_name = headphone_switch_print_name;

		ret = switch_dev_register(headphone_switch);
		if (ret < 0) {
			printk(KERN_ERR "Unable to register headphone switch\n");
			kfree(headphone_switch);
			headphone_switch = NULL;
		} else {
			headphone_plugged = hp_jack.status ? 1 : 0;
			printk(KERN_INFO "Headphone switch initialized, plugged=%d\n",
					headphone_plugged);
			switch_set_state(headphone_switch, headphone_plugged);
		}
	} else {
		printk(KERN_ERR "Unable to allocate headphone switch\n");
	}

   return ret;
}
예제 #11
0
static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
{
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct snd_soc_component *component;
	struct snd_soc_dai_link *dai_link = rtd->dai_link;
	struct snd_soc_card *card = rtd->card;
	struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
	int i, rval;

	switch (cpu_dai->id) {
	case MI2S_PRIMARY:
		writel(readl(pdata->spkr_iomux) | SPKR_CTL_PRI_WS_SLAVE_SEL_11,
			pdata->spkr_iomux);
		break;

	case MI2S_QUATERNARY:
		/* Configure the Quat MI2S to TLMM */
		writel(readl(pdata->mic_iomux) | MIC_CTRL_QUA_WS_SLAVE_SEL_10 |
			MIC_CTRL_TLMM_SCLK_EN,
			pdata->mic_iomux);
		break;
	case MI2S_TERTIARY:
		writel(readl(pdata->mic_iomux) | MIC_CTRL_TER_WS_SLAVE_SEL |
			MIC_CTRL_TLMM_SCLK_EN,
			pdata->mic_iomux);

		break;

	default:
		dev_err(card->dev, "unsupported cpu dai configuration\n");
		return -EINVAL;

	}

	if (!pdata->jack_setup) {
		struct snd_jack *jack;

		rval = snd_soc_card_jack_new(card, "Headset Jack",
					     SND_JACK_HEADSET |
					     SND_JACK_HEADPHONE |
					     SND_JACK_BTN_0 | SND_JACK_BTN_1 |
					     SND_JACK_BTN_2 | SND_JACK_BTN_3 |
					     SND_JACK_BTN_4,
					     &pdata->jack, NULL, 0);

		if (rval < 0) {
			dev_err(card->dev, "Unable to add Headphone Jack\n");
			return rval;
		}

		jack = pdata->jack.jack;

		snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
		snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
		snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
		snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
		pdata->jack_setup = true;
	}

	for (i = 0 ; i < dai_link->num_codecs; i++) {
		struct snd_soc_dai *dai = rtd->codec_dais[i];

		component = dai->component;
		/* Set default mclk for internal codec */
		rval = snd_soc_component_set_sysclk(component, 0, 0, DEFAULT_MCLK_RATE,
				       SND_SOC_CLOCK_IN);
		if (rval != 0 && rval != -ENOTSUPP) {
			dev_warn(card->dev, "Failed to set mclk: %d\n", rval);
			return rval;
		}
		rval = snd_soc_component_set_jack(component, &pdata->jack, NULL);
		if (rval != 0 && rval != -ENOTSUPP) {
			dev_warn(card->dev, "Failed to set jack: %d\n", rval);
			return rval;
		}
	}

	return 0;
}