diff options
Diffstat (limited to 'sound/soc/qcom/apq8016_sbc.c')
-rw-r--r-- | sound/soc/qcom/apq8016_sbc.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index d084d7468299..d49adc822a11 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -21,12 +21,16 @@ #include <linux/platform_device.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <sound/jack.h> #include <sound/soc.h> +#include <uapi/linux/input-event-codes.h> #include <dt-bindings/sound/apq8016-lpass.h> struct apq8016_sbc_data { void __iomem *mic_iomux; void __iomem *spkr_iomux; + struct snd_soc_jack jack; + bool jack_setup; struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ }; @@ -34,13 +38,16 @@ struct apq8016_sbc_data { #define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17) #define MIC_CTRL_TLMM_SCLK_EN BIT(1) #define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16)) +#define DEFAULT_MCLK_RATE 9600000 static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_codec *codec; + 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 rval = 0; + int i, rval; switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -63,12 +70,54 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) default: dev_err(card->dev, "unsupported cpu dai configuration\n"); - rval = -EINVAL; - break; + 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_MEDIA); + 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]; + + codec = dai->codec; + /* Set default mclk for internal codec */ + rval = snd_soc_codec_set_sysclk(codec, 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_codec_set_jack(codec, &pdata->jack, NULL); + if (rval != 0 && rval != -ENOTSUPP) { + dev_warn(card->dev, "Failed to set jack: %d\n", rval); + return rval; + } } - return rval; + return 0; } static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) @@ -191,7 +240,6 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) if (IS_ERR(data->spkr_iomux)) return PTR_ERR(data->spkr_iomux); - platform_set_drvdata(pdev, data); snd_soc_card_set_drvdata(card, data); return devm_snd_soc_register_card(&pdev->dev, card); |