tegra_asoc_machine.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * tegra_asoc_machine.c - Universal ASoC machine driver for NVIDIA Tegra boards.
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/export.h>
  7. #include <linux/gpio/consumer.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/of_device.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/slab.h>
  13. #include <sound/core.h>
  14. #include <sound/jack.h>
  15. #include <sound/pcm.h>
  16. #include <sound/pcm_params.h>
  17. #include <sound/soc.h>
  18. #include "tegra_asoc_machine.h"
  19. /* Headphones Jack */
  20. static struct snd_soc_jack tegra_machine_hp_jack;
  21. static struct snd_soc_jack_pin tegra_machine_hp_jack_pins[] = {
  22. { .pin = "Headphone", .mask = SND_JACK_HEADPHONE },
  23. { .pin = "Headphones", .mask = SND_JACK_HEADPHONE },
  24. };
  25. static struct snd_soc_jack_gpio tegra_machine_hp_jack_gpio = {
  26. .name = "Headphones detection",
  27. .report = SND_JACK_HEADPHONE,
  28. .debounce_time = 150,
  29. };
  30. /* Headset Jack */
  31. static struct snd_soc_jack tegra_machine_headset_jack;
  32. static struct snd_soc_jack_pin tegra_machine_headset_jack_pins[] = {
  33. { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE },
  34. { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE },
  35. };
  36. static struct snd_soc_jack_gpio tegra_machine_headset_jack_gpio = {
  37. .name = "Headset detection",
  38. .report = SND_JACK_HEADSET,
  39. .debounce_time = 150,
  40. };
  41. /* Mic Jack */
  42. static struct snd_soc_jack tegra_machine_mic_jack;
  43. static struct snd_soc_jack_pin tegra_machine_mic_jack_pins[] = {
  44. { .pin = "Mic Jack", .mask = SND_JACK_MICROPHONE },
  45. { .pin = "Headset Mic", .mask = SND_JACK_MICROPHONE },
  46. };
  47. static struct snd_soc_jack_gpio tegra_machine_mic_jack_gpio = {
  48. .name = "Mic detection",
  49. .report = SND_JACK_MICROPHONE,
  50. .debounce_time = 150,
  51. };
  52. static int tegra_machine_event(struct snd_soc_dapm_widget *w,
  53. struct snd_kcontrol *k, int event)
  54. {
  55. struct snd_soc_dapm_context *dapm = w->dapm;
  56. struct tegra_machine *machine = snd_soc_card_get_drvdata(dapm->card);
  57. if (!strcmp(w->name, "Int Spk") || !strcmp(w->name, "Speakers"))
  58. gpiod_set_value_cansleep(machine->gpiod_spkr_en,
  59. SND_SOC_DAPM_EVENT_ON(event));
  60. if (!strcmp(w->name, "Mic Jack"))
  61. gpiod_set_value_cansleep(machine->gpiod_ext_mic_en,
  62. SND_SOC_DAPM_EVENT_ON(event));
  63. if (!strcmp(w->name, "Int Mic"))
  64. gpiod_set_value_cansleep(machine->gpiod_int_mic_en,
  65. SND_SOC_DAPM_EVENT_ON(event));
  66. if (!strcmp(w->name, "Headphone") || !strcmp(w->name, "Headphone Jack"))
  67. gpiod_set_value_cansleep(machine->gpiod_hp_mute,
  68. !SND_SOC_DAPM_EVENT_ON(event));
  69. return 0;
  70. }
  71. static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = {
  72. SND_SOC_DAPM_HP("Headphone Jack", tegra_machine_event),
  73. SND_SOC_DAPM_HP("Headphone", tegra_machine_event),
  74. SND_SOC_DAPM_HP("Headset Stereophone", NULL),
  75. SND_SOC_DAPM_HP("Headphones", NULL),
  76. SND_SOC_DAPM_SPK("Speakers", tegra_machine_event),
  77. SND_SOC_DAPM_SPK("Int Spk", tegra_machine_event),
  78. SND_SOC_DAPM_MIC("Int Mic", tegra_machine_event),
  79. SND_SOC_DAPM_MIC("Mic Jack", tegra_machine_event),
  80. SND_SOC_DAPM_MIC("Internal Mic 1", NULL),
  81. SND_SOC_DAPM_MIC("Internal Mic 2", NULL),
  82. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  83. SND_SOC_DAPM_MIC("Digital Mic", NULL),
  84. SND_SOC_DAPM_MIC("Mic", NULL),
  85. SND_SOC_DAPM_LINE("Line In Jack", NULL),
  86. SND_SOC_DAPM_LINE("Line In", NULL),
  87. SND_SOC_DAPM_LINE("LineIn", NULL),
  88. };
  89. static const struct snd_kcontrol_new tegra_machine_controls[] = {
  90. SOC_DAPM_PIN_SWITCH("Speakers"),
  91. SOC_DAPM_PIN_SWITCH("Int Spk"),
  92. SOC_DAPM_PIN_SWITCH("Int Mic"),
  93. SOC_DAPM_PIN_SWITCH("Headset Mic"),
  94. SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
  95. SOC_DAPM_PIN_SWITCH("Internal Mic 2"),
  96. SOC_DAPM_PIN_SWITCH("Headphones"),
  97. SOC_DAPM_PIN_SWITCH("Mic Jack"),
  98. };
  99. int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
  100. {
  101. struct snd_soc_card *card = rtd->card;
  102. struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
  103. const char *jack_name;
  104. int err;
  105. if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) {
  106. if (machine->asoc->hp_jack_name)
  107. jack_name = machine->asoc->hp_jack_name;
  108. else
  109. jack_name = "Headphones Jack";
  110. err = snd_soc_card_jack_new_pins(card, jack_name,
  111. SND_JACK_HEADPHONE,
  112. &tegra_machine_hp_jack,
  113. tegra_machine_hp_jack_pins,
  114. ARRAY_SIZE(tegra_machine_hp_jack_pins));
  115. if (err) {
  116. dev_err(rtd->dev,
  117. "Headphones Jack creation failed: %d\n", err);
  118. return err;
  119. }
  120. tegra_machine_hp_jack_gpio.desc = machine->gpiod_hp_det;
  121. err = snd_soc_jack_add_gpios(&tegra_machine_hp_jack, 1,
  122. &tegra_machine_hp_jack_gpio);
  123. if (err)
  124. dev_err(rtd->dev, "HP GPIOs not added: %d\n", err);
  125. }
  126. if (machine->gpiod_hp_det && machine->asoc->add_headset_jack) {
  127. err = snd_soc_card_jack_new_pins(card, "Headset Jack",
  128. SND_JACK_HEADSET,
  129. &tegra_machine_headset_jack,
  130. tegra_machine_headset_jack_pins,
  131. ARRAY_SIZE(tegra_machine_headset_jack_pins));
  132. if (err) {
  133. dev_err(rtd->dev,
  134. "Headset Jack creation failed: %d\n", err);
  135. return err;
  136. }
  137. tegra_machine_headset_jack_gpio.desc = machine->gpiod_hp_det;
  138. err = snd_soc_jack_add_gpios(&tegra_machine_headset_jack, 1,
  139. &tegra_machine_headset_jack_gpio);
  140. if (err)
  141. dev_err(rtd->dev, "Headset GPIOs not added: %d\n", err);
  142. }
  143. if (machine->gpiod_mic_det && machine->asoc->add_mic_jack) {
  144. err = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack",
  145. SND_JACK_MICROPHONE,
  146. &tegra_machine_mic_jack,
  147. tegra_machine_mic_jack_pins,
  148. ARRAY_SIZE(tegra_machine_mic_jack_pins));
  149. if (err) {
  150. dev_err(rtd->dev, "Mic Jack creation failed: %d\n", err);
  151. return err;
  152. }
  153. tegra_machine_mic_jack_gpio.desc = machine->gpiod_mic_det;
  154. err = snd_soc_jack_add_gpios(&tegra_machine_mic_jack, 1,
  155. &tegra_machine_mic_jack_gpio);
  156. if (err)
  157. dev_err(rtd->dev, "Mic GPIOs not added: %d\n", err);
  158. }
  159. return 0;
  160. }
  161. EXPORT_SYMBOL_GPL(tegra_asoc_machine_init);
  162. static unsigned int tegra_machine_mclk_rate_128(unsigned int srate)
  163. {
  164. return 128 * srate;
  165. }
  166. static unsigned int tegra_machine_mclk_rate_256(unsigned int srate)
  167. {
  168. return 256 * srate;
  169. }
  170. static unsigned int tegra_machine_mclk_rate_512(unsigned int srate)
  171. {
  172. return 512 * srate;
  173. }
  174. static unsigned int tegra_machine_mclk_rate_12mhz(unsigned int srate)
  175. {
  176. unsigned int mclk;
  177. switch (srate) {
  178. case 8000:
  179. case 16000:
  180. case 24000:
  181. case 32000:
  182. case 48000:
  183. case 64000:
  184. case 96000:
  185. mclk = 12288000;
  186. break;
  187. case 11025:
  188. case 22050:
  189. case 44100:
  190. case 88200:
  191. mclk = 11289600;
  192. break;
  193. default:
  194. mclk = 12000000;
  195. break;
  196. }
  197. return mclk;
  198. }
  199. static int tegra_machine_hw_params(struct snd_pcm_substream *substream,
  200. struct snd_pcm_hw_params *params)
  201. {
  202. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  203. struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
  204. struct snd_soc_card *card = rtd->card;
  205. struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
  206. unsigned int srate = params_rate(params);
  207. unsigned int mclk = machine->asoc->mclk_rate(srate);
  208. unsigned int clk_id = machine->asoc->mclk_id;
  209. unsigned int new_baseclock;
  210. int err;
  211. switch (srate) {
  212. case 11025:
  213. case 22050:
  214. case 44100:
  215. case 88200:
  216. if (of_machine_is_compatible("nvidia,tegra20"))
  217. new_baseclock = 56448000;
  218. else if (of_machine_is_compatible("nvidia,tegra30"))
  219. new_baseclock = 564480000;
  220. else
  221. new_baseclock = 282240000;
  222. break;
  223. case 8000:
  224. case 16000:
  225. case 32000:
  226. case 48000:
  227. case 64000:
  228. case 96000:
  229. if (of_machine_is_compatible("nvidia,tegra20"))
  230. new_baseclock = 73728000;
  231. else if (of_machine_is_compatible("nvidia,tegra30"))
  232. new_baseclock = 552960000;
  233. else
  234. new_baseclock = 368640000;
  235. break;
  236. default:
  237. dev_err(card->dev, "Invalid sound rate: %u\n", srate);
  238. return -EINVAL;
  239. }
  240. if (new_baseclock != machine->set_baseclock ||
  241. mclk != machine->set_mclk) {
  242. machine->set_baseclock = 0;
  243. machine->set_mclk = 0;
  244. clk_disable_unprepare(machine->clk_cdev1);
  245. err = clk_set_rate(machine->clk_pll_a, new_baseclock);
  246. if (err) {
  247. dev_err(card->dev, "Can't set pll_a rate: %d\n", err);
  248. return err;
  249. }
  250. err = clk_set_rate(machine->clk_pll_a_out0, mclk);
  251. if (err) {
  252. dev_err(card->dev, "Can't set pll_a_out0 rate: %d\n", err);
  253. return err;
  254. }
  255. /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
  256. err = clk_prepare_enable(machine->clk_cdev1);
  257. if (err) {
  258. dev_err(card->dev, "Can't enable cdev1: %d\n", err);
  259. return err;
  260. }
  261. machine->set_baseclock = new_baseclock;
  262. machine->set_mclk = mclk;
  263. }
  264. err = snd_soc_dai_set_sysclk(codec_dai, clk_id, mclk, SND_SOC_CLOCK_IN);
  265. if (err < 0) {
  266. dev_err(card->dev, "codec_dai clock not set: %d\n", err);
  267. return err;
  268. }
  269. return 0;
  270. }
  271. static const struct snd_soc_ops tegra_machine_snd_ops = {
  272. .hw_params = tegra_machine_hw_params,
  273. };
  274. static void tegra_machine_node_release(void *of_node)
  275. {
  276. of_node_put(of_node);
  277. }
  278. static struct device_node *
  279. tegra_machine_parse_phandle(struct device *dev, const char *name)
  280. {
  281. struct device_node *np;
  282. int err;
  283. np = of_parse_phandle(dev->of_node, name, 0);
  284. if (!np) {
  285. dev_err(dev, "Property '%s' missing or invalid\n", name);
  286. return ERR_PTR(-EINVAL);
  287. }
  288. err = devm_add_action_or_reset(dev, tegra_machine_node_release, np);
  289. if (err)
  290. return ERR_PTR(err);
  291. return np;
  292. }
  293. static void tegra_machine_unregister_codec(void *pdev)
  294. {
  295. platform_device_unregister(pdev);
  296. }
  297. static int tegra_machine_register_codec(struct device *dev, const char *name)
  298. {
  299. struct platform_device *pdev;
  300. int err;
  301. if (!name)
  302. return 0;
  303. pdev = platform_device_register_simple(name, -1, NULL, 0);
  304. if (IS_ERR(pdev))
  305. return PTR_ERR(pdev);
  306. err = devm_add_action_or_reset(dev, tegra_machine_unregister_codec,
  307. pdev);
  308. if (err)
  309. return err;
  310. return 0;
  311. }
  312. int tegra_asoc_machine_probe(struct platform_device *pdev)
  313. {
  314. struct device_node *np_codec, *np_i2s, *np_ac97;
  315. const struct tegra_asoc_data *asoc;
  316. struct device *dev = &pdev->dev;
  317. struct tegra_machine *machine;
  318. struct snd_soc_card *card;
  319. struct gpio_desc *gpiod;
  320. int err;
  321. machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL);
  322. if (!machine)
  323. return -ENOMEM;
  324. asoc = of_device_get_match_data(dev);
  325. card = asoc->card;
  326. card->dev = dev;
  327. machine->asoc = asoc;
  328. machine->mic_jack = &tegra_machine_mic_jack;
  329. machine->hp_jack_gpio = &tegra_machine_hp_jack_gpio;
  330. snd_soc_card_set_drvdata(card, machine);
  331. gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-mute", GPIOD_OUT_HIGH);
  332. machine->gpiod_hp_mute = gpiod;
  333. if (IS_ERR(gpiod))
  334. return PTR_ERR(gpiod);
  335. gpiod = devm_gpiod_get_optional(dev, "nvidia,hp-det", GPIOD_IN);
  336. machine->gpiod_hp_det = gpiod;
  337. if (IS_ERR(gpiod))
  338. return PTR_ERR(gpiod);
  339. gpiod = devm_gpiod_get_optional(dev, "nvidia,mic-det", GPIOD_IN);
  340. machine->gpiod_mic_det = gpiod;
  341. if (IS_ERR(gpiod))
  342. return PTR_ERR(gpiod);
  343. gpiod = devm_gpiod_get_optional(dev, "nvidia,spkr-en", GPIOD_OUT_LOW);
  344. machine->gpiod_spkr_en = gpiod;
  345. if (IS_ERR(gpiod))
  346. return PTR_ERR(gpiod);
  347. gpiod = devm_gpiod_get_optional(dev, "nvidia,int-mic-en", GPIOD_OUT_LOW);
  348. machine->gpiod_int_mic_en = gpiod;
  349. if (IS_ERR(gpiod))
  350. return PTR_ERR(gpiod);
  351. gpiod = devm_gpiod_get_optional(dev, "nvidia,ext-mic-en", GPIOD_OUT_LOW);
  352. machine->gpiod_ext_mic_en = gpiod;
  353. if (IS_ERR(gpiod))
  354. return PTR_ERR(gpiod);
  355. err = snd_soc_of_parse_card_name(card, "nvidia,model");
  356. if (err)
  357. return err;
  358. if (!card->dapm_routes) {
  359. err = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
  360. if (err)
  361. return err;
  362. }
  363. if (asoc->set_ac97) {
  364. err = tegra_machine_register_codec(dev, asoc->codec_dev_name);
  365. if (err)
  366. return err;
  367. np_ac97 = tegra_machine_parse_phandle(dev, "nvidia,ac97-controller");
  368. if (IS_ERR(np_ac97))
  369. return PTR_ERR(np_ac97);
  370. card->dai_link->cpus->of_node = np_ac97;
  371. card->dai_link->platforms->of_node = np_ac97;
  372. } else {
  373. np_codec = tegra_machine_parse_phandle(dev, "nvidia,audio-codec");
  374. if (IS_ERR(np_codec))
  375. return PTR_ERR(np_codec);
  376. np_i2s = tegra_machine_parse_phandle(dev, "nvidia,i2s-controller");
  377. if (IS_ERR(np_i2s))
  378. return PTR_ERR(np_i2s);
  379. card->dai_link->cpus->of_node = np_i2s;
  380. card->dai_link->codecs->of_node = np_codec;
  381. card->dai_link->platforms->of_node = np_i2s;
  382. }
  383. if (asoc->add_common_controls) {
  384. card->controls = tegra_machine_controls;
  385. card->num_controls = ARRAY_SIZE(tegra_machine_controls);
  386. }
  387. if (asoc->add_common_dapm_widgets) {
  388. card->dapm_widgets = tegra_machine_dapm_widgets;
  389. card->num_dapm_widgets = ARRAY_SIZE(tegra_machine_dapm_widgets);
  390. }
  391. if (asoc->add_common_snd_ops)
  392. card->dai_link->ops = &tegra_machine_snd_ops;
  393. if (!card->owner)
  394. card->owner = THIS_MODULE;
  395. if (!card->driver_name)
  396. card->driver_name = "tegra";
  397. machine->clk_pll_a = devm_clk_get(dev, "pll_a");
  398. if (IS_ERR(machine->clk_pll_a)) {
  399. dev_err(dev, "Can't retrieve clk pll_a\n");
  400. return PTR_ERR(machine->clk_pll_a);
  401. }
  402. machine->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0");
  403. if (IS_ERR(machine->clk_pll_a_out0)) {
  404. dev_err(dev, "Can't retrieve clk pll_a_out0\n");
  405. return PTR_ERR(machine->clk_pll_a_out0);
  406. }
  407. machine->clk_cdev1 = devm_clk_get(dev, "mclk");
  408. if (IS_ERR(machine->clk_cdev1)) {
  409. dev_err(dev, "Can't retrieve clk cdev1\n");
  410. return PTR_ERR(machine->clk_cdev1);
  411. }
  412. /*
  413. * If clock parents are not set in DT, configure here to use clk_out_1
  414. * as mclk and extern1 as parent for Tegra30 and higher.
  415. */
  416. if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) &&
  417. !of_machine_is_compatible("nvidia,tegra20")) {
  418. struct clk *clk_out_1, *clk_extern1;
  419. dev_warn(dev, "Configuring clocks for a legacy device-tree\n");
  420. dev_warn(dev, "Please update DT to use assigned-clock-parents\n");
  421. clk_extern1 = devm_clk_get(dev, "extern1");
  422. if (IS_ERR(clk_extern1)) {
  423. dev_err(dev, "Can't retrieve clk extern1\n");
  424. return PTR_ERR(clk_extern1);
  425. }
  426. err = clk_set_parent(clk_extern1, machine->clk_pll_a_out0);
  427. if (err < 0) {
  428. dev_err(dev, "Set parent failed for clk extern1\n");
  429. return err;
  430. }
  431. clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1");
  432. if (IS_ERR(clk_out_1)) {
  433. dev_err(dev, "Can't retrieve pmc_clk_out_1\n");
  434. return PTR_ERR(clk_out_1);
  435. }
  436. err = clk_set_parent(clk_out_1, clk_extern1);
  437. if (err < 0) {
  438. dev_err(dev, "Set parent failed for pmc_clk_out_1\n");
  439. return err;
  440. }
  441. machine->clk_cdev1 = clk_out_1;
  442. }
  443. if (asoc->set_ac97) {
  444. /*
  445. * AC97 rate is fixed at 24.576MHz and is used for both the
  446. * host controller and the external codec
  447. */
  448. err = clk_set_rate(machine->clk_pll_a, 73728000);
  449. if (err) {
  450. dev_err(dev, "Can't set pll_a rate: %d\n", err);
  451. return err;
  452. }
  453. err = clk_set_rate(machine->clk_pll_a_out0, 24576000);
  454. if (err) {
  455. dev_err(dev, "Can't set pll_a_out0 rate: %d\n", err);
  456. return err;
  457. }
  458. machine->set_baseclock = 73728000;
  459. machine->set_mclk = 24576000;
  460. }
  461. /*
  462. * FIXME: There is some unknown dependency between audio MCLK disable
  463. * and suspend-resume functionality on Tegra30, although audio MCLK is
  464. * only needed for audio.
  465. */
  466. err = clk_prepare_enable(machine->clk_cdev1);
  467. if (err) {
  468. dev_err(dev, "Can't enable cdev1: %d\n", err);
  469. return err;
  470. }
  471. err = devm_snd_soc_register_card(dev, card);
  472. if (err)
  473. return err;
  474. return 0;
  475. }
  476. EXPORT_SYMBOL_GPL(tegra_asoc_machine_probe);
  477. /* WM8753 machine */
  478. SND_SOC_DAILINK_DEFS(wm8753_hifi,
  479. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  480. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8753-hifi")),
  481. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  482. static struct snd_soc_dai_link tegra_wm8753_dai = {
  483. .name = "WM8753",
  484. .stream_name = "WM8753 PCM",
  485. .dai_fmt = SND_SOC_DAIFMT_I2S |
  486. SND_SOC_DAIFMT_NB_NF |
  487. SND_SOC_DAIFMT_CBS_CFS,
  488. SND_SOC_DAILINK_REG(wm8753_hifi),
  489. };
  490. static struct snd_soc_card snd_soc_tegra_wm8753 = {
  491. .components = "codec:wm8753",
  492. .dai_link = &tegra_wm8753_dai,
  493. .num_links = 1,
  494. .fully_routed = true,
  495. };
  496. static const struct tegra_asoc_data tegra_wm8753_data = {
  497. .mclk_rate = tegra_machine_mclk_rate_12mhz,
  498. .card = &snd_soc_tegra_wm8753,
  499. .add_common_dapm_widgets = true,
  500. .add_common_snd_ops = true,
  501. };
  502. /* WM9712 machine */
  503. static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
  504. {
  505. return snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
  506. }
  507. SND_SOC_DAILINK_DEFS(wm9712_hifi,
  508. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  509. DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
  510. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  511. static struct snd_soc_dai_link tegra_wm9712_dai = {
  512. .name = "AC97 HiFi",
  513. .stream_name = "AC97 HiFi",
  514. .init = tegra_wm9712_init,
  515. SND_SOC_DAILINK_REG(wm9712_hifi),
  516. };
  517. static struct snd_soc_card snd_soc_tegra_wm9712 = {
  518. .components = "codec:wm9712",
  519. .dai_link = &tegra_wm9712_dai,
  520. .num_links = 1,
  521. .fully_routed = true,
  522. };
  523. static const struct tegra_asoc_data tegra_wm9712_data = {
  524. .card = &snd_soc_tegra_wm9712,
  525. .add_common_dapm_widgets = true,
  526. .codec_dev_name = "wm9712-codec",
  527. .set_ac97 = true,
  528. };
  529. /* MAX98090 machine */
  530. SND_SOC_DAILINK_DEFS(max98090_hifi,
  531. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  532. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
  533. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  534. static struct snd_soc_dai_link tegra_max98090_dai = {
  535. .name = "max98090",
  536. .stream_name = "max98090 PCM",
  537. .init = tegra_asoc_machine_init,
  538. .dai_fmt = SND_SOC_DAIFMT_I2S |
  539. SND_SOC_DAIFMT_NB_NF |
  540. SND_SOC_DAIFMT_CBS_CFS,
  541. SND_SOC_DAILINK_REG(max98090_hifi),
  542. };
  543. static struct snd_soc_card snd_soc_tegra_max98090 = {
  544. .components = "codec:max98090",
  545. .dai_link = &tegra_max98090_dai,
  546. .num_links = 1,
  547. .fully_routed = true,
  548. };
  549. static const struct tegra_asoc_data tegra_max98090_data = {
  550. .mclk_rate = tegra_machine_mclk_rate_12mhz,
  551. .card = &snd_soc_tegra_max98090,
  552. .hp_jack_name = "Headphones",
  553. .add_common_dapm_widgets = true,
  554. .add_common_controls = true,
  555. .add_common_snd_ops = true,
  556. .add_mic_jack = true,
  557. .add_hp_jack = true,
  558. };
  559. /* SGTL5000 machine */
  560. SND_SOC_DAILINK_DEFS(sgtl5000_hifi,
  561. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  562. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "sgtl5000")),
  563. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  564. static struct snd_soc_dai_link tegra_sgtl5000_dai = {
  565. .name = "sgtl5000",
  566. .stream_name = "HiFi",
  567. .dai_fmt = SND_SOC_DAIFMT_I2S |
  568. SND_SOC_DAIFMT_NB_NF |
  569. SND_SOC_DAIFMT_CBS_CFS,
  570. SND_SOC_DAILINK_REG(sgtl5000_hifi),
  571. };
  572. static struct snd_soc_card snd_soc_tegra_sgtl5000 = {
  573. .components = "codec:sgtl5000",
  574. .dai_link = &tegra_sgtl5000_dai,
  575. .num_links = 1,
  576. .fully_routed = true,
  577. };
  578. static const struct tegra_asoc_data tegra_sgtl5000_data = {
  579. .mclk_rate = tegra_machine_mclk_rate_12mhz,
  580. .card = &snd_soc_tegra_sgtl5000,
  581. .add_common_dapm_widgets = true,
  582. .add_common_snd_ops = true,
  583. };
  584. /* TLV320AIC23 machine */
  585. static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = {
  586. SND_SOC_DAPM_HP("Line Out", NULL),
  587. SND_SOC_DAPM_LINE("Line In", NULL),
  588. };
  589. static const struct snd_soc_dapm_route trimslice_audio_map[] = {
  590. {"Line Out", NULL, "LOUT"},
  591. {"Line Out", NULL, "ROUT"},
  592. {"LLINEIN", NULL, "Line In"},
  593. {"RLINEIN", NULL, "Line In"},
  594. };
  595. SND_SOC_DAILINK_DEFS(tlv320aic23_hifi,
  596. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  597. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic23-hifi")),
  598. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  599. static struct snd_soc_dai_link tegra_tlv320aic23_dai = {
  600. .name = "TLV320AIC23",
  601. .stream_name = "AIC23",
  602. .dai_fmt = SND_SOC_DAIFMT_I2S |
  603. SND_SOC_DAIFMT_NB_NF |
  604. SND_SOC_DAIFMT_CBS_CFS,
  605. SND_SOC_DAILINK_REG(tlv320aic23_hifi),
  606. };
  607. static struct snd_soc_card snd_soc_tegra_trimslice = {
  608. .name = "tegra-trimslice",
  609. .components = "codec:tlv320aic23",
  610. .dai_link = &tegra_tlv320aic23_dai,
  611. .num_links = 1,
  612. .dapm_widgets = trimslice_dapm_widgets,
  613. .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets),
  614. .dapm_routes = trimslice_audio_map,
  615. .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map),
  616. .fully_routed = true,
  617. };
  618. static const struct tegra_asoc_data tegra_trimslice_data = {
  619. .mclk_rate = tegra_machine_mclk_rate_128,
  620. .card = &snd_soc_tegra_trimslice,
  621. .add_common_snd_ops = true,
  622. };
  623. /* RT5677 machine */
  624. static int tegra_rt5677_init(struct snd_soc_pcm_runtime *rtd)
  625. {
  626. struct snd_soc_card *card = rtd->card;
  627. int err;
  628. err = tegra_asoc_machine_init(rtd);
  629. if (err)
  630. return err;
  631. snd_soc_dapm_force_enable_pin(&card->dapm, "MICBIAS1");
  632. return 0;
  633. }
  634. SND_SOC_DAILINK_DEFS(rt5677_aif1,
  635. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  636. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif1")),
  637. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  638. static struct snd_soc_dai_link tegra_rt5677_dai = {
  639. .name = "RT5677",
  640. .stream_name = "RT5677 PCM",
  641. .init = tegra_rt5677_init,
  642. .dai_fmt = SND_SOC_DAIFMT_I2S |
  643. SND_SOC_DAIFMT_NB_NF |
  644. SND_SOC_DAIFMT_CBS_CFS,
  645. SND_SOC_DAILINK_REG(rt5677_aif1),
  646. };
  647. static struct snd_soc_card snd_soc_tegra_rt5677 = {
  648. .components = "codec:rt5677",
  649. .dai_link = &tegra_rt5677_dai,
  650. .num_links = 1,
  651. .fully_routed = true,
  652. };
  653. static const struct tegra_asoc_data tegra_rt5677_data = {
  654. .mclk_rate = tegra_machine_mclk_rate_256,
  655. .card = &snd_soc_tegra_rt5677,
  656. .add_common_dapm_widgets = true,
  657. .add_common_controls = true,
  658. .add_common_snd_ops = true,
  659. .add_mic_jack = true,
  660. .add_hp_jack = true,
  661. };
  662. /* RT5640 machine */
  663. SND_SOC_DAILINK_DEFS(rt5640_aif1,
  664. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  665. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5640-aif1")),
  666. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  667. static struct snd_soc_dai_link tegra_rt5640_dai = {
  668. .name = "RT5640",
  669. .stream_name = "RT5640 PCM",
  670. .init = tegra_asoc_machine_init,
  671. .dai_fmt = SND_SOC_DAIFMT_I2S |
  672. SND_SOC_DAIFMT_NB_NF |
  673. SND_SOC_DAIFMT_CBS_CFS,
  674. SND_SOC_DAILINK_REG(rt5640_aif1),
  675. };
  676. static struct snd_soc_card snd_soc_tegra_rt5640 = {
  677. .components = "codec:rt5640",
  678. .dai_link = &tegra_rt5640_dai,
  679. .num_links = 1,
  680. .fully_routed = true,
  681. };
  682. static const struct tegra_asoc_data tegra_rt5640_data = {
  683. .mclk_rate = tegra_machine_mclk_rate_256,
  684. .card = &snd_soc_tegra_rt5640,
  685. .add_common_dapm_widgets = true,
  686. .add_common_controls = true,
  687. .add_common_snd_ops = true,
  688. .add_hp_jack = true,
  689. };
  690. /* RT5632 machine */
  691. SND_SOC_DAILINK_DEFS(rt5632_hifi,
  692. DAILINK_COMP_ARRAY(COMP_EMPTY()),
  693. DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "alc5632-hifi")),
  694. DAILINK_COMP_ARRAY(COMP_EMPTY()));
  695. static struct snd_soc_dai_link tegra_rt5632_dai = {
  696. .name = "ALC5632",
  697. .stream_name = "ALC5632 PCM",
  698. .init = tegra_rt5677_init,
  699. .dai_fmt = SND_SOC_DAIFMT_I2S |
  700. SND_SOC_DAIFMT_NB_NF |
  701. SND_SOC_DAIFMT_CBS_CFS,
  702. SND_SOC_DAILINK_REG(rt5632_hifi),
  703. };
  704. static struct snd_soc_card snd_soc_tegra_rt5632 = {
  705. .components = "codec:rt5632",
  706. .dai_link = &tegra_rt5632_dai,
  707. .num_links = 1,
  708. .fully_routed = true,
  709. };
  710. static const struct tegra_asoc_data tegra_rt5632_data = {
  711. .mclk_rate = tegra_machine_mclk_rate_512,
  712. .card = &snd_soc_tegra_rt5632,
  713. .add_common_dapm_widgets = true,
  714. .add_common_controls = true,
  715. .add_common_snd_ops = true,
  716. .add_headset_jack = true,
  717. };
  718. static const struct of_device_id tegra_machine_of_match[] = {
  719. { .compatible = "nvidia,tegra-audio-trimslice", .data = &tegra_trimslice_data },
  720. { .compatible = "nvidia,tegra-audio-max98090", .data = &tegra_max98090_data },
  721. { .compatible = "nvidia,tegra-audio-sgtl5000", .data = &tegra_sgtl5000_data },
  722. { .compatible = "nvidia,tegra-audio-wm9712", .data = &tegra_wm9712_data },
  723. { .compatible = "nvidia,tegra-audio-wm8753", .data = &tegra_wm8753_data },
  724. { .compatible = "nvidia,tegra-audio-rt5677", .data = &tegra_rt5677_data },
  725. { .compatible = "nvidia,tegra-audio-rt5640", .data = &tegra_rt5640_data },
  726. { .compatible = "nvidia,tegra-audio-alc5632", .data = &tegra_rt5632_data },
  727. {},
  728. };
  729. MODULE_DEVICE_TABLE(of, tegra_machine_of_match);
  730. static struct platform_driver tegra_asoc_machine_driver = {
  731. .driver = {
  732. .name = "tegra-audio",
  733. .of_match_table = tegra_machine_of_match,
  734. .pm = &snd_soc_pm_ops,
  735. },
  736. .probe = tegra_asoc_machine_probe,
  737. };
  738. module_platform_driver(tegra_asoc_machine_driver);
  739. MODULE_AUTHOR("Anatol Pomozov <[email protected]>");
  740. MODULE_AUTHOR("Andrey Danin <[email protected]>");
  741. MODULE_AUTHOR("Dmitry Osipenko <[email protected]>");
  742. MODULE_AUTHOR("Ion Agorria <[email protected]>");
  743. MODULE_AUTHOR("Leon Romanovsky <[email protected]>");
  744. MODULE_AUTHOR("Lucas Stach <[email protected]>");
  745. MODULE_AUTHOR("Marc Dietrich <[email protected]>");
  746. MODULE_AUTHOR("Marcel Ziswiler <[email protected]>");
  747. MODULE_AUTHOR("Mike Rapoport <[email protected]>");
  748. MODULE_AUTHOR("Stephen Warren <[email protected]>");
  749. MODULE_AUTHOR("Svyatoslav Ryhel <[email protected]>");
  750. MODULE_DESCRIPTION("Tegra machine ASoC driver");
  751. MODULE_LICENSE("GPL");