Loading sound/soc/codecs/wcd_cpe_core.c +264 −198 Original line number Original line Diff line number Diff line Loading @@ -94,32 +94,6 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param); static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core); static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core); static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core); static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core); struct cpe_load_priv { void *cdc_handle; int cpe_load; struct kobject *cpe_load_kobj; struct attribute_group *attr_group; }; static ssize_t wcd_cpe_load_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); static struct kobj_attribute cpe_load_attr = __ATTR(load, 0600, NULL, wcd_cpe_load_store); static struct attribute *attrs[] = { &cpe_load_attr.attr, NULL, }; static struct attribute_group attr_grp = { .attrs = attrs, }; static struct cpe_load_priv cpe_priv; /* wcd_cpe_lsm_session_active: check if any session is active /* wcd_cpe_lsm_session_active: check if any session is active * return true if any session is active. * return true if any session is active. */ */ Loading Loading @@ -294,13 +268,16 @@ static int wcd_cpe_enable_cpe_clks(struct wcd_cpe_core *core, bool enable) } } /* /* * wcd_cpe_load_fw_image: Function to load the fw image * wcd_cpe_load_fw: Function to load the fw image * @core: cpe core pointer * @core: cpe core pointer * @load_type: indicates whether to load to data section * or the instruction section * * * Parse the mdt file to look for program headers, load each * Parse the mdt file to look for program headers, load each * split file corresponding to the program headers. * split file corresponding to the program headers. */ */ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) static int wcd_cpe_load_fw(struct wcd_cpe_core *core, unsigned int load_type) { { int ret, phdr_idx; int ret, phdr_idx; Loading @@ -312,6 +289,7 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) const u8 *elf_ptr; const u8 *elf_ptr; char mdt_name[64]; char mdt_name[64]; bool img_dload_fail = false; bool img_dload_fail = false; bool load_segment; if (!core || !core->cpe_handle) { if (!core || !core->cpe_handle) { pr_err("%s: Error CPE core %p\n", __func__, pr_err("%s: Error CPE core %p\n", __func__, Loading @@ -337,6 +315,7 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) elf_ptr = fw->data + sizeof(*ehdr); elf_ptr = fw->data + sizeof(*ehdr); if (load_type == ELF_FLAG_EXECUTE) { /* Reset CPE first */ /* Reset CPE first */ ret = cpe_svc_reset(core->cpe_handle); ret = cpe_svc_reset(core->cpe_handle); if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) { Loading @@ -345,45 +324,95 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) __func__, ret); __func__, ret); goto done; goto done; } } } dev_dbg(core->dev, "%s: starting image download, image = %s\n", dev_dbg(core->dev, "%s: start image dload, name = %s, load_type = 0x%x\n", __func__, core->fname); __func__, core->fname, load_type); /* parse every program header and request corresponding firmware */ /* parse every program header and request corresponding firmware */ for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) { for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) { phdr = (struct elf32_phdr *)elf_ptr; phdr = (struct elf32_phdr *)elf_ptr; load_segment = false; dev_dbg(core->dev, dev_dbg(core->dev, "index = %d, vaddr = 0x%x, paddr = 0x%x,\n" "index = %d, vaddr = 0x%x, paddr = 0x%x, " "filesz = 0x%x, memsz = 0x%x, flags = 0x%x\n" "filesz = 0x%x, memsz = 0x%x, flags = 0x%x\n" , phdr_idx, phdr->p_vaddr, phdr->p_paddr, , phdr_idx, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, phdr->p_memsz, phdr->p_flags); phdr->p_filesz, phdr->p_memsz, phdr->p_flags); ret = wcd_cpe_load_each_segment(core, phdr_idx, phdr); switch (load_type) { case ELF_FLAG_EXECUTE: if (phdr->p_flags & load_type) load_segment = true; break; case ELF_FLAG_RW: if (!(phdr->p_flags & ELF_FLAG_EXECUTE) && (phdr->p_flags & load_type)) load_segment = true; break; default: pr_err("%s: Invalid load_type 0x%x\n", __func__, load_type); ret = -EINVAL; goto done; } if (load_segment) { ret = wcd_cpe_load_each_segment(core, phdr_idx, phdr); if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) { dev_err(core->dev, dev_err(core->dev, "Failed to load segment %d .. aborting img dload\n", "Failed to load segment %d, aborting img dload\n", phdr_idx); phdr_idx); img_dload_fail = true; img_dload_fail = true; goto done; goto done; } } } else { dev_dbg(core->dev, "%s: skipped segment with index %d\n", __func__, phdr_idx); } elf_ptr = elf_ptr + sizeof(*phdr); elf_ptr = elf_ptr + sizeof(*phdr); } if (load_type == ELF_FLAG_EXECUTE) core->ssr_type = WCD_CPE_IMEM_DOWNLOADED; done: release_firmware(fw); return ret; } } if (!img_dload_fail) { /* wcd_cpe_enable_cpe_clks(core, true); * wcd_cpe_change_online_state - mark cpe online/offline state ret = cpe_svc_boot(core->cpe_handle, core->cpe_debug_mode); * @core: core session to mark if (IS_ERR_VALUE(ret)) * @online: whether online of offline dev_err(core->dev, * "%s: Failed to boot CPE\n", */ static void wcd_cpe_change_online_state(struct wcd_cpe_core *core, int online) { struct wcd_cpe_ssr_entry *ssr_entry = NULL; unsigned long ret; if (!core) { pr_err("%s: Invalid core handle\n", __func__); __func__); return; } } done: ssr_entry = &core->ssr_entry; release_firmware(fw); WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR"); return ret; ssr_entry->offline = !online; wmb(); ret = xchg(&ssr_entry->offline_change, 1); wake_up_interruptible(&ssr_entry->offline_poll_wait); WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR"); pr_debug("%s: change state 0x%x offline_change 0x%x\n" " core->offline 0x%x, ret = %ld\n", __func__, online, ssr_entry->offline_change, core->ssr_entry.offline, ret); } } /* /* Loading @@ -398,7 +427,12 @@ static void wcd_cpe_load_fw_image(struct work_struct *work) struct wcd_cpe_core *core; struct wcd_cpe_core *core; int ret = 0; int ret = 0; core = container_of(work, struct wcd_cpe_core, load_fw_work); core = container_of(work, struct wcd_cpe_core, load_fw_work); ret = wcd_cpe_load_fw(core); ret = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE); if (!ret) wcd_cpe_change_online_state(core, 1); else pr_err("%s: failed to load instruction section, err = %d\n", __func__, ret); return; return; } } Loading Loading @@ -534,37 +568,6 @@ static unsigned int wcd_cpe_state_poll(struct snd_info_entry *entry, return ret; return ret; } } /* * wcd_cpe_change_online_state - mark cpe online/offline state * @core: core session to mark * @online: whether online of offline * */ void wcd_cpe_change_online_state(struct wcd_cpe_core *core, int online) { struct wcd_cpe_ssr_entry *ssr_entry = NULL; unsigned long ret; if (!core) { pr_err("%s: Invalid core handle\n", __func__); return; } ssr_entry = &core->ssr_entry; WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR"); ssr_entry->offline = !online; wmb(); ret = xchg(&ssr_entry->offline_change, 1); wake_up_interruptible(&ssr_entry->offline_poll_wait); WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR"); pr_debug("%s: change state 0x%x offline_change 0x%x\n" " core->offline 0x%x, ret = %ld\n", __func__, online, ssr_entry->offline_change, core->ssr_entry.offline, ret); } /* /* * wcd_cpe_is_online_state - return true if card is online state * wcd_cpe_is_online_state - return true if card is online state * @core: core offline to query * @core: core offline to query Loading @@ -586,6 +589,74 @@ static struct snd_info_entry_ops wcd_cpe_state_proc_ops = { .poll = wcd_cpe_state_poll, .poll = wcd_cpe_state_poll, }; }; static int wcd_cpe_enable(struct wcd_cpe_core *core, bool enable) { int ret = 0; if (enable) { ret = wcd_cpe_setup_irqs(core); if (ret) { dev_err(core->dev, "%s: CPE IRQs setup failed, error = %d\n", __func__, ret); goto done; } /* Dload data section */ ret = wcd_cpe_load_fw(core, ELF_FLAG_RW); if (ret) { dev_err(core->dev, "%s: Failed to dload data section, err = %d\n", __func__, ret); goto fail_boot; } wcd_cpe_enable_cpe_clks(core, true); ret = cpe_svc_boot(core->cpe_handle, core->cpe_debug_mode); if (IS_ERR_VALUE(ret)) { dev_err(core->dev, "%s: Failed to boot CPE\n", __func__); goto fail_boot; } /* wait for CPE to be online */ dev_dbg(core->dev, "%s: waiting for CPE bootup\n", __func__); wait_for_completion(&core->online_compl); dev_dbg(core->dev, "%s: CPE bootup done\n", __func__); core->ssr_type = WCD_CPE_ENABLED; } else { /* Reset CPE first */ ret = cpe_svc_reset(core->cpe_handle); if (IS_ERR_VALUE(ret)) { dev_err(core->dev, "%s: Failed to reset CPE with error %d\n", __func__, ret); goto done; } wcd_cpe_enable_cpe_clks(core, false); wcd_cpe_cleanup_irqs(core); core->ssr_type = WCD_CPE_IMEM_DOWNLOADED; } return ret; fail_boot: wcd_cpe_cleanup_irqs(core); done: return ret; } /* /* * wcd_cpe_boot_ssr: Load the images to CPE after ssr and bootup cpe * wcd_cpe_boot_ssr: Load the images to CPE after ssr and bootup cpe * @core: handle to the core * @core: handle to the core Loading @@ -599,7 +670,17 @@ static int wcd_cpe_boot_ssr(struct wcd_cpe_core *core) rc = -EINVAL; rc = -EINVAL; goto fail; goto fail; } } rc = wcd_cpe_load_fw(core); /* Load the instruction section and mark CPE as online */ rc = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE); if (rc) { dev_err(core->dev, "%s: Failed to load instruction, err = %d\n", __func__, rc); goto fail; } else { wcd_cpe_change_online_state(core, 1); } fail: fail: return rc; return rc; } } Loading Loading @@ -692,6 +773,7 @@ void wcd_cpe_ssr_work(struct work_struct *work) irq = CPE_IRQ_WDOG_BITE; irq = CPE_IRQ_WDOG_BITE; } } if (core->cpe_users > 0) { rc = cpe_svc_process_irq(core->cpe_handle, irq); rc = cpe_svc_process_irq(core->cpe_handle, irq); if (IS_ERR_VALUE(rc)) if (IS_ERR_VALUE(rc)) /* /* Loading @@ -710,6 +792,12 @@ void wcd_cpe_ssr_work(struct work_struct *work) __func__); __func__); goto err_ret; goto err_ret; } } } else { pr_err("%s: no cpe users, mark as offline\n", __func__); wcd_cpe_change_online_state(core, 0); wcd_cpe_set_and_complete(core, WCD_CPE_BLK_READY); } rc = wait_for_completion_timeout(&core->ready_compl, rc = wait_for_completion_timeout(&core->ready_compl, CPE_READY_WAIT_TIMEOUT); CPE_READY_WAIT_TIMEOUT); Loading Loading @@ -785,8 +873,6 @@ int wcd_cpe_ssr_event(void *core_handle, break; break; case WCD_CPE_BUS_UP_EVENT: case WCD_CPE_BUS_UP_EVENT: wcd_cpe_cleanup_irqs(core); wcd_cpe_setup_irqs(core); wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY); wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY); /* /* * In case of bus up event ssr_type will be changed * In case of bus up event ssr_type will be changed Loading Loading @@ -976,10 +1062,10 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param) switch (param->event) { switch (param->event) { case CPE_SVC_ONLINE: case CPE_SVC_ONLINE: wcd_cpe_change_online_state(core, 1); core->ssr_type = WCD_CPE_ACTIVE; core->ssr_type = WCD_CPE_ACTIVE; dev_err(core->dev, "%s CPE is now online\n", dev_dbg(core->dev, "%s CPE is now online\n", __func__); __func__); complete(&core->online_compl); break; break; case CPE_SVC_OFFLINE: case CPE_SVC_OFFLINE: active_sessions = wcd_cpe_lsm_session_active(); active_sessions = wcd_cpe_lsm_session_active(); Loading @@ -987,18 +1073,10 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param) complete(&core->offline_compl); complete(&core->offline_compl); dev_err(core->dev, "%s: CPE is now offline\n", dev_err(core->dev, "%s: CPE is now offline\n", __func__); __func__); if (!active_sessions) { dev_dbg(core->dev, "%s: No active sessions, ready for online", __func__); wcd_cpe_set_and_complete(core, WCD_CPE_BLK_READY); } break; break; case CPE_SVC_CMI_CLIENTS_DEREG: case CPE_SVC_CMI_CLIENTS_DEREG: if (core->ssr_type != WCD_CPE_ACTIVE) if (core->ssr_type == WCD_CPE_SSR_EVENT) wcd_cpe_set_and_complete(core, wcd_cpe_set_and_complete(core, WCD_CPE_BLK_READY); WCD_CPE_BLK_READY); break; break; Loading Loading @@ -1189,7 +1267,8 @@ static int wcd_cpe_cal_init(struct wcd_cpe_core *core) * the work to download image and bootup the CPE. * the work to download image and bootup the CPE. * core: handle to cpe core structure * core: handle to cpe core structure */ */ static int wcd_cpe_enable(struct wcd_cpe_core *core) static int wcd_cpe_vote(struct wcd_cpe_core *core, bool enable) { { int ret = 0; int ret = 0; Loading @@ -1200,72 +1279,52 @@ static int wcd_cpe_enable(struct wcd_cpe_core *core) goto done; goto done; } } if (core->ssr_type != WCD_CPE_INITIALIZED) { dev_dbg(core->dev, dev_err(core->dev, "%s: enter, enable = %s, cpe_users = %u\n", "%s: CPE not initialized, state = 0x%x\n", __func__, (enable ? "true" : "false"), __func__, core->ssr_type); core->cpe_users); ret = -EINVAL; goto done; } ret = wcd_cpe_setup_irqs(core); if (enable) { if (core->cpe_users == 0) { ret = wcd_cpe_enable(core, enable); if (ret) { if (ret) { dev_err(core->dev, dev_err(core->dev, "%s: CPE IRQs setup failed, error = %d\n", "%s: CPE enable failed, err = %d\n", __func__, ret); __func__, ret); goto done; goto done; } } core->cpe_users++; core->ssr_type = WCD_CPE_ENABLED; } else { schedule_work(&core->load_fw_work); dev_dbg(core->dev, "%s: cpe already enabled, users = %u\n", done: __func__, core->cpe_users); return ret; goto done; } } } else { /* if (core->cpe_users == 1) { * wcd_cpe_load_store: Function invoked with sysfs property ret = wcd_cpe_enable(core, enable); * is written to. Enable CPE if value of the cpe_load if (ret) { * property is non-zero. dev_err(core->dev, * kobj: Kobject associated with the sysfs property "%s: CPE disable failed, err = %d\n", * attr: The attribute that is written to __func__, ret); * buf: holds the data that is written * count: number of data bytes in the buffer */ static ssize_t wcd_cpe_load_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct wcd_cpe_core *core; int ret = 0; if (cpe_priv.cpe_load) { pr_err("%s: CPE already loaded\n", __func__); goto done; goto done; } } core->cpe_users--; core = wcd_cpe_get_core_handle(cpe_priv.cdc_handle); } else { if (!core) { dev_dbg(core->dev, pr_err("%s: Invalid core handle\n", "%s: %u valid users on cpe\n", __func__); __func__, core->cpe_users); goto done; goto done; } } sscanf(buf, "%du", &cpe_priv.cpe_load); if (cpe_priv.cpe_load) { ret = wcd_cpe_enable(core); if (IS_ERR_VALUE(ret)) cpe_priv.cpe_load = 0; else pr_info("%s: CPE enabled for tomtom_codec\n", __func__); } } dev_dbg(core->dev, "%s: leave, enable = %s, cpe_users = %u\n", __func__, (enable ? "true" : "false"), core->cpe_users); done: done: return count; return ret; } } /* /* Loading Loading @@ -1336,8 +1395,10 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, INIT_WORK(&core->ssr_work, wcd_cpe_ssr_work); INIT_WORK(&core->ssr_work, wcd_cpe_ssr_work); init_completion(&core->offline_compl); init_completion(&core->offline_compl); init_completion(&core->ready_compl); init_completion(&core->ready_compl); init_completion(&core->online_compl); init_waitqueue_head(&core->ssr_entry.offline_poll_wait); init_waitqueue_head(&core->ssr_entry.offline_poll_wait); mutex_init(&core->ssr_lock); mutex_init(&core->ssr_lock); core->cpe_users = 0; /* /* * By default, during probe, it is assumed that * By default, during probe, it is assumed that Loading Loading @@ -1367,7 +1428,6 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, goto fail_cpe_register; goto fail_cpe_register; } } card = codec->card->snd_card; card = codec->card->snd_card; snprintf(proc_name, (sizeof("cpe") + sizeof("_state") + snprintf(proc_name, (sizeof("cpe") + sizeof("_state") + sizeof(id) - 2), "%s%d%s", cpe_name, id, state_name); sizeof(id) - 2), "%s%d%s", cpe_name, id, state_name); Loading Loading @@ -1398,35 +1458,22 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, */ */ } } cpe_priv.cdc_handle = codec; cpe_priv.attr_group = &attr_grp; cpe_priv.cpe_load_kobj = kobject_create_and_add("wcd_cpe", kernel_kobj); if (!cpe_priv.cpe_load_kobj) { pr_err("%s: cpe_load: sysfs create_add failed\n", __func__); goto fail_cpe_register; } else if (sysfs_create_group(cpe_priv.cpe_load_kobj, cpe_priv.attr_group)) { pr_err("%s: sysfs_create_group failed\n", __func__); kobject_del(cpe_priv.cpe_load_kobj); goto fail_cpe_register; } core->ssr_type = WCD_CPE_INITIALIZED; core_d = core; core_d = core; ret = wcd_cpe_cal_init(core); ret = wcd_cpe_cal_init(core); if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) { dev_err(core->dev, dev_err(core->dev, "%s: CPE calibration init failed, err = %d\n", "%s: CPE calibration init failed, err = %d\n", __func__, ret); __func__, ret); goto fail_cpe_register; goto fail_cpe_reset; } } core->ssr_type = WCD_CPE_INITIALIZED; core->ssr_type = WCD_CPE_INITIALIZED; schedule_work(&core->load_fw_work); return core; return core; fail_cpe_reset: cpe_svc_deregister(core->cpe_handle, core->cpe_reg_handle); fail_cpe_register: fail_cpe_register: cpe_svc_deinitialize(core->cpe_handle); cpe_svc_deinitialize(core->cpe_handle); Loading Loading @@ -2256,6 +2303,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( int i, session_id = -1; int i, session_id = -1; struct wcd_cpe_core *core = core_handle; struct wcd_cpe_core *core = core_handle; bool afe_register_service = false; bool afe_register_service = false; int ret = 0; /* /* * Even if multiple listen sessions can be * Even if multiple listen sessions can be Loading @@ -2280,12 +2328,20 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( return NULL; return NULL; } } ret = wcd_cpe_vote(core, true); if (ret) { dev_err(core->dev, "%s: Failed to enable cpe, err = %d\n", __func__, ret); return NULL; } session = kzalloc(sizeof(struct cpe_lsm_session), GFP_KERNEL); session = kzalloc(sizeof(struct cpe_lsm_session), GFP_KERNEL); if (!session) { if (!session) { dev_err(core->dev, dev_err(core->dev, "%s: failed to allocate session, no memory\n", "%s: failed to allocate session, no memory\n", __func__); __func__); return NULL; goto err_session_alloc; } } session->id = session_id; session->id = session_id; Loading Loading @@ -2322,8 +2378,12 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( err_afe_svc_reg: err_afe_svc_reg: cmi_deregister(session->cmi_reg_handle); cmi_deregister(session->cmi_reg_handle); mutex_destroy(&session->lsm_lock); mutex_destroy(&session->lsm_lock); err_ret: err_ret: kfree(session); kfree(session); err_session_alloc: wcd_cpe_vote(core, false); return NULL; return NULL; } } Loading Loading @@ -2637,6 +2697,7 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, struct cpe_lsm_session *session) struct cpe_lsm_session *session) { { struct wcd_cpe_core *core = core_handle; struct wcd_cpe_core *core = core_handle; int ret = 0; if (!session) { if (!session) { dev_err(core->dev, dev_err(core->dev, Loading Loading @@ -2665,7 +2726,12 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, wcd_cpe_deinitialize_afe_port_data(); wcd_cpe_deinitialize_afe_port_data(); } } return 0; ret = wcd_cpe_vote(core, false); if (ret) dev_dbg(core->dev, "%s: Failed to un-vote cpe, err = %d\n", __func__, ret); return ret; } } static int slim_master_read_enable(void *core_handle, static int slim_master_read_enable(void *core_handle, Loading sound/soc/codecs/wcd_cpe_core.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,11 @@ #define WCD_CPE_READY_TO_DLOAD \ #define WCD_CPE_READY_TO_DLOAD \ (WCD_CPE_BLK_READY | WCD_CPE_BUS_READY) (WCD_CPE_BLK_READY | WCD_CPE_BUS_READY) #define WCD_CPE_LOAD_IMEM (1 << 0) #define WCD_CPE_LOAD_DATA (1 << 1) #define WCD_CPE_LOAD_ALL \ (WCD_CPE_LOAD_IMEM | WCD_CPE_LOAD_DATA) enum { enum { WCD_CPE_LSM_CAL_AFE = 0, WCD_CPE_LSM_CAL_AFE = 0, WCD_CPE_LSM_CAL_LSM, WCD_CPE_LSM_CAL_LSM, Loading @@ -46,6 +51,8 @@ struct wcd_cpe_cdc_cb { enum wcd_cpe_ssr_state_event { enum wcd_cpe_ssr_state_event { /* Indicates CPE is initialized */ /* Indicates CPE is initialized */ WCD_CPE_INITIALIZED = 0, WCD_CPE_INITIALIZED = 0, /* Indicates that IMEM is downloaded to CPE */ WCD_CPE_IMEM_DOWNLOADED, /* Indicates CPE is enabled */ /* Indicates CPE is enabled */ WCD_CPE_ENABLED, WCD_CPE_ENABLED, /* Indicates that CPE is currently active */ /* Indicates that CPE is currently active */ Loading Loading @@ -125,6 +132,12 @@ struct wcd_cpe_core { /* Store the calibration data needed for cpe */ /* Store the calibration data needed for cpe */ struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX]; struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX]; /* completion event to signal CPE is online */ struct completion online_compl; /* reference counter for cpe usage */ u8 cpe_users; }; }; struct wcd_cpe_params { struct wcd_cpe_params { Loading Loading
sound/soc/codecs/wcd_cpe_core.c +264 −198 Original line number Original line Diff line number Diff line Loading @@ -94,32 +94,6 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param); static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core); static int wcd_cpe_setup_irqs(struct wcd_cpe_core *core); static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core); static void wcd_cpe_cleanup_irqs(struct wcd_cpe_core *core); struct cpe_load_priv { void *cdc_handle; int cpe_load; struct kobject *cpe_load_kobj; struct attribute_group *attr_group; }; static ssize_t wcd_cpe_load_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); static struct kobj_attribute cpe_load_attr = __ATTR(load, 0600, NULL, wcd_cpe_load_store); static struct attribute *attrs[] = { &cpe_load_attr.attr, NULL, }; static struct attribute_group attr_grp = { .attrs = attrs, }; static struct cpe_load_priv cpe_priv; /* wcd_cpe_lsm_session_active: check if any session is active /* wcd_cpe_lsm_session_active: check if any session is active * return true if any session is active. * return true if any session is active. */ */ Loading Loading @@ -294,13 +268,16 @@ static int wcd_cpe_enable_cpe_clks(struct wcd_cpe_core *core, bool enable) } } /* /* * wcd_cpe_load_fw_image: Function to load the fw image * wcd_cpe_load_fw: Function to load the fw image * @core: cpe core pointer * @core: cpe core pointer * @load_type: indicates whether to load to data section * or the instruction section * * * Parse the mdt file to look for program headers, load each * Parse the mdt file to look for program headers, load each * split file corresponding to the program headers. * split file corresponding to the program headers. */ */ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) static int wcd_cpe_load_fw(struct wcd_cpe_core *core, unsigned int load_type) { { int ret, phdr_idx; int ret, phdr_idx; Loading @@ -312,6 +289,7 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) const u8 *elf_ptr; const u8 *elf_ptr; char mdt_name[64]; char mdt_name[64]; bool img_dload_fail = false; bool img_dload_fail = false; bool load_segment; if (!core || !core->cpe_handle) { if (!core || !core->cpe_handle) { pr_err("%s: Error CPE core %p\n", __func__, pr_err("%s: Error CPE core %p\n", __func__, Loading @@ -337,6 +315,7 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) elf_ptr = fw->data + sizeof(*ehdr); elf_ptr = fw->data + sizeof(*ehdr); if (load_type == ELF_FLAG_EXECUTE) { /* Reset CPE first */ /* Reset CPE first */ ret = cpe_svc_reset(core->cpe_handle); ret = cpe_svc_reset(core->cpe_handle); if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) { Loading @@ -345,45 +324,95 @@ static int wcd_cpe_load_fw(struct wcd_cpe_core *core) __func__, ret); __func__, ret); goto done; goto done; } } } dev_dbg(core->dev, "%s: starting image download, image = %s\n", dev_dbg(core->dev, "%s: start image dload, name = %s, load_type = 0x%x\n", __func__, core->fname); __func__, core->fname, load_type); /* parse every program header and request corresponding firmware */ /* parse every program header and request corresponding firmware */ for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) { for (phdr_idx = 0; phdr_idx < ehdr->e_phnum; phdr_idx++) { phdr = (struct elf32_phdr *)elf_ptr; phdr = (struct elf32_phdr *)elf_ptr; load_segment = false; dev_dbg(core->dev, dev_dbg(core->dev, "index = %d, vaddr = 0x%x, paddr = 0x%x,\n" "index = %d, vaddr = 0x%x, paddr = 0x%x, " "filesz = 0x%x, memsz = 0x%x, flags = 0x%x\n" "filesz = 0x%x, memsz = 0x%x, flags = 0x%x\n" , phdr_idx, phdr->p_vaddr, phdr->p_paddr, , phdr_idx, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, phdr->p_memsz, phdr->p_flags); phdr->p_filesz, phdr->p_memsz, phdr->p_flags); ret = wcd_cpe_load_each_segment(core, phdr_idx, phdr); switch (load_type) { case ELF_FLAG_EXECUTE: if (phdr->p_flags & load_type) load_segment = true; break; case ELF_FLAG_RW: if (!(phdr->p_flags & ELF_FLAG_EXECUTE) && (phdr->p_flags & load_type)) load_segment = true; break; default: pr_err("%s: Invalid load_type 0x%x\n", __func__, load_type); ret = -EINVAL; goto done; } if (load_segment) { ret = wcd_cpe_load_each_segment(core, phdr_idx, phdr); if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) { dev_err(core->dev, dev_err(core->dev, "Failed to load segment %d .. aborting img dload\n", "Failed to load segment %d, aborting img dload\n", phdr_idx); phdr_idx); img_dload_fail = true; img_dload_fail = true; goto done; goto done; } } } else { dev_dbg(core->dev, "%s: skipped segment with index %d\n", __func__, phdr_idx); } elf_ptr = elf_ptr + sizeof(*phdr); elf_ptr = elf_ptr + sizeof(*phdr); } if (load_type == ELF_FLAG_EXECUTE) core->ssr_type = WCD_CPE_IMEM_DOWNLOADED; done: release_firmware(fw); return ret; } } if (!img_dload_fail) { /* wcd_cpe_enable_cpe_clks(core, true); * wcd_cpe_change_online_state - mark cpe online/offline state ret = cpe_svc_boot(core->cpe_handle, core->cpe_debug_mode); * @core: core session to mark if (IS_ERR_VALUE(ret)) * @online: whether online of offline dev_err(core->dev, * "%s: Failed to boot CPE\n", */ static void wcd_cpe_change_online_state(struct wcd_cpe_core *core, int online) { struct wcd_cpe_ssr_entry *ssr_entry = NULL; unsigned long ret; if (!core) { pr_err("%s: Invalid core handle\n", __func__); __func__); return; } } done: ssr_entry = &core->ssr_entry; release_firmware(fw); WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR"); return ret; ssr_entry->offline = !online; wmb(); ret = xchg(&ssr_entry->offline_change, 1); wake_up_interruptible(&ssr_entry->offline_poll_wait); WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR"); pr_debug("%s: change state 0x%x offline_change 0x%x\n" " core->offline 0x%x, ret = %ld\n", __func__, online, ssr_entry->offline_change, core->ssr_entry.offline, ret); } } /* /* Loading @@ -398,7 +427,12 @@ static void wcd_cpe_load_fw_image(struct work_struct *work) struct wcd_cpe_core *core; struct wcd_cpe_core *core; int ret = 0; int ret = 0; core = container_of(work, struct wcd_cpe_core, load_fw_work); core = container_of(work, struct wcd_cpe_core, load_fw_work); ret = wcd_cpe_load_fw(core); ret = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE); if (!ret) wcd_cpe_change_online_state(core, 1); else pr_err("%s: failed to load instruction section, err = %d\n", __func__, ret); return; return; } } Loading Loading @@ -534,37 +568,6 @@ static unsigned int wcd_cpe_state_poll(struct snd_info_entry *entry, return ret; return ret; } } /* * wcd_cpe_change_online_state - mark cpe online/offline state * @core: core session to mark * @online: whether online of offline * */ void wcd_cpe_change_online_state(struct wcd_cpe_core *core, int online) { struct wcd_cpe_ssr_entry *ssr_entry = NULL; unsigned long ret; if (!core) { pr_err("%s: Invalid core handle\n", __func__); return; } ssr_entry = &core->ssr_entry; WCD_CPE_GRAB_LOCK(&core->ssr_lock, "SSR"); ssr_entry->offline = !online; wmb(); ret = xchg(&ssr_entry->offline_change, 1); wake_up_interruptible(&ssr_entry->offline_poll_wait); WCD_CPE_REL_LOCK(&core->ssr_lock, "SSR"); pr_debug("%s: change state 0x%x offline_change 0x%x\n" " core->offline 0x%x, ret = %ld\n", __func__, online, ssr_entry->offline_change, core->ssr_entry.offline, ret); } /* /* * wcd_cpe_is_online_state - return true if card is online state * wcd_cpe_is_online_state - return true if card is online state * @core: core offline to query * @core: core offline to query Loading @@ -586,6 +589,74 @@ static struct snd_info_entry_ops wcd_cpe_state_proc_ops = { .poll = wcd_cpe_state_poll, .poll = wcd_cpe_state_poll, }; }; static int wcd_cpe_enable(struct wcd_cpe_core *core, bool enable) { int ret = 0; if (enable) { ret = wcd_cpe_setup_irqs(core); if (ret) { dev_err(core->dev, "%s: CPE IRQs setup failed, error = %d\n", __func__, ret); goto done; } /* Dload data section */ ret = wcd_cpe_load_fw(core, ELF_FLAG_RW); if (ret) { dev_err(core->dev, "%s: Failed to dload data section, err = %d\n", __func__, ret); goto fail_boot; } wcd_cpe_enable_cpe_clks(core, true); ret = cpe_svc_boot(core->cpe_handle, core->cpe_debug_mode); if (IS_ERR_VALUE(ret)) { dev_err(core->dev, "%s: Failed to boot CPE\n", __func__); goto fail_boot; } /* wait for CPE to be online */ dev_dbg(core->dev, "%s: waiting for CPE bootup\n", __func__); wait_for_completion(&core->online_compl); dev_dbg(core->dev, "%s: CPE bootup done\n", __func__); core->ssr_type = WCD_CPE_ENABLED; } else { /* Reset CPE first */ ret = cpe_svc_reset(core->cpe_handle); if (IS_ERR_VALUE(ret)) { dev_err(core->dev, "%s: Failed to reset CPE with error %d\n", __func__, ret); goto done; } wcd_cpe_enable_cpe_clks(core, false); wcd_cpe_cleanup_irqs(core); core->ssr_type = WCD_CPE_IMEM_DOWNLOADED; } return ret; fail_boot: wcd_cpe_cleanup_irqs(core); done: return ret; } /* /* * wcd_cpe_boot_ssr: Load the images to CPE after ssr and bootup cpe * wcd_cpe_boot_ssr: Load the images to CPE after ssr and bootup cpe * @core: handle to the core * @core: handle to the core Loading @@ -599,7 +670,17 @@ static int wcd_cpe_boot_ssr(struct wcd_cpe_core *core) rc = -EINVAL; rc = -EINVAL; goto fail; goto fail; } } rc = wcd_cpe_load_fw(core); /* Load the instruction section and mark CPE as online */ rc = wcd_cpe_load_fw(core, ELF_FLAG_EXECUTE); if (rc) { dev_err(core->dev, "%s: Failed to load instruction, err = %d\n", __func__, rc); goto fail; } else { wcd_cpe_change_online_state(core, 1); } fail: fail: return rc; return rc; } } Loading Loading @@ -692,6 +773,7 @@ void wcd_cpe_ssr_work(struct work_struct *work) irq = CPE_IRQ_WDOG_BITE; irq = CPE_IRQ_WDOG_BITE; } } if (core->cpe_users > 0) { rc = cpe_svc_process_irq(core->cpe_handle, irq); rc = cpe_svc_process_irq(core->cpe_handle, irq); if (IS_ERR_VALUE(rc)) if (IS_ERR_VALUE(rc)) /* /* Loading @@ -710,6 +792,12 @@ void wcd_cpe_ssr_work(struct work_struct *work) __func__); __func__); goto err_ret; goto err_ret; } } } else { pr_err("%s: no cpe users, mark as offline\n", __func__); wcd_cpe_change_online_state(core, 0); wcd_cpe_set_and_complete(core, WCD_CPE_BLK_READY); } rc = wait_for_completion_timeout(&core->ready_compl, rc = wait_for_completion_timeout(&core->ready_compl, CPE_READY_WAIT_TIMEOUT); CPE_READY_WAIT_TIMEOUT); Loading Loading @@ -785,8 +873,6 @@ int wcd_cpe_ssr_event(void *core_handle, break; break; case WCD_CPE_BUS_UP_EVENT: case WCD_CPE_BUS_UP_EVENT: wcd_cpe_cleanup_irqs(core); wcd_cpe_setup_irqs(core); wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY); wcd_cpe_set_and_complete(core, WCD_CPE_BUS_READY); /* /* * In case of bus up event ssr_type will be changed * In case of bus up event ssr_type will be changed Loading Loading @@ -976,10 +1062,10 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param) switch (param->event) { switch (param->event) { case CPE_SVC_ONLINE: case CPE_SVC_ONLINE: wcd_cpe_change_online_state(core, 1); core->ssr_type = WCD_CPE_ACTIVE; core->ssr_type = WCD_CPE_ACTIVE; dev_err(core->dev, "%s CPE is now online\n", dev_dbg(core->dev, "%s CPE is now online\n", __func__); __func__); complete(&core->online_compl); break; break; case CPE_SVC_OFFLINE: case CPE_SVC_OFFLINE: active_sessions = wcd_cpe_lsm_session_active(); active_sessions = wcd_cpe_lsm_session_active(); Loading @@ -987,18 +1073,10 @@ static void wcd_cpe_svc_event_cb(const struct cpe_svc_notification *param) complete(&core->offline_compl); complete(&core->offline_compl); dev_err(core->dev, "%s: CPE is now offline\n", dev_err(core->dev, "%s: CPE is now offline\n", __func__); __func__); if (!active_sessions) { dev_dbg(core->dev, "%s: No active sessions, ready for online", __func__); wcd_cpe_set_and_complete(core, WCD_CPE_BLK_READY); } break; break; case CPE_SVC_CMI_CLIENTS_DEREG: case CPE_SVC_CMI_CLIENTS_DEREG: if (core->ssr_type != WCD_CPE_ACTIVE) if (core->ssr_type == WCD_CPE_SSR_EVENT) wcd_cpe_set_and_complete(core, wcd_cpe_set_and_complete(core, WCD_CPE_BLK_READY); WCD_CPE_BLK_READY); break; break; Loading Loading @@ -1189,7 +1267,8 @@ static int wcd_cpe_cal_init(struct wcd_cpe_core *core) * the work to download image and bootup the CPE. * the work to download image and bootup the CPE. * core: handle to cpe core structure * core: handle to cpe core structure */ */ static int wcd_cpe_enable(struct wcd_cpe_core *core) static int wcd_cpe_vote(struct wcd_cpe_core *core, bool enable) { { int ret = 0; int ret = 0; Loading @@ -1200,72 +1279,52 @@ static int wcd_cpe_enable(struct wcd_cpe_core *core) goto done; goto done; } } if (core->ssr_type != WCD_CPE_INITIALIZED) { dev_dbg(core->dev, dev_err(core->dev, "%s: enter, enable = %s, cpe_users = %u\n", "%s: CPE not initialized, state = 0x%x\n", __func__, (enable ? "true" : "false"), __func__, core->ssr_type); core->cpe_users); ret = -EINVAL; goto done; } ret = wcd_cpe_setup_irqs(core); if (enable) { if (core->cpe_users == 0) { ret = wcd_cpe_enable(core, enable); if (ret) { if (ret) { dev_err(core->dev, dev_err(core->dev, "%s: CPE IRQs setup failed, error = %d\n", "%s: CPE enable failed, err = %d\n", __func__, ret); __func__, ret); goto done; goto done; } } core->cpe_users++; core->ssr_type = WCD_CPE_ENABLED; } else { schedule_work(&core->load_fw_work); dev_dbg(core->dev, "%s: cpe already enabled, users = %u\n", done: __func__, core->cpe_users); return ret; goto done; } } } else { /* if (core->cpe_users == 1) { * wcd_cpe_load_store: Function invoked with sysfs property ret = wcd_cpe_enable(core, enable); * is written to. Enable CPE if value of the cpe_load if (ret) { * property is non-zero. dev_err(core->dev, * kobj: Kobject associated with the sysfs property "%s: CPE disable failed, err = %d\n", * attr: The attribute that is written to __func__, ret); * buf: holds the data that is written * count: number of data bytes in the buffer */ static ssize_t wcd_cpe_load_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct wcd_cpe_core *core; int ret = 0; if (cpe_priv.cpe_load) { pr_err("%s: CPE already loaded\n", __func__); goto done; goto done; } } core->cpe_users--; core = wcd_cpe_get_core_handle(cpe_priv.cdc_handle); } else { if (!core) { dev_dbg(core->dev, pr_err("%s: Invalid core handle\n", "%s: %u valid users on cpe\n", __func__); __func__, core->cpe_users); goto done; goto done; } } sscanf(buf, "%du", &cpe_priv.cpe_load); if (cpe_priv.cpe_load) { ret = wcd_cpe_enable(core); if (IS_ERR_VALUE(ret)) cpe_priv.cpe_load = 0; else pr_info("%s: CPE enabled for tomtom_codec\n", __func__); } } dev_dbg(core->dev, "%s: leave, enable = %s, cpe_users = %u\n", __func__, (enable ? "true" : "false"), core->cpe_users); done: done: return count; return ret; } } /* /* Loading Loading @@ -1336,8 +1395,10 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, INIT_WORK(&core->ssr_work, wcd_cpe_ssr_work); INIT_WORK(&core->ssr_work, wcd_cpe_ssr_work); init_completion(&core->offline_compl); init_completion(&core->offline_compl); init_completion(&core->ready_compl); init_completion(&core->ready_compl); init_completion(&core->online_compl); init_waitqueue_head(&core->ssr_entry.offline_poll_wait); init_waitqueue_head(&core->ssr_entry.offline_poll_wait); mutex_init(&core->ssr_lock); mutex_init(&core->ssr_lock); core->cpe_users = 0; /* /* * By default, during probe, it is assumed that * By default, during probe, it is assumed that Loading Loading @@ -1367,7 +1428,6 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, goto fail_cpe_register; goto fail_cpe_register; } } card = codec->card->snd_card; card = codec->card->snd_card; snprintf(proc_name, (sizeof("cpe") + sizeof("_state") + snprintf(proc_name, (sizeof("cpe") + sizeof("_state") + sizeof(id) - 2), "%s%d%s", cpe_name, id, state_name); sizeof(id) - 2), "%s%d%s", cpe_name, id, state_name); Loading Loading @@ -1398,35 +1458,22 @@ struct wcd_cpe_core *wcd_cpe_init(const char *img_fname, */ */ } } cpe_priv.cdc_handle = codec; cpe_priv.attr_group = &attr_grp; cpe_priv.cpe_load_kobj = kobject_create_and_add("wcd_cpe", kernel_kobj); if (!cpe_priv.cpe_load_kobj) { pr_err("%s: cpe_load: sysfs create_add failed\n", __func__); goto fail_cpe_register; } else if (sysfs_create_group(cpe_priv.cpe_load_kobj, cpe_priv.attr_group)) { pr_err("%s: sysfs_create_group failed\n", __func__); kobject_del(cpe_priv.cpe_load_kobj); goto fail_cpe_register; } core->ssr_type = WCD_CPE_INITIALIZED; core_d = core; core_d = core; ret = wcd_cpe_cal_init(core); ret = wcd_cpe_cal_init(core); if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) { dev_err(core->dev, dev_err(core->dev, "%s: CPE calibration init failed, err = %d\n", "%s: CPE calibration init failed, err = %d\n", __func__, ret); __func__, ret); goto fail_cpe_register; goto fail_cpe_reset; } } core->ssr_type = WCD_CPE_INITIALIZED; core->ssr_type = WCD_CPE_INITIALIZED; schedule_work(&core->load_fw_work); return core; return core; fail_cpe_reset: cpe_svc_deregister(core->cpe_handle, core->cpe_reg_handle); fail_cpe_register: fail_cpe_register: cpe_svc_deinitialize(core->cpe_handle); cpe_svc_deinitialize(core->cpe_handle); Loading Loading @@ -2256,6 +2303,7 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( int i, session_id = -1; int i, session_id = -1; struct wcd_cpe_core *core = core_handle; struct wcd_cpe_core *core = core_handle; bool afe_register_service = false; bool afe_register_service = false; int ret = 0; /* /* * Even if multiple listen sessions can be * Even if multiple listen sessions can be Loading @@ -2280,12 +2328,20 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( return NULL; return NULL; } } ret = wcd_cpe_vote(core, true); if (ret) { dev_err(core->dev, "%s: Failed to enable cpe, err = %d\n", __func__, ret); return NULL; } session = kzalloc(sizeof(struct cpe_lsm_session), GFP_KERNEL); session = kzalloc(sizeof(struct cpe_lsm_session), GFP_KERNEL); if (!session) { if (!session) { dev_err(core->dev, dev_err(core->dev, "%s: failed to allocate session, no memory\n", "%s: failed to allocate session, no memory\n", __func__); __func__); return NULL; goto err_session_alloc; } } session->id = session_id; session->id = session_id; Loading Loading @@ -2322,8 +2378,12 @@ static struct cpe_lsm_session *wcd_cpe_alloc_lsm_session( err_afe_svc_reg: err_afe_svc_reg: cmi_deregister(session->cmi_reg_handle); cmi_deregister(session->cmi_reg_handle); mutex_destroy(&session->lsm_lock); mutex_destroy(&session->lsm_lock); err_ret: err_ret: kfree(session); kfree(session); err_session_alloc: wcd_cpe_vote(core, false); return NULL; return NULL; } } Loading Loading @@ -2637,6 +2697,7 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, struct cpe_lsm_session *session) struct cpe_lsm_session *session) { { struct wcd_cpe_core *core = core_handle; struct wcd_cpe_core *core = core_handle; int ret = 0; if (!session) { if (!session) { dev_err(core->dev, dev_err(core->dev, Loading Loading @@ -2665,7 +2726,12 @@ static int wcd_cpe_dealloc_lsm_session(void *core_handle, wcd_cpe_deinitialize_afe_port_data(); wcd_cpe_deinitialize_afe_port_data(); } } return 0; ret = wcd_cpe_vote(core, false); if (ret) dev_dbg(core->dev, "%s: Failed to un-vote cpe, err = %d\n", __func__, ret); return ret; } } static int slim_master_read_enable(void *core_handle, static int slim_master_read_enable(void *core_handle, Loading
sound/soc/codecs/wcd_cpe_core.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,11 @@ #define WCD_CPE_READY_TO_DLOAD \ #define WCD_CPE_READY_TO_DLOAD \ (WCD_CPE_BLK_READY | WCD_CPE_BUS_READY) (WCD_CPE_BLK_READY | WCD_CPE_BUS_READY) #define WCD_CPE_LOAD_IMEM (1 << 0) #define WCD_CPE_LOAD_DATA (1 << 1) #define WCD_CPE_LOAD_ALL \ (WCD_CPE_LOAD_IMEM | WCD_CPE_LOAD_DATA) enum { enum { WCD_CPE_LSM_CAL_AFE = 0, WCD_CPE_LSM_CAL_AFE = 0, WCD_CPE_LSM_CAL_LSM, WCD_CPE_LSM_CAL_LSM, Loading @@ -46,6 +51,8 @@ struct wcd_cpe_cdc_cb { enum wcd_cpe_ssr_state_event { enum wcd_cpe_ssr_state_event { /* Indicates CPE is initialized */ /* Indicates CPE is initialized */ WCD_CPE_INITIALIZED = 0, WCD_CPE_INITIALIZED = 0, /* Indicates that IMEM is downloaded to CPE */ WCD_CPE_IMEM_DOWNLOADED, /* Indicates CPE is enabled */ /* Indicates CPE is enabled */ WCD_CPE_ENABLED, WCD_CPE_ENABLED, /* Indicates that CPE is currently active */ /* Indicates that CPE is currently active */ Loading Loading @@ -125,6 +132,12 @@ struct wcd_cpe_core { /* Store the calibration data needed for cpe */ /* Store the calibration data needed for cpe */ struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX]; struct cal_type_data *cal_data[WCD_CPE_LSM_CAL_MAX]; /* completion event to signal CPE is online */ struct completion online_compl; /* reference counter for cpe usage */ u8 cpe_users; }; }; struct wcd_cpe_params { struct wcd_cpe_params { Loading