Advertisement
jznomoney

Untitled

Mar 27th, 2011
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.11 KB | None | 0 0
  1. /* linux/driver/spi/spi_aic3254.c
  2. *
  3. *
  4. * Copyright (C) 2009 HTC Corporation.
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16.  
  17. #include <linux/kernel.h>
  18. #include <linux/init.h>
  19. #include <linux/miscdevice.h>
  20. #include <linux/fs.h>
  21. #include <linux/uaccess.h>
  22. #include <linux/spi/spi.h>
  23. #include <linux/spi/spi_aic3254.h>
  24. #include <linux/spi/spi_aic3254_reg.h>
  25. #include <linux/delay.h>
  26. #include <linux/clk.h>
  27. #include <linux/wakelock.h>
  28.  
  29. static struct spi_device *codec_dev;
  30. static struct mutex lock;
  31. static int aic3254_opend;
  32. static struct _CODEC_SPI_CMD **aic3254_uplink;
  33. static struct _CODEC_SPI_CMD **aic3254_downlink;
  34. static struct _CODEC_SPI_CMD **aic3254_minidsp;
  35. static int suspend_flag;
  36. static int aic3254_rx_mode;
  37. static int aic3254_tx_mode;
  38. static struct aic3254_ctl_ops default_ctl_ops;
  39. static struct aic3254_ctl_ops *ctl_ops = &default_ctl_ops;
  40.  
  41. struct ecodec_aic3254_state {
  42. int enabled;
  43. struct clk *rx_mclk;
  44. struct clk *rx_sclk;
  45. struct wake_lock idlelock;
  46. };
  47. static struct ecodec_aic3254_state codec_clk;
  48.  
  49. /* function prototype */
  50. int route_tx_enable(int, int);
  51. int route_rx_enable(int, int);
  52.  
  53. void aic3254_register_ctl_ops(struct aic3254_ctl_ops *ops)
  54. {
  55. ctl_ops = ops;
  56. }
  57.  
  58. static int codec_spi_write(unsigned char addr, unsigned char data)
  59. {
  60. unsigned char buffer[2];
  61. int rc;
  62.  
  63. if (!codec_dev)
  64. return 0;
  65.  
  66. codec_dev->bits_per_word = 16;
  67. buffer[0] = addr << 1;
  68. buffer[1] = data;
  69. rc = spi_write(codec_dev, buffer, 2);
  70.  
  71. return 1;
  72. }
  73.  
  74. static int codec_spi_read(unsigned char addr, unsigned char *data)
  75. {
  76. int rc;
  77. u8 buffer[2] = {0, 0};
  78. u8 result[2] = {0, 0};
  79.  
  80. codec_dev->bits_per_word = 16;
  81. buffer[0] = addr << 1 | 1;
  82. rc = spi_write_and_read(codec_dev, buffer, result, 2);
  83. if (rc < 0)
  84. return rc;
  85.  
  86. *data = result[1];
  87. return 0;
  88. }
  89.  
  90. static int aic3254_config(CODEC_SPI_CMD *cmds, int size)
  91. {
  92. int i, retry, ret;
  93. unsigned char data;
  94.  
  95. if (!codec_dev) {
  96. pr_err("%s: no spi device\n", __func__);
  97. return -EFAULT;
  98. }
  99.  
  100. if (cmds == NULL) {
  101. pr_err("%s: invalid spi parameters\n", __func__);
  102. return -EINVAL;
  103. } else
  104. pr_info("%s: size = %d\n", __func__, size);
  105.  
  106. /* when LCM power is off, spi transmission would fail sometime */
  107. if (suspend_flag && ctl_ops->panel_sleep_in) {
  108. ret = ctl_ops->panel_sleep_in();
  109. suspend_flag = 0;
  110. if (ret < 0)
  111. pr_err("%s: cannot make panel awake,"
  112. "it might failed on transmit SPI command\n"
  113. , __func__);
  114. else
  115. pr_info("%s: success on invoking panel_sleep_in\n"
  116. , __func__);
  117. }
  118.  
  119.  
  120. for (i = 0; i < size; i++) {
  121. switch (cmds[i].act) {
  122. case 'w':
  123. codec_spi_write(cmds[i].reg, cmds[i].data);
  124. break;
  125. case 'r':
  126. for (retry = AIC3254_MAX_RETRY; retry > 0; retry--) {
  127. ret = codec_spi_read(cmds[i].reg, &data);
  128. if (ret < 0)
  129. pr_err("%s: read fail %d, retry\n",
  130. __func__, ret);
  131. else if (data == cmds[i].data)
  132. break;
  133. hr_msleep(10);
  134. }
  135. if (retry <= 0)
  136. pr_err("%s: 3254 power down procedure"
  137. " ,flag 0x%02X=0x%02X(0x%02X)\n",
  138. __func__, cmds[i].reg,
  139. ret, cmds[i].data);
  140. break;
  141. case 'd':
  142. hr_msleep(cmds[i].data);
  143. break;
  144. default:
  145. break;
  146. }
  147. }
  148.  
  149. return 0;
  150. }
  151.  
  152. static int aic3254_config_ex(CODEC_SPI_CMD *cmds, int size)
  153. {
  154. int i = 0;
  155. int ret = -EINVAL;
  156. struct spi_transfer *spi_t_cmds = NULL;
  157. struct spi_message m;
  158. unsigned char *buffer = NULL;
  159. unsigned char *ptr = NULL;
  160.  
  161. if (!codec_dev) {
  162. pr_err("%s: no spi device\n", __func__);
  163. return -EFAULT;
  164. }
  165.  
  166. if (cmds == NULL || size == 0) {
  167. pr_err("%s: invalid spi parameters\n", __func__);
  168. return -EINVAL;
  169. } else {
  170. /* pr_info("%s: size = %d", __func__, size); */
  171. }
  172.  
  173. spi_t_cmds = (struct spi_transfer *) kmalloc(size*sizeof(struct spi_transfer), GFP_KERNEL);
  174. if (spi_t_cmds == NULL) {
  175. pr_err("%s: kmalloc spi transfer struct fail\n", __func__);
  176. goto error;
  177. } else
  178. memset(spi_t_cmds, 0, size*sizeof(struct spi_transfer));
  179.  
  180. buffer = (unsigned char *) kmalloc(size * 2 * sizeof(unsigned char), GFP_KERNEL);
  181. if (buffer == NULL) {
  182. pr_err("%s: kmalloc buffer fail\n", __func__);
  183. goto error;
  184. } else
  185. memset(buffer, 0, size*sizeof(CODEC_SPI_CMD)*sizeof(unsigned char));
  186.  
  187. spi_message_init(&m);
  188. for (i=0, ptr=buffer; i<size; i++, ptr+=2) {
  189. ptr[0] = cmds[i].reg << 1;
  190. ptr[1] = cmds[i].data;
  191.  
  192. spi_t_cmds[i].tx_buf = ptr;
  193. spi_t_cmds[i].len = 2;
  194. spi_message_add_tail(&spi_t_cmds[i], &m);
  195. }
  196. codec_dev->bits_per_word = 16;
  197. ret = spi_sync(codec_dev, &m);
  198.  
  199. error:
  200. if (buffer)
  201. kfree(buffer);
  202.  
  203. if (spi_t_cmds)
  204. kfree(spi_t_cmds);
  205. return ret;
  206. }
  207.  
  208. static void aic3254_tx_config(int mode)
  209. {
  210. /* use default setting when tx table doesn't be updated*/
  211. if (aic3254_uplink == NULL) {
  212. if (mode == UPLINK_OFF)
  213. route_tx_enable(mode, 0);
  214. else
  215. route_tx_enable(mode, 1);
  216. return;
  217. }
  218.  
  219. if (mode != UPLINK_OFF && mode != POWER_OFF) {
  220. /* uplink_Wakeup */
  221. aic3254_config(
  222. &aic3254_uplink[UPLINK_WAKEUP][1],
  223. aic3254_uplink[UPLINK_WAKEUP][0].data);
  224. }
  225.  
  226. /* route tx device */
  227. aic3254_config(&aic3254_uplink[mode][1],
  228. aic3254_uplink[mode][0].data);
  229. }
  230.  
  231. static void aic3254_rx_config(int mode)
  232. {
  233. /* use default setting when rx table doesn't be updated*/
  234. if (aic3254_downlink == NULL) {
  235. if (mode == DOWNLINK_OFF)
  236. route_rx_enable(mode, 0);
  237. else
  238. route_rx_enable(mode, 1);
  239. return;
  240. }
  241.  
  242. if (mode != DOWNLINK_OFF && mode != POWER_OFF) {
  243. /* Downlink Wakeup */
  244. aic3254_config(
  245. &aic3254_downlink[DOWNLINK_WAKEUP][1],
  246. aic3254_downlink[DOWNLINK_WAKEUP][0].data);
  247. }
  248.  
  249. /* route rx device */
  250. aic3254_config(&aic3254_downlink[mode][1],
  251. aic3254_downlink[mode][0].data);
  252. }
  253.  
  254. static void aic3254_powerdown(void)
  255. {
  256. struct ecodec_aic3254_state *drv = &codec_clk;
  257. if (aic3254_tx_mode != UPLINK_OFF || aic3254_rx_mode != DOWNLINK_OFF)
  258. return;
  259.  
  260. pr_info("%s: power off AIC3254\n", __func__);
  261. wake_lock(&drv->idlelock);
  262. if (aic3254_uplink != NULL)
  263. aic3254_config(&aic3254_uplink[POWER_OFF][1],
  264. aic3254_uplink[POWER_OFF][0].data);
  265. else
  266. aic3254_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF));
  267.  
  268. if (drv->enabled) {
  269. /* Disable MI2S RX master block */
  270. /* Disable MI2S RX bit clock */
  271. clk_disable(drv->rx_sclk);
  272. clk_disable(drv->rx_mclk);
  273. drv->enabled = 0;
  274. printk("%s: disable CLK\n", __func__);
  275. }
  276. wake_unlock(&drv->idlelock);
  277. return;
  278. }
  279. static void aic3254_loopback(int mode)
  280. {
  281. if (!(ctl_ops->lb_dsp_init &&
  282. ctl_ops->lb_receiver_imic &&
  283. ctl_ops->lb_speaker_imic &&
  284. ctl_ops->lb_headset_emic)) {
  285. pr_info("%s: AIC3254 LOOPBACK not supported\n", __func__);
  286. return;
  287. }
  288.  
  289. /* Init AIC3254 A00 */
  290. aic3254_config(ctl_ops->lb_dsp_init->data, ctl_ops->lb_dsp_init->len);
  291.  
  292. pr_info("%s: set AIC3254 in LOOPBACK mode\n", __func__);
  293. switch (mode) {
  294. case 0:
  295. /* receiver v.s. imic */
  296. aic3254_config(ctl_ops->lb_receiver_imic->data,
  297. ctl_ops->lb_receiver_imic->len);
  298. break;
  299. case 1:
  300. /* speaker v.s. imic */
  301. aic3254_config(ctl_ops->lb_speaker_imic->data,
  302. ctl_ops->lb_speaker_imic->len);
  303. break;
  304. case 2:
  305. /* headphone v.s emic */
  306. aic3254_config(ctl_ops->lb_headset_emic->data,
  307. ctl_ops->lb_headset_emic->len);
  308. case 13:
  309. /* headphone v.s 2nd mic */
  310. if (ctl_ops->lb_headset_bmic)
  311. aic3254_config(ctl_ops->lb_headset_bmic->data,
  312. ctl_ops->lb_headset_bmic->len);
  313. else
  314. pr_info("%s: 2nd mic loopback not supported\n", __func__);
  315. break;
  316. }
  317. }
  318.  
  319. int route_rx_enable(int path, int en)
  320. {
  321. pr_info("%s: (%d,%d) uses 3254 default setting\n", __func__, path, en);
  322. if (en) {
  323. /* Downlink_Wakeup */
  324. aic3254_config(CODEC_DOWNLINK_ON,
  325. ARRAY_SIZE(CODEC_DOWNLINK_ON));
  326. /* Path switching */
  327. switch (path) {
  328. case FM_OUT_HEADSET:
  329. /* FM headset */
  330. aic3254_config(FM_In_Headphone,
  331. ARRAY_SIZE(FM_In_Headphone));
  332. aic3254_config(FM_Out_Headphone,
  333. ARRAY_SIZE(FM_Out_Headphone));
  334. break;
  335. case FM_OUT_SPEAKER:
  336. /* FM speaker */
  337. aic3254_config(FM_In_SPK,
  338. ARRAY_SIZE(FM_In_SPK));
  339. aic3254_config(FM_Out_SPK,
  340. ARRAY_SIZE(FM_Out_SPK));
  341. break;
  342. default:
  343. /* By pass */
  344. aic3254_config(Downlink_IMIC_Receiver,
  345. ARRAY_SIZE(Downlink_IMIC_Receiver));
  346. break;
  347. }
  348. } else {
  349. /* Downlink_Off */
  350. aic3254_config(CODEC_DOWNLINK_OFF,
  351. ARRAY_SIZE(CODEC_DOWNLINK_OFF));
  352. }
  353.  
  354. return 0;
  355. }
  356.  
  357. int route_tx_enable(int path, int en)
  358. {
  359. pr_info("%s: (%d,%d) uses 3254 default setting\n", __func__, path, en);
  360. if (en) {
  361. /* Uplink_Wakeup */
  362. aic3254_config(CODEC_UPLINK_ON, ARRAY_SIZE(CODEC_UPLINK_ON));
  363. /* Path switching */
  364. switch (path) {
  365. case CALL_UPLINK_IMIC_RECEIVER:
  366. case CALL_UPLINK_IMIC_HEADSET:
  367. case CALL_UPLINK_IMIC_SPEAKER:
  368. case VOICERECORD_IMIC:
  369. /* By pass */
  370. aic3254_config(MECHA_Uplink_IMIC,
  371. ARRAY_SIZE(MECHA_Uplink_IMIC));
  372. break;
  373. case CALL_UPLINK_EMIC_HEADSET:
  374. case VOICERECORD_EMIC:
  375. aic3254_config(Uplink_EMIC,
  376. ARRAY_SIZE(Uplink_EMIC));
  377. break;
  378. }
  379. } else {
  380. /* Uplink_Off */
  381. aic3254_config(CODEC_UPLINK_OFF, ARRAY_SIZE(CODEC_UPLINK_OFF));
  382. }
  383.  
  384. return 0;
  385. }
  386.  
  387.  
  388. void aic3254_set_mic_bias(int en) {
  389.  
  390. if (en)
  391. aic3254_config(CODEC_MICBIAS_ON, ARRAY_SIZE(CODEC_MICBIAS_ON));
  392. else
  393. aic3254_config(CODEC_MICBIAS_OFF, ARRAY_SIZE(CODEC_MICBIAS_OFF));
  394. }
  395.  
  396. static int aic3254_set_config(int config_tbl, int idx, int en)
  397. {
  398. int len;
  399. struct ecodec_aic3254_state *drv = &codec_clk;
  400. pr_info("%s: table(0x%X) index(%d)\n", __func__, config_tbl, idx);
  401.  
  402. wake_lock(&drv->idlelock);
  403.  
  404. if (drv->enabled == 0) {
  405. /* enable MI2S RX master block */
  406. /* enable MI2S RX bit clock */
  407. clk_enable(drv->rx_mclk);
  408. clk_enable(drv->rx_sclk);
  409. printk("%s: enable CLK\n", __func__);
  410. drv->enabled = 1;
  411. }
  412.  
  413. switch (config_tbl) {
  414. case AIC3254_CONFIG_TX:
  415. /* TX */
  416. pr_info("%s: enable tx\n", __func__);
  417. if (en) {
  418. if (ctl_ops->tx_amp_enable)
  419. ctl_ops->tx_amp_enable(0);
  420.  
  421. aic3254_tx_config(idx);
  422. aic3254_tx_mode = idx;
  423.  
  424. if (ctl_ops->tx_amp_enable)
  425. ctl_ops->tx_amp_enable(1);
  426. } else {
  427. aic3254_tx_config(UPLINK_OFF);
  428. aic3254_tx_mode = UPLINK_OFF;
  429. pr_info("%s: disable tx\n", __func__);
  430. if(ctl_ops->tx_amp_enable)
  431. ctl_ops->tx_amp_enable(0);
  432. aic3254_powerdown();
  433. }
  434. break;
  435. case AIC3254_CONFIG_RX:
  436. /* RX */
  437. pr_info("%s: enable rx\n", __func__);
  438. if (en) {
  439. if (ctl_ops->rx_amp_enable)
  440. ctl_ops->rx_amp_enable(0);
  441.  
  442. aic3254_rx_config(idx);
  443. aic3254_rx_mode = idx;
  444.  
  445. if (ctl_ops->rx_amp_enable)
  446. ctl_ops->rx_amp_enable(1);
  447. } else {
  448. aic3254_rx_config(DOWNLINK_OFF);
  449. aic3254_rx_mode = DOWNLINK_OFF;
  450. pr_info("%s: disable rx\n", __func__);
  451. if(ctl_ops->rx_amp_enable)
  452. ctl_ops->rx_amp_enable(0);
  453. aic3254_powerdown();
  454. }
  455. break;
  456. case AIC3254_CONFIG_MEDIA:
  457. if (aic3254_minidsp == NULL)
  458. return -EFAULT;
  459. len = (aic3254_minidsp[idx][0].reg << 8)
  460. | aic3254_minidsp[idx][0].data;
  461.  
  462. pr_info("%s: miniDSP command len = %d\n", __func__, len);
  463. pr_info("%s: rx mode %d, tx mode %d\n",
  464. __func__, aic3254_rx_mode, aic3254_tx_mode);
  465.  
  466. if (ctl_ops->rx_amp_enable)
  467. ctl_ops->rx_amp_enable(0);
  468.  
  469. /* step 1: power off first */
  470. if (aic3254_rx_mode != DOWNLINK_OFF)
  471. aic3254_rx_config(DOWNLINK_OFF);
  472.  
  473. /* step 2: config DSP */
  474. aic3254_config(&aic3254_minidsp[idx][1], len);
  475.  
  476. /* step 3: switch back to original path */
  477. if (aic3254_rx_mode != DOWNLINK_OFF)
  478. aic3254_rx_config(aic3254_rx_mode);
  479. if (aic3254_tx_mode != UPLINK_OFF)
  480. aic3254_tx_config(aic3254_tx_mode);
  481.  
  482. if (ctl_ops->rx_amp_enable)
  483. ctl_ops->rx_amp_enable(1);
  484.  
  485. pr_info("%s: configure minidsp done\n", __func__);
  486. break;
  487. }
  488.  
  489. wake_unlock(&drv->idlelock);
  490. return 0;
  491. }
  492.  
  493. static int aic3254_open(struct inode *inode, struct file *pfile)
  494. {
  495. int ret = 0;
  496.  
  497. mutex_lock(&lock);
  498. if (aic3254_opend) {
  499. pr_err("%s: busy\n", __func__);
  500. ret = -EBUSY;
  501. } else
  502. aic3254_opend = 1;
  503. mutex_unlock(&lock);
  504.  
  505. return ret;
  506. }
  507.  
  508. static int aic3254_release(struct inode *inode, struct file *pfile)
  509. {
  510. mutex_lock(&lock);
  511. aic3254_opend = 0;
  512. mutex_unlock(&lock);
  513.  
  514. return 0;
  515. }
  516.  
  517. static int aic3254_ioctl(struct inode *inode, struct file *file,
  518. unsigned int cmd, unsigned long argc)
  519. {
  520. struct AIC3254_PARAM para;
  521. void *table;
  522. int ret = 0, i = 0, mem_size, volume = 0;
  523. CODEC_SPI_CMD reg[2];
  524. unsigned char data;
  525.  
  526. switch (cmd) {
  527. case AIC3254_SET_TX_PARAM:
  528. case AIC3254_SET_RX_PARAM:
  529. if (copy_from_user(&para, (void *)argc, sizeof(para))) {
  530. pr_err("%s: failed on copy_from_user\n", __func__);
  531. return -EFAULT;
  532. }
  533.  
  534. pr_info("%s: parameters(%d, %d, %p)\n", __func__,
  535. para.row_num, para.col_num, para.cmd_data);
  536. if (cmd == AIC3254_SET_TX_PARAM)
  537. table = aic3254_uplink[0];
  538. else
  539. table = aic3254_downlink[0];
  540.  
  541. /* confirm indicated size doesn't exceed the allocated one */
  542. if (para.row_num > IO_CTL_ROW_MAX
  543. || para.col_num != IO_CTL_COL_MAX) {
  544. pr_err("%s: data size mismatch with allocated"
  545. " memory (%d,%d)\n", __func__,
  546. IO_CTL_ROW_MAX, IO_CTL_COL_MAX);
  547. return -EFAULT;
  548. }
  549.  
  550. mem_size = para.row_num * para.col_num * sizeof(CODEC_SPI_CMD);
  551. if (copy_from_user(table, para.cmd_data, mem_size)) {
  552. pr_err("%s: failed on copy_from_user\n", __func__);
  553. return -EFAULT;
  554. }
  555.  
  556. /* invoking initialization procedure of AIC3254 */
  557. if (cmd == AIC3254_SET_TX_PARAM)
  558. aic3254_tx_config(INITIAL);
  559.  
  560. pr_info("%s: update table(%d,%d) successfully\n",
  561. __func__, para.row_num, para.col_num);
  562. break;
  563. case AIC3254_SET_DSP_PARAM:
  564. if (copy_from_user(&para, (void *)argc, sizeof(para))) {
  565. pr_err("%s: failed on copy_from_user\n", __func__);
  566. return -EFAULT;
  567. }
  568. pr_info("%s: parameters(%d, %d, %p)\n", __func__,
  569. para.row_num, para.col_num, para.cmd_data);
  570.  
  571. table = aic3254_minidsp[0];
  572.  
  573. /* confirm indicated size doesn't exceed the allocated one */
  574. if (para.row_num > MINIDSP_ROW_MAX
  575. || para.col_num != MINIDSP_COL_MAX) {
  576. pr_err("%s: data size mismatch with allocated"
  577. " memory (%d,%d)\n", __func__,
  578. MINIDSP_ROW_MAX, MINIDSP_COL_MAX);
  579. return -EFAULT;
  580. }
  581.  
  582. mem_size = para.row_num * para.col_num * sizeof(CODEC_SPI_CMD);
  583. if (copy_from_user(table, para.cmd_data, mem_size)) {
  584. pr_err("%s: failed on copy_from_user\n", __func__);
  585. return -EFAULT;
  586. }
  587.  
  588. pr_info("%s: update table(%d,%d) successfully\n",
  589. __func__, para.row_num, para.col_num);
  590. break;
  591. case AIC3254_CONFIG_TX:
  592. case AIC3254_CONFIG_RX:
  593. case AIC3254_CONFIG_MEDIA:
  594. if (copy_from_user(&i, (void *)argc, sizeof(int))) {
  595. pr_err("%s: failed on copy_from_user\n", __func__);
  596. return -EFAULT;
  597. }
  598. pr_info("%s: index %d for %X\n", __func__, i, cmd);
  599. ret = aic3254_set_config(cmd, i, 1);
  600. if (ret < 0)
  601. pr_err("%s: configure(%d) error %d\n",
  602. __func__, i, ret);
  603. break;
  604. case AIC3254_CONFIG_VOLUME_L:
  605. if (copy_from_user(&volume, (void *)argc, sizeof(int))) {
  606. pr_err("%s: failed on copy_from_user\n", __func__);
  607. return -EFAULT;
  608. }
  609.  
  610. if (volume < -127 || volume > 48) {
  611. pr_err("%s: volume out of range\n", __func__);
  612. return -EFAULT;
  613. }
  614.  
  615. pr_info("%s: AIC3254 config left volume %d\n",
  616. __func__, volume);
  617.  
  618. CODEC_SET_VOLUME_L[1].data = volume;
  619. aic3254_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L));
  620. break;
  621. case AIC3254_CONFIG_VOLUME_R:
  622. if (copy_from_user(&volume, (void *)argc, sizeof(int))) {
  623. pr_err("%s: failed on copy_from_user\n", __func__);
  624. return -EFAULT;
  625. }
  626.  
  627. if (volume < -127 || volume > 48) {
  628. pr_err("%s: volume out of range\n", __func__);
  629. return -EFAULT;
  630. }
  631.  
  632. pr_info("%s: AIC3254 config right volume %d\n",
  633. __func__, volume);
  634.  
  635. CODEC_SET_VOLUME_R[1].data = volume;
  636. aic3254_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R));
  637. break;
  638. case AIC3254_DUMP_PAGES:
  639. if (copy_from_user(&i, (void *)argc, sizeof(int))) {
  640. pr_err("%s: failed on copy_from_user\n", __func__);
  641. return -EFAULT;
  642. }
  643. if (i > AIC3254_MAX_PAGES) {
  644. pr_err("%s: invalid page number %d\n", __func__, i);
  645. return -EINVAL;
  646. }
  647.  
  648. pr_info("========== %s: dump page %d ==========\n",
  649. __func__, i);
  650. /* indicated page number to AIC3254 */
  651. codec_spi_write(0x00, i);
  652. for (i = 0; i < AIC3254_MAX_REGS; i++) {
  653. ret = codec_spi_read(i, &data);
  654. if (ret < 0)
  655. pr_err("read fail on register 0x%X\n", i);
  656. else
  657. pr_info("(0x%02X, 0x%02X)\n", i, data);
  658. }
  659. pr_info("=============================================\n");
  660. break;
  661. case AIC3254_WRITE_REG:
  662. if (copy_from_user(&reg, (void *)argc,
  663. sizeof(CODEC_SPI_CMD)*2)) {
  664. pr_err("%s: failed on copy_from_user\n", __func__);
  665. return -EFAULT;
  666. }
  667. pr_info("%s: command list (%c,%02X,%02X) (%c,%02X,%02X)\n",
  668. __func__, reg[0].act, reg[0].reg, reg[0].data,
  669. reg[1].act, reg[1].reg, reg[1].data);
  670. aic3254_config_ex(reg, 2);
  671. break;
  672. case AIC3254_READ_REG:
  673. if (copy_from_user(&reg, (void *)argc,
  674. sizeof(CODEC_SPI_CMD)*2)) {
  675. pr_err("%s: failed on copy_from_user\n", __func__);
  676. return -EFAULT;
  677. }
  678. for (i = 0; i < 2; i++) {
  679. if (reg[i].act == 'r' || reg[i].act == 'R')
  680. codec_spi_read(reg[i].reg, &reg[i].data);
  681. else if (reg[i].act == 'w' || reg[i].act == 'W')
  682. codec_spi_write(reg[i].reg, reg[i].data);
  683. else
  684. return -EINVAL;
  685. }
  686. if (copy_to_user((void *)argc, &reg, sizeof(CODEC_SPI_CMD)*2)) {
  687. pr_err("%s: failed on copy_to_user\n", __func__);
  688. return -EFAULT;
  689. }
  690. break;
  691. case AIC3254_POWERDOWN:
  692. aic3254_powerdown();
  693. break;
  694. case AIC3254_LOOPBACK:
  695. if (copy_from_user(&i, (void *)argc, sizeof(int))) {
  696. pr_err("%s: failed on copy_from_user\n", __func__);
  697. return -EFAULT;
  698. }
  699. pr_info("%s: index %d for LOOPBACK\n", __func__, i);
  700. aic3254_loopback(i);
  701. break;
  702. default:
  703. pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd));
  704. ret = -EINVAL;
  705. }
  706.  
  707. return ret;
  708. }
  709.  
  710. static const struct file_operations aic3254_fops = {
  711. .owner = THIS_MODULE,
  712. .open = aic3254_open,
  713. .release = aic3254_release,
  714. .ioctl = aic3254_ioctl,
  715. };
  716.  
  717. static struct miscdevice aic3254_misc = {
  718. .minor = MISC_DYNAMIC_MINOR,
  719. .name = "codec_aic3254",
  720. .fops = &aic3254_fops,
  721. };
  722.  
  723. static CODEC_SPI_CMD** init_2d_array(int row_sz, int col_sz)
  724. {
  725. CODEC_SPI_CMD *table = NULL;
  726. CODEC_SPI_CMD **table_ptr = NULL;
  727. int i = 0;
  728.  
  729. table_ptr = kzalloc(row_sz * sizeof(CODEC_SPI_CMD *), GFP_KERNEL);
  730. table = kzalloc(row_sz * col_sz * sizeof(CODEC_SPI_CMD), GFP_KERNEL);
  731. if (table_ptr == NULL || table == NULL) {
  732. pr_err("%s: out of memory\n", __func__);
  733. kfree(table);
  734. kfree(table_ptr);
  735. } else
  736. for (i = 0; i < row_sz; i++)
  737. table_ptr[i] = (CODEC_SPI_CMD *)table + i * col_sz;
  738.  
  739. return table_ptr;
  740. }
  741.  
  742. static int spi_aic3254_probe(struct spi_device *aic3254)
  743. {
  744. pr_info("%s\n", __func__);
  745.  
  746. codec_dev = aic3254;
  747.  
  748. /* Boot up */
  749. #if 0
  750. aic3254_config(CODEC_INIT_REG, ARRAY_SIZE(CODEC_INIT_REG));
  751. aic3254_config(CODEC_DOWNLINK_OFF, ARRAY_SIZE(CODEC_DOWNLINK_OFF));
  752. aic3254_config(CODEC_UPLINK_OFF, ARRAY_SIZE(CODEC_UPLINK_OFF));
  753. aic3254_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF));
  754. #endif
  755.  
  756. aic3254_tx_mode = UPLINK_OFF;
  757. aic3254_rx_mode = DOWNLINK_OFF;
  758.  
  759. /* request space for firmware data of AIC3254 */
  760. aic3254_uplink = init_2d_array(IO_CTL_ROW_MAX, IO_CTL_COL_MAX);
  761. aic3254_downlink = init_2d_array(IO_CTL_ROW_MAX, IO_CTL_COL_MAX);
  762. aic3254_minidsp = init_2d_array(MINIDSP_ROW_MAX, MINIDSP_COL_MAX);
  763. return 0;
  764. }
  765.  
  766.  
  767. static int spi_aic3254_suspend(struct spi_device *aic3254, pm_message_t pmsg)
  768. {
  769. pr_info("%s\n", __func__);
  770. suspend_flag = 1;
  771. return 0;
  772. }
  773.  
  774. static int spi_aic3254_resume(struct spi_device *aic3254)
  775. {
  776. pr_info("%s\n", __func__);
  777. return 0;
  778. }
  779.  
  780. static int spi_aic3254_remove(struct spi_device *aic3254)
  781. {
  782. pr_info("%s\n", __func__);
  783.  
  784. /* release allocated memory in this driver */
  785. if (aic3254_uplink != NULL) {
  786. kfree(aic3254_uplink[0]);
  787. kfree(aic3254_uplink);
  788. aic3254_uplink = NULL;
  789. }
  790. if (aic3254_downlink != NULL) {
  791. kfree(aic3254_downlink[0]);
  792. kfree(aic3254_downlink);
  793. aic3254_downlink = NULL;
  794. }
  795. if (aic3254_minidsp != NULL) {
  796. kfree(aic3254_minidsp[0]);
  797. kfree(aic3254_minidsp);
  798. aic3254_minidsp = NULL;
  799. }
  800.  
  801. return 0;
  802. }
  803.  
  804. static struct spi_driver spi_aic3254 = {
  805. .driver = {
  806. .name = "spi_aic3254",
  807. .owner = THIS_MODULE,
  808. },
  809. .probe = spi_aic3254_probe,
  810. .suspend = spi_aic3254_suspend,
  811. .resume = spi_aic3254_resume,
  812. .remove = spi_aic3254_remove,
  813. };
  814.  
  815. static int __init spi_aic3254_init(void)
  816. {
  817. int ret = 0;
  818. struct ecodec_aic3254_state *codec_drv = &codec_clk;
  819.  
  820. pr_info("%s\n", __func__);
  821. mutex_init(&lock);
  822.  
  823. ret = spi_register_driver(&spi_aic3254);
  824. if (ret < 0) {
  825. pr_err("%s:failed to register spi driver(%d)\n", __func__, ret);
  826. return ret;
  827. }
  828.  
  829. ret = misc_register(&aic3254_misc);
  830. if (ret < 0) {
  831. pr_err("%s:failed to register misc device\n", __func__);
  832. spi_unregister_driver(&spi_aic3254);
  833. return ret;
  834. }
  835.  
  836. codec_drv->rx_mclk = clk_get(NULL, "mi2s_codec_rx_m_clk");
  837. if (IS_ERR(codec_drv->rx_mclk)) {
  838. pr_err("%s:failed to get mi2s mclk\n", __func__);
  839. misc_deregister(&aic3254_misc);
  840. spi_unregister_driver(&spi_aic3254);
  841. return -ENODEV;
  842. }
  843. codec_drv->rx_sclk = clk_get(NULL, "mi2s_codec_rx_s_clk");
  844. if (IS_ERR(codec_drv->rx_sclk)) {
  845. pr_err("%s:failed to get mi2s sclk\n", __func__);
  846. misc_deregister(&aic3254_misc);
  847. spi_unregister_driver(&spi_aic3254);
  848. clk_put(codec_drv->rx_mclk);
  849. return -ENODEV;
  850. }
  851.  
  852. wake_lock_init(&codec_drv->idlelock, WAKE_LOCK_IDLE,
  853. "aic3254_lock");
  854.  
  855. return 0;
  856. }
  857. module_init(spi_aic3254_init);
  858.  
  859. static void __exit spi_aic3254_exit(void)
  860. {
  861. struct ecodec_aic3254_state *codec_drv = &codec_clk;
  862.  
  863. spi_unregister_driver(&spi_aic3254);
  864. misc_deregister(&aic3254_misc);
  865.  
  866. clk_put(codec_drv->rx_mclk);
  867. clk_put(codec_drv->rx_sclk);
  868. return;
  869. }
  870. module_exit(spi_aic3254_exit);
  871.  
  872. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement