aw87519_audio.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /*
  2. * aw87519_audio.c aw87519 pa module
  3. *
  4. * Version: v1.0.5
  5. *
  6. * Copyright (c) 2019 AWINIC Technology CO., LTD
  7. *
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by the
  11. * Free Software Foundation; either version 2 of the License, or (at your
  12. * option) any later version.
  13. */
  14. #include <linux/i2c.h>
  15. #include <linux/gpio.h>
  16. #include <linux/of_gpio.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/delay.h>
  19. #include <linux/irq.h>
  20. #include <linux/firmware.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/slab.h>
  23. #include <linux/fs.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/uaccess.h>
  26. #include <linux/io.h>
  27. #include <linux/init.h>
  28. #include <linux/pci.h>
  29. #include <linux/dma-mapping.h>
  30. #include <linux/gameport.h>
  31. #include <linux/module.h>
  32. #include <linux/moduleparam.h>
  33. #include <linux/mutex.h>
  34. #include <linux/timer.h>
  35. #include <linux/workqueue.h>
  36. #include <linux/hrtimer.h>
  37. #include "aw87519_audio.h"
  38. /*******************************************************************************
  39. * aw87519 marco
  40. ******************************************************************************/
  41. #define AW87519_I2C_NAME "aw87519_pa"
  42. #define AW87519_DRIVER_VERSION "v1.0.5"
  43. /*******************************************************************************
  44. * aw87519 variable
  45. ******************************************************************************/
  46. struct aw87519 *aw87519;
  47. struct aw87519_container *aw87519_spk_cnt;
  48. struct aw87519_container *aw87519_rcv_cnt;
  49. static char *aw87519_spk_name = "aw87519_spk.bin";
  50. static char *aw87519_rcv_name = "aw87519_rcv.bin";
  51. /*****************************************************************************
  52. * i2c write and read
  53. ****************************************************************************/
  54. static int aw87519_i2c_write(struct aw87519 *aw87519,
  55. unsigned char reg_addr, unsigned char reg_data)
  56. {
  57. int ret = -1;
  58. unsigned char cnt = 0;
  59. while (cnt < AW_I2C_RETRIES) {
  60. ret = i2c_smbus_write_byte_data(aw87519->i2c_client,
  61. reg_addr,
  62. reg_data);
  63. if (ret < 0) {
  64. return -1;
  65. } else {
  66. break;
  67. }
  68. cnt++;
  69. usleep_range(2000, 2500);
  70. }
  71. return ret;
  72. }
  73. static int aw87519_i2c_read(struct aw87519 *aw87519,
  74. unsigned char reg_addr, unsigned char *reg_data)
  75. {
  76. int ret = -1;
  77. unsigned char cnt = 0;
  78. while (cnt < AW_I2C_RETRIES) {
  79. ret = i2c_smbus_read_byte_data(aw87519->i2c_client, reg_addr);
  80. if (ret < 0) {
  81. return -1;
  82. } else {
  83. *reg_data = ret;
  84. break;
  85. }
  86. cnt++;
  87. usleep_range(2000, 2500);
  88. }
  89. return ret;
  90. }
  91. /****************************************************************************
  92. * aw87519 hardware control
  93. ***************************************************************************/
  94. unsigned int aw87519_hw_on(struct aw87519 *aw87519)
  95. {
  96. if (aw87519 && gpio_is_valid(aw87519->reset_gpio)) {
  97. gpio_set_value_cansleep(aw87519->reset_gpio, 0);
  98. usleep_range(2000, 2500);
  99. gpio_set_value_cansleep(aw87519->reset_gpio, 1);
  100. usleep_range(2000, 2500);
  101. aw87519->hwen_flag = 1;
  102. aw87519_i2c_write(aw87519, 0x64, 0x2C);
  103. } else {
  104. dev_err(&aw87519->i2c_client->dev, "%s: failed\n", __func__);
  105. }
  106. return 0;
  107. }
  108. unsigned int aw87519_hw_off(struct aw87519 *aw87519)
  109. {
  110. if (aw87519 && gpio_is_valid(aw87519->reset_gpio)) {
  111. gpio_set_value_cansleep(aw87519->reset_gpio, 0);
  112. usleep_range(2000, 2500);
  113. aw87519->hwen_flag = 0;
  114. } else {
  115. dev_err(&aw87519->i2c_client->dev, "%s: failed\n", __func__);
  116. }
  117. return 0;
  118. }
  119. /*******************************************************************************
  120. * aw87519 control interface
  121. ******************************************************************************/
  122. unsigned char aw87519_audio_receiver(void)
  123. {
  124. unsigned int i;
  125. unsigned int length;
  126. pr_info("%s enter\n", __func__);
  127. if (aw87519 == NULL)
  128. return 2;
  129. if (!aw87519->hwen_flag)
  130. aw87519_hw_on(aw87519);
  131. length = sizeof(aw87519_spk_cfg_default)/sizeof(char);
  132. if (aw87519->rcv_cfg_update_flag == 0) { /*update array data*/
  133. for (i = 0; i < length; i = i+2)
  134. aw87519_i2c_write(aw87519,
  135. aw87519_rcv_cfg_default[i],
  136. aw87519_rcv_cfg_default[i+1]);
  137. }
  138. if (aw87519->rcv_cfg_update_flag == 1) { /*update bin data*/
  139. for (i = 0; i < aw87519_rcv_cnt->len; i = i+2)
  140. aw87519_i2c_write(aw87519,
  141. aw87519_rcv_cnt->data[i],
  142. aw87519_rcv_cnt->data[i+1]);
  143. }
  144. return 0;
  145. }
  146. unsigned char aw87519_audio_speaker(void)
  147. {
  148. unsigned int i;
  149. unsigned int length;
  150. pr_info("%s enter\n", __func__);
  151. if (aw87519 == NULL)
  152. return 2;
  153. if (!aw87519->hwen_flag)
  154. aw87519_hw_on(aw87519);
  155. length = sizeof(aw87519_spk_cfg_default)/sizeof(char);
  156. if (aw87519->spk_cfg_update_flag == 0) { /*send array data*/
  157. for (i = 0; i < length; i = i+2)
  158. aw87519_i2c_write(aw87519,
  159. aw87519_spk_cfg_default[i],
  160. aw87519_spk_cfg_default[i+1]);
  161. }
  162. if (aw87519->spk_cfg_update_flag == 1) { /*send bin data*/
  163. for (i = 0; i < aw87519_spk_cnt->len; i = i+2)
  164. aw87519_i2c_write(aw87519,
  165. aw87519_spk_cnt->data[i],
  166. aw87519_spk_cnt->data[i+1]);
  167. }
  168. return 0;
  169. }
  170. unsigned char aw87519_audio_off(void)
  171. {
  172. if (aw87519 == NULL)
  173. return 2;
  174. if (aw87519->hwen_flag)
  175. aw87519_i2c_write(aw87519, 0x01, 0x00); /*CHIP Disable*/
  176. aw87519_hw_off(aw87519);
  177. return 0;
  178. }
  179. /*******************************************************************************
  180. * aw87519 firmware cfg update
  181. ******************************************************************************/
  182. static void aw87519_receiver_cfg_loaded(const struct firmware *cont,
  183. void *context)
  184. {
  185. int i = 0;
  186. pr_info("%s enter\n", __func__);
  187. if (!cont) {
  188. pr_err("%s: failed to read %s\n", __func__, aw87519_rcv_name);
  189. release_firmware(cont);
  190. return;
  191. }
  192. pr_info("%s: loaded %s - size: %zu\n", __func__, aw87519_rcv_name,
  193. cont ? cont->size : 0);
  194. for (i = 0; i < cont->size; i = i+2)
  195. pr_info("%s: addr:0x%04x, data:0x%02x\n",
  196. __func__, *(cont->data+i), *(cont->data+i+1));
  197. /* aw87519 ram update */
  198. aw87519_rcv_cnt = kzalloc(cont->size+sizeof(int), GFP_KERNEL);
  199. if (!aw87519_rcv_cnt) {
  200. release_firmware(cont);
  201. pr_err("%s: Error allocating memory\n", __func__);
  202. return;
  203. }
  204. aw87519_rcv_cnt->len = cont->size;
  205. memcpy(aw87519_rcv_cnt->data, cont->data, cont->size);
  206. release_firmware(cont);
  207. aw87519->rcv_cfg_update_flag = 1;
  208. pr_info("%s: fw update complete\n", __func__);
  209. }
  210. static int aw87519_rcv_update(struct aw87519 *aw87519)
  211. {
  212. pr_info("%s enter\n", __func__);
  213. return request_firmware_nowait(THIS_MODULE,
  214. FW_ACTION_HOTPLUG,
  215. aw87519_rcv_name,
  216. &aw87519->i2c_client->dev,
  217. GFP_KERNEL,
  218. aw87519,
  219. aw87519_receiver_cfg_loaded);
  220. }
  221. static void aw87519_speaker_cfg_loaded(const struct firmware *cont,
  222. void *context)
  223. {
  224. int i = 0;
  225. pr_info("%s enter\n", __func__);
  226. if (!cont) {
  227. pr_err("%s: failed to read %s\n", __func__, aw87519_spk_name);
  228. release_firmware(cont);
  229. return;
  230. }
  231. pr_info("%s: loaded %s - size: %zu\n", __func__, aw87519_spk_name,
  232. cont ? cont->size : 0);
  233. for (i = 0; i < cont->size; i = i+2)
  234. pr_info("%s: addr:0x%04x, data:0x%02x\n",
  235. __func__, *(cont->data+i), *(cont->data+i+1));
  236. /* aw87519 ram update */
  237. aw87519_spk_cnt = kzalloc(cont->size+sizeof(int), GFP_KERNEL);
  238. if (!aw87519_spk_cnt) {
  239. release_firmware(cont);
  240. pr_err("%s: Error allocating memory\n", __func__);
  241. return;
  242. }
  243. aw87519_spk_cnt->len = cont->size;
  244. memcpy(aw87519_spk_cnt->data, cont->data, cont->size);
  245. release_firmware(cont);
  246. aw87519->spk_cfg_update_flag = 1;
  247. pr_info("%s: fw update complete\n", __func__);
  248. aw87519_rcv_update(aw87519);
  249. }
  250. #ifdef AWINIC_CFG_UPDATE_DELAY
  251. static int aw87519_cfg_update(struct aw87519 *aw87519)
  252. {
  253. pr_info("%s enter\n", __func__);
  254. return request_firmware_nowait(THIS_MODULE,
  255. FW_ACTION_HOTPLUG,
  256. aw87519_spk_name,
  257. &aw87519->i2c_client->dev,
  258. GFP_KERNEL,
  259. aw87519,
  260. aw87519_speaker_cfg_loaded);
  261. }
  262. static void aw87519_cfg_work_routine(struct work_struct *work)
  263. {
  264. pr_info("%s enter\n", __func__);
  265. aw87519_cfg_update(aw87519);
  266. }
  267. #endif
  268. static int aw87519_cfg_init(struct aw87519 *aw87519)
  269. {
  270. int ret = -1;
  271. #ifdef AWINIC_CFG_UPDATE_DELAY
  272. int cfg_timer_val = 5000;
  273. INIT_DELAYED_WORK(&aw87519->ram_work, aw87519_cfg_work_routine);
  274. schedule_delayed_work(&aw87519->ram_work,
  275. msecs_to_jiffies(cfg_timer_val));
  276. ret = 0;
  277. #endif
  278. return ret;
  279. }
  280. /*******************************************************************************
  281. * aw87519 attribute
  282. ******************************************************************************/
  283. static ssize_t aw87519_get_reg(struct device *dev,
  284. struct device_attribute *attr, char *buf)
  285. {
  286. ssize_t len = 0;
  287. unsigned int i = 0;
  288. unsigned char reg_val = 0;
  289. for (i = 0; i < AW87519_REG_MAX; i++) {
  290. aw87519_i2c_read(aw87519, i, &reg_val);
  291. len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x\n",
  292. i, reg_val);
  293. }
  294. for (i = 0x60; i <= 0x69; i++) {
  295. aw87519_i2c_read(aw87519, i, &reg_val);
  296. len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x\n",
  297. i, reg_val);
  298. }
  299. return len;
  300. }
  301. static ssize_t aw87519_set_reg(struct device *dev,
  302. struct device_attribute *attr, const char *buf, size_t len)
  303. {
  304. unsigned int databuf[2] = {0, 0};
  305. if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2)
  306. aw87519_i2c_write(aw87519, databuf[0], databuf[1]);
  307. return len;
  308. }
  309. static ssize_t aw87519_get_hwen(struct device *dev,
  310. struct device_attribute *attr, char *buf)
  311. {
  312. ssize_t len = 0;
  313. len += snprintf(buf+len, PAGE_SIZE-len, "hwen: %d\n",
  314. aw87519->hwen_flag);
  315. return len;
  316. }
  317. static ssize_t aw87519_set_hwen(struct device *dev,
  318. struct device_attribute *attr, const char *buf, size_t len)
  319. {
  320. ssize_t ret;
  321. unsigned int state;
  322. ret = kstrtouint(buf, 10, &state);
  323. if (ret)
  324. goto out_strtoint;
  325. if (state == 1)
  326. aw87519_hw_on(aw87519);
  327. else
  328. aw87519_hw_off(aw87519);
  329. if (ret < 0)
  330. goto out;
  331. return len;
  332. out:
  333. dev_err(&aw87519->i2c_client->dev, "%s: i2c access fail to register\n",
  334. __func__);
  335. out_strtoint:
  336. dev_err(&aw87519->i2c_client->dev, "%s: fail to change str to int\n",
  337. __func__);
  338. return ret;
  339. }
  340. static ssize_t aw87519_get_update(struct device *dev,
  341. struct device_attribute *attr, char *buf)
  342. {
  343. ssize_t len = 0;
  344. return len;
  345. }
  346. static ssize_t aw87519_set_update(struct device *dev,
  347. struct device_attribute *attr, const char *buf, size_t len)
  348. {
  349. ssize_t ret, ret_fir;
  350. unsigned int state;
  351. ret = kstrtouint(buf, 10, &state);
  352. if (ret)
  353. goto out_strtoint;
  354. if (state > 0) {
  355. aw87519->spk_cfg_update_flag = 1;
  356. aw87519->rcv_cfg_update_flag = 1;
  357. ret_fir = request_firmware_nowait(THIS_MODULE,
  358. FW_ACTION_HOTPLUG,
  359. aw87519_spk_name,
  360. &aw87519->i2c_client->dev,
  361. GFP_KERNEL,
  362. aw87519,
  363. aw87519_speaker_cfg_loaded);
  364. if (ret_fir)
  365. pr_err("%s: request_firmware failed with read %s",
  366. __func__, aw87519_spk_name);
  367. }
  368. if (ret < 0)
  369. goto out;
  370. return len;
  371. out:
  372. dev_err(&aw87519->i2c_client->dev, "%s: i2c access fail to register\n",
  373. __func__);
  374. out_strtoint:
  375. dev_err(&aw87519->i2c_client->dev, "%s: fail to change str to int\n",
  376. __func__);
  377. return ret;
  378. }
  379. static ssize_t aw87519_get_mode(struct device *cd,
  380. struct device_attribute *attr, char *buf)
  381. {
  382. ssize_t len = 0;
  383. len += snprintf(buf+len, PAGE_SIZE-len, "0: off mode\n");
  384. len += snprintf(buf+len, PAGE_SIZE-len, "1: spk mode\n");
  385. len += snprintf(buf+len, PAGE_SIZE-len, "2: rcv mode\n");
  386. return len;
  387. }
  388. static ssize_t aw87519_set_mode(struct device *dev,
  389. struct device_attribute *attr, const char *buf, size_t len)
  390. {
  391. ssize_t ret;
  392. unsigned int state;
  393. ret = kstrtouint(buf, 10, &state);
  394. ret = kstrtouint(buf, 10, &state);
  395. if (ret)
  396. goto out_strtoint;
  397. if (state == 0)
  398. aw87519_audio_off();
  399. else if (state == 1)
  400. aw87519_audio_speaker();
  401. else if (state == 2)
  402. aw87519_audio_receiver();
  403. else
  404. aw87519_audio_off();
  405. if (ret < 0)
  406. goto out;
  407. return len;
  408. out:
  409. dev_err(&aw87519->i2c_client->dev, "%s: i2c access fail to register\n",
  410. __func__);
  411. out_strtoint:
  412. dev_err(&aw87519->i2c_client->dev, "%s: fail to change str to int\n",
  413. __func__);
  414. return ret;
  415. }
  416. static DEVICE_ATTR(reg, 0660, aw87519_get_reg, aw87519_set_reg);
  417. static DEVICE_ATTR(hwen, 0660, aw87519_get_hwen, aw87519_set_hwen);
  418. static DEVICE_ATTR(update, 0660, aw87519_get_update, aw87519_set_update);
  419. static DEVICE_ATTR(mode, 0660, aw87519_get_mode, aw87519_set_mode);
  420. static struct attribute *aw87519_attributes[] = {
  421. &dev_attr_reg.attr,
  422. &dev_attr_hwen.attr,
  423. &dev_attr_update.attr,
  424. &dev_attr_mode.attr,
  425. NULL
  426. };
  427. static struct attribute_group aw87519_attribute_group = {
  428. .attrs = aw87519_attributes
  429. };
  430. /*****************************************************
  431. * device tree
  432. *****************************************************/
  433. static int aw87519_parse_dt(struct device *dev, struct device_node *np)
  434. {
  435. aw87519->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
  436. if (aw87519->reset_gpio >= 0) {
  437. dev_err(dev, "%s: reset gpio provided ok\n", __func__);
  438. } else {
  439. dev_err(dev, "%s: no reset gpio provided failed\n", __func__);
  440. return -1;
  441. }
  442. return 0;
  443. }
  444. int aw87519_hw_reset(struct aw87519 *aw87519)
  445. {
  446. if (aw87519 && gpio_is_valid(aw87519->reset_gpio)) {
  447. gpio_set_value_cansleep(aw87519->reset_gpio, 1);
  448. usleep_range(5000, 5500);
  449. gpio_set_value_cansleep(aw87519->reset_gpio, 0);
  450. usleep_range(2500, 3000);
  451. gpio_set_value_cansleep(aw87519->reset_gpio, 1);
  452. usleep_range(5000, 5500);
  453. aw87519->hwen_flag = 1;
  454. } else {
  455. aw87519->hwen_flag = 0;
  456. dev_err(&aw87519->i2c_client->dev, "%s: failed\n", __func__);
  457. }
  458. return 0;
  459. }
  460. /*****************************************************
  461. * check chip id
  462. *****************************************************/
  463. int aw87519_read_chipid(struct aw87519 *aw87519)
  464. {
  465. unsigned int cnt = 0;
  466. unsigned int retry_count = 1;
  467. int ret = -1;
  468. unsigned char reg_val = 0;
  469. retry:
  470. while (cnt < AW_READ_CHIPID_RETRIES) {
  471. aw87519_i2c_write(aw87519, 0x64, 0x2C);
  472. ret = aw87519_i2c_read(aw87519, REG_CHIPID, &reg_val);
  473. if (reg_val == AW87519_CHIPID) {
  474. return 0;
  475. }
  476. cnt++;
  477. usleep_range(2500, 3000);
  478. }
  479. if (retry_count > 0) {
  480. aw87519_hw_reset(aw87519);
  481. cnt = 0;
  482. retry_count--;
  483. goto retry;
  484. }
  485. return -EINVAL;
  486. }
  487. /*******************************************************************************
  488. * aw87519 i2c driver
  489. ******************************************************************************/
  490. static int aw87519_i2c_probe(struct i2c_client *client,
  491. const struct i2c_device_id *id)
  492. {
  493. struct device_node *np = client->dev.of_node;
  494. int ret = -1;
  495. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  496. dev_err(&client->dev, "%s: i2c check failed\n", __func__);
  497. ret = -ENODEV;
  498. goto exit_check_functionality_failed;
  499. }
  500. aw87519 =
  501. devm_kzalloc(&client->dev, sizeof(struct aw87519), GFP_KERNEL);
  502. if (aw87519 == NULL) {
  503. ret = -ENOMEM;
  504. goto exit_devm_kzalloc_failed;
  505. }
  506. aw87519->i2c_client = client;
  507. i2c_set_clientdata(client, aw87519);
  508. /* aw87519 rst */
  509. if (np) {
  510. ret = aw87519_parse_dt(&client->dev, np);
  511. if (ret) {
  512. dev_err(&client->dev,
  513. "%s: failed to parse device tree node\n",
  514. __func__);
  515. goto exit_gpio_get_failed;
  516. }
  517. } else {
  518. aw87519->reset_gpio = -1;
  519. }
  520. if (gpio_is_valid(aw87519->reset_gpio)) {
  521. ret = devm_gpio_request_one(&client->dev, aw87519->reset_gpio,
  522. GPIOF_OUT_INIT_LOW, "aw87519_rst");
  523. if (ret) {
  524. dev_err(&client->dev, "%s: rst request failed\n",
  525. __func__);
  526. goto exit_gpio_request_failed;
  527. }
  528. }
  529. /* hardware reset */
  530. aw87519_hw_reset(aw87519);
  531. /* aw87519 chip id */
  532. ret = aw87519_read_chipid(aw87519);
  533. if (ret < 0) {
  534. dev_err(&client->dev, "%s: aw87519_read_chipid failed %d\n",
  535. __func__, ret);
  536. goto exit_i2c_check_id_failed;
  537. }
  538. ret = sysfs_create_group(&client->dev.kobj, &aw87519_attribute_group);
  539. if (ret < 0) {
  540. dev_info(&client->dev, "%s error creating sysfs attr files\n",
  541. __func__);
  542. }
  543. /* aw87519 cfg update */
  544. aw87519->spk_cfg_update_flag = 0;
  545. aw87519->rcv_cfg_update_flag = 0;
  546. aw87519_cfg_init(aw87519);
  547. /* aw87519 hardware off */
  548. aw87519_hw_off(aw87519);
  549. return 0;
  550. exit_i2c_check_id_failed:
  551. exit_gpio_request_failed:
  552. exit_gpio_get_failed:
  553. devm_kfree(&client->dev, aw87519);
  554. aw87519 = NULL;
  555. exit_devm_kzalloc_failed:
  556. exit_check_functionality_failed:
  557. return ret;
  558. }
  559. static int aw87519_i2c_remove(struct i2c_client *client)
  560. {
  561. struct aw87519 *aw87519 = i2c_get_clientdata(client);
  562. if (gpio_is_valid(aw87519->reset_gpio))
  563. devm_gpio_free(&client->dev, aw87519->reset_gpio);
  564. return 0;
  565. }
  566. static const struct i2c_device_id aw87519_i2c_id[] = {
  567. { AW87519_I2C_NAME, 0 },
  568. { }
  569. };
  570. static const struct of_device_id extpa_of_match[] = {
  571. {.compatible = "awinic,aw87519_pa"},
  572. {},
  573. };
  574. static struct i2c_driver aw87519_i2c_driver = {
  575. .driver = {
  576. .owner = THIS_MODULE,
  577. .name = AW87519_I2C_NAME,
  578. .of_match_table = extpa_of_match,
  579. },
  580. .probe = aw87519_i2c_probe,
  581. .remove = aw87519_i2c_remove,
  582. .id_table = aw87519_i2c_id,
  583. };
  584. static int __init aw87519_pa_init(void)
  585. {
  586. int ret;
  587. ret = i2c_add_driver(&aw87519_i2c_driver);
  588. if (ret) {
  589. pr_info("%s Unable to register driver (%d)\n", __func__, ret);
  590. return ret;
  591. }
  592. return 0;
  593. }
  594. static void __exit aw87519_pa_exit(void)
  595. {
  596. pr_info("%s enter\n", __func__);
  597. i2c_del_driver(&aw87519_i2c_driver);
  598. }
  599. late_initcall(aw87519_pa_init);
  600. module_exit(aw87519_pa_exit);
  601. MODULE_DESCRIPTION("AWINIC AW87519 PA driver");
  602. MODULE_LICENSE("GPL v2");