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

Commit 80507977 authored by Anish Kumar's avatar Anish Kumar Committed by Yeleswarapu Nagaradhesh
Browse files

ASoC: wcd9306: use hwdep nodes to get calibration



Use hwdep node to use calibration and at the same
time keep the code backward compatible. Codec
driver can still use request_firmware to get the
calibration if hwdep is not available.

Change-Id: Iea2cf1ff753a5750919b201ded63cd8840a40baf
Signed-off-by: default avatarYeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
parent e143b669
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -68,7 +68,7 @@ snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-wcd9320-objs := wcd9320.o wcd9320-tables.o
snd-soc-wcd9320-objs := wcd9320.o wcd9320-tables.o
snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o wcdcal-hwdep.o
snd-soc-wcd9330-objs := wcd9330.o wcd9330-tables.o wcdcal-hwdep.o
snd-soc-wcd9330-objs := wcd9330.o wcd9330-tables.o wcdcal-hwdep.o
snd-soc-wcd9xxx-objs := wcd9xxx-resmgr.o wcd9xxx-mbhc.o wcd9xxx-common.o
snd-soc-wcd9xxx-objs := wcd9xxx-resmgr.o wcd9xxx-mbhc.o wcd9xxx-common.o
snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o wcd9xxx-common.o
snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o wcd9xxx-common.o
+88 −24
Original line number Original line Diff line number Diff line
@@ -19,7 +19,6 @@
#include <linux/ratelimit.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
#include <linux/debugfs.h>
#include <linux/wait.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9306_registers.h>
#include <linux/mfd/wcd9xxx/wcd9306_registers.h>
@@ -38,6 +37,7 @@
#include "wcd9306.h"
#include "wcd9306.h"
#include "wcd9xxx-resmgr.h"
#include "wcd9xxx-resmgr.h"
#include "wcd9xxx-common.h"
#include "wcd9xxx-common.h"
#include "wcdcal-hwdep.h"


