mop500_ab8500.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. * Copyright (C) ST-Ericsson SA 2012
  3. *
  4. * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  5. * Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
  6. * for ST-Ericsson.
  7. *
  8. * License terms:
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as published
  12. * by the Free Software Foundation.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/device.h>
  16. #include <linux/io.h>
  17. #include <linux/clk.h>
  18. #include <sound/soc.h>
  19. #include <sound/soc-dapm.h>
  20. #include <sound/pcm.h>
  21. #include <sound/pcm_params.h>
  22. #include "ux500_pcm.h"
  23. #include "ux500_msp_dai.h"
  24. #include "../codecs/ab8500-codec.h"
  25. #define TX_SLOT_MONO 0x0008
  26. #define TX_SLOT_STEREO 0x000a
  27. #define RX_SLOT_MONO 0x0001
  28. #define RX_SLOT_STEREO 0x0003
  29. #define TX_SLOT_8CH 0x00FF
  30. #define RX_SLOT_8CH 0x00FF
  31. #define DEF_TX_SLOTS TX_SLOT_STEREO
  32. #define DEF_RX_SLOTS RX_SLOT_MONO
  33. #define DRIVERMODE_NORMAL 0
  34. #define DRIVERMODE_CODEC_ONLY 1
  35. /* Slot configuration */
  36. static unsigned int tx_slots = DEF_TX_SLOTS;
  37. static unsigned int rx_slots = DEF_RX_SLOTS;
  38. /* Clocks */
  39. static const char * const enum_mclk[] = {
  40. "SYSCLK",
  41. "ULPCLK"
  42. };
  43. enum mclk {
  44. MCLK_SYSCLK,
  45. MCLK_ULPCLK,
  46. };
  47. static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
  48. /* Private data for machine-part MOP500<->AB8500 */
  49. struct mop500_ab8500_drvdata {
  50. /* Clocks */
  51. enum mclk mclk_sel;
  52. struct clk *clk_ptr_intclk;
  53. struct clk *clk_ptr_sysclk;
  54. struct clk *clk_ptr_ulpclk;
  55. };
  56. static inline const char *get_mclk_str(enum mclk mclk_sel)
  57. {
  58. switch (mclk_sel) {
  59. case MCLK_SYSCLK:
  60. return "SYSCLK";
  61. case MCLK_ULPCLK:
  62. return "ULPCLK";
  63. default:
  64. return "Unknown";
  65. }
  66. }
  67. static int mop500_ab8500_set_mclk(struct device *dev,
  68. struct mop500_ab8500_drvdata *drvdata)
  69. {
  70. int status;
  71. struct clk *clk_ptr;
  72. if (IS_ERR(drvdata->clk_ptr_intclk)) {
  73. dev_err(dev,
  74. "%s: ERROR: intclk not initialized!\n", __func__);
  75. return -EIO;
  76. }
  77. switch (drvdata->mclk_sel) {
  78. case MCLK_SYSCLK:
  79. clk_ptr = drvdata->clk_ptr_sysclk;
  80. break;
  81. case MCLK_ULPCLK:
  82. clk_ptr = drvdata->clk_ptr_ulpclk;
  83. break;
  84. default:
  85. return -EINVAL;
  86. }
  87. if (IS_ERR(clk_ptr)) {
  88. dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
  89. get_mclk_str(drvdata->mclk_sel));
  90. return -EIO;
  91. }
  92. status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
  93. if (status)
  94. dev_err(dev,
  95. "%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
  96. __func__, get_mclk_str(drvdata->mclk_sel), status);
  97. else
  98. dev_dbg(dev,
  99. "%s: intclk parent changed to %s.\n",
  100. __func__, get_mclk_str(drvdata->mclk_sel));
  101. return status;
  102. }
  103. /*
  104. * Control-events
  105. */
  106. static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
  107. struct snd_ctl_elem_value *ucontrol)
  108. {
  109. struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
  110. struct mop500_ab8500_drvdata *drvdata =
  111. snd_soc_card_get_drvdata(card);
  112. ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
  113. return 0;
  114. }
  115. static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
  116. struct snd_ctl_elem_value *ucontrol)
  117. {
  118. struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
  119. struct mop500_ab8500_drvdata *drvdata =
  120. snd_soc_card_get_drvdata(card);
  121. unsigned int val = ucontrol->value.enumerated.item[0];
  122. if (val > (unsigned int)MCLK_ULPCLK)
  123. return -EINVAL;
  124. if (drvdata->mclk_sel == val)
  125. return 0;
  126. drvdata->mclk_sel = val;
  127. return 1;
  128. }
  129. /*
  130. * Controls
  131. */
  132. static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
  133. SOC_ENUM_EXT("Master Clock Select",
  134. soc_enum_mclk,
  135. mclk_input_control_get, mclk_input_control_put),
  136. SOC_DAPM_PIN_SWITCH("Headset Left"),
  137. SOC_DAPM_PIN_SWITCH("Headset Right"),
  138. SOC_DAPM_PIN_SWITCH("Earpiece"),
  139. SOC_DAPM_PIN_SWITCH("Speaker Left"),
  140. SOC_DAPM_PIN_SWITCH("Speaker Right"),
  141. SOC_DAPM_PIN_SWITCH("LineOut Left"),
  142. SOC_DAPM_PIN_SWITCH("LineOut Right"),
  143. SOC_DAPM_PIN_SWITCH("Vibra 1"),
  144. SOC_DAPM_PIN_SWITCH("Vibra 2"),
  145. SOC_DAPM_PIN_SWITCH("Mic 1"),
  146. SOC_DAPM_PIN_SWITCH("Mic 2"),
  147. SOC_DAPM_PIN_SWITCH("LineIn Left"),
  148. SOC_DAPM_PIN_SWITCH("LineIn Right"),
  149. SOC_DAPM_PIN_SWITCH("DMic 1"),
  150. SOC_DAPM_PIN_SWITCH("DMic 2"),
  151. SOC_DAPM_PIN_SWITCH("DMic 3"),
  152. SOC_DAPM_PIN_SWITCH("DMic 4"),
  153. SOC_DAPM_PIN_SWITCH("DMic 5"),
  154. SOC_DAPM_PIN_SWITCH("DMic 6"),
  155. };
  156. /* ASoC */
  157. int mop500_ab8500_startup(struct snd_pcm_substream *substream)
  158. {
  159. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  160. /* Set audio-clock source */
  161. return mop500_ab8500_set_mclk(rtd->card->dev,
  162. snd_soc_card_get_drvdata(rtd->card));
  163. }
  164. void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
  165. {
  166. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  167. struct device *dev = rtd->card->dev;
  168. dev_dbg(dev, "%s: Enter\n", __func__);
  169. /* Reset slots configuration to default(s) */
  170. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  171. tx_slots = DEF_TX_SLOTS;
  172. else
  173. rx_slots = DEF_RX_SLOTS;
  174. }
  175. int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
  176. struct snd_pcm_hw_params *params)
  177. {
  178. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  179. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  180. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  181. struct device *dev = rtd->card->dev;
  182. unsigned int fmt;
  183. int channels, ret = 0, driver_mode, slots;
  184. unsigned int sw_codec, sw_cpu;
  185. bool is_playback;
  186. dev_dbg(dev, "%s: Enter\n", __func__);
  187. dev_dbg(dev, "%s: substream->pcm->name = %s\n"
  188. "substream->pcm->id = %s.\n"
  189. "substream->name = %s.\n"
  190. "substream->number = %d.\n",
  191. __func__,
  192. substream->pcm->name,
  193. substream->pcm->id,
  194. substream->name,
  195. substream->number);
  196. channels = params_channels(params);
  197. switch (params_format(params)) {
  198. case SNDRV_PCM_FORMAT_S32_LE:
  199. sw_cpu = 32;
  200. break;
  201. case SNDRV_PCM_FORMAT_S16_LE:
  202. sw_cpu = 16;
  203. break;
  204. default:
  205. return -EINVAL;
  206. }
  207. /* Setup codec depending on driver-mode */
  208. if (channels == 8)
  209. driver_mode = DRIVERMODE_CODEC_ONLY;
  210. else
  211. driver_mode = DRIVERMODE_NORMAL;
  212. dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
  213. (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
  214. /* Setup format */
  215. if (driver_mode == DRIVERMODE_NORMAL) {
  216. fmt = SND_SOC_DAIFMT_DSP_A |
  217. SND_SOC_DAIFMT_CBM_CFM |
  218. SND_SOC_DAIFMT_NB_NF |
  219. SND_SOC_DAIFMT_CONT;
  220. } else {
  221. fmt = SND_SOC_DAIFMT_DSP_A |
  222. SND_SOC_DAIFMT_CBM_CFM |
  223. SND_SOC_DAIFMT_NB_NF |
  224. SND_SOC_DAIFMT_GATED;
  225. }
  226. ret = snd_soc_dai_set_fmt(codec_dai, fmt);
  227. if (ret < 0) {
  228. dev_err(dev,
  229. "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
  230. __func__, ret);
  231. return ret;
  232. }
  233. ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
  234. if (ret < 0) {
  235. dev_err(dev,
  236. "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
  237. __func__, ret);
  238. return ret;
  239. }
  240. /* Setup TDM-slots */
  241. is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
  242. switch (channels) {
  243. case 1:
  244. slots = 16;
  245. tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
  246. rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
  247. break;
  248. case 2:
  249. slots = 16;
  250. tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
  251. rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
  252. break;
  253. case 8:
  254. slots = 16;
  255. tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
  256. rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
  257. break;
  258. default:
  259. return -EINVAL;
  260. }
  261. if (driver_mode == DRIVERMODE_NORMAL)
  262. sw_codec = sw_cpu;
  263. else
  264. sw_codec = 20;
  265. dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
  266. tx_slots, rx_slots);
  267. ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
  268. sw_cpu);
  269. if (ret)
  270. return ret;
  271. dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
  272. tx_slots, rx_slots);
  273. ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
  274. sw_codec);
  275. if (ret)
  276. return ret;
  277. return 0;
  278. }
  279. struct snd_soc_ops mop500_ab8500_ops[] = {
  280. {
  281. .hw_params = mop500_ab8500_hw_params,
  282. .startup = mop500_ab8500_startup,
  283. .shutdown = mop500_ab8500_shutdown,
  284. }
  285. };
  286. int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
  287. {
  288. struct snd_soc_codec *codec = rtd->codec;
  289. struct device *dev = rtd->card->dev;
  290. struct mop500_ab8500_drvdata *drvdata;
  291. int ret;
  292. dev_dbg(dev, "%s Enter.\n", __func__);
  293. /* Create driver private-data struct */
  294. drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
  295. GFP_KERNEL);
  296. snd_soc_card_set_drvdata(rtd->card, drvdata);
  297. /* Setup clocks */
  298. drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
  299. if (IS_ERR(drvdata->clk_ptr_sysclk))
  300. dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
  301. __func__);
  302. drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
  303. if (IS_ERR(drvdata->clk_ptr_ulpclk))
  304. dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
  305. __func__);
  306. drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
  307. if (IS_ERR(drvdata->clk_ptr_intclk))
  308. dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
  309. __func__);
  310. /* Set intclk default parent to ulpclk */
  311. drvdata->mclk_sel = MCLK_ULPCLK;
  312. ret = mop500_ab8500_set_mclk(dev, drvdata);
  313. if (ret < 0)
  314. dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
  315. __func__);
  316. drvdata->mclk_sel = MCLK_ULPCLK;
  317. /* Add controls */
  318. ret = snd_soc_add_card_controls(codec->card, mop500_ab8500_ctrls,
  319. ARRAY_SIZE(mop500_ab8500_ctrls));
  320. if (ret < 0) {
  321. pr_err("%s: Failed to add machine-controls (%d)!\n",
  322. __func__, ret);
  323. return ret;
  324. }
  325. ret = snd_soc_dapm_disable_pin(&codec->dapm, "Earpiece");
  326. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Left");
  327. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Right");
  328. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Left");
  329. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Right");
  330. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 1");
  331. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 2");
  332. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 1");
  333. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 2");
  334. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Left");
  335. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Right");
  336. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 1");
  337. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 2");
  338. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 3");
  339. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 4");
  340. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 5");
  341. ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 6");
  342. return ret;
  343. }
  344. void mop500_ab8500_remove(struct snd_soc_card *card)
  345. {
  346. struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
  347. if (drvdata->clk_ptr_sysclk != NULL)
  348. clk_put(drvdata->clk_ptr_sysclk);
  349. if (drvdata->clk_ptr_ulpclk != NULL)
  350. clk_put(drvdata->clk_ptr_ulpclk);
  351. if (drvdata->clk_ptr_intclk != NULL)
  352. clk_put(drvdata->clk_ptr_intclk);
  353. snd_soc_card_set_drvdata(card, drvdata);
  354. }