static int marimba_adie_codec_enable_sidetone( struct adie_codec_path *rx_path_ptr, u32 enable) { int rc = 0; pr_debug("%s()\n", __func__); mutex_lock(&adie_codec.lock); if (!rx_path_ptr || &adie_codec.path[ADIE_CODEC_RX] != rx_path_ptr) { pr_err("%s: invalid path pointer\n", __func__); rc = -EINVAL; goto error; } else if (rx_path_ptr->curr_stage != ADIE_CODEC_DIGITAL_ANALOG_READY) { pr_err("%s: bad state\n", __func__); rc = -EPERM; goto error; } if (enable) rc = adie_codec_write(MARIMBA_CDC_RX_CTL, MARIMBA_CDC_RX_CTL_ST_EN_MASK, (0x1 << MARIMBA_CDC_RX_CTL_ST_EN_SHFT)); else rc = adie_codec_write(MARIMBA_CDC_RX_CTL, MARIMBA_CDC_RX_CTL_ST_EN_MASK, 0); error: mutex_unlock(&adie_codec.lock); return rc; }
static void marimba_codec_bring_down(void) { adie_codec_write(0xFF, 0xFF, 0x07); adie_codec_write(0xFF, 0xFF, 0x06); adie_codec_write(0xFF, 0xFF, 0x0e); adie_codec_write(0xFF, 0xFF, 0x08); adie_codec_write(0x03, 0xFF, 0x00); }
static ssize_t codec_debug_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { char *access_str = filp->private_data; char lbuf[32]; int rc; long int param[5]; if (cnt > sizeof(lbuf) - 1) return -EINVAL; rc = copy_from_user(lbuf, ubuf, cnt); if (rc) return -EFAULT; lbuf[cnt] = '\0'; if (!strcmp(access_str, "power")) { if (get_parameters(lbuf, param, 1) == 0) { switch (param[0]) { case 1: adie_codec.codec_pdata->marimba_codec_power(1); marimba_codec_bring_up(); break; case 0: marimba_codec_bring_down(); adie_codec.codec_pdata->marimba_codec_power(0); break; default: rc = -EINVAL; break; } } else rc = -EINVAL; } else if (!strcmp(access_str, "poke")) { /* write */ rc = get_parameters(lbuf, param, 2); if ((param[0] <= 0xFF) && (param[1] <= 0xFF) && (rc == 0)) adie_codec_write(param[0], 0xFF, param[1]); else rc = -EINVAL; } else if (!strcmp(access_str, "peek")) { /* read */ rc = get_parameters(lbuf, param, 1); if ((param[0] <= 0xFF) && (rc == 0)) adie_codec_read(param[0], &read_data); else rc = -EINVAL; } if (rc == 0) rc = cnt; else pr_err("%s: rc = %d\n", __func__, rc); return rc; }
static void marimba_codec_bring_up(void) { /* bring up sequence for Marimba codec core * ensure RESET_N = 0 and GDFS_CLAMP_EN=1 - * set GDFS_EN_FEW=1 then GDFS_EN_REST=1 then * GDFS_CLAMP_EN = 0 and finally RESET_N = 1 * Marimba codec bring up should use the Marimba * slave address after which the codec slave * address can be used */ /* Bring up codec */ adie_codec_write(0xFF, 0xFF, 0x08); /* set GDFS_EN_FEW=1 */ adie_codec_write(0xFF, 0xFF, 0x0a); /* set GDFS_EN_REST=1 */ adie_codec_write(0xFF, 0xFF, 0x0e); /* set RESET_N=1 */ adie_codec_write(0xFF, 0xFF, 0x07); adie_codec_write(0xFF, 0xFF, 0x17); /* enable band gap */ adie_codec_write(0x03, 0xFF, 0x04); /* dither delay selected and dmic gain stage bypassed */ adie_codec_write(0x8F, 0xFF, 0x44); }
int adie_codec_close(struct adie_codec_path *path_ptr) { int rc = 0; mutex_lock(&adie_codec.lock); if (!path_ptr) { rc = -EINVAL; goto error; } if (path_ptr->curr_stage != ADIE_CODEC_DIGITAL_OFF) adie_codec_proceed_stage(path_ptr, ADIE_CODEC_DIGITAL_OFF); BUG_ON(!adie_codec.ref_cnt); path_ptr->profile = NULL; adie_codec.ref_cnt--; if (!adie_codec.ref_cnt) { adie_codec_write(0xFF, 0xFF, 0x07); adie_codec_write(0xFF, 0xFF, 0x06); adie_codec_write(0xFF, 0xFF, 0x0e); adie_codec_write(0xFF, 0xFF, 0x08); adie_codec_write(0x03, 0xFF, 0x00); if (adie_codec.codec_pdata && adie_codec.codec_pdata->marimba_codec_power) { rc = adie_codec.codec_pdata->marimba_codec_power(0); if (rc) { pr_aud_err("%s: could not power down marimba " "codec\n", __func__); goto error; } } } error: mutex_unlock(&adie_codec.lock); return rc; }
static void adie_codec_reach_stage_action(struct adie_codec_path *path_ptr, u32 stage) { u32 iter; struct adie_codec_register *reg_info; if (stage == ADIE_CODEC_FLASH_IMAGE) { /* perform reimage */ for (iter = 0; iter < path_ptr->img.img_sz; iter++) { reg_info = &path_ptr->img.regs[iter]; adie_codec_write(reg_info->reg, reg_info->mask, reg_info->val); } } }
static int marimba_adie_codec_proceed_stage(struct adie_codec_path *path_ptr, u32 state) { int rc = 0, loop_exit = 0; struct adie_codec_action_unit *curr_action; struct adie_codec_hwsetting_entry *setting; u8 reg, mask, val; mutex_lock(&adie_codec.lock); setting = &path_ptr->profile->settings[path_ptr->hwsetting_idx]; while (!loop_exit) { curr_action = &setting->actions[path_ptr->stage_idx]; switch (curr_action->type) { case ADIE_CODEC_ACTION_ENTRY: ADIE_CODEC_UNPACK_ENTRY(curr_action->action, reg, mask, val); adie_codec_write(reg, mask, val); break; case ADIE_CODEC_ACTION_DELAY_WAIT: if (curr_action->action > MAX_MDELAY_US) msleep(curr_action->action/1000); else if (curr_action->action < MIN_MDELAY_US) udelay(curr_action->action); else mdelay(curr_action->action/1000); break; case ADIE_CODEC_ACTION_STAGE_REACHED: adie_codec_reach_stage_action(path_ptr, curr_action->action); if (curr_action->action == state) { path_ptr->curr_stage = state; loop_exit = 1; } break; default: BUG(); } path_ptr->stage_idx++; if (path_ptr->stage_idx == setting->action_sz) path_ptr->stage_idx = 0; } mutex_unlock(&adie_codec.lock); return rc; }
static int adie_codec_set_dig_vol(enum adie_vol_type vol_type, u32 chan_index, u32 cur_index, u32 target_index) { u32 count; u8 reg, mask, val; u32 i; u32 index; u32 index_jump; int rc; index_jump = adie_codec_vol_cntrl[vol_type].jump_length; reg = adie_codec_vol_cntrl[vol_type]. ch_vol_cntrl_info[chan_index].codec_reg; mask = adie_codec_vol_cntrl[vol_type]. ch_vol_cntrl_info[chan_index].codec_mask; /* compare the target index with current index */ if (cur_index < target_index) { /* Volume is being increased loop and increase it in 4-5 steps */ count = ((target_index - cur_index) * 100 / index_jump); index = cur_index; for (i = 1; i <= count; i++) { index = index + (int)(index_jump / 100); val = adie_codec_vol_cntrl[vol_type].ch_vol_cntrl_info [chan_index].vol_cntrl_data[index]; pr_debug("%s: write reg %x val 0x%x\n", __func__, reg, val); rc = adie_codec_write(reg, mask, val); if (rc < 0) { pr_err("%s: write reg %x val 0x%x failed\n", __func__, reg, val); return rc; } } /*do one final write to take it to the target index level */ val = adie_codec_vol_cntrl[vol_type].ch_vol_cntrl_info [chan_index].vol_cntrl_data[target_index]; pr_debug("%s: write reg %x val 0x%x\n", __func__, reg, val); rc = adie_codec_write(reg, mask, val); if (rc < 0) { pr_err("%s: write reg %x val 0x%x failed\n", __func__, reg, val); return rc; } } else { /* Volume is being decreased from the current setting */ index = cur_index; /* loop and decrease it in 4-5 steps */ count = ((cur_index - target_index) * 100 / index_jump); for (i = 1; i <= count; i++) { index = index - (int)(index_jump / 100); val = adie_codec_vol_cntrl[vol_type].ch_vol_cntrl_info [chan_index].vol_cntrl_data[index]; pr_debug("%s: write reg %x val 0x%x\n", __func__, reg, val); rc = adie_codec_write(reg, mask, val); if (rc < 0) { pr_err("%s: write reg %x val 0x%x failed\n", __func__, reg, val); return rc; } } /* do one final write to take it to the target index level */ val = adie_codec_vol_cntrl[vol_type].ch_vol_cntrl_info [chan_index].vol_cntrl_data[target_index]; pr_debug("%s: write reg %x val 0x%x\n", __func__, reg, val); rc = adie_codec_write(reg, mask, val); if (rc < 0) { pr_err("%s: write reg %x val 0x%x failed\n", __func__, reg, val); return rc; } } return 0; }
int usb_headset_adie_enable(int enable) { int rc = 0; mutex_lock(&adie_codec.lock); if (!adie_codec.ref_cnt && enable) { if (adie_codec.codec_pdata && adie_codec.codec_pdata->marimba_codec_power) { rc = adie_codec.codec_pdata->marimba_codec_power(1); if (rc) { pr_aud_err("%s: could not power up marimba " "codec\n", __func__); goto error; } } /* bring up sequence for Marimba codec core * ensure RESET_N = 0 and GDFS_CLAMP_EN=1 - * set GDFS_EN_FEW=1 then GDFS_EN_REST=1 then * GDFS_CLAMP_EN = 0 and finally RESET_N = 1 * Marimba codec bring up should use the Marimba * slave address after which the codec slave * address can be used */ /* Bring up codec */ adie_codec_write(0xFF, 0xFF, 0x08); /* set GDFS_EN_FEW=1 */ adie_codec_write(0xFF, 0xFF, 0x0a); /* set GDFS_EN_REST=1 */ adie_codec_write(0xFF, 0xFF, 0x0e); /* set RESET_N=1 */ adie_codec_write(0xFF, 0xFF, 0x07); adie_codec_write(0xFF, 0xFF, 0x17); /* enable band gap */ adie_codec_write(0x03, 0xFF, 0x04); /* dither delay selected and dmic gain stage bypassed */ adie_codec_write(0x8F, 0xFF, 0x44); /* usb audio adie parameter */ adie_codec_write(0x8a, 0xFF, 0x03); adie_codec_write(0x83, 0xFF, 0x00); adie_codec_write(0x33, 0xFF, 0x8f); mdelay(30); adie_codec.usb_state = 1; adie_codec.ref_cnt++; pr_aud_err("usb adie enabled\n"); } else if (enable) { adie_codec.ref_cnt++; adie_codec.usb_state = 1; } else if (!enable && adie_codec.ref_cnt > 1) { adie_codec.ref_cnt--; adie_codec.usb_state = 0; } else if (!enable && adie_codec.ref_cnt == 1) { adie_codec.ref_cnt = 0; adie_codec.usb_state = 0; adie_codec_write(0x8a, 0x03, 0x03); adie_codec_write(0x33, 0xFF, 0x03); adie_codec_write(0x33, 0xFF, 0x00); adie_codec_write(0xFF, 0xFF, 0x07); adie_codec_write(0xFF, 0xFF, 0x06); adie_codec_write(0xFF, 0xFF, 0x0e); adie_codec_write(0xFF, 0xFF, 0x08); adie_codec_write(0x03, 0xFF, 0x00); if (adie_codec.codec_pdata && adie_codec.codec_pdata->marimba_codec_power) { rc = adie_codec.codec_pdata->marimba_codec_power(0); if (rc) { pr_aud_err("%s: could not power down marimba " "codec\n", __func__); goto error; } } pr_aud_err("usb headset adie disabled"); } error: mutex_unlock(&adie_codec.lock); return rc; }
int adie_codec_open(struct adie_codec_dev_profile *profile, struct adie_codec_path **path_pptr) { int rc = 0; mutex_lock(&adie_codec.lock); if (!profile || !path_pptr) { rc = -EINVAL; goto error; } if (adie_codec.path[profile->path_type].profile) { rc = -EBUSY; goto error; } if (!adie_codec.ref_cnt) { if (adie_codec.codec_pdata && adie_codec.codec_pdata->marimba_codec_power) { rc = adie_codec.codec_pdata->marimba_codec_power(1); if (rc) { pr_aud_err("%s: could not power up marimba " "codec\n", __func__); goto error; } } /* bring up sequence for Marimba codec core * ensure RESET_N = 0 and GDFS_CLAMP_EN=1 - * set GDFS_EN_FEW=1 then GDFS_EN_REST=1 then * GDFS_CLAMP_EN = 0 and finally RESET_N = 1 * Marimba codec bring up should use the Marimba * slave address after which the codec slave * address can be used */ /* Bring up codec */ adie_codec_write(0xFF, 0xFF, 0x08); /* set GDFS_EN_FEW=1 */ adie_codec_write(0xFF, 0xFF, 0x0a); /* set GDFS_EN_REST=1 */ adie_codec_write(0xFF, 0xFF, 0x0e); /* set RESET_N=1 */ adie_codec_write(0xFF, 0xFF, 0x07); adie_codec_write(0xFF, 0xFF, 0x17); /* enable band gap */ adie_codec_write(0x03, 0xFF, 0x04); /* dither delay selected and dmic gain stage bypassed */ adie_codec_write(0x8F, 0xFF, 0x44); } adie_codec.path[profile->path_type].profile = profile; *path_pptr = (void *) &adie_codec.path[profile->path_type]; adie_codec.ref_cnt++; adie_codec.path[profile->path_type].hwsetting_idx = 0; adie_codec.path[profile->path_type].curr_stage = ADIE_CODEC_FLASH_IMAGE; adie_codec.path[profile->path_type].stage_idx = 0; error: mutex_unlock(&adie_codec.lock); return rc; }