Loading sound/soc/codecs/wcd9330.c +134 −43 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/tlv.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/pm_runtime.h> #include <linux/kernel.h> Loading @@ -38,6 +37,7 @@ #include "wcd9330.h" #include "wcd9xxx-resmgr.h" #include "wcd9xxx-common.h" #include "wcdcal-hwdep.h" #include "wcd_cpe_core.h" enum { Loading Loading @@ -517,6 +517,9 @@ struct tomtom_priv { u32 anc_slot; bool anc_func; /* cal info for codec */ struct fw_info *fw_data; /*track tomtom interface type*/ u8 intf_type; Loading Loading @@ -3212,28 +3215,56 @@ static int tomtom_codec_config_mad(struct snd_soc_codec *codec) { int ret; const struct firmware *fw; struct firmware_cal *hwdep_cal = NULL; struct mad_audio_cal *mad_cal; const void *data; const char *filename = TOMTOM_MAD_AUDIO_FIRMWARE_PATH; struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec); size_t cal_size; pr_debug("%s: enter\n", __func__); if (!tomtom->fw_data) { dev_err(codec->dev, "%s: invalid cal data\n", __func__); return -ENODEV; } hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, WCD9XXX_MAD_CAL); if (hwdep_cal) { data = hwdep_cal->data; cal_size = hwdep_cal->size; dev_dbg(codec->dev, "%s: using hwdep calibration\n", __func__); } else { ret = request_firmware(&fw, filename, codec->dev); if (ret != 0) { pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename, ret); pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename, ret); return -ENODEV; } if (fw->size < sizeof(struct mad_audio_cal)) { pr_err("%s: incorrect firmware size %zu\n", __func__, fw->size); release_firmware(fw); return -ENOMEM; if (!fw) { dev_err(codec->dev, "failed to get mad fw"); return -ENODEV; } data = fw->data; cal_size = fw->size; dev_dbg(codec->dev, "%s: using request_firmware calibration\n", __func__); } if (cal_size < sizeof(struct mad_audio_cal)) { pr_err("%s: incorrect hwdep cal size %zu\n", __func__, cal_size); ret = -ENOMEM; goto err; } mad_cal = (struct mad_audio_cal *)(fw->data); mad_cal = (struct mad_audio_cal *)(data); if (!mad_cal) { pr_err("%s: Invalid calibration data\n", __func__); release_firmware(fw); return -EINVAL; dev_err(codec->dev, "%s: Invalid calibration data\n", __func__); ret = -EINVAL; goto err; } snd_soc_write(codec, TOMTOM_A_CDC_MAD_MAIN_CTL_2, Loading Loading @@ -3283,13 +3314,13 @@ static int tomtom_codec_config_mad(struct snd_soc_codec *codec) snd_soc_write(codec, TOMTOM_A_CDC_MAD_ULTR_CTL_6, mad_cal->ultrasound_info.rms_threshold_msb); release_firmware(fw); /* Set MAD intr time to 20 msec */ snd_soc_update_bits(codec, 0x4E, 0x01F, 0x13); pr_debug("%s: leave ret %d\n", __func__, ret); err: if (!hwdep_cal) release_firmware(fw); return ret; } Loading Loading @@ -3896,17 +3927,19 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, const char *filename; const struct firmware *fw; int i; int ret; int ret = 0; int num_anc_slots; struct wcd9xxx_anc_header *anc_head; struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec); struct firmware_cal *hwdep_cal = NULL; u32 anc_writes_size = 0; u32 anc_cal_size = 0; int anc_size_remaining; u32 *anc_ptr; u16 reg; u8 mask, val, old_val; size_t cal_size; const void *data; if (tomtom->anc_func == 0) return 0; Loading @@ -3915,37 +3948,51 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: filename = "wcd9320/wcd9320_anc.bin"; hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, WCD9XXX_ANC_CAL); if (hwdep_cal) { data = hwdep_cal->data; cal_size = hwdep_cal->size; dev_dbg(codec->dev, "%s: using hwdep calibration\n", __func__); } else { ret = request_firmware(&fw, filename, codec->dev); if (ret != 0) { dev_err(codec->dev, "Failed to acquire ANC data: %d\n", ret); return -ENODEV; } if (fw->size < sizeof(struct wcd9xxx_anc_header)) { if (!fw) { dev_err(codec->dev, "failed to get anc fw"); return -ENODEV; } data = fw->data; cal_size = fw->size; dev_dbg(codec->dev, "%s: using request_firmware calibration\n", __func__); } if (cal_size < sizeof(struct wcd9xxx_anc_header)) { dev_err(codec->dev, "Not enough data\n"); release_firmware(fw); return -ENOMEM; ret = -ENOMEM; goto err; } /* First number is the number of register writes */ anc_head = (struct wcd9xxx_anc_header *)(fw->data); anc_ptr = (u32 *)(fw->data + anc_head = (struct wcd9xxx_anc_header *)(data); anc_ptr = (u32 *)(data + sizeof(struct wcd9xxx_anc_header)); anc_size_remaining = fw->size - anc_size_remaining = cal_size - sizeof(struct wcd9xxx_anc_header); num_anc_slots = anc_head->num_anc_slots; if (tomtom->anc_slot >= num_anc_slots) { dev_err(codec->dev, "Invalid ANC slot selected\n"); release_firmware(fw); return -EINVAL; ret = -EINVAL; goto err; } for (i = 0; i < num_anc_slots; i++) { if (anc_size_remaining < TOMTOM_PACKED_REG_SIZE) { dev_err(codec->dev, "Invalid register format\n"); release_firmware(fw); return -EINVAL; ret = -EINVAL; goto err; } anc_writes_size = (u32)(*anc_ptr); anc_size_remaining -= sizeof(u32); Loading @@ -3954,8 +4001,8 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, if (anc_writes_size * TOMTOM_PACKED_REG_SIZE > anc_size_remaining) { dev_err(codec->dev, "Invalid register format\n"); release_firmware(fw); return -ENOMEM; ret = -EINVAL; goto err; } if (tomtom->anc_slot == i) Loading @@ -3967,8 +4014,8 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, } if (i == num_anc_slots) { dev_err(codec->dev, "Selected ANC slot not present\n"); release_firmware(fw); return -ENOMEM; ret = -EINVAL; goto err; } i = 0; Loading Loading @@ -4010,6 +4057,7 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, if (w->reg == TOMTOM_A_RX_HPH_R_DAC_CTL) snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x0C, 0x00); if (!hwdep_cal) release_firmware(fw); break; case SND_SOC_DAPM_PRE_PMD: Loading @@ -4025,6 +4073,10 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, break; } return 0; err: if (!hwdep_cal) release_firmware(fw); return ret; } static int tomtom_hphl_dac_event(struct snd_soc_dapm_widget *w, Loading Loading @@ -7536,6 +7588,27 @@ static void tomtom_cleanup_irqs(struct tomtom_priv *tomtom) wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tomtom); } static struct firmware_cal *tomtom_get_hwdep_fw_cal(struct snd_soc_codec *codec, enum wcd_cal_type type) { struct tomtom_priv *tomtom; struct firmware_cal *hwdep_cal; if (!codec) { pr_err("%s: NULL codec pointer\n", __func__); return NULL; } tomtom = snd_soc_codec_get_drvdata(codec); hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, type); if (!hwdep_cal) { dev_err(codec->dev, "%s: cal not sent by %d\n", __func__, type); return NULL; } else { return hwdep_cal; } } int tomtom_hs_detect(struct snd_soc_codec *codec, struct wcd9xxx_mbhc_config *mbhc_cfg) { Loading Loading @@ -8123,6 +8196,7 @@ static const struct wcd9xxx_mbhc_cb mbhc_cb = { .micbias_pulldown_ctrl = tomtom_mbhc_micb_pulldown_ctrl, .codec_rco_ctrl = tomtom_codec_internal_rco_ctrl, .hph_auto_pulldown_ctrl = tomtom_codec_hph_auto_pull_down, .get_hwdep_fw_cal = tomtom_get_hwdep_fw_cal, }; static const struct wcd9xxx_mbhc_intr cdc_intr_ids = { Loading Loading @@ -8417,6 +8491,21 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ; tomtom->fw_data = kzalloc(sizeof(*(tomtom->fw_data)), GFP_KERNEL); if (!tomtom->fw_data) { dev_err(codec->dev, "Failed to allocate fw_data\n"); goto err_nomem_slimch; } set_bit(WCD9XXX_ANC_CAL, tomtom->fw_data->cal_bit); set_bit(WCD9XXX_MAD_CAL, tomtom->fw_data->cal_bit); set_bit(WCD9XXX_MBHC_CAL, tomtom->fw_data->cal_bit); ret = wcd_cal_create_hwdep(tomtom->fw_data, WCD9XXX_CODEC_HWDEP_NODE, codec); if (ret < 0) { dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret); goto err_hwdep; } /* init and start mbhc */ ret = wcd9xxx_mbhc_init(&tomtom->mbhc, &tomtom->resmgr, codec, tomtom_enable_mbhc_micbias, Loading @@ -8424,7 +8513,7 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) rco_clk_rate, TOMTOM_ZDET_SUPPORTED); if (ret) { pr_err("%s: mbhc init failed %d\n", __func__, ret); goto err_nomem_slimch; goto err_hwdep; } tomtom->codec = codec; Loading @@ -8449,7 +8538,7 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) ret = tomtom_handle_pdata(tomtom); if (IS_ERR_VALUE(ret)) { pr_err("%s: bad pdata\n", __func__); goto err_nomem_slimch; goto err_hwdep; } tomtom->spkdrv_reg = tomtom_codec_find_regulator(codec, Loading @@ -8462,7 +8551,7 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) if (!ptr) { pr_err("%s: no mem for slim chan ctl data\n", __func__); ret = -ENOMEM; goto err_nomem_slimch; goto err_hwdep; } if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { Loading Loading @@ -8536,6 +8625,8 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) err_pdata: kfree(ptr); err_hwdep: kfree(tomtom->fw_data); err_nomem_slimch: devm_kfree(codec->dev, tomtom); return ret; Loading sound/soc/codecs/wcd9xxx-mbhc.c +76 −33 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ #include "wcd9320.h" #include "wcd9306.h" #include "wcd9xxx-mbhc.h" #include "wcdcal-hwdep.h" #include "wcd9xxx-resmgr.h" #include "wcd9xxx-common.h" Loading Loading @@ -74,7 +75,7 @@ #define OCP_ATTEMPT 1 #define FW_READ_ATTEMPTS 15 #define FW_READ_TIMEOUT 2000000 #define FW_READ_TIMEOUT 4000000 #define BUTTON_POLLING_SUPPORTED true Loading Loading @@ -2893,35 +2894,39 @@ static void wcd9xxx_mbhc_insert_work(struct work_struct *work) wcd9xxx_unlock_sleep(core_res); } static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw) static bool wcd9xxx_mbhc_fw_validate(const void *data, size_t size) { u32 cfg_offset; struct wcd9xxx_mbhc_imped_detect_cfg *imped_cfg; struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg; struct firmware_cal fw; if (fw->size < WCD9XXX_MBHC_CAL_MIN_SIZE) fw.data = (void *)data; fw.size = size; if (fw.size < WCD9XXX_MBHC_CAL_MIN_SIZE) return false; /* * Previous check guarantees that there is enough fw data up * to num_btn */ btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw->data); cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data); if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg))) btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw.data); cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data); if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg))) return false; /* * Previous check guarantees that there is enough fw data up * to start of impedance detection configuration */ imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw->data); cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data); imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw.data); cfg_offset = (u32) ((void *) imped_cfg - (void *) fw.data); if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ)) if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ)) return false; if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg))) if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg))) return false; return true; Loading Loading @@ -4279,7 +4284,9 @@ static void wcd9xxx_mbhc_fw_read(struct work_struct *work) struct wcd9xxx_mbhc *mbhc; struct snd_soc_codec *codec; const struct firmware *fw; struct firmware_cal *fw_data = NULL; int ret = -1, retry = 0; bool use_default_cal = false; dwork = to_delayed_work(work); mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_firmware_dwork); Loading @@ -4289,29 +4296,62 @@ static void wcd9xxx_mbhc_fw_read(struct work_struct *work) retry++; pr_info("%s:Attempt %d to request MBHC firmware\n", __func__, retry); if (mbhc->mbhc_cb->get_hwdep_fw_cal) fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(codec, WCD9XXX_MBHC_CAL); if (!fw_data) ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin", codec->dev); if (ret != 0) { /* * if request_firmware and hwdep cal both fail then * retry for few times before bailing out */ if ((ret != 0) && !fw_data) { usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT + WCD9XXX_USLEEP_RANGE_MARGIN_US); } else { pr_info("%s: MBHC Firmware read succesful\n", __func__); pr_info("%s: MBHC Firmware read succesful\n", __func__); break; } } if (ret != 0) { if (!fw_data) pr_info("%s: using request_firmware\n", __func__); else pr_info("%s: using hwdep cal\n", __func__); if (ret != 0 && !fw_data) { pr_err("%s: Cannot load MBHC firmware use default cal\n", __func__); } else if (wcd9xxx_mbhc_fw_validate(fw) == false) { use_default_cal = true; } if (!use_default_cal) { const void *data; size_t size; if (fw_data) { data = fw_data->data; size = fw_data->size; } else { data = fw->data; size = fw->size; } if (wcd9xxx_mbhc_fw_validate(data, size) == false) { pr_err("%s: Invalid MBHC cal data size use default cal\n", __func__); if (!fw_data) release_firmware(fw); } else { mbhc->mbhc_cfg->calibration = (void *)fw->data; if (fw_data) { mbhc->mbhc_cfg->calibration = (void *)fw_data->data; mbhc->mbhc_cal = fw_data; } else { mbhc->mbhc_cfg->calibration = (void *)fw->data; mbhc->mbhc_fw = fw; } } } (void) wcd9xxx_init_and_calibrate(mbhc); } Loading Loading @@ -4500,15 +4540,16 @@ int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc, mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true); if (!mbhc->mbhc_cfg->read_fw_bin || (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw)) { (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) || (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) { rc = wcd9xxx_init_and_calibrate(mbhc); } else { if (!mbhc->mbhc_fw) if (!mbhc->mbhc_fw || !mbhc->mbhc_cal) schedule_delayed_work(&mbhc->mbhc_firmware_dwork, usecs_to_jiffies(FW_READ_TIMEOUT)); else pr_debug("%s: Skipping to read mbhc fw, 0x%p\n", __func__, mbhc->mbhc_fw); pr_debug("%s: Skipping to read mbhc fw, 0x%p %p\n", __func__, mbhc->mbhc_fw, mbhc->mbhc_cal); } pr_debug("%s: leave %d\n", __func__, rc); Loading @@ -4518,10 +4559,12 @@ EXPORT_SYMBOL(wcd9xxx_mbhc_start); void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc) { if (mbhc->mbhc_fw) { if (mbhc->mbhc_fw || mbhc->mbhc_cal) { cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork); if (!mbhc->mbhc_cal) release_firmware(mbhc->mbhc_fw); mbhc->mbhc_fw = NULL; mbhc->mbhc_cal = NULL; } } EXPORT_SYMBOL(wcd9xxx_mbhc_stop); Loading sound/soc/codecs/wcd9xxx-mbhc.h +4 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #define __WCD9XXX_MBHC_H__ #include "wcd9xxx-resmgr.h" #include "wcdcal-hwdep.h" #define WCD9XXX_CFILT_FAST_MODE 0x00 #define WCD9XXX_CFILT_SLOW_MODE 0x40 Loading Loading @@ -318,6 +319,8 @@ struct wcd9xxx_mbhc_cb { void (*micbias_pulldown_ctrl) (struct wcd9xxx_mbhc *, bool); int (*codec_rco_ctrl) (struct snd_soc_codec *, bool); void (*hph_auto_pulldown_ctrl) (struct snd_soc_codec *, bool); struct firmware_cal * (*get_hwdep_fw_cal) (struct snd_soc_codec *, enum wcd_cal_type); }; struct wcd9xxx_mbhc { Loading @@ -343,6 +346,7 @@ struct wcd9xxx_mbhc { /* Work to perform MBHC Firmware Read */ struct delayed_work mbhc_firmware_dwork; const struct firmware *mbhc_fw; struct firmware_cal *mbhc_cal; struct delayed_work mbhc_insert_dwork; Loading Loading
sound/soc/codecs/wcd9330.c +134 −43 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/tlv.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/pm_runtime.h> #include <linux/kernel.h> Loading @@ -38,6 +37,7 @@ #include "wcd9330.h" #include "wcd9xxx-resmgr.h" #include "wcd9xxx-common.h" #include "wcdcal-hwdep.h" #include "wcd_cpe_core.h" enum { Loading Loading @@ -517,6 +517,9 @@ struct tomtom_priv { u32 anc_slot; bool anc_func; /* cal info for codec */ struct fw_info *fw_data; /*track tomtom interface type*/ u8 intf_type; Loading Loading @@ -3212,28 +3215,56 @@ static int tomtom_codec_config_mad(struct snd_soc_codec *codec) { int ret; const struct firmware *fw; struct firmware_cal *hwdep_cal = NULL; struct mad_audio_cal *mad_cal; const void *data; const char *filename = TOMTOM_MAD_AUDIO_FIRMWARE_PATH; struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec); size_t cal_size; pr_debug("%s: enter\n", __func__); if (!tomtom->fw_data) { dev_err(codec->dev, "%s: invalid cal data\n", __func__); return -ENODEV; } hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, WCD9XXX_MAD_CAL); if (hwdep_cal) { data = hwdep_cal->data; cal_size = hwdep_cal->size; dev_dbg(codec->dev, "%s: using hwdep calibration\n", __func__); } else { ret = request_firmware(&fw, filename, codec->dev); if (ret != 0) { pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename, ret); pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename, ret); return -ENODEV; } if (fw->size < sizeof(struct mad_audio_cal)) { pr_err("%s: incorrect firmware size %zu\n", __func__, fw->size); release_firmware(fw); return -ENOMEM; if (!fw) { dev_err(codec->dev, "failed to get mad fw"); return -ENODEV; } data = fw->data; cal_size = fw->size; dev_dbg(codec->dev, "%s: using request_firmware calibration\n", __func__); } if (cal_size < sizeof(struct mad_audio_cal)) { pr_err("%s: incorrect hwdep cal size %zu\n", __func__, cal_size); ret = -ENOMEM; goto err; } mad_cal = (struct mad_audio_cal *)(fw->data); mad_cal = (struct mad_audio_cal *)(data); if (!mad_cal) { pr_err("%s: Invalid calibration data\n", __func__); release_firmware(fw); return -EINVAL; dev_err(codec->dev, "%s: Invalid calibration data\n", __func__); ret = -EINVAL; goto err; } snd_soc_write(codec, TOMTOM_A_CDC_MAD_MAIN_CTL_2, Loading Loading @@ -3283,13 +3314,13 @@ static int tomtom_codec_config_mad(struct snd_soc_codec *codec) snd_soc_write(codec, TOMTOM_A_CDC_MAD_ULTR_CTL_6, mad_cal->ultrasound_info.rms_threshold_msb); release_firmware(fw); /* Set MAD intr time to 20 msec */ snd_soc_update_bits(codec, 0x4E, 0x01F, 0x13); pr_debug("%s: leave ret %d\n", __func__, ret); err: if (!hwdep_cal) release_firmware(fw); return ret; } Loading Loading @@ -3896,17 +3927,19 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, const char *filename; const struct firmware *fw; int i; int ret; int ret = 0; int num_anc_slots; struct wcd9xxx_anc_header *anc_head; struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec); struct firmware_cal *hwdep_cal = NULL; u32 anc_writes_size = 0; u32 anc_cal_size = 0; int anc_size_remaining; u32 *anc_ptr; u16 reg; u8 mask, val, old_val; size_t cal_size; const void *data; if (tomtom->anc_func == 0) return 0; Loading @@ -3915,37 +3948,51 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: filename = "wcd9320/wcd9320_anc.bin"; hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, WCD9XXX_ANC_CAL); if (hwdep_cal) { data = hwdep_cal->data; cal_size = hwdep_cal->size; dev_dbg(codec->dev, "%s: using hwdep calibration\n", __func__); } else { ret = request_firmware(&fw, filename, codec->dev); if (ret != 0) { dev_err(codec->dev, "Failed to acquire ANC data: %d\n", ret); return -ENODEV; } if (fw->size < sizeof(struct wcd9xxx_anc_header)) { if (!fw) { dev_err(codec->dev, "failed to get anc fw"); return -ENODEV; } data = fw->data; cal_size = fw->size; dev_dbg(codec->dev, "%s: using request_firmware calibration\n", __func__); } if (cal_size < sizeof(struct wcd9xxx_anc_header)) { dev_err(codec->dev, "Not enough data\n"); release_firmware(fw); return -ENOMEM; ret = -ENOMEM; goto err; } /* First number is the number of register writes */ anc_head = (struct wcd9xxx_anc_header *)(fw->data); anc_ptr = (u32 *)(fw->data + anc_head = (struct wcd9xxx_anc_header *)(data); anc_ptr = (u32 *)(data + sizeof(struct wcd9xxx_anc_header)); anc_size_remaining = fw->size - anc_size_remaining = cal_size - sizeof(struct wcd9xxx_anc_header); num_anc_slots = anc_head->num_anc_slots; if (tomtom->anc_slot >= num_anc_slots) { dev_err(codec->dev, "Invalid ANC slot selected\n"); release_firmware(fw); return -EINVAL; ret = -EINVAL; goto err; } for (i = 0; i < num_anc_slots; i++) { if (anc_size_remaining < TOMTOM_PACKED_REG_SIZE) { dev_err(codec->dev, "Invalid register format\n"); release_firmware(fw); return -EINVAL; ret = -EINVAL; goto err; } anc_writes_size = (u32)(*anc_ptr); anc_size_remaining -= sizeof(u32); Loading @@ -3954,8 +4001,8 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, if (anc_writes_size * TOMTOM_PACKED_REG_SIZE > anc_size_remaining) { dev_err(codec->dev, "Invalid register format\n"); release_firmware(fw); return -ENOMEM; ret = -EINVAL; goto err; } if (tomtom->anc_slot == i) Loading @@ -3967,8 +4014,8 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, } if (i == num_anc_slots) { dev_err(codec->dev, "Selected ANC slot not present\n"); release_firmware(fw); return -ENOMEM; ret = -EINVAL; goto err; } i = 0; Loading Loading @@ -4010,6 +4057,7 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, if (w->reg == TOMTOM_A_RX_HPH_R_DAC_CTL) snd_soc_update_bits(codec, TOMTOM_A_CDC_CLK_ANC_RESET_CTL, 0x0C, 0x00); if (!hwdep_cal) release_firmware(fw); break; case SND_SOC_DAPM_PRE_PMD: Loading @@ -4025,6 +4073,10 @@ static int tomtom_codec_enable_anc(struct snd_soc_dapm_widget *w, break; } return 0; err: if (!hwdep_cal) release_firmware(fw); return ret; } static int tomtom_hphl_dac_event(struct snd_soc_dapm_widget *w, Loading Loading @@ -7536,6 +7588,27 @@ static void tomtom_cleanup_irqs(struct tomtom_priv *tomtom) wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tomtom); } static struct firmware_cal *tomtom_get_hwdep_fw_cal(struct snd_soc_codec *codec, enum wcd_cal_type type) { struct tomtom_priv *tomtom; struct firmware_cal *hwdep_cal; if (!codec) { pr_err("%s: NULL codec pointer\n", __func__); return NULL; } tomtom = snd_soc_codec_get_drvdata(codec); hwdep_cal = wcdcal_get_fw_cal(tomtom->fw_data, type); if (!hwdep_cal) { dev_err(codec->dev, "%s: cal not sent by %d\n", __func__, type); return NULL; } else { return hwdep_cal; } } int tomtom_hs_detect(struct snd_soc_codec *codec, struct wcd9xxx_mbhc_config *mbhc_cfg) { Loading Loading @@ -8123,6 +8196,7 @@ static const struct wcd9xxx_mbhc_cb mbhc_cb = { .micbias_pulldown_ctrl = tomtom_mbhc_micb_pulldown_ctrl, .codec_rco_ctrl = tomtom_codec_internal_rco_ctrl, .hph_auto_pulldown_ctrl = tomtom_codec_hph_auto_pull_down, .get_hwdep_fw_cal = tomtom_get_hwdep_fw_cal, }; static const struct wcd9xxx_mbhc_intr cdc_intr_ids = { Loading Loading @@ -8417,6 +8491,21 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ; tomtom->fw_data = kzalloc(sizeof(*(tomtom->fw_data)), GFP_KERNEL); if (!tomtom->fw_data) { dev_err(codec->dev, "Failed to allocate fw_data\n"); goto err_nomem_slimch; } set_bit(WCD9XXX_ANC_CAL, tomtom->fw_data->cal_bit); set_bit(WCD9XXX_MAD_CAL, tomtom->fw_data->cal_bit); set_bit(WCD9XXX_MBHC_CAL, tomtom->fw_data->cal_bit); ret = wcd_cal_create_hwdep(tomtom->fw_data, WCD9XXX_CODEC_HWDEP_NODE, codec); if (ret < 0) { dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret); goto err_hwdep; } /* init and start mbhc */ ret = wcd9xxx_mbhc_init(&tomtom->mbhc, &tomtom->resmgr, codec, tomtom_enable_mbhc_micbias, Loading @@ -8424,7 +8513,7 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) rco_clk_rate, TOMTOM_ZDET_SUPPORTED); if (ret) { pr_err("%s: mbhc init failed %d\n", __func__, ret); goto err_nomem_slimch; goto err_hwdep; } tomtom->codec = codec; Loading @@ -8449,7 +8538,7 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) ret = tomtom_handle_pdata(tomtom); if (IS_ERR_VALUE(ret)) { pr_err("%s: bad pdata\n", __func__); goto err_nomem_slimch; goto err_hwdep; } tomtom->spkdrv_reg = tomtom_codec_find_regulator(codec, Loading @@ -8462,7 +8551,7 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) if (!ptr) { pr_err("%s: no mem for slim chan ctl data\n", __func__); ret = -ENOMEM; goto err_nomem_slimch; goto err_hwdep; } if (tomtom->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) { Loading Loading @@ -8536,6 +8625,8 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) err_pdata: kfree(ptr); err_hwdep: kfree(tomtom->fw_data); err_nomem_slimch: devm_kfree(codec->dev, tomtom); return ret; Loading
sound/soc/codecs/wcd9xxx-mbhc.c +76 −33 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ #include "wcd9320.h" #include "wcd9306.h" #include "wcd9xxx-mbhc.h" #include "wcdcal-hwdep.h" #include "wcd9xxx-resmgr.h" #include "wcd9xxx-common.h" Loading Loading @@ -74,7 +75,7 @@ #define OCP_ATTEMPT 1 #define FW_READ_ATTEMPTS 15 #define FW_READ_TIMEOUT 2000000 #define FW_READ_TIMEOUT 4000000 #define BUTTON_POLLING_SUPPORTED true Loading Loading @@ -2893,35 +2894,39 @@ static void wcd9xxx_mbhc_insert_work(struct work_struct *work) wcd9xxx_unlock_sleep(core_res); } static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw) static bool wcd9xxx_mbhc_fw_validate(const void *data, size_t size) { u32 cfg_offset; struct wcd9xxx_mbhc_imped_detect_cfg *imped_cfg; struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg; struct firmware_cal fw; if (fw->size < WCD9XXX_MBHC_CAL_MIN_SIZE) fw.data = (void *)data; fw.size = size; if (fw.size < WCD9XXX_MBHC_CAL_MIN_SIZE) return false; /* * Previous check guarantees that there is enough fw data up * to num_btn */ btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw->data); cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data); if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg))) btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw.data); cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data); if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg))) return false; /* * Previous check guarantees that there is enough fw data up * to start of impedance detection configuration */ imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw->data); cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data); imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw.data); cfg_offset = (u32) ((void *) imped_cfg - (void *) fw.data); if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ)) if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ)) return false; if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg))) if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg))) return false; return true; Loading Loading @@ -4279,7 +4284,9 @@ static void wcd9xxx_mbhc_fw_read(struct work_struct *work) struct wcd9xxx_mbhc *mbhc; struct snd_soc_codec *codec; const struct firmware *fw; struct firmware_cal *fw_data = NULL; int ret = -1, retry = 0; bool use_default_cal = false; dwork = to_delayed_work(work); mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_firmware_dwork); Loading @@ -4289,29 +4296,62 @@ static void wcd9xxx_mbhc_fw_read(struct work_struct *work) retry++; pr_info("%s:Attempt %d to request MBHC firmware\n", __func__, retry); if (mbhc->mbhc_cb->get_hwdep_fw_cal) fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(codec, WCD9XXX_MBHC_CAL); if (!fw_data) ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin", codec->dev); if (ret != 0) { /* * if request_firmware and hwdep cal both fail then * retry for few times before bailing out */ if ((ret != 0) && !fw_data) { usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT + WCD9XXX_USLEEP_RANGE_MARGIN_US); } else { pr_info("%s: MBHC Firmware read succesful\n", __func__); pr_info("%s: MBHC Firmware read succesful\n", __func__); break; } } if (ret != 0) { if (!fw_data) pr_info("%s: using request_firmware\n", __func__); else pr_info("%s: using hwdep cal\n", __func__); if (ret != 0 && !fw_data) { pr_err("%s: Cannot load MBHC firmware use default cal\n", __func__); } else if (wcd9xxx_mbhc_fw_validate(fw) == false) { use_default_cal = true; } if (!use_default_cal) { const void *data; size_t size; if (fw_data) { data = fw_data->data; size = fw_data->size; } else { data = fw->data; size = fw->size; } if (wcd9xxx_mbhc_fw_validate(data, size) == false) { pr_err("%s: Invalid MBHC cal data size use default cal\n", __func__); if (!fw_data) release_firmware(fw); } else { mbhc->mbhc_cfg->calibration = (void *)fw->data; if (fw_data) { mbhc->mbhc_cfg->calibration = (void *)fw_data->data; mbhc->mbhc_cal = fw_data; } else { mbhc->mbhc_cfg->calibration = (void *)fw->data; mbhc->mbhc_fw = fw; } } } (void) wcd9xxx_init_and_calibrate(mbhc); } Loading Loading @@ -4500,15 +4540,16 @@ int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc, mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true); if (!mbhc->mbhc_cfg->read_fw_bin || (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw)) { (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) || (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) { rc = wcd9xxx_init_and_calibrate(mbhc); } else { if (!mbhc->mbhc_fw) if (!mbhc->mbhc_fw || !mbhc->mbhc_cal) schedule_delayed_work(&mbhc->mbhc_firmware_dwork, usecs_to_jiffies(FW_READ_TIMEOUT)); else pr_debug("%s: Skipping to read mbhc fw, 0x%p\n", __func__, mbhc->mbhc_fw); pr_debug("%s: Skipping to read mbhc fw, 0x%p %p\n", __func__, mbhc->mbhc_fw, mbhc->mbhc_cal); } pr_debug("%s: leave %d\n", __func__, rc); Loading @@ -4518,10 +4559,12 @@ EXPORT_SYMBOL(wcd9xxx_mbhc_start); void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc) { if (mbhc->mbhc_fw) { if (mbhc->mbhc_fw || mbhc->mbhc_cal) { cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork); if (!mbhc->mbhc_cal) release_firmware(mbhc->mbhc_fw); mbhc->mbhc_fw = NULL; mbhc->mbhc_cal = NULL; } } EXPORT_SYMBOL(wcd9xxx_mbhc_stop); Loading
sound/soc/codecs/wcd9xxx-mbhc.h +4 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #define __WCD9XXX_MBHC_H__ #include "wcd9xxx-resmgr.h" #include "wcdcal-hwdep.h" #define WCD9XXX_CFILT_FAST_MODE 0x00 #define WCD9XXX_CFILT_SLOW_MODE 0x40 Loading Loading @@ -318,6 +319,8 @@ struct wcd9xxx_mbhc_cb { void (*micbias_pulldown_ctrl) (struct wcd9xxx_mbhc *, bool); int (*codec_rco_ctrl) (struct snd_soc_codec *, bool); void (*hph_auto_pulldown_ctrl) (struct snd_soc_codec *, bool); struct firmware_cal * (*get_hwdep_fw_cal) (struct snd_soc_codec *, enum wcd_cal_type); }; struct wcd9xxx_mbhc { Loading @@ -343,6 +346,7 @@ struct wcd9xxx_mbhc { /* Work to perform MBHC Firmware Read */ struct delayed_work mbhc_firmware_dwork; const struct firmware *mbhc_fw; struct firmware_cal *mbhc_cal; struct delayed_work mbhc_insert_dwork; Loading