tegra210_mixer.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // tegra210_mixer.c - Tegra210 MIXER driver
  4. //
  5. // Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved.
  6. #include <linux/clk.h>
  7. #include <linux/device.h>
  8. #include <linux/io.h>
  9. #include <linux/mod_devicetable.h>
  10. #include <linux/module.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/pm_runtime.h>
  13. #include <linux/regmap.h>
  14. #include <sound/core.h>
  15. #include <sound/pcm.h>
  16. #include <sound/pcm_params.h>
  17. #include <sound/soc.h>
  18. #include "tegra210_mixer.h"
  19. #include "tegra_cif.h"
  20. #define MIXER_REG(reg, id) ((reg) + ((id) * TEGRA210_MIXER_REG_STRIDE))
  21. #define MIXER_REG_BASE(reg) ((reg) % TEGRA210_MIXER_REG_STRIDE)
  22. #define MIXER_GAIN_CFG_RAM_ADDR(id) \
  23. (TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 + \
  24. ((id) * TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE))
  25. #define MIXER_RX_REG_DEFAULTS(id) \
  26. { MIXER_REG(TEGRA210_MIXER_RX1_CIF_CTRL, id), 0x00007700}, \
  27. { MIXER_REG(TEGRA210_MIXER_RX1_CTRL, id), 0x00010823}, \
  28. { MIXER_REG(TEGRA210_MIXER_RX1_PEAK_CTRL, id), 0x000012c0}
  29. #define MIXER_TX_REG_DEFAULTS(id) \
  30. { MIXER_REG(TEGRA210_MIXER_TX1_INT_MASK, (id)), 0x00000001}, \
  31. { MIXER_REG(TEGRA210_MIXER_TX1_CIF_CTRL, (id)), 0x00007700}
  32. #define REG_DURATION_PARAM(reg, i) ((reg) + NUM_GAIN_POLY_COEFFS + 1 + (i))
  33. static const struct reg_default tegra210_mixer_reg_defaults[] = {
  34. /* Inputs */
  35. MIXER_RX_REG_DEFAULTS(0),
  36. MIXER_RX_REG_DEFAULTS(1),
  37. MIXER_RX_REG_DEFAULTS(2),
  38. MIXER_RX_REG_DEFAULTS(3),
  39. MIXER_RX_REG_DEFAULTS(4),
  40. MIXER_RX_REG_DEFAULTS(5),
  41. MIXER_RX_REG_DEFAULTS(6),
  42. MIXER_RX_REG_DEFAULTS(7),
  43. MIXER_RX_REG_DEFAULTS(8),
  44. MIXER_RX_REG_DEFAULTS(9),
  45. /* Outputs */
  46. MIXER_TX_REG_DEFAULTS(0),
  47. MIXER_TX_REG_DEFAULTS(1),
  48. MIXER_TX_REG_DEFAULTS(2),
  49. MIXER_TX_REG_DEFAULTS(3),
  50. MIXER_TX_REG_DEFAULTS(4),
  51. { TEGRA210_MIXER_CG, 0x00000001},
  52. { TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000},
  53. { TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000},
  54. { TEGRA210_MIXER_ENABLE, 0x1 },
  55. };
  56. /* Default gain parameters */
  57. static const struct tegra210_mixer_gain_params gain_params = {
  58. /* Polynomial coefficients */
  59. { 0, 0, 0, 0, 0, 0, 0, 0x1000000, 0 },
  60. /* Gain value */
  61. 0x10000,
  62. /* Duration Parameters */
  63. { 0, 0, 0x400, 0x8000000 },
  64. };
  65. static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev)
  66. {
  67. struct tegra210_mixer *mixer = dev_get_drvdata(dev);
  68. regcache_cache_only(mixer->regmap, true);
  69. regcache_mark_dirty(mixer->regmap);
  70. return 0;
  71. }
  72. static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev)
  73. {
  74. struct tegra210_mixer *mixer = dev_get_drvdata(dev);
  75. regcache_cache_only(mixer->regmap, false);
  76. regcache_sync(mixer->regmap);
  77. return 0;
  78. }
  79. static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
  80. unsigned int addr,
  81. unsigned int coef)
  82. {
  83. unsigned int reg, val;
  84. int err;
  85. /* Check if busy */
  86. err = regmap_read_poll_timeout(mixer->regmap,
  87. TEGRA210_MIXER_GAIN_CFG_RAM_CTRL,
  88. val, !(val & 0x80000000), 10, 10000);
  89. if (err < 0)
  90. return err;
  91. reg = (addr << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) &
  92. TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK;
  93. reg |= TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN;
  94. reg |= TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE;
  95. reg |= TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN;
  96. regmap_write(mixer->regmap,
  97. TEGRA210_MIXER_GAIN_CFG_RAM_CTRL,
  98. reg);
  99. regmap_write(mixer->regmap,
  100. TEGRA210_MIXER_GAIN_CFG_RAM_DATA,
  101. coef);
  102. return 0;
  103. }
  104. static int tegra210_mixer_configure_gain(struct snd_soc_component *cmpnt,
  105. unsigned int id, bool instant_gain)
  106. {
  107. struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
  108. unsigned int reg = MIXER_GAIN_CFG_RAM_ADDR(id);
  109. int err, i;
  110. pm_runtime_get_sync(cmpnt->dev);
  111. /* Write default gain poly coefficients */
  112. for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) {
  113. err = tegra210_mixer_write_ram(mixer, reg + i,
  114. gain_params.poly_coeff[i]);
  115. if (err < 0)
  116. goto rpm_put;
  117. }
  118. /* Write stored gain value */
  119. err = tegra210_mixer_write_ram(mixer, reg + NUM_GAIN_POLY_COEFFS,
  120. mixer->gain_value[id]);
  121. if (err < 0)
  122. goto rpm_put;
  123. /* Write duration parameters */
  124. for (i = 0; i < NUM_DURATION_PARMS; i++) {
  125. int val;
  126. if (instant_gain)
  127. val = 1;
  128. else
  129. val = gain_params.duration[i];
  130. err = tegra210_mixer_write_ram(mixer,
  131. REG_DURATION_PARAM(reg, i),
  132. val);
  133. if (err < 0)
  134. goto rpm_put;
  135. }
  136. /* Trigger to apply gain configurations */
  137. err = tegra210_mixer_write_ram(mixer, reg + REG_CFG_DONE_TRIGGER,
  138. VAL_CFG_DONE_TRIGGER);
  139. rpm_put:
  140. pm_runtime_put(cmpnt->dev);
  141. return err;
  142. }
  143. static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol,
  144. struct snd_ctl_elem_value *ucontrol)
  145. {
  146. struct soc_mixer_control *mc =
  147. (struct soc_mixer_control *)kcontrol->private_value;
  148. struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
  149. struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
  150. unsigned int reg = mc->reg;
  151. unsigned int i;
  152. i = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
  153. TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
  154. ucontrol->value.integer.value[0] = mixer->gain_value[i];
  155. return 0;
  156. }
  157. static int tegra210_mixer_apply_gain(struct snd_kcontrol *kcontrol,
  158. struct snd_ctl_elem_value *ucontrol,
  159. bool instant_gain)
  160. {
  161. struct soc_mixer_control *mc =
  162. (struct soc_mixer_control *)kcontrol->private_value;
  163. struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
  164. struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
  165. unsigned int reg = mc->reg, id;
  166. int err;
  167. /* Save gain value for specific MIXER input */
  168. id = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
  169. TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
  170. if (mixer->gain_value[id] == ucontrol->value.integer.value[0])
  171. return 0;
  172. mixer->gain_value[id] = ucontrol->value.integer.value[0];
  173. err = tegra210_mixer_configure_gain(cmpnt, id, instant_gain);
  174. if (err) {
  175. dev_err(cmpnt->dev, "Failed to apply gain\n");
  176. return err;
  177. }
  178. return 1;
  179. }
  180. static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
  181. struct snd_ctl_elem_value *ucontrol)
  182. {
  183. return tegra210_mixer_apply_gain(kcontrol, ucontrol, false);
  184. }
  185. static int tegra210_mixer_put_instant_gain(struct snd_kcontrol *kcontrol,
  186. struct snd_ctl_elem_value *ucontrol)
  187. {
  188. return tegra210_mixer_apply_gain(kcontrol, ucontrol, true);
  189. }
  190. static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
  191. struct snd_pcm_hw_params *params,
  192. unsigned int reg,
  193. unsigned int id)
  194. {
  195. unsigned int channels, audio_bits;
  196. struct tegra_cif_conf cif_conf;
  197. memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
  198. channels = params_channels(params);
  199. switch (params_format(params)) {
  200. case SNDRV_PCM_FORMAT_S16_LE:
  201. audio_bits = TEGRA_ACIF_BITS_16;
  202. break;
  203. case SNDRV_PCM_FORMAT_S32_LE:
  204. audio_bits = TEGRA_ACIF_BITS_32;
  205. break;
  206. default:
  207. return -EINVAL;
  208. }
  209. cif_conf.audio_ch = channels;
  210. cif_conf.client_ch = channels;
  211. cif_conf.audio_bits = audio_bits;
  212. cif_conf.client_bits = audio_bits;
  213. tegra_set_cif(mixer->regmap,
  214. reg + (id * TEGRA210_MIXER_REG_STRIDE),
  215. &cif_conf);
  216. return 0;
  217. }
  218. static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream,
  219. struct snd_pcm_hw_params *params,
  220. struct snd_soc_dai *dai)
  221. {
  222. struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
  223. int err;
  224. err = tegra210_mixer_set_audio_cif(mixer, params,
  225. TEGRA210_MIXER_RX1_CIF_CTRL,
  226. dai->id);
  227. if (err < 0)
  228. return err;
  229. return tegra210_mixer_configure_gain(dai->component, dai->id, false);
  230. }
  231. static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream,
  232. struct snd_pcm_hw_params *params,
  233. struct snd_soc_dai *dai)
  234. {
  235. struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai);
  236. return tegra210_mixer_set_audio_cif(mixer, params,
  237. TEGRA210_MIXER_TX1_CIF_CTRL,
  238. dai->id - TEGRA210_MIXER_RX_MAX);
  239. }
  240. static const struct snd_soc_dai_ops tegra210_mixer_out_dai_ops = {
  241. .hw_params = tegra210_mixer_out_hw_params,
  242. };
  243. static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = {
  244. .hw_params = tegra210_mixer_in_hw_params,
  245. };
  246. #define IN_DAI(id) \
  247. { \
  248. .name = "MIXER-RX-CIF"#id, \
  249. .playback = { \
  250. .stream_name = "RX" #id "-CIF-Playback",\
  251. .channels_min = 1, \
  252. .channels_max = 8, \
  253. .rates = SNDRV_PCM_RATE_8000_192000, \
  254. .formats = SNDRV_PCM_FMTBIT_S8 | \
  255. SNDRV_PCM_FMTBIT_S16_LE | \
  256. SNDRV_PCM_FMTBIT_S32_LE, \
  257. }, \
  258. .capture = { \
  259. .stream_name = "RX" #id "-CIF-Capture", \
  260. .channels_min = 1, \
  261. .channels_max = 8, \
  262. .rates = SNDRV_PCM_RATE_8000_192000, \
  263. .formats = SNDRV_PCM_FMTBIT_S8 | \
  264. SNDRV_PCM_FMTBIT_S16_LE | \
  265. SNDRV_PCM_FMTBIT_S32_LE, \
  266. }, \
  267. .ops = &tegra210_mixer_in_dai_ops, \
  268. }
  269. #define OUT_DAI(id) \
  270. { \
  271. .name = "MIXER-TX-CIF" #id, \
  272. .playback = { \
  273. .stream_name = "TX" #id "-CIF-Playback",\
  274. .channels_min = 1, \
  275. .channels_max = 8, \
  276. .rates = SNDRV_PCM_RATE_8000_192000, \
  277. .formats = SNDRV_PCM_FMTBIT_S8 | \
  278. SNDRV_PCM_FMTBIT_S16_LE | \
  279. SNDRV_PCM_FMTBIT_S32_LE, \
  280. }, \
  281. .capture = { \
  282. .stream_name = "TX" #id "-CIF-Capture", \
  283. .channels_min = 1, \
  284. .channels_max = 8, \
  285. .rates = SNDRV_PCM_RATE_8000_192000, \
  286. .formats = SNDRV_PCM_FMTBIT_S8 | \
  287. SNDRV_PCM_FMTBIT_S16_LE | \
  288. SNDRV_PCM_FMTBIT_S32_LE, \
  289. }, \
  290. .ops = &tegra210_mixer_out_dai_ops, \
  291. }
  292. static struct snd_soc_dai_driver tegra210_mixer_dais[] = {
  293. /* Mixer Input */
  294. IN_DAI(1),
  295. IN_DAI(2),
  296. IN_DAI(3),
  297. IN_DAI(4),
  298. IN_DAI(5),
  299. IN_DAI(6),
  300. IN_DAI(7),
  301. IN_DAI(8),
  302. IN_DAI(9),
  303. IN_DAI(10),
  304. /* Mixer Output */
  305. OUT_DAI(1),
  306. OUT_DAI(2),
  307. OUT_DAI(3),
  308. OUT_DAI(4),
  309. OUT_DAI(5),
  310. };
  311. #define ADDER_CTRL_DECL(name, reg) \
  312. static const struct snd_kcontrol_new name[] = { \
  313. SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0), \
  314. SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0), \
  315. SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0), \
  316. SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0), \
  317. SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0), \
  318. SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0), \
  319. SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0), \
  320. SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0), \
  321. SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0), \
  322. SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0), \
  323. }
  324. ADDER_CTRL_DECL(adder1, TEGRA210_MIXER_TX1_ADDER_CONFIG);
  325. ADDER_CTRL_DECL(adder2, TEGRA210_MIXER_TX2_ADDER_CONFIG);
  326. ADDER_CTRL_DECL(adder3, TEGRA210_MIXER_TX3_ADDER_CONFIG);
  327. ADDER_CTRL_DECL(adder4, TEGRA210_MIXER_TX4_ADDER_CONFIG);
  328. ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_TX5_ADDER_CONFIG);
  329. #define GAIN_CTRL(id) \
  330. SOC_SINGLE_EXT("RX" #id " Gain Volume", \
  331. MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \
  332. 0x20000, 0, tegra210_mixer_get_gain, \
  333. tegra210_mixer_put_gain), \
  334. SOC_SINGLE_EXT("RX" #id " Instant Gain Volume", \
  335. MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \
  336. 0x20000, 0, tegra210_mixer_get_gain, \
  337. tegra210_mixer_put_instant_gain),
  338. /* Volume controls for all MIXER inputs */
  339. static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = {
  340. GAIN_CTRL(1)
  341. GAIN_CTRL(2)
  342. GAIN_CTRL(3)
  343. GAIN_CTRL(4)
  344. GAIN_CTRL(5)
  345. GAIN_CTRL(6)
  346. GAIN_CTRL(7)
  347. GAIN_CTRL(8)
  348. GAIN_CTRL(9)
  349. GAIN_CTRL(10)
  350. };
  351. static const struct snd_soc_dapm_widget tegra210_mixer_widgets[] = {
  352. SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
  353. SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
  354. SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
  355. SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0),
  356. SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0),
  357. SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0),
  358. SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0),
  359. SND_SOC_DAPM_AIF_IN("RX8", NULL, 0, SND_SOC_NOPM, 0, 0),
  360. SND_SOC_DAPM_AIF_IN("RX9", NULL, 0, SND_SOC_NOPM, 0, 0),
  361. SND_SOC_DAPM_AIF_IN("RX10", NULL, 0, SND_SOC_NOPM, 0, 0),
  362. SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_MIXER_TX1_ENABLE, 0, 0),
  363. SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_MIXER_TX2_ENABLE, 0, 0),
  364. SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_MIXER_TX3_ENABLE, 0, 0),
  365. SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_MIXER_TX4_ENABLE, 0, 0),
  366. SND_SOC_DAPM_AIF_OUT("TX5", NULL, 0, TEGRA210_MIXER_TX5_ENABLE, 0, 0),
  367. SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, adder1,
  368. ARRAY_SIZE(adder1)),
  369. SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, adder2,
  370. ARRAY_SIZE(adder2)),
  371. SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, adder3,
  372. ARRAY_SIZE(adder3)),
  373. SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, adder4,
  374. ARRAY_SIZE(adder4)),
  375. SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, adder5,
  376. ARRAY_SIZE(adder5)),
  377. };
  378. #define RX_ROUTES(id, sname) \
  379. { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \
  380. { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname }, \
  381. { "RX" #id, NULL, "RX" #id "-CIF-" sname }
  382. #define MIXER_RX_ROUTES(id) \
  383. RX_ROUTES(id, "Playback"), \
  384. RX_ROUTES(id, "Capture")
  385. #define ADDER_ROUTES(id, sname) \
  386. { "Adder" #id, "RX1", "RX1" }, \
  387. { "Adder" #id, "RX2", "RX2" }, \
  388. { "Adder" #id, "RX3", "RX3" }, \
  389. { "Adder" #id, "RX4", "RX4" }, \
  390. { "Adder" #id, "RX5", "RX5" }, \
  391. { "Adder" #id, "RX6", "RX6" }, \
  392. { "Adder" #id, "RX7", "RX7" }, \
  393. { "Adder" #id, "RX8", "RX8" }, \
  394. { "Adder" #id, "RX9", "RX9" }, \
  395. { "Adder" #id, "RX10", "RX10" }, \
  396. { "TX" #id, NULL, "Adder" #id }, \
  397. { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \
  398. { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \
  399. { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } \
  400. #define TX_ROUTES(id, sname) \
  401. ADDER_ROUTES(1, sname), \
  402. ADDER_ROUTES(2, sname), \
  403. ADDER_ROUTES(3, sname), \
  404. ADDER_ROUTES(4, sname), \
  405. ADDER_ROUTES(5, sname)
  406. #define MIXER_TX_ROUTES(id) \
  407. TX_ROUTES(id, "Playback"), \
  408. TX_ROUTES(id, "Capture")
  409. static const struct snd_soc_dapm_route tegra210_mixer_routes[] = {
  410. /* Input */
  411. MIXER_RX_ROUTES(1),
  412. MIXER_RX_ROUTES(2),
  413. MIXER_RX_ROUTES(3),
  414. MIXER_RX_ROUTES(4),
  415. MIXER_RX_ROUTES(5),
  416. MIXER_RX_ROUTES(6),
  417. MIXER_RX_ROUTES(7),
  418. MIXER_RX_ROUTES(8),
  419. MIXER_RX_ROUTES(9),
  420. MIXER_RX_ROUTES(10),
  421. /* Output */
  422. MIXER_TX_ROUTES(1),
  423. MIXER_TX_ROUTES(2),
  424. MIXER_TX_ROUTES(3),
  425. MIXER_TX_ROUTES(4),
  426. MIXER_TX_ROUTES(5),
  427. };
  428. static const struct snd_soc_component_driver tegra210_mixer_cmpnt = {
  429. .dapm_widgets = tegra210_mixer_widgets,
  430. .num_dapm_widgets = ARRAY_SIZE(tegra210_mixer_widgets),
  431. .dapm_routes = tegra210_mixer_routes,
  432. .num_dapm_routes = ARRAY_SIZE(tegra210_mixer_routes),
  433. .controls = tegra210_mixer_gain_ctls,
  434. .num_controls = ARRAY_SIZE(tegra210_mixer_gain_ctls),
  435. };
  436. static bool tegra210_mixer_wr_reg(struct device *dev,
  437. unsigned int reg)
  438. {
  439. if (reg < TEGRA210_MIXER_RX_LIMIT)
  440. reg = MIXER_REG_BASE(reg);
  441. else if (reg < TEGRA210_MIXER_TX_LIMIT)
  442. reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
  443. switch (reg) {
  444. case TEGRA210_MIXER_RX1_SOFT_RESET:
  445. case TEGRA210_MIXER_RX1_CIF_CTRL ... TEGRA210_MIXER_RX1_PEAK_CTRL:
  446. case TEGRA210_MIXER_TX1_ENABLE:
  447. case TEGRA210_MIXER_TX1_SOFT_RESET:
  448. case TEGRA210_MIXER_TX1_INT_MASK ... TEGRA210_MIXER_TX1_ADDER_CONFIG:
  449. case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CG:
  450. case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL ... TEGRA210_MIXER_CTRL:
  451. return true;
  452. default:
  453. return false;
  454. }
  455. }
  456. static bool tegra210_mixer_rd_reg(struct device *dev,
  457. unsigned int reg)
  458. {
  459. if (reg < TEGRA210_MIXER_RX_LIMIT)
  460. reg = MIXER_REG_BASE(reg);
  461. else if (reg < TEGRA210_MIXER_TX_LIMIT)
  462. reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
  463. switch (reg) {
  464. case TEGRA210_MIXER_RX1_SOFT_RESET ... TEGRA210_MIXER_RX1_SAMPLE_COUNT:
  465. case TEGRA210_MIXER_TX1_ENABLE ... TEGRA210_MIXER_TX1_ADDER_CONFIG:
  466. case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CTRL:
  467. return true;
  468. default:
  469. return false;
  470. }
  471. }
  472. static bool tegra210_mixer_volatile_reg(struct device *dev,
  473. unsigned int reg)
  474. {
  475. if (reg < TEGRA210_MIXER_RX_LIMIT)
  476. reg = MIXER_REG_BASE(reg);
  477. else if (reg < TEGRA210_MIXER_TX_LIMIT)
  478. reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE;
  479. switch (reg) {
  480. case TEGRA210_MIXER_RX1_SOFT_RESET:
  481. case TEGRA210_MIXER_RX1_STATUS:
  482. case TEGRA210_MIXER_TX1_SOFT_RESET:
  483. case TEGRA210_MIXER_TX1_STATUS:
  484. case TEGRA210_MIXER_TX1_INT_STATUS:
  485. case TEGRA210_MIXER_TX1_INT_SET:
  486. case TEGRA210_MIXER_SOFT_RESET:
  487. case TEGRA210_MIXER_STATUS:
  488. case TEGRA210_MIXER_INT_STATUS:
  489. case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL:
  490. case TEGRA210_MIXER_GAIN_CFG_RAM_DATA:
  491. case TEGRA210_MIXER_PEAKM_RAM_CTRL:
  492. case TEGRA210_MIXER_PEAKM_RAM_DATA:
  493. return true;
  494. default:
  495. return false;
  496. }
  497. }
  498. static bool tegra210_mixer_precious_reg(struct device *dev,
  499. unsigned int reg)
  500. {
  501. switch (reg) {
  502. case TEGRA210_MIXER_GAIN_CFG_RAM_DATA:
  503. case TEGRA210_MIXER_PEAKM_RAM_DATA:
  504. return true;
  505. default:
  506. return false;
  507. }
  508. }
  509. static const struct regmap_config tegra210_mixer_regmap_config = {
  510. .reg_bits = 32,
  511. .reg_stride = 4,
  512. .val_bits = 32,
  513. .max_register = TEGRA210_MIXER_CTRL,
  514. .writeable_reg = tegra210_mixer_wr_reg,
  515. .readable_reg = tegra210_mixer_rd_reg,
  516. .volatile_reg = tegra210_mixer_volatile_reg,
  517. .precious_reg = tegra210_mixer_precious_reg,
  518. .reg_defaults = tegra210_mixer_reg_defaults,
  519. .num_reg_defaults = ARRAY_SIZE(tegra210_mixer_reg_defaults),
  520. .cache_type = REGCACHE_FLAT,
  521. };
  522. static const struct of_device_id tegra210_mixer_of_match[] = {
  523. { .compatible = "nvidia,tegra210-amixer" },
  524. {},
  525. };
  526. MODULE_DEVICE_TABLE(of, tegra210_mixer_of_match);
  527. static int tegra210_mixer_platform_probe(struct platform_device *pdev)
  528. {
  529. struct device *dev = &pdev->dev;
  530. struct tegra210_mixer *mixer;
  531. void __iomem *regs;
  532. int err, i;
  533. mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
  534. if (!mixer)
  535. return -ENOMEM;
  536. dev_set_drvdata(dev, mixer);
  537. /* Use default gain value for all MIXER inputs */
  538. for (i = 0; i < TEGRA210_MIXER_RX_MAX; i++)
  539. mixer->gain_value[i] = gain_params.gain_value;
  540. regs = devm_platform_ioremap_resource(pdev, 0);
  541. if (IS_ERR(regs))
  542. return PTR_ERR(regs);
  543. mixer->regmap = devm_regmap_init_mmio(dev, regs,
  544. &tegra210_mixer_regmap_config);
  545. if (IS_ERR(mixer->regmap)) {
  546. dev_err(dev, "regmap init failed\n");
  547. return PTR_ERR(mixer->regmap);
  548. }
  549. regcache_cache_only(mixer->regmap, true);
  550. err = devm_snd_soc_register_component(dev, &tegra210_mixer_cmpnt,
  551. tegra210_mixer_dais,
  552. ARRAY_SIZE(tegra210_mixer_dais));
  553. if (err) {
  554. dev_err(dev, "can't register MIXER component, err: %d\n", err);
  555. return err;
  556. }
  557. pm_runtime_enable(dev);
  558. return 0;
  559. }
  560. static void tegra210_mixer_platform_remove(struct platform_device *pdev)
  561. {
  562. pm_runtime_disable(&pdev->dev);
  563. }
  564. static const struct dev_pm_ops tegra210_mixer_pm_ops = {
  565. SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
  566. tegra210_mixer_runtime_resume, NULL)
  567. SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
  568. pm_runtime_force_resume)
  569. };
  570. static struct platform_driver tegra210_mixer_driver = {
  571. .driver = {
  572. .name = "tegra210_mixer",
  573. .of_match_table = tegra210_mixer_of_match,
  574. .pm = &tegra210_mixer_pm_ops,
  575. },
  576. .probe = tegra210_mixer_platform_probe,
  577. .remove = tegra210_mixer_platform_remove,
  578. };
  579. module_platform_driver(tegra210_mixer_driver);
  580. MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
  581. MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver");
  582. MODULE_LICENSE("GPL v2");