sec_audio_sysfs.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (c) 2020, The Linux Foundation. All rights reserved.
  4. */
  5. /*
  6. * sec_audio_sysfs.c
  7. *
  8. * Copyright (c) 2017 Samsung Electronics
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. *
  24. */
  25. #include <linux/err.h>
  26. #include <linux/init.h>
  27. #include <linux/module.h>
  28. #include <linux/of.h>
  29. #include <linux/platform_device.h>
  30. #include <linux/slab.h>
  31. #include <linux/time.h>
  32. #include <linux/uaccess.h>
  33. #include <linux/wait.h>
  34. #include <sound/samsung/sec_audio_sysfs.h>
  35. #include <sound/samsung/snd_debug_proc.h>
  36. #define EARJACK_DEV_ID 0
  37. #define CODEC_DEV_ID 1
  38. #define AMP_DEV_ID 2
  39. #define ADSP_DEV_ID 3
  40. #define ADSP_SRCNT_MAX 1000
  41. #define ADSP_SRCNT_SUM_MAX 10000
  42. /* bigdata add */
  43. #define DECLARE_AMP_BIGDATA_SYSFS(id) \
  44. static ssize_t audio_amp_##id##_temperature_max_show(struct device *dev, \
  45. struct device_attribute *attr, char *buf) \
  46. { \
  47. int report = 0; \
  48. if (audio_data->get_amp_temperature_max) \
  49. report = audio_data->get_amp_temperature_max((id)); \
  50. else \
  51. dev_info(dev, "%s: No callback registered\n", __func__); \
  52. return snprintf(buf, PAGE_SIZE, "%d\n", report); \
  53. } \
  54. static DEVICE_ATTR(temperature_max_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  55. audio_amp_##id##_temperature_max_show, NULL); \
  56. static ssize_t audio_amp_##id##_temperature_keep_max_show(struct device *dev, \
  57. struct device_attribute *attr, char *buf) \
  58. { \
  59. int report = 0; \
  60. if (audio_data->get_amp_temperature_keep_max) \
  61. report = audio_data->get_amp_temperature_keep_max((id)); \
  62. else \
  63. dev_info(dev, "%s: No callback registered\n", __func__); \
  64. return snprintf(buf, PAGE_SIZE, "%d\n", report); \
  65. } \
  66. static DEVICE_ATTR(temperature_keep_max_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  67. audio_amp_##id##_temperature_keep_max_show, NULL); \
  68. static ssize_t audio_amp_##id##_temperature_overcount_show(struct device *dev, \
  69. struct device_attribute *attr, char *buf) \
  70. { \
  71. int report = 0; \
  72. if (audio_data->get_amp_temperature_overcount) \
  73. report = audio_data->get_amp_temperature_overcount((id)); \
  74. else \
  75. dev_info(dev, "%s: No callback registered\n", __func__); \
  76. return snprintf(buf, PAGE_SIZE, "%d\n", report); \
  77. } \
  78. static DEVICE_ATTR(temperature_overcount_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  79. audio_amp_##id##_temperature_overcount_show, NULL); \
  80. static ssize_t audio_amp_##id##_excursion_max_show(struct device *dev, \
  81. struct device_attribute *attr, char *buf) \
  82. { \
  83. int report = 0; \
  84. if (audio_data->get_amp_excursion_max) \
  85. report = audio_data->get_amp_excursion_max((id)); \
  86. else \
  87. dev_info(dev, "%s: No callback registered\n", __func__); \
  88. return snprintf(buf, PAGE_SIZE, "%04d\n", report); \
  89. } \
  90. static DEVICE_ATTR(excursion_max_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  91. audio_amp_##id##_excursion_max_show, NULL); \
  92. static ssize_t audio_amp_##id##_excursion_overcount_show(struct device *dev, \
  93. struct device_attribute *attr, char *buf) \
  94. { \
  95. int report = 0; \
  96. if (audio_data->get_amp_excursion_overcount) \
  97. report = audio_data->get_amp_excursion_overcount(id); \
  98. else \
  99. dev_info(dev, "%s: No callback registered\n", __func__); \
  100. return snprintf(buf, PAGE_SIZE, "%d\n", report); \
  101. } \
  102. static DEVICE_ATTR(excursion_overcount_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  103. audio_amp_##id##_excursion_overcount_show, NULL); \
  104. static ssize_t audio_amp_##id##_curr_temperature_show(struct device *dev, \
  105. struct device_attribute *attr, char *buf) \
  106. { \
  107. int report = 0; \
  108. if (audio_data->get_amp_curr_temperature) \
  109. report = audio_data->get_amp_curr_temperature((id)); \
  110. else \
  111. dev_info(dev, "%s: No callback registered\n", __func__); \
  112. return snprintf(buf, PAGE_SIZE, "%d\n", report); \
  113. } \
  114. static DEVICE_ATTR(curr_temperature_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  115. audio_amp_##id##_curr_temperature_show, NULL); \
  116. static ssize_t audio_amp_##id##_surface_temperature_store(struct device *dev, \
  117. struct device_attribute *attr, const char *buf, size_t size) \
  118. { \
  119. int ret, temp = 0; \
  120. ret = kstrtos32(buf, 10, &temp); \
  121. if (audio_data->set_amp_surface_temperature) \
  122. ret = audio_data->set_amp_surface_temperature((id), temp); \
  123. else \
  124. dev_info(dev, "%s: No callback registered\n", __func__); \
  125. return size; \
  126. } \
  127. static DEVICE_ATTR(surface_temperature_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  128. NULL, audio_amp_##id##_surface_temperature_store); \
  129. static ssize_t audio_amp_##id##_ready_show(struct device *dev, \
  130. struct device_attribute *attr, char *buf) \
  131. { \
  132. int report = 0; \
  133. if (audio_data->get_amp_ready) \
  134. report = audio_data->get_amp_ready((id)); \
  135. else {\
  136. dev_info(dev, "%s: No callback registered\n", __func__); \
  137. report = -EACCES; \
  138. } \
  139. return snprintf(buf, PAGE_SIZE, "%d\n", report); \
  140. } \
  141. static DEVICE_ATTR(ready_##id, S_IRUGO | S_IWUSR | S_IWGRP, \
  142. audio_amp_##id##_ready_show, NULL); \
  143. static struct attribute *audio_amp_##id##_attr[] = { \
  144. &dev_attr_temperature_max_##id.attr, \
  145. &dev_attr_temperature_keep_max_##id.attr, \
  146. &dev_attr_temperature_overcount_##id.attr, \
  147. &dev_attr_excursion_max_##id.attr, \
  148. &dev_attr_excursion_overcount_##id.attr, \
  149. &dev_attr_curr_temperature_##id.attr, \
  150. &dev_attr_surface_temperature_##id.attr, \
  151. &dev_attr_ready_##id.attr, \
  152. NULL, \
  153. }
  154. static struct sec_audio_sysfs_data *audio_data;
  155. static int adsp_silent_reset_count;
  156. static int adsp_silent_reset_count_sum;
  157. int audio_register_jack_select_cb(int (*set_jack) (int))
  158. {
  159. if (audio_data->set_jack_state) {
  160. dev_err(audio_data->jack_dev,
  161. "%s: Already registered\n", __func__);
  162. return -EEXIST;
  163. }
  164. audio_data->set_jack_state = set_jack;
  165. return 0;
  166. }
  167. EXPORT_SYMBOL_GPL(audio_register_jack_select_cb);
  168. static ssize_t audio_jack_select_store(struct device *dev,
  169. struct device_attribute *attr, const char *buf, size_t size)
  170. {
  171. if (audio_data->set_jack_state) {
  172. if ((!size) || (buf[0] != '1')) {
  173. dev_info(dev, "%s: Forced remove jack\n", __func__);
  174. audio_data->set_jack_state(0);
  175. } else {
  176. dev_info(dev, "%s: Forced detect jack\n", __func__);
  177. audio_data->set_jack_state(1);
  178. }
  179. } else {
  180. dev_info(dev, "%s: No callback registered\n", __func__);
  181. }
  182. return size;
  183. }
  184. static DEVICE_ATTR(select_jack, S_IRUGO | S_IWUSR | S_IWGRP,
  185. NULL, audio_jack_select_store);
  186. int audio_register_jack_state_cb(int (*jack_state) (void))
  187. {
  188. if (audio_data->get_jack_state) {
  189. dev_err(audio_data->jack_dev,
  190. "%s: Already registered\n", __func__);
  191. return -EEXIST;
  192. }
  193. audio_data->get_jack_state = jack_state;
  194. return 0;
  195. }
  196. EXPORT_SYMBOL_GPL(audio_register_jack_state_cb);
  197. static ssize_t audio_jack_state_show(struct device *dev,
  198. struct device_attribute *attr, char *buf)
  199. {
  200. int report = 0;
  201. if (audio_data->get_jack_state)
  202. report = audio_data->get_jack_state();
  203. else
  204. dev_info(dev, "%s: No callback registered\n", __func__);
  205. return snprintf(buf, 4, "%d\n", report);
  206. }
  207. static DEVICE_ATTR(state, S_IRUGO | S_IWUSR | S_IWGRP,
  208. audio_jack_state_show, NULL);
  209. int audio_register_key_state_cb(int (*key_state) (void))
  210. {
  211. if (audio_data->get_key_state) {
  212. dev_err(audio_data->jack_dev,
  213. "%s: Already registered\n", __func__);
  214. return -EEXIST;
  215. }
  216. audio_data->get_key_state = key_state;
  217. return 0;
  218. }
  219. EXPORT_SYMBOL_GPL(audio_register_key_state_cb);
  220. static ssize_t audio_key_state_show(struct device *dev,
  221. struct device_attribute *attr, char *buf)
  222. {
  223. int report = 0;
  224. if (audio_data->get_key_state)
  225. report = audio_data->get_key_state();
  226. else
  227. dev_info(dev, "%s: No callback registered\n", __func__);
  228. return snprintf(buf, 4, "%d\n", report);
  229. }
  230. static DEVICE_ATTR(key_state, S_IRUGO | S_IWUSR | S_IWGRP,
  231. audio_key_state_show, NULL);
  232. int audio_register_mic_adc_cb(int (*mic_adc) (void))
  233. {
  234. if (audio_data->get_mic_adc) {
  235. dev_err(audio_data->jack_dev,
  236. "%s: Already registered\n", __func__);
  237. return -EEXIST;
  238. }
  239. audio_data->get_mic_adc = mic_adc;
  240. return 0;
  241. }
  242. EXPORT_SYMBOL_GPL(audio_register_mic_adc_cb);
  243. static ssize_t audio_mic_adc_show(struct device *dev,
  244. struct device_attribute *attr, char *buf)
  245. {
  246. int report = 0;
  247. if (audio_data->get_mic_adc)
  248. report = audio_data->get_mic_adc();
  249. else
  250. dev_info(dev, "%s: No callback registered\n", __func__);
  251. return snprintf(buf, 16, "%d\n", report);
  252. }
  253. static DEVICE_ATTR(mic_adc, S_IRUGO | S_IWUSR | S_IWGRP,
  254. audio_mic_adc_show, NULL);
  255. int audio_register_force_enable_antenna_cb(int (*force_enable_antenna) (int))
  256. {
  257. if (audio_data->set_force_enable_antenna) {
  258. dev_err(audio_data->jack_dev,
  259. "%s: Already registered\n", __func__);
  260. return -EEXIST;
  261. }
  262. audio_data->set_force_enable_antenna = force_enable_antenna;
  263. return 0;
  264. }
  265. EXPORT_SYMBOL_GPL(audio_register_force_enable_antenna_cb);
  266. static ssize_t force_enable_antenna_store(struct device *dev,
  267. struct device_attribute *attr, const char *buf, size_t size)
  268. {
  269. if (audio_data->set_force_enable_antenna) {
  270. if ((!size) || (buf[0] != '1')) {
  271. dev_info(dev, "%s: antenna disable\n", __func__);
  272. audio_data->set_force_enable_antenna(0);
  273. } else {
  274. dev_info(dev, "%s: update antenna enable\n", __func__);
  275. audio_data->set_force_enable_antenna(1);
  276. }
  277. } else {
  278. dev_info(dev, "%s: No callback registered\n", __func__);
  279. }
  280. return size;
  281. }
  282. static DEVICE_ATTR(force_enable_antenna, S_IRUGO | S_IWUSR | S_IWGRP,
  283. NULL, force_enable_antenna_store);
  284. int audio_register_antenna_state_cb(int (*antenna_state) (void))
  285. {
  286. if (audio_data->get_antenna_state) {
  287. dev_err(audio_data->jack_dev,
  288. "%s: Already registered\n", __func__);
  289. return -EEXIST;
  290. }
  291. audio_data->get_antenna_state = antenna_state;
  292. return 0;
  293. }
  294. EXPORT_SYMBOL_GPL(audio_register_antenna_state_cb);
  295. static ssize_t audio_antenna_state_show(struct device *dev,
  296. struct device_attribute *attr, char *buf)
  297. {
  298. int report = 0;
  299. if (audio_data->get_antenna_state)
  300. report = audio_data->get_antenna_state();
  301. else
  302. dev_info(dev, "%s: No callback registered\n", __func__);
  303. return snprintf(buf, 4, "%d\n", report);
  304. }
  305. static DEVICE_ATTR(antenna_state, S_IRUGO | S_IWUSR | S_IWGRP,
  306. audio_antenna_state_show, NULL);
  307. static struct attribute *sec_audio_jack_attr[] = {
  308. &dev_attr_select_jack.attr,
  309. &dev_attr_state.attr,
  310. &dev_attr_key_state.attr,
  311. &dev_attr_mic_adc.attr,
  312. &dev_attr_force_enable_antenna.attr,
  313. &dev_attr_antenna_state.attr,
  314. NULL,
  315. };
  316. static struct attribute_group sec_audio_jack_attr_group = {
  317. .attrs = sec_audio_jack_attr,
  318. };
  319. int audio_register_codec_id_state_cb(int (*codec_id_state) (void))
  320. {
  321. if (audio_data->get_codec_id_state) {
  322. dev_err(audio_data->codec_dev,
  323. "%s: Already registered\n", __func__);
  324. return -EEXIST;
  325. }
  326. audio_data->get_codec_id_state = codec_id_state;
  327. return 0;
  328. }
  329. EXPORT_SYMBOL_GPL(audio_register_codec_id_state_cb);
  330. static ssize_t audio_check_codec_id_show(struct device *dev,
  331. struct device_attribute *attr, char *buf)
  332. {
  333. int report = 0;
  334. if (audio_data->get_codec_id_state)
  335. report = audio_data->get_codec_id_state();
  336. else
  337. dev_info(dev, "%s: No callback registered\n", __func__);
  338. return snprintf(buf, 4, "%d\n", report);
  339. }
  340. static DEVICE_ATTR(check_codec_id, S_IRUGO | S_IWUSR | S_IWGRP,
  341. audio_check_codec_id_show, NULL);
  342. static struct attribute *sec_audio_codec_attr[] = {
  343. &dev_attr_check_codec_id.attr,
  344. NULL,
  345. };
  346. static struct attribute_group sec_audio_codec_attr_group = {
  347. .attrs = sec_audio_codec_attr,
  348. };
  349. /* bigdata */
  350. int audio_register_temperature_max_cb(int (*temperature_max) (enum amp_id))
  351. {
  352. if (audio_data->get_amp_temperature_max) {
  353. dev_err(audio_data->amp_dev,
  354. "%s: Already registered\n", __func__);
  355. return -EEXIST;
  356. }
  357. audio_data->get_amp_temperature_max = temperature_max;
  358. return 0;
  359. }
  360. EXPORT_SYMBOL_GPL(audio_register_temperature_max_cb);
  361. int audio_register_temperature_keep_max_cb(int (*temperature_keep_max) (enum amp_id))
  362. {
  363. if (audio_data->get_amp_temperature_keep_max) {
  364. dev_err(audio_data->amp_dev,
  365. "%s: Already registered\n", __func__);
  366. return -EEXIST;
  367. }
  368. audio_data->get_amp_temperature_keep_max = temperature_keep_max;
  369. return 0;
  370. }
  371. EXPORT_SYMBOL_GPL(audio_register_temperature_keep_max_cb);
  372. int audio_register_temperature_overcount_cb(int (*temperature_overcount) (enum amp_id))
  373. {
  374. if (audio_data->get_amp_temperature_overcount) {
  375. dev_err(audio_data->amp_dev,
  376. "%s: Already registered\n", __func__);
  377. return -EEXIST;
  378. }
  379. audio_data->get_amp_temperature_overcount = temperature_overcount;
  380. return 0;
  381. }
  382. EXPORT_SYMBOL_GPL(audio_register_temperature_overcount_cb);
  383. int audio_register_excursion_max_cb(int (*excursion_max) (enum amp_id))
  384. {
  385. if (audio_data->get_amp_excursion_max) {
  386. dev_err(audio_data->amp_dev,
  387. "%s: Already registered\n", __func__);
  388. return -EEXIST;
  389. }
  390. audio_data->get_amp_excursion_max = excursion_max;
  391. return 0;
  392. }
  393. EXPORT_SYMBOL_GPL(audio_register_excursion_max_cb);
  394. int audio_register_excursion_overcount_cb(int (*excursion_overcount) (enum amp_id))
  395. {
  396. if (audio_data->get_amp_excursion_overcount) {
  397. dev_err(audio_data->amp_dev,
  398. "%s: Already registered\n", __func__);
  399. return -EEXIST;
  400. }
  401. audio_data->get_amp_excursion_overcount = excursion_overcount;
  402. return 0;
  403. }
  404. EXPORT_SYMBOL_GPL(audio_register_excursion_overcount_cb);
  405. int audio_register_curr_temperature_cb(int (*curr_temperature) (enum amp_id))
  406. {
  407. if (audio_data->get_amp_curr_temperature) {
  408. dev_err(audio_data->amp_dev,
  409. "%s: Already registered\n", __func__);
  410. return -EEXIST;
  411. }
  412. audio_data->get_amp_curr_temperature = curr_temperature;
  413. return 0;
  414. }
  415. EXPORT_SYMBOL_GPL(audio_register_curr_temperature_cb);
  416. int audio_register_surface_temperature_cb(int (*surface_temperature) (enum amp_id, int temperature))
  417. {
  418. if (audio_data->set_amp_surface_temperature) {
  419. dev_err(audio_data->amp_dev,
  420. "%s: Already registered\n", __func__);
  421. return -EEXIST;
  422. }
  423. audio_data->set_amp_surface_temperature = surface_temperature;
  424. return 0;
  425. }
  426. EXPORT_SYMBOL_GPL(audio_register_surface_temperature_cb);
  427. int audio_register_ready_cb(int (*ready) (enum amp_id))
  428. {
  429. if (audio_data->get_amp_ready) {
  430. dev_err(audio_data->amp_dev,
  431. "%s: Already registered\n", __func__);
  432. return -EEXIST;
  433. }
  434. audio_data->get_amp_ready = ready;
  435. return 0;
  436. }
  437. EXPORT_SYMBOL_GPL(audio_register_ready_cb);
  438. DECLARE_AMP_BIGDATA_SYSFS(0);
  439. DECLARE_AMP_BIGDATA_SYSFS(1);
  440. DECLARE_AMP_BIGDATA_SYSFS(2);
  441. DECLARE_AMP_BIGDATA_SYSFS(3);
  442. static struct attribute_group sec_audio_amp_big_data_attr_group[AMP_ID_MAX] = {
  443. [AMP_0] = {.attrs = audio_amp_0_attr, },
  444. [AMP_1] = {.attrs = audio_amp_1_attr, },
  445. [AMP_2] = {.attrs = audio_amp_2_attr, },
  446. [AMP_3] = {.attrs = audio_amp_3_attr, },
  447. };
  448. void send_adsp_silent_reset_ev(void)
  449. {
  450. if (adsp_silent_reset_count < ADSP_SRCNT_MAX)
  451. adsp_silent_reset_count++;
  452. if (adsp_silent_reset_count_sum < ADSP_SRCNT_SUM_MAX)
  453. adsp_silent_reset_count_sum++;
  454. pr_info("%s: count %d\n", __func__,
  455. (adsp_silent_reset_count + adsp_silent_reset_count_sum));
  456. sdp_info_print("%s: count %d\n", __func__,
  457. (adsp_silent_reset_count + adsp_silent_reset_count_sum));
  458. }
  459. EXPORT_SYMBOL_GPL(send_adsp_silent_reset_ev);
  460. static ssize_t srcnt_show(struct device *dev,
  461. struct device_attribute *attr, char *buf)
  462. {
  463. int report = adsp_silent_reset_count;
  464. adsp_silent_reset_count = 0;
  465. if (adsp_silent_reset_count_sum < ADSP_SRCNT_SUM_MAX)
  466. adsp_silent_reset_count_sum += report;
  467. if (adsp_silent_reset_count_sum > ADSP_SRCNT_SUM_MAX)
  468. adsp_silent_reset_count_sum = ADSP_SRCNT_SUM_MAX;
  469. dev_info(dev, "%s: %d\n", __func__, report);
  470. return snprintf(buf, 8, "%d\n", report);
  471. }
  472. static DEVICE_ATTR_RO(srcnt);
  473. static ssize_t srcnt_keep_show(struct device *dev,
  474. struct device_attribute *attr, char *buf)
  475. {
  476. int report = adsp_silent_reset_count_sum;
  477. dev_info(dev, "%s: %d\n", __func__, report);
  478. return snprintf(buf, 8, "%d\n", report);
  479. }
  480. static DEVICE_ATTR_RO(srcnt_keep);
  481. static struct attribute *sec_audio_adsp_attrs[] = {
  482. &dev_attr_srcnt.attr,
  483. &dev_attr_srcnt_keep.attr,
  484. NULL,
  485. };
  486. static struct attribute_group sec_audio_adsp_attr_group = {
  487. .attrs = sec_audio_adsp_attrs,
  488. };
  489. static int sec_audio_sysfs_probe(struct platform_device *pdev)
  490. {
  491. struct device_node *np = pdev->dev.of_node;
  492. int i;
  493. if (audio_data == NULL) {
  494. dev_err(&pdev->dev, "%s: no audio_data\n", __func__);
  495. return -ENOMEM;
  496. }
  497. audio_data->no_earjack = of_property_read_bool(np, "audio,no-earjack");
  498. if (audio_data->no_earjack) {
  499. dev_info(&pdev->dev, "%s: remove earjack sysfs dev\n", __func__);
  500. if (audio_data->jack_dev) {
  501. sysfs_remove_group(&audio_data->jack_dev->kobj,
  502. &sec_audio_jack_attr_group);
  503. device_destroy(audio_data->audio_class, EARJACK_DEV_ID);
  504. }
  505. }
  506. of_property_read_u32(np, "audio,num-amp", &audio_data->num_amp);
  507. if (audio_data->num_amp > 0) {
  508. for (i = audio_data->num_amp; i < AMP_ID_MAX; i++) {
  509. sysfs_remove_group(&audio_data->amp_dev->kobj,
  510. &sec_audio_amp_big_data_attr_group[i]);
  511. }
  512. }
  513. return 0;
  514. }
  515. static int sec_audio_sysfs_remove(struct platform_device *pdev)
  516. {
  517. int i;
  518. if (audio_data->num_amp == 0)
  519. audio_data->num_amp = AMP_ID_MAX;
  520. for (i = 0; i < audio_data->num_amp; i++) {
  521. sysfs_remove_group(&audio_data->amp_dev->kobj,
  522. &sec_audio_amp_big_data_attr_group[i]);
  523. }
  524. return 0;
  525. }
  526. #if IS_ENABLED(CONFIG_OF)
  527. static const struct of_device_id sec_audio_sysfs_of_match[] = {
  528. { .compatible = "samsung,audio-sysfs", },
  529. {},
  530. };
  531. MODULE_DEVICE_TABLE(of, sec_audio_sysfs_of_match);
  532. #endif /* CONFIG_OF */
  533. static struct platform_driver sec_audio_sysfs_driver = {
  534. .driver = {
  535. .name = "sec-audio-sysfs",
  536. .owner = THIS_MODULE,
  537. .of_match_table = of_match_ptr(sec_audio_sysfs_of_match),
  538. },
  539. .probe = sec_audio_sysfs_probe,
  540. .remove = sec_audio_sysfs_remove,
  541. };
  542. static int __init sec_audio_sysfs_init(void)
  543. {
  544. int ret = 0;
  545. int i = 0;
  546. audio_data = kzalloc(sizeof(struct sec_audio_sysfs_data), GFP_KERNEL);
  547. if (audio_data == NULL)
  548. return -ENOMEM;
  549. audio_data->audio_class = class_create(THIS_MODULE, "audio");
  550. if (IS_ERR(audio_data->audio_class)) {
  551. pr_err("%s: Failed to create audio class\n", __func__);
  552. ret = PTR_ERR(audio_data->audio_class);
  553. goto err_alloc;
  554. }
  555. audio_data->jack_dev =
  556. device_create(audio_data->audio_class,
  557. NULL, EARJACK_DEV_ID, NULL, "earjack");
  558. if (IS_ERR(audio_data->jack_dev)) {
  559. pr_err("%s: Failed to create earjack device\n", __func__);
  560. ret = PTR_ERR(audio_data->jack_dev);
  561. goto err_class;
  562. }
  563. ret = sysfs_create_group(&audio_data->jack_dev->kobj,
  564. &sec_audio_jack_attr_group);
  565. if (ret) {
  566. pr_err("%s: Failed to create earjack sysfs\n", __func__);
  567. goto err_jack_device;
  568. }
  569. audio_data->codec_dev =
  570. device_create(audio_data->audio_class,
  571. NULL, CODEC_DEV_ID, NULL, "codec");
  572. if (IS_ERR(audio_data->codec_dev)) {
  573. pr_err("%s: Failed to create codec device\n", __func__);
  574. ret = PTR_ERR(audio_data->codec_dev);
  575. goto err_jack_attr;
  576. }
  577. ret = sysfs_create_group(&audio_data->codec_dev->kobj,
  578. &sec_audio_codec_attr_group);
  579. if (ret) {
  580. pr_err("%s: Failed to create codec sysfs\n", __func__);
  581. goto err_codec_device;
  582. }
  583. audio_data->amp_dev =
  584. device_create(audio_data->audio_class,
  585. NULL, AMP_DEV_ID, NULL, "amp");
  586. if (IS_ERR(audio_data->amp_dev)) {
  587. pr_err("%s: Failed to create amp device\n", __func__);
  588. ret = PTR_ERR(audio_data->amp_dev);
  589. goto err_codec_attr;
  590. }
  591. audio_data->num_amp = 0;
  592. for (i = 0; i < AMP_ID_MAX; i++) {
  593. ret = sysfs_create_group(&audio_data->amp_dev->kobj,
  594. &sec_audio_amp_big_data_attr_group[i]);
  595. if (ret) {
  596. pr_err("%s: Failed to create amp sysfs\n", __func__);
  597. goto err_amp_attr;
  598. }
  599. }
  600. pr_err("%s: DSP DEVICE CREATE\n", __func__);
  601. audio_data->adsp_dev =
  602. device_create(audio_data->audio_class,
  603. NULL, ADSP_DEV_ID, NULL, "dsp");
  604. if (IS_ERR(audio_data->adsp_dev)) {
  605. pr_err("%s: Failed to create adsp device\n", __func__);
  606. ret = PTR_ERR(audio_data->adsp_dev);
  607. goto err_amp_attr;
  608. }
  609. ret = sysfs_create_group(&audio_data->adsp_dev->kobj,
  610. &sec_audio_adsp_attr_group);
  611. if (ret) {
  612. pr_err("%s: Failed to create adsp sysfs\n", __func__);
  613. goto err_adsp_device;
  614. }
  615. ret = platform_driver_register(&sec_audio_sysfs_driver);
  616. if (ret) {
  617. pr_err("%s: fail to register sysfs driver\n", __func__);
  618. goto err_adsp_attr;
  619. }
  620. adsp_silent_reset_count = 0;
  621. adsp_silent_reset_count_sum = 0;
  622. return ret;
  623. err_adsp_attr:
  624. sysfs_remove_group(&audio_data->adsp_dev->kobj,
  625. &sec_audio_adsp_attr_group);
  626. err_adsp_device:
  627. device_destroy(audio_data->audio_class, ADSP_DEV_ID);
  628. audio_data->adsp_dev = NULL;
  629. err_amp_attr:
  630. while (--i >= 0)
  631. sysfs_remove_group(&audio_data->amp_dev->kobj,
  632. &sec_audio_amp_big_data_attr_group[i]);
  633. device_destroy(audio_data->audio_class, AMP_DEV_ID);
  634. audio_data->amp_dev = NULL;
  635. err_codec_attr:
  636. sysfs_remove_group(&audio_data->codec_dev->kobj,
  637. &sec_audio_codec_attr_group);
  638. err_codec_device:
  639. device_destroy(audio_data->audio_class, CODEC_DEV_ID);
  640. audio_data->codec_dev = NULL;
  641. err_jack_attr:
  642. sysfs_remove_group(&audio_data->jack_dev->kobj,
  643. &sec_audio_jack_attr_group);
  644. err_jack_device:
  645. device_destroy(audio_data->audio_class, EARJACK_DEV_ID);
  646. audio_data->jack_dev = NULL;
  647. err_class:
  648. class_destroy(audio_data->audio_class);
  649. audio_data->audio_class = NULL;
  650. err_alloc:
  651. kfree(audio_data);
  652. audio_data = NULL;
  653. return ret;
  654. }
  655. module_init(sec_audio_sysfs_init);
  656. static void __exit sec_audio_sysfs_exit(void)
  657. {
  658. platform_driver_unregister(&sec_audio_sysfs_driver);
  659. if (audio_data->amp_dev)
  660. device_destroy(audio_data->audio_class, AMP_DEV_ID);
  661. if (audio_data->codec_dev) {
  662. sysfs_remove_group(&audio_data->codec_dev->kobj,
  663. &sec_audio_codec_attr_group);
  664. device_destroy(audio_data->audio_class, CODEC_DEV_ID);
  665. }
  666. if (audio_data->jack_dev) {
  667. sysfs_remove_group(&audio_data->jack_dev->kobj,
  668. &sec_audio_jack_attr_group);
  669. device_destroy(audio_data->audio_class, EARJACK_DEV_ID);
  670. }
  671. if (audio_data->audio_class)
  672. class_destroy(audio_data->audio_class);
  673. kfree(audio_data);
  674. }
  675. module_exit(sec_audio_sysfs_exit);
  676. MODULE_DESCRIPTION("Samsung Electronics Audio SYSFS driver");
  677. MODULE_LICENSE("GPL");