mfld_machine.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
  3. *
  4. * Copyright (C) 2010 Intel Corp
  5. * Author: Vinod Koul <vinod.koul@intel.com>
  6. * Author: Harsha Priya <priya.harsha@intel.com>
  7. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; version 2 of the License.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  21. *
  22. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23. */
  24. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  25. #include <linux/init.h>
  26. #include <linux/device.h>
  27. #include <linux/slab.h>
  28. #include <linux/io.h>
  29. #include <sound/pcm.h>
  30. #include <sound/pcm_params.h>
  31. #include <sound/soc.h>
  32. #include <sound/jack.h>
  33. #include "../codecs/sn95031.h"
  34. #define MID_MONO 1
  35. #define MID_STEREO 2
  36. #define MID_MAX_CAP 5
  37. #define MFLD_JACK_INSERT 0x04
  38. enum soc_mic_bias_zones {
  39. MFLD_MV_START = 0,
  40. /* mic bias volutage range for Headphones*/
  41. MFLD_MV_HP = 400,
  42. /* mic bias volutage range for American Headset*/
  43. MFLD_MV_AM_HS = 650,
  44. /* mic bias volutage range for Headset*/
  45. MFLD_MV_HS = 2000,
  46. MFLD_MV_UNDEFINED,
  47. };
  48. static unsigned int hs_switch;
  49. static unsigned int lo_dac;
  50. struct mfld_mc_private {
  51. struct platform_device *socdev;
  52. void __iomem *int_base;
  53. struct snd_soc_codec *codec;
  54. u8 interrupt_status;
  55. };
  56. struct snd_soc_jack mfld_jack;
  57. /*Headset jack detection DAPM pins */
  58. static struct snd_soc_jack_pin mfld_jack_pins[] = {
  59. {
  60. .pin = "Headphones",
  61. .mask = SND_JACK_HEADPHONE,
  62. },
  63. {
  64. .pin = "AMIC1",
  65. .mask = SND_JACK_MICROPHONE,
  66. },
  67. };
  68. /* jack detection voltage zones */
  69. static struct snd_soc_jack_zone mfld_zones[] = {
  70. {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
  71. {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
  72. };
  73. /* sound card controls */
  74. static const char *headset_switch_text[] = {"Earpiece", "Headset"};
  75. static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
  76. static const struct soc_enum headset_enum =
  77. SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
  78. static const struct soc_enum lo_enum =
  79. SOC_ENUM_SINGLE_EXT(4, lo_text);
  80. static int headset_get_switch(struct snd_kcontrol *kcontrol,
  81. struct snd_ctl_elem_value *ucontrol)
  82. {
  83. ucontrol->value.integer.value[0] = hs_switch;
  84. return 0;
  85. }
  86. static int headset_set_switch(struct snd_kcontrol *kcontrol,
  87. struct snd_ctl_elem_value *ucontrol)
  88. {
  89. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  90. if (ucontrol->value.integer.value[0] == hs_switch)
  91. return 0;
  92. if (ucontrol->value.integer.value[0]) {
  93. pr_debug("hs_set HS path\n");
  94. snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
  95. snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
  96. } else {
  97. pr_debug("hs_set EP path\n");
  98. snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
  99. snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
  100. }
  101. snd_soc_dapm_sync(&codec->dapm);
  102. hs_switch = ucontrol->value.integer.value[0];
  103. return 0;
  104. }
  105. static void lo_enable_out_pins(struct snd_soc_codec *codec)
  106. {
  107. snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL");
  108. snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR");
  109. snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL");
  110. snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR");
  111. snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT");
  112. snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT");
  113. if (hs_switch) {
  114. snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
  115. snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
  116. } else {
  117. snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
  118. snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
  119. }
  120. }
  121. static int lo_get_switch(struct snd_kcontrol *kcontrol,
  122. struct snd_ctl_elem_value *ucontrol)
  123. {
  124. ucontrol->value.integer.value[0] = lo_dac;
  125. return 0;
  126. }
  127. static int lo_set_switch(struct snd_kcontrol *kcontrol,
  128. struct snd_ctl_elem_value *ucontrol)
  129. {
  130. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  131. if (ucontrol->value.integer.value[0] == lo_dac)
  132. return 0;
  133. /* we dont want to work with last state of lineout so just enable all
  134. * pins and then disable pins not required
  135. */
  136. lo_enable_out_pins(codec);
  137. switch (ucontrol->value.integer.value[0]) {
  138. case 0:
  139. pr_debug("set vibra path\n");
  140. snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT");
  141. snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT");
  142. snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
  143. break;
  144. case 1:
  145. pr_debug("set hs path\n");
  146. snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
  147. snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
  148. snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
  149. break;
  150. case 2:
  151. pr_debug("set spkr path\n");
  152. snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL");
  153. snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR");
  154. snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
  155. break;
  156. case 3:
  157. pr_debug("set null path\n");
  158. snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL");
  159. snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR");
  160. snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
  161. break;
  162. }
  163. snd_soc_dapm_sync(&codec->dapm);
  164. lo_dac = ucontrol->value.integer.value[0];
  165. return 0;
  166. }
  167. static const struct snd_kcontrol_new mfld_snd_controls[] = {
  168. SOC_ENUM_EXT("Playback Switch", headset_enum,
  169. headset_get_switch, headset_set_switch),
  170. SOC_ENUM_EXT("Lineout Mux", lo_enum,
  171. lo_get_switch, lo_set_switch),
  172. };
  173. static const struct snd_soc_dapm_widget mfld_widgets[] = {
  174. SND_SOC_DAPM_HP("Headphones", NULL),
  175. SND_SOC_DAPM_MIC("Mic", NULL),
  176. };
  177. static const struct snd_soc_dapm_route mfld_map[] = {
  178. {"Headphones", NULL, "HPOUTR"},
  179. {"Headphones", NULL, "HPOUTL"},
  180. {"Mic", NULL, "AMIC1"},
  181. };
  182. static void mfld_jack_check(unsigned int intr_status)
  183. {
  184. struct mfld_jack_data jack_data;
  185. jack_data.mfld_jack = &mfld_jack;
  186. jack_data.intr_id = intr_status;
  187. sn95031_jack_detection(&jack_data);
  188. /* TODO: add american headset detection post gpiolib support */
  189. }
  190. static int mfld_init(struct snd_soc_pcm_runtime *runtime)
  191. {
  192. struct snd_soc_codec *codec = runtime->codec;
  193. struct snd_soc_dapm_context *dapm = &codec->dapm;
  194. int ret_val;
  195. /* Add jack sense widgets */
  196. snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
  197. /* Set up the map */
  198. snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
  199. /* always connected */
  200. snd_soc_dapm_enable_pin(dapm, "Headphones");
  201. snd_soc_dapm_enable_pin(dapm, "Mic");
  202. snd_soc_dapm_sync(dapm);
  203. ret_val = snd_soc_add_controls(codec, mfld_snd_controls,
  204. ARRAY_SIZE(mfld_snd_controls));
  205. if (ret_val) {
  206. pr_err("soc_add_controls failed %d", ret_val);
  207. return ret_val;
  208. }
  209. /* default is earpiece pin, userspace sets it explcitly */
  210. snd_soc_dapm_disable_pin(dapm, "Headphones");
  211. /* default is lineout NC, userspace sets it explcitly */
  212. snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
  213. snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
  214. lo_dac = 3;
  215. hs_switch = 0;
  216. /* we dont use linein in this so set to NC */
  217. snd_soc_dapm_disable_pin(dapm, "LINEINL");
  218. snd_soc_dapm_disable_pin(dapm, "LINEINR");
  219. snd_soc_dapm_sync(dapm);
  220. /* Headset and button jack detection */
  221. ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
  222. SND_JACK_HEADSET | SND_JACK_BTN_0 |
  223. SND_JACK_BTN_1, &mfld_jack);
  224. if (ret_val) {
  225. pr_err("jack creation failed\n");
  226. return ret_val;
  227. }
  228. ret_val = snd_soc_jack_add_pins(&mfld_jack,
  229. ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
  230. if (ret_val) {
  231. pr_err("adding jack pins failed\n");
  232. return ret_val;
  233. }
  234. ret_val = snd_soc_jack_add_zones(&mfld_jack,
  235. ARRAY_SIZE(mfld_zones), mfld_zones);
  236. if (ret_val) {
  237. pr_err("adding jack zones failed\n");
  238. return ret_val;
  239. }
  240. /* we want to check if anything is inserted at boot,
  241. * so send a fake event to codec and it will read adc
  242. * to find if anything is there or not */
  243. mfld_jack_check(MFLD_JACK_INSERT);
  244. return ret_val;
  245. }
  246. struct snd_soc_dai_link mfld_msic_dailink[] = {
  247. {
  248. .name = "Medfield Headset",
  249. .stream_name = "Headset",
  250. .cpu_dai_name = "Headset-cpu-dai",
  251. .codec_dai_name = "SN95031 Headset",
  252. .codec_name = "sn95031",
  253. .platform_name = "sst-platform",
  254. .init = mfld_init,
  255. },
  256. {
  257. .name = "Medfield Speaker",
  258. .stream_name = "Speaker",
  259. .cpu_dai_name = "Speaker-cpu-dai",
  260. .codec_dai_name = "SN95031 Speaker",
  261. .codec_name = "sn95031",
  262. .platform_name = "sst-platform",
  263. .init = NULL,
  264. },
  265. {
  266. .name = "Medfield Vibra",
  267. .stream_name = "Vibra1",
  268. .cpu_dai_name = "Vibra1-cpu-dai",
  269. .codec_dai_name = "SN95031 Vibra1",
  270. .codec_name = "sn95031",
  271. .platform_name = "sst-platform",
  272. .init = NULL,
  273. },
  274. {
  275. .name = "Medfield Haptics",
  276. .stream_name = "Vibra2",
  277. .cpu_dai_name = "Vibra2-cpu-dai",
  278. .codec_dai_name = "SN95031 Vibra2",
  279. .codec_name = "sn95031",
  280. .platform_name = "sst-platform",
  281. .init = NULL,
  282. },
  283. };
  284. /* SoC card */
  285. static struct snd_soc_card snd_soc_card_mfld = {
  286. .name = "medfield_audio",
  287. .dai_link = mfld_msic_dailink,
  288. .num_links = ARRAY_SIZE(mfld_msic_dailink),
  289. };
  290. static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
  291. {
  292. struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
  293. memcpy_fromio(&mc_private->interrupt_status,
  294. ((void *)(mc_private->int_base)),
  295. sizeof(u8));
  296. return IRQ_WAKE_THREAD;
  297. }
  298. static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
  299. {
  300. struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
  301. if (mfld_jack.codec == NULL)
  302. return IRQ_HANDLED;
  303. mfld_jack_check(mc_drv_ctx->interrupt_status);
  304. return IRQ_HANDLED;
  305. }
  306. static int __devinit snd_mfld_mc_probe(struct platform_device *pdev)
  307. {
  308. int ret_val = 0, irq;
  309. struct mfld_mc_private *mc_drv_ctx;
  310. struct resource *irq_mem;
  311. pr_debug("snd_mfld_mc_probe called\n");
  312. /* retrive the irq number */
  313. irq = platform_get_irq(pdev, 0);
  314. /* audio interrupt base of SRAM location where
  315. * interrupts are stored by System FW */
  316. mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC);
  317. if (!mc_drv_ctx) {
  318. pr_err("allocation failed\n");
  319. return -ENOMEM;
  320. }
  321. irq_mem = platform_get_resource_byname(
  322. pdev, IORESOURCE_MEM, "IRQ_BASE");
  323. if (!irq_mem) {
  324. pr_err("no mem resource given\n");
  325. ret_val = -ENODEV;
  326. goto unalloc;
  327. }
  328. mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start,
  329. resource_size(irq_mem));
  330. if (!mc_drv_ctx->int_base) {
  331. pr_err("Mapping of cache failed\n");
  332. ret_val = -ENOMEM;
  333. goto unalloc;
  334. }
  335. /* register for interrupt */
  336. ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler,
  337. snd_mfld_jack_detection,
  338. IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
  339. if (ret_val) {
  340. pr_err("cannot register IRQ\n");
  341. goto unalloc;
  342. }
  343. /* register the soc card */
  344. snd_soc_card_mfld.dev = &pdev->dev;
  345. ret_val = snd_soc_register_card(&snd_soc_card_mfld);
  346. if (ret_val) {
  347. pr_debug("snd_soc_register_card failed %d\n", ret_val);
  348. goto freeirq;
  349. }
  350. platform_set_drvdata(pdev, mc_drv_ctx);
  351. pr_debug("successfully exited probe\n");
  352. return ret_val;
  353. freeirq:
  354. free_irq(irq, mc_drv_ctx);
  355. unalloc:
  356. kfree(mc_drv_ctx);
  357. return ret_val;
  358. }
  359. static int __devexit snd_mfld_mc_remove(struct platform_device *pdev)
  360. {
  361. struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev);
  362. pr_debug("snd_mfld_mc_remove called\n");
  363. free_irq(platform_get_irq(pdev, 0), mc_drv_ctx);
  364. snd_soc_unregister_card(&snd_soc_card_mfld);
  365. kfree(mc_drv_ctx);
  366. platform_set_drvdata(pdev, NULL);
  367. return 0;
  368. }
  369. static struct platform_driver snd_mfld_mc_driver = {
  370. .driver = {
  371. .owner = THIS_MODULE,
  372. .name = "msic_audio",
  373. },
  374. .probe = snd_mfld_mc_probe,
  375. .remove = __devexit_p(snd_mfld_mc_remove),
  376. };
  377. static int __init snd_mfld_driver_init(void)
  378. {
  379. pr_debug("snd_mfld_driver_init called\n");
  380. return platform_driver_register(&snd_mfld_mc_driver);
  381. }
  382. module_init(snd_mfld_driver_init);
  383. static void __exit snd_mfld_driver_exit(void)
  384. {
  385. pr_debug("snd_mfld_driver_exit called\n");
  386. platform_driver_unregister(&snd_mfld_mc_driver);
  387. }
  388. module_exit(snd_mfld_driver_exit);
  389. MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
  390. MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
  391. MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
  392. MODULE_LICENSE("GPL v2");
  393. MODULE_ALIAS("platform:msic-audio");