Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e32fea6 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ASoC: wcd9330: use hwdep nodes to get calibration"

parents 9fa976d0 8508d9d4
Loading
Loading
Loading
Loading
+134 −43
Original line number Diff line number Diff line
@@ -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>
@@ -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 {
@@ -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;

@@ -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,
@@ -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;
}

@@ -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;
@@ -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);
@@ -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)
@@ -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;
@@ -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:
@@ -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,
@@ -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)
{
@@ -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 = {
@@ -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,
@@ -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;
@@ -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,
@@ -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) {
@@ -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;
+76 −33
Original line number Diff line number Diff line
@@ -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"

@@ -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

@@ -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;
@@ -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);
@@ -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);
}
@@ -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);
@@ -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);
+4 −0
Original line number Diff line number Diff line
@@ -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
@@ -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 {
@@ -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;