jznomoney

spi_aic3254.c

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