Advertisement
jznomoney

diff

Mar 27th, 2011
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.58 KB | None | 0 0
  1. diff --git a/drivers/spi/spi_aic3254.c b/drivers/spi/spi_aic3254.c
  2. index 1ac1b9f..dca3758 100644
  3. --- a/drivers/spi/spi_aic3254.c
  4. +++ b/drivers/spi/spi_aic3254.c
  5. @@ -23,6 +23,8 @@
  6. #include <linux/spi/spi_aic3254.h>
  7. #include <linux/spi/spi_aic3254_reg.h>
  8. #include <linux/delay.h>
  9. +#include <linux/clk.h>
  10. +#include <linux/wakelock.h>
  11.  
  12. static struct spi_device *codec_dev;
  13. static struct mutex lock;
  14. @@ -36,6 +38,14 @@ static int aic3254_tx_mode;
  15. static struct aic3254_ctl_ops default_ctl_ops;
  16. static struct aic3254_ctl_ops *ctl_ops = &default_ctl_ops;
  17.  
  18. +struct ecodec_aic3254_state {
  19. + int enabled;
  20. + struct clk *rx_mclk;
  21. + struct clk *rx_sclk;
  22. + struct wake_lock idlelock;
  23. +};
  24. +static struct ecodec_aic3254_state codec_clk;
  25. +
  26. /* function prototype */
  27. int route_tx_enable(int, int);
  28. int route_rx_enable(int, int);
  29. @@ -61,7 +71,7 @@ static int codec_spi_write(unsigned char addr, unsigned char data)
  30. return 1;
  31. }
  32.  
  33. -static int codec_spi_read(unsigned char addr)
  34. +static int codec_spi_read(unsigned char addr, unsigned char *data)
  35. {
  36. int rc;
  37. u8 buffer[2] = {0, 0};
  38. @@ -73,13 +83,14 @@ static int codec_spi_read(unsigned char addr)
  39. if (rc < 0)
  40. return rc;
  41.  
  42. - return result[1];
  43. + *data = result[1];
  44. + return 0;
  45. }
  46.  
  47. static int aic3254_config(CODEC_SPI_CMD *cmds, int size)
  48. {
  49. - int i, retry;
  50. - unsigned char ret = 0;
  51. + int i, retry, ret;
  52. + unsigned char data;
  53.  
  54. if (!codec_dev) {
  55. pr_err("%s: no spi device\n", __func__);
  56. @@ -113,8 +124,11 @@ static int aic3254_config(CODEC_SPI_CMD *cmds, int size)
  57. break;
  58. case 'r':
  59. for (retry = AIC3254_MAX_RETRY; retry > 0; retry--) {
  60. - ret = codec_spi_read(cmds[i].reg);
  61. - if (ret == cmds[i].data)
  62. + ret = codec_spi_read(cmds[i].reg, &data);
  63. + if (ret < 0)
  64. + pr_err("%s: read fail %d, retry\n",
  65. + __func__, ret);
  66. + else if (data == cmds[i].data)
  67. break;
  68. hr_msleep(10);
  69. }
  70. @@ -239,15 +253,67 @@ static void aic3254_rx_config(int mode)
  71.  
  72. static void aic3254_powerdown(void)
  73. {
  74. + struct ecodec_aic3254_state *drv = &codec_clk;
  75. if (aic3254_tx_mode != UPLINK_OFF || aic3254_rx_mode != DOWNLINK_OFF)
  76. return;
  77.  
  78. pr_info("%s: power off AIC3254\n", __func__);
  79. + wake_lock(&drv->idlelock);
  80. if (aic3254_uplink != NULL)
  81. aic3254_config(&aic3254_uplink[POWER_OFF][1],
  82. aic3254_uplink[POWER_OFF][0].data);
  83. else
  84. aic3254_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF));
  85. +
  86. + if (drv->enabled) {
  87. + /* Disable MI2S RX master block */
  88. + /* Disable MI2S RX bit clock */
  89. + clk_disable(drv->rx_sclk);
  90. + clk_disable(drv->rx_mclk);
  91. + drv->enabled = 0;
  92. + printk("%s: disable CLK\n", __func__);
  93. + }
  94. + wake_unlock(&drv->idlelock);
  95. + return;
  96. +}
  97. +static void aic3254_loopback(int mode)
  98. +{
  99. + if (!(ctl_ops->lb_dsp_init &&
  100. + ctl_ops->lb_receiver_imic &&
  101. + ctl_ops->lb_speaker_imic &&
  102. + ctl_ops->lb_headset_emic)) {
  103. + pr_info("%s: AIC3254 LOOPBACK not supported\n", __func__);
  104. + return;
  105. + }
  106. +
  107. + /* Init AIC3254 A00 */
  108. + aic3254_config(ctl_ops->lb_dsp_init->data, ctl_ops->lb_dsp_init->len);
  109. +
  110. + pr_info("%s: set AIC3254 in LOOPBACK mode\n", __func__);
  111. + switch (mode) {
  112. + case 0:
  113. + /* receiver v.s. imic */
  114. + aic3254_config(ctl_ops->lb_receiver_imic->data,
  115. + ctl_ops->lb_receiver_imic->len);
  116. + break;
  117. + case 1:
  118. + /* speaker v.s. imic */
  119. + aic3254_config(ctl_ops->lb_speaker_imic->data,
  120. + ctl_ops->lb_speaker_imic->len);
  121. + break;
  122. + case 2:
  123. + /* headphone v.s emic */
  124. + aic3254_config(ctl_ops->lb_headset_emic->data,
  125. + ctl_ops->lb_headset_emic->len);
  126. + case 13:
  127. + /* headphone v.s 2nd mic */
  128. + if (ctl_ops->lb_headset_bmic)
  129. + aic3254_config(ctl_ops->lb_headset_bmic->data,
  130. + ctl_ops->lb_headset_bmic->len);
  131. + else
  132. + pr_info("%s: 2nd mic loopback not supported\n", __func__);
  133. + break;
  134. + }
  135. }
  136.  
  137. int route_rx_enable(int path, int en)
  138. @@ -318,26 +384,42 @@ int route_tx_enable(int path, int en)
  139. return 0;
  140. }
  141.  
  142. +
  143. +void aic3254_set_mic_bias(int en) {
  144. +
  145. + if (en)
  146. + aic3254_config(CODEC_MICBIAS_ON, ARRAY_SIZE(CODEC_MICBIAS_ON));
  147. + else
  148. + aic3254_config(CODEC_MICBIAS_OFF, ARRAY_SIZE(CODEC_MICBIAS_OFF));
  149. +}
  150. +
  151. static int aic3254_set_config(int config_tbl, int idx, int en)
  152. {
  153. int len;
  154. + struct ecodec_aic3254_state *drv = &codec_clk;
  155. pr_info("%s: table(0x%X) index(%d)\n", __func__, config_tbl, idx);
  156.  
  157. + wake_lock(&drv->idlelock);
  158. +
  159. + if (drv->enabled == 0) {
  160. + /* enable MI2S RX master block */
  161. + /* enable MI2S RX bit clock */
  162. + clk_enable(drv->rx_mclk);
  163. + clk_enable(drv->rx_sclk);
  164. + printk("%s: enable CLK\n", __func__);
  165. + drv->enabled = 1;
  166. + }
  167. +
  168. switch (config_tbl) {
  169. case AIC3254_CONFIG_TX:
  170. /* TX */
  171. - if (en && idx != DOWNLINK_OFF) {
  172. - pr_info("%s: enable tx\n", __func__);
  173. + pr_info("%s: enable tx\n", __func__);
  174. + if (en) {
  175. if (ctl_ops->tx_amp_enable)
  176. ctl_ops->tx_amp_enable(0);
  177.  
  178. aic3254_tx_config(idx);
  179. aic3254_tx_mode = idx;
  180. - /* update to current volume */
  181. - aic3254_config_ex(CODEC_SET_VOLUME_L,
  182. - ARRAY_SIZE(CODEC_SET_VOLUME_L));
  183. - aic3254_config_ex(CODEC_SET_VOLUME_R,
  184. - ARRAY_SIZE(CODEC_SET_VOLUME_R));
  185.  
  186. if (ctl_ops->tx_amp_enable)
  187. ctl_ops->tx_amp_enable(1);
  188. @@ -352,20 +434,15 @@ static int aic3254_set_config(int config_tbl, int idx, int en)
  189. break;
  190. case AIC3254_CONFIG_RX:
  191. /* RX */
  192. - if (en && idx != DOWNLINK_OFF) {
  193. - pr_info("%s: enable rx\n", __func__);
  194. + pr_info("%s: enable rx\n", __func__);
  195. + if (en) {
  196. if (ctl_ops->rx_amp_enable)
  197. ctl_ops->rx_amp_enable(0);
  198.  
  199. aic3254_rx_config(idx);
  200. aic3254_rx_mode = idx;
  201. - /* update to current volume */
  202. - aic3254_config_ex(CODEC_SET_VOLUME_L,
  203. - ARRAY_SIZE(CODEC_SET_VOLUME_L));
  204. - aic3254_config_ex(CODEC_SET_VOLUME_R,
  205. - ARRAY_SIZE(CODEC_SET_VOLUME_R));
  206.  
  207. - if(ctl_ops->rx_amp_enable)
  208. + if (ctl_ops->rx_amp_enable)
  209. ctl_ops->rx_amp_enable(1);
  210. } else {
  211. aic3254_rx_config(DOWNLINK_OFF);
  212. @@ -389,31 +466,27 @@ static int aic3254_set_config(int config_tbl, int idx, int en)
  213. if (ctl_ops->rx_amp_enable)
  214. ctl_ops->rx_amp_enable(0);
  215.  
  216. - /* step 1,2: sw reset and config DSP */
  217. + /* step 1: power off first */
  218. + if (aic3254_rx_mode != DOWNLINK_OFF)
  219. + aic3254_rx_config(DOWNLINK_OFF);
  220. +
  221. + /* step 2: config DSP */
  222. aic3254_config(&aic3254_minidsp[idx][1], len);
  223.  
  224. /* step 3: switch back to original path */
  225. - if (aic3254_rx_mode != DOWNLINK_OFF) {
  226. + if (aic3254_rx_mode != DOWNLINK_OFF)
  227. aic3254_rx_config(aic3254_rx_mode);
  228. -
  229. - /* update to current volume */
  230. - aic3254_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L));
  231. - aic3254_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R));
  232. - }
  233. - if (aic3254_tx_mode != UPLINK_OFF) {
  234. + if (aic3254_tx_mode != UPLINK_OFF)
  235. aic3254_tx_config(aic3254_tx_mode);
  236.  
  237. - /* update to current volume */
  238. - aic3254_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L));
  239. - aic3254_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R));
  240. - }
  241. -
  242. if (ctl_ops->rx_amp_enable)
  243. ctl_ops->rx_amp_enable(1);
  244.  
  245. pr_info("%s: configure minidsp done\n", __func__);
  246. break;
  247. }
  248. +
  249. + wake_unlock(&drv->idlelock);
  250. return 0;
  251. }
  252.  
  253. @@ -435,7 +508,6 @@ static int aic3254_open(struct inode *inode, struct file *pfile)
  254. static int aic3254_release(struct inode *inode, struct file *pfile)
  255. {
  256. mutex_lock(&lock);
  257. -
  258. aic3254_opend = 0;
  259. mutex_unlock(&lock);
  260.  
  261. @@ -449,6 +521,7 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
  262. void *table;
  263. int ret = 0, i = 0, mem_size, volume = 0;
  264. CODEC_SPI_CMD reg[2];
  265. + unsigned char data;
  266.  
  267. switch (cmd) {
  268. case AIC3254_SET_TX_PARAM:
  269. @@ -486,12 +559,12 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
  270.  
  271. pr_info("%s: update table(%d,%d) successfully\n",
  272. __func__, para.row_num, para.col_num);
  273. - break;
  274. + break;
  275. case AIC3254_SET_DSP_PARAM:
  276. if (copy_from_user(&para, (void *)argc, sizeof(para))) {
  277. pr_err("%s: failed on copy_from_user\n", __func__);
  278. return -EFAULT;
  279. - }
  280. + }
  281. pr_info("%s: parameters(%d, %d, %p)\n", __func__,
  282. para.row_num, para.col_num, para.cmd_data);
  283.  
  284. @@ -504,7 +577,7 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
  285. " memory (%d,%d)\n", __func__,
  286. MINIDSP_ROW_MAX, MINIDSP_COL_MAX);
  287. return -EFAULT;
  288. - }
  289. + }
  290.  
  291. mem_size = para.row_num * para.col_num * sizeof(CODEC_SPI_CMD);
  292. if (copy_from_user(table, para.cmd_data, mem_size)) {
  293. @@ -576,8 +649,13 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
  294. __func__, i);
  295. /* indicated page number to AIC3254 */
  296. codec_spi_write(0x00, i);
  297. - for (i = 0; i < AIC3254_MAX_REGS; i++)
  298. - codec_spi_read(i);
  299. + for (i = 0; i < AIC3254_MAX_REGS; i++) {
  300. + ret = codec_spi_read(i, &data);
  301. + if (ret < 0)
  302. + pr_err("read fail on register 0x%X\n", i);
  303. + else
  304. + pr_info("(0x%02X, 0x%02X)\n", i, data);
  305. + }
  306. pr_info("=============================================\n");
  307. break;
  308. case AIC3254_WRITE_REG:
  309. @@ -599,7 +677,7 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
  310. }
  311. for (i = 0; i < 2; i++) {
  312. if (reg[i].act == 'r' || reg[i].act == 'R')
  313. - reg[i].data = codec_spi_read(reg[i].reg);
  314. + codec_spi_read(reg[i].reg, &reg[i].data);
  315. else if (reg[i].act == 'w' || reg[i].act == 'W')
  316. codec_spi_write(reg[i].reg, reg[i].data);
  317. else
  318. @@ -613,6 +691,14 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
  319. case AIC3254_POWERDOWN:
  320. aic3254_powerdown();
  321. break;
  322. + case AIC3254_LOOPBACK:
  323. + if (copy_from_user(&i, (void *)argc, sizeof(int))) {
  324. + pr_err("%s: failed on copy_from_user\n", __func__);
  325. + return -EFAULT;
  326. + }
  327. + pr_info("%s: index %d for LOOPBACK\n", __func__, i);
  328. + aic3254_loopback(i);
  329. + break;
  330. default:
  331. pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd));
  332. ret = -EINVAL;
  333. @@ -729,6 +815,7 @@ static struct spi_driver spi_aic3254 = {
  334. static int __init spi_aic3254_init(void)
  335. {
  336. int ret = 0;
  337. + struct ecodec_aic3254_state *codec_drv = &codec_clk;
  338.  
  339. pr_info("%s\n", __func__);
  340. mutex_init(&lock);
  341. @@ -745,14 +832,40 @@ static int __init spi_aic3254_init(void)
  342. spi_unregister_driver(&spi_aic3254);
  343. return ret;
  344. }
  345. - return ret;
  346. +
  347. + codec_drv->rx_mclk = clk_get(NULL, "mi2s_codec_rx_m_clk");
  348. + if (IS_ERR(codec_drv->rx_mclk)) {
  349. + pr_err("%s:failed to get mi2s mclk\n", __func__);
  350. + misc_deregister(&aic3254_misc);
  351. + spi_unregister_driver(&spi_aic3254);
  352. + return -ENODEV;
  353. + }
  354. + codec_drv->rx_sclk = clk_get(NULL, "mi2s_codec_rx_s_clk");
  355. + if (IS_ERR(codec_drv->rx_sclk)) {
  356. + pr_err("%s:failed to get mi2s sclk\n", __func__);
  357. + misc_deregister(&aic3254_misc);
  358. + spi_unregister_driver(&spi_aic3254);
  359. + clk_put(codec_drv->rx_mclk);
  360. + return -ENODEV;
  361. + }
  362. +
  363. + wake_lock_init(&codec_drv->idlelock, WAKE_LOCK_IDLE,
  364. + "aic3254_lock");
  365. +
  366. + return 0;
  367. }
  368. module_init(spi_aic3254_init);
  369.  
  370. static void __exit spi_aic3254_exit(void)
  371. {
  372. + struct ecodec_aic3254_state *codec_drv = &codec_clk;
  373. +
  374. spi_unregister_driver(&spi_aic3254);
  375. misc_deregister(&aic3254_misc);
  376. +
  377. + clk_put(codec_drv->rx_mclk);
  378. + clk_put(codec_drv->rx_sclk);
  379. + return;
  380. }
  381. module_exit(spi_aic3254_exit);
  382.  
  383. diff --git a/include/linux/spi/spi_aic3254.h b/include/linux/spi/spi_aic3254.h
  384. index 72b3524..cfd8889 100644
  385. --- a/include/linux/spi/spi_aic3254.h
  386. +++ b/include/linux/spi/spi_aic3254.h
  387. @@ -24,6 +24,11 @@ typedef struct _CODEC_SPI_CMD {
  388. unsigned char data;
  389. } CODEC_SPI_CMD;
  390.  
  391. +typedef struct _CODEC_SPI_CMD_PARAM {
  392. + CODEC_SPI_CMD *data;
  393. + unsigned int len;
  394. +} CODEC_SPI_CMD_PARAM;
  395. +
  396. struct AIC3254_PARAM {
  397. unsigned int row_num;
  398. unsigned int col_num;
  399. @@ -47,6 +52,7 @@ struct CODEC_CFG {
  400. #define AIC3254_CONFIG_VOLUME_L _IOW(AIC3254_IOCTL_MAGIC, 0x23, unsigned int)
  401. #define AIC3254_CONFIG_VOLUME_R _IOW(AIC3254_IOCTL_MAGIC, 0x24, unsigned int)
  402. #define AIC3254_POWERDOWN _IOW(AIC3254_IOCTL_MAGIC, 0x25, unsigned int)
  403. +#define AIC3254_LOOPBACK _IOW(AIC3254_IOCTL_MAGIC, 0x26, unsigned int)
  404. #define AIC3254_DUMP_PAGES _IOW(AIC3254_IOCTL_MAGIC, 0x30, unsigned int)
  405. #define AIC3254_READ_REG _IOWR(AIC3254_IOCTL_MAGIC, 0x31, unsigned)
  406. #define AIC3254_WRITE_REG _IOW(AIC3254_IOCTL_MAGIC, 0x32, unsigned)
  407. @@ -85,7 +91,22 @@ struct aic3254_ctl_ops {
  408. void (*tx_amp_enable)(int en);
  409. void (*rx_amp_enable)(int en);
  410. int (*panel_sleep_in)(void);
  411. + CODEC_SPI_CMD_PARAM *downlink_off;
  412. + CODEC_SPI_CMD_PARAM *uplink_off;
  413. + CODEC_SPI_CMD_PARAM *downlink_on;
  414. + CODEC_SPI_CMD_PARAM *uplink_on;
  415. + CODEC_SPI_CMD_PARAM *lb_dsp_init;
  416. + CODEC_SPI_CMD_PARAM *lb_downlink_receiver;
  417. + CODEC_SPI_CMD_PARAM *lb_downlink_speaker;
  418. + CODEC_SPI_CMD_PARAM *lb_downlink_headset;
  419. + CODEC_SPI_CMD_PARAM *lb_uplink_imic;
  420. + CODEC_SPI_CMD_PARAM *lb_uplink_emic;
  421. + CODEC_SPI_CMD_PARAM *lb_receiver_imic;
  422. + CODEC_SPI_CMD_PARAM *lb_speaker_imic;
  423. + CODEC_SPI_CMD_PARAM *lb_headset_emic;
  424. + CODEC_SPI_CMD_PARAM *lb_headset_bmic;
  425. };
  426.  
  427. void aic3254_register_ctl_ops(struct aic3254_ctl_ops *ops);
  428. +void aic3254_set_mic_bias(int en);
  429. #endif /* __SPI_AIC3254_H__*/
  430. diff --git a/include/linux/spi/spi_aic3254_reg.h b/include/linux/spi/spi_aic3254_reg.h
  431. index 0fca1d6..2639b84 100644
  432. --- a/include/linux/spi/spi_aic3254_reg.h
  433. +++ b/include/linux/spi/spi_aic3254_reg.h
  434. @@ -299,4 +299,16 @@ static CODEC_SPI_CMD CODEC_SET_VOLUME_R[] = {
  435. {'w', 0x42, 0x00}
  436. };
  437.  
  438. +static CODEC_SPI_CMD CODEC_MICBIAS_ON[] = {
  439. + {'w', 0x00, 0x01},
  440. + {'w', 0x01, 0x08},
  441. + {'w', 0x02, 0x21},
  442. + {'w', 0x33, 0x68}
  443. +};
  444. +
  445. +static CODEC_SPI_CMD CODEC_MICBIAS_OFF[] = {
  446. + {'w', 0x00, 0x01},
  447. + {'w', 0x33, 0x28}
  448. +};
  449. +
  450. #endif /* __SPI_AIC3254_REG_H__*/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement