/* * The MCLK1 clock source is XCLKOUT with its mux set to the external fixed rate * oscillator (XXTI).
*/ #define MCLK1_RATE 24000000U #define MCLK2_RATE 32768U #define DEFAULT_FLL1_RATE 11289600U
/* * min_mv/max_mv values in this struct are set up based on DT values.
*/ staticstruct snd_soc_jack_zone headset_jack_zones[] = {
{ .jack_type = SND_JACK_HEADPHONE, },
{ .jack_type = SND_JACK_HEADSET, },
{ .jack_type = SND_JACK_HEADPHONE, },
};
/* * This is used for manual detection in headset_key_check, we reuse the * structure since it's convenient. * * min_mv/max_mv values in this struct are set up based on DT values.
*/ staticstruct snd_soc_jack_zone headset_key_zones[] = {
{ .jack_type = SND_JACK_BTN_0, }, /* Media */
{ .jack_type = SND_JACK_BTN_1, }, /* Volume Up */
{ .jack_type = SND_JACK_BTN_2, }, /* Volume Down */
};
if (!gpiod_get_value_cansleep(priv->gpio_headset_detect)) return 0;
/* Enable headset mic bias regulator so that the ADC reading works */
ret = snd_soc_dapm_force_enable_pin(dapm, "headset-mic-bias"); if (ret < 0) {
pr_err("%s: Failed to enable headset mic bias regulator (%d), assuming headphones\n",
__func__, ret); return SND_JACK_HEADPHONE;
}
snd_soc_dapm_sync(dapm);
/* Sleep for a small amount of time to get the value to stabilize */
msleep(20);
ret = iio_read_channel_processed(priv->adc_headset_detect, &adc); if (ret) {
pr_err("%s: Failed to read ADC (%d), assuming headphones\n",
__func__, ret);
jack_type = SND_JACK_HEADPHONE; goto out;
}
pr_debug("%s: ADC value is %d\n", __func__, adc);
if (!rate)
rate = priv->fll1_rate; /* * If no new rate is requested, set FLL1 to a sane default for jack * detection.
*/ if (!rate)
rate = DEFAULT_FLL1_RATE;
if (rate != priv->fll1_rate && priv->fll1_rate) { /* while reconfiguring, switch to MCLK2 for SYSCLK */
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
MCLK2_RATE, SND_SOC_CLOCK_IN); if (ret < 0) {
dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret); return ret;
}
}
ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
MCLK1_RATE, rate); if (ret < 0) {
dev_err(card->dev, "Failed to set FLL1 rate: %d\n", ret); return ret;
}
priv->fll1_rate = rate;
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_FLL1,
priv->fll1_rate, SND_SOC_CLOCK_IN); if (ret < 0) {
dev_err(card->dev, "Failed to set SYSCLK source: %d\n", ret); return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK, 0,
SAMSUNG_I2S_OPCLK_PCLK); if (ret < 0) {
dev_err(card->dev, "Failed to set OPCLK source: %d\n", ret); return ret;
}
/* AIF1CLK should be at least 3MHz for "optimal performance" */ if (params_rate(params) == 8000 || params_rate(params) == 11025)
pll_out = params_rate(params) * 512; else
pll_out = params_rate(params) * 256;
/* * We only have a single external speaker, so mix stereo data * to a single mono stream.
*/ staticint midas_ext_spkmode(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event)
{ struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); int ret = 0;
switch (event) { case SND_SOC_DAPM_PRE_PMU:
ret = snd_soc_component_update_bits(codec, WM8994_SPKOUT_MIXERS,
WM8994_SPKMIXR_TO_SPKOUTL_MASK,
WM8994_SPKMIXR_TO_SPKOUTL); break; case SND_SOC_DAPM_POST_PMD:
ret = snd_soc_component_update_bits(codec, WM8994_SPKOUT_MIXERS,
WM8994_SPKMIXR_TO_SPKOUTL_MASK,
0); break;
}
/* Use MCLK2 as SYSCLK for boot */
ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, MCLK2_RATE,
SND_SOC_CLOCK_IN); if (ret < 0) {
dev_err(aif1_dai->dev, "Failed to switch to MCLK2: %d\n", ret); return ret;
}
if (!priv->gpio_headset_detect) {
ret = snd_soc_card_jack_new_pins(card, "Headset",
SND_JACK_HEADSET | SND_JACK_MECHANICAL |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
SND_JACK_BTN_4 | SND_JACK_BTN_5,
&priv->headset_jack,
headset_jack_pins,
ARRAY_SIZE(headset_jack_pins)); if (ret) return ret;
wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
NULL, NULL, NULL, NULL);
} else { /* Some devices (n8000, t310) use a GPIO to detect the jack. */
ret = snd_soc_card_jack_new_pins(card, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2,
&priv->headset_jack,
headset_jack_pins,
ARRAY_SIZE(headset_jack_pins)); if (ret) {
dev_err(card->dev, "Failed to set up headset pins: %d\n", ret); return ret;
}
ret = snd_soc_jack_add_zones(&priv->headset_jack,
ARRAY_SIZE(headset_jack_zones),
headset_jack_zones); if (ret) {
dev_err(card->dev, "Failed to set up headset zones: %d\n", ret); return ret;
}
ret = snd_soc_jack_add_gpios(&priv->headset_jack,
ARRAY_SIZE(headset_gpio),
headset_gpio); if (ret)
dev_err(card->dev, "Failed to set up headset jack GPIOs: %d\n",
ret);
priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH); if (IS_ERR(priv->gpio_fm_sel)) return dev_err_probe(dev, PTR_ERR(priv->gpio_fm_sel), "Failed to get FM selection GPIO\n");
priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel",
GPIOD_OUT_HIGH); if (IS_ERR(priv->gpio_lineout_sel)) return dev_err_probe(dev, PTR_ERR(priv->gpio_lineout_sel), "Failed to get line out selection GPIO\n");
priv->gpio_headset_detect = devm_gpiod_get_optional(dev, "headset-detect", GPIOD_IN); if (IS_ERR(priv->gpio_headset_detect)) return dev_err_probe(dev, PTR_ERR(priv->gpio_headset_detect), "Failed to get headset jack detect GPIO\n");
if (priv->gpio_headset_detect) {
priv->adc_headset_detect = devm_iio_channel_get(dev, "headset-detect"); if (IS_ERR(priv->adc_headset_detect)) return dev_err_probe(dev,
PTR_ERR(priv->adc_headset_detect), "Failed to get ADC channel\n");
ret = iio_get_channel_type(priv->adc_headset_detect,
&channel_type); if (ret) {
dev_err(dev, "Failed to get ADC channel type\n"); return ret;
}
if (channel_type != IIO_VOLTAGE) {
dev_err(dev, "ADC channel is not voltage\n"); return -EINVAL;
}
priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key",
GPIOD_IN); if (IS_ERR(priv->gpio_headset_key)) return dev_err_probe(dev,
PTR_ERR(priv->gpio_headset_key), "Failed to get headset key GPIO\n");
ret = of_property_read_u32_array(dev->of_node, "samsung,headset-4pole-threshold-microvolt",
fourpole_threshold,
ARRAY_SIZE(fourpole_threshold)); if (ret) {
dev_err(dev, "Failed to get 4-pole jack detection threshold\n"); return ret;
}
if (fourpole_threshold[0] > fourpole_threshold[1]) {
dev_err(dev, "Invalid 4-pole jack detection threshold value\n"); return -EINVAL;
}
ret = of_property_read_u32_array(dev->of_node, "samsung,headset-button-threshold-microvolt",
button_threshold,
ARRAY_SIZE(button_threshold)); if (ret) {
dev_err(dev, "Failed to get headset button detection threshold\n"); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.