msm8930.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426
  1. /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/clk.h>
  13. #include <linux/delay.h>
  14. #include <linux/gpio.h>
  15. #include <linux/mfd/pm8xxx/spk.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/gpio.h>
  18. #include <linux/slab.h>
  19. #include <sound/core.h>
  20. #include <sound/soc.h>
  21. #include <sound/soc-dapm.h>
  22. #include <sound/pcm.h>
  23. #include <sound/jack.h>
  24. #include <asm/mach-types.h>
  25. #include <mach/socinfo.h>
  26. #include "msm-pcm-routing.h"
  27. #include "../codecs/wcd9304.h"
  28. /* 8930 machine driver */
  29. #define MSM8930_SPK_ON 1
  30. #define MSM8930_SPK_OFF 0
  31. #define BTSCO_RATE_8KHZ 8000
  32. #define BTSCO_RATE_16KHZ 16000
  33. #define SPK_AMP_POS 0x1
  34. #define SPK_AMP_NEG 0x2
  35. #define SPKR_BOOST_GPIO 15
  36. #define LEFT_SPKR_AMPL_GPIO 15
  37. #define DEFAULT_PMIC_SPK_GAIN 0x0D
  38. #define SITAR_EXT_CLK_RATE 12288000
  39. #define SITAR_MBHC_DEF_BUTTONS 8
  40. #define SITAR_MBHC_DEF_RLOADS 5
  41. #define GPIO_AUX_PCM_DOUT 63
  42. #define GPIO_AUX_PCM_DIN 64
  43. #define GPIO_AUX_PCM_SYNC 65
  44. #define GPIO_AUX_PCM_CLK 66
  45. static int msm8930_spk_control;
  46. static int msm8930_slim_0_rx_ch = 1;
  47. static int msm8930_slim_0_tx_ch = 1;
  48. static int msm8930_pmic_spk_gain = DEFAULT_PMIC_SPK_GAIN;
  49. static int msm8930_ext_spk_pamp;
  50. static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
  51. static int msm8930_btsco_ch = 1;
  52. static int hdmi_rate_variable;
  53. static struct clk *codec_clk;
  54. static int clk_users;
  55. static int msm8930_headset_gpios_configured;
  56. static struct mutex cdc_mclk_mutex;
  57. static struct snd_soc_jack hs_jack;
  58. static struct snd_soc_jack button_jack;
  59. static atomic_t auxpcm_rsc_ref;
  60. static int msm8930_enable_codec_ext_clk(
  61. struct snd_soc_codec *codec, int enable,
  62. bool dapm);
  63. static struct sitar_mbhc_config mbhc_cfg = {
  64. .headset_jack = &hs_jack,
  65. .button_jack = &button_jack,
  66. .read_fw_bin = false,
  67. .calibration = NULL,
  68. .micbias = SITAR_MICBIAS2,
  69. .mclk_cb_fn = msm8930_enable_codec_ext_clk,
  70. .mclk_rate = SITAR_EXT_CLK_RATE,
  71. .gpio = 0,
  72. .gpio_irq = 0,
  73. .gpio_level_insert = 1,
  74. };
  75. static void msm8930_ext_control(struct snd_soc_codec *codec)
  76. {
  77. struct snd_soc_dapm_context *dapm = &codec->dapm;
  78. pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
  79. if (msm8930_spk_control == MSM8930_SPK_ON) {
  80. snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
  81. snd_soc_dapm_enable_pin(dapm, "Ext Spk left Neg");
  82. } else {
  83. snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
  84. snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Neg");
  85. }
  86. snd_soc_dapm_sync(dapm);
  87. }
  88. static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
  89. struct snd_ctl_elem_value *ucontrol)
  90. {
  91. pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
  92. ucontrol->value.integer.value[0] = msm8930_spk_control;
  93. return 0;
  94. }
  95. static int msm8930_set_spk(struct snd_kcontrol *kcontrol,
  96. struct snd_ctl_elem_value *ucontrol)
  97. {
  98. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  99. pr_debug("%s()\n", __func__);
  100. if (msm8930_spk_control == ucontrol->value.integer.value[0])
  101. return 0;
  102. msm8930_spk_control = ucontrol->value.integer.value[0];
  103. msm8930_ext_control(codec);
  104. return 1;
  105. }
  106. static int msm8930_cfg_spkr_gpio(int gpio,
  107. int enable, const char *gpio_label)
  108. {
  109. int ret = 0;
  110. pr_debug("%s: Configure %s GPIO %u",
  111. __func__, gpio_label, gpio);
  112. ret = gpio_request(gpio, gpio_label);
  113. if (ret)
  114. return ret;
  115. pr_debug("%s: Enable %s gpio %u\n",
  116. __func__, gpio_label, gpio);
  117. gpio_direction_output(gpio, enable);
  118. return ret;
  119. }
  120. static void msm8960_ext_spk_power_amp_on(u32 spk)
  121. {
  122. int ret = 0;
  123. if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
  124. if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
  125. (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
  126. pr_debug("%s() External Bottom Speaker Ampl already "
  127. "turned on. spk = 0x%08x\n", __func__, spk);
  128. return;
  129. }
  130. msm8930_ext_spk_pamp |= spk;
  131. if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
  132. (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
  133. if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
  134. ret = msm8930_cfg_spkr_gpio(
  135. LEFT_SPKR_AMPL_GPIO,
  136. 1, "LEFT_SPKR_AMPL");
  137. if (ret) {
  138. pr_err("%s: Failed to config ampl gpio %u\n",
  139. __func__, LEFT_SPKR_AMPL_GPIO);
  140. return;
  141. }
  142. } else {
  143. /*
  144. * 8930 CDP does not have a 5V speaker boost,
  145. * hence the GPIO enable for speaker boost is
  146. * only required for platforms other than CDP
  147. */
  148. if (!machine_is_msm8930_cdp()) {
  149. ret = msm8930_cfg_spkr_gpio(
  150. SPKR_BOOST_GPIO, 1, "SPKR_BOOST");
  151. if (ret) {
  152. pr_err("%s: Failure: spkr boost gpio %u\n",
  153. __func__, SPKR_BOOST_GPIO);
  154. return;
  155. }
  156. }
  157. pm8xxx_spk_enable(MSM8930_SPK_ON);
  158. }
  159. pr_debug("%s: sleeping 10 ms after turning on external "
  160. " Left Speaker Ampl\n", __func__);
  161. usleep_range(10000, 10000);
  162. }
  163. } else {
  164. pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
  165. __func__, spk);
  166. return;
  167. }
  168. }
  169. static void msm8960_ext_spk_power_amp_off(u32 spk)
  170. {
  171. if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
  172. if (!msm8930_ext_spk_pamp)
  173. return;
  174. if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
  175. gpio_free(LEFT_SPKR_AMPL_GPIO);
  176. msm8930_ext_spk_pamp = 0;
  177. return;
  178. }
  179. if (!machine_is_msm8930_cdp()) {
  180. pr_debug("%s: Free speaker boost gpio %u\n",
  181. __func__, SPKR_BOOST_GPIO);
  182. gpio_direction_output(SPKR_BOOST_GPIO, 0);
  183. gpio_free(SPKR_BOOST_GPIO);
  184. }
  185. pm8xxx_spk_enable(MSM8930_SPK_OFF);
  186. msm8930_ext_spk_pamp = 0;
  187. pr_debug("%s: slepping 10 ms after turning on external "
  188. " Left Speaker Ampl\n", __func__);
  189. usleep_range(10000, 10000);
  190. } else {
  191. pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
  192. __func__, spk);
  193. return;
  194. }
  195. }
  196. static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
  197. struct snd_kcontrol *k, int event)
  198. {
  199. pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
  200. if (SND_SOC_DAPM_EVENT_ON(event)) {
  201. if (!strncmp(w->name, "Ext Spk Left Pos", 17))
  202. msm8960_ext_spk_power_amp_on(SPK_AMP_POS);
  203. else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
  204. msm8960_ext_spk_power_amp_on(SPK_AMP_NEG);
  205. else {
  206. pr_err("%s() Invalid Speaker Widget = %s\n",
  207. __func__, w->name);
  208. return -EINVAL;
  209. }
  210. } else {
  211. if (!strncmp(w->name, "Ext Spk Left Pos", 17))
  212. msm8960_ext_spk_power_amp_off(SPK_AMP_POS);
  213. else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
  214. msm8960_ext_spk_power_amp_off(SPK_AMP_NEG);
  215. else {
  216. pr_err("%s() Invalid Speaker Widget = %s\n",
  217. __func__, w->name);
  218. return -EINVAL;
  219. }
  220. }
  221. return 0;
  222. }
  223. static int msm8930_enable_codec_ext_clk(
  224. struct snd_soc_codec *codec, int enable,
  225. bool dapm)
  226. {
  227. int r = 0;
  228. pr_debug("%s: enable = %d\n", __func__, enable);
  229. mutex_lock(&cdc_mclk_mutex);
  230. if (enable) {
  231. clk_users++;
  232. pr_debug("%s: clk_users = %d\n", __func__, clk_users);
  233. if (clk_users == 1) {
  234. if (codec_clk) {
  235. clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
  236. clk_prepare_enable(codec_clk);
  237. sitar_mclk_enable(codec, 1, dapm);
  238. } else {
  239. pr_err("%s: Error setting Sitar MCLK\n",
  240. __func__);
  241. clk_users--;
  242. r = -EINVAL;
  243. }
  244. }
  245. } else {
  246. if (clk_users > 0) {
  247. clk_users--;
  248. pr_debug("%s: clk_users = %d\n", __func__, clk_users);
  249. if (clk_users == 0) {
  250. pr_debug("%s: disabling MCLK. clk_users = %d\n",
  251. __func__, clk_users);
  252. sitar_mclk_enable(codec, 0, dapm);
  253. clk_disable_unprepare(codec_clk);
  254. }
  255. } else {
  256. pr_err("%s: Error releasing Sitar MCLK\n", __func__);
  257. r = -EINVAL;
  258. }
  259. }
  260. mutex_unlock(&cdc_mclk_mutex);
  261. return r;
  262. }
  263. static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
  264. struct snd_kcontrol *kcontrol, int event)
  265. {
  266. pr_debug("%s: event = %d\n", __func__, event);
  267. switch (event) {
  268. case SND_SOC_DAPM_PRE_PMU:
  269. return msm8930_enable_codec_ext_clk(w->codec, 1, true);
  270. case SND_SOC_DAPM_POST_PMD:
  271. return msm8930_enable_codec_ext_clk(w->codec, 0, true);
  272. }
  273. return 0;
  274. }
  275. static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
  276. SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
  277. msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
  278. SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
  279. SND_SOC_DAPM_SPK("Ext Spk Left Neg", msm8930_spkramp_event),
  280. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  281. SND_SOC_DAPM_MIC("Digital Mic1", NULL),
  282. SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
  283. SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
  284. SND_SOC_DAPM_MIC("Digital Mic1", NULL),
  285. SND_SOC_DAPM_MIC("Digital Mic2", NULL),
  286. SND_SOC_DAPM_MIC("Digital Mic3", NULL),
  287. SND_SOC_DAPM_MIC("Digital Mic4", NULL),
  288. };
  289. static const struct snd_soc_dapm_route common_audio_map[] = {
  290. {"RX_BIAS", NULL, "MCLK"},
  291. {"LDO_H", NULL, "MCLK"},
  292. {"MIC BIAS1 Internal1", NULL, "MCLK"},
  293. {"MIC BIAS2 Internal1", NULL, "MCLK"},
  294. /* Speaker path */
  295. {"Ext Spk Left Pos", NULL, "LINEOUT1"},
  296. {"Ext Spk Left Neg", NULL, "LINEOUT2"},
  297. /* Headset Mic */
  298. {"AMIC2", NULL, "MIC BIAS2 External"},
  299. {"MIC BIAS2 External", NULL, "Headset Mic"},
  300. /* Microphone path */
  301. {"AMIC1", NULL, "MIC BIAS2 External"},
  302. {"MIC BIAS2 External", NULL, "ANCLeft Headset Mic"},
  303. {"AMIC3", NULL, "MIC BIAS2 External"},
  304. {"MIC BIAS2 External", NULL, "ANCRight Headset Mic"},
  305. {"HEADPHONE", NULL, "LDO_H"},
  306. /**
  307. * The digital Mic routes are setup considering
  308. * fluid as default device.
  309. */
  310. /**
  311. * Digital Mic1. Front Bottom left Mic on Fluid and MTP.
  312. * Digital Mic GM5 on CDP mainboard.
  313. * Conncted to DMIC1 Input on Sitar codec.
  314. */
  315. {"DMIC1", NULL, "MIC BIAS1 External"},
  316. {"MIC BIAS1 External", NULL, "Digital Mic1"},
  317. /**
  318. * Digital Mic2. Back top MIC on Fluid.
  319. * Digital Mic GM6 on CDP mainboard.
  320. * Conncted to DMIC2 Input on Sitar codec.
  321. */
  322. {"DMIC2", NULL, "MIC BIAS1 External"},
  323. {"MIC BIAS1 External", NULL, "Digital Mic2"},
  324. /**
  325. * Digital Mic3. Back Bottom Digital Mic on Fluid.
  326. * Digital Mic GM1 on CDP mainboard.
  327. * Conncted to DMIC4 Input on Sitar codec.
  328. */
  329. {"DMIC3", NULL, "MIC BIAS1 External"},
  330. {"MIC BIAS1 External", NULL, "Digital Mic3"},
  331. /**
  332. * Digital Mic4. Back top Digital Mic on Fluid.
  333. * Digital Mic GM2 on CDP mainboard.
  334. * Conncted to DMIC3 Input on Sitar codec.
  335. */
  336. {"DMIC4", NULL, "MIC BIAS1 External"},
  337. {"MIC BIAS1 External", NULL, "Digital Mic4"},
  338. };
  339. static const char *spk_function[] = {"Off", "On"};
  340. static const char *slim0_rx_ch_text[] = {"One", "Two"};
  341. static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
  342. static const char * const hdmi_rate[] = {"Default", "Variable"};
  343. static const struct soc_enum msm8930_enum[] = {
  344. SOC_ENUM_SINGLE_EXT(2, spk_function),
  345. SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
  346. SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
  347. SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
  348. };
  349. static const char *btsco_rate_text[] = {"8000", "16000"};
  350. static const struct soc_enum msm8930_btsco_enum[] = {
  351. SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
  352. };
  353. static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
  354. struct snd_ctl_elem_value *ucontrol)
  355. {
  356. pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
  357. msm8930_slim_0_rx_ch);
  358. ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
  359. return 0;
  360. }
  361. static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
  362. struct snd_ctl_elem_value *ucontrol)
  363. {
  364. msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
  365. pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
  366. msm8930_slim_0_rx_ch);
  367. return 1;
  368. }
  369. static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
  370. struct snd_ctl_elem_value *ucontrol)
  371. {
  372. pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
  373. msm8930_slim_0_tx_ch);
  374. ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
  375. return 0;
  376. }
  377. static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
  378. struct snd_ctl_elem_value *ucontrol)
  379. {
  380. msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
  381. pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
  382. msm8930_slim_0_tx_ch);
  383. return 1;
  384. }
  385. static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
  386. struct snd_ctl_elem_value *ucontrol)
  387. {
  388. pr_debug("%s: msm8930_btsco_rate = %d", __func__, msm8930_btsco_rate);
  389. ucontrol->value.integer.value[0] = msm8930_btsco_rate;
  390. return 0;
  391. }
  392. static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
  393. struct snd_ctl_elem_value *ucontrol)
  394. {
  395. switch (ucontrol->value.integer.value[0]) {
  396. case 8000:
  397. msm8930_btsco_rate = BTSCO_RATE_8KHZ;
  398. break;
  399. case 16000:
  400. msm8930_btsco_rate = BTSCO_RATE_16KHZ;
  401. break;
  402. default:
  403. msm8930_btsco_rate = BTSCO_RATE_8KHZ;
  404. break;
  405. }
  406. pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
  407. return 0;
  408. }
  409. static const char *pmic_spk_gain_text[] = {
  410. "NEG_6_DB", "NEG_4_DB", "NEG_2_DB", "ZERO_DB", "POS_2_DB", "POS_4_DB",
  411. "POS_6_DB", "POS_8_DB", "POS_10_DB", "POS_12_DB", "POS_14_DB",
  412. "POS_16_DB", "POS_18_DB", "POS_20_DB", "POS_22_DB", "POS_24_DB"
  413. };
  414. static const struct soc_enum msm8960_pmic_spk_gain_enum[] = {
  415. SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pmic_spk_gain_text),
  416. pmic_spk_gain_text),
  417. };
  418. static int msm8930_pmic_gain_get(struct snd_kcontrol *kcontrol,
  419. struct snd_ctl_elem_value *ucontrol)
  420. {
  421. pr_debug("%s: msm8930_pmic_spk_gain = %d\n", __func__,
  422. msm8930_pmic_spk_gain);
  423. ucontrol->value.integer.value[0] = msm8930_pmic_spk_gain;
  424. return 0;
  425. }
  426. static int msm8930_pmic_gain_put(struct snd_kcontrol *kcontrol,
  427. struct snd_ctl_elem_value *ucontrol)
  428. {
  429. int ret = 0;
  430. msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
  431. if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
  432. ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
  433. pr_debug("%s: msm8930_pmic_spk_gain = %d"
  434. " ucontrol->value.integer.value[0] = %d\n", __func__,
  435. msm8930_pmic_spk_gain,
  436. (int) ucontrol->value.integer.value[0]);
  437. return ret;
  438. }
  439. static int msm8930_hdmi_rate_put(struct snd_kcontrol *kcontrol,
  440. struct snd_ctl_elem_value *ucontrol)
  441. {
  442. hdmi_rate_variable = ucontrol->value.integer.value[0];
  443. pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
  444. return 0;
  445. }
  446. static int msm8930_hdmi_rate_get(struct snd_kcontrol *kcontrol,
  447. struct snd_ctl_elem_value *ucontrol)
  448. {
  449. ucontrol->value.integer.value[0] = hdmi_rate_variable;
  450. return 0;
  451. }
  452. static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
  453. SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
  454. msm8930_set_spk),
  455. SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
  456. msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
  457. SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
  458. msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
  459. SOC_ENUM_EXT("PMIC SPK Gain", msm8960_pmic_spk_gain_enum[0],
  460. msm8930_pmic_gain_get, msm8930_pmic_gain_put),
  461. SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
  462. msm8930_btsco_rate_get, msm8930_btsco_rate_put),
  463. SOC_ENUM_EXT("HDMI RX Rate", msm8930_enum[3],
  464. msm8930_hdmi_rate_get,
  465. msm8930_hdmi_rate_put),
  466. };
  467. static void *def_sitar_mbhc_cal(void)
  468. {
  469. void *sitar_cal;
  470. struct sitar_mbhc_btn_detect_cfg *btn_cfg;
  471. u16 *btn_low, *btn_high;
  472. u8 *n_ready, *n_cic, *gain;
  473. sitar_cal = kzalloc(SITAR_MBHC_CAL_SIZE(SITAR_MBHC_DEF_BUTTONS,
  474. SITAR_MBHC_DEF_RLOADS),
  475. GFP_KERNEL);
  476. if (!sitar_cal) {
  477. pr_err("%s: out of memory\n", __func__);
  478. return NULL;
  479. }
  480. #define S(X, Y) ((SITAR_MBHC_CAL_GENERAL_PTR(sitar_cal)->X) = (Y))
  481. S(t_ldoh, 100);
  482. S(t_bg_fast_settle, 100);
  483. S(t_shutdown_plug_rem, 255);
  484. S(mbhc_nsa, 4);
  485. S(mbhc_navg, 4);
  486. #undef S
  487. #define S(X, Y) ((SITAR_MBHC_CAL_PLUG_DET_PTR(sitar_cal)->X) = (Y))
  488. S(mic_current, SITAR_PID_MIC_5_UA);
  489. S(hph_current, SITAR_PID_MIC_5_UA);
  490. S(t_mic_pid, 100);
  491. S(t_ins_complete, 250);
  492. S(t_ins_retry, 200);
  493. #undef S
  494. #define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
  495. S(v_no_mic, 30);
  496. S(v_hs_max, 1650);
  497. #undef S
  498. #define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
  499. S(c[0], 62);
  500. S(c[1], 124);
  501. S(nc, 1);
  502. S(n_meas, 3);
  503. S(mbhc_nsc, 11);
  504. S(n_btn_meas, 1);
  505. S(n_btn_con, 2);
  506. S(num_btn, SITAR_MBHC_DEF_BUTTONS);
  507. S(v_btn_press_delta_sta, 100);
  508. S(v_btn_press_delta_cic, 50);
  509. #undef S
  510. btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal);
  511. btn_low = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_LOW);
  512. btn_high = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_HIGH);
  513. btn_low[0] = -50;
  514. btn_high[0] = 10;
  515. btn_low[1] = 11;
  516. btn_high[1] = 38;
  517. btn_low[2] = 39;
  518. btn_high[2] = 64;
  519. btn_low[3] = 65;
  520. btn_high[3] = 91;
  521. btn_low[4] = 92;
  522. btn_high[4] = 115;
  523. btn_low[5] = 116;
  524. btn_high[5] = 141;
  525. btn_low[6] = 142;
  526. btn_high[6] = 163;
  527. btn_low[7] = 164;
  528. btn_high[7] = 250;
  529. n_ready = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_READY);
  530. n_ready[0] = 48;
  531. n_ready[1] = 38;
  532. n_cic = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_CIC);
  533. n_cic[0] = 60;
  534. n_cic[1] = 47;
  535. gain = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_GAIN);
  536. gain[0] = 11;
  537. gain[1] = 9;
  538. return sitar_cal;
  539. }
  540. static int msm8930_hw_params(struct snd_pcm_substream *substream,
  541. struct snd_pcm_hw_params *params)
  542. {
  543. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  544. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  545. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  546. int ret = 0;
  547. unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
  548. unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
  549. pr_debug("%s: ch=%d\n", __func__,
  550. msm8930_slim_0_rx_ch);
  551. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  552. ret = snd_soc_dai_get_channel_map(codec_dai,
  553. &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
  554. if (ret < 0) {
  555. pr_err("%s: failed to get codec chan map\n", __func__);
  556. goto end;
  557. }
  558. ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
  559. msm8930_slim_0_rx_ch, rx_ch);
  560. if (ret < 0) {
  561. pr_err("%s: failed to set cpu chan map\n", __func__);
  562. goto end;
  563. }
  564. } else {
  565. ret = snd_soc_dai_get_channel_map(codec_dai,
  566. &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
  567. if (ret < 0) {
  568. pr_err("%s: failed to get codec chan map\n", __func__);
  569. goto end;
  570. }
  571. ret = snd_soc_dai_set_channel_map(cpu_dai,
  572. msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
  573. if (ret < 0) {
  574. pr_err("%s: failed to set cpu chan map\n", __func__);
  575. goto end;
  576. }
  577. }
  578. end:
  579. return ret;
  580. }
  581. static int msm8930_audrx_init(struct snd_soc_pcm_runtime *rtd)
  582. {
  583. int err;
  584. struct snd_soc_codec *codec = rtd->codec;
  585. struct snd_soc_dapm_context *dapm = &codec->dapm;
  586. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  587. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  588. /* Tabla SLIMBUS configuration
  589. * RX1, RX2, RX3, RX4, RX5
  590. * TX1, TX2, TX3, TX4, TX5
  591. */
  592. unsigned int rx_ch[SITAR_RX_MAX] = {138, 139, 140, 141, 142};
  593. unsigned int tx_ch[SITAR_TX_MAX] = {128, 129, 130, 131, 132};
  594. pr_debug("%s()\n", __func__);
  595. snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
  596. ARRAY_SIZE(msm8930_dapm_widgets));
  597. snd_soc_dapm_add_routes(dapm, common_audio_map,
  598. ARRAY_SIZE(common_audio_map));
  599. snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
  600. snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Neg");
  601. snd_soc_dapm_sync(dapm);
  602. err = snd_soc_jack_new(codec, "Headset Jack",
  603. (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
  604. &hs_jack);
  605. if (err) {
  606. pr_err("failed to create new jack\n");
  607. return err;
  608. }
  609. err = snd_soc_jack_new(codec, "Button Jack",
  610. SITAR_JACK_BUTTON_MASK, &button_jack);
  611. if (err) {
  612. pr_err("failed to create new jack\n");
  613. return err;
  614. }
  615. codec_clk = clk_get(cpu_dai->dev, "osr_clk");
  616. snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
  617. tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
  618. mbhc_cfg.gpio = 37;
  619. mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
  620. sitar_hs_detect(codec, &mbhc_cfg);
  621. if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
  622. /* Initialize default PMIC speaker gain */
  623. pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
  624. }
  625. return 0;
  626. }
  627. static int msm8930_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  628. struct snd_pcm_hw_params *params)
  629. {
  630. struct snd_interval *rate = hw_param_interval(params,
  631. SNDRV_PCM_HW_PARAM_RATE);
  632. struct snd_interval *channels = hw_param_interval(params,
  633. SNDRV_PCM_HW_PARAM_CHANNELS);
  634. pr_debug("%s()\n", __func__);
  635. rate->min = rate->max = 48000;
  636. channels->min = channels->max = msm8930_slim_0_rx_ch;
  637. return 0;
  638. }
  639. static int msm8930_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  640. struct snd_pcm_hw_params *params)
  641. {
  642. struct snd_interval *rate = hw_param_interval(params,
  643. SNDRV_PCM_HW_PARAM_RATE);
  644. struct snd_interval *channels = hw_param_interval(params,
  645. SNDRV_PCM_HW_PARAM_CHANNELS);
  646. pr_debug("%s()\n", __func__);
  647. rate->min = rate->max = 48000;
  648. channels->min = channels->max = msm8930_slim_0_tx_ch;
  649. return 0;
  650. }
  651. static int msm8930_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  652. struct snd_pcm_hw_params *params)
  653. {
  654. struct snd_interval *rate = hw_param_interval(params,
  655. SNDRV_PCM_HW_PARAM_RATE);
  656. pr_debug("%s()\n", __func__);
  657. rate->min = rate->max = 48000;
  658. return 0;
  659. }
  660. static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  661. struct snd_pcm_hw_params *params)
  662. {
  663. struct snd_interval *rate = hw_param_interval(params,
  664. SNDRV_PCM_HW_PARAM_RATE);
  665. struct snd_interval *channels = hw_param_interval(params,
  666. SNDRV_PCM_HW_PARAM_CHANNELS);
  667. if (!hdmi_rate_variable)
  668. rate->min = rate->max = 48000;
  669. channels->min = channels->max = 2;
  670. return 0;
  671. }
  672. static int msm8930_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  673. struct snd_pcm_hw_params *params)
  674. {
  675. struct snd_interval *rate = hw_param_interval(params,
  676. SNDRV_PCM_HW_PARAM_RATE);
  677. struct snd_interval *channels = hw_param_interval(params,
  678. SNDRV_PCM_HW_PARAM_CHANNELS);
  679. rate->min = rate->max = msm8930_btsco_rate;
  680. channels->min = channels->max = msm8930_btsco_ch;
  681. return 0;
  682. }
  683. static int msm8930_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
  684. struct snd_pcm_hw_params *params)
  685. {
  686. struct snd_interval *rate = hw_param_interval(params,
  687. SNDRV_PCM_HW_PARAM_RATE);
  688. struct snd_interval *channels = hw_param_interval(params,
  689. SNDRV_PCM_HW_PARAM_CHANNELS);
  690. /* PCM only supports mono output with 8khz sample rate */
  691. rate->min = rate->max = 8000;
  692. channels->min = channels->max = 1;
  693. return 0;
  694. }
  695. static int msm8930_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  696. struct snd_pcm_hw_params *params)
  697. {
  698. struct snd_interval *rate = hw_param_interval(params,
  699. SNDRV_PCM_HW_PARAM_RATE);
  700. pr_debug("%s()\n", __func__);
  701. rate->min = rate->max = 48000;
  702. return 0;
  703. }
  704. static int msm8930_aux_pcm_get_gpios(void)
  705. {
  706. int ret = 0;
  707. pr_debug("%s\n", __func__);
  708. ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
  709. if (ret < 0) {
  710. pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
  711. __func__, GPIO_AUX_PCM_DOUT);
  712. goto fail_dout;
  713. }
  714. ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
  715. if (ret < 0) {
  716. pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
  717. __func__, GPIO_AUX_PCM_DIN);
  718. goto fail_din;
  719. }
  720. ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
  721. if (ret < 0) {
  722. pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
  723. __func__, GPIO_AUX_PCM_SYNC);
  724. goto fail_sync;
  725. }
  726. ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
  727. if (ret < 0) {
  728. pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
  729. __func__, GPIO_AUX_PCM_CLK);
  730. goto fail_clk;
  731. }
  732. return 0;
  733. fail_clk:
  734. gpio_free(GPIO_AUX_PCM_SYNC);
  735. fail_sync:
  736. gpio_free(GPIO_AUX_PCM_DIN);
  737. fail_din:
  738. gpio_free(GPIO_AUX_PCM_DOUT);
  739. fail_dout:
  740. return ret;
  741. }
  742. static int msm8930_aux_pcm_free_gpios(void)
  743. {
  744. gpio_free(GPIO_AUX_PCM_DIN);
  745. gpio_free(GPIO_AUX_PCM_DOUT);
  746. gpio_free(GPIO_AUX_PCM_SYNC);
  747. gpio_free(GPIO_AUX_PCM_CLK);
  748. return 0;
  749. }
  750. static int msm8930_startup(struct snd_pcm_substream *substream)
  751. {
  752. pr_debug("%s(): substream = %s stream = %d\n", __func__,
  753. substream->name, substream->stream);
  754. return 0;
  755. }
  756. static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
  757. {
  758. int ret = 0;
  759. pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
  760. __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
  761. if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
  762. ret = msm8930_aux_pcm_get_gpios();
  763. if (ret < 0) {
  764. pr_err("%s: Aux PCM GPIO request failed\n", __func__);
  765. return -EINVAL;
  766. }
  767. return 0;
  768. }
  769. static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
  770. {
  771. pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
  772. __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
  773. if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
  774. msm8930_aux_pcm_free_gpios();
  775. }
  776. static void msm8930_shutdown(struct snd_pcm_substream *substream)
  777. {
  778. pr_debug("%s(): substream = %s stream = %d\n", __func__,
  779. substream->name, substream->stream);
  780. }
  781. static struct snd_soc_ops msm8930_be_ops = {
  782. .startup = msm8930_startup,
  783. .hw_params = msm8930_hw_params,
  784. .shutdown = msm8930_shutdown,
  785. };
  786. static struct snd_soc_ops msm8930_auxpcm_be_ops = {
  787. .startup = msm8930_auxpcm_startup,
  788. .shutdown = msm8930_auxpcm_shutdown,
  789. };
  790. /* Digital audio interface glue - connects codec <---> CPU */
  791. static struct snd_soc_dai_link msm8930_dai[] = {
  792. /* FrontEnd DAI Links */
  793. {
  794. .name = "MSM8930 Media1",
  795. .stream_name = "MultiMedia1",
  796. .cpu_dai_name = "MultiMedia1",
  797. .platform_name = "msm-pcm-dsp",
  798. .dynamic = 1,
  799. .codec_dai_name = "snd-soc-dummy-dai",
  800. .codec_name = "snd-soc-dummy",
  801. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  802. .ignore_suspend = 1,
  803. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  804. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
  805. },
  806. {
  807. .name = "MSM8930 Media2",
  808. .stream_name = "MultiMedia2",
  809. .cpu_dai_name = "MultiMedia2",
  810. .platform_name = "msm-multi-ch-pcm-dsp",
  811. .dynamic = 1,
  812. .codec_dai_name = "snd-soc-dummy-dai",
  813. .codec_name = "snd-soc-dummy",
  814. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  815. .ignore_suspend = 1,
  816. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  817. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
  818. },
  819. {
  820. .name = "Circuit-Switch Voice",
  821. .stream_name = "CS-Voice",
  822. .cpu_dai_name = "CS-VOICE",
  823. .platform_name = "msm-pcm-voice",
  824. .dynamic = 1,
  825. .codec_dai_name = "snd-soc-dummy-dai",
  826. .codec_name = "snd-soc-dummy",
  827. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  828. .be_id = MSM_FRONTEND_DAI_CS_VOICE,
  829. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  830. .ignore_suspend = 1,
  831. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  832. },
  833. {
  834. .name = "MSM VoIP",
  835. .stream_name = "VoIP",
  836. .cpu_dai_name = "VoIP",
  837. .platform_name = "msm-voip-dsp",
  838. .dynamic = 1,
  839. .codec_dai_name = "snd-soc-dummy-dai",
  840. .codec_name = "snd-soc-dummy",
  841. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  842. .ignore_suspend = 1,
  843. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  844. .be_id = MSM_FRONTEND_DAI_VOIP,
  845. },
  846. {
  847. .name = "MSM8930 LPA",
  848. .stream_name = "LPA",
  849. .cpu_dai_name = "MultiMedia3",
  850. .platform_name = "msm-pcm-lpa",
  851. .dynamic = 1,
  852. .codec_dai_name = "snd-soc-dummy-dai",
  853. .codec_name = "snd-soc-dummy",
  854. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  855. .ignore_suspend = 1,
  856. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  857. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
  858. },
  859. /* Hostless PMC purpose */
  860. {
  861. .name = "SLIMBUS_0 Hostless",
  862. .stream_name = "SLIMBUS_0 Hostless",
  863. .cpu_dai_name = "SLIMBUS0_HOSTLESS",
  864. .platform_name = "msm-pcm-hostless",
  865. .dynamic = 1,
  866. .codec_dai_name = "snd-soc-dummy-dai",
  867. .codec_name = "snd-soc-dummy",
  868. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  869. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  870. .ignore_suspend = 1,
  871. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  872. /* .be_id = do not care */
  873. },
  874. {
  875. .name = "INT_FM Hostless",
  876. .stream_name = "INT_FM Hostless",
  877. .cpu_dai_name = "INT_FM_HOSTLESS",
  878. .platform_name = "msm-pcm-hostless",
  879. .dynamic = 1,
  880. .codec_dai_name = "snd-soc-dummy-dai",
  881. .codec_name = "snd-soc-dummy",
  882. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  883. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  884. .ignore_suspend = 1,
  885. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  886. /* .be_id = do not care */
  887. },
  888. {
  889. .name = "MSM AFE-PCM RX",
  890. .stream_name = "AFE-PROXY RX",
  891. .cpu_dai_name = "msm-dai-q6.241",
  892. .codec_name = "msm-stub-codec.1",
  893. .codec_dai_name = "msm-stub-rx",
  894. .platform_name = "msm-pcm-afe",
  895. .ignore_suspend = 1,
  896. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  897. },
  898. {
  899. .name = "MSM AFE-PCM TX",
  900. .stream_name = "AFE-PROXY TX",
  901. .cpu_dai_name = "msm-dai-q6.240",
  902. .codec_name = "msm-stub-codec.1",
  903. .codec_dai_name = "msm-stub-tx",
  904. .platform_name = "msm-pcm-afe",
  905. .ignore_suspend = 1,
  906. },
  907. {
  908. .name = "MSM8930 Compr",
  909. .stream_name = "COMPR",
  910. .cpu_dai_name = "MultiMedia4",
  911. .platform_name = "msm-compr-dsp",
  912. .dynamic = 1,
  913. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  914. .codec_dai_name = "snd-soc-dummy-dai",
  915. .codec_name = "snd-soc-dummy",
  916. .ignore_suspend = 1,
  917. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  918. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
  919. },
  920. {
  921. .name = "AUXPCM Hostless",
  922. .stream_name = "AUXPCM Hostless",
  923. .cpu_dai_name = "AUXPCM_HOSTLESS",
  924. .platform_name = "msm-pcm-hostless",
  925. .dynamic = 1,
  926. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  927. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  928. .ignore_suspend = 1,
  929. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  930. .codec_dai_name = "snd-soc-dummy-dai",
  931. .codec_name = "snd-soc-dummy",
  932. },
  933. /* HDMI Hostless */
  934. {
  935. .name = "HDMI_RX_HOSTLESS",
  936. .stream_name = "HDMI_RX_HOSTLESS",
  937. .cpu_dai_name = "HDMI_HOSTLESS",
  938. .platform_name = "msm-pcm-hostless",
  939. .dynamic = 1,
  940. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  941. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  942. .ignore_suspend = 1,
  943. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  944. .codec_dai_name = "snd-soc-dummy-dai",
  945. .codec_name = "snd-soc-dummy",
  946. },
  947. {
  948. .name = "VoLTE",
  949. .stream_name = "VoLTE",
  950. .cpu_dai_name = "VoLTE",
  951. .platform_name = "msm-pcm-voice",
  952. .dynamic = 1,
  953. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  954. SND_SOC_DPCM_TRIGGER_POST},
  955. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  956. .ignore_suspend = 1,
  957. /* this dainlink has playback support */
  958. .ignore_pmdown_time = 1,
  959. .codec_dai_name = "snd-soc-dummy-dai",
  960. .codec_name = "snd-soc-dummy",
  961. .be_id = MSM_FRONTEND_DAI_VOLTE,
  962. },
  963. {
  964. .name = "Voice2",
  965. .stream_name = "Voice2",
  966. .cpu_dai_name = "Voice2",
  967. .platform_name = "msm-pcm-voice",
  968. .dynamic = 1,
  969. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  970. SND_SOC_DPCM_TRIGGER_POST},
  971. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  972. .ignore_suspend = 1,
  973. /* this dainlink has playback support */
  974. .ignore_pmdown_time = 1,
  975. .codec_dai_name = "snd-soc-dummy-dai",
  976. .codec_name = "snd-soc-dummy",
  977. .be_id = MSM_FRONTEND_DAI_VOICE2,
  978. },
  979. {
  980. .name = "MSM8960 LowLatency",
  981. .stream_name = "MultiMedia5",
  982. .cpu_dai_name = "MultiMedia5",
  983. .platform_name = "msm-lowlatency-pcm-dsp",
  984. .dynamic = 1,
  985. .codec_dai_name = "snd-soc-dummy-dai",
  986. .codec_name = "snd-soc-dummy",
  987. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  988. SND_SOC_DPCM_TRIGGER_POST},
  989. .ignore_suspend = 1,
  990. /* this dainlink has playback support */
  991. .ignore_pmdown_time = 1,
  992. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
  993. },
  994. {
  995. .name = "MSM8960 FM",
  996. .stream_name = "MultiMedia6",
  997. .cpu_dai_name = "MultiMedia6",
  998. .platform_name = "msm-pcm-loopback",
  999. .dynamic = 1,
  1000. .codec_dai_name = "snd-soc-dummy-dai",
  1001. .codec_name = "snd-soc-dummy",
  1002. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  1003. SND_SOC_DPCM_TRIGGER_POST},
  1004. .ignore_suspend = 1,
  1005. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1006. /* this dainlink has playback support */
  1007. .ignore_pmdown_time = 1,
  1008. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
  1009. },
  1010. /* Backend DAI Links */
  1011. {
  1012. .name = LPASS_BE_SLIMBUS_0_RX,
  1013. .stream_name = "Slimbus Playback",
  1014. .cpu_dai_name = "msm-dai-q6.16384",
  1015. .platform_name = "msm-pcm-routing",
  1016. .codec_name = "sitar_codec",
  1017. .codec_dai_name = "sitar_rx1",
  1018. .no_pcm = 1,
  1019. .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
  1020. .init = &msm8930_audrx_init,
  1021. .be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
  1022. .ops = &msm8930_be_ops,
  1023. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1024. },
  1025. {
  1026. .name = LPASS_BE_SLIMBUS_0_TX,
  1027. .stream_name = "Slimbus Capture",
  1028. .cpu_dai_name = "msm-dai-q6.16385",
  1029. .platform_name = "msm-pcm-routing",
  1030. .codec_name = "sitar_codec",
  1031. .codec_dai_name = "sitar_tx1",
  1032. .no_pcm = 1,
  1033. .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
  1034. .be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
  1035. .ops = &msm8930_be_ops,
  1036. },
  1037. /* Backend BT/FM DAI Links */
  1038. {
  1039. .name = LPASS_BE_INT_BT_SCO_RX,
  1040. .stream_name = "Internal BT-SCO Playback",
  1041. .cpu_dai_name = "msm-dai-q6.12288",
  1042. .platform_name = "msm-pcm-routing",
  1043. .codec_name = "msm-stub-codec.1",
  1044. .codec_dai_name = "msm-stub-rx",
  1045. .no_pcm = 1,
  1046. .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
  1047. .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
  1048. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1049. },
  1050. {
  1051. .name = LPASS_BE_INT_BT_SCO_TX,
  1052. .stream_name = "Internal BT-SCO Capture",
  1053. .cpu_dai_name = "msm-dai-q6.12289",
  1054. .platform_name = "msm-pcm-routing",
  1055. .codec_name = "msm-stub-codec.1",
  1056. .codec_dai_name = "msm-stub-tx",
  1057. .no_pcm = 1,
  1058. .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
  1059. .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
  1060. },
  1061. {
  1062. .name = LPASS_BE_INT_FM_RX,
  1063. .stream_name = "Internal FM Playback",
  1064. .cpu_dai_name = "msm-dai-q6.12292",
  1065. .platform_name = "msm-pcm-routing",
  1066. .codec_name = "msm-stub-codec.1",
  1067. .codec_dai_name = "msm-stub-rx",
  1068. .no_pcm = 1,
  1069. .be_id = MSM_BACKEND_DAI_INT_FM_RX,
  1070. .be_hw_params_fixup = msm8930_be_hw_params_fixup,
  1071. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1072. },
  1073. {
  1074. .name = LPASS_BE_INT_FM_TX,
  1075. .stream_name = "Internal FM Capture",
  1076. .cpu_dai_name = "msm-dai-q6.12293",
  1077. .platform_name = "msm-pcm-routing",
  1078. .codec_name = "msm-stub-codec.1",
  1079. .codec_dai_name = "msm-stub-tx",
  1080. .no_pcm = 1,
  1081. .be_id = MSM_BACKEND_DAI_INT_FM_TX,
  1082. .be_hw_params_fixup = msm8930_be_hw_params_fixup,
  1083. },
  1084. /* HDMI BACK END DAI Link */
  1085. {
  1086. .name = LPASS_BE_HDMI,
  1087. .stream_name = "HDMI Playback",
  1088. .cpu_dai_name = "msm-dai-q6-hdmi.8",
  1089. .platform_name = "msm-pcm-routing",
  1090. .codec_name = "msm-stub-codec.1",
  1091. .codec_dai_name = "msm-stub-rx",
  1092. .no_pcm = 1,
  1093. .be_id = MSM_BACKEND_DAI_HDMI_RX,
  1094. .be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
  1095. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1096. },
  1097. /* Backend AFE DAI Links */
  1098. {
  1099. .name = LPASS_BE_AFE_PCM_RX,
  1100. .stream_name = "AFE Playback",
  1101. .cpu_dai_name = "msm-dai-q6.224",
  1102. .platform_name = "msm-pcm-routing",
  1103. .codec_name = "msm-stub-codec.1",
  1104. .codec_dai_name = "msm-stub-rx",
  1105. .no_pcm = 1,
  1106. .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
  1107. .be_hw_params_fixup = msm8930_proxy_be_hw_params_fixup,
  1108. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1109. },
  1110. {
  1111. .name = LPASS_BE_AFE_PCM_TX,
  1112. .stream_name = "AFE Capture",
  1113. .cpu_dai_name = "msm-dai-q6.225",
  1114. .platform_name = "msm-pcm-routing",
  1115. .codec_name = "msm-stub-codec.1",
  1116. .codec_dai_name = "msm-stub-tx",
  1117. .no_pcm = 1,
  1118. .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
  1119. .be_hw_params_fixup = msm8930_proxy_be_hw_params_fixup,
  1120. },
  1121. /* AUX PCM Backend DAI Links */
  1122. {
  1123. .name = LPASS_BE_AUXPCM_RX,
  1124. .stream_name = "AUX PCM Playback",
  1125. .cpu_dai_name = "msm-dai-q6.2",
  1126. .platform_name = "msm-pcm-routing",
  1127. .codec_name = "msm-stub-codec.1",
  1128. .codec_dai_name = "msm-stub-rx",
  1129. .no_pcm = 1,
  1130. .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
  1131. .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
  1132. .ops = &msm8930_auxpcm_be_ops,
  1133. },
  1134. {
  1135. .name = LPASS_BE_AUXPCM_TX,
  1136. .stream_name = "AUX PCM Capture",
  1137. .cpu_dai_name = "msm-dai-q6.3",
  1138. .platform_name = "msm-pcm-routing",
  1139. .codec_name = "msm-stub-codec.1",
  1140. .codec_dai_name = "msm-stub-tx",
  1141. .no_pcm = 1,
  1142. .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
  1143. .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
  1144. .ops = &msm8930_auxpcm_be_ops,
  1145. },
  1146. /* Incall Music BACK END DAI Link */
  1147. {
  1148. .name = LPASS_BE_VOICE_PLAYBACK_TX,
  1149. .stream_name = "Voice Farend Playback",
  1150. .cpu_dai_name = "msm-dai-q6.32773",
  1151. .platform_name = "msm-pcm-routing",
  1152. .codec_name = "msm-stub-codec.1",
  1153. .codec_dai_name = "msm-stub-rx",
  1154. .no_pcm = 1,
  1155. .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
  1156. .be_hw_params_fixup = msm8930_be_hw_params_fixup,
  1157. },
  1158. /* Incall Record Uplink BACK END DAI Link */
  1159. {
  1160. .name = LPASS_BE_INCALL_RECORD_TX,
  1161. .stream_name = "Voice Uplink Capture",
  1162. .cpu_dai_name = "msm-dai-q6.32772",
  1163. .platform_name = "msm-pcm-routing",
  1164. .codec_name = "msm-stub-codec.1",
  1165. .codec_dai_name = "msm-stub-tx",
  1166. .no_pcm = 1,
  1167. .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
  1168. .be_hw_params_fixup = msm8930_be_hw_params_fixup,
  1169. },
  1170. /* Incall Record Downlink BACK END DAI Link */
  1171. {
  1172. .name = LPASS_BE_INCALL_RECORD_RX,
  1173. .stream_name = "Voice Downlink Capture",
  1174. .cpu_dai_name = "msm-dai-q6.32771",
  1175. .platform_name = "msm-pcm-routing",
  1176. .codec_name = "msm-stub-codec.1",
  1177. .codec_dai_name = "msm-stub-tx",
  1178. .no_pcm = 1,
  1179. .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
  1180. .be_hw_params_fixup = msm8930_be_hw_params_fixup,
  1181. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1182. },
  1183. };
  1184. struct snd_soc_card snd_soc_card_msm8930 = {
  1185. .name = "msm8930-sitar-snd-card",
  1186. .dai_link = msm8930_dai,
  1187. .num_links = ARRAY_SIZE(msm8930_dai),
  1188. .controls = sitar_msm8930_controls,
  1189. .num_controls = ARRAY_SIZE(sitar_msm8930_controls),
  1190. };
  1191. static struct platform_device *msm8930_snd_device;
  1192. static int msm8930_configure_headset_mic_gpios(void)
  1193. {
  1194. int ret;
  1195. ret = gpio_request(80, "US_EURO_SWITCH");
  1196. if (ret) {
  1197. pr_err("%s: Failed to request gpio 80\n", __func__);
  1198. return ret;
  1199. }
  1200. ret = gpio_direction_output(80, 0);
  1201. if (ret) {
  1202. pr_err("%s: Unable to set direction\n", __func__);
  1203. gpio_free(80);
  1204. }
  1205. msm8930_headset_gpios_configured = 0;
  1206. return 0;
  1207. }
  1208. static void msm8930_free_headset_mic_gpios(void)
  1209. {
  1210. if (msm8930_headset_gpios_configured)
  1211. gpio_free(80);
  1212. }
  1213. static int __init msm8930_audio_init(void)
  1214. {
  1215. int ret;
  1216. if (!soc_class_is_msm8930()) {
  1217. pr_err("%s: Not the right machine type\n", __func__);
  1218. return -ENODEV ;
  1219. }
  1220. mbhc_cfg.calibration = def_sitar_mbhc_cal();
  1221. if (!mbhc_cfg.calibration) {
  1222. pr_err("Calibration data allocation failed\n");
  1223. return -ENOMEM;
  1224. }
  1225. msm8930_snd_device = platform_device_alloc("soc-audio", 0);
  1226. if (!msm8930_snd_device) {
  1227. pr_err("Platform device allocation failed\n");
  1228. kfree(mbhc_cfg.calibration);
  1229. return -ENOMEM;
  1230. }
  1231. platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
  1232. ret = platform_device_add(msm8930_snd_device);
  1233. if (ret) {
  1234. platform_device_put(msm8930_snd_device);
  1235. kfree(mbhc_cfg.calibration);
  1236. return ret;
  1237. }
  1238. if (msm8930_configure_headset_mic_gpios()) {
  1239. pr_err("%s Fail to configure headset mic gpios\n", __func__);
  1240. msm8930_headset_gpios_configured = 0;
  1241. } else
  1242. msm8930_headset_gpios_configured = 1;
  1243. atomic_set(&auxpcm_rsc_ref, 0);
  1244. mutex_init(&cdc_mclk_mutex);
  1245. return ret;
  1246. }
  1247. module_init(msm8930_audio_init);
  1248. static void __exit msm8930_audio_exit(void)
  1249. {
  1250. if (!soc_class_is_msm8930()) {
  1251. pr_err("%s: Not the right machine type\n", __func__);
  1252. return ;
  1253. }
  1254. msm8930_free_headset_mic_gpios();
  1255. platform_device_unregister(msm8930_snd_device);
  1256. kfree(mbhc_cfg.calibration);
  1257. mutex_destroy(&cdc_mclk_mutex);
  1258. }
  1259. module_exit(msm8930_audio_exit);
  1260. MODULE_DESCRIPTION("ALSA SoC MSM8930");
  1261. MODULE_LICENSE("GPL v2");