cs40l26-a2h.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // cs40l26.c -- ALSA SoC Audio driver for Cirrus Logic Haptic Device: CS40L26
  4. //
  5. // Copyright 2022 Cirrus Logic. Inc.
  6. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  7. #include <linux/vibrator/cs40l26.h>
  8. #else
  9. #include <linux/mfd/cs40l26.h>
  10. #endif
  11. static const struct cs40l26_pll_sysclk_config cs40l26_pll_sysclk[] = {
  12. {CS40L26_PLL_CLK_FRQ_32768, CS40L26_PLL_CLK_CFG_32768},
  13. {CS40L26_PLL_CLK_FRQ_1536000, CS40L26_PLL_CLK_CFG_1536000},
  14. {CS40L26_PLL_CLK_FRQ_3072000, CS40L26_PLL_CLK_CFG_3072000},
  15. {CS40L26_PLL_CLK_FRQ_6144000, CS40L26_PLL_CLK_CFG_6144000},
  16. {CS40L26_PLL_CLK_FRQ_9600000, CS40L26_PLL_CLK_CFG_9600000},
  17. {CS40L26_PLL_CLK_FRQ_12288000, CS40L26_PLL_CLK_CFG_12288000},
  18. };
  19. static int cs40l26_get_clk_config(u32 freq, u8 *clk_cfg)
  20. {
  21. int i;
  22. for (i = 0; i < ARRAY_SIZE(cs40l26_pll_sysclk); i++) {
  23. if (cs40l26_pll_sysclk[i].freq == freq) {
  24. *clk_cfg = cs40l26_pll_sysclk[i].clk_cfg;
  25. return 0;
  26. }
  27. }
  28. return -EINVAL;
  29. }
  30. static int cs40l26_swap_ext_clk(struct cs40l26_codec *codec, u8 clk_src)
  31. {
  32. struct regmap *regmap = codec->regmap;
  33. struct device *dev = codec->dev;
  34. u8 clk_cfg, clk_sel;
  35. int error;
  36. switch (clk_src) {
  37. case CS40L26_PLL_REFCLK_BCLK:
  38. clk_sel = CS40L26_PLL_CLK_SEL_BCLK;
  39. error = cs40l26_get_clk_config(codec->sysclk_rate, &clk_cfg);
  40. break;
  41. case CS40L26_PLL_REFCLK_MCLK:
  42. clk_sel = CS40L26_PLL_CLK_SEL_MCLK;
  43. error = cs40l26_get_clk_config(CS40L26_PLL_CLK_FRQ_32768, &clk_cfg);
  44. break;
  45. case CS40L26_PLL_REFCLK_FSYNC:
  46. error = -EPERM;
  47. break;
  48. default:
  49. error = -EINVAL;
  50. }
  51. if (error) {
  52. dev_err(dev, "Failed to get clock configuration\n");
  53. return error;
  54. }
  55. error = cs40l26_set_pll_loop(codec->core, CS40L26_PLL_REFCLK_SET_OPEN_LOOP);
  56. if (error)
  57. return error;
  58. error = regmap_update_bits(regmap, CS40L26_REFCLK_INPUT, CS40L26_PLL_REFCLK_FREQ_MASK |
  59. CS40L26_PLL_REFCLK_SEL_MASK, (clk_cfg << CS40L26_PLL_REFCLK_FREQ_SHIFT) |
  60. clk_sel);
  61. if (error) {
  62. dev_err(dev, "Failed to update REFCLK input\n");
  63. return error;
  64. }
  65. return cs40l26_set_pll_loop(codec->core, CS40L26_PLL_REFCLK_SET_CLOSED_LOOP);
  66. }
  67. static int cs40l26_clk_en(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event)
  68. {
  69. struct cs40l26_codec *codec =
  70. snd_soc_component_get_drvdata(snd_soc_dapm_to_component(w->dapm));
  71. struct cs40l26_private *cs40l26 = codec->core;
  72. struct device *dev = cs40l26->dev;
  73. int error;
  74. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  75. dev_info(dev, "%s: %s\n", __func__, event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
  76. #else
  77. dev_dbg(dev, "%s: %s\n", __func__, event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
  78. #endif
  79. switch (event) {
  80. case SND_SOC_DAPM_POST_PMU:
  81. mutex_lock(&cs40l26->lock);
  82. cs40l26_vibe_state_update(cs40l26, CS40L26_VIBE_STATE_EVENT_ASP_START);
  83. error = cs40l26_asp_start(cs40l26);
  84. mutex_unlock(&cs40l26->lock);
  85. if (error)
  86. return error;
  87. if (!completion_done(&cs40l26->i2s_cont)) {
  88. if (!wait_for_completion_timeout(&cs40l26->i2s_cont,
  89. msecs_to_jiffies(CS40L26_ASP_START_TIMEOUT)))
  90. dev_warn(codec->dev, "SVC calibration not complete\n");
  91. }
  92. error = cs40l26_swap_ext_clk(codec, CS40L26_PLL_REFCLK_BCLK);
  93. if (error)
  94. return error;
  95. break;
  96. case SND_SOC_DAPM_PRE_PMD:
  97. error = cs40l26_swap_ext_clk(codec, CS40L26_PLL_REFCLK_MCLK);
  98. if (error)
  99. return error;
  100. mutex_lock(&cs40l26->lock);
  101. cs40l26_vibe_state_update(cs40l26, CS40L26_VIBE_STATE_EVENT_ASP_STOP);
  102. mutex_unlock(&cs40l26->lock);
  103. break;
  104. default:
  105. dev_err(dev, "Invalid event: %d\n", event);
  106. return -EINVAL;
  107. }
  108. return 0;
  109. }
  110. static int cs40l26_dsp_tx(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event)
  111. { struct cs40l26_codec *codec =
  112. snd_soc_component_get_drvdata(snd_soc_dapm_to_component(w->dapm));
  113. struct cs40l26_private *cs40l26 = codec->core;
  114. struct device *dev = cs40l26->dev;
  115. const struct firmware *fw;
  116. int error;
  117. u32 reg;
  118. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  119. dev_info(dev, "%s: %s\n", __func__, event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
  120. #else
  121. dev_dbg(dev, "%s: %s\n", __func__, event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
  122. #endif
  123. if (codec->dsp_bypass) {
  124. dev_err(dev, "Cannot use A2H while bypassing DSP\n");
  125. return -EPERM;
  126. }
  127. error = cl_dsp_get_reg(cs40l26->dsp, "A2HEN", CL_DSP_XM_UNPACKED_TYPE, CS40L26_A2H_ALGO_ID,
  128. &reg);
  129. if (error)
  130. return error;
  131. switch (event) {
  132. case SND_SOC_DAPM_POST_PMU:
  133. if (codec->tuning != codec->tuning_prev) {
  134. error = request_firmware(&fw, codec->bin_file, dev);
  135. if (error) {
  136. dev_err(codec->dev, "Failed to request %s\n", codec->bin_file);
  137. return error;
  138. }
  139. error = cl_dsp_coeff_file_parse(cs40l26->dsp, fw);
  140. release_firmware(fw);
  141. if (error) {
  142. dev_warn(dev, "Failed to load %s, %d. Continuing...",
  143. codec->bin_file, error);
  144. return error;
  145. }
  146. dev_info(dev, "%s Loaded Successfully\n", codec->bin_file);
  147. codec->tuning_prev = codec->tuning;
  148. error = cs40l26_mailbox_write(cs40l26, CS40L26_DSP_MBOX_CMD_A2H_REINIT);
  149. if (error)
  150. return error;
  151. }
  152. return regmap_write(cs40l26->regmap, reg, 1);
  153. case SND_SOC_DAPM_PRE_PMD:
  154. return regmap_write(cs40l26->regmap, reg, 0);
  155. default:
  156. dev_err(dev, "Invalid A2H event: %d\n", event);
  157. return -EINVAL;
  158. }
  159. }
  160. static int cs40l26_asp_rx(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event)
  161. { struct cs40l26_codec *codec =
  162. snd_soc_component_get_drvdata(snd_soc_dapm_to_component(w->dapm));
  163. struct cs40l26_private *cs40l26 = codec->core;
  164. struct regmap *regmap = cs40l26->regmap;
  165. struct device *dev = cs40l26->dev;
  166. u32 asp_en_mask = CS40L26_ASP_TX1_EN_MASK | CS40L26_ASP_TX2_EN_MASK |
  167. CS40L26_ASP_RX1_EN_MASK | CS40L26_ASP_RX2_EN_MASK;
  168. u32 asp_enables;
  169. u8 data_src;
  170. int error;
  171. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  172. dev_info(dev, "%s: %s\n", __func__, event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
  173. #else
  174. dev_dbg(dev, "%s: %s\n", __func__, event == SND_SOC_DAPM_POST_PMU ? "PMU" : "PMD");
  175. #endif
  176. mutex_lock(&cs40l26->lock);
  177. data_src = codec->dsp_bypass ? CS40L26_DATA_SRC_ASPRX1 : CS40L26_DATA_SRC_DSP1TX1;
  178. switch (event) {
  179. case SND_SOC_DAPM_POST_PMU:
  180. error = regmap_update_bits(regmap, CS40L26_DACPCM1_INPUT,
  181. CS40L26_DATA_SRC_MASK, data_src);
  182. if (error) {
  183. dev_err(dev, "Failed to set DAC PCM input\n");
  184. goto err_mutex;
  185. }
  186. error = regmap_update_bits(regmap, CS40L26_ASPTX1_INPUT, CS40L26_DATA_SRC_MASK,
  187. data_src);
  188. if (error) {
  189. dev_err(dev, "Failed to set ASPTX1 input\n");
  190. goto err_mutex;
  191. }
  192. asp_enables = 1 | (1 << CS40L26_ASP_TX2_EN_SHIFT) | (1 << CS40L26_ASP_RX1_EN_SHIFT)
  193. | (1 << CS40L26_ASP_RX2_EN_SHIFT);
  194. error = regmap_update_bits(regmap, CS40L26_ASP_ENABLES1, asp_en_mask, asp_enables);
  195. if (error) {
  196. dev_err(dev, "Failed to enable ASP channels\n");
  197. goto err_mutex;
  198. }
  199. break;
  200. case SND_SOC_DAPM_PRE_PMD:
  201. error = cs40l26_mailbox_write(cs40l26, CS40L26_DSP_MBOX_CMD_STOP_I2S);
  202. if (error)
  203. goto err_mutex;
  204. error = regmap_update_bits(regmap, CS40L26_ASP_ENABLES1, asp_en_mask, 0);
  205. if (error) {
  206. dev_err(dev, "Failed to clear ASPTX1 input\n");
  207. goto err_mutex;
  208. }
  209. error = regmap_update_bits(regmap, CS40L26_ASPTX1_INPUT, CS40L26_DATA_SRC_MASK,
  210. CS40L26_DATA_SRC_VMON);
  211. if (error)
  212. dev_err(dev, "Failed to set ASPTX1 input\n");
  213. break;
  214. default:
  215. dev_err(dev, "Invalid PCM event: %d\n", event);
  216. error = -EINVAL;
  217. }
  218. err_mutex:
  219. mutex_unlock(&cs40l26->lock);
  220. return error;
  221. }
  222. static int cs40l26_i2s_vmon_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  223. {
  224. struct cs40l26_codec *codec =
  225. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  226. struct cs40l26_private *cs40l26 = codec->core;
  227. int error;
  228. u32 val;
  229. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  230. dev_info(cs40l26->dev, "%s\n", __func__);
  231. #endif
  232. error = cs40l26_pm_enter(cs40l26->dev);
  233. if (error)
  234. return error;
  235. error = regmap_read(cs40l26->regmap, CS40L26_SPKMON_VMON_DEC_OUT_DATA, &val);
  236. if (error) {
  237. dev_err(cs40l26->dev, "Failed to get VMON Data for I2S\n");
  238. goto pm_err;
  239. }
  240. if (val & CS40L26_VMON_OVFL_FLAG_MASK) {
  241. dev_err(cs40l26->dev, "I2S VMON overflow detected\n");
  242. error = -EOVERFLOW;
  243. goto pm_err;
  244. }
  245. ucontrol->value.enumerated.item[0] = val & CS40L26_VMON_DEC_OUT_DATA_MASK;
  246. pm_err:
  247. cs40l26_pm_exit(cs40l26->dev);
  248. return error;
  249. }
  250. static int cs40l26_dsp_bypass_get(struct snd_kcontrol *kcontrol,
  251. struct snd_ctl_elem_value *ucontrol)
  252. {
  253. struct cs40l26_codec *codec =
  254. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  255. struct cs40l26_private *cs40l26 = codec->core;
  256. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  257. dev_info(cs40l26->dev, "%s\n", __func__);
  258. #endif
  259. mutex_lock(&cs40l26->lock);
  260. if (codec->dsp_bypass)
  261. ucontrol->value.enumerated.item[0] = 1;
  262. else
  263. ucontrol->value.enumerated.item[0] = 0;
  264. mutex_unlock(&cs40l26->lock);
  265. return 0;
  266. }
  267. static int cs40l26_dsp_bypass_put(struct snd_kcontrol *kcontrol,
  268. struct snd_ctl_elem_value *ucontrol)
  269. {
  270. struct cs40l26_codec *codec =
  271. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  272. struct cs40l26_private *cs40l26 = codec->core;
  273. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  274. dev_info(cs40l26->dev, "%s\n", __func__);
  275. #endif
  276. mutex_lock(&cs40l26->lock);
  277. if (ucontrol->value.enumerated.item[0])
  278. codec->dsp_bypass = true;
  279. else
  280. codec->dsp_bypass = false;
  281. mutex_unlock(&cs40l26->lock);
  282. return 0;
  283. }
  284. static int cs40l26_svc_en_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  285. {
  286. struct cs40l26_codec *codec =
  287. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  288. struct cs40l26_private *cs40l26 = codec->core;
  289. struct regmap *regmap = cs40l26->regmap;
  290. struct device *dev = cs40l26->dev;
  291. unsigned int val = 0, reg;
  292. int error;
  293. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  294. dev_info(dev, "%s\n", __func__);
  295. #endif
  296. error = cl_dsp_get_reg(cs40l26->dsp, "FLAGS", CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID,
  297. &reg);
  298. if (error)
  299. return error;
  300. error = cs40l26_pm_enter(dev);
  301. if (error)
  302. return error;
  303. error = regmap_read(regmap, reg, &val);
  304. if (error) {
  305. dev_err(cs40l26->dev, "Failed to read FLAGS\n");
  306. goto pm_err;
  307. }
  308. if (val & CS40L26_SVC_EN_MASK)
  309. ucontrol->value.enumerated.item[0] = 1;
  310. else
  311. ucontrol->value.enumerated.item[0] = 0;
  312. pm_err:
  313. cs40l26_pm_exit(dev);
  314. return error;
  315. }
  316. static int cs40l26_svc_en_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  317. {
  318. struct snd_soc_dapm_context *dapm =
  319. snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
  320. struct cs40l26_codec *codec =
  321. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  322. struct cs40l26_private *cs40l26 = codec->core;
  323. struct regmap *regmap = cs40l26->regmap;
  324. struct device *dev = cs40l26->dev;
  325. unsigned int reg;
  326. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  327. int error = 0;
  328. #else
  329. int error;
  330. #endif
  331. #if IS_ENABLED(CONFIG_SEC_FACTORY)
  332. return error;
  333. #endif
  334. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  335. dev_info(dev, "%s\n", __func__);
  336. #endif
  337. error = cl_dsp_get_reg(cs40l26->dsp, "FLAGS", CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID,
  338. &reg);
  339. if (error)
  340. return error;
  341. error = cs40l26_pm_enter(dev);
  342. if (error)
  343. return error;
  344. snd_soc_dapm_mutex_lock(dapm);
  345. error = regmap_update_bits(regmap, reg, CS40L26_SVC_EN_MASK,
  346. ucontrol->value.enumerated.item[0]);
  347. if (error)
  348. dev_err(cs40l26->dev, "Failed to specify SVC for streaming\n");
  349. snd_soc_dapm_mutex_unlock(dapm);
  350. cs40l26_pm_exit(dev);
  351. return error;
  352. }
  353. static int cs40l26_invert_streaming_data_get(struct snd_kcontrol *kcontrol,
  354. struct snd_ctl_elem_value *ucontrol)
  355. {
  356. struct cs40l26_codec *codec =
  357. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  358. struct cs40l26_private *cs40l26 = codec->core;
  359. struct regmap *regmap = cs40l26->regmap;
  360. struct device *dev = cs40l26->dev;
  361. unsigned int val = 0, reg;
  362. int error;
  363. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  364. dev_info(dev, "%s\n", __func__);
  365. #endif
  366. error = cl_dsp_get_reg(cs40l26->dsp, "SOURCE_INVERT",
  367. CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
  368. if (error)
  369. return error;
  370. error = cs40l26_pm_enter(dev);
  371. if (error)
  372. return error;
  373. error = regmap_read(regmap, reg, &val);
  374. if (error) {
  375. dev_err(cs40l26->dev, "Failed to read SOURCE_INVERT\n");
  376. goto pm_err;
  377. }
  378. if (val)
  379. ucontrol->value.enumerated.item[0] = 1;
  380. else
  381. ucontrol->value.enumerated.item[0] = 0;
  382. pm_err:
  383. cs40l26_pm_exit(dev);
  384. return error;
  385. }
  386. static int cs40l26_invert_streaming_data_put(struct snd_kcontrol *kcontrol,
  387. struct snd_ctl_elem_value *ucontrol)
  388. {
  389. struct snd_soc_dapm_context *dapm =
  390. snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
  391. struct cs40l26_codec *codec =
  392. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  393. struct cs40l26_private *cs40l26 = codec->core;
  394. struct regmap *regmap = cs40l26->regmap;
  395. struct device *dev = cs40l26->dev;
  396. unsigned int reg;
  397. int error;
  398. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  399. dev_info(dev, "%s\n", __func__);
  400. #endif
  401. error = cl_dsp_get_reg(cs40l26->dsp, "SOURCE_INVERT",
  402. CL_DSP_XM_UNPACKED_TYPE, CS40L26_EXT_ALGO_ID, &reg);
  403. if (error)
  404. return error;
  405. error = cs40l26_pm_enter(dev);
  406. if (error)
  407. return error;
  408. snd_soc_dapm_mutex_lock(dapm);
  409. error = regmap_write(regmap, reg, ucontrol->value.enumerated.item[0]);
  410. if (error)
  411. dev_err(cs40l26->dev, "Failed to specify invert streaming data\n");
  412. snd_soc_dapm_mutex_unlock(dapm);
  413. cs40l26_pm_exit(dev);
  414. return error;
  415. }
  416. static int cs40l26_tuning_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  417. {
  418. struct cs40l26_codec *codec =
  419. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  420. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  421. struct cs40l26_private *cs40l26 = codec->core;
  422. dev_info(cs40l26->dev, "%s\n", __func__);
  423. #endif
  424. ucontrol->value.enumerated.item[0] = codec->tuning;
  425. return 0;
  426. }
  427. static int cs40l26_tuning_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  428. {
  429. struct cs40l26_codec *codec =
  430. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  431. struct cs40l26_private *cs40l26 = codec->core;
  432. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  433. dev_info(cs40l26->dev, "%s\n", __func__);
  434. #endif
  435. if (ucontrol->value.enumerated.item[0] == codec->tuning)
  436. return 0;
  437. if (cs40l26->asp_enable)
  438. return -EBUSY;
  439. codec->tuning = ucontrol->value.enumerated.item[0];
  440. memset(codec->bin_file, 0, PAGE_SIZE);
  441. codec->bin_file[PAGE_SIZE - 1] = '\0';
  442. if (codec->tuning > 0)
  443. snprintf(codec->bin_file, PAGE_SIZE, "cs40l26-a2h%d.bin", codec->tuning);
  444. else
  445. snprintf(codec->bin_file, PAGE_SIZE, "cs40l26-a2h.bin");
  446. return 0;
  447. }
  448. static int cs40l26_a2h_level_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  449. {
  450. struct cs40l26_codec *codec =
  451. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  452. struct cs40l26_private *cs40l26 = codec->core;
  453. struct regmap *regmap = cs40l26->regmap;
  454. struct device *dev = cs40l26->dev;
  455. unsigned int val = 0, reg;
  456. int error;
  457. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  458. dev_info(dev, "%s\n", __func__);
  459. #endif
  460. error = cl_dsp_get_reg(cs40l26->dsp, "VOLUMELEVEL", CL_DSP_XM_UNPACKED_TYPE,
  461. CS40L26_A2H_ALGO_ID, &reg);
  462. if (error)
  463. return error;
  464. error = cs40l26_pm_enter(dev);
  465. if (error)
  466. return error;
  467. error = regmap_read(regmap, reg, &val);
  468. if (error) {
  469. dev_err(dev, "Failed to get VOLUMELEVEL\n");
  470. goto pm_err;
  471. }
  472. ucontrol->value.integer.value[0] = val;
  473. pm_err:
  474. cs40l26_pm_exit(dev);
  475. return error;
  476. }
  477. static int cs40l26_a2h_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  478. {
  479. struct snd_soc_dapm_context *dapm =
  480. snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
  481. struct cs40l26_codec *codec =
  482. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  483. struct cs40l26_private *cs40l26 = codec->core;
  484. struct regmap *regmap = cs40l26->regmap;
  485. struct device *dev = cs40l26->dev;
  486. unsigned int val = 0, reg;
  487. int error;
  488. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  489. dev_info(dev, "%s\n", __func__);
  490. #endif
  491. error = cl_dsp_get_reg(cs40l26->dsp, "VOLUMELEVEL", CL_DSP_XM_UNPACKED_TYPE,
  492. CS40L26_A2H_ALGO_ID, &reg);
  493. if (error)
  494. return error;
  495. error = cs40l26_pm_enter(dev);
  496. if (error)
  497. return error;
  498. snd_soc_dapm_mutex_lock(dapm);
  499. if (ucontrol->value.integer.value[0] > CS40L26_A2H_LEVEL_MAX)
  500. val = CS40L26_A2H_LEVEL_MAX;
  501. else if (ucontrol->value.integer.value[0] < CS40L26_A2H_LEVEL_MIN)
  502. val = CS40L26_A2H_LEVEL_MIN;
  503. else
  504. val = ucontrol->value.integer.value[0];
  505. error = regmap_write(regmap, reg, val);
  506. if (error)
  507. dev_err(dev, "Failed to set VOLUMELEVEL\n");
  508. snd_soc_dapm_mutex_unlock(dapm);
  509. cs40l26_pm_exit(dev);
  510. return error;
  511. }
  512. static int cs40l26_a2h_delay_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  513. {
  514. struct cs40l26_codec *codec =
  515. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  516. struct cs40l26_private *cs40l26 = codec->core;
  517. struct regmap *regmap = cs40l26->regmap;
  518. struct device *dev = cs40l26->dev;
  519. unsigned int val = 0, reg;
  520. int error;
  521. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  522. dev_info(dev, "%s\n", __func__);
  523. #endif
  524. error = cl_dsp_get_reg(cs40l26->dsp, "LRADELAYSAMPS",
  525. CL_DSP_XM_UNPACKED_TYPE, CS40L26_A2H_ALGO_ID, &reg);
  526. if (error)
  527. return error;
  528. error = cs40l26_pm_enter(dev);
  529. if (error)
  530. return error;
  531. error = regmap_read(regmap, reg, &val);
  532. if (error) {
  533. dev_err(dev, "Failed to get LRADELAYSAMPS\n");
  534. goto err;
  535. }
  536. ucontrol->value.integer.value[0] = val;
  537. err:
  538. cs40l26_pm_exit(dev);
  539. return error;
  540. }
  541. static int cs40l26_a2h_delay_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  542. {
  543. struct snd_soc_dapm_context *dapm =
  544. snd_soc_component_get_dapm(snd_soc_kcontrol_component(kcontrol));
  545. struct cs40l26_codec *codec =
  546. snd_soc_component_get_drvdata(snd_soc_kcontrol_component(kcontrol));
  547. struct cs40l26_private *cs40l26 = codec->core;
  548. struct regmap *regmap = cs40l26->regmap;
  549. struct device *dev = cs40l26->dev;
  550. unsigned int val = 0, reg;
  551. int error;
  552. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  553. dev_info(dev, "%s\n", __func__);
  554. #endif
  555. error = cl_dsp_get_reg(cs40l26->dsp, "LRADELAYSAMPS",
  556. CL_DSP_XM_UNPACKED_TYPE, CS40L26_A2H_ALGO_ID, &reg);
  557. if (error)
  558. return error;
  559. error = cs40l26_pm_enter(dev);
  560. if (error)
  561. return error;
  562. snd_soc_dapm_mutex_lock(dapm);
  563. if (ucontrol->value.integer.value[0] > CS40L26_A2H_DELAY_MAX)
  564. val = CS40L26_A2H_DELAY_MAX;
  565. else if (ucontrol->value.integer.value[0] < 0)
  566. val = 0;
  567. else
  568. val = ucontrol->value.integer.value[0];
  569. error = regmap_write(regmap, reg, val);
  570. if (error)
  571. dev_err(dev, "Failed to set LRADELAYSAMPS\n");
  572. snd_soc_dapm_mutex_unlock(dapm);
  573. cs40l26_pm_exit(dev);
  574. return error;
  575. }
  576. static const struct snd_kcontrol_new cs40l26_controls[] = {
  577. SOC_SINGLE_EXT("A2H Tuning", 0, 0, CS40L26_A2H_MAX_TUNINGS, 0, cs40l26_tuning_get,
  578. cs40l26_tuning_put),
  579. SOC_SINGLE_EXT("A2H Level", 0, 0, CS40L26_A2H_LEVEL_MAX, 0, cs40l26_a2h_level_get,
  580. cs40l26_a2h_level_put),
  581. SOC_SINGLE_EXT("SVC Algo Enable", 0, 0, 1, 0, cs40l26_svc_en_get, cs40l26_svc_en_put),
  582. SOC_SINGLE_EXT("Invert streaming data", 0, 0, 1, 0, cs40l26_invert_streaming_data_get,
  583. cs40l26_invert_streaming_data_put),
  584. SOC_SINGLE_EXT("I2S VMON", 0, 0, CS40L26_VMON_DEC_OUT_DATA_MAX, 0,
  585. cs40l26_i2s_vmon_get, NULL),
  586. SOC_SINGLE_EXT("DSP Bypass", 0, 0, 1, 0, cs40l26_dsp_bypass_get, cs40l26_dsp_bypass_put),
  587. SOC_SINGLE_EXT("A2H Delay", 0, 0, CS40L26_A2H_DELAY_MAX, 0, cs40l26_a2h_delay_get,
  588. cs40l26_a2h_delay_put),
  589. };
  590. static const char * const cs40l26_out_mux_texts[] = { "Off", "PCM", "A2H" };
  591. static SOC_ENUM_SINGLE_VIRT_DECL(cs40l26_out_mux_enum, cs40l26_out_mux_texts);
  592. static const struct snd_kcontrol_new cs40l26_out_mux =
  593. SOC_DAPM_ENUM("Haptics Source", cs40l26_out_mux_enum);
  594. static const struct snd_soc_dapm_widget cs40l26_dapm_widgets[] = {
  595. SND_SOC_DAPM_SUPPLY_S("ASP PLL", 0, SND_SOC_NOPM, 0, 0, cs40l26_clk_en,
  596. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  597. SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, SND_SOC_NOPM, 0, 0),
  598. SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, SND_SOC_NOPM, 0, 0),
  599. SND_SOC_DAPM_PGA_E("PCM", SND_SOC_NOPM, 0, 0, NULL, 0, cs40l26_asp_rx,
  600. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  601. SND_SOC_DAPM_MIXER_E("A2H", SND_SOC_NOPM, 0, 0, NULL, 0, cs40l26_dsp_tx,
  602. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  603. SND_SOC_DAPM_MUX("Haptics Source", SND_SOC_NOPM, 0, 0, &cs40l26_out_mux),
  604. SND_SOC_DAPM_OUTPUT("OUT"),
  605. };
  606. static const struct snd_soc_dapm_route cs40l26_dapm_routes[] = {
  607. { "ASP Playback", NULL, "ASP PLL" },
  608. { "ASPRX1", NULL, "ASP Playback" },
  609. { "ASPRX2", NULL, "ASP Playback" },
  610. { "PCM", NULL, "ASPRX1" },
  611. { "PCM", NULL, "ASPRX2" },
  612. { "A2H", NULL, "PCM" },
  613. { "Haptics Source", "PCM", "PCM" },
  614. { "Haptics Source", "A2H", "A2H" },
  615. { "OUT", NULL, "Haptics Source" },
  616. };
  617. static int cs40l26_component_set_sysclk(struct snd_soc_component *component,
  618. int clk_id, int source, unsigned int freq, int dir)
  619. {
  620. struct cs40l26_codec *codec = snd_soc_component_get_drvdata(component);
  621. struct device *dev = codec->dev;
  622. u8 clk_cfg;
  623. int error;
  624. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  625. dev_info(dev, "%s clk_id(%d) source(%d) freq(%u) dir(%d)\n",
  626. __func__, clk_id, source, freq, dir);
  627. #endif
  628. error = cs40l26_get_clk_config((u32) (CS40L26_PLL_CLK_FREQ_MASK & freq), &clk_cfg);
  629. if (error) {
  630. dev_err(dev, "Invalid Clock Frequency: %u Hz\n", freq);
  631. return error;
  632. }
  633. if (clk_id != 0) {
  634. dev_err(dev, "Invalid Input Clock (ID: %d)\n", clk_id);
  635. return -EINVAL;
  636. }
  637. codec->sysclk_rate = (u32) (CS40L26_PLL_CLK_FREQ_MASK & freq);
  638. return 0;
  639. }
  640. static int cs40l26_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
  641. {
  642. struct cs40l26_codec *codec =
  643. snd_soc_component_get_drvdata(codec_dai->component);
  644. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  645. dev_info(codec->dev, "%s fmt(%u)\n", __func__, fmt);
  646. #endif
  647. if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
  648. dev_err(codec->dev, "Device can not be master\n");
  649. return -EINVAL;
  650. }
  651. switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  652. case SND_SOC_DAIFMT_NB_NF:
  653. codec->daifmt = 0;
  654. break;
  655. case SND_SOC_DAIFMT_NB_IF:
  656. codec->daifmt = CS40L26_ASP_FSYNC_INV_MASK;
  657. break;
  658. case SND_SOC_DAIFMT_IB_NF:
  659. codec->daifmt = CS40L26_ASP_BCLK_INV_MASK;
  660. break;
  661. case SND_SOC_DAIFMT_IB_IF:
  662. codec->daifmt = CS40L26_ASP_FSYNC_INV_MASK | CS40L26_ASP_BCLK_INV_MASK;
  663. break;
  664. default:
  665. dev_err(codec->dev, "Invalid DAI clock INV\n");
  666. return -EINVAL;
  667. }
  668. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  669. case SND_SOC_DAIFMT_DSP_A:
  670. codec->daifmt |= ((CS40L26_ASP_FMT_TDM1_DSPA << CS40L26_ASP_FMT_SHIFT) &
  671. CS40L26_ASP_FMT_MASK);
  672. break;
  673. case SND_SOC_DAIFMT_I2S:
  674. codec->daifmt |= ((CS40L26_ASP_FMT_I2S << CS40L26_ASP_FMT_SHIFT) &
  675. CS40L26_ASP_FMT_MASK);
  676. break;
  677. default:
  678. dev_err(codec->dev, "Invalid DAI format: 0x%X\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK);
  679. return -EINVAL;
  680. }
  681. return 0;
  682. }
  683. static int cs40l26_pcm_hw_params(struct snd_pcm_substream *substream,
  684. struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
  685. {
  686. struct cs40l26_codec *codec = snd_soc_component_get_drvdata(dai->component);
  687. int error, lrck = params_rate(params);
  688. u32 asp_rx_wl, asp_rx_width, ultrasonic;
  689. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  690. dev_info(codec->dev, "%s\n", __func__);
  691. #endif
  692. error = cs40l26_pm_enter(codec->dev);
  693. if (error)
  694. return error;
  695. if (lrck == 48000)
  696. ultrasonic = 0;
  697. else if (lrck == 96000)
  698. ultrasonic = 1;
  699. else
  700. error = -EINVAL;
  701. if (error) {
  702. dev_err(codec->dev, "Invalid sample rate: %d Hz\n", lrck);
  703. goto err_pm;
  704. }
  705. error = regmap_update_bits(codec->regmap, CS40L26_MONITOR_FILT,
  706. CS40L26_VIMON_DUAL_RATE_MASK,
  707. FIELD_PREP(CS40L26_VIMON_DUAL_RATE_MASK, ultrasonic));
  708. if (error)
  709. goto err_pm;
  710. asp_rx_wl = (u8) (params_width(params) & 0xFF);
  711. error = regmap_update_bits(codec->regmap, CS40L26_ASP_DATA_CONTROL5,
  712. CS40L26_ASP_RX_WL_MASK, asp_rx_wl);
  713. if (error) {
  714. dev_err(codec->dev, "Failed to update ASP RX WL\n");
  715. goto err_pm;
  716. }
  717. if (!codec->tdm_width)
  718. asp_rx_width = asp_rx_wl;
  719. else
  720. asp_rx_width = (u8) (codec->tdm_width & 0xFF);
  721. codec->daifmt |= ((asp_rx_width << CS40L26_ASP_RX_WIDTH_SHIFT) &
  722. CS40L26_ASP_RX_WIDTH_MASK);
  723. error = regmap_update_bits(codec->regmap, CS40L26_ASP_CONTROL2,
  724. CS40L26_ASP_FSYNC_INV_MASK | CS40L26_ASP_BCLK_INV_MASK |
  725. CS40L26_ASP_FMT_MASK | CS40L26_ASP_RX_WIDTH_MASK, codec->daifmt);
  726. if (error) {
  727. dev_err(codec->dev, "Failed to update ASP RX width\n");
  728. goto err_pm;
  729. }
  730. error = regmap_update_bits(codec->regmap, CS40L26_ASP_FRAME_CONTROL5,
  731. CS40L26_ASP_RX1_SLOT_MASK | CS40L26_ASP_RX2_SLOT_MASK,
  732. codec->tdm_slot[0] | (codec->tdm_slot[1] << CS40L26_ASP_RX2_SLOT_SHIFT));
  733. if (error) {
  734. dev_err(codec->dev, "Failed to update ASP slot number\n");
  735. goto err_pm;
  736. }
  737. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  738. dev_info(codec->dev, "ASP: %d bits in %d bit slots, slot #s: %d, %d\n",
  739. asp_rx_wl, asp_rx_width, codec->tdm_slot[0], codec->tdm_slot[1]);
  740. #else
  741. dev_dbg(codec->dev, "ASP: %d bits in %d bit slots, slot #s: %d, %d\n",
  742. asp_rx_wl, asp_rx_width, codec->tdm_slot[0], codec->tdm_slot[1]);
  743. #endif
  744. err_pm:
  745. cs40l26_pm_exit(codec->dev);
  746. return error;
  747. }
  748. static int cs40l26_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
  749. unsigned int rx_mask, int slots, int slot_width)
  750. {
  751. struct cs40l26_codec *codec =
  752. snd_soc_component_get_drvdata(dai->component);
  753. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  754. dev_info(codec->dev, "%s\n", __func__);
  755. #endif
  756. codec->tdm_width = slot_width;
  757. codec->tdm_slots = slots;
  758. /* Reset to slots 0,1 if TDM is being disabled, and catch the case
  759. * where both RX1 and RX2 would be set to slot 0 since that causes
  760. * hardware to flag an error
  761. */
  762. if (!slots || rx_mask == 0x1)
  763. rx_mask = 0x3;
  764. codec->tdm_slot[0] = ffs(rx_mask) - 1;
  765. rx_mask &= ~(1 << codec->tdm_slot[0]);
  766. codec->tdm_slot[1] = ffs(rx_mask) - 1;
  767. return 0;
  768. }
  769. static const struct snd_soc_dai_ops cs40l26_dai_ops = {
  770. .set_fmt = cs40l26_set_dai_fmt,
  771. .set_tdm_slot = cs40l26_set_tdm_slot,
  772. .hw_params = cs40l26_pcm_hw_params,
  773. };
  774. static struct snd_soc_dai_driver cs40l26_dai[] = {
  775. {
  776. .name = "cs40l26-pcm",
  777. .id = 0,
  778. .playback = {
  779. .stream_name = "ASP Playback",
  780. .channels_min = 1,
  781. .channels_max = 2,
  782. .rates = CS40L26_RATES,
  783. .formats = CS40L26_FORMATS,
  784. },
  785. .ops = &cs40l26_dai_ops,
  786. #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 4)
  787. .symmetric_rates = 1,
  788. #else
  789. .symmetric_rate = 1,
  790. #endif
  791. },
  792. };
  793. static int cs40l26_codec_probe(struct snd_soc_component *component)
  794. {
  795. struct cs40l26_codec *codec = snd_soc_component_get_drvdata(component);
  796. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  797. dev_info(codec->dev, "%s\n", __func__);
  798. #endif
  799. codec->bin_file = devm_kzalloc(codec->dev, PAGE_SIZE, GFP_KERNEL);
  800. if (!codec->bin_file)
  801. return -ENOMEM;
  802. codec->bin_file[PAGE_SIZE - 1] = '\0';
  803. snprintf(codec->bin_file, PAGE_SIZE, CS40L26_A2H_TUNING_FILE_NAME);
  804. /* Default audio SCLK frequency */
  805. codec->sysclk_rate = CS40L26_PLL_CLK_FRQ_1536000;
  806. codec->tdm_slot[0] = 0;
  807. codec->tdm_slot[1] = 1;
  808. return 0;
  809. }
  810. static const struct snd_soc_component_driver soc_codec_dev_cs40l26 = {
  811. .probe = cs40l26_codec_probe,
  812. .set_sysclk = cs40l26_component_set_sysclk,
  813. .dapm_widgets = cs40l26_dapm_widgets,
  814. .num_dapm_widgets = ARRAY_SIZE(cs40l26_dapm_widgets),
  815. .dapm_routes = cs40l26_dapm_routes,
  816. .num_dapm_routes = ARRAY_SIZE(cs40l26_dapm_routes),
  817. .controls = cs40l26_controls,
  818. .num_controls = ARRAY_SIZE(cs40l26_controls),
  819. };
  820. static int cs40l26_codec_driver_probe(struct platform_device *pdev)
  821. {
  822. struct cs40l26_private *cs40l26 = dev_get_drvdata(pdev->dev.parent);
  823. struct cs40l26_codec *codec;
  824. int error;
  825. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  826. dev_info(cs40l26->dev, "%s\n", __func__);
  827. #endif
  828. codec = devm_kzalloc(&pdev->dev, sizeof(struct cs40l26_codec), GFP_KERNEL);
  829. if (!codec)
  830. return -ENOMEM;
  831. codec->core = cs40l26;
  832. codec->regmap = cs40l26->regmap;
  833. codec->dev = &pdev->dev;
  834. platform_set_drvdata(pdev, codec);
  835. pm_runtime_enable(&pdev->dev);
  836. error = snd_soc_register_component(&pdev->dev, &soc_codec_dev_cs40l26,
  837. cs40l26_dai, ARRAY_SIZE(cs40l26_dai));
  838. if (error < 0)
  839. dev_err(&pdev->dev, "Failed to register codec: %d\n", error);
  840. return error;
  841. }
  842. static int cs40l26_codec_driver_remove(struct platform_device *pdev)
  843. {
  844. struct cs40l26_codec *codec = dev_get_drvdata(&pdev->dev);
  845. #ifdef CONFIG_CS40L26_SAMSUNG_FEATURE
  846. dev_info(codec->dev, "%s\n", __func__);
  847. #endif
  848. pm_runtime_disable(codec->dev);
  849. snd_soc_unregister_component(codec->dev);
  850. return 0;
  851. }
  852. static struct platform_driver cs40l26_codec_driver = {
  853. .driver = {
  854. .name = "cs40l26-codec",
  855. },
  856. .probe = cs40l26_codec_driver_probe,
  857. .remove = cs40l26_codec_driver_remove,
  858. };
  859. module_platform_driver(cs40l26_codec_driver);
  860. MODULE_DESCRIPTION("ASoC CS40L26 driver");
  861. MODULE_AUTHOR("Fred Treven <[email protected]>");
  862. MODULE_LICENSE("GPL v2");
  863. MODULE_ALIAS("platform:cs40l26-codec");