#define TAPAN_HPH_PA_SETTLE_COMP_ON 5000
#define TAPAN_HPH_PA_SETTLE_COMP_ON 5000
#define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
#define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
@@ -291,6 +291,9 @@ struct tapan_priv {
	u32 anc_slot;
	u32 anc_slot;
	bool anc_func;
	bool anc_func;


	/* cal info for codec */
	struct fw_info *fw_data;

	/*track adie loopback mode*/
	/*track adie loopback mode*/
	bool lb_mode;
	bool lb_mode;


@@ -2245,15 +2248,18 @@ static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
	const char *filename;
	const char *filename;
	const struct firmware *fw;
	const struct firmware *fw;
	int i;
	int i;
	int ret;
	int ret = 0;
	int num_anc_slots;
	int num_anc_slots;
	struct wcd9xxx_anc_header *anc_head;
	struct wcd9xxx_anc_header *anc_head;
	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
	struct firmware_cal *hwdep_cal = NULL;
	u32 anc_writes_size = 0;
	u32 anc_writes_size = 0;
	int anc_size_remaining;
	int anc_size_remaining;
	u32 *anc_ptr;
	u32 *anc_ptr;
	u16 reg;
	u16 reg;
	u8 mask, val, old_val;
	u8 mask, val, old_val;
	size_t cal_size;
	const void *data;


	dev_dbg(codec->dev, "%s %d\n", __func__, event);
	dev_dbg(codec->dev, "%s %d\n", __func__, event);
	if (tapan->anc_func == 0)
	if (tapan->anc_func == 0)
@@ -2263,39 +2269,54 @@ static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,


		filename = "wcd9306/wcd9306_anc.bin";
		filename = "wcd9306/wcd9306_anc.bin";


		hwdep_cal = wcdcal_get_fw_cal(tapan->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);
			ret = request_firmware(&fw, filename, codec->dev);
			if (ret != 0) {
			if (ret != 0) {
				dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
				dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
					ret);
					ret);
				return -ENODEV;
				return -ENODEV;
			}
			}

			if (!fw) {
		if (fw->size < sizeof(struct wcd9xxx_anc_header)) {
				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");
			dev_err(codec->dev, "Not enough data\n");
			release_firmware(fw);
			ret = -ENOMEM;
			return -ENOMEM;
			goto err;
		}
		}


		/* First number is the number of register writes */
		/* First number is the number of register writes */
		anc_head = (struct wcd9xxx_anc_header *)(fw->data);
		anc_head = (struct wcd9xxx_anc_header *)(data);
		anc_ptr = (u32 *)(fw->data +
		anc_ptr = (u32 *)(data +
				  sizeof(struct wcd9xxx_anc_header));
				  sizeof(struct wcd9xxx_anc_header));
		anc_size_remaining = fw->size -
		anc_size_remaining = cal_size -
				     sizeof(struct wcd9xxx_anc_header);
				     sizeof(struct wcd9xxx_anc_header);
		num_anc_slots = anc_head->num_anc_slots;
		num_anc_slots = anc_head->num_anc_slots;


		if (tapan->anc_slot >= num_anc_slots) {
		if (tapan->anc_slot >= num_anc_slots) {
			dev_err(codec->dev, "Invalid ANC slot selected\n");
			dev_err(codec->dev, "Invalid ANC slot selected\n");
			release_firmware(fw);
			ret = -EINVAL;
			return -EINVAL;
			goto err;
		}
		}


		for (i = 0; i < num_anc_slots; i++) {
		for (i = 0; i < num_anc_slots; i++) {


			if (anc_size_remaining < TAPAN_PACKED_REG_SIZE) {
			if (anc_size_remaining < TAPAN_PACKED_REG_SIZE) {
				dev_err(codec->dev, "Invalid register format\n");
				dev_err(codec->dev, "Invalid register format\n");
				release_firmware(fw);
				ret = -EINVAL;
				return -EINVAL;
				goto err;
			}
			}
			anc_writes_size = (u32)(*anc_ptr);
			anc_writes_size = (u32)(*anc_ptr);
			anc_size_remaining -= sizeof(u32);
			anc_size_remaining -= sizeof(u32);
@@ -2304,8 +2325,8 @@ static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
			if (anc_writes_size * TAPAN_PACKED_REG_SIZE
			if (anc_writes_size * TAPAN_PACKED_REG_SIZE
				> anc_size_remaining) {
				> anc_size_remaining) {
				dev_err(codec->dev, "Invalid register format\n");
				dev_err(codec->dev, "Invalid register format\n");
				release_firmware(fw);
				ret = -EINVAL;
				return -ENOMEM;
				goto err;
			}
			}


			if (tapan->anc_slot == i)
			if (tapan->anc_slot == i)
@@ -2317,8 +2338,8 @@ static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
		}
		}
		if (i == num_anc_slots) {
		if (i == num_anc_slots) {
			dev_err(codec->dev, "Selected ANC slot not present\n");
			dev_err(codec->dev, "Selected ANC slot not present\n");
			release_firmware(fw);
			ret = -EINVAL;
			return -ENOMEM;
			goto err;
		}
		}


		for (i = 0; i < anc_writes_size; i++) {
		for (i = 0; i < anc_writes_size; i++) {
@@ -2328,6 +2349,7 @@ static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
			snd_soc_write(codec, reg, (old_val & ~mask) |
			snd_soc_write(codec, reg, (old_val & ~mask) |
					(val & mask));
					(val & mask));
		}
		}
		if (!hwdep_cal)
			release_firmware(fw);
			release_firmware(fw);


		break;
		break;
@@ -2342,6 +2364,10 @@ static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
		break;
		break;
	}
	}
	return 0;
	return 0;
err:
	if (!hwdep_cal)
		release_firmware(fw);
	return ret;
}
}


static int tapan_codec_enable_micbias(struct snd_soc_dapm_widget *w,
static int tapan_codec_enable_micbias(struct snd_soc_dapm_widget *w,
@@ -6037,6 +6063,26 @@ static void tapan_compute_impedance(struct wcd9xxx_mbhc *mbhc, s16 *l, s16 *r,
	*zr = rr;
	*zr = rr;
}
}


static struct firmware_cal *tapan_get_hwdep_fw_cal(struct snd_soc_codec *codec,
		enum wcd_cal_type type)
{
	struct tapan_priv *tapan;
	struct firmware_cal *hwdep_cal;
	if (!codec) {
		pr_err("%s: NULL codec pointer\n", __func__);
		return NULL;
	}
	tapan = snd_soc_codec_get_drvdata(codec);
	hwdep_cal = wcdcal_get_fw_cal(tapan->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;
	}
}

static const struct wcd9xxx_mbhc_cb mbhc_cb = {
static const struct wcd9xxx_mbhc_cb mbhc_cb = {
	.enable_mux_bias_block = tapan_enable_mux_bias_block,
	.enable_mux_bias_block = tapan_enable_mux_bias_block,
	.cfilt_fast_mode = tapan_put_cfilt_fast_mode,
	.cfilt_fast_mode = tapan_put_cfilt_fast_mode,
@@ -6046,6 +6092,7 @@ static const struct wcd9xxx_mbhc_cb mbhc_cb = {
	.get_cdc_type = tapan_get_cdc_type,
	.get_cdc_type = tapan_get_cdc_type,
	.setup_zdet = tapan_setup_zdet,
	.setup_zdet = tapan_setup_zdet,
	.compute_impedance = tapan_compute_impedance,
	.compute_impedance = tapan_compute_impedance,
	.get_hwdep_fw_cal = tapan_get_hwdep_fw_cal,
};
};


int tapan_hs_detect(struct snd_soc_codec *codec,
int tapan_hs_detect(struct snd_soc_codec *codec,
@@ -6380,6 +6427,21 @@ static int tapan_codec_probe(struct snd_soc_codec *codec)
	else
	else
		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;



	tapan->fw_data = kzalloc(sizeof(*(tapan->fw_data)), GFP_KERNEL);
	if (!tapan->fw_data) {
		dev_err(codec->dev, "Failed to allocate fw_data\n");
		goto err_nomem_slimch;
	}
	set_bit(WCD9XXX_ANC_CAL, tapan->fw_data->cal_bit);
	set_bit(WCD9XXX_MAD_CAL, tapan->fw_data->cal_bit);
	set_bit(WCD9XXX_MBHC_CAL, tapan->fw_data->cal_bit);
	ret = wcd_cal_create_hwdep(tapan->fw_data,
				WCD9XXX_CODEC_HWDEP_NODE, codec);
	if (ret < 0) {
		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
		goto err_hwdep;
	}
	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
				tapan_enable_mbhc_micbias,
				tapan_enable_mbhc_micbias,
				&mbhc_cb, &cdc_intr_ids, rco_clk_rate,
				&mbhc_cb, &cdc_intr_ids, rco_clk_rate,
@@ -6425,7 +6487,7 @@ static int tapan_codec_probe(struct snd_soc_codec *codec)
	if (!ptr) {
	if (!ptr) {
		pr_err("%s: no mem for slim chan ctl data\n", __func__);
		pr_err("%s: no mem for slim chan ctl data\n", __func__);
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto err_nomem_slimch;
		goto err_hwdep;
	}
	}


	if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
	if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -6487,6 +6549,8 @@ static int tapan_codec_probe(struct snd_soc_codec *codec)


err_pdata:
err_pdata:
	kfree(ptr);
	kfree(ptr);
err_hwdep:
	kfree(tapan->fw_data);
err_nomem_slimch:
err_nomem_slimch:
	kfree(tapan);
	kfree(tapan);
	return ret;
	return ret;
+1 −0
Original line number Original line Diff line number Diff line
@@ -190,6 +190,7 @@ config SND_SOC_MSM8226
	select DOLBY_DAP
	select DOLBY_DAP
	select DTS_SRS_TM
	select DTS_SRS_TM
	select QTI_PP
	select QTI_PP
	select SND_HWDEP
	help
	help
	 To add support for SoC audio on MSM8226.
	 To add support for SoC audio on MSM8226.
	 This will enable sound soc drivers which
	 This will enable sound soc drivers which