msm8960.c 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863
  1. /* Copyright (c) 2011-2013, 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/pm8921.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/mfd/pm8xxx/pm8921.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 <linux/mfd/wcd9xxx/core.h>
  27. #include "msm-pcm-routing.h"
  28. #include "../codecs/wcd9310.h"
  29. /* 8960 machine driver */
  30. #define PM8921_GPIO_BASE NR_GPIO_IRQS
  31. #define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
  32. #define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
  33. #define MSM8960_SPK_ON 1
  34. #define MSM8960_SPK_OFF 0
  35. #define msm8960_SLIM_0_RX_MAX_CHANNELS 2
  36. #define msm8960_SLIM_0_TX_MAX_CHANNELS 4
  37. #define SAMPLE_RATE_8KHZ 8000
  38. #define SAMPLE_RATE_16KHZ 16000
  39. #define BOTTOM_SPK_AMP_POS 0x1
  40. #define BOTTOM_SPK_AMP_NEG 0x2
  41. #define TOP_SPK_AMP_POS 0x4
  42. #define TOP_SPK_AMP_NEG 0x8
  43. #define TOP_SPK_AMP 0x10
  44. #define GPIO_AUX_PCM_DOUT 63
  45. #define GPIO_AUX_PCM_DIN 64
  46. #define GPIO_AUX_PCM_SYNC 65
  47. #define GPIO_AUX_PCM_CLK 66
  48. #define TABLA_EXT_CLK_RATE 12288000
  49. #define TABLA_MBHC_DEF_BUTTONS 8
  50. #define TABLA_MBHC_DEF_RLOADS 5
  51. #define JACK_DETECT_GPIO 38
  52. #define JACK_DETECT_INT PM8921_GPIO_IRQ(PM8921_IRQ_BASE, JACK_DETECT_GPIO)
  53. #define JACK_US_EURO_SEL_GPIO 35
  54. static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
  55. static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
  56. static int msm8960_spk_control;
  57. static int msm8960_ext_bottom_spk_pamp;
  58. static int msm8960_ext_top_spk_pamp;
  59. static int msm8960_slim_0_rx_ch = 1;
  60. static int msm8960_slim_0_tx_ch = 1;
  61. static int msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
  62. static int msm8960_btsco_ch = 1;
  63. static int hdmi_rate_variable;
  64. static int msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
  65. static struct clk *codec_clk;
  66. static int clk_users;
  67. static int msm8960_headset_gpios_configured;
  68. static struct snd_soc_jack hs_jack;
  69. static struct snd_soc_jack button_jack;
  70. static atomic_t auxpcm_rsc_ref;
  71. static bool hs_micbias_always_on;
  72. module_param(hs_micbias_always_on, bool, 0444);
  73. MODULE_PARM_DESC(hs_micbias_always_on, "Keep micbias always on if headset is inserted");
  74. static bool hs_detect_use_gpio;
  75. module_param(hs_detect_use_gpio, bool, 0444);
  76. MODULE_PARM_DESC(hs_detect_use_gpio, "Use GPIO for headset detection");
  77. static bool hs_detect_extn_cable;
  78. module_param(hs_detect_extn_cable, bool, 0444);
  79. MODULE_PARM_DESC(hs_detect_extn_cable, "Enable extension cable feature");
  80. static bool hs_detect_use_firmware;
  81. module_param(hs_detect_use_firmware, bool, 0444);
  82. MODULE_PARM_DESC(hs_detect_use_firmware, "Use firmware for headset detection");
  83. static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
  84. bool dapm);
  85. static bool msm8960_swap_gnd_mic(struct snd_soc_codec *codec);
  86. static struct tabla_mbhc_config mbhc_cfg = {
  87. .headset_jack = &hs_jack,
  88. .button_jack = &button_jack,
  89. .read_fw_bin = false,
  90. .calibration = NULL,
  91. .micbias = TABLA_MICBIAS2,
  92. .mclk_cb_fn = msm8960_enable_codec_ext_clk,
  93. .mclk_rate = TABLA_EXT_CLK_RATE,
  94. .gpio = 0,
  95. .gpio_irq = 0,
  96. .gpio_level_insert = 1,
  97. .swap_gnd_mic = NULL,
  98. .detect_extn_cable = false,
  99. .micbias_always_on = false
  100. };
  101. static u32 us_euro_sel_gpio = PM8921_GPIO_PM_TO_SYS(JACK_US_EURO_SEL_GPIO);
  102. static struct mutex cdc_mclk_mutex;
  103. static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
  104. {
  105. int ret = 0;
  106. struct pm_gpio param = {
  107. .direction = PM_GPIO_DIR_OUT,
  108. .output_buffer = PM_GPIO_OUT_BUF_CMOS,
  109. .output_value = 1,
  110. .pull = PM_GPIO_PULL_NO,
  111. .vin_sel = PM_GPIO_VIN_S4,
  112. .out_strength = PM_GPIO_STRENGTH_MED,
  113. .
  114. function = PM_GPIO_FUNC_NORMAL,
  115. };
  116. if (spk_amp_gpio == bottom_spk_pamp_gpio) {
  117. ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
  118. if (ret) {
  119. pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
  120. __func__, bottom_spk_pamp_gpio);
  121. return;
  122. }
  123. ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
  124. if (ret)
  125. pr_err("%s: Failed to configure Bottom Spk Ampl"
  126. " gpio %u\n", __func__, bottom_spk_pamp_gpio);
  127. else {
  128. pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
  129. gpio_direction_output(bottom_spk_pamp_gpio, 1);
  130. }
  131. } else if (spk_amp_gpio == top_spk_pamp_gpio) {
  132. ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
  133. if (ret) {
  134. pr_err("%s: Error requesting GPIO %d\n", __func__,
  135. top_spk_pamp_gpio);
  136. return;
  137. }
  138. ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
  139. if (ret)
  140. pr_err("%s: Failed to configure Top Spk Ampl"
  141. " gpio %u\n", __func__, top_spk_pamp_gpio);
  142. else {
  143. pr_debug("%s: enable Top spkr amp gpio\n", __func__);
  144. gpio_direction_output(top_spk_pamp_gpio, 1);
  145. }
  146. } else {
  147. pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
  148. " gpio = %u\n", __func__, spk_amp_gpio);
  149. return;
  150. }
  151. }
  152. static void msm8960_ext_spk_power_amp_on(u32 spk)
  153. {
  154. if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
  155. if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
  156. (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
  157. pr_debug("%s() External Bottom Speaker Ampl already "
  158. "turned on. spk = 0x%08x\n", __func__, spk);
  159. return;
  160. }
  161. msm8960_ext_bottom_spk_pamp |= spk;
  162. if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
  163. (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
  164. msm8960_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
  165. pr_debug("%s: slepping 4 ms after turning on external "
  166. " Bottom Speaker Ampl\n", __func__);
  167. usleep_range(4000, 4000);
  168. }
  169. } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
  170. pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
  171. __func__, msm8960_ext_top_spk_pamp, spk);
  172. if (((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
  173. (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
  174. (msm8960_ext_top_spk_pamp & TOP_SPK_AMP)) {
  175. pr_debug("%s() External Top Speaker Ampl already"
  176. "turned on. spk = 0x%08x\n", __func__, spk);
  177. return;
  178. }
  179. msm8960_ext_top_spk_pamp |= spk;
  180. if (((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
  181. (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
  182. (msm8960_ext_top_spk_pamp & TOP_SPK_AMP)) {
  183. msm8960_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
  184. pr_debug("%s: sleeping 4 ms after turning on "
  185. " external Top Speaker Ampl\n", __func__);
  186. usleep_range(4000, 4000);
  187. }
  188. } else {
  189. pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
  190. __func__, spk);
  191. return;
  192. }
  193. }
  194. static void msm8960_ext_spk_power_amp_off(u32 spk)
  195. {
  196. if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
  197. if (!msm8960_ext_bottom_spk_pamp)
  198. return;
  199. gpio_direction_output(bottom_spk_pamp_gpio, 0);
  200. gpio_free(bottom_spk_pamp_gpio);
  201. msm8960_ext_bottom_spk_pamp = 0;
  202. pr_debug("%s: sleeping 4 ms after turning off external Bottom"
  203. " Speaker Ampl\n", __func__);
  204. usleep_range(4000, 4000);
  205. } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
  206. pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
  207. __func__, msm8960_ext_top_spk_pamp, spk);
  208. if (!msm8960_ext_top_spk_pamp)
  209. return;
  210. if ((spk & TOP_SPK_AMP_POS) || (spk & TOP_SPK_AMP_NEG)) {
  211. msm8960_ext_top_spk_pamp &= (~(TOP_SPK_AMP_POS |
  212. TOP_SPK_AMP_NEG));
  213. } else if (spk & TOP_SPK_AMP) {
  214. msm8960_ext_top_spk_pamp &= ~TOP_SPK_AMP;
  215. }
  216. if (msm8960_ext_top_spk_pamp)
  217. return;
  218. gpio_direction_output(top_spk_pamp_gpio, 0);
  219. gpio_free(top_spk_pamp_gpio);
  220. msm8960_ext_top_spk_pamp = 0;
  221. pr_debug("%s: sleeping 4 ms after ext Top Spek Ampl is off\n",
  222. __func__);
  223. usleep_range(4000, 4000);
  224. } else {
  225. pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
  226. __func__, spk);
  227. return;
  228. }
  229. }
  230. static void msm8960_ext_control(struct snd_soc_codec *codec)
  231. {
  232. struct snd_soc_dapm_context *dapm = &codec->dapm;
  233. mutex_lock(&dapm->codec->mutex);
  234. pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
  235. if (msm8960_spk_control == MSM8960_SPK_ON) {
  236. snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
  237. snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
  238. snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
  239. snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
  240. } else {
  241. snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
  242. snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
  243. snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
  244. snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
  245. }
  246. snd_soc_dapm_sync(dapm);
  247. mutex_unlock(&dapm->codec->mutex);
  248. }
  249. static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
  250. struct snd_ctl_elem_value *ucontrol)
  251. {
  252. pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
  253. ucontrol->value.integer.value[0] = msm8960_spk_control;
  254. return 0;
  255. }
  256. static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
  257. struct snd_ctl_elem_value *ucontrol)
  258. {
  259. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  260. pr_debug("%s()\n", __func__);
  261. if (msm8960_spk_control == ucontrol->value.integer.value[0])
  262. return 0;
  263. msm8960_spk_control = ucontrol->value.integer.value[0];
  264. msm8960_ext_control(codec);
  265. return 1;
  266. }
  267. static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
  268. struct snd_kcontrol *k, int event)
  269. {
  270. pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
  271. if (SND_SOC_DAPM_EVENT_ON(event)) {
  272. if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
  273. msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
  274. else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
  275. msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
  276. else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
  277. msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
  278. else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
  279. msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
  280. else if (!strncmp(w->name, "Ext Spk Top", 12))
  281. msm8960_ext_spk_power_amp_on(TOP_SPK_AMP);
  282. else {
  283. pr_err("%s() Invalid Speaker Widget = %s\n",
  284. __func__, w->name);
  285. return -EINVAL;
  286. }
  287. } else {
  288. if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
  289. msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
  290. else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
  291. msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
  292. else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
  293. msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
  294. else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
  295. msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
  296. else if (!strncmp(w->name, "Ext Spk Top", 12))
  297. msm8960_ext_spk_power_amp_off(TOP_SPK_AMP);
  298. else {
  299. pr_err("%s() Invalid Speaker Widget = %s\n",
  300. __func__, w->name);
  301. return -EINVAL;
  302. }
  303. }
  304. return 0;
  305. }
  306. static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
  307. bool dapm)
  308. {
  309. int r = 0;
  310. pr_debug("%s: enable = %d\n", __func__, enable);
  311. mutex_lock(&cdc_mclk_mutex);
  312. if (enable) {
  313. clk_users++;
  314. pr_debug("%s: clk_users = %d\n", __func__, clk_users);
  315. if (clk_users == 1) {
  316. if (codec_clk) {
  317. clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
  318. clk_prepare_enable(codec_clk);
  319. tabla_mclk_enable(codec, 1, dapm);
  320. } else {
  321. pr_err("%s: Error setting Tabla MCLK\n",
  322. __func__);
  323. clk_users--;
  324. r = -EINVAL;
  325. }
  326. }
  327. } else {
  328. if (clk_users > 0) {
  329. clk_users--;
  330. pr_debug("%s: clk_users = %d\n", __func__, clk_users);
  331. if (clk_users == 0) {
  332. pr_debug("%s: disabling MCLK. clk_users = %d\n",
  333. __func__, clk_users);
  334. tabla_mclk_enable(codec, 0, dapm);
  335. clk_disable_unprepare(codec_clk);
  336. }
  337. } else {
  338. pr_err("%s: Error releasing Tabla MCLK\n", __func__);
  339. r = -EINVAL;
  340. }
  341. }
  342. mutex_unlock(&cdc_mclk_mutex);
  343. return r;
  344. }
  345. static bool msm8960_swap_gnd_mic(struct snd_soc_codec *codec)
  346. {
  347. int value = gpio_get_value_cansleep(us_euro_sel_gpio);
  348. pr_debug("%s: US EURO select switch %d to %d\n", __func__, value,
  349. !value);
  350. gpio_set_value_cansleep(us_euro_sel_gpio, !value);
  351. return true;
  352. }
  353. static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
  354. struct snd_kcontrol *kcontrol, int event)
  355. {
  356. pr_debug("%s: event = %d\n", __func__, event);
  357. switch (event) {
  358. case SND_SOC_DAPM_PRE_PMU:
  359. return msm8960_enable_codec_ext_clk(w->codec, 1, true);
  360. case SND_SOC_DAPM_POST_PMD:
  361. return msm8960_enable_codec_ext_clk(w->codec, 0, true);
  362. }
  363. return 0;
  364. }
  365. static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
  366. SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
  367. msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
  368. SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
  369. SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
  370. SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
  371. SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
  372. SND_SOC_DAPM_SPK("Ext Spk Top", msm8960_spkramp_event),
  373. SND_SOC_DAPM_MIC("Handset Mic", NULL),
  374. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  375. SND_SOC_DAPM_MIC("Digital Mic1", NULL),
  376. SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
  377. SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
  378. SND_SOC_DAPM_MIC("Digital Mic1", NULL),
  379. SND_SOC_DAPM_MIC("Digital Mic2", NULL),
  380. SND_SOC_DAPM_MIC("Digital Mic3", NULL),
  381. SND_SOC_DAPM_MIC("Digital Mic4", NULL),
  382. SND_SOC_DAPM_MIC("Digital Mic5", NULL),
  383. SND_SOC_DAPM_MIC("Digital Mic6", NULL),
  384. };
  385. static const struct snd_soc_dapm_route common_audio_map[] = {
  386. {"RX_BIAS", NULL, "MCLK"},
  387. {"LDO_H", NULL, "MCLK"},
  388. /* Speaker path */
  389. {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
  390. {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
  391. {"Ext Spk Top Pos", NULL, "LINEOUT2"},
  392. {"Ext Spk Top Neg", NULL, "LINEOUT4"},
  393. {"Ext Spk Top", NULL, "LINEOUT5"},
  394. /* Microphone path */
  395. {"AMIC1", NULL, "MIC BIAS1 Internal1"},
  396. {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
  397. {"AMIC2", NULL, "MIC BIAS2 External"},
  398. {"MIC BIAS2 External", NULL, "Headset Mic"},
  399. /**
  400. * AMIC3 and AMIC4 inputs are connected to ANC microphones
  401. * These mics are biased differently on CDP and FLUID
  402. * routing entries below are based on bias arrangement
  403. * on FLUID.
  404. */
  405. {"AMIC3", NULL, "MIC BIAS3 Internal1"},
  406. {"MIC BIAS3 Internal1", NULL, "MIC BIAS2 External"},
  407. {"MIC BIAS2 External", NULL, "ANCRight Headset Mic"},
  408. {"AMIC4", NULL, "MIC BIAS1 Internal2"},
  409. {"MIC BIAS1 Internal2", NULL, "MIC BIAS2 External"},
  410. {"MIC BIAS2 External", NULL, "ANCLeft Headset Mic"},
  411. {"HEADPHONE", NULL, "LDO_H"},
  412. /**
  413. * The digital Mic routes are setup considering
  414. * fluid as default device.
  415. */
  416. /**
  417. * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
  418. * Digital Mic GM5 on CDP mainboard.
  419. * Conncted to DMIC2 Input on Tabla codec.
  420. */
  421. {"DMIC2", NULL, "MIC BIAS1 External"},
  422. {"MIC BIAS1 External", NULL, "Digital Mic1"},
  423. /**
  424. * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
  425. * Digital Mic GM6 on CDP mainboard.
  426. * Conncted to DMIC1 Input on Tabla codec.
  427. */
  428. {"DMIC1", NULL, "MIC BIAS1 External"},
  429. {"MIC BIAS1 External", NULL, "Digital Mic2"},
  430. /**
  431. * Digital Mic3. Back Bottom Digital Mic on Fluid.
  432. * Digital Mic GM1 on CDP mainboard.
  433. * Conncted to DMIC4 Input on Tabla codec.
  434. */
  435. {"DMIC4", NULL, "MIC BIAS3 External"},
  436. {"MIC BIAS3 External", NULL, "Digital Mic3"},
  437. /**
  438. * Digital Mic4. Back top Digital Mic on Fluid.
  439. * Digital Mic GM2 on CDP mainboard.
  440. * Conncted to DMIC3 Input on Tabla codec.
  441. */
  442. {"DMIC3", NULL, "MIC BIAS3 External"},
  443. {"MIC BIAS3 External", NULL, "Digital Mic4"},
  444. /**
  445. * Digital Mic5. Front top Digital Mic on Fluid.
  446. * Digital Mic GM3 on CDP mainboard.
  447. * Conncted to DMIC5 Input on Tabla codec.
  448. */
  449. {"DMIC5", NULL, "MIC BIAS4 External"},
  450. {"MIC BIAS4 External", NULL, "Digital Mic5"},
  451. /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
  452. * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
  453. */
  454. {"DMIC6", NULL, "MIC BIAS4 External"},
  455. {"MIC BIAS4 External", NULL, "Digital Mic6"},
  456. };
  457. static const char *spk_function[] = {"Off", "On"};
  458. static const char *slim0_rx_ch_text[] = {"One", "Two"};
  459. static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
  460. static const char * const hdmi_rate[] = {"Default", "Variable"};
  461. static const struct soc_enum msm8960_enum[] = {
  462. SOC_ENUM_SINGLE_EXT(2, spk_function),
  463. SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
  464. SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
  465. SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
  466. };
  467. static const char *btsco_rate_text[] = {"8000", "16000"};
  468. static const struct soc_enum msm8960_btsco_enum[] = {
  469. SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
  470. };
  471. static const char *auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
  472. static const struct soc_enum msm8960_auxpcm_enum[] = {
  473. SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
  474. };
  475. static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
  476. struct snd_ctl_elem_value *ucontrol)
  477. {
  478. pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
  479. msm8960_slim_0_rx_ch);
  480. ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
  481. return 0;
  482. }
  483. static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
  484. struct snd_ctl_elem_value *ucontrol)
  485. {
  486. msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
  487. pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
  488. msm8960_slim_0_rx_ch);
  489. return 1;
  490. }
  491. static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
  492. struct snd_ctl_elem_value *ucontrol)
  493. {
  494. pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
  495. msm8960_slim_0_tx_ch);
  496. ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
  497. return 0;
  498. }
  499. static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
  500. struct snd_ctl_elem_value *ucontrol)
  501. {
  502. msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
  503. pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
  504. msm8960_slim_0_tx_ch);
  505. return 1;
  506. }
  507. static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
  508. struct snd_ctl_elem_value *ucontrol)
  509. {
  510. pr_debug("%s: msm8960_btsco_rate = %d", __func__, msm8960_btsco_rate);
  511. ucontrol->value.integer.value[0] = msm8960_btsco_rate;
  512. return 0;
  513. }
  514. static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
  515. struct snd_ctl_elem_value *ucontrol)
  516. {
  517. switch (ucontrol->value.integer.value[0]) {
  518. case 8000:
  519. msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
  520. break;
  521. case 16000:
  522. msm8960_btsco_rate = SAMPLE_RATE_16KHZ;
  523. break;
  524. default:
  525. msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
  526. break;
  527. }
  528. pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
  529. return 0;
  530. }
  531. static int msm8960_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
  532. struct snd_ctl_elem_value *ucontrol)
  533. {
  534. pr_debug("%s: msm8960_auxpcm_rate = %d", __func__,
  535. msm8960_auxpcm_rate);
  536. ucontrol->value.integer.value[0] = msm8960_auxpcm_rate;
  537. return 0;
  538. }
  539. static int msm8960_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
  540. struct snd_ctl_elem_value *ucontrol)
  541. {
  542. switch (ucontrol->value.integer.value[0]) {
  543. case 0:
  544. msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
  545. break;
  546. case 1:
  547. msm8960_auxpcm_rate = SAMPLE_RATE_16KHZ;
  548. break;
  549. default:
  550. msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
  551. break;
  552. }
  553. pr_debug("%s: msm8960_auxpcm_rate = %d"
  554. "ucontrol->value.integer.value[0] = %d\n", __func__,
  555. msm8960_auxpcm_rate,
  556. (int)ucontrol->value.integer.value[0]);
  557. return 0;
  558. }
  559. static int msm8960_hdmi_rate_put(struct snd_kcontrol *kcontrol,
  560. struct snd_ctl_elem_value *ucontrol)
  561. {
  562. hdmi_rate_variable = ucontrol->value.integer.value[0];
  563. pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
  564. return 0;
  565. }
  566. static int msm8960_hdmi_rate_get(struct snd_kcontrol *kcontrol,
  567. struct snd_ctl_elem_value *ucontrol)
  568. {
  569. ucontrol->value.integer.value[0] = hdmi_rate_variable;
  570. return 0;
  571. }
  572. static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
  573. SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
  574. msm8960_set_spk),
  575. SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
  576. msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
  577. SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
  578. msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
  579. SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
  580. msm8960_btsco_rate_get, msm8960_btsco_rate_put),
  581. SOC_ENUM_EXT("AUX PCM SampleRate", msm8960_auxpcm_enum[0],
  582. msm8960_auxpcm_rate_get, msm8960_auxpcm_rate_put),
  583. SOC_ENUM_EXT("HDMI RX Rate", msm8960_enum[3],
  584. msm8960_hdmi_rate_get,
  585. msm8960_hdmi_rate_put),
  586. };
  587. static void *def_tabla_mbhc_cal(void)
  588. {
  589. void *tabla_cal;
  590. struct tabla_mbhc_btn_detect_cfg *btn_cfg;
  591. u16 *btn_low, *btn_high;
  592. u8 *n_ready, *n_cic, *gain;
  593. tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
  594. TABLA_MBHC_DEF_RLOADS),
  595. GFP_KERNEL);
  596. if (!tabla_cal) {
  597. pr_err("%s: out of memory\n", __func__);
  598. return NULL;
  599. }
  600. #define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
  601. S(t_ldoh, 100);
  602. S(t_bg_fast_settle, 100);
  603. S(t_shutdown_plug_rem, 255);
  604. S(mbhc_nsa, 4);
  605. S(mbhc_navg, 4);
  606. #undef S
  607. #define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
  608. S(mic_current, TABLA_PID_MIC_5_UA);
  609. S(hph_current, TABLA_PID_MIC_5_UA);
  610. S(t_mic_pid, 100);
  611. S(t_ins_complete, 250);
  612. S(t_ins_retry, 200);
  613. #undef S
  614. #define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
  615. S(v_no_mic, 30);
  616. S(v_hs_max, 2400);
  617. #undef S
  618. #define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
  619. S(c[0], 62);
  620. S(c[1], 124);
  621. S(nc, 1);
  622. S(n_meas, 3);
  623. S(mbhc_nsc, 11);
  624. S(n_btn_meas, 1);
  625. S(n_btn_con, 2);
  626. S(num_btn, TABLA_MBHC_DEF_BUTTONS);
  627. S(v_btn_press_delta_sta, 100);
  628. S(v_btn_press_delta_cic, 50);
  629. #undef S
  630. btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
  631. btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
  632. btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
  633. btn_low[0] = -50;
  634. btn_high[0] = 21;
  635. btn_low[1] = 22;
  636. btn_high[1] = 67;
  637. btn_low[2] = 68;
  638. btn_high[2] = 111;
  639. btn_low[3] = 112;
  640. btn_high[3] = 153;
  641. btn_low[4] = 154;
  642. btn_high[4] = 191;
  643. btn_low[5] = 192;
  644. btn_high[5] = 233;
  645. btn_low[6] = 234;
  646. btn_high[6] = 272;
  647. btn_low[7] = 273;
  648. btn_high[7] = 400;
  649. n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
  650. n_ready[0] = 80;
  651. n_ready[1] = 68;
  652. n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
  653. n_cic[0] = 60;
  654. n_cic[1] = 47;
  655. gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
  656. gain[0] = 11;
  657. gain[1] = 9;
  658. return tabla_cal;
  659. }
  660. static int msm8960_hw_params(struct snd_pcm_substream *substream,
  661. struct snd_pcm_hw_params *params)
  662. {
  663. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  664. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  665. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  666. int ret = 0;
  667. unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
  668. unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
  669. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  670. pr_debug("%s: rx_0_ch=%d\n", __func__, msm8960_slim_0_rx_ch);
  671. ret = snd_soc_dai_get_channel_map(codec_dai,
  672. &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
  673. if (ret < 0) {
  674. pr_err("%s: failed to get codec chan map\n", __func__);
  675. goto end;
  676. }
  677. ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
  678. msm8960_slim_0_rx_ch, rx_ch);
  679. if (ret < 0) {
  680. pr_err("%s: failed to set cpu chan map\n", __func__);
  681. goto end;
  682. }
  683. } else {
  684. pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
  685. codec_dai->name, codec_dai->id, msm8960_slim_0_tx_ch);
  686. ret = snd_soc_dai_get_channel_map(codec_dai,
  687. &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
  688. if (ret < 0) {
  689. pr_err("%s: failed to get codec chan map\n", __func__);
  690. goto end;
  691. }
  692. ret = snd_soc_dai_set_channel_map(cpu_dai,
  693. msm8960_slim_0_tx_ch, tx_ch, 0 , 0);
  694. if (ret < 0) {
  695. pr_err("%s: failed to set cpu chan map\n", __func__);
  696. goto end;
  697. }
  698. }
  699. end:
  700. return ret;
  701. }
  702. static int msm8960_slimbus_2_hw_params(struct snd_pcm_substream *substream,
  703. struct snd_pcm_hw_params *params)
  704. {
  705. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  706. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  707. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  708. int ret = 0;
  709. unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
  710. unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
  711. unsigned int num_tx_ch = 0;
  712. unsigned int num_rx_ch = 0;
  713. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  714. num_rx_ch = params_channels(params);
  715. pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
  716. codec_dai->name, codec_dai->id, num_rx_ch);
  717. ret = snd_soc_dai_get_channel_map(codec_dai,
  718. &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
  719. if (ret < 0) {
  720. pr_err("%s: failed to get codec chan map\n", __func__);
  721. goto end;
  722. }
  723. ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
  724. num_rx_ch, rx_ch);
  725. if (ret < 0) {
  726. pr_err("%s: failed to set cpu chan map\n", __func__);
  727. goto end;
  728. }
  729. } else {
  730. num_tx_ch = params_channels(params);
  731. pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
  732. codec_dai->name, codec_dai->id, num_tx_ch);
  733. ret = snd_soc_dai_get_channel_map(codec_dai,
  734. &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
  735. if (ret < 0) {
  736. pr_err("%s: failed to get codec chan map\n", __func__);
  737. goto end;
  738. }
  739. ret = snd_soc_dai_set_channel_map(cpu_dai,
  740. num_tx_ch, tx_ch, 0 , 0);
  741. if (ret < 0) {
  742. pr_err("%s: failed to set cpu chan map\n", __func__);
  743. goto end;
  744. }
  745. }
  746. end:
  747. return ret;
  748. }
  749. static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
  750. {
  751. int err;
  752. struct snd_soc_codec *codec = rtd->codec;
  753. struct snd_soc_dapm_context *dapm = &codec->dapm;
  754. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  755. struct pm_gpio jack_gpio_cfg = {
  756. .direction = PM_GPIO_DIR_IN,
  757. .pull = PM_GPIO_PULL_UP_1P5,
  758. .function = PM_GPIO_FUNC_NORMAL,
  759. .vin_sel = 2,
  760. .inv_int_pol = 0,
  761. };
  762. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  763. /* Tabla SLIMBUS configuration
  764. * RX1, RX2, RX3, RX4, RX5, RX6, RX7
  765. * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8
  766. */
  767. unsigned int rx_ch[TABLA_RX_MAX] = {138, 139, 140, 141, 142, 143, 144};
  768. unsigned int tx_ch[TABLA_TX_MAX] = {128, 129, 130, 131, 132, 133, 134,
  769. 135, 136, 137};
  770. pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
  771. if (machine_is_msm8960_liquid()) {
  772. top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
  773. bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
  774. }
  775. snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
  776. ARRAY_SIZE(msm8960_dapm_widgets));
  777. snd_soc_dapm_add_routes(dapm, common_audio_map,
  778. ARRAY_SIZE(common_audio_map));
  779. snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
  780. snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
  781. snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
  782. snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
  783. snd_soc_dapm_sync(dapm);
  784. err = snd_soc_jack_new(codec, "Headset Jack",
  785. (SND_JACK_HEADSET | SND_JACK_LINEOUT |
  786. SND_JACK_OC_HPHL | SND_JACK_OC_HPHR |
  787. SND_JACK_UNSUPPORTED),
  788. &hs_jack);
  789. if (err) {
  790. pr_err("failed to create new jack\n");
  791. return err;
  792. }
  793. err = snd_soc_jack_new(codec, "Button Jack",
  794. TABLA_JACK_BUTTON_MASK, &button_jack);
  795. if (err) {
  796. pr_err("failed to create new jack\n");
  797. return err;
  798. }
  799. codec_clk = clk_get(cpu_dai->dev, "osr_clk");
  800. if (machine_is_msm8960_cdp())
  801. mbhc_cfg.swap_gnd_mic = msm8960_swap_gnd_mic;
  802. if (hs_micbias_always_on)
  803. mbhc_cfg.micbias_always_on = true;
  804. if (hs_detect_use_gpio) {
  805. mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
  806. mbhc_cfg.gpio_irq = JACK_DETECT_INT;
  807. if (hs_detect_extn_cable)
  808. mbhc_cfg.detect_extn_cable = true;
  809. }
  810. if (mbhc_cfg.gpio) {
  811. err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
  812. if (err) {
  813. pr_err("%s: pm8xxx_gpio_config JACK_DETECT failed %d\n",
  814. __func__, err);
  815. return err;
  816. }
  817. }
  818. mbhc_cfg.read_fw_bin = hs_detect_use_firmware;
  819. err = tabla_hs_detect(codec, &mbhc_cfg);
  820. snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
  821. tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
  822. return err;
  823. }
  824. static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  825. struct snd_pcm_hw_params *params)
  826. {
  827. struct snd_interval *rate = hw_param_interval(params,
  828. SNDRV_PCM_HW_PARAM_RATE);
  829. struct snd_interval *channels = hw_param_interval(params,
  830. SNDRV_PCM_HW_PARAM_CHANNELS);
  831. pr_debug("%s()\n", __func__);
  832. rate->min = rate->max = 48000;
  833. channels->min = channels->max = msm8960_slim_0_rx_ch;
  834. return 0;
  835. }
  836. static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  837. struct snd_pcm_hw_params *params)
  838. {
  839. struct snd_interval *rate = hw_param_interval(params,
  840. SNDRV_PCM_HW_PARAM_RATE);
  841. struct snd_interval *channels = hw_param_interval(params,
  842. SNDRV_PCM_HW_PARAM_CHANNELS);
  843. pr_debug("%s()\n", __func__);
  844. rate->min = rate->max = 48000;
  845. channels->min = channels->max = msm8960_slim_0_tx_ch;
  846. return 0;
  847. }
  848. static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  849. struct snd_pcm_hw_params *params)
  850. {
  851. struct snd_interval *rate = hw_param_interval(params,
  852. SNDRV_PCM_HW_PARAM_RATE);
  853. pr_debug("%s()\n", __func__);
  854. rate->min = rate->max = 48000;
  855. return 0;
  856. }
  857. static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  858. struct snd_pcm_hw_params *params)
  859. {
  860. struct snd_interval *rate = hw_param_interval(params,
  861. SNDRV_PCM_HW_PARAM_RATE);
  862. struct snd_interval *channels = hw_param_interval(params,
  863. SNDRV_PCM_HW_PARAM_CHANNELS);
  864. pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
  865. channels->min, channels->max);
  866. if (channels->max < 2)
  867. channels->min = channels->max = 2;
  868. if (!hdmi_rate_variable)
  869. rate->min = rate->max = 48000;
  870. return 0;
  871. }
  872. static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  873. struct snd_pcm_hw_params *params)
  874. {
  875. struct snd_interval *rate = hw_param_interval(params,
  876. SNDRV_PCM_HW_PARAM_RATE);
  877. struct snd_interval *channels = hw_param_interval(params,
  878. SNDRV_PCM_HW_PARAM_CHANNELS);
  879. rate->min = rate->max = msm8960_btsco_rate;
  880. channels->min = channels->max = msm8960_btsco_ch;
  881. return 0;
  882. }
  883. static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
  884. struct snd_pcm_hw_params *params)
  885. {
  886. struct snd_interval *rate = hw_param_interval(params,
  887. SNDRV_PCM_HW_PARAM_RATE);
  888. struct snd_interval *channels = hw_param_interval(params,
  889. SNDRV_PCM_HW_PARAM_CHANNELS);
  890. rate->min = rate->max = msm8960_auxpcm_rate;
  891. /* PCM only supports mono output */
  892. channels->min = channels->max = 1;
  893. return 0;
  894. }
  895. static int msm8960_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  896. struct snd_pcm_hw_params *params)
  897. {
  898. struct snd_interval *rate = hw_param_interval(params,
  899. SNDRV_PCM_HW_PARAM_RATE);
  900. pr_debug("%s()\n", __func__);
  901. rate->min = rate->max = 48000;
  902. return 0;
  903. }
  904. static int msm8960_aux_pcm_get_gpios(void)
  905. {
  906. int ret = 0;
  907. pr_debug("%s\n", __func__);
  908. ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
  909. if (ret < 0) {
  910. pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
  911. __func__, GPIO_AUX_PCM_DOUT);
  912. goto fail_dout;
  913. }
  914. ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
  915. if (ret < 0) {
  916. pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
  917. __func__, GPIO_AUX_PCM_DIN);
  918. goto fail_din;
  919. }
  920. ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
  921. if (ret < 0) {
  922. pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
  923. __func__, GPIO_AUX_PCM_SYNC);
  924. goto fail_sync;
  925. }
  926. ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
  927. if (ret < 0) {
  928. pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
  929. __func__, GPIO_AUX_PCM_CLK);
  930. goto fail_clk;
  931. }
  932. return 0;
  933. fail_clk:
  934. gpio_free(GPIO_AUX_PCM_SYNC);
  935. fail_sync:
  936. gpio_free(GPIO_AUX_PCM_DIN);
  937. fail_din:
  938. gpio_free(GPIO_AUX_PCM_DOUT);
  939. fail_dout:
  940. return ret;
  941. }
  942. static int msm8960_aux_pcm_free_gpios(void)
  943. {
  944. gpio_free(GPIO_AUX_PCM_DIN);
  945. gpio_free(GPIO_AUX_PCM_DOUT);
  946. gpio_free(GPIO_AUX_PCM_SYNC);
  947. gpio_free(GPIO_AUX_PCM_CLK);
  948. return 0;
  949. }
  950. static int msm8960_startup(struct snd_pcm_substream *substream)
  951. {
  952. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  953. pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
  954. __func__, rtd->dai_link->stream_name,
  955. rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
  956. return 0;
  957. }
  958. static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
  959. {
  960. int ret = 0;
  961. pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
  962. __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
  963. if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
  964. ret = msm8960_aux_pcm_get_gpios();
  965. if (ret < 0) {
  966. pr_err("%s: Aux PCM GPIO request failed\n", __func__);
  967. return -EINVAL;
  968. }
  969. return 0;
  970. }
  971. static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
  972. {
  973. pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
  974. __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
  975. if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
  976. msm8960_aux_pcm_free_gpios();
  977. }
  978. static void msm8960_shutdown(struct snd_pcm_substream *substream)
  979. {
  980. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  981. pr_debug("%s(): dai_link str_name = %s cpu_dai = %s codec_dai = %s\n",
  982. __func__, rtd->dai_link->stream_name,
  983. rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
  984. }
  985. static struct snd_soc_ops msm8960_be_ops = {
  986. .startup = msm8960_startup,
  987. .hw_params = msm8960_hw_params,
  988. .shutdown = msm8960_shutdown,
  989. };
  990. static struct snd_soc_ops msm8960_auxpcm_be_ops = {
  991. .startup = msm8960_auxpcm_startup,
  992. .shutdown = msm8960_auxpcm_shutdown,
  993. };
  994. static struct snd_soc_ops msm8960_slimbus_2_be_ops = {
  995. .startup = msm8960_startup,
  996. .hw_params = msm8960_slimbus_2_hw_params,
  997. .shutdown = msm8960_shutdown,
  998. };
  999. /* Digital audio interface glue - connects codec <---> CPU */
  1000. static struct snd_soc_dai_link msm8960_dai_common[] = {
  1001. /* FrontEnd DAI Links */
  1002. {
  1003. .name = "MSM8960 Media1",
  1004. .stream_name = "MultiMedia1",
  1005. .cpu_dai_name = "MultiMedia1",
  1006. .platform_name = "msm-pcm-dsp",
  1007. .dynamic = 1,
  1008. .codec_dai_name = "snd-soc-dummy-dai",
  1009. .codec_name = "snd-soc-dummy",
  1010. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1011. .ignore_suspend = 1,
  1012. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1013. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
  1014. },
  1015. {
  1016. .name = "MSM8960 Media2",
  1017. .stream_name = "MultiMedia2",
  1018. .cpu_dai_name = "MultiMedia2",
  1019. .platform_name = "msm-multi-ch-pcm-dsp",
  1020. .dynamic = 1,
  1021. .codec_dai_name = "snd-soc-dummy-dai",
  1022. .codec_name = "snd-soc-dummy",
  1023. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1024. .ignore_suspend = 1,
  1025. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1026. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
  1027. },
  1028. {
  1029. .name = "Circuit-Switch Voice",
  1030. .stream_name = "CS-Voice",
  1031. .cpu_dai_name = "CS-VOICE",
  1032. .platform_name = "msm-pcm-voice",
  1033. .dynamic = 1,
  1034. .codec_dai_name = "snd-soc-dummy-dai",
  1035. .codec_name = "snd-soc-dummy",
  1036. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1037. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1038. .ignore_suspend = 1,
  1039. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1040. .be_id = MSM_FRONTEND_DAI_CS_VOICE,
  1041. },
  1042. {
  1043. .name = "MSM VoIP",
  1044. .stream_name = "VoIP",
  1045. .cpu_dai_name = "VoIP",
  1046. .platform_name = "msm-voip-dsp",
  1047. .dynamic = 1,
  1048. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1049. .codec_dai_name = "snd-soc-dummy-dai",
  1050. .codec_name = "snd-soc-dummy",
  1051. .ignore_suspend = 1,
  1052. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1053. .be_id = MSM_FRONTEND_DAI_VOIP,
  1054. },
  1055. {
  1056. .name = "MSM8960 LPA",
  1057. .stream_name = "LPA",
  1058. .cpu_dai_name = "MultiMedia3",
  1059. .platform_name = "msm-pcm-lpa",
  1060. .dynamic = 1,
  1061. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1062. .codec_dai_name = "snd-soc-dummy-dai",
  1063. .codec_name = "snd-soc-dummy",
  1064. .ignore_suspend = 1,
  1065. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1066. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
  1067. },
  1068. /* Hostless PMC purpose */
  1069. {
  1070. .name = "SLIMBUS_0 Hostless",
  1071. .stream_name = "SLIMBUS_0 Hostless",
  1072. .cpu_dai_name = "SLIMBUS0_HOSTLESS",
  1073. .platform_name = "msm-pcm-hostless",
  1074. .dynamic = 1,
  1075. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1076. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1077. .ignore_suspend = 1,
  1078. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1079. .codec_dai_name = "snd-soc-dummy-dai",
  1080. .codec_name = "snd-soc-dummy",
  1081. },
  1082. {
  1083. .name = "INT_FM Hostless",
  1084. .stream_name = "INT_FM Hostless",
  1085. .cpu_dai_name = "INT_FM_HOSTLESS",
  1086. .platform_name = "msm-pcm-hostless",
  1087. .dynamic = 1,
  1088. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1089. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1090. .ignore_suspend = 1,
  1091. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1092. .codec_dai_name = "snd-soc-dummy-dai",
  1093. .codec_name = "snd-soc-dummy",
  1094. },
  1095. {
  1096. .name = "MSM AFE-PCM RX",
  1097. .stream_name = "AFE-PROXY RX",
  1098. .cpu_dai_name = "msm-dai-q6.241",
  1099. .codec_name = "msm-stub-codec.1",
  1100. .codec_dai_name = "msm-stub-rx",
  1101. .platform_name = "msm-pcm-afe",
  1102. .ignore_suspend = 1,
  1103. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1104. },
  1105. {
  1106. .name = "MSM AFE-PCM TX",
  1107. .stream_name = "AFE-PROXY TX",
  1108. .cpu_dai_name = "msm-dai-q6.240",
  1109. .codec_name = "msm-stub-codec.1",
  1110. .codec_dai_name = "msm-stub-tx",
  1111. .platform_name = "msm-pcm-afe",
  1112. .ignore_suspend = 1,
  1113. },
  1114. {
  1115. .name = "MSM8960 Compr",
  1116. .stream_name = "COMPR",
  1117. .cpu_dai_name = "MultiMedia4",
  1118. .platform_name = "msm-compr-dsp",
  1119. .dynamic = 1,
  1120. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1121. .codec_dai_name = "snd-soc-dummy-dai",
  1122. .codec_name = "snd-soc-dummy",
  1123. .ignore_suspend = 1,
  1124. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1125. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
  1126. },
  1127. {
  1128. .name = "AUXPCM Hostless",
  1129. .stream_name = "AUXPCM Hostless",
  1130. .cpu_dai_name = "AUXPCM_HOSTLESS",
  1131. .platform_name = "msm-pcm-hostless",
  1132. .dynamic = 1,
  1133. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1134. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1135. .ignore_suspend = 1,
  1136. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1137. .codec_dai_name = "snd-soc-dummy-dai",
  1138. .codec_name = "snd-soc-dummy",
  1139. },
  1140. /* HDMI Hostless */
  1141. {
  1142. .name = "HDMI_RX_HOSTLESS",
  1143. .stream_name = "HDMI_RX_HOSTLESS",
  1144. .cpu_dai_name = "HDMI_HOSTLESS",
  1145. .platform_name = "msm-pcm-hostless",
  1146. .dynamic = 1,
  1147. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1148. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1149. .ignore_suspend = 1,
  1150. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1151. .codec_dai_name = "snd-soc-dummy-dai",
  1152. .codec_name = "snd-soc-dummy",
  1153. },
  1154. {
  1155. .name = "VoLTE",
  1156. .stream_name = "VoLTE",
  1157. .cpu_dai_name = "VoLTE",
  1158. .platform_name = "msm-pcm-voice",
  1159. .dynamic = 1,
  1160. .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
  1161. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1162. .ignore_suspend = 1,
  1163. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1164. .codec_dai_name = "snd-soc-dummy-dai",
  1165. .codec_name = "snd-soc-dummy",
  1166. .be_id = MSM_FRONTEND_DAI_VOLTE,
  1167. },
  1168. {
  1169. .name = "Voice2",
  1170. .stream_name = "Voice2",
  1171. .cpu_dai_name = "Voice2",
  1172. .platform_name = "msm-pcm-voice",
  1173. .dynamic = 1,
  1174. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  1175. SND_SOC_DPCM_TRIGGER_POST},
  1176. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1177. .ignore_suspend = 1,
  1178. .ignore_pmdown_time = 1,/* this dainlink has playback support */
  1179. .codec_dai_name = "snd-soc-dummy-dai",
  1180. .codec_name = "snd-soc-dummy",
  1181. .be_id = MSM_FRONTEND_DAI_VOICE2,
  1182. },
  1183. {
  1184. .name = "MSM8960 LowLatency",
  1185. .stream_name = "MultiMedia5",
  1186. .cpu_dai_name = "MultiMedia5",
  1187. .platform_name = "msm-lowlatency-pcm-dsp",
  1188. .dynamic = 1,
  1189. .codec_dai_name = "snd-soc-dummy-dai",
  1190. .codec_name = "snd-soc-dummy",
  1191. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  1192. SND_SOC_DPCM_TRIGGER_POST},
  1193. .ignore_suspend = 1,
  1194. /* this dainlink has playback support */
  1195. .ignore_pmdown_time = 1,
  1196. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
  1197. },
  1198. {
  1199. .name = "MSM8960 Media6",
  1200. .stream_name = "MultiMedia6",
  1201. .cpu_dai_name = "MultiMedia6",
  1202. .platform_name = "msm-multi-ch-pcm-dsp",
  1203. .dynamic = 1,
  1204. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  1205. SND_SOC_DPCM_TRIGGER_POST},
  1206. .codec_dai_name = "snd-soc-dummy-dai",
  1207. .codec_name = "snd-soc-dummy",
  1208. .ignore_suspend = 1,
  1209. .ignore_pmdown_time = 1, /* this dailink has playback support */
  1210. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6
  1211. },
  1212. {
  1213. .name = "MSM8960 Compr2",
  1214. .stream_name = "COMPR2",
  1215. .cpu_dai_name = "MultiMedia7",
  1216. .platform_name = "msm-compr-dsp",
  1217. .dynamic = 1,
  1218. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  1219. SND_SOC_DPCM_TRIGGER_POST},
  1220. .codec_dai_name = "snd-soc-dummy-dai",
  1221. .codec_name = "snd-soc-dummy",
  1222. .ignore_suspend = 1,
  1223. .ignore_pmdown_time = 1, /* this dailink has playback support */
  1224. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
  1225. },
  1226. {
  1227. .name = "MSM8960 Compr3",
  1228. .stream_name = "COMPR3",
  1229. .cpu_dai_name = "MultiMedia8",
  1230. .platform_name = "msm-compr-dsp",
  1231. .dynamic = 1,
  1232. .trigger = {SND_SOC_DPCM_TRIGGER_POST,
  1233. SND_SOC_DPCM_TRIGGER_POST},
  1234. .codec_dai_name = "snd-soc-dummy-dai",
  1235. .codec_name = "snd-soc-dummy",
  1236. .ignore_suspend = 1,
  1237. .ignore_pmdown_time = 1, /* this dailink has playback support */
  1238. .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
  1239. },
  1240. /* Backend BT/FM DAI Links */
  1241. {
  1242. .name = LPASS_BE_INT_BT_SCO_RX,
  1243. .stream_name = "Internal BT-SCO Playback",
  1244. .cpu_dai_name = "msm-dai-q6.12288",
  1245. .platform_name = "msm-pcm-routing",
  1246. .codec_name = "msm-stub-codec.1",
  1247. .codec_dai_name = "msm-stub-rx",
  1248. .no_pcm = 1,
  1249. .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
  1250. .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
  1251. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1252. },
  1253. {
  1254. .name = LPASS_BE_INT_BT_SCO_TX,
  1255. .stream_name = "Internal BT-SCO Capture",
  1256. .cpu_dai_name = "msm-dai-q6.12289",
  1257. .platform_name = "msm-pcm-routing",
  1258. .codec_name = "msm-stub-codec.1",
  1259. .codec_dai_name = "msm-stub-tx",
  1260. .no_pcm = 1,
  1261. .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
  1262. .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
  1263. },
  1264. {
  1265. .name = LPASS_BE_INT_FM_RX,
  1266. .stream_name = "Internal FM Playback",
  1267. .cpu_dai_name = "msm-dai-q6.12292",
  1268. .platform_name = "msm-pcm-routing",
  1269. .codec_name = "msm-stub-codec.1",
  1270. .codec_dai_name = "msm-stub-rx",
  1271. .no_pcm = 1,
  1272. .be_id = MSM_BACKEND_DAI_INT_FM_RX,
  1273. .be_hw_params_fixup = msm8960_be_hw_params_fixup,
  1274. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1275. },
  1276. {
  1277. .name = LPASS_BE_INT_FM_TX,
  1278. .stream_name = "Internal FM Capture",
  1279. .cpu_dai_name = "msm-dai-q6.12293",
  1280. .platform_name = "msm-pcm-routing",
  1281. .codec_name = "msm-stub-codec.1",
  1282. .codec_dai_name = "msm-stub-tx",
  1283. .no_pcm = 1,
  1284. .be_id = MSM_BACKEND_DAI_INT_FM_TX,
  1285. .be_hw_params_fixup = msm8960_be_hw_params_fixup,
  1286. },
  1287. /* HDMI BACK END DAI Link */
  1288. {
  1289. .name = LPASS_BE_HDMI,
  1290. .stream_name = "HDMI Playback",
  1291. .cpu_dai_name = "msm-dai-q6-hdmi.8",
  1292. .platform_name = "msm-pcm-routing",
  1293. .codec_name = "msm-stub-codec.1",
  1294. .codec_dai_name = "msm-stub-rx",
  1295. .no_pcm = 1,
  1296. .be_id = MSM_BACKEND_DAI_HDMI_RX,
  1297. .be_hw_params_fixup = msm8960_hdmi_be_hw_params_fixup,
  1298. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1299. },
  1300. /* Backend AFE DAI Links */
  1301. {
  1302. .name = LPASS_BE_AFE_PCM_RX,
  1303. .stream_name = "AFE Playback",
  1304. .cpu_dai_name = "msm-dai-q6.224",
  1305. .platform_name = "msm-pcm-routing",
  1306. .codec_name = "msm-stub-codec.1",
  1307. .codec_dai_name = "msm-stub-rx",
  1308. .no_pcm = 1,
  1309. .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
  1310. .be_hw_params_fixup = msm8960_proxy_be_hw_params_fixup,
  1311. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1312. },
  1313. {
  1314. .name = LPASS_BE_AFE_PCM_TX,
  1315. .stream_name = "AFE Capture",
  1316. .cpu_dai_name = "msm-dai-q6.225",
  1317. .platform_name = "msm-pcm-routing",
  1318. .codec_name = "msm-stub-codec.1",
  1319. .codec_dai_name = "msm-stub-tx",
  1320. .no_pcm = 1,
  1321. .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
  1322. .be_hw_params_fixup = msm8960_proxy_be_hw_params_fixup,
  1323. },
  1324. /* AUX PCM Backend DAI Links */
  1325. {
  1326. .name = LPASS_BE_AUXPCM_RX,
  1327. .stream_name = "AUX PCM Playback",
  1328. .cpu_dai_name = "msm-dai-q6.2",
  1329. .platform_name = "msm-pcm-routing",
  1330. .codec_name = "msm-stub-codec.1",
  1331. .codec_dai_name = "msm-stub-rx",
  1332. .no_pcm = 1,
  1333. .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
  1334. .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
  1335. .ops = &msm8960_auxpcm_be_ops,
  1336. .ignore_pmdown_time = 1,
  1337. },
  1338. {
  1339. .name = LPASS_BE_AUXPCM_TX,
  1340. .stream_name = "AUX PCM Capture",
  1341. .cpu_dai_name = "msm-dai-q6.3",
  1342. .platform_name = "msm-pcm-routing",
  1343. .codec_name = "msm-stub-codec.1",
  1344. .codec_dai_name = "msm-stub-tx",
  1345. .no_pcm = 1,
  1346. .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
  1347. .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
  1348. .ops = &msm8960_auxpcm_be_ops,
  1349. },
  1350. /* Incall Music BACK END DAI Link */
  1351. {
  1352. .name = LPASS_BE_VOICE_PLAYBACK_TX,
  1353. .stream_name = "Voice Farend Playback",
  1354. .cpu_dai_name = "msm-dai-q6.32773",
  1355. .platform_name = "msm-pcm-routing",
  1356. .codec_name = "msm-stub-codec.1",
  1357. .codec_dai_name = "msm-stub-rx",
  1358. .no_pcm = 1,
  1359. .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
  1360. .be_hw_params_fixup = msm8960_be_hw_params_fixup,
  1361. },
  1362. /* Incall Record Uplink BACK END DAI Link */
  1363. {
  1364. .name = LPASS_BE_INCALL_RECORD_TX,
  1365. .stream_name = "Voice Uplink Capture",
  1366. .cpu_dai_name = "msm-dai-q6.32772",
  1367. .platform_name = "msm-pcm-routing",
  1368. .codec_name = "msm-stub-codec.1",
  1369. .codec_dai_name = "msm-stub-tx",
  1370. .no_pcm = 1,
  1371. .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
  1372. .be_hw_params_fixup = msm8960_be_hw_params_fixup,
  1373. },
  1374. /* Incall Record Downlink BACK END DAI Link */
  1375. {
  1376. .name = LPASS_BE_INCALL_RECORD_RX,
  1377. .stream_name = "Voice Downlink Capture",
  1378. .cpu_dai_name = "msm-dai-q6.32771",
  1379. .platform_name = "msm-pcm-routing",
  1380. .codec_name = "msm-stub-codec.1",
  1381. .codec_dai_name = "msm-stub-tx",
  1382. .no_pcm = 1,
  1383. .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
  1384. .be_hw_params_fixup = msm8960_be_hw_params_fixup,
  1385. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1386. },
  1387. };
  1388. static struct snd_soc_dai_link msm8960_dai_delta_tabla1x[] = {
  1389. /* Backend DAI Links */
  1390. {
  1391. .name = LPASS_BE_SLIMBUS_0_RX,
  1392. .stream_name = "Slimbus Playback",
  1393. .cpu_dai_name = "msm-dai-q6.16384",
  1394. .platform_name = "msm-pcm-routing",
  1395. .codec_name = "tabla1x_codec",
  1396. .codec_dai_name = "tabla_rx1",
  1397. .no_pcm = 1,
  1398. .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
  1399. .init = &msm8960_audrx_init,
  1400. .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
  1401. .ops = &msm8960_be_ops,
  1402. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1403. },
  1404. {
  1405. .name = LPASS_BE_SLIMBUS_0_TX,
  1406. .stream_name = "Slimbus Capture",
  1407. .cpu_dai_name = "msm-dai-q6.16385",
  1408. .platform_name = "msm-pcm-routing",
  1409. .codec_name = "tabla1x_codec",
  1410. .codec_dai_name = "tabla_tx1",
  1411. .no_pcm = 1,
  1412. .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
  1413. .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
  1414. .ops = &msm8960_be_ops,
  1415. },
  1416. /* Ultrasound TX Back End DAI Link */
  1417. {
  1418. .name = "SLIMBUS_2 Hostless Capture",
  1419. .stream_name = "SLIMBUS_2 Hostless Capture",
  1420. .cpu_dai_name = "msm-dai-q6.16389",
  1421. .platform_name = "msm-pcm-hostless",
  1422. .codec_name = "tabla1x_codec",
  1423. .codec_dai_name = "tabla_tx2",
  1424. .ignore_suspend = 1,
  1425. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1426. .ops = &msm8960_slimbus_2_be_ops,
  1427. },
  1428. /* Ultrasound RX Back End DAI Link */
  1429. {
  1430. .name = "SLIMBUS_2 Hostless Playback",
  1431. .stream_name = "SLIMBUS_2 Hostless Playback",
  1432. .cpu_dai_name = "msm-dai-q6.16388",
  1433. .platform_name = "msm-pcm-hostless",
  1434. .codec_name = "tabla1x_codec",
  1435. .codec_dai_name = "tabla_rx3",
  1436. .ignore_suspend = 1,
  1437. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1438. .ops = &msm8960_slimbus_2_be_ops,
  1439. },
  1440. };
  1441. static struct snd_soc_dai_link msm8960_dai_delta_tabla2x[] = {
  1442. /* Backend DAI Links */
  1443. {
  1444. .name = LPASS_BE_SLIMBUS_0_RX,
  1445. .stream_name = "Slimbus Playback",
  1446. .cpu_dai_name = "msm-dai-q6.16384",
  1447. .platform_name = "msm-pcm-routing",
  1448. .codec_name = "tabla_codec",
  1449. .codec_dai_name = "tabla_rx1",
  1450. .no_pcm = 1,
  1451. .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
  1452. .init = &msm8960_audrx_init,
  1453. .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
  1454. .ops = &msm8960_be_ops,
  1455. .ignore_pmdown_time = 1, /* this dainlink has playback support */
  1456. },
  1457. {
  1458. .name = LPASS_BE_SLIMBUS_0_TX,
  1459. .stream_name = "Slimbus Capture",
  1460. .cpu_dai_name = "msm-dai-q6.16385",
  1461. .platform_name = "msm-pcm-routing",
  1462. .codec_name = "tabla_codec",
  1463. .codec_dai_name = "tabla_tx1",
  1464. .no_pcm = 1,
  1465. .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
  1466. .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
  1467. .ops = &msm8960_be_ops,
  1468. },
  1469. /* Ultrasound TX Back End DAI Link */
  1470. {
  1471. .name = "SLIMBUS_2 Hostless Capture",
  1472. .stream_name = "SLIMBUS_2 Hostless Capture",
  1473. .cpu_dai_name = "msm-dai-q6.16389",
  1474. .platform_name = "msm-pcm-hostless",
  1475. .codec_name = "tabla_codec",
  1476. .codec_dai_name = "tabla_tx2",
  1477. .ignore_suspend = 1,
  1478. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1479. .ops = &msm8960_slimbus_2_be_ops,
  1480. },
  1481. /* Ultrasound RX Back End DAI Link */
  1482. {
  1483. .name = "SLIMBUS_2 Hostless Playback",
  1484. .stream_name = "SLIMBUS_2 Hostless Playback",
  1485. .cpu_dai_name = "msm-dai-q6.16388",
  1486. .platform_name = "msm-pcm-hostless",
  1487. .codec_name = "tabla_codec",
  1488. .codec_dai_name = "tabla_rx3",
  1489. .ignore_suspend = 1,
  1490. .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
  1491. .ops = &msm8960_slimbus_2_be_ops,
  1492. },
  1493. };
  1494. static struct snd_soc_dai_link msm8960_tabla1x_dai[
  1495. ARRAY_SIZE(msm8960_dai_common) +
  1496. ARRAY_SIZE(msm8960_dai_delta_tabla1x)];
  1497. static struct snd_soc_dai_link msm8960_dai[
  1498. ARRAY_SIZE(msm8960_dai_common) +
  1499. ARRAY_SIZE(msm8960_dai_delta_tabla2x)];
  1500. static struct snd_soc_card snd_soc_tabla1x_card_msm8960 = {
  1501. .name = "msm8960-tabla1x-snd-card",
  1502. .dai_link = msm8960_tabla1x_dai,
  1503. .num_links = ARRAY_SIZE(msm8960_tabla1x_dai),
  1504. .controls = tabla_msm8960_controls,
  1505. .num_controls = ARRAY_SIZE(tabla_msm8960_controls),
  1506. };
  1507. static struct snd_soc_card snd_soc_card_msm8960 = {
  1508. .name = "msm8960-snd-card",
  1509. .dai_link = msm8960_dai,
  1510. .num_links = ARRAY_SIZE(msm8960_dai),
  1511. .controls = tabla_msm8960_controls,
  1512. .num_controls = ARRAY_SIZE(tabla_msm8960_controls),
  1513. };
  1514. static struct platform_device *msm8960_snd_device;
  1515. static struct platform_device *msm8960_snd_tabla1x_device;
  1516. static int msm8960_configure_headset_mic_gpios(void)
  1517. {
  1518. int ret;
  1519. struct pm_gpio param = {
  1520. .direction = PM_GPIO_DIR_OUT,
  1521. .output_buffer = PM_GPIO_OUT_BUF_CMOS,
  1522. .output_value = 1,
  1523. .pull = PM_GPIO_PULL_NO,
  1524. .vin_sel = PM_GPIO_VIN_S4,
  1525. .out_strength = PM_GPIO_STRENGTH_MED,
  1526. .function = PM_GPIO_FUNC_NORMAL,
  1527. };
  1528. ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
  1529. if (ret) {
  1530. pr_err("%s: Failed to request gpio %d\n", __func__,
  1531. PM8921_GPIO_PM_TO_SYS(23));
  1532. return ret;
  1533. }
  1534. ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
  1535. if (ret)
  1536. pr_err("%s: Failed to configure gpio %d\n", __func__,
  1537. PM8921_GPIO_PM_TO_SYS(23));
  1538. else
  1539. gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
  1540. ret = gpio_request(us_euro_sel_gpio, "US_EURO_SWITCH");
  1541. if (ret) {
  1542. pr_err("%s: Failed to request gpio %d\n", __func__,
  1543. us_euro_sel_gpio);
  1544. gpio_free(PM8921_GPIO_PM_TO_SYS(23));
  1545. return ret;
  1546. }
  1547. ret = pm8xxx_gpio_config(us_euro_sel_gpio, &param);
  1548. if (ret)
  1549. pr_err("%s: Failed to configure gpio %d\n", __func__,
  1550. us_euro_sel_gpio);
  1551. else
  1552. gpio_direction_output(us_euro_sel_gpio, 0);
  1553. return 0;
  1554. }
  1555. static void msm8960_free_headset_mic_gpios(void)
  1556. {
  1557. if (msm8960_headset_gpios_configured) {
  1558. gpio_free(PM8921_GPIO_PM_TO_SYS(23));
  1559. gpio_free(us_euro_sel_gpio);
  1560. }
  1561. }
  1562. static int __init msm8960_audio_init(void)
  1563. {
  1564. int ret;
  1565. if (!soc_class_is_msm8960()) {
  1566. pr_debug("%s: Not the right machine type\n", __func__);
  1567. return -ENODEV ;
  1568. }
  1569. mutex_init(&cdc_mclk_mutex);
  1570. mbhc_cfg.calibration = def_tabla_mbhc_cal();
  1571. if (!mbhc_cfg.calibration) {
  1572. pr_err("Calibration data allocation failed\n");
  1573. return -ENOMEM;
  1574. }
  1575. msm8960_snd_device = platform_device_alloc("soc-audio", 0);
  1576. if (!msm8960_snd_device) {
  1577. pr_err("Platform device allocation failed\n");
  1578. kfree(mbhc_cfg.calibration);
  1579. return -ENOMEM;
  1580. }
  1581. memcpy(msm8960_dai, msm8960_dai_common, sizeof(msm8960_dai_common));
  1582. memcpy(msm8960_dai + ARRAY_SIZE(msm8960_dai_common),
  1583. msm8960_dai_delta_tabla2x, sizeof(msm8960_dai_delta_tabla2x));
  1584. platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
  1585. ret = platform_device_add(msm8960_snd_device);
  1586. if (ret) {
  1587. platform_device_put(msm8960_snd_device);
  1588. kfree(mbhc_cfg.calibration);
  1589. return ret;
  1590. }
  1591. msm8960_snd_tabla1x_device = platform_device_alloc("soc-audio", 1);
  1592. if (!msm8960_snd_tabla1x_device) {
  1593. pr_err("Platform device allocation failed\n");
  1594. kfree(mbhc_cfg.calibration);
  1595. return -ENOMEM;
  1596. }
  1597. memcpy(msm8960_tabla1x_dai, msm8960_dai_common,
  1598. sizeof(msm8960_dai_common));
  1599. memcpy(msm8960_tabla1x_dai + ARRAY_SIZE(msm8960_dai_common),
  1600. msm8960_dai_delta_tabla1x, sizeof(msm8960_dai_delta_tabla1x));
  1601. platform_set_drvdata(msm8960_snd_tabla1x_device,
  1602. &snd_soc_tabla1x_card_msm8960);
  1603. ret = platform_device_add(msm8960_snd_tabla1x_device);
  1604. if (ret) {
  1605. platform_device_put(msm8960_snd_tabla1x_device);
  1606. kfree(mbhc_cfg.calibration);
  1607. return ret;
  1608. }
  1609. if (cpu_is_msm8960()) {
  1610. if (msm8960_configure_headset_mic_gpios()) {
  1611. pr_err("%s Fail to configure headset mic gpios\n",
  1612. __func__);
  1613. msm8960_headset_gpios_configured = 0;
  1614. } else
  1615. msm8960_headset_gpios_configured = 1;
  1616. } else {
  1617. msm8960_headset_gpios_configured = 0;
  1618. pr_debug("%s headset GPIO 23 and 35 not configured msm960ab",
  1619. __func__);
  1620. }
  1621. atomic_set(&auxpcm_rsc_ref, 0);
  1622. return ret;
  1623. }
  1624. module_init(msm8960_audio_init);
  1625. static void __exit msm8960_audio_exit(void)
  1626. {
  1627. if (!soc_class_is_msm8960()) {
  1628. pr_debug("%s: Not the right machine type\n", __func__);
  1629. return ;
  1630. }
  1631. msm8960_free_headset_mic_gpios();
  1632. platform_device_unregister(msm8960_snd_device);
  1633. platform_device_unregister(msm8960_snd_tabla1x_device);
  1634. kfree(mbhc_cfg.calibration);
  1635. mutex_destroy(&cdc_mclk_mutex);
  1636. }
  1637. module_exit(msm8960_audio_exit);
  1638. MODULE_DESCRIPTION("ALSA SoC MSM8960");
  1639. MODULE_LICENSE("GPL v2");