summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter Yang <yandongy@codeaurora.org>2016-08-26 20:25:36 +0800
committerWalter Yang <yandongy@codeaurora.org>2016-09-14 08:11:38 +0800
commit24bf042aefd0c438db56fea9e1059f1c58d6acd3 (patch)
tree9f0c3e6258bb90b551fb2a3ed7100d84b88d4839
parent9b82a4c5896632b62140d1ddda55638fea254007 (diff)
ASoC: wcd934x: Add codec version check for wcd934x
As there are many hardware version of wcd934x codec. Add version check in the code so that userspace can get the version info. CRs-Fixed: 1063367 Change-Id: Ia320380d568426c2d7a414a832980a556ff27f0f Signed-off-by: Walter Yang <yandongy@codeaurora.org>
-rw-r--r--include/linux/mfd/wcd9xxx/core.h34
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c176
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.h9
3 files changed, 204 insertions, 15 deletions
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index f595275e9d42..e545d8d55a33 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -60,6 +60,40 @@
#define TASHA_IS_2_0(ver) \
((ver == TASHA_VERSION_2_0) ? 1 : 0)
+/*
+ * As fine version info cannot be retrieved before tavil probe.
+ * Define three coarse versions for possible future use before tavil probe.
+ */
+#define TAVIL_VERSION_1_0 0
+#define TAVIL_VERSION_1_1 1
+#define TAVIL_VERSION_WCD9340_1_0 2
+#define TAVIL_VERSION_WCD9341_1_0 3
+#define TAVIL_VERSION_WCD9340_1_1 4
+#define TAVIL_VERSION_WCD9341_1_1 5
+
+#define TAVIL_IS_1_0(wcd) \
+ ((wcd->type == WCD934X) ? \
+ ((wcd->version == TAVIL_VERSION_1_0 || \
+ wcd->version == TAVIL_VERSION_WCD9340_1_0 || \
+ wcd->version == TAVIL_VERSION_WCD9341_1_0) ? 1 : 0) : 0)
+#define TAVIL_IS_1_1(wcd) \
+ ((wcd->type == WCD934X) ? \
+ ((wcd->version == TAVIL_VERSION_1_1 || \
+ wcd->version == TAVIL_VERSION_WCD9340_1_1 || \
+ wcd->version == TAVIL_VERSION_WCD9341_1_1) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9340_1_0(wcd) \
+ ((wcd->type == WCD934X) ? \
+ ((wcd->version == TAVIL_VERSION_WCD9340_1_0) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9341_1_0(wcd) \
+ ((wcd->type == WCD934X) ? \
+ ((wcd->version == TAVIL_VERSION_WCD9341_1_0) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9340_1_1(wcd) \
+ ((wcd->type == WCD934X) ? \
+ ((wcd->version == TAVIL_VERSION_WCD9340_1_1) ? 1 : 0) : 0)
+#define TAVIL_IS_WCD9341_1_1(wcd) \
+ ((wcd->type == WCD934X) ? \
+ ((wcd->version == TAVIL_VERSION_WCD9341_1_1) ? 1 : 0) : 0)
+
#define IS_CODEC_TYPE(wcd, wcdtype) \
((wcd->type == wcdtype) ? true : false)
#define IS_CODEC_VERSION(wcd, wcdversion) \
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 84e5c09494c6..e425c1ba3896 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -129,6 +129,8 @@ static const struct snd_kcontrol_new name##_mux = \
#define WCD934X_MAD_AUDIO_FIRMWARE_PATH "wcd934x/wcd934x_mad_audio.bin"
+#define TAVIL_VERSION_ENTRY_SIZE 17
+
enum {
VI_SENSE_1,
VI_SENSE_2,
@@ -494,6 +496,10 @@ struct tavil_priv {
/* cal info for codec */
struct fw_info *fw_data;
+ /* Entry for version info */
+ struct snd_info_entry *entry;
+ struct snd_info_entry *version_entry;
+
/* SVS voting related */
struct mutex svs_mutex;
int svs_ref_cnt;
@@ -537,7 +543,7 @@ int wcd934x_get_codec_info(struct wcd9xxx *wcd9xxx,
{
u16 id_minor, id_major;
struct regmap *wcd_regmap;
- int rc, version = 0;
+ int rc, version = -1;
if (!wcd9xxx || !wcd_type)
return -EINVAL;
@@ -561,8 +567,22 @@ int wcd934x_get_codec_info(struct wcd9xxx *wcd9xxx,
dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
__func__, id_major, id_minor);
- /* Version detection */
- version = 1.0;
+ if (id_major != TAVIL_MAJOR)
+ goto version_unknown;
+
+ /*
+ * As fine version info cannot be retrieved before tavil probe.
+ * Assign coarse versions for possible future use before tavil probe.
+ */
+ if (id_minor == cpu_to_le16(0))
+ version = TAVIL_VERSION_1_0;
+ else if (id_minor == cpu_to_le16(0x01))
+ version = TAVIL_VERSION_1_1;
+
+version_unknown:
+ if (version < 0)
+ dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n",
+ __func__);
/* Fill codec type info */
wcd_type->id_major = id_major;
@@ -6222,6 +6242,104 @@ static int __tavil_cdc_mclk_enable(struct tavil_priv *tavil,
return ret;
}
+static ssize_t tavil_codec_version_read(struct snd_info_entry *entry,
+ void *file_private_data,
+ struct file *file,
+ char __user *buf, size_t count,
+ loff_t pos)
+{
+ struct tavil_priv *tavil;
+ struct wcd9xxx *wcd9xxx;
+ char buffer[TAVIL_VERSION_ENTRY_SIZE];
+ int len = 0;
+
+ tavil = (struct tavil_priv *) entry->private_data;
+ if (!tavil) {
+ pr_err("%s: tavil priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ wcd9xxx = tavil->wcd9xxx;
+
+ switch (wcd9xxx->version) {
+ case TAVIL_VERSION_WCD9340_1_0:
+ len = snprintf(buffer, sizeof(buffer), "WCD9340_1_0\n");
+ break;
+ case TAVIL_VERSION_WCD9341_1_0:
+ len = snprintf(buffer, sizeof(buffer), "WCD9341_1_0\n");
+ break;
+ case TAVIL_VERSION_WCD9340_1_1:
+ len = snprintf(buffer, sizeof(buffer), "WCD9340_1_1\n");
+ break;
+ case TAVIL_VERSION_WCD9341_1_1:
+ len = snprintf(buffer, sizeof(buffer), "WCD9341_1_1\n");
+ break;
+ default:
+ len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
+ }
+
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static struct snd_info_entry_ops tavil_codec_info_ops = {
+ .read = tavil_codec_version_read,
+};
+
+/*
+ * tavil_codec_info_create_codec_entry - creates wcd934x module
+ * @codec_root: The parent directory
+ * @codec: Codec instance
+ *
+ * Creates wcd934x module and version entry under the given
+ * parent directory.
+ *
+ * Return: 0 on success or negative error code on failure.
+ */
+int tavil_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
+ struct snd_soc_codec *codec)
+{
+ struct snd_info_entry *version_entry;
+ struct tavil_priv *tavil;
+ struct snd_soc_card *card;
+
+ if (!codec_root || !codec)
+ return -EINVAL;
+
+ tavil = snd_soc_codec_get_drvdata(codec);
+ card = codec->component.card;
+ tavil->entry = snd_register_module_info(codec_root->module,
+ "tavil",
+ codec_root);
+ if (!tavil->entry) {
+ dev_dbg(codec->dev, "%s: failed to create wcd934x entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry = snd_info_create_card_entry(card->snd_card,
+ "version",
+ tavil->entry);
+ if (!version_entry) {
+ dev_dbg(codec->dev, "%s: failed to create wcd934x version entry\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ version_entry->private_data = tavil;
+ version_entry->size = TAVIL_VERSION_ENTRY_SIZE;
+ version_entry->content = SNDRV_INFO_CONTENT_DATA;
+ version_entry->c.ops = &tavil_codec_info_ops;
+
+ if (snd_info_register(version_entry) < 0) {
+ snd_info_free_entry(version_entry);
+ return -ENOMEM;
+ }
+ tavil->version_entry = version_entry;
+
+ return 0;
+}
+EXPORT_SYMBOL(tavil_codec_info_create_codec_entry);
+
/**
* tavil_cdc_mclk_enable - Enable/disable codec mclk
*
@@ -7433,6 +7551,45 @@ static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
return rc;
}
+static void ___tavil_get_codec_fine_version(struct tavil_priv *tavil)
+{
+ int val1, val2, version;
+ struct regmap *regmap;
+ u16 id_minor;
+ u32 version_mask = 0;
+
+ regmap = tavil->wcd9xxx->regmap;
+ version = tavil->wcd9xxx->version;
+ id_minor = tavil->wcd9xxx->codec_type->id_minor;
+
+ regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1);
+ regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2);
+
+ dev_dbg(tavil->dev, "%s: chip version :0x%x 0x:%x\n",
+ __func__, val1, val2);
+
+ version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK;
+ version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK;
+
+ switch (version_mask) {
+ case DSD_DISABLED | SLNQ_DISABLED:
+ if (id_minor == cpu_to_le16(0))
+ version = TAVIL_VERSION_WCD9340_1_0;
+ else if (id_minor == cpu_to_le16(0x01))
+ version = TAVIL_VERSION_WCD9340_1_1;
+ break;
+ case SLNQ_DISABLED:
+ if (id_minor == cpu_to_le16(0))
+ version = TAVIL_VERSION_WCD9341_1_0;
+ else if (id_minor == cpu_to_le16(0x01))
+ version = TAVIL_VERSION_WCD9341_1_1;
+ break;
+ }
+
+ tavil->wcd9xxx->version = version;
+ tavil->wcd9xxx->codec_type->version = version;
+}
+
/*
* tavil_get_wcd_dsp_cntl: Get the reference to wcd_dsp_cntl
* @dev: Device pointer for codec device
@@ -7462,7 +7619,6 @@ static int tavil_probe(struct platform_device *pdev)
struct tavil_priv *tavil;
struct clk *wcd_ext_clk;
struct wcd9xxx_resmgr_v2 *resmgr;
- int val1, val2, val3, val4;
tavil = devm_kzalloc(&pdev->dev, sizeof(struct tavil_priv),
GFP_KERNEL);
@@ -7530,17 +7686,7 @@ static int tavil_probe(struct platform_device *pdev)
0x03, 0x01);
tavil_update_reg_defaults(tavil);
__tavil_enable_efuse_sensing(tavil);
-
- regmap_read(tavil->wcd9xxx->regmap,
- WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val1);
- regmap_read(tavil->wcd9xxx->regmap,
- WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val2);
- regmap_read(tavil->wcd9xxx->regmap,
- WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val3);
- regmap_read(tavil->wcd9xxx->regmap,
- WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9, &val4);
- dev_dbg(&pdev->dev, "%s: chip version :0x%x 0x:%x 0x:%x 0x:%x\n",
- __func__, val1, val2, val3, val4);
+ ___tavil_get_codec_fine_version(tavil);
/* Register with soc framework */
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tavil,
diff --git a/sound/soc/codecs/wcd934x/wcd934x.h b/sound/soc/codecs/wcd934x/wcd934x.h
index 9cffa168c298..f65068a9a245 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.h
+++ b/sound/soc/codecs/wcd934x/wcd934x.h
@@ -39,6 +39,13 @@
/* Convert from vout ctl to micbias voltage in mV */
#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50)
+/* Feature masks to distinguish codec version */
+#define DSD_DISABLED_MASK 0
+#define SLNQ_DISABLED_MASK 1
+
+#define DSD_DISABLED (1 << DSD_DISABLED_MASK)
+#define SLNQ_DISABLED (1 << SLNQ_DISABLED_MASK)
+
/* Number of input and output Slimbus port */
enum {
WCD934X_RX0 = 0,
@@ -180,4 +187,6 @@ extern struct wcd934x_mbhc *tavil_soc_get_mbhc(struct snd_soc_codec *codec);
extern int tavil_codec_enable_interp_clk(struct snd_soc_codec *codec,
int event, int intp_idx);
extern struct tavil_dsd_config *tavil_get_dsd_config(struct snd_soc_codec *);
+extern int tavil_codec_info_create_codec_entry(struct snd_info_entry *,
+ struct snd_soc_codec *);
#endif