cirrus-amp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. * Extended support for Cirrus Logic Smart Amplifiers
  3. *
  4. * Copyright 2017 Cirrus Logic
  5. *
  6. * Author: David Rhodes <[email protected]>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/device.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/slab.h>
  17. #include <sound/cirrus/core.h>
  18. #include <sound/cirrus/big_data.h>
  19. #include <sound/cirrus/calibration.h>
  20. #include <sound/cirrus/power.h>
  21. #include "wm_adsp.h"
  22. #include <linux/firmware/cirrus/cs_dsp.h>
  23. #include <linux/firmware/cirrus/wmfw.h>
  24. struct class *cirrus_amp_class;
  25. EXPORT_SYMBOL_GPL(cirrus_amp_class);
  26. struct cirrus_amp_group *amp_group;
  27. static struct cirrus_cal_ops *cirrus_cal_ops[3] = {
  28. &cirrus_cspl_cal_ops,
  29. &cirrus_cspl_cal_ops,
  30. #if IS_ENABLED(CONFIG_SND_SOC_CS35L43)
  31. &cirrus_cs35l43_cal_ops
  32. #endif
  33. };
  34. struct cirrus_amp *cirrus_get_amp_from_suffix(const char *suffix)
  35. {
  36. int i;
  37. if (suffix == NULL)
  38. return NULL;
  39. if (amp_group == NULL || (amp_group->num_amps == 0))
  40. return NULL;
  41. pr_debug("%s: suffix = %s\n", __func__, suffix);
  42. for (i = 0; i < amp_group->num_amps; i++) {
  43. if (amp_group->amps[i].bd.bd_suffix) {
  44. pr_debug("%s: comparing %s & %s\n", __func__,
  45. amp_group->amps[i].bd.bd_suffix, suffix);
  46. if (!strcmp(amp_group->amps[i].bd.bd_suffix, suffix))
  47. return &amp_group->amps[i];
  48. }
  49. }
  50. for (i = 0; i < amp_group->num_amps; i++) {
  51. pr_debug("%s: comparing %s & %s\n", __func__,
  52. amp_group->amps[i].mfd_suffix, suffix);
  53. if (!strcmp(amp_group->amps[i].mfd_suffix, suffix))
  54. return &amp_group->amps[i];
  55. }
  56. return NULL;
  57. }
  58. EXPORT_SYMBOL_GPL(cirrus_get_amp_from_suffix);
  59. void cirrus_amp_register_i2c_error_callback(const char *suffix, void *func)
  60. {
  61. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  62. if (amp)
  63. amp->i2c_callback = func;
  64. }
  65. EXPORT_SYMBOL_GPL(cirrus_amp_register_i2c_error_callback);
  66. void cirrus_amp_register_error_callback(const char *suffix, void *func)
  67. {
  68. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  69. if (amp)
  70. amp->error_callback = func;
  71. }
  72. EXPORT_SYMBOL_GPL(cirrus_amp_register_error_callback);
  73. int cirrus_amp_add(const char *mfd_suffix, struct cirrus_amp_config cfg)
  74. {
  75. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(mfd_suffix);
  76. if (amp) {
  77. dev_info(amp_group->cal_dev,
  78. "Amp added, suffix: %s dsp_part_name: %s\n",
  79. mfd_suffix, cfg.dsp_part_name);
  80. amp->component = cfg.component;
  81. amp->regmap = cfg.regmap;
  82. amp->dsp_part_name = cfg.dsp_part_name;
  83. amp->num_pre_configs = cfg.num_pre_configs;
  84. amp->num_post_configs = cfg.num_post_configs;
  85. amp->mbox_cmd = cfg.mbox_cmd;
  86. amp->mbox_sts = cfg.mbox_sts;
  87. amp->global_en = cfg.global_en;
  88. amp->global_en_mask = cfg.global_en_mask;
  89. amp->vimon_alg_id = cfg.vimon_alg_id;
  90. amp->pwr.target_temp = cfg.target_temp;
  91. amp->pwr.exit_temp = cfg.exit_temp;
  92. amp->perform_vimon_cal = cfg.perform_vimon_cal;
  93. amp->calibration_disable = cfg.calibration_disable;
  94. amp->cal_vpk_id = cfg.cal_vpk_id ? cfg.cal_vpk_id :
  95. CIRRUS_CAL_RTLOG_ID_V_PEAK;
  96. amp->cal_ipk_id = cfg.cal_ipk_id ? cfg.cal_ipk_id :
  97. CIRRUS_CAL_RTLOG_ID_I_PEAK;
  98. amp->halo_alg_id = cfg.halo_alg_id ? cfg.halo_alg_id :
  99. CIRRUS_AMP_ALG_ID_HALO;
  100. amp->bd.bd_alg_id = cfg.bd_alg_id ? cfg.bd_alg_id :
  101. CIRRUS_AMP_ALG_ID_CSPL;
  102. amp->bd.bd_prefix = cfg.bd_prefix ? cfg.bd_prefix :
  103. "BDLOG_";
  104. amp->cal_vsc_ub = cfg.cal_vsc_ub ? cfg.cal_vsc_ub :
  105. CIRRUS_CAL_VIMON_CAL_VSC_UB;
  106. amp->cal_vsc_lb = cfg.cal_vsc_lb ? cfg.cal_vsc_lb :
  107. CIRRUS_CAL_VIMON_CAL_VSC_LB;
  108. amp->cal_isc_ub = cfg.cal_isc_ub ? cfg.cal_isc_ub :
  109. CIRRUS_CAL_VIMON_CAL_ISC_UB;
  110. amp->cal_isc_lb = cfg.cal_isc_lb ? cfg.cal_isc_lb :
  111. CIRRUS_CAL_VIMON_CAL_ISC_LB;
  112. amp->bd.max_temp_limit = cfg.bd_max_temp ?
  113. cfg.bd_max_temp - 1 : 99;
  114. amp->default_redc = cfg.default_redc ? cfg.default_redc :
  115. CIRRUS_CAL_RDC_DEFAULT;
  116. amp->cal_ops = cfg.cal_ops_idx ? cirrus_cal_ops[cfg.cal_ops_idx] :
  117. cirrus_cal_ops[CIRRUS_CAL_CSPL_CAL_OPS_IDX];
  118. amp->pre_config = kcalloc(cfg.num_pre_configs,
  119. sizeof(struct reg_sequence),
  120. GFP_KERNEL);
  121. amp->post_config = kcalloc(cfg.num_post_configs,
  122. sizeof(struct reg_sequence),
  123. GFP_KERNEL);
  124. amp->amp_reinit = cfg.amp_reinit;
  125. amp->runtime_pm = cfg.runtime_pm;
  126. amp_group->pwr_enable |= cfg.pwr_enable;
  127. memcpy(amp->pre_config, cfg.pre_config,
  128. sizeof(struct reg_sequence) * cfg.num_pre_configs);
  129. memcpy(amp->post_config, cfg.post_config,
  130. sizeof(struct reg_sequence) * cfg.num_post_configs);
  131. } else {
  132. dev_err(amp_group->cal_dev,
  133. "No amp with suffix %s registered\n", mfd_suffix);
  134. return -EINVAL;
  135. }
  136. return 0;
  137. }
  138. EXPORT_SYMBOL_GPL(cirrus_amp_add);
  139. int cirrus_amp_read_ctl(struct cirrus_amp *amp, const char *name,
  140. int type, unsigned int id, unsigned int *value)
  141. {
  142. struct wm_adsp *dsp = snd_soc_component_get_drvdata(amp->component);
  143. unsigned int tmp;
  144. int ret = 0, retry = CIRRUS_AMP_CTL_RETRY;
  145. if (amp->component) {
  146. do {
  147. ret = wm_adsp_read_ctl(dsp, name, type, id, (void *)&tmp, 4);
  148. *value = (tmp & 0xff0000) >> 8 |
  149. (tmp & 0xff00) << 8 |
  150. (tmp & 0xff000000) >> 24;
  151. if (ret)
  152. dev_err(dsp->cs_dsp.dev, "%s: ret = %d\n", __func__, ret);
  153. } while (ret != 0 && ret != -EINVAL && retry-- > 0);
  154. }
  155. return ret;
  156. }
  157. EXPORT_SYMBOL_GPL(cirrus_amp_read_ctl);
  158. int cirrus_amp_write_ctl(struct cirrus_amp *amp, const char *name,
  159. int type, unsigned int id, unsigned int value)
  160. {
  161. struct wm_adsp *dsp = snd_soc_component_get_drvdata(amp->component);
  162. unsigned int tmp;
  163. int ret = 0, retry = CIRRUS_AMP_CTL_RETRY;
  164. tmp = (value & 0xff0000) >> 8 |
  165. (value & 0xff00) << 8 |
  166. (value & 0xff000000) >> 24 |
  167. (value & 0xff) << 24;
  168. if (amp->component) {
  169. do {
  170. ret = wm_adsp_write_ctl(dsp, name, type, id, (void *)&tmp, 4);
  171. if (ret && ret != -EINVAL)
  172. dev_err(dsp->cs_dsp.dev, "%s: ret = %d\n", __func__, ret);
  173. } while (ret != 0 && ret != -EINVAL && retry-- > 0);
  174. }
  175. return ret;
  176. }
  177. EXPORT_SYMBOL_GPL(cirrus_amp_write_ctl);
  178. static const struct of_device_id cirrus_amp_of_match[] = {
  179. { .compatible = "cirrus-amp", },
  180. {},
  181. };
  182. MODULE_DEVICE_TABLE(of, cirrus_amp_of_match);
  183. static int cirrus_amp_probe(struct platform_device *pdev)
  184. {
  185. struct device_node *np;
  186. struct device_node *amp_node;
  187. const char **mfd_suffixes;
  188. const char **bd_suffixes;
  189. bool v_val_separate[CIRRUS_MAX_AMPS];
  190. int ret = 0, num = 0, num_amps, i, j;
  191. cirrus_amp_class = class_create(THIS_MODULE, "cirrus");
  192. if (IS_ERR(cirrus_amp_class)) {
  193. ret = PTR_ERR(cirrus_amp_class);
  194. pr_err("%s: Unable to register cirrus_amp class (%d)",
  195. __func__, ret);
  196. return ret;
  197. }
  198. for_each_matching_node(np, cirrus_amp_of_match)
  199. num++;
  200. if (num != 1) {
  201. pr_info("%s: Exactly 1 OF entry is allowed (%d detected)\n",
  202. __func__, num);
  203. ret = -EINVAL;
  204. goto class_err;
  205. }
  206. np = of_find_matching_node(NULL, cirrus_amp_of_match);
  207. if (!np) {
  208. pr_err("%s: Device node required\n", __func__);
  209. ret = -ENODEV;
  210. goto class_err;
  211. }
  212. num_amps = of_count_phandle_with_args(np, "cirrus,amps", NULL);
  213. if (num_amps <= 0) {
  214. pr_err("%s: Failed to parse 'cirrus,amps'\n", __func__);
  215. ret = -ENODEV;
  216. goto class_err;
  217. }
  218. amp_group = kzalloc(sizeof(struct cirrus_amp_group) +
  219. sizeof(struct cirrus_amp) * num_amps,
  220. GFP_KERNEL);
  221. mfd_suffixes = kcalloc(num_amps, sizeof(char *), GFP_KERNEL);
  222. bd_suffixes = kcalloc(num_amps, sizeof(char *), GFP_KERNEL);
  223. amp_group->num_amps = num_amps;
  224. for (i = 0; i < num_amps; i++) {
  225. amp_node = of_parse_phandle(np, "cirrus,amps", i);
  226. if (IS_ERR(amp_node)) {
  227. pr_err("%s: Failed to parse 'cirrus,amps' (%d)\n",
  228. __func__, i);
  229. ret = PTR_ERR(amp_node);
  230. goto suffix_free;
  231. }
  232. pr_debug("%s: Found linked amp: %s\n", __func__,
  233. amp_node->full_name);
  234. ret = of_property_read_string(amp_node, "cirrus,mfd-suffix",
  235. &mfd_suffixes[i]);
  236. if (ret < 0) {
  237. pr_err("%s: No MFD suffix found for amp: %s\n",
  238. __func__, amp_node->full_name);
  239. of_node_put(amp_node);
  240. goto suffix_free;
  241. }
  242. ret = of_property_read_string(amp_node, "cirrus,bd-suffix",
  243. &bd_suffixes[i]);
  244. if (ret < 0)
  245. pr_debug("%s: No BD suffix found for amp: %s\n",
  246. __func__, amp_node->full_name);
  247. v_val_separate[i] = of_property_read_bool(amp_node,
  248. "cirrus,v-val_separate");
  249. of_node_put(amp_node);
  250. }
  251. for (i = 0; i < num_amps; i++) {
  252. for (j = 0; j < num_amps; j++) {
  253. if (i == j)
  254. continue;
  255. if (strcmp(mfd_suffixes[i], mfd_suffixes[j]) == 0) {
  256. pr_err("%s: MFD suffixes must be unique\n",
  257. __func__);
  258. pr_err("%s: Found duplicate suffix: %s\n",
  259. __func__, mfd_suffixes[i]);
  260. ret = -EINVAL;
  261. goto suffix_err;
  262. }
  263. /* bd_suffixes can be empty but must be unique */
  264. if (bd_suffixes[i] && bd_suffixes[j] &&
  265. (strcmp(bd_suffixes[i], bd_suffixes[j]) == 0)) {
  266. pr_err("%s: BD suffixes must be unique\n",
  267. __func__);
  268. pr_err("%s: Found duplicate suffix: %s\n",
  269. __func__, bd_suffixes[i]);
  270. ret = -EINVAL;
  271. goto suffix_err;
  272. }
  273. }
  274. pr_info("%s: Found MFD suffix: %s\n", __func__,
  275. mfd_suffixes[i]);
  276. amp_group->amps[i].mfd_suffix =
  277. kstrdup(mfd_suffixes[i], GFP_KERNEL);
  278. if (bd_suffixes[i]) {
  279. pr_info("%s: Found BD suffix: %s\n", __func__,
  280. bd_suffixes[i]);
  281. amp_group->amps[i].bd.bd_suffix =
  282. kstrdup(bd_suffixes[i], GFP_KERNEL);
  283. }
  284. if (v_val_separate[i])
  285. amp_group->amps[i].v_val_separate = true;
  286. }
  287. ret = cirrus_bd_init();
  288. if (ret < 0) {
  289. pr_err("%s: Error in BD init (%d)\n", __func__, ret);
  290. goto suffix_err;
  291. }
  292. ret = cirrus_cal_init();
  293. if (ret < 0) {
  294. pr_err("%s: Error in CAL init (%d)\n", __func__, ret);
  295. cirrus_bd_exit();
  296. goto suffix_err;
  297. }
  298. ret = cirrus_pwr_init();
  299. if (ret < 0) {
  300. pr_err("%s: Error in PWR init (%d)\n", __func__, ret);
  301. cirrus_bd_exit();
  302. cirrus_cal_exit();
  303. goto suffix_err;
  304. }
  305. ret = 0;
  306. goto suffix_free;
  307. suffix_err:
  308. for (i = 0; i < num_amps; i++) {
  309. kfree(amp_group->amps[i].mfd_suffix);
  310. kfree(amp_group->amps[i].bd.bd_suffix);
  311. }
  312. suffix_free:
  313. kfree(mfd_suffixes);
  314. kfree(bd_suffixes);
  315. if (ret < 0)
  316. kfree(amp_group);
  317. class_err:
  318. if (ret < 0)
  319. class_destroy(cirrus_amp_class);
  320. return ret;
  321. }
  322. static int cirrus_amp_remove(struct platform_device *pdev)
  323. {
  324. int i;
  325. cirrus_cal_exit();
  326. cirrus_bd_exit();
  327. cirrus_pwr_exit();
  328. for (i = 0; i < amp_group->num_amps; i++) {
  329. kfree(amp_group->amps[i].pre_config);
  330. kfree(amp_group->amps[i].post_config);
  331. }
  332. kfree(amp_group);
  333. class_destroy(cirrus_amp_class);
  334. return 0;
  335. }
  336. static struct platform_driver cirrus_amp_driver = {
  337. .driver = {
  338. .name = "cirrus-amp",
  339. .of_match_table = cirrus_amp_of_match,
  340. },
  341. .probe = cirrus_amp_probe,
  342. .remove = cirrus_amp_remove,
  343. };
  344. module_platform_driver(cirrus_amp_driver);
  345. MODULE_AUTHOR("David Rhodes <[email protected]>");
  346. MODULE_DESCRIPTION("Cirrus Amp driver");
  347. MODULE_LICENSE("GPL");