int route_tx_enable(int path, int en) { pr_aud_info("%s: (%d,%d) uses 3254 default setting\n", __func__, path, en); if (en) { /* Uplink_Wakeup */ aic3254_config(CODEC_UPLINK_ON, ARRAY_SIZE(CODEC_UPLINK_ON)); /* Path switching */ switch (path) { case CALL_UPLINK_IMIC_RECEIVER: case CALL_UPLINK_IMIC_HEADSET: case CALL_UPLINK_IMIC_SPEAKER: case VOICERECORD_IMIC: /* By pass */ aic3254_config(MECHA_Uplink_IMIC, ARRAY_SIZE(MECHA_Uplink_IMIC)); break; case CALL_UPLINK_EMIC_HEADSET: case VOICERECORD_EMIC: aic3254_config(Uplink_EMIC, ARRAY_SIZE(Uplink_EMIC)); break; } } else { /* Uplink_Off */ aic3254_config(CODEC_UPLINK_OFF, ARRAY_SIZE(CODEC_UPLINK_OFF)); } return 0; }
static int spi_aic3254_probe(struct spi_device *aic3254) { pr_aud_info("%s\n", __func__); codec_dev = aic3254; /* Boot up */ #if 0 aic3254_config(CODEC_INIT_REG, ARRAY_SIZE(CODEC_INIT_REG)); aic3254_config(CODEC_DOWNLINK_OFF, ARRAY_SIZE(CODEC_DOWNLINK_OFF)); aic3254_config(CODEC_UPLINK_OFF, ARRAY_SIZE(CODEC_UPLINK_OFF)); aic3254_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF)); #endif aic3254_tx_mode = UPLINK_OFF; aic3254_rx_mode = DOWNLINK_OFF; /* request space for firmware data of AIC3254 */ aic3254_uplink = init_2d_array(IO_CTL_ROW_MAX, IO_CTL_COL_MAX); aic3254_downlink = init_2d_array(IO_CTL_ROW_MAX, IO_CTL_COL_MAX); aic3254_minidsp = init_2d_array(MINIDSP_ROW_MAX, MINIDSP_COL_MAX); bulk_tx = kcalloc(MINIDSP_COL_MAX * 2 , sizeof(uint8_t), GFP_KERNEL); spin_lock_init(&spinlock); 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 void aic3254_rx_config(int mode) { /* use default setting when rx table doesn't be updated*/ if (aic3254_downlink == NULL) { if (mode == DOWNLINK_OFF) route_rx_enable(mode, 0); else route_rx_enable(mode, 1); return; } if (mode != DOWNLINK_OFF && mode != POWER_OFF) { /* Downlink Wakeup */ pr_aud_info("downlink wakeup len(%d)\n", (aic3254_downlink[DOWNLINK_WAKEUP][0].data-1)); aic3254_config( &aic3254_downlink[DOWNLINK_WAKEUP][1], aic3254_downlink[DOWNLINK_WAKEUP][0].data); } /* route rx device */ pr_aud_info("downlink RX %d len(%d)\n", mode, (aic3254_downlink[mode][0].data-1)); aic3254_config(&aic3254_downlink[mode][1], aic3254_downlink[mode][0].data); }
static void aic3254_tx_config(int mode) { /* use default setting when tx table doesn't be updated*/ if (aic3254_uplink == NULL) { if (mode == UPLINK_OFF) route_tx_enable(mode, 0); else route_tx_enable(mode, 1); return; } if (mode != UPLINK_OFF && mode != POWER_OFF) { /* uplink_Wakeup */ pr_aud_info("uplink wakeup len(%d)\n", (aic3254_uplink[UPLINK_WAKEUP][0].data-1)); aic3254_config( &aic3254_uplink[UPLINK_WAKEUP][1], aic3254_uplink[UPLINK_WAKEUP][0].data); } /* route tx device */ pr_aud_info("uplink TX %d len(%d)\n", mode, (aic3254_uplink[mode][0].data-1)); aic3254_config(&aic3254_uplink[mode][1], aic3254_uplink[mode][0].data); }
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_aud_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 defined(CONFIG_ARCH_MSM7X30) 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__); } #endif 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_aud_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_aud_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); break; case 13: /* receiver v.s 2nd mic */ if (ctl_ops->lb_receiver_bmic) aic3254_config(ctl_ops->lb_receiver_bmic->data, ctl_ops->lb_receiver_bmic->len); else pr_aud_info("%s: receiver v.s. 2nd mic loopback not supported\n", __func__); break; case 14: /* speaker v.s 2nd mic */ if (ctl_ops->lb_speaker_bmic) aic3254_config(ctl_ops->lb_speaker_bmic->data, ctl_ops->lb_speaker_bmic->len); else pr_aud_info("%s: speaker v.s. 2nd mic loopback not supported\n", __func__); break; case 15: /* 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_aud_info("%s: headset v.s. 2nd mic loopback not supported\n", __func__); break; default: break; } }
static void aic3254_powerdown(void) { int64_t t1, t2; #if defined(CONFIG_ARCH_MSM7X30) struct ecodec_aic3254_state *drv = &codec_clk; #endif if (aic3254_tx_mode != UPLINK_OFF || aic3254_rx_mode != DOWNLINK_OFF) return; t1 = ktime_to_ms(ktime_get()); spi_aic3254_prevent_sleep(); if (aic3254_uplink != NULL) { pr_aud_info("power off AIC3254 len(%d)++\n", (aic3254_uplink[POWER_OFF][0].data-1)); aic3254_config(&aic3254_uplink[POWER_OFF][1], aic3254_uplink[POWER_OFF][0].data); } else { pr_aud_info("power off AIC3254 len(%d)++\n", (ARRAY_SIZE(CODEC_POWER_OFF))); aic3254_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF)); } #if defined(CONFIG_ARCH_MSM7X30) 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; pr_aud_info("%s: disable CLK\n", __func__); } #endif spi_aic3254_allow_sleep(); t2 = ktime_to_ms(ktime_get())-t1; pr_aud_info("power off AIC3254 %lldms --\n", t2); return; }
int route_rx_enable(int path, int en) { pr_aud_info("%s: (%d,%d) uses 3254 default setting\n", __func__, path, en); if (en) { /* Downlink_Wakeup */ aic3254_config(CODEC_DOWNLINK_ON, ARRAY_SIZE(CODEC_DOWNLINK_ON)); /* Path switching */ switch (path) { case FM_OUT_HEADSET: /* FM headset */ aic3254_config(FM_In_Headphone, ARRAY_SIZE(FM_In_Headphone)); aic3254_config(FM_Out_Headphone, ARRAY_SIZE(FM_Out_Headphone)); break; case FM_OUT_SPEAKER: /* FM speaker */ aic3254_config(FM_In_SPK, ARRAY_SIZE(FM_In_SPK)); aic3254_config(FM_Out_SPK, ARRAY_SIZE(FM_Out_SPK)); break; default: /* By pass */ aic3254_config(Downlink_IMIC_Receiver, ARRAY_SIZE(Downlink_IMIC_Receiver)); break; } } else { /* Downlink_Off */ aic3254_config(CODEC_DOWNLINK_OFF, ARRAY_SIZE(CODEC_DOWNLINK_OFF)); } return 0; }
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); pr_aud_info("%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 (en) { 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; } break; case AIC3254_CONFIG_RX: /* RX */ pr_aud_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; if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); } else { aic3254_rx_config(DOWNLINK_OFF); aic3254_rx_mode = DOWNLINK_OFF; } 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_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 (en) { 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; } break; case AIC3254_CONFIG_RX: /* RX */ pr_aud_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; if (ctl_ops->rx_amp_enable) ctl_ops->rx_amp_enable(1); } else { aic3254_rx_config(DOWNLINK_OFF); aic3254_rx_mode = DOWNLINK_OFF; } 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; }