18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/sound/soc/pxa/palm27x.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * SoC Audio driver for Palm T|X, T5 and LifeDrive
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * based on tosa.c
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/gpio.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <sound/core.h>
188c2ecf20Sopenharmony_ci#include <sound/pcm.h>
198c2ecf20Sopenharmony_ci#include <sound/soc.h>
208c2ecf20Sopenharmony_ci#include <sound/jack.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
238c2ecf20Sopenharmony_ci#include <mach/audio.h>
248c2ecf20Sopenharmony_ci#include <linux/platform_data/asoc-palm27x.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic struct snd_soc_jack hs_jack;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Headphones jack detection DAPM pins */
298c2ecf20Sopenharmony_cistatic struct snd_soc_jack_pin hs_jack_pins[] = {
308c2ecf20Sopenharmony_ci	{
318c2ecf20Sopenharmony_ci		.pin    = "Headphone Jack",
328c2ecf20Sopenharmony_ci		.mask   = SND_JACK_HEADPHONE,
338c2ecf20Sopenharmony_ci	},
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* Headphones jack detection gpios */
378c2ecf20Sopenharmony_cistatic struct snd_soc_jack_gpio hs_jack_gpios[] = {
388c2ecf20Sopenharmony_ci	[0] = {
398c2ecf20Sopenharmony_ci		/* gpio is set on per-platform basis */
408c2ecf20Sopenharmony_ci		.name           = "hp-gpio",
418c2ecf20Sopenharmony_ci		.report         = SND_JACK_HEADPHONE,
428c2ecf20Sopenharmony_ci		.debounce_time	= 200,
438c2ecf20Sopenharmony_ci	},
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* Palm27x machine dapm widgets */
478c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = {
488c2ecf20Sopenharmony_ci	SND_SOC_DAPM_HP("Headphone Jack", NULL),
498c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SPK("Ext. Speaker", NULL),
508c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MIC("Ext. Microphone", NULL),
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* PalmTX audio map */
548c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = {
558c2ecf20Sopenharmony_ci	/* headphone connected to HPOUTL, HPOUTR */
568c2ecf20Sopenharmony_ci	{"Headphone Jack", NULL, "HPOUTL"},
578c2ecf20Sopenharmony_ci	{"Headphone Jack", NULL, "HPOUTR"},
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* ext speaker connected to ROUT2, LOUT2 */
608c2ecf20Sopenharmony_ci	{"Ext. Speaker", NULL, "LOUT2"},
618c2ecf20Sopenharmony_ci	{"Ext. Speaker", NULL, "ROUT2"},
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* mic connected to MIC1 */
648c2ecf20Sopenharmony_ci	{"MIC1", NULL, "Ext. Microphone"},
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic struct snd_soc_card palm27x_asoc;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int err;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* Jack detection API stuff */
748c2ecf20Sopenharmony_ci	err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
758c2ecf20Sopenharmony_ci				    SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins,
768c2ecf20Sopenharmony_ci				    ARRAY_SIZE(hs_jack_pins));
778c2ecf20Sopenharmony_ci	if (err)
788c2ecf20Sopenharmony_ci		return err;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
818c2ecf20Sopenharmony_ci				hs_jack_gpios);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return err;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(hifi,
878c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
888c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
898c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(aux,
928c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
938c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-aux")),
948c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link palm27x_dai[] = {
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	.name = "AC97 HiFi",
998c2ecf20Sopenharmony_ci	.stream_name = "AC97 HiFi",
1008c2ecf20Sopenharmony_ci	.init = palm27x_ac97_init,
1018c2ecf20Sopenharmony_ci	SND_SOC_DAILINK_REG(hifi),
1028c2ecf20Sopenharmony_ci},
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	.name = "AC97 Aux",
1058c2ecf20Sopenharmony_ci	.stream_name = "AC97 Aux",
1068c2ecf20Sopenharmony_ci	SND_SOC_DAILINK_REG(aux),
1078c2ecf20Sopenharmony_ci},
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic struct snd_soc_card palm27x_asoc = {
1118c2ecf20Sopenharmony_ci	.name = "Palm/PXA27x",
1128c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
1138c2ecf20Sopenharmony_ci	.dai_link = palm27x_dai,
1148c2ecf20Sopenharmony_ci	.num_links = ARRAY_SIZE(palm27x_dai),
1158c2ecf20Sopenharmony_ci	.dapm_widgets = palm27x_dapm_widgets,
1168c2ecf20Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets),
1178c2ecf20Sopenharmony_ci	.dapm_routes = audio_map,
1188c2ecf20Sopenharmony_ci	.num_dapm_routes = ARRAY_SIZE(audio_map),
1198c2ecf20Sopenharmony_ci	.fully_routed = true,
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int palm27x_asoc_probe(struct platform_device *pdev)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	int ret;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (!(machine_is_palmtx() || machine_is_palmt5() ||
1278c2ecf20Sopenharmony_ci		machine_is_palmld() || machine_is_palmte2()))
1288c2ecf20Sopenharmony_ci		return -ENODEV;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!pdev->dev.platform_data) {
1318c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "please supply platform_data\n");
1328c2ecf20Sopenharmony_ci		return -ENODEV;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *)
1368c2ecf20Sopenharmony_ci			(pdev->dev.platform_data))->jack_gpio;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	palm27x_asoc.dev = &pdev->dev;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_card(&pdev->dev, &palm27x_asoc);
1418c2ecf20Sopenharmony_ci	if (ret)
1428c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
1438c2ecf20Sopenharmony_ci			ret);
1448c2ecf20Sopenharmony_ci	return ret;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic struct platform_driver palm27x_wm9712_driver = {
1488c2ecf20Sopenharmony_ci	.probe		= palm27x_asoc_probe,
1498c2ecf20Sopenharmony_ci	.driver		= {
1508c2ecf20Sopenharmony_ci		.name		= "palm27x-asoc",
1518c2ecf20Sopenharmony_ci		.pm     = &snd_soc_pm_ops,
1528c2ecf20Sopenharmony_ci	},
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cimodule_platform_driver(palm27x_wm9712_driver);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/* Module information */
1588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
1598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive");
1608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1618c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:palm27x-asoc");
162