cirrus-cal-cspl.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /*
  2. * Calibration support for Cirrus Logic Smart Amplifiers
  3. *
  4. * Copyright 2021 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/uaccess.h>
  13. #include <linux/delay.h>
  14. #include <linux/regmap.h>
  15. #include <linux/slab.h>
  16. #include <linux/syscalls.h>
  17. #include <linux/file.h>
  18. #include <linux/fcntl.h>
  19. #include <linux/fs.h>
  20. #include <linux/init.h>
  21. #include <linux/platform_device.h>
  22. #include <asm/io.h>
  23. #include <linux/firmware.h>
  24. #include <linux/vmalloc.h>
  25. #include <linux/workqueue.h>
  26. #include <linux/power_supply.h>
  27. #include <sound/cirrus/core.h>
  28. #include <sound/cirrus/calibration.h>
  29. #include <linux/firmware/cirrus/wmfw.h>
  30. #include <linux/firmware/cirrus/cs_dsp.h>
  31. #include "wm_adsp.h"
  32. #define CIRRUS_CAL_COMPLETE_DELAY_MS 1250
  33. #define CIRRUS_CAL_RETRIES 2
  34. #define CIRRUS_CAL_AMBIENT_DEFAULT 23
  35. #define CIRRUS_CAL_CONFIG_FILENAME_SUFFIX "-dsp1-spk-prot-calib.bin"
  36. #define CIRRUS_CAL_PLAYBACK_FILENAME_SUFFIX "-dsp1-spk-prot.bin"
  37. enum cirrus_cspl_mboxstate {
  38. CSPL_MBOX_STS_RUNNING = 0,
  39. CSPL_MBOX_STS_PAUSED = 1,
  40. CSPL_MBOX_STS_RDY_FOR_REINIT = 2,
  41. };
  42. enum cirrus_cspl_mboxcmd {
  43. CSPL_MBOX_CMD_NONE = 0,
  44. CSPL_MBOX_CMD_PAUSE = 1,
  45. CSPL_MBOX_CMD_RESUME = 2,
  46. CSPL_MBOX_CMD_REINIT = 3,
  47. CSPL_MBOX_CMD_STOP_PRE_REINIT = 4,
  48. CSPL_MBOX_CMD_UNKNOWN_CMD = -1,
  49. CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
  50. };
  51. static unsigned long long cirrus_cal_rdc_to_ohms(unsigned long rdc)
  52. {
  53. return ((rdc * CIRRUS_CAL_AMP_CONSTANT_NUM) /
  54. CIRRUS_CAL_AMP_CONSTANT_DENOM);
  55. }
  56. static unsigned int cirrus_cal_vpk_to_mv(unsigned int vpk)
  57. {
  58. return (vpk * CIRRUS_CAL_VFS_MV) >> 19;
  59. }
  60. static int32_t cirrus_cal_sign_extend(uint32_t in)
  61. {
  62. uint8_t shift = 8;
  63. return (int32_t)(in << shift) >> shift;
  64. }
  65. int cirrus_cal_logger_get_variable(struct cirrus_amp *amp, unsigned int id,
  66. unsigned int *result)
  67. {
  68. unsigned int state;
  69. int retries = 100;
  70. cirrus_amp_write_ctl(amp, "RTLOG_COUNT", WMFW_ADSP2_XM,
  71. CIRRUS_AMP_ALG_ID_CSPL, 0);
  72. cirrus_amp_write_ctl(amp, "RTLOG_VARIABLE", WMFW_ADSP2_XM,
  73. CIRRUS_AMP_ALG_ID_CSPL, id);
  74. cirrus_amp_write_ctl(amp, "RTLOG_COUNT", WMFW_ADSP2_XM,
  75. CIRRUS_AMP_ALG_ID_CSPL, 1);
  76. cirrus_amp_write_ctl(amp, "RTLOG_STATE", WMFW_ADSP2_XM,
  77. CIRRUS_AMP_ALG_ID_CSPL, 0);
  78. cirrus_amp_write_ctl(amp, "RTLOG_ENABLE", WMFW_ADSP2_XM,
  79. CIRRUS_AMP_ALG_ID_CSPL, 1);
  80. do {
  81. usleep_range(20, 50);
  82. cirrus_amp_read_ctl(amp, "RTLOG_STATE", WMFW_ADSP2_XM,
  83. CIRRUS_AMP_ALG_ID_CSPL, &state);
  84. } while (state == 0 && --retries > 0);
  85. if (retries == 0) {
  86. dev_err(amp_group->cal_dev, "variable read failed\n");
  87. return -1;
  88. }
  89. cirrus_amp_read_ctl(amp, "RTLOG_DATA", WMFW_ADSP2_XM,
  90. CIRRUS_AMP_ALG_ID_CSPL, result);
  91. cirrus_amp_write_ctl(amp, "RTLOG_ENABLE", WMFW_ADSP2_XM,
  92. CIRRUS_AMP_ALG_ID_CSPL, 0);
  93. return 0;
  94. }
  95. static int cirrus_cal_load_config(const char *file, struct cirrus_amp *amp)
  96. {
  97. struct wm_adsp *dsp = snd_soc_component_get_drvdata(amp->component);
  98. const struct firmware *firmware;
  99. int ret;
  100. ret = request_firmware(&firmware, file, amp->component->dev);
  101. if (ret != 0) {
  102. dev_err(amp_group->cal_dev, "Failed to request '%s'\n", file);
  103. return -EINVAL;
  104. }
  105. ret = cs_dsp_load_coeff(&dsp->cs_dsp, firmware, file);
  106. return ret;
  107. }
  108. static int cirrus_cal_get_power_temp(void)
  109. {
  110. union power_supply_propval value = {0};
  111. struct power_supply *psy;
  112. int ret;
  113. psy = power_supply_get_by_name("battery");
  114. if (!psy) {
  115. dev_warn(amp_group->cal_dev,
  116. "failed to get battery, assuming %d\n",
  117. CIRRUS_CAL_AMBIENT_DEFAULT);
  118. return CIRRUS_CAL_AMBIENT_DEFAULT;
  119. }
  120. ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &value);
  121. if (ret) {
  122. dev_warn(amp_group->cal_dev,
  123. "failed to get battery temp prop (%d), assuming %d\n",
  124. ret, CIRRUS_CAL_AMBIENT_DEFAULT);
  125. return CIRRUS_CAL_AMBIENT_DEFAULT;
  126. }
  127. return DIV_ROUND_CLOSEST(value.intval, 10);
  128. }
  129. static int cirrus_cal_cspl_start(void);
  130. static void cirrus_cal_cspl_complete(void)
  131. {
  132. struct cirrus_amp *amp;
  133. struct reg_sequence *post_config;
  134. struct regmap *regmap;
  135. const char *dsp_part_name;
  136. char *playback_config_filename;
  137. unsigned long long ohms;
  138. unsigned int cal_state, mbox_cmd, mbox_sts;
  139. int rdc, status, checksum, temp, vsc, isc, timeout = 100, i;
  140. int delay = msecs_to_jiffies(CIRRUS_CAL_COMPLETE_DELAY_MS);
  141. bool vsc_in_range, isc_in_range;
  142. bool cal_retry = false;
  143. mutex_lock(&amp_group->cal_lock);
  144. for (i = 0; i < amp_group->num_amps; i++) {
  145. amp = &amp_group->amps[i];
  146. if (amp->calibration_disable)
  147. continue;
  148. regmap = amp->regmap;
  149. dsp_part_name = amp->dsp_part_name;
  150. post_config = amp->post_config;
  151. mbox_cmd = amp->mbox_cmd;
  152. mbox_sts = amp->mbox_sts;
  153. playback_config_filename = kzalloc(PAGE_SIZE, GFP_KERNEL);
  154. snprintf(playback_config_filename, PAGE_SIZE, "%s%s",
  155. dsp_part_name, CIRRUS_CAL_PLAYBACK_FILENAME_SUFFIX);
  156. cirrus_amp_read_ctl(amp, "CAL_STATUS", WMFW_ADSP2_XM,
  157. CIRRUS_AMP_ALG_ID_CSPL, &status);
  158. cirrus_amp_read_ctl(amp, "CAL_R", WMFW_ADSP2_XM,
  159. CIRRUS_AMP_ALG_ID_CSPL, &rdc);
  160. cirrus_amp_read_ctl(amp, "CAL_AMBIENT", WMFW_ADSP2_XM,
  161. CIRRUS_AMP_ALG_ID_CSPL, &temp);
  162. cirrus_amp_read_ctl(amp, "CAL_CHECKSUM", WMFW_ADSP2_XM,
  163. CIRRUS_AMP_ALG_ID_CSPL, &checksum);
  164. ohms = cirrus_cal_rdc_to_ohms((unsigned long)rdc);
  165. cirrus_amp_read_ctl(amp, "CSPL_STATE", WMFW_ADSP2_XM,
  166. CIRRUS_AMP_ALG_ID_CSPL, &cal_state);
  167. if (cal_state == CSPL_STATE_ERROR) {
  168. dev_err(amp_group->cal_dev,
  169. "Error during ReDC cal, invalidating results\n");
  170. rdc = status = checksum = 0;
  171. }
  172. if (amp->perform_vimon_cal) {
  173. cirrus_amp_read_ctl(amp, "VSC", WMFW_ADSP2_XM,
  174. amp->vimon_alg_id, &vsc);
  175. cirrus_amp_read_ctl(amp, "ISC", WMFW_ADSP2_XM,
  176. amp->vimon_alg_id, &isc);
  177. cirrus_amp_read_ctl(amp, "VIMON_CAL_STATE",
  178. WMFW_ADSP2_XM, amp->vimon_alg_id,
  179. &cal_state);
  180. if (cal_state == CIRRUS_CAL_VIMON_STATUS_INVALID ||
  181. cal_state == 0) {
  182. dev_err(amp_group->cal_dev,
  183. "Error during VIMON cal, invalidating results\n");
  184. rdc = status = checksum = 0;
  185. }
  186. vsc_in_range = ((vsc <= amp->cal_vsc_ub) ||
  187. (vsc >= amp->cal_vsc_lb && vsc <= 0x00FFFFFF));
  188. isc_in_range = ((isc <= amp->cal_isc_ub) ||
  189. (isc >= amp->cal_isc_lb && isc <= 0x00FFFFFF));
  190. if (!vsc_in_range)
  191. dev_err(amp_group->cal_dev, "VIMON Cal %s (%s): VSC out of range (%x)\n",
  192. amp->dsp_part_name, amp->mfd_suffix, vsc);
  193. if (!isc_in_range)
  194. dev_err(amp_group->cal_dev, "VIMON Cal %s (%s): ISC out of range (%x)\n",
  195. amp->dsp_part_name, amp->mfd_suffix, isc);
  196. if (!vsc_in_range || !isc_in_range) {
  197. dev_err(amp_group->cal_dev, "VIMON cal out of range, invalidating results\n");
  198. rdc = status = checksum = 0;
  199. cirrus_amp_write_ctl(amp, "VIMON_CAL_STATE",
  200. WMFW_ADSP2_XM, amp->vimon_alg_id,
  201. CIRRUS_CAL_VIMON_STATUS_INVALID);
  202. if (amp_group->cal_retry < CIRRUS_CAL_RETRIES) {
  203. dev_info(amp_group->cal_dev, "Retry Calibration\n");
  204. cal_retry = true;
  205. }
  206. }
  207. } else {
  208. vsc = 0;
  209. isc = 0;
  210. cirrus_amp_write_ctl(amp, "VIMON_CAL_STATE",
  211. WMFW_ADSP2_XM, amp->vimon_alg_id,
  212. CIRRUS_CAL_VIMON_STATUS_INVALID);
  213. }
  214. dev_info(amp_group->cal_dev,
  215. "Calibration finished: %s (%s)\n",
  216. amp->dsp_part_name, amp->mfd_suffix);
  217. dev_info(amp_group->cal_dev, "Duration:\t%d ms\n",
  218. CIRRUS_CAL_COMPLETE_DELAY_MS);
  219. dev_info(amp_group->cal_dev, "Status:\t%d\n", status);
  220. if (status == CSPL_STATUS_OUT_OF_RANGE)
  221. dev_err(amp_group->cal_dev,
  222. "Calibration out of range\n");
  223. if (status == CSPL_STATUS_INCOMPLETE)
  224. dev_err(amp_group->cal_dev, "Calibration incomplete\n");
  225. dev_info(amp_group->cal_dev, "R :\t\t%d (%llu.%04llu Ohms)\n",
  226. rdc, ohms >> CIRRUS_CAL_RDC_RADIX,
  227. (ohms & (((1 << CIRRUS_CAL_RDC_RADIX) - 1))) *
  228. 10000 / (1 << CIRRUS_CAL_RDC_RADIX));
  229. dev_info(amp_group->cal_dev, "Checksum:\t%d\n", checksum);
  230. dev_info(amp_group->cal_dev, "Ambient:\t%d\n", temp);
  231. usleep_range(5000, 5500);
  232. /* Send STOP_PRE_REINIT command and poll for response */
  233. regmap_write(regmap, mbox_cmd, CSPL_MBOX_CMD_STOP_PRE_REINIT);
  234. timeout = 100;
  235. do {
  236. dev_info(amp_group->cal_dev,
  237. "waiting for REINIT ready...\n");
  238. usleep_range(1000, 1500);
  239. regmap_read(regmap, mbox_sts, &cal_state);
  240. } while ((cal_state != CSPL_MBOX_STS_RDY_FOR_REINIT) &&
  241. --timeout > 0);
  242. msleep(100);
  243. cirrus_cal_load_config(playback_config_filename, amp);
  244. cirrus_amp_write_ctl(amp, "CAL_STATUS", WMFW_ADSP2_XM,
  245. CIRRUS_AMP_ALG_ID_CSPL, status);
  246. cirrus_amp_write_ctl(amp, "CAL_R", WMFW_ADSP2_XM,
  247. CIRRUS_AMP_ALG_ID_CSPL, rdc);
  248. cirrus_amp_write_ctl(amp, "CAL_AMBIENT", WMFW_ADSP2_XM,
  249. CIRRUS_AMP_ALG_ID_CSPL, temp);
  250. cirrus_amp_write_ctl(amp, "CAL_CHECKSUM", WMFW_ADSP2_XM,
  251. CIRRUS_AMP_ALG_ID_CSPL, checksum);
  252. /* Send REINIT command and poll for response */
  253. regmap_write(regmap, mbox_cmd, CSPL_MBOX_CMD_REINIT);
  254. timeout = 100;
  255. do {
  256. dev_info(amp_group->cal_dev,
  257. "waiting for REINIT done...\n");
  258. usleep_range(1000, 1500);
  259. regmap_read(regmap, mbox_sts, &cal_state);
  260. } while ((cal_state != CSPL_MBOX_STS_RUNNING) &&
  261. --timeout > 0);
  262. msleep(100);
  263. cirrus_amp_read_ctl(amp, "CSPL_STATE", WMFW_ADSP2_XM,
  264. CIRRUS_AMP_ALG_ID_CSPL, &cal_state);
  265. if (cal_state == CSPL_STATE_ERROR)
  266. dev_err(amp_group->cal_dev,
  267. "Playback config load error\n");
  268. regmap_multi_reg_write(regmap, post_config,
  269. amp->num_post_configs);
  270. amp->cal.efs_cache_rdc = rdc;
  271. amp->cal.efs_cache_vsc = vsc;
  272. amp->cal.efs_cache_isc = isc;
  273. amp_group->efs_cache_temp = temp;
  274. amp->cal.efs_cache_valid = 1;
  275. kfree(playback_config_filename);
  276. }
  277. if (cal_retry == true) {
  278. cirrus_cal_cspl_start();
  279. queue_delayed_work(system_unbound_wq,
  280. &amp_group->cal_complete_work,
  281. delay);
  282. amp_group->cal_retry++;
  283. } else {
  284. amp_group->cal_running = 0;
  285. }
  286. dev_dbg(amp_group->cal_dev, "Calibration complete\n");
  287. mutex_unlock(&amp_group->cal_lock);
  288. }
  289. static void cirrus_cal_v_val_complete(struct cirrus_amp *amps, int num_amps,
  290. bool separate)
  291. {
  292. struct regmap *regmap;
  293. struct reg_sequence *post_config;
  294. const char *dsp_part_name;
  295. char *playback_config_filename;
  296. unsigned int mbox_cmd, mbox_sts, cal_state;
  297. int timeout = 100, amp;
  298. for (amp = 0; amp < num_amps; amp++) {
  299. if (amps[amp].v_val_separate && !separate)
  300. continue;
  301. regmap = amps[amp].regmap;
  302. dsp_part_name = amps[amp].dsp_part_name;
  303. post_config = amps[amp].post_config;
  304. mbox_cmd = amps[amp].mbox_cmd;
  305. mbox_sts = amps[amp].mbox_sts;
  306. playback_config_filename = kzalloc(PAGE_SIZE, GFP_KERNEL);
  307. snprintf(playback_config_filename, PAGE_SIZE, "%s%s",
  308. dsp_part_name, CIRRUS_CAL_PLAYBACK_FILENAME_SUFFIX);
  309. /* Send STOP_PRE_REINIT command and poll for response */
  310. regmap_write(regmap, mbox_cmd, CSPL_MBOX_CMD_STOP_PRE_REINIT);
  311. timeout = 100;
  312. do {
  313. dev_info(amp_group->cal_dev,
  314. "waiting for REINIT ready...\n");
  315. usleep_range(1000, 1500);
  316. regmap_read(regmap, mbox_sts, &cal_state);
  317. } while ((cal_state != CSPL_MBOX_STS_RDY_FOR_REINIT) &&
  318. --timeout > 0);
  319. msleep(100);
  320. cirrus_cal_load_config(playback_config_filename,
  321. &amp_group->amps[amp]);
  322. /* Send REINIT command and poll for response */
  323. regmap_write(regmap, mbox_cmd, CSPL_MBOX_CMD_REINIT);
  324. timeout = 100;
  325. do {
  326. dev_info(amp_group->cal_dev,
  327. "waiting for REINIT done...\n");
  328. usleep_range(1000, 1500);
  329. regmap_read(regmap, mbox_sts, &cal_state);
  330. } while ((cal_state != CSPL_MBOX_STS_RUNNING) &&
  331. --timeout > 0);
  332. msleep(100);
  333. cirrus_amp_read_ctl(&amp_group->amps[amp], "CSPL_STATE",
  334. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL,
  335. &cal_state);
  336. if (cal_state == CSPL_STATE_ERROR)
  337. dev_err(amp_group->cal_dev,
  338. "Playback config load error\n");
  339. regmap_multi_reg_write(regmap, post_config,
  340. amps[amp].num_post_configs);
  341. kfree(playback_config_filename);
  342. }
  343. dev_info(amp_group->cal_dev, "V validation complete\n");
  344. }
  345. static void cirrus_cal_cspl_vimon_cal_start(struct cirrus_amp *amp)
  346. {
  347. cirrus_amp_write_ctl(amp, "VIMON_CLASS_H_CAL_DELAY", WMFW_ADSP2_XM,
  348. amp->vimon_alg_id, CIRRUS_CAL_CLASSH_DELAY_50MS);
  349. cirrus_amp_write_ctl(amp, "VIMON_CLASS_D_CAL_DELAY", WMFW_ADSP2_XM,
  350. amp->vimon_alg_id, CIRRUS_CAL_CLASSD_DELAY_50MS);
  351. cirrus_amp_write_ctl(amp, "VIMON_CAL_STATE", WMFW_ADSP2_XM,
  352. amp->vimon_alg_id, 0);
  353. cirrus_amp_write_ctl(amp, "HALO_HEARTBEAT", WMFW_ADSP2_XM,
  354. amp->halo_alg_id, 0);
  355. }
  356. static int cirrus_cal_cspl_vimon_cal_complete(struct cirrus_amp *amp)
  357. {
  358. unsigned int vimon_cal, vsc, isc;
  359. bool vsc_in_range, isc_in_range;
  360. cirrus_amp_read_ctl(amp, "VIMON_CAL_STATE", WMFW_ADSP2_XM,
  361. amp->vimon_alg_id, &vimon_cal);
  362. cirrus_amp_read_ctl(amp, "VSC", WMFW_ADSP2_XM, amp->vimon_alg_id, &vsc);
  363. cirrus_amp_read_ctl(amp, "ISC", WMFW_ADSP2_XM, amp->vimon_alg_id, &isc);
  364. dev_info(amp_group->cal_dev,
  365. "VIMON Cal results %s (%s), status=%d vsc=%x isc=%x\n",
  366. amp->dsp_part_name, amp->mfd_suffix, vimon_cal, vsc, isc);
  367. vsc_in_range = ((vsc <= amp->cal_vsc_ub) ||
  368. (vsc >= amp->cal_vsc_lb && vsc <= 0x00FFFFFF));
  369. isc_in_range = ((isc <= amp->cal_isc_ub) ||
  370. (isc >= amp->cal_isc_lb && isc <= 0x00FFFFFF));
  371. if (!vsc_in_range || !isc_in_range)
  372. vimon_cal = CIRRUS_CAL_VIMON_STATUS_INVALID;
  373. return vimon_cal;
  374. }
  375. static int cirrus_cal_wait_for_active(struct cirrus_amp *amp)
  376. {
  377. struct regmap *regmap = amp->regmap;
  378. unsigned int global_en;
  379. unsigned int halo_state;
  380. int timeout = 50;
  381. regmap_read(regmap, amp->global_en, &global_en);
  382. while ((global_en & amp->global_en_mask) == 0) {
  383. usleep_range(1000, 1500);
  384. regmap_read(regmap, amp->global_en, &global_en);
  385. }
  386. do {
  387. dev_info(amp_group->cal_dev, "waiting for HALO start...\n");
  388. usleep_range(16000, 16100);
  389. cirrus_amp_read_ctl(amp, "HALO_STATE", WMFW_ADSP2_XM,
  390. amp->halo_alg_id, &halo_state);
  391. timeout--;
  392. } while ((halo_state == 0) && timeout > 0);
  393. if (timeout == 0) {
  394. dev_err(amp_group->cal_dev, "Failed to setup calibration\n");
  395. return -EINVAL;
  396. }
  397. return 0;
  398. }
  399. static void cirrus_cal_cspl_redc_start(struct cirrus_amp *amp)
  400. {
  401. struct regmap *regmap = amp->regmap;
  402. const char *dsp_part_name = amp->dsp_part_name;
  403. char *cal_config_filename;
  404. unsigned int halo_state;
  405. int timeout = 50;
  406. int ambient;
  407. cal_config_filename = kzalloc(PAGE_SIZE, GFP_KERNEL);
  408. snprintf(cal_config_filename, PAGE_SIZE, "%s%s", dsp_part_name,
  409. CIRRUS_CAL_CONFIG_FILENAME_SUFFIX);
  410. dev_info(amp_group->cal_dev, "ReDC Calibration load start\n");
  411. /* Send STOP_PRE_REINIT command and poll for response */
  412. regmap_write(regmap, amp->mbox_cmd, CSPL_MBOX_CMD_STOP_PRE_REINIT);
  413. timeout = 100;
  414. do {
  415. dev_info(amp_group->cal_dev, "waiting for REINIT ready...\n");
  416. usleep_range(1000, 1500);
  417. regmap_read(regmap, amp->mbox_sts, &halo_state);
  418. } while ((halo_state != CSPL_MBOX_STS_RDY_FOR_REINIT) &&
  419. --timeout > 0);
  420. if (timeout == 0)
  421. dev_err(amp->component->dev, "REINIT ready not found\n");
  422. msleep(100);
  423. dev_dbg(amp_group->cal_dev, "load %s\n", dsp_part_name);
  424. cirrus_cal_load_config(cal_config_filename, amp);
  425. ambient = cirrus_cal_get_power_temp();
  426. cirrus_amp_write_ctl(amp, "CAL_AMBIENT", WMFW_ADSP2_XM,
  427. CIRRUS_AMP_ALG_ID_CSPL, ambient);
  428. /* Send REINIT command and poll for response */
  429. regmap_write(regmap, amp->mbox_cmd, CSPL_MBOX_CMD_REINIT);
  430. timeout = 100;
  431. do {
  432. dev_info(amp_group->cal_dev, "waiting for REINIT done...\n");
  433. usleep_range(1000, 1500);
  434. regmap_read(regmap, amp->mbox_sts, &halo_state);
  435. } while ((halo_state != CSPL_MBOX_STS_RUNNING) &&
  436. --timeout > 0);
  437. if (timeout == 0)
  438. dev_err(amp->component->dev, "REINIT done not found\n");
  439. kfree(cal_config_filename);
  440. }
  441. int cirrus_cal_cspl_cal_apply(struct cirrus_amp *amp)
  442. {
  443. unsigned int temp, rdc, status, checksum, vsc, isc;
  444. unsigned int vimon_cal_status = CIRRUS_CAL_VIMON_STATUS_SUCCESS;
  445. int ret = 0;
  446. if (!amp)
  447. return 0;
  448. if (amp->cal.efs_cache_valid == 1) {
  449. rdc = amp->cal.efs_cache_rdc;
  450. vsc = amp->cal.efs_cache_vsc;
  451. isc = amp->cal.efs_cache_isc;
  452. vimon_cal_status = CIRRUS_CAL_VIMON_STATUS_SUCCESS;
  453. temp = amp_group->efs_cache_temp;
  454. } else if (amp->cal.efs_cache_rdc && amp_group->efs_cache_temp &&
  455. (!amp->cal.efs_cache_vsc && !amp->cal.efs_cache_isc)) {
  456. dev_info(amp_group->cal_dev,
  457. "No VIMON, writing RDC only\n");
  458. rdc = amp->cal.efs_cache_rdc;
  459. temp = amp_group->efs_cache_temp;
  460. vimon_cal_status = CIRRUS_CAL_VIMON_STATUS_INVALID;
  461. } else {
  462. dev_info(amp_group->cal_dev,
  463. "No saved EFS, writing defaults\n");
  464. rdc = amp->default_redc;
  465. temp = CIRRUS_CAL_AMBIENT_DEFAULT;
  466. vimon_cal_status = CIRRUS_CAL_VIMON_STATUS_INVALID;
  467. amp->cal.efs_cache_rdc = rdc;
  468. amp_group->efs_cache_temp = temp;
  469. }
  470. status = 1;
  471. checksum = status + rdc;
  472. dev_info(amp_group->cal_dev, "Writing calibration to %s (%s)\n",
  473. amp->dsp_part_name, amp->mfd_suffix);
  474. dev_info(amp_group->cal_dev,
  475. "RDC = %d, Temp = %d, Status = %d Checksum = %d\n",
  476. rdc, temp, status, checksum);
  477. cirrus_amp_write_ctl(amp, "CAL_STATUS", WMFW_ADSP2_XM,
  478. CIRRUS_AMP_ALG_ID_CSPL, status);
  479. cirrus_amp_write_ctl(amp, "CAL_R", WMFW_ADSP2_XM,
  480. CIRRUS_AMP_ALG_ID_CSPL, rdc);
  481. cirrus_amp_write_ctl(amp, "CAL_AMBIENT", WMFW_ADSP2_XM,
  482. CIRRUS_AMP_ALG_ID_CSPL, temp);
  483. cirrus_amp_write_ctl(amp, "CAL_CHECKSUM", WMFW_ADSP2_XM,
  484. CIRRUS_AMP_ALG_ID_CSPL, checksum);
  485. if (!amp->perform_vimon_cal) {
  486. cirrus_amp_write_ctl(amp, "VIMON_CAL_STATE", WMFW_ADSP2_XM,
  487. amp->vimon_alg_id,
  488. CIRRUS_CAL_VIMON_STATUS_INVALID);
  489. goto skip_vimon_cal;
  490. }
  491. cirrus_amp_write_ctl(amp, "VIMON_CAL_STATE", WMFW_ADSP2_XM,
  492. amp->vimon_alg_id, vimon_cal_status);
  493. if (amp->perform_vimon_cal &&
  494. vimon_cal_status != CIRRUS_CAL_VIMON_STATUS_INVALID) {
  495. dev_info(amp_group->cal_dev,
  496. "VIMON Cal status=%d vsc=0x%x isc=0x%x\n",
  497. vimon_cal_status, vsc, isc);
  498. cirrus_amp_write_ctl(amp, "VSC", WMFW_ADSP2_XM,
  499. amp->vimon_alg_id, vsc);
  500. cirrus_amp_write_ctl(amp, "ISC", WMFW_ADSP2_XM,
  501. amp->vimon_alg_id, isc);
  502. } else {
  503. dev_info(amp_group->cal_dev, "VIMON Cal status invalid\n");
  504. }
  505. skip_vimon_cal:
  506. return ret;
  507. }
  508. int cirrus_cal_cspl_read_temp(struct cirrus_amp *amp)
  509. {
  510. int reg = 0, ret;
  511. unsigned int halo_state;
  512. unsigned int global_en;
  513. if (!amp)
  514. goto err;
  515. regmap_read(amp->regmap, amp->global_en, &global_en);
  516. if ((global_en & amp->global_en_mask) == 0)
  517. goto err;
  518. regmap_read(amp->regmap, amp->mbox_sts, &halo_state);
  519. if (halo_state != CSPL_MBOX_STS_RUNNING)
  520. goto err;
  521. if (amp_group->cal_running)
  522. goto err;
  523. ret = cirrus_cal_logger_get_variable(amp,
  524. CIRRUS_CAL_RTLOG_ID_TEMP,
  525. &reg);
  526. if (ret == 0) {
  527. if (reg == 0)
  528. cirrus_cal_logger_get_variable(amp,
  529. CIRRUS_CAL_RTLOG_ID_TEMP,
  530. &reg);
  531. reg = cirrus_cal_sign_extend(reg);
  532. dev_info(amp_group->cal_dev,
  533. "Read temp: %d.%04d degrees C\n",
  534. reg >> CIRRUS_CAL_RTLOG_RADIX_TEMP,
  535. (reg & (((1 << CIRRUS_CAL_RTLOG_RADIX_TEMP) - 1))) *
  536. 10000 / (1 << CIRRUS_CAL_RTLOG_RADIX_TEMP));
  537. return (reg >> CIRRUS_CAL_RTLOG_RADIX_TEMP);
  538. }
  539. err:
  540. return -1;
  541. }
  542. int cirrus_cal_cspl_set_surface_temp(struct cirrus_amp *amp, int temperature)
  543. {
  544. unsigned int global_en;
  545. if (!amp)
  546. return -EINVAL;
  547. regmap_read(amp->regmap, amp->global_en, &global_en);
  548. if ((global_en & amp->global_en_mask) == 0)
  549. return -EINVAL;
  550. dev_info(amp->component->dev, "Set surface temp: %d degrees\n", temperature);
  551. cirrus_amp_write_ctl(amp, "CSPL_SURFACE_TEMP", WMFW_ADSP2_XM,
  552. CIRRUS_AMP_ALG_ID_CSPL, temperature);
  553. return 0;
  554. }
  555. static int cirrus_cal_cspl_start(void)
  556. {
  557. int redc_cal_start_retries, vimon_cal_retries = 0;
  558. bool vimon_calibration_failed = false;
  559. unsigned int cal_state;
  560. int amp;
  561. struct reg_sequence *config;
  562. struct regmap *regmap;
  563. int ret = 0;
  564. for (amp = 0; amp < amp_group->num_amps; amp++) {
  565. if (amp_group->amps[amp].calibration_disable)
  566. continue;
  567. cirrus_amp_write_ctl(&amp_group->amps[amp], "CAL_STATUS",
  568. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, 0);
  569. cirrus_amp_write_ctl(&amp_group->amps[amp], "CAL_R",
  570. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, 0);
  571. cirrus_amp_write_ctl(&amp_group->amps[amp], "CAL_AMBIENT",
  572. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, 0);
  573. cirrus_amp_write_ctl(&amp_group->amps[amp], "CAL_CHECKSUM",
  574. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, 0);
  575. if (amp_group->amps[amp].perform_vimon_cal) {
  576. cirrus_amp_write_ctl(&amp_group->amps[amp], "VSC",
  577. WMFW_ADSP2_XM,
  578. amp_group->amps[amp].vimon_alg_id, 0);
  579. cirrus_amp_write_ctl(&amp_group->amps[amp], "ISC",
  580. WMFW_ADSP2_XM,
  581. amp_group->amps[amp].vimon_alg_id, 0);
  582. }
  583. ret = cirrus_cal_wait_for_active(&amp_group->amps[amp]);
  584. if (ret < 0) {
  585. dev_err(amp_group->cal_dev,
  586. "Could not start amp%s (%d)\n",
  587. amp_group->amps[amp].mfd_suffix, ret);
  588. return -ETIMEDOUT;
  589. }
  590. }
  591. do {
  592. vimon_calibration_failed = false;
  593. for (amp = 0; amp < amp_group->num_amps; amp++) {
  594. if (amp_group->amps[amp].calibration_disable)
  595. continue;
  596. regmap = amp_group->amps[amp].regmap;
  597. config = amp_group->amps[amp].pre_config;
  598. regmap_multi_reg_write(regmap, config,
  599. amp_group->amps[amp].num_pre_configs);
  600. if (amp_group->amps[amp].perform_vimon_cal)
  601. cirrus_cal_cspl_vimon_cal_start(&amp_group->amps[amp]);
  602. }
  603. msleep(112);
  604. for (amp = 0; amp < amp_group->num_amps; amp++) {
  605. if (amp_group->amps[amp].calibration_disable)
  606. continue;
  607. if (amp_group->amps[amp].perform_vimon_cal) {
  608. ret = cirrus_cal_cspl_vimon_cal_complete(
  609. &amp_group->amps[amp]);
  610. if (ret != CIRRUS_CAL_VIMON_STATUS_SUCCESS) {
  611. vimon_calibration_failed = true;
  612. dev_info(amp_group->cal_dev,
  613. "VIMON Calibration Error %s (%s)\n",
  614. amp_group->amps[amp].dsp_part_name,
  615. amp_group->amps[amp].mfd_suffix);
  616. }
  617. }
  618. }
  619. vimon_cal_retries--;
  620. } while (vimon_cal_retries >= 0 && vimon_calibration_failed);
  621. for (amp = 0; amp < amp_group->num_amps; amp++) {
  622. if (amp_group->amps[amp].calibration_disable)
  623. continue;
  624. regmap = amp_group->amps[amp].regmap;
  625. cirrus_cal_cspl_redc_start(&amp_group->amps[amp]);
  626. cirrus_amp_read_ctl(&amp_group->amps[amp], "CSPL_STATE",
  627. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, &cal_state);
  628. redc_cal_start_retries = 5;
  629. while (cal_state == CSPL_STATE_ERROR &&
  630. redc_cal_start_retries > 0) {
  631. if (cal_state == CSPL_STATE_ERROR)
  632. dev_err(amp_group->cal_dev,
  633. "Calibration load error\n");
  634. cirrus_cal_cspl_redc_start(&amp_group->amps[amp]);
  635. cirrus_amp_read_ctl(&amp_group->amps[amp], "CSPL_STATE",
  636. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, &cal_state);
  637. redc_cal_start_retries--;
  638. }
  639. if (redc_cal_start_retries == 0) {
  640. config = amp_group->amps[amp].post_config;
  641. dev_err(amp_group->cal_dev,
  642. "Calibration setup fail amp%s (%d)\n",
  643. amp_group->amps[amp].mfd_suffix, ret);
  644. regmap_multi_reg_write(regmap, config,
  645. amp_group->amps[amp].num_post_configs);
  646. return -ETIMEDOUT;
  647. }
  648. }
  649. return 0;
  650. }
  651. int cirrus_cal_cspl_v_val_start(struct cirrus_amp *amps, int num_amps, bool separate)
  652. {
  653. struct reg_sequence *config;
  654. struct regmap *regmap;
  655. unsigned int vmax[CIRRUS_MAX_AMPS] = {0, 0, 0, 0, 0, 0, 0, 0};
  656. unsigned int vmin[CIRRUS_MAX_AMPS] = {0, 0, 0, 0, 0, 0, 0, 0};
  657. unsigned int cal_state;
  658. int ret = 0, i, j, reg, retries, count;
  659. for (i = 0; i < amp_group->num_amps; i++) {
  660. if (amps[i].v_val_separate && !separate)
  661. continue;
  662. regmap = amps[i].regmap;
  663. config = amps[i].pre_config;
  664. vmax[i] = 0;
  665. vmin[i] = INT_MAX;
  666. ret = cirrus_cal_wait_for_active(&amps[i]);
  667. if (ret < 0) {
  668. dev_err(amp_group->cal_dev,
  669. "Could not start amp%s\n",
  670. amps[i].mfd_suffix);
  671. goto err;
  672. }
  673. regmap_multi_reg_write(regmap, config,
  674. amps[i].num_pre_configs);
  675. cirrus_cal_cspl_redc_start(&amps[i]);
  676. cirrus_amp_read_ctl(&amps[i], "CSPL_STATE",
  677. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, &cal_state);
  678. retries = 5;
  679. while (cal_state == CSPL_STATE_ERROR && retries > 0) {
  680. if (cal_state == CSPL_STATE_ERROR)
  681. dev_err(amp_group->cal_dev,
  682. "Calibration load error\n");
  683. cirrus_cal_cspl_redc_start(&amps[i]);
  684. cirrus_amp_read_ctl(&amps[i], "CSPL_STATE",
  685. WMFW_ADSP2_XM, CIRRUS_AMP_ALG_ID_CSPL, &cal_state);
  686. retries--;
  687. }
  688. if (retries == 0) {
  689. config = amps[i].post_config;
  690. dev_err(amp_group->cal_dev,
  691. "Calibration setup fail @ %d\n", i);
  692. regmap_multi_reg_write(regmap, config,
  693. amps[i].num_post_configs);
  694. goto err;
  695. }
  696. }
  697. dev_info(amp_group->cal_dev, "V validation prepare complete\n");
  698. for (i = 0; i < 1000; i++) {
  699. count = 0;
  700. for (j = 0; j < num_amps; j++) {
  701. if (amps[j].v_val_separate && !separate)
  702. continue;
  703. cirrus_cal_logger_get_variable(&amps[j],
  704. amps[j].cal_vpk_id,
  705. &reg);
  706. if (reg > vmax[j])
  707. vmax[j] = reg;
  708. if (reg < vmin[j])
  709. vmin[j] = reg;
  710. cirrus_amp_read_ctl(&amp_group->amps[j], "CAL_STATUS",
  711. WMFW_ADSP2_XM,
  712. CIRRUS_AMP_ALG_ID_CSPL, &reg);
  713. if (reg != 0 && reg != CSPL_STATUS_INCOMPLETE)
  714. count++;
  715. }
  716. if (count == num_amps) {
  717. dev_info(amp_group->cal_dev,
  718. "V Validation complete (%d)\n", i);
  719. break;
  720. }
  721. }
  722. for (i = 0; i < num_amps; i++) {
  723. if (amps[i].v_val_separate && !separate)
  724. continue;
  725. dev_info(amp_group->cal_dev,
  726. "V Validation results for amp%s\n",
  727. amps[i].mfd_suffix);
  728. dev_dbg(amp_group->cal_dev, "V Max: 0x%x\n", vmax[i]);
  729. vmax[i] = cirrus_cal_vpk_to_mv(vmax[i]);
  730. dev_info(amp_group->cal_dev, "V Max: %d mV\n", vmax[i]);
  731. dev_dbg(amp_group->cal_dev, "V Min: 0x%x\n", vmin[i]);
  732. vmin[i] = cirrus_cal_vpk_to_mv(vmin[i]);
  733. dev_info(amp_group->cal_dev, "V Min: %d mV\n", vmin[i]);
  734. if (vmax[i] < CIRRUS_CAL_V_VAL_UB_MV &&
  735. vmax[i] > CIRRUS_CAL_V_VAL_LB_MV) {
  736. amps[i].cal.v_validation = 1;
  737. dev_info(amp_group->cal_dev,
  738. "V validation success\n");
  739. } else {
  740. amps[i].cal.v_validation = 0xCC;
  741. dev_err(amp_group->cal_dev,
  742. "V validation failed\n");
  743. }
  744. }
  745. cirrus_cal_v_val_complete(amps, num_amps, separate);
  746. return 0;
  747. err:
  748. return -1;
  749. }
  750. struct cirrus_cal_ops cirrus_cspl_cal_ops = {
  751. .controls = {
  752. { "CAL_R", CIRRUS_AMP_ALG_ID_CSPL},
  753. { "CAL_CHECKSUM", CIRRUS_AMP_ALG_ID_CSPL},
  754. { "CAL_SET_STATUS", CIRRUS_AMP_ALG_ID_CSPL},
  755. },
  756. .cal_start = cirrus_cal_cspl_start,
  757. .cal_complete = cirrus_cal_cspl_complete,
  758. .v_val = cirrus_cal_cspl_v_val_start,
  759. .cal_apply = cirrus_cal_cspl_cal_apply,
  760. .read_temp = cirrus_cal_cspl_read_temp,
  761. .set_temp = cirrus_cal_cspl_set_surface_temp,
  762. };