cirrus-cal.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /*
  2. * Calibration 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/module.h>
  13. #include <linux/miscdevice.h>
  14. #include <linux/device.h>
  15. #include <linux/uaccess.h>
  16. #include <linux/delay.h>
  17. #include <linux/regmap.h>
  18. #include <linux/slab.h>
  19. #include <linux/syscalls.h>
  20. #include <linux/file.h>
  21. #include <linux/fcntl.h>
  22. #include <linux/fs.h>
  23. #include <linux/init.h>
  24. #include <linux/platform_device.h>
  25. #include <asm/io.h>
  26. #include <linux/firmware.h>
  27. #include <linux/vmalloc.h>
  28. #include <linux/workqueue.h>
  29. #include <linux/power_supply.h>
  30. #include <linux/fs.h>
  31. #include <sound/cirrus/core.h>
  32. #include <sound/cirrus/calibration.h>
  33. #include "wm_adsp.h"
  34. #define CIRRUS_CAL_VERSION "5.01.18"
  35. #define CIRRUS_CAL_DIR_NAME "cirrus_cal"
  36. #define CIRRUS_CAL_RDC_SAVE_LOCATION "/efs/cirrus/rdc_cal"
  37. #define CIRRUS_CAL_TEMP_SAVE_LOCATION "/efs/cirrus/temp_cal"
  38. #define CIRRUS_CAL_VSC_SAVE_LOCATION "/efs/cirrus/vsc_cal"
  39. #define CIRRUS_CAL_ISC_SAVE_LOCATION "/efs/cirrus/isc_cal"
  40. #define CIRRUS_CAL_AMBIENT_DEFAULT 23
  41. #define CIRRUS_CAL_COMPLETE_DELAY_MS 1250
  42. int cirrus_cal_apply(const char *mfd_suffix)
  43. {
  44. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(mfd_suffix);
  45. if (amp == NULL)
  46. return -EINVAL;
  47. return amp->cal_ops->cal_apply(amp);
  48. }
  49. EXPORT_SYMBOL_GPL(cirrus_cal_apply);
  50. int cirrus_cal_read_temp(const char *mfd_suffix)
  51. {
  52. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(mfd_suffix);
  53. if (amp == NULL)
  54. return -EINVAL;
  55. return amp->cal_ops->read_temp(amp);
  56. }
  57. EXPORT_SYMBOL_GPL(cirrus_cal_read_temp);
  58. int cirrus_cal_set_surface_temp(const char *suffix, int temperature)
  59. {
  60. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  61. if (amp == NULL)
  62. return -EINVAL;
  63. return amp->cal_ops->set_temp(amp, temperature);
  64. }
  65. EXPORT_SYMBOL_GPL(cirrus_cal_set_surface_temp);
  66. void cirrus_cal_complete_work(struct work_struct *work)
  67. {
  68. amp_group->amps[0].cal_ops->cal_complete();
  69. }
  70. /***** SYSFS Interfaces *****/
  71. static ssize_t cirrus_cal_version_show(struct device *dev,
  72. struct device_attribute *attr,
  73. char *buf)
  74. {
  75. return sprintf(buf, CIRRUS_CAL_VERSION "\n");
  76. }
  77. static ssize_t cirrus_cal_version_store(struct device *dev,
  78. struct device_attribute *attr,
  79. const char *buf, size_t size)
  80. {
  81. return 0;
  82. }
  83. static ssize_t cirrus_cal_status_show(struct device *dev,
  84. struct device_attribute *attr,
  85. char *buf)
  86. {
  87. return sprintf(buf, "%s\n", amp_group->cal_running ?
  88. "Enabled" : "Disabled");
  89. }
  90. static ssize_t cirrus_cal_status_store(struct device *dev,
  91. struct device_attribute *attr,
  92. const char *buf, size_t size)
  93. {
  94. int ret = 0, prepare;
  95. if (amp_group->cal_running) {
  96. dev_err(amp_group->cal_dev,
  97. "cirrus_cal measurement in progress\n");
  98. return size;
  99. }
  100. mutex_lock(&amp_group->cal_lock);
  101. ret = kstrtos32(buf, 10, &prepare);
  102. if (ret != 0 || prepare != 1)
  103. goto err;
  104. amp_group->cal_running = true;
  105. amp_group->cal_retry = 0;
  106. amp_group->amps[0].cal_ops->cal_start();
  107. dev_dbg(amp_group->cal_dev, "Calibration prepare complete\n");
  108. queue_delayed_work(system_unbound_wq, &amp_group->cal_complete_work,
  109. msecs_to_jiffies(CIRRUS_CAL_COMPLETE_DELAY_MS));
  110. err:
  111. mutex_unlock(&amp_group->cal_lock);
  112. if (ret < 0)
  113. amp_group->cal_running = false;
  114. return size;
  115. }
  116. static ssize_t cirrus_cal_v_status_show(struct device *dev,
  117. struct device_attribute *attr,
  118. char *buf)
  119. {
  120. return sprintf(buf, "%s\n", amp_group->cal_running ?
  121. "Enabled" : "Disabled");
  122. }
  123. static ssize_t cirrus_cal_v_status_store(struct device *dev,
  124. struct device_attribute *attr,
  125. const char *buf, size_t size)
  126. {
  127. int ret = 0, prepare, num_amps;
  128. const char *suffix;
  129. struct cirrus_amp *amps;
  130. bool separate = false;
  131. if (amp_group->cal_running) {
  132. dev_err(amp_group->cal_dev,
  133. "cirrus_cal measurement in progress\n");
  134. return size;
  135. }
  136. mutex_lock(&amp_group->cal_lock);
  137. ret = kstrtos32(buf, 10, &prepare);
  138. if (ret != 0 || prepare != 1)
  139. goto err;
  140. amp_group->cal_running = true;
  141. if (strlen(attr->attr.name) > strlen("v_status")) {
  142. suffix = &(attr->attr.name[strlen("v_status")]);
  143. amps = cirrus_get_amp_from_suffix(suffix);
  144. if (amps) {
  145. dev_info(dev, "V-validation for amp: %s (%s)\n",
  146. amps->dsp_part_name, suffix);
  147. num_amps = 1;
  148. separate = true;
  149. } else {
  150. mutex_unlock(&amp_group->cal_lock);
  151. return size;
  152. }
  153. } else {
  154. num_amps = amp_group->num_amps;
  155. amps = amp_group->amps;
  156. separate = false;
  157. }
  158. amps[0].cal_ops->v_val(amps, num_amps, separate);
  159. err:
  160. amp_group->cal_running = false;
  161. mutex_unlock(&amp_group->cal_lock);
  162. return size;
  163. }
  164. #ifdef CONFIG_SND_SOC_CIRRUS_REINIT_SYSFS
  165. static ssize_t cirrus_cal_reinit_show(struct device *dev,
  166. struct device_attribute *attr,
  167. char *buf)
  168. {
  169. return sprintf(buf, "\n");
  170. }
  171. static ssize_t cirrus_cal_reinit_store(struct device *dev,
  172. struct device_attribute *attr,
  173. const char *buf, size_t size)
  174. {
  175. int reinit, i;
  176. int ret = kstrtos32(buf, 10, &reinit);
  177. if (amp_group->cal_running) {
  178. dev_err(amp_group->cal_dev,
  179. "cirrus_cal measurement in progress\n");
  180. return size;
  181. }
  182. if (ret == 0 && reinit == 1) {
  183. mutex_lock(&amp_group->cal_lock);
  184. for (i = 0; i < amp_group->num_amps; i++) {
  185. if (amp_group->amps[i].amp_reinit != NULL)
  186. amp_group->amps[i].amp_reinit(
  187. amp_group->amps[i].component);
  188. }
  189. mutex_unlock(&amp_group->cal_lock);
  190. }
  191. return size;
  192. }
  193. #endif /* CONFIG_SND_SOC_CIRRUS_REINIT_SYSFS*/
  194. static ssize_t cirrus_cal_vval_show(struct device *dev,
  195. struct device_attribute *attr,
  196. char *buf)
  197. {
  198. const char *suffix = &(attr->attr.name[strlen("v_validation")]);
  199. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  200. dev_info(dev, "%s\n", __func__);
  201. return sprintf(buf, "%d", amp->cal.v_validation);
  202. }
  203. static ssize_t cirrus_cal_vval_store(struct device *dev,
  204. struct device_attribute *attr,
  205. const char *buf, size_t size)
  206. {
  207. dev_info(dev, "%s\n", __func__);
  208. return 0;
  209. }
  210. static ssize_t cirrus_cal_rdc_show(struct device *dev,
  211. struct device_attribute *attr,
  212. char *buf)
  213. {
  214. unsigned int rdc;
  215. const char *suffix = &(attr->attr.name[strlen("rdc")]);
  216. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  217. if (amp) {
  218. rdc = amp->cal.efs_cache_rdc;
  219. return sprintf(buf, "%d", rdc);
  220. } else
  221. return 0;
  222. }
  223. static ssize_t cirrus_cal_rdc_store(struct device *dev,
  224. struct device_attribute *attr,
  225. const char *buf, size_t size)
  226. {
  227. int rdc, ret;
  228. const char *suffix = &(attr->attr.name[strlen("rdc")]);
  229. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  230. bool vimon_valid;
  231. ret = kstrtos32(buf, 10, &rdc);
  232. if (ret == 0 && amp) {
  233. if (rdc < 0) {
  234. amp->cal.efs_cache_vsc = 0;
  235. amp->cal.efs_cache_isc = 0;
  236. amp->cal.efs_cache_rdc = 0;
  237. amp->cal.efs_cache_valid = 0;
  238. return size;
  239. }
  240. amp->cal.efs_cache_rdc = rdc;
  241. dev_info(dev, "EFS Cache RDC set: 0x%x\n", rdc);
  242. vimon_valid = (!amp->perform_vimon_cal) || (amp->cal.efs_cache_vsc &&
  243. amp->cal.efs_cache_isc);
  244. if (amp->cal.efs_cache_rdc && amp_group->efs_cache_temp &&
  245. vimon_valid)
  246. amp->cal.efs_cache_valid = 1;
  247. }
  248. return size;
  249. }
  250. static ssize_t cirrus_cal_vsc_show(struct device *dev,
  251. struct device_attribute *attr,
  252. char *buf)
  253. {
  254. unsigned int vsc;
  255. const char *suffix = &(attr->attr.name[strlen("vsc")]);
  256. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  257. if (amp) {
  258. vsc = amp->cal.efs_cache_vsc;
  259. return sprintf(buf, "%d", vsc);
  260. } else
  261. return 0;
  262. }
  263. static ssize_t cirrus_cal_vsc_store(struct device *dev,
  264. struct device_attribute *attr,
  265. const char *buf, size_t size)
  266. {
  267. int vsc, ret;
  268. const char *suffix = &(attr->attr.name[strlen("vsc")]);
  269. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  270. bool vimon_valid;
  271. ret = kstrtos32(buf, 10, &vsc);
  272. if (ret == 0 && amp) {
  273. if (vsc < 0) {
  274. amp->cal.efs_cache_vsc = 0;
  275. amp->cal.efs_cache_isc = 0;
  276. amp->cal.efs_cache_rdc = 0;
  277. amp->cal.efs_cache_valid = 0;
  278. return size;
  279. }
  280. amp->cal.efs_cache_vsc = vsc;
  281. dev_info(dev, "EFS Cache VSC set: 0x%x\n", vsc);
  282. vimon_valid = (!amp->perform_vimon_cal) || (amp->cal.efs_cache_vsc &&
  283. amp->cal.efs_cache_isc);
  284. if (amp->cal.efs_cache_rdc && amp_group->efs_cache_temp &&
  285. vimon_valid)
  286. amp->cal.efs_cache_valid = 1;
  287. }
  288. return size;
  289. }
  290. static ssize_t cirrus_cal_isc_show(struct device *dev,
  291. struct device_attribute *attr,
  292. char *buf)
  293. {
  294. unsigned int isc;
  295. const char *suffix = &(attr->attr.name[strlen("isc")]);
  296. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  297. if (amp) {
  298. isc = amp->cal.efs_cache_isc;
  299. return sprintf(buf, "%d", isc);
  300. } else
  301. return 0;
  302. }
  303. static ssize_t cirrus_cal_isc_store(struct device *dev,
  304. struct device_attribute *attr,
  305. const char *buf, size_t size)
  306. {
  307. int isc, ret;
  308. const char *suffix = &(attr->attr.name[strlen("isc")]);
  309. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  310. bool vimon_valid;
  311. ret = kstrtos32(buf, 10, &isc);
  312. if (ret == 0 && amp) {
  313. if (isc < 0) {
  314. amp->cal.efs_cache_vsc = 0;
  315. amp->cal.efs_cache_isc = 0;
  316. amp->cal.efs_cache_rdc = 0;
  317. amp->cal.efs_cache_valid = 0;
  318. return size;
  319. }
  320. amp->cal.efs_cache_isc = isc;
  321. dev_info(dev, "EFS Cache ISC set: 0x%x\n", isc);
  322. vimon_valid = (!amp->perform_vimon_cal) || (amp->cal.efs_cache_vsc &&
  323. amp->cal.efs_cache_isc);
  324. if (amp->cal.efs_cache_rdc && amp_group->efs_cache_temp &&
  325. vimon_valid)
  326. amp->cal.efs_cache_valid = 1;
  327. }
  328. return size;
  329. }
  330. static ssize_t cirrus_cal_temp_show(struct device *dev,
  331. struct device_attribute *attr,
  332. char *buf)
  333. {
  334. unsigned int temp;
  335. const char *suffix = &(attr->attr.name[strlen("temp")]);
  336. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  337. if (amp) {
  338. temp = amp_group->efs_cache_temp;
  339. return sprintf(buf, "%d", temp);
  340. } else
  341. return 0;
  342. }
  343. static ssize_t cirrus_cal_temp_store(struct device *dev,
  344. struct device_attribute *attr,
  345. const char *buf, size_t size)
  346. {
  347. int temp, ret;
  348. const char *suffix = &(attr->attr.name[strlen("temp")]);
  349. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  350. bool vimon_valid;
  351. ret = kstrtos32(buf, 10, &temp);
  352. if (ret == 0 && amp) {
  353. amp_group->efs_cache_temp = temp;
  354. dev_info(dev, "EFS Cache temp set: %d\n", temp);
  355. vimon_valid = (!amp->perform_vimon_cal) || (amp->cal.efs_cache_vsc &&
  356. amp->cal.efs_cache_isc);
  357. if (amp->cal.efs_cache_rdc && amp_group->efs_cache_temp &&
  358. vimon_valid)
  359. amp->cal.efs_cache_valid = 1;
  360. }
  361. return size;
  362. }
  363. static ssize_t cirrus_cal_checksum_show(struct device *dev,
  364. struct device_attribute *attr,
  365. char *buf)
  366. {
  367. unsigned int checksum;
  368. const char *suffix = &(attr->attr.name[strlen("checksum")]);
  369. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  370. if (amp) {
  371. cirrus_amp_read_ctl(amp, amp->cal_ops->controls.cal_checksum.name,
  372. WMFW_ADSP2_XM, amp->cal_ops->controls.cal_checksum.alg_id, &checksum);
  373. return sprintf(buf, "%d", checksum);
  374. } else
  375. return 0;
  376. }
  377. static ssize_t cirrus_cal_checksum_store(struct device *dev,
  378. struct device_attribute *attr,
  379. const char *buf, size_t size)
  380. {
  381. int checksum, ret;
  382. const char *suffix = &(attr->attr.name[strlen("checksum")]);
  383. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  384. ret = kstrtos32(buf, 10, &checksum);
  385. if (ret == 0 && amp)
  386. cirrus_amp_write_ctl(amp, amp->cal_ops->controls.cal_checksum.name,
  387. WMFW_ADSP2_XM, amp->cal_ops->controls.cal_checksum.alg_id, checksum);
  388. return size;
  389. }
  390. static ssize_t cirrus_cal_set_status_show(struct device *dev,
  391. struct device_attribute *attr,
  392. char *buf)
  393. {
  394. unsigned int set_status;
  395. const char *suffix = &(attr->attr.name[strlen("set_status")]);
  396. struct cirrus_amp *amp = cirrus_get_amp_from_suffix(suffix);
  397. if (amp) {
  398. cirrus_amp_read_ctl(amp, amp->cal_ops->controls.cal_set_status.name,
  399. WMFW_ADSP2_XM, amp->cal_ops->controls.cal_checksum.alg_id, &set_status);
  400. return sprintf(buf, "%d", set_status);
  401. } else
  402. return 0;
  403. }
  404. static ssize_t cirrus_cal_set_status_store(struct device *dev,
  405. struct device_attribute *attr,
  406. const char *buf, size_t size)
  407. {
  408. return 0;
  409. }
  410. static DEVICE_ATTR(version, 0444, cirrus_cal_version_show,
  411. cirrus_cal_version_store);
  412. static DEVICE_ATTR(status, 0664, cirrus_cal_status_show,
  413. cirrus_cal_status_store);
  414. static DEVICE_ATTR(v_status, 0664, cirrus_cal_v_status_show,
  415. cirrus_cal_v_status_store);
  416. #ifdef CONFIG_SND_SOC_CIRRUS_REINIT_SYSFS
  417. static DEVICE_ATTR(reinit, 0664, cirrus_cal_reinit_show,
  418. cirrus_cal_reinit_store);
  419. #endif /* CONFIG_SND_SOC_CIRRUS_REINIT_SYSFS */
  420. static struct device_attribute v_val_attribute = {
  421. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0664)},
  422. .show = cirrus_cal_v_status_show,
  423. .store = cirrus_cal_v_status_store,
  424. };
  425. static struct device_attribute generic_amp_attrs[CIRRUS_CAL_NUM_ATTRS_AMP] = {
  426. {
  427. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0444)},
  428. .show = cirrus_cal_vval_show,
  429. .store = cirrus_cal_vval_store,
  430. },
  431. {
  432. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0664)},
  433. .show = cirrus_cal_rdc_show,
  434. .store = cirrus_cal_rdc_store,
  435. },
  436. {
  437. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0664)},
  438. .show = cirrus_cal_vsc_show,
  439. .store = cirrus_cal_vsc_store,
  440. },
  441. {
  442. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0664)},
  443. .show = cirrus_cal_isc_show,
  444. .store = cirrus_cal_isc_store,
  445. },
  446. {
  447. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0664)},
  448. .show = cirrus_cal_temp_show,
  449. .store = cirrus_cal_temp_store,
  450. },
  451. {
  452. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0664)},
  453. .show = cirrus_cal_checksum_show,
  454. .store = cirrus_cal_checksum_store,
  455. },
  456. {
  457. .attr = {.mode = VERIFY_OCTAL_PERMISSIONS(0444)},
  458. .show = cirrus_cal_set_status_show,
  459. .store = cirrus_cal_set_status_store,
  460. },
  461. };
  462. static const char *generic_amp_attr_names[CIRRUS_CAL_NUM_ATTRS_AMP] = {
  463. "v_validation",
  464. "rdc",
  465. "vsc",
  466. "isc",
  467. "temp",
  468. "checksum",
  469. "set_status"
  470. };
  471. static struct attribute *cirrus_cal_attr_base[] = {
  472. &dev_attr_version.attr,
  473. &dev_attr_status.attr,
  474. &dev_attr_v_status.attr,
  475. #ifdef CONFIG_SND_SOC_CIRRUS_REINIT_SYSFS
  476. &dev_attr_reinit.attr,
  477. #endif /* CONFIG_SND_SOC_CIRRUS_REINIT_SYSFS */
  478. NULL,
  479. };
  480. /* Kernel does not allow attributes to be dynamically allocated */
  481. static struct attribute_group cirrus_cal_attr_grp;
  482. static struct device_attribute
  483. amp_attrs_prealloc[CIRRUS_MAX_AMPS][CIRRUS_CAL_NUM_ATTRS_AMP];
  484. static char attr_names_prealloc[CIRRUS_MAX_AMPS][CIRRUS_CAL_NUM_ATTRS_AMP][20];
  485. static char v_val_attr_names_prealloc[CIRRUS_MAX_AMPS][20];
  486. static struct device_attribute v_val_attrs_prealloc[CIRRUS_MAX_AMPS];
  487. struct device_attribute *cirrus_cal_create_amp_attrs(const char *mfd_suffix,
  488. int index)
  489. {
  490. struct device_attribute *amp_attrs_new;
  491. int i, suffix_len = strlen(mfd_suffix);
  492. if (index >= CIRRUS_MAX_AMPS)
  493. return NULL;
  494. amp_attrs_new = &(amp_attrs_prealloc[index][0]);
  495. memcpy(amp_attrs_new, &generic_amp_attrs,
  496. sizeof(struct device_attribute) *
  497. CIRRUS_CAL_NUM_ATTRS_AMP);
  498. for (i = 0; i < CIRRUS_CAL_NUM_ATTRS_AMP; i++) {
  499. amp_attrs_new[i].attr.name = attr_names_prealloc[index][i];
  500. snprintf((char *)amp_attrs_new[i].attr.name,
  501. strlen(generic_amp_attr_names[i]) + suffix_len + 1,
  502. "%s%s", generic_amp_attr_names[i], mfd_suffix);
  503. }
  504. return amp_attrs_new;
  505. }
  506. int cirrus_cal_init(void)
  507. {
  508. struct device_attribute *new_attrs;
  509. int ret = 0, i, j, num_amps, v_val_num_attrs = 0;
  510. if (!amp_group) {
  511. pr_err("%s: Empty amp group\n", __func__);
  512. return -ENODATA;
  513. }
  514. amp_group->cal_dev = device_create(cirrus_amp_class, NULL, 1, NULL,
  515. CIRRUS_CAL_DIR_NAME);
  516. if (IS_ERR(amp_group->cal_dev)) {
  517. ret = PTR_ERR(amp_group->cal_dev);
  518. pr_err("%s: Failed to create CAL device (%d)\n", __func__, ret);
  519. return ret;
  520. }
  521. dev_set_drvdata(amp_group->cal_dev, amp_group);
  522. num_amps = amp_group->num_amps;
  523. for (i = 0; i < num_amps; i++) {
  524. if (amp_group->amps[i].v_val_separate)
  525. v_val_num_attrs++;
  526. }
  527. cirrus_cal_attr_grp.attrs = kzalloc(sizeof(struct attribute *) *
  528. (CIRRUS_CAL_NUM_ATTRS_AMP * num_amps +
  529. v_val_num_attrs +
  530. CIRRUS_CAL_NUM_ATTRS_BASE + 1),
  531. GFP_KERNEL);
  532. for (i = 0; i < num_amps; i++) {
  533. new_attrs = cirrus_cal_create_amp_attrs(
  534. amp_group->amps[i].mfd_suffix, i);
  535. for (j = 0; j < CIRRUS_CAL_NUM_ATTRS_AMP; j++) {
  536. dev_dbg(amp_group->cal_dev, "New attribute: %s\n",
  537. new_attrs[j].attr.name);
  538. cirrus_cal_attr_grp.attrs[i * CIRRUS_CAL_NUM_ATTRS_AMP
  539. + j] = &new_attrs[j].attr;
  540. }
  541. }
  542. for (i = j = 0; i < num_amps; i++) {
  543. if (amp_group->amps[i].v_val_separate) {
  544. memcpy(&v_val_attrs_prealloc[j],
  545. &v_val_attribute, sizeof(struct device_attribute));
  546. v_val_attrs_prealloc[j].attr.name =
  547. v_val_attr_names_prealloc[j];
  548. snprintf((char *)v_val_attrs_prealloc[j].attr.name,
  549. strlen("v_status") +
  550. strlen(amp_group->amps[i].mfd_suffix) + 1,
  551. "v_status%s", amp_group->amps[i].mfd_suffix);
  552. dev_info(amp_group->cal_dev, "New attribute: %s\n",
  553. v_val_attrs_prealloc[j].attr.name);
  554. cirrus_cal_attr_grp.attrs[num_amps * CIRRUS_CAL_NUM_ATTRS_AMP
  555. + j] = &v_val_attrs_prealloc[j].attr;
  556. j++;
  557. }
  558. }
  559. memcpy(&cirrus_cal_attr_grp.attrs[num_amps * CIRRUS_CAL_NUM_ATTRS_AMP +
  560. v_val_num_attrs],
  561. cirrus_cal_attr_base, sizeof(struct attribute *) *
  562. CIRRUS_CAL_NUM_ATTRS_BASE);
  563. cirrus_cal_attr_grp.attrs[num_amps * CIRRUS_CAL_NUM_ATTRS_AMP +
  564. CIRRUS_CAL_NUM_ATTRS_BASE + v_val_num_attrs] = NULL;
  565. ret = sysfs_create_group(&amp_group->cal_dev->kobj,
  566. &cirrus_cal_attr_grp);
  567. if (ret) {
  568. dev_err(amp_group->cal_dev, "Failed to create sysfs group\n");
  569. device_del(amp_group->bd_dev);
  570. return ret;
  571. }
  572. mutex_init(&amp_group->cal_lock);
  573. INIT_DELAYED_WORK(&amp_group->cal_complete_work, cirrus_cal_complete_work);
  574. return ret;
  575. }
  576. void cirrus_cal_exit(void)
  577. {
  578. flush_work(&amp_group->cal_complete_work.work);
  579. mutex_destroy(&amp_group->cal_lock);
  580. kfree(cirrus_cal_attr_grp.attrs);
  581. device_del(amp_group->bd_dev);
  582. }