void aic3254_set_mode(int config, int mode) { mutex_lock(&lock); spi_aic3254_prevent_sleep(); switch (config) { case AIC3254_CONFIG_TX: /* TX */ pr_aud_info("%s: AIC3254_CONFIG_TX mode = %d\n", __func__, mode); aic3254_tx_config(mode); aic3254_tx_mode = mode; break; case AIC3254_CONFIG_RX: /* RX */ pr_aud_info("%s: AIC3254_CONFIG_RX mode = %d\n", __func__, mode); aic3254_rx_config(mode); if (mode == FM_OUT_SPEAKER) aic3254_tx_config(FM_IN_SPEAKER); else if (mode == FM_OUT_HEADSET) aic3254_tx_config(FM_IN_HEADSET); aic3254_rx_mode = mode; break; } aic3254_powerdown(); spi_aic3254_allow_sleep(); mutex_unlock(&lock); }
void aic3254_set_mode(int config, int mode) { pr_aud_info("%s: aic3254_set_mode %d mode = %d\n", __func__, config, mode); mutex_lock(&lock); switch (config) { case AIC3254_CONFIG_TX: /* TX */ aic3254_tx_config(mode); aic3254_tx_mode = mode; break; case AIC3254_CONFIG_RX: /* RX */ aic3254_rx_config(mode); if (mode == FM_OUT_SPEAKER) aic3254_tx_config(FM_IN_SPEAKER); else if (mode == FM_OUT_HEADSET) aic3254_tx_config(FM_IN_HEADSET); else if (mode == DOWNLINK_OFF && (mode == FM_OUT_HEADSET || mode == FM_OUT_HEADSET)) aic3254_tx_config(POWER_OFF); aic3254_rx_mode = mode; break; } aic3254_powerdown(); mutex_unlock(&lock); }
void aic3254_force_powerdown(void) { aic3254_rx_config(DOWNLINK_OFF); aic3254_rx_mode = DOWNLINK_OFF; aic3254_tx_config(UPLINK_OFF); aic3254_tx_mode = UPLINK_OFF; aic3254_powerdown(); }
static long aic3254_ioctl(struct file *file, unsigned int cmd, unsigned long argc) { struct AIC3254_PARAM para; void *table; int ret = 0, i = 0, mem_size, volume = 0; CODEC_SPI_CMD reg[2]; unsigned char data; if (aic3254_uplink == NULL || aic3254_downlink == NULL || aic3254_minidsp == NULL) { pr_aud_err("%s: cmd 0x%x, invalid pointers\n", __func__, cmd); return -EFAULT; } switch (cmd) { case AIC3254_SET_TX_PARAM: case AIC3254_SET_RX_PARAM: if (copy_from_user(¶, (void *)argc, sizeof(para))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } pr_aud_info("%s: parameters(%d, %d, %p)\n", __func__, para.row_num, para.col_num, para.cmd_data); if (cmd == AIC3254_SET_TX_PARAM) table = aic3254_uplink[0]; else table = aic3254_downlink[0]; /* confirm indicated size doesn't exceed the allocated one */ if (para.row_num > IO_CTL_ROW_MAX || para.col_num != IO_CTL_COL_MAX) { pr_aud_err("%s: data size mismatch with allocated" " memory (%d,%d)\n", __func__, IO_CTL_ROW_MAX, IO_CTL_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)) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } /* invoking initialization procedure of AIC3254 */ if (cmd == AIC3254_SET_TX_PARAM) aic3254_tx_config(INITIAL); pr_aud_info("%s: update table(%d,%d) successfully\n", __func__, para.row_num, para.col_num); break; case AIC3254_SET_DSP_PARAM: if (copy_from_user(¶, (void *)argc, sizeof(para))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } pr_aud_info("%s: parameters(%d, %d, %p)\n", __func__, para.row_num, para.col_num, para.cmd_data); table = aic3254_minidsp[0]; /* confirm indicated size doesn't exceed the allocated one */ if (para.row_num > MINIDSP_ROW_MAX || para.col_num != MINIDSP_COL_MAX) { pr_aud_err("%s: data size mismatch with allocated" " 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)) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } pr_aud_info("%s: update table(%d,%d) successfully\n", __func__, para.row_num, para.col_num); break; case AIC3254_CONFIG_TX: case AIC3254_CONFIG_RX: case AIC3254_CONFIG_MEDIA: if (copy_from_user(&i, (void *)argc, sizeof(int))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } ret = aic3254_set_config(cmd, i, 1); if (ret < 0) pr_aud_err("%s: configure(%d) error %d\n", __func__, i, ret); break; case AIC3254_CONFIG_VOLUME_L: if (copy_from_user(&volume, (void *)argc, sizeof(int))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } if (volume < -127 || volume > 48) { pr_aud_err("%s: volume out of range\n", __func__); return -EFAULT; } pr_aud_info("%s: AIC3254 config left volume %d\n", __func__, volume); CODEC_SET_VOLUME_L[1].data = volume; aic3254_config_ex(CODEC_SET_VOLUME_L, ARRAY_SIZE(CODEC_SET_VOLUME_L)); break; case AIC3254_CONFIG_VOLUME_R: if (copy_from_user(&volume, (void *)argc, sizeof(int))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } if (volume < -127 || volume > 48) { pr_aud_err("%s: volume out of range\n", __func__); return -EFAULT; } pr_aud_info("%s: AIC3254 config right volume %d\n", __func__, volume); CODEC_SET_VOLUME_R[1].data = volume; aic3254_config_ex(CODEC_SET_VOLUME_R, ARRAY_SIZE(CODEC_SET_VOLUME_R)); break; case AIC3254_DUMP_PAGES: if (copy_from_user(&i, (void *)argc, sizeof(int))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } if (i > AIC3254_MAX_PAGES) { pr_aud_err("%s: invalid page number %d\n", __func__, i); return -EINVAL; } pr_aud_info("========== %s: dump page %d ==========\n", __func__, i); /* indicated page number to AIC3254 */ if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); codec_spi_write(0x00, i); for (i = 0; i < AIC3254_MAX_REGS; i++) { ret = codec_spi_read(i, &data); if (ret < 0) pr_aud_err("read fail on register 0x%X\n", i); else pr_aud_info("(0x%02X, 0x%02X)\n", i, data); } if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); pr_aud_info("=============================================\n"); break; case AIC3254_WRITE_REG: if (copy_from_user(®, (void *)argc, sizeof(CODEC_SPI_CMD)*2)) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } pr_aud_info("%s: command list (%c,%02X,%02X) (%c,%02X,%02X)\n", __func__, reg[0].act, reg[0].reg, reg[0].data, reg[1].act, reg[1].reg, reg[1].data); aic3254_config_ex(reg, 2); break; case AIC3254_READ_REG: if (copy_from_user(®, (void *)argc, sizeof(CODEC_SPI_CMD)*2)) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } if (ctl_ops->spibus_enable) ctl_ops->spibus_enable(1); for (i = 0; i < 2; i++) { if (reg[i].act == 'r' || reg[i].act == 'R') 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 return -EINVAL; } if (ctl_ops->spibus_enable) ctl_ops->spibus_enable(0); if (copy_to_user((void *)argc, ®, sizeof(CODEC_SPI_CMD)*2)) { pr_aud_err("%s: failed on copy_to_user\n", __func__); return -EFAULT; } break; case AIC3254_POWERDOWN: mutex_lock(&lock); aic3254_powerdown(); mutex_unlock(&lock); break; case AIC3254_LOOPBACK: if (copy_from_user(&i, (void *)argc, sizeof(int))) { pr_aud_err("%s: failed on copy_from_user\n", __func__); return -EFAULT; } pr_aud_info("%s: index %d for LOOPBACK\n", __func__, i); aic3254_loopback(i); break; default: pr_aud_err("%s: invalid command %d\n", __func__, _IOC_NR(cmd)); ret = -EINVAL; } return ret; }
static int aic3254_set_config(int config_tbl, int idx, int en) { int rc = 0, len = 0; int64_t t1, t2; #if defined(CONFIG_ARCH_MSM7X30) struct ecodec_aic3254_state *drv = &codec_clk; #endif mutex_lock(&lock); spi_aic3254_prevent_sleep(); #if defined(CONFIG_ARCH_MSM7X30) 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; } #endif switch (config_tbl) { case AIC3254_CONFIG_TX: /* TX */ pr_aud_info("%s: enable tx\n", __func__); #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (en && idx != UPLINK_OFF) { #else if (en) { #endif if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(0); aic3254_tx_config(idx); aic3254_tx_mode = idx; if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(1); } else { aic3254_tx_config(UPLINK_OFF); aic3254_tx_mode = UPLINK_OFF; #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(0); aic3254_powerdown(); #endif } break; case AIC3254_CONFIG_RX: /* RX */ pr_aud_info("%s: enable rx\n", __func__); #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (en && idx != DOWNLINK_OFF) { #else if (en) { #endif if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); aic3254_rx_config(idx); aic3254_rx_mode = idx; if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); } else { aic3254_rx_config(DOWNLINK_OFF); aic3254_rx_mode = DOWNLINK_OFF; #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); aic3254_powerdown(); #endif } break; case AIC3254_CONFIG_MEDIA: if (aic3254_minidsp == NULL) { rc = -EFAULT; break; } len = (aic3254_minidsp[idx][0].reg << 8) | aic3254_minidsp[idx][0].data; pr_aud_info("%s: configure miniDSP index(%d) len = %d ++\n", __func__, idx, len); pr_aud_info("%s: rx mode %d, tx mode %d\n", __func__, aic3254_rx_mode, aic3254_tx_mode); t1 = ktime_to_ms(ktime_get()); if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); /* 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) aic3254_rx_config(aic3254_rx_mode); if (aic3254_tx_mode != UPLINK_OFF) aic3254_tx_config(aic3254_tx_mode); t2 = ktime_to_ms(ktime_get())-t1; if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); pr_aud_info("%s: configure miniDSP index(%d) time: %lldms --\n", __func__, idx, (t2)); break; } spi_aic3254_allow_sleep(); mutex_unlock(&lock); return rc; } static int aic3254_open(struct inode *inode, struct file *pfile) { int ret = 0; mutex_lock(&lock); if (aic3254_opend) { pr_aud_err("%s: busy\n", __func__); ret = -EBUSY; } else aic3254_opend = 1; mutex_unlock(&lock); return ret; } static int aic3254_release(struct inode *inode, struct file *pfile) { mutex_lock(&lock); aic3254_opend = 0; mutex_unlock(&lock); return 0; }
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__); if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(0); aic3254_tx_config(idx); aic3254_tx_mode = idx; if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(1); } else { aic3254_tx_config(UPLINK_OFF); aic3254_tx_mode = UPLINK_OFF; pr_info("%s: disable tx\n", __func__); if(ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(0); aic3254_powerdown(); } break; case AIC3254_CONFIG_RX: /* RX */ if (en && idx != DOWNLINK_OFF) { pr_info("%s: enable rx\n", __func__); if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); aic3254_rx_config(idx); aic3254_rx_mode = idx; if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); } else { aic3254_rx_config(DOWNLINK_OFF); aic3254_rx_mode = DOWNLINK_OFF; pr_info("%s: disable rx\n", __func__); if(ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); aic3254_powerdown(); } break; case AIC3254_CONFIG_MEDIA: if (aic3254_minidsp == NULL) return -EFAULT; len = (aic3254_minidsp[idx][0].reg << 8) | aic3254_minidsp[idx][0].data; pr_info("%s: miniDSP command len = %d\n", __func__, len); pr_info("%s: rx mode %d, tx mode %d\n", __func__, aic3254_rx_mode, aic3254_tx_mode); if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); /* 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) aic3254_rx_config(aic3254_rx_mode); if (aic3254_tx_mode != UPLINK_OFF) aic3254_tx_config(aic3254_tx_mode); 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; }
static int aic3254_set_config(int config_tbl, int idx, int en) { int len; struct ecodec_aic3254_state *drv = &codec_clk; pr_aud_info("%s: table(0x%X) index(%d)\n", __func__, config_tbl, idx); wake_lock(&drv->idlelock); #if defined(CONFIG_ARCH_MSM7X30) 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; } #endif switch (config_tbl) { case AIC3254_CONFIG_TX: /* TX */ pr_aud_info("%s: enable tx\n", __func__); #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (en && idx != UPLINK_OFF) { #else if (en) { #endif if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(0); aic3254_tx_config(idx); aic3254_tx_mode = idx; if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(1); } else { aic3254_tx_config(UPLINK_OFF); aic3254_tx_mode = UPLINK_OFF; #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (ctl_ops->tx_amp_enable) ctl_ops->tx_amp_enable(0); aic3254_powerdown(); #endif } break; case AIC3254_CONFIG_RX: /* RX */ pr_aud_info("%s: enable rx\n", __func__); #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (en && idx != DOWNLINK_OFF) { #else if (en) { #endif if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); aic3254_rx_config(idx); aic3254_rx_mode = idx; if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); } else { aic3254_rx_config(DOWNLINK_OFF); aic3254_rx_mode = DOWNLINK_OFF; #if defined(CONFIG_SPI_AIC3254_SELF_POWER_DOWN) if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); aic3254_powerdown(); #endif } break; case AIC3254_CONFIG_MEDIA: if (aic3254_minidsp == NULL) return -EFAULT; len = (aic3254_minidsp[idx][0].reg << 8) | aic3254_minidsp[idx][0].data; pr_aud_info("%s: miniDSP command len = %d\n", __func__, len); pr_aud_info("%s: rx mode %d, tx mode %d\n", __func__, aic3254_rx_mode, aic3254_tx_mode); if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(0); /* 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) aic3254_rx_config(aic3254_rx_mode); if (aic3254_tx_mode != UPLINK_OFF) aic3254_tx_config(aic3254_tx_mode); if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); pr_aud_info("%s: configure minidsp done\n", __func__); break; } wake_unlock(&drv->idlelock); return 0; } static int aic3254_open(struct inode *inode, struct file *pfile) { int ret = 0; mutex_lock(&lock); if (aic3254_opend) { pr_aud_err("%s: busy\n", __func__); ret = -EBUSY; } else aic3254_opend = 1; mutex_unlock(&lock); return ret; } static int aic3254_release(struct inode *inode, struct file *pfile) { mutex_lock(&lock); aic3254_opend = 0; mutex_unlock(&lock); return 0; }