Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/drivers/spi/spi_aic3254.c b/drivers/spi/spi_aic3254.c
- index 1ac1b9f..dca3758 100644
- --- a/drivers/spi/spi_aic3254.c
- +++ b/drivers/spi/spi_aic3254.c
- @@ -23,6 +23,8 @@
- #include <linux/spi/spi_aic3254.h>
- #include <linux/spi/spi_aic3254_reg.h>
- #include <linux/delay.h>
- +#include <linux/clk.h>
- +#include <linux/wakelock.h>
- static struct spi_device *codec_dev;
- static struct mutex lock;
- @@ -36,6 +38,14 @@ static int aic3254_tx_mode;
- static struct aic3254_ctl_ops default_ctl_ops;
- static struct aic3254_ctl_ops *ctl_ops = &default_ctl_ops;
- +struct ecodec_aic3254_state {
- + int enabled;
- + struct clk *rx_mclk;
- + struct clk *rx_sclk;
- + struct wake_lock idlelock;
- +};
- +static struct ecodec_aic3254_state codec_clk;
- +
- /* function prototype */
- int route_tx_enable(int, int);
- int route_rx_enable(int, int);
- @@ -61,7 +71,7 @@ static int codec_spi_write(unsigned char addr, unsigned char data)
- return 1;
- }
- -static int codec_spi_read(unsigned char addr)
- +static int codec_spi_read(unsigned char addr, unsigned char *data)
- {
- int rc;
- u8 buffer[2] = {0, 0};
- @@ -73,13 +83,14 @@ static int codec_spi_read(unsigned char addr)
- if (rc < 0)
- return rc;
- - return result[1];
- + *data = result[1];
- + return 0;
- }
- static int aic3254_config(CODEC_SPI_CMD *cmds, int size)
- {
- - int i, retry;
- - unsigned char ret = 0;
- + int i, retry, ret;
- + unsigned char data;
- if (!codec_dev) {
- pr_err("%s: no spi device\n", __func__);
- @@ -113,8 +124,11 @@ static int aic3254_config(CODEC_SPI_CMD *cmds, int size)
- break;
- case 'r':
- for (retry = AIC3254_MAX_RETRY; retry > 0; retry--) {
- - ret = codec_spi_read(cmds[i].reg);
- - if (ret == cmds[i].data)
- + ret = codec_spi_read(cmds[i].reg, &data);
- + if (ret < 0)
- + pr_err("%s: read fail %d, retry\n",
- + __func__, ret);
- + else if (data == cmds[i].data)
- break;
- hr_msleep(10);
- }
- @@ -239,15 +253,67 @@ static void aic3254_rx_config(int mode)
- static void aic3254_powerdown(void)
- {
- + struct ecodec_aic3254_state *drv = &codec_clk;
- if (aic3254_tx_mode != UPLINK_OFF || aic3254_rx_mode != DOWNLINK_OFF)
- return;
- pr_info("%s: power off AIC3254\n", __func__);
- + wake_lock(&drv->idlelock);
- if (aic3254_uplink != NULL)
- aic3254_config(&aic3254_uplink[POWER_OFF][1],
- aic3254_uplink[POWER_OFF][0].data);
- else
- aic3254_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF));
- +
- + if (drv->enabled) {
- + /* Disable MI2S RX master block */
- + /* Disable MI2S RX bit clock */
- + clk_disable(drv->rx_sclk);
- + clk_disable(drv->rx_mclk);
- + drv->enabled = 0;
- + printk("%s: disable CLK\n", __func__);
- + }
- + wake_unlock(&drv->idlelock);
- + return;
- +}
- +static void aic3254_loopback(int mode)
- +{
- + if (!(ctl_ops->lb_dsp_init &&
- + ctl_ops->lb_receiver_imic &&
- + ctl_ops->lb_speaker_imic &&
- + ctl_ops->lb_headset_emic)) {
- + pr_info("%s: AIC3254 LOOPBACK not supported\n", __func__);
- + return;
- + }
- +
- + /* Init AIC3254 A00 */
- + aic3254_config(ctl_ops->lb_dsp_init->data, ctl_ops->lb_dsp_init->len);
- +
- + pr_info("%s: set AIC3254 in LOOPBACK mode\n", __func__);
- + switch (mode) {
- + case 0:
- + /* receiver v.s. imic */
- + aic3254_config(ctl_ops->lb_receiver_imic->data,
- + ctl_ops->lb_receiver_imic->len);
- + break;
- + case 1:
- + /* speaker v.s. imic */
- + aic3254_config(ctl_ops->lb_speaker_imic->data,
- + ctl_ops->lb_speaker_imic->len);
- + break;
- + case 2:
- + /* headphone v.s emic */
- + aic3254_config(ctl_ops->lb_headset_emic->data,
- + ctl_ops->lb_headset_emic->len);
- + case 13:
- + /* headphone v.s 2nd mic */
- + if (ctl_ops->lb_headset_bmic)
- + aic3254_config(ctl_ops->lb_headset_bmic->data,
- + ctl_ops->lb_headset_bmic->len);
- + else
- + pr_info("%s: 2nd mic loopback not supported\n", __func__);
- + break;
- + }
- }
- int route_rx_enable(int path, int en)
- @@ -318,26 +384,42 @@ int route_tx_enable(int path, int en)
- return 0;
- }
- +
- +void aic3254_set_mic_bias(int en) {
- +
- + if (en)
- + aic3254_config(CODEC_MICBIAS_ON, ARRAY_SIZE(CODEC_MICBIAS_ON));
- + else
- + aic3254_config(CODEC_MICBIAS_OFF, ARRAY_SIZE(CODEC_MICBIAS_OFF));
- +}
- +
- static int aic3254_set_config(int config_tbl, int idx, int en)
- {
- int len;
- + struct ecodec_aic3254_state *drv = &codec_clk;
- pr_info("%s: table(0x%X) index(%d)\n", __func__, config_tbl, idx);
- + wake_lock(&drv->idlelock);
- +
- + if (drv->enabled == 0) {
- + /* enable MI2S RX master block */
- + /* enable MI2S RX bit clock */
- + clk_enable(drv->rx_mclk);
- + clk_enable(drv->rx_sclk);
- + printk("%s: enable CLK\n", __func__);
- + drv->enabled = 1;
- + }
- +
- switch (config_tbl) {
- case AIC3254_CONFIG_TX:
- /* TX */
- - if (en && idx != DOWNLINK_OFF) {
- - pr_info("%s: enable tx\n", __func__);
- + pr_info("%s: enable tx\n", __func__);
- + if (en) {
- if (ctl_ops->tx_amp_enable)
- ctl_ops->tx_amp_enable(0);
- aic3254_tx_config(idx);
- aic3254_tx_mode = idx;
- - /* update to current volume */
- - aic3254_config_ex(CODEC_SET_VOLUME_L,
- - ARRAY_SIZE(CODEC_SET_VOLUME_L));
- - aic3254_config_ex(CODEC_SET_VOLUME_R,
- - ARRAY_SIZE(CODEC_SET_VOLUME_R));
- if (ctl_ops->tx_amp_enable)
- ctl_ops->tx_amp_enable(1);
- @@ -352,20 +434,15 @@ static int aic3254_set_config(int config_tbl, int idx, int en)
- break;
- case AIC3254_CONFIG_RX:
- /* RX */
- - if (en && idx != DOWNLINK_OFF) {
- - pr_info("%s: enable rx\n", __func__);
- + pr_info("%s: enable rx\n", __func__);
- + if (en) {
- if (ctl_ops->rx_amp_enable)
- ctl_ops->rx_amp_enable(0);
- aic3254_rx_config(idx);
- aic3254_rx_mode = idx;
- - /* update to current volume */
- - aic3254_config_ex(CODEC_SET_VOLUME_L,
- - ARRAY_SIZE(CODEC_SET_VOLUME_L));
- - aic3254_config_ex(CODEC_SET_VOLUME_R,
- - ARRAY_SIZE(CODEC_SET_VOLUME_R));
- - if(ctl_ops->rx_amp_enable)
- + if (ctl_ops->rx_amp_enable)
- ctl_ops->rx_amp_enable(1);
- } else {
- aic3254_rx_config(DOWNLINK_OFF);
- @@ -389,31 +466,27 @@ static int aic3254_set_config(int config_tbl, int idx, int en)
- if (ctl_ops->rx_amp_enable)
- ctl_ops->rx_amp_enable(0);
- - /* step 1,2: sw reset and config DSP */
- + /* step 1: power off first */
- + if (aic3254_rx_mode != DOWNLINK_OFF)
- + aic3254_rx_config(DOWNLINK_OFF);
- +
- + /* step 2: config DSP */
- aic3254_config(&aic3254_minidsp[idx][1], len);
- /* step 3: switch back to original path */
- - if (aic3254_rx_mode != DOWNLINK_OFF) {
- + if (aic3254_rx_mode != DOWNLINK_OFF)
- aic3254_rx_config(aic3254_rx_mode);
- -
- - /* update to current volume */
- - aic3254_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L));
- - aic3254_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R));
- - }
- - if (aic3254_tx_mode != UPLINK_OFF) {
- + if (aic3254_tx_mode != UPLINK_OFF)
- aic3254_tx_config(aic3254_tx_mode);
- - /* update to current volume */
- - aic3254_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L));
- - aic3254_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R));
- - }
- -
- if (ctl_ops->rx_amp_enable)
- ctl_ops->rx_amp_enable(1);
- pr_info("%s: configure minidsp done\n", __func__);
- break;
- }
- +
- + wake_unlock(&drv->idlelock);
- return 0;
- }
- @@ -435,7 +508,6 @@ static int aic3254_open(struct inode *inode, struct file *pfile)
- static int aic3254_release(struct inode *inode, struct file *pfile)
- {
- mutex_lock(&lock);
- -
- aic3254_opend = 0;
- mutex_unlock(&lock);
- @@ -449,6 +521,7 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
- void *table;
- int ret = 0, i = 0, mem_size, volume = 0;
- CODEC_SPI_CMD reg[2];
- + unsigned char data;
- switch (cmd) {
- case AIC3254_SET_TX_PARAM:
- @@ -486,12 +559,12 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
- pr_info("%s: update table(%d,%d) successfully\n",
- __func__, para.row_num, para.col_num);
- - break;
- + break;
- case AIC3254_SET_DSP_PARAM:
- if (copy_from_user(¶, (void *)argc, sizeof(para))) {
- pr_err("%s: failed on copy_from_user\n", __func__);
- return -EFAULT;
- - }
- + }
- pr_info("%s: parameters(%d, %d, %p)\n", __func__,
- para.row_num, para.col_num, para.cmd_data);
- @@ -504,7 +577,7 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
- " memory (%d,%d)\n", __func__,
- MINIDSP_ROW_MAX, MINIDSP_COL_MAX);
- return -EFAULT;
- - }
- + }
- mem_size = para.row_num * para.col_num * sizeof(CODEC_SPI_CMD);
- if (copy_from_user(table, para.cmd_data, mem_size)) {
- @@ -576,8 +649,13 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
- __func__, i);
- /* indicated page number to AIC3254 */
- codec_spi_write(0x00, i);
- - for (i = 0; i < AIC3254_MAX_REGS; i++)
- - codec_spi_read(i);
- + for (i = 0; i < AIC3254_MAX_REGS; i++) {
- + ret = codec_spi_read(i, &data);
- + if (ret < 0)
- + pr_err("read fail on register 0x%X\n", i);
- + else
- + pr_info("(0x%02X, 0x%02X)\n", i, data);
- + }
- pr_info("=============================================\n");
- break;
- case AIC3254_WRITE_REG:
- @@ -599,7 +677,7 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
- }
- for (i = 0; i < 2; i++) {
- if (reg[i].act == 'r' || reg[i].act == 'R')
- - reg[i].data = codec_spi_read(reg[i].reg);
- + codec_spi_read(reg[i].reg, ®[i].data);
- else if (reg[i].act == 'w' || reg[i].act == 'W')
- codec_spi_write(reg[i].reg, reg[i].data);
- else
- @@ -613,6 +691,14 @@ static int aic3254_ioctl(struct inode *inode, struct file *file,
- case AIC3254_POWERDOWN:
- aic3254_powerdown();
- break;
- + case AIC3254_LOOPBACK:
- + if (copy_from_user(&i, (void *)argc, sizeof(int))) {
- + pr_err("%s: failed on copy_from_user\n", __func__);
- + return -EFAULT;
- + }
- + pr_info("%s: index %d for LOOPBACK\n", __func__, i);
- + aic3254_loopback(i);
- + break;
- default:
- pr_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd));
- ret = -EINVAL;
- @@ -729,6 +815,7 @@ static struct spi_driver spi_aic3254 = {
- static int __init spi_aic3254_init(void)
- {
- int ret = 0;
- + struct ecodec_aic3254_state *codec_drv = &codec_clk;
- pr_info("%s\n", __func__);
- mutex_init(&lock);
- @@ -745,14 +832,40 @@ static int __init spi_aic3254_init(void)
- spi_unregister_driver(&spi_aic3254);
- return ret;
- }
- - return ret;
- +
- + codec_drv->rx_mclk = clk_get(NULL, "mi2s_codec_rx_m_clk");
- + if (IS_ERR(codec_drv->rx_mclk)) {
- + pr_err("%s:failed to get mi2s mclk\n", __func__);
- + misc_deregister(&aic3254_misc);
- + spi_unregister_driver(&spi_aic3254);
- + return -ENODEV;
- + }
- + codec_drv->rx_sclk = clk_get(NULL, "mi2s_codec_rx_s_clk");
- + if (IS_ERR(codec_drv->rx_sclk)) {
- + pr_err("%s:failed to get mi2s sclk\n", __func__);
- + misc_deregister(&aic3254_misc);
- + spi_unregister_driver(&spi_aic3254);
- + clk_put(codec_drv->rx_mclk);
- + return -ENODEV;
- + }
- +
- + wake_lock_init(&codec_drv->idlelock, WAKE_LOCK_IDLE,
- + "aic3254_lock");
- +
- + return 0;
- }
- module_init(spi_aic3254_init);
- static void __exit spi_aic3254_exit(void)
- {
- + struct ecodec_aic3254_state *codec_drv = &codec_clk;
- +
- spi_unregister_driver(&spi_aic3254);
- misc_deregister(&aic3254_misc);
- +
- + clk_put(codec_drv->rx_mclk);
- + clk_put(codec_drv->rx_sclk);
- + return;
- }
- module_exit(spi_aic3254_exit);
- diff --git a/include/linux/spi/spi_aic3254.h b/include/linux/spi/spi_aic3254.h
- index 72b3524..cfd8889 100644
- --- a/include/linux/spi/spi_aic3254.h
- +++ b/include/linux/spi/spi_aic3254.h
- @@ -24,6 +24,11 @@ typedef struct _CODEC_SPI_CMD {
- unsigned char data;
- } CODEC_SPI_CMD;
- +typedef struct _CODEC_SPI_CMD_PARAM {
- + CODEC_SPI_CMD *data;
- + unsigned int len;
- +} CODEC_SPI_CMD_PARAM;
- +
- struct AIC3254_PARAM {
- unsigned int row_num;
- unsigned int col_num;
- @@ -47,6 +52,7 @@ struct CODEC_CFG {
- #define AIC3254_CONFIG_VOLUME_L _IOW(AIC3254_IOCTL_MAGIC, 0x23, unsigned int)
- #define AIC3254_CONFIG_VOLUME_R _IOW(AIC3254_IOCTL_MAGIC, 0x24, unsigned int)
- #define AIC3254_POWERDOWN _IOW(AIC3254_IOCTL_MAGIC, 0x25, unsigned int)
- +#define AIC3254_LOOPBACK _IOW(AIC3254_IOCTL_MAGIC, 0x26, unsigned int)
- #define AIC3254_DUMP_PAGES _IOW(AIC3254_IOCTL_MAGIC, 0x30, unsigned int)
- #define AIC3254_READ_REG _IOWR(AIC3254_IOCTL_MAGIC, 0x31, unsigned)
- #define AIC3254_WRITE_REG _IOW(AIC3254_IOCTL_MAGIC, 0x32, unsigned)
- @@ -85,7 +91,22 @@ struct aic3254_ctl_ops {
- void (*tx_amp_enable)(int en);
- void (*rx_amp_enable)(int en);
- int (*panel_sleep_in)(void);
- + CODEC_SPI_CMD_PARAM *downlink_off;
- + CODEC_SPI_CMD_PARAM *uplink_off;
- + CODEC_SPI_CMD_PARAM *downlink_on;
- + CODEC_SPI_CMD_PARAM *uplink_on;
- + CODEC_SPI_CMD_PARAM *lb_dsp_init;
- + CODEC_SPI_CMD_PARAM *lb_downlink_receiver;
- + CODEC_SPI_CMD_PARAM *lb_downlink_speaker;
- + CODEC_SPI_CMD_PARAM *lb_downlink_headset;
- + CODEC_SPI_CMD_PARAM *lb_uplink_imic;
- + CODEC_SPI_CMD_PARAM *lb_uplink_emic;
- + CODEC_SPI_CMD_PARAM *lb_receiver_imic;
- + CODEC_SPI_CMD_PARAM *lb_speaker_imic;
- + CODEC_SPI_CMD_PARAM *lb_headset_emic;
- + CODEC_SPI_CMD_PARAM *lb_headset_bmic;
- };
- void aic3254_register_ctl_ops(struct aic3254_ctl_ops *ops);
- +void aic3254_set_mic_bias(int en);
- #endif /* __SPI_AIC3254_H__*/
- diff --git a/include/linux/spi/spi_aic3254_reg.h b/include/linux/spi/spi_aic3254_reg.h
- index 0fca1d6..2639b84 100644
- --- a/include/linux/spi/spi_aic3254_reg.h
- +++ b/include/linux/spi/spi_aic3254_reg.h
- @@ -299,4 +299,16 @@ static CODEC_SPI_CMD CODEC_SET_VOLUME_R[] = {
- {'w', 0x42, 0x00}
- };
- +static CODEC_SPI_CMD CODEC_MICBIAS_ON[] = {
- + {'w', 0x00, 0x01},
- + {'w', 0x01, 0x08},
- + {'w', 0x02, 0x21},
- + {'w', 0x33, 0x68}
- +};
- +
- +static CODEC_SPI_CMD CODEC_MICBIAS_OFF[] = {
- + {'w', 0x00, 0x01},
- + {'w', 0x33, 0x28}
- +};
- +
- #endif /* __SPI_AIC3254_REG_H__*/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement