tegra210_mixer.c 19 KB

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