All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ASoC: Add max98371 codec driver
@ 2016-03-21  1:59 anish kumar
  2016-03-21 14:56 ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: anish kumar @ 2016-03-21  1:59 UTC (permalink / raw)
  To: broonie, lgirdwood; +Cc: alsa-devel, anish kumar

Signed-off-by: anish kumar <yesanishhere@gmail.com>
---
 .../devicetree/bindings/sound/max98371.txt         |  17 +
 sound/soc/codecs/max98371.c                        | 428 +++++++++++++++++++++
 sound/soc/codecs/max98371.h                        |  63 +++
 3 files changed, 508 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/max98371.txt
 create mode 100644 sound/soc/codecs/max98371.c
 create mode 100644 sound/soc/codecs/max98371.h

diff --git a/Documentation/devicetree/bindings/sound/max98371.txt b/Documentation/devicetree/bindings/sound/max98371.txt
new file mode 100644
index 0000000..6c28523
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/max98371.txt
@@ -0,0 +1,17 @@
+max98371 codec
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "maxim,max98371"
+- reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+	max98371: max98371@0x31 {
+		compatible = "maxim,max98371";
+		reg = <0x31>;
+	};
+};
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
new file mode 100644
index 0000000..1aba140
--- /dev/null
+++ b/sound/soc/codecs/max98371.c
@@ -0,0 +1,428 @@
+/*
+ * max98371.c -- ALSA SoC Stereo MAX98371 driver
+ *
+ * Copyright 2015-16 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98371.h"
+
+static const char *const monomix_text[] = {
+	"Left", "Right", "LeftRightDiv2",
+};
+
+static const char *const voltage_level_text[] = {
+	"9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
+	"13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
+	"18.5dB", "19.5dB", "20.5dB"
+};
+
+static const char *const hpf_cutoff_txt[] = {
+	"Disable", "DC Block", "50Hz",
+	"100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98371_voltage, MAX98371_GAIN, 0,
+		voltage_level_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0,
+		monomix_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0,
+		hpf_cutoff_txt);
+
+static struct reg_default max98371_reg[] = {
+	{ 0x01, 0x00 },
+	{ 0x02, 0x00 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0A, 0x00 },
+	{ 0x10, 0x06 },
+	{ 0x11, 0x08 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1C, 0x00 },
+	{ 0x1D, 0x00 },
+	{ 0x1E, 0x00 },
+	{ 0x1F, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2A, 0x00 },
+	{ 0x2B, 0x00 },
+	{ 0x2C, 0x00 },
+	{ 0x2D, 0x00 },
+	{ 0x2E, 0x0B },
+	{ 0x31, 0x00 },
+	{ 0x32, 0x18 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x00 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x00 },
+	{ 0x3A, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3C, 0x00 },
+	{ 0x3D, 0x00 },
+	{ 0x3E, 0x00 },
+	{ 0x3F, 0x00 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x42, 0x00 },
+	{ 0x43, 0x00 },
+	{ 0x4A, 0x00 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x4D, 0x00 },
+	{ 0x4E, 0x00 },
+	{ 0x50, 0x00 },
+	{ 0x51, 0x00 },
+	{ 0x55, 0x00 },
+	{ 0x58, 0x00 },
+	{ 0x59, 0x00 },
+	{ 0x5C, 0x00 },
+	{ 0xFF, 0x43 },
+};
+
+static bool max98371_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_IRQ_CLEAR1:
+	case MAX98371_IRQ_CLEAR2:
+	case MAX98371_IRQ_CLEAR3:
+	case MAX98371_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98371_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_SOFT_RESET:
+		return false;
+	default:
+		return true;
+	}
+};
+
+static const unsigned int max98371_gain_tlv[] = {
+	0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
+	9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
+	11, 15, TLV_DB_SCALE_ITEM(0, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1);
+
+static const struct snd_kcontrol_new max98371_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Gain", MAX98371_GAIN,
+			MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
+			max98371_gain_tlv),
+	SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0,
+			(1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv),
+	SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0),
+	SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0),
+	SOC_ENUM("Voltage Level", max98371_voltage),
+	SOC_ENUM("Monomix Select", max98371_monomix),
+	SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff),
+};
+
+static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(codec->dev, "DAI clock mode unsupported");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= 0;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= MAX98371_DAI_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= MAX98371_DAI_LEFT;
+		break;
+	default:
+		dev_err(codec->dev, "DAI wrong mode unsupported");
+		return -EINVAL;
+	}
+	regmap_update_bits(max98371->regmap, MAX98371_FMT,
+			MAX98371_FMT_MODE_MASK, val);
+	return 0;
+}
+
+static int max98371_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	int blr_clk_ratio, ch_size, channels = params_channels(params);
+	int rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 32;
+		break;
+	default:
+		pr_info("%s: format unsupported %d",
+				__func__, params_format(params));
+		return -EINVAL;
+	}
+
+	/* BCLK/LRCLK ratio calculation */
+	blr_clk_ratio = channels * ch_size;
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64);
+		break;
+	default:
+		pr_info("%s: ratio unsupported %d", __func__, blr_clk_ratio);
+		return -EINVAL;
+	}
+
+	switch (rate) {
+	case 32000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32);
+		break;
+	case 44100:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44);
+		break;
+	case 48000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48);
+		break;
+	case 88200:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88);
+		break;
+	case 96000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96);
+		break;
+	default:
+		pr_info("%s: rate unsupported %d", __func__, rate);
+		return -EINVAL;
+	}
+
+	/* enabling both the RX channels*/
+	regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC,
+			MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1);
+	regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL,
+			MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAI_OUT",
+		"HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Enable",
+		"HiFi Playback", MAX98371_SPK_ENABLE, 0, 0),
+	SND_SOC_DAPM_SUPPLY("Global Enable",
+		MAX98371_GLOBAL_ENABLE, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98371_audio_map[] = {
+	{"DAC Enable", NULL, "DAI_OUT"},
+	{"SPK_OUT", NULL, "DAC Enable"},
+	{"SPK_OUT", NULL, "Global Enable"},
+};
+
+#define MAX98371_RATES SNDRV_PCM_RATE_8000_48000
+#define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static struct snd_soc_dai_ops max98371_dai_ops = {
+	.set_fmt = max98371_dai_set_fmt,
+	.hw_params = max98371_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98371_dai[] = {
+	{
+		.name = "max98371-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98371_FORMATS,
+		},
+		.ops = &max98371_dai_ops,
+	}
+};
+
+static int max98371_probe(struct snd_soc_codec *codec)
+{
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+
+	max98371->codec = codec;
+	return 0;
+}
+
+static struct snd_soc_codec_driver max98371_codec = {
+	.probe = max98371_probe,
+	.controls = max98371_snd_controls,
+	.num_controls = ARRAY_SIZE(max98371_snd_controls),
+	.dapm_routes = max98371_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
+	.dapm_widgets = max98371_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+};
+
+static const struct regmap_config max98371_regmap = {
+	.reg_bits         = 8,
+	.val_bits         = 8,
+	.max_register     = MAX98371_VERSION,
+	.reg_defaults     = max98371_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98371_reg),
+	.volatile_reg     = max98371_volatile_register,
+	.readable_reg     = max98371_readable_register,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98371_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct max98371_priv *max98371;
+	int ret, reg;
+
+	max98371 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98371), GFP_KERNEL);
+	if (!max98371)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98371);
+	max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
+	if (IS_ERR(max98371->regmap)) {
+		ret = PTR_ERR(max98371->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
+	if (ret < 0) {
+		dev_info(&i2c->dev, "device error %d\n", ret);
+		return ret;
+	}
+	dev_info(&i2c->dev, "device version %x\n", reg);
+
+	ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
+			max98371_dai, ARRAY_SIZE(max98371_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int max98371_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id max98371_i2c_id[] = {
+	{ "max98371", 0 },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
+
+static const struct of_device_id max98371_of_match[] = {
+	{ .compatible = "maxim,max98371", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98371_of_match);
+
+static struct i2c_driver max98371_i2c_driver = {
+	.driver = {
+		.name = "max98371",
+		.owner = THIS_MODULE,
+		.pm = NULL,
+		.of_match_table = of_match_ptr(max98371_of_match),
+	},
+	.probe  = max98371_i2c_probe,
+	.remove = max98371_i2c_remove,
+	.id_table = max98371_i2c_id,
+};
+
+module_i2c_driver(max98371_i2c_driver);
+
+MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC MAX98371 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h
new file mode 100644
index 0000000..644316a
--- /dev/null
+++ b/sound/soc/codecs/max98371.h
@@ -0,0 +1,63 @@
+/*
+ * max98371.h -- MAX98371 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98371_H
+#define _MAX98371_H
+
+#define MAX98371_IRQ_CLEAR1			0x01
+#define MAX98371_IRQ_CLEAR2			0x02
+#define MAX98371_IRQ_CLEAR3			0x03
+#define MAX98371_DAI_CLK			0x10
+#define MAX98371_DAI_BSEL_MASK			0xF
+#define MAX98371_DAI_BSEL_32			2
+#define MAX98371_DAI_BSEL_48			3
+#define MAX98371_DAI_BSEL_64			4
+#define MAX98371_SPK_SR				0x11
+#define MAX98371_SPK_SR_MASK			0xF
+#define MAX98371_SPK_SR_32			6
+#define MAX98371_SPK_SR_44			7
+#define MAX98371_SPK_SR_48			8
+#define MAX98371_SPK_SR_88			10
+#define MAX98371_SPK_SR_96			11
+#define MAX98371_DAI_CHANNEL			0x15
+#define MAX98371_CHANNEL_MASK			0x3
+#define MAX98371_MONOMIX_SRC			0x18
+#define MAX98371_MONOMIX_CFG			0x19
+#define MAX98371_HPF				0x1C
+#define MAX98371_MONOMIX_SRC_MASK		0xFF
+#define MONOMIX_RX_0_1				((0x1)<<(4))
+#define M98371_DAI_CHANNEL_I2S			0x3
+#define MAX98371_DIGITAL_GAIN			0x2D
+#define MAX98371_DIGITAL_GAIN_WIDTH		0x7
+#define MAX98371_GAIN				0x2E
+#define MAX98371_GAIN_SHIFT			0x4
+#define MAX98371_GAIN_WIDTH			0x4
+#define MAX98371_FMT				0x14
+#define MAX98371_CHANSZ_WIDTH			6
+#define MAX98371_FMT_MASK		        ((0x3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_FMT_MODE_MASK		        ((0x7)<<(3))
+#define MAX98371_DAI_LEFT		        ((0x1)<<(3))
+#define MAX98371_DAI_RIGHT		        ((0x2)<<(3))
+#define MAX98371_DAI_CHANSZ_16                  ((1)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_24                  ((2)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_32                  ((3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DHT  0x32
+#define MAX98371_DHT_STEP			0x3
+#define MAX98371_SPK_ENABLE			0x4A
+#define MAX98371_GLOBAL_ENABLE			0x50
+#define MAX98371_SOFT_RESET			0x51
+#define MAX98371_VERSION			0xFF
+
+
+struct max98371_priv {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+};
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21  1:59 [PATCH] ASoC: Add max98371 codec driver anish kumar
@ 2016-03-21 14:56 ` Mark Brown
  2016-03-21 15:29   ` Micka
  2016-03-24 10:49   ` Micka
  0 siblings, 2 replies; 27+ messages in thread
From: Mark Brown @ 2016-03-21 14:56 UTC (permalink / raw)
  To: anish kumar; +Cc: alsa-devel, lgirdwood


[-- Attachment #1.1: Type: text/plain, Size: 825 bytes --]

On Sun, Mar 20, 2016 at 06:59:02PM -0700, anish kumar wrote:

This looks mostly good, a few small things:

> +static const char *const voltage_level_text[] = {
> +	"9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
> +	"13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
> +	"18.5dB", "19.5dB", "20.5dB"
> +};

Volume controls should be done with TLV data not enums.

> +static const struct snd_kcontrol_new max98371_snd_controls[] = {
> +	SOC_SINGLE_TLV("Speaker Gain", MAX98371_GAIN,
> +			MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
> +			max98371_gain_tlv),

Volume controls should end with Volume.

> +static int max98371_probe(struct snd_soc_codec *codec)
> +{
> +	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
> +
> +	max98371->codec = codec;
> +	return 0;
> +}

Do we ever actually use this?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21 14:56 ` Mark Brown
@ 2016-03-21 15:29   ` Micka
  2016-03-21 15:56     ` Mark Brown
  2016-03-24 10:49   ` Micka
  1 sibling, 1 reply; 27+ messages in thread
From: Micka @ 2016-03-21 15:29 UTC (permalink / raw)
  To: Mark Brown, anish kumar; +Cc: alsa-devel, lgirdwood

Hi Mark,

Could you tell me how do you control this device/codec with Linux ? What is
the command ?

Thank you !

Le lun. 21 mars 2016 à 16:03, Mark Brown <broonie@kernel.org> a écrit :

> On Sun, Mar 20, 2016 at 06:59:02PM -0700, anish kumar wrote:
>
> This looks mostly good, a few small things:
>
> > +static const char *const voltage_level_text[] = {
> > +     "9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
> > +     "13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
> > +     "18.5dB", "19.5dB", "20.5dB"
> > +};
>
> Volume controls should be done with TLV data not enums.
>
> > +static const struct snd_kcontrol_new max98371_snd_controls[] = {
> > +     SOC_SINGLE_TLV("Speaker Gain", MAX98371_GAIN,
> > +                     MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
> > +                     max98371_gain_tlv),
>
> Volume controls should end with Volume.
>
> > +static int max98371_probe(struct snd_soc_codec *codec)
> > +{
> > +     struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
> > +
> > +     max98371->codec = codec;
> > +     return 0;
> > +}
>
> Do we ever actually use this?
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21 15:29   ` Micka
@ 2016-03-21 15:56     ` Mark Brown
  2016-03-21 16:41       ` Micka
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-03-21 15:56 UTC (permalink / raw)
  To: Micka; +Cc: alsa-devel, lgirdwood, anish kumar


[-- Attachment #1.1: Type: text/plain, Size: 442 bytes --]

On Mon, Mar 21, 2016 at 03:29:00PM +0000, Micka wrote:
> Hi Mark,

Please don't top post, reply in line with needed context.  This allows
readers to readily follow the flow of conversation and understand what
you are talking about and also helps ensure that everything in the
discussion is being addressed.

> Could you tell me how do you control this device/codec with Linux ? What is
> the command ?

Using any ALSA userspace applications.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21 15:56     ` Mark Brown
@ 2016-03-21 16:41       ` Micka
  2016-03-21 17:05         ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: Micka @ 2016-03-21 16:41 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, lgirdwood, anish kumar

*Please don't top post, reply in line with needed context.  This
allowsreaders to readily follow the flow of conversation and understand
whatyou are talking about and also helps ensure that everything in
thediscussion is being addressed.*

Sorry ...




*> Could you tell me how do you control this device/codec with Linux ? What
is> the command ?*
*Using any ALSA userspace applications.*

But How do you find the device in the amixer application ? That the part
don't I don't get it !

Micka,


Le lun. 21 mars 2016 à 16:57, Mark Brown <broonie@kernel.org> a écrit :

> On Mon, Mar 21, 2016 at 03:29:00PM +0000, Micka wrote:
> > Hi Mark,
>
> Please don't top post, reply in line with needed context.  This allows
> readers to readily follow the flow of conversation and understand what
> you are talking about and also helps ensure that everything in the
> discussion is being addressed.
>
> > Could you tell me how do you control this device/codec with Linux ? What
> is
> > the command ?
>
> Using any ALSA userspace applications.
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21 16:41       ` Micka
@ 2016-03-21 17:05         ` Mark Brown
  2016-03-23 12:45           ` Micka
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-03-21 17:05 UTC (permalink / raw)
  To: Micka; +Cc: alsa-devel, lgirdwood, anish kumar


[-- Attachment #1.1: Type: text/plain, Size: 522 bytes --]

On Mon, Mar 21, 2016 at 04:41:43PM +0000, Micka wrote:

> *> Could you tell me how do you control this device/codec with Linux ? What
> is> the command ?*
> *Using any ALSA userspace applications.*

> But How do you find the device in the amixer application ? That the part
> don't I don't get it !

The machine driver that uses the CODEC will create a card.  Probably
it's going to be the only card in the system, if not you might need to
flip between cards using whatever UI you have.  With amixer that's the
-c option.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21 17:05         ` Mark Brown
@ 2016-03-23 12:45           ` Micka
  2016-03-23 16:23             ` Amish Kumar
  0 siblings, 1 reply; 27+ messages in thread
From: Micka @ 2016-03-23 12:45 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, lgirdwood, anish kumar

Ok,

I  'v a problem with the codec max9768, because I don't see it in the
device list.

but in the kernel log, everything looks ok !


[    9.582179] i2C max9768 probe
[    9.582369] ASoC: Registered codec 'max9768.2-0049'

root@beaglebone:/# /sbin/lsmod | grep snd
snd_soc_simple_card     7597  0
*snd_soc_max9768*         4736  0
snd_soc_tlv320aic3x    40053  1
snd_soc_davinci_mcasp    14383  2
snd_soc_edma            1150  1 snd_soc_davinci_mcasp
snd_soc_omap            2581  1 snd_soc_davinci_mcasp
snd_soc_core          155826  6
snd_soc_davinci_mcasp,snd_soc_edma,snd_soc_omap,snd_soc_tlv320aic3x,snd_soc_max9768,snd_soc_simple_card
snd_compress           11589  1 snd_soc_core
snd_pcm_dmaengine       5061  2 snd_soc_core,snd_soc_omap
snd_pcm                76985  5
snd_soc_davinci_mcasp,snd_soc_core,snd_soc_omap,snd_soc_tlv320aic3x,snd_pcm_dmaengine
snd_seq                45177  0
snd_seq_device          4534  1 snd_seq
snd_timer              16867  2 snd_pcm,snd_seq
snd                    56907  7
snd_soc_core,snd_timer,snd_pcm,snd_seq,snd_soc_max9768,snd_seq_device,snd_compress
soundcore               6893  1 snd


Le lun. 21 mars 2016 à 18:05, Mark Brown <broonie@kernel.org> a écrit :

> On Mon, Mar 21, 2016 at 04:41:43PM +0000, Micka wrote:
>
> > *> Could you tell me how do you control this device/codec with Linux ?
> What
> > is> the command ?*
> > *Using any ALSA userspace applications.*
>
> > But How do you find the device in the amixer application ? That the part
> > don't I don't get it !
>
> The machine driver that uses the CODEC will create a card.  Probably
> it's going to be the only card in the system, if not you might need to
> flip between cards using whatever UI you have.  With amixer that's the
> -c option.
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-23 12:45           ` Micka
@ 2016-03-23 16:23             ` Amish Kumar
  0 siblings, 0 replies; 27+ messages in thread
From: Amish Kumar @ 2016-03-23 16:23 UTC (permalink / raw)
  To: Micka; +Cc: alsa-devel, Mark Brown, lgirdwood



> On Mar 23, 2016, at 5:45 AM, Micka <mickamusset@gmail.com> wrote:
> 
> Ok, 
> 
> I  'v a problem with the codec max9768, because I don't see it in the device list.
> 
> but in the kernel log, everything looks ok !

What does cat /proc/asound/cards say?
Send a mail to me with the dmesg and I can help you. 

> 
> 
> [    9.582179] i2C max9768 probe
> [    9.582369] ASoC: Registered codec 'max9768.2-0049'
> 
> root@beaglebone:/# /sbin/lsmod | grep snd
> snd_soc_simple_card     7597  0
> snd_soc_max9768         4736  0
> snd_soc_tlv320aic3x    40053  1
> snd_soc_davinci_mcasp    14383  2
> snd_soc_edma            1150  1 snd_soc_davinci_mcasp
> snd_soc_omap            2581  1 snd_soc_davinci_mcasp
> snd_soc_core          155826  6 snd_soc_davinci_mcasp,snd_soc_edma,snd_soc_omap,snd_soc_tlv320aic3x,snd_soc_max9768,snd_soc_simple_card
> snd_compress           11589  1 snd_soc_core
> snd_pcm_dmaengine       5061  2 snd_soc_core,snd_soc_omap
> snd_pcm                76985  5 snd_soc_davinci_mcasp,snd_soc_core,snd_soc_omap,snd_soc_tlv320aic3x,snd_pcm_dmaengine
> snd_seq                45177  0
> snd_seq_device          4534  1 snd_seq
> snd_timer              16867  2 snd_pcm,snd_seq
> snd                    56907  7 snd_soc_core,snd_timer,snd_pcm,snd_seq,snd_soc_max9768,snd_seq_device,snd_compress
> soundcore               6893  1 snd
> 
> 
>> Le lun. 21 mars 2016 à 18:05, Mark Brown <broonie@kernel.org> a écrit :
>> On Mon, Mar 21, 2016 at 04:41:43PM +0000, Micka wrote:
>> 
>> > *> Could you tell me how do you control this device/codec with Linux ? What
>> > is> the command ?*
>> > *Using any ALSA userspace applications.*
>> 
>> > But How do you find the device in the amixer application ? That the part
>> > don't I don't get it !
>> 
>> The machine driver that uses the CODEC will create a card.  Probably
>> it's going to be the only card in the system, if not you might need to
>> flip between cards using whatever UI you have.  With amixer that's the
>> -c option.
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-21 14:56 ` Mark Brown
  2016-03-21 15:29   ` Micka
@ 2016-03-24 10:49   ` Micka
  2016-03-24 11:05     ` Mark Brown
  1 sibling, 1 reply; 27+ messages in thread
From: Micka @ 2016-03-24 10:49 UTC (permalink / raw)
  To: Mark Brown, anish kumar; +Cc: alsa-devel, lgirdwood

Hi Mark,

Where I can find your patch ? Will it work under the kernel 4.1 ? And how
do you make it work with the dts file ?

Micka,

Le lun. 21 mars 2016 à 16:03, Mark Brown <broonie@kernel.org> a écrit :

> On Sun, Mar 20, 2016 at 06:59:02PM -0700, anish kumar wrote:
>
> This looks mostly good, a few small things:
>
> > +static const char *const voltage_level_text[] = {
> > +     "9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
> > +     "13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
> > +     "18.5dB", "19.5dB", "20.5dB"
> > +};
>
> Volume controls should be done with TLV data not enums.
>
> > +static const struct snd_kcontrol_new max98371_snd_controls[] = {
> > +     SOC_SINGLE_TLV("Speaker Gain", MAX98371_GAIN,
> > +                     MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
> > +                     max98371_gain_tlv),
>
> Volume controls should end with Volume.
>
> > +static int max98371_probe(struct snd_soc_codec *codec)
> > +{
> > +     struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
> > +
> > +     max98371->codec = codec;
> > +     return 0;
> > +}
>
> Do we ever actually use this?
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-24 10:49   ` Micka
@ 2016-03-24 11:05     ` Mark Brown
  2016-03-24 11:19       ` Micka
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-03-24 11:05 UTC (permalink / raw)
  To: Micka; +Cc: alsa-devel, lgirdwood, anish kumar


[-- Attachment #1.1: Type: text/plain, Size: 481 bytes --]

On Thu, Mar 24, 2016 at 10:49:59AM +0000, Micka wrote:
> Hi Mark,

Please don't top post, reply in line with needed context.  This allows
readers to readily follow the flow of conversation and understand what
you are talking about and also helps ensure that everything in the
discussion is being addressed.

> Where I can find your patch ? Will it work under the kernel 4.1 ? And how
> do you make it work with the dts file ?

I have no idea what you're talking about here, sorry.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-24 11:05     ` Mark Brown
@ 2016-03-24 11:19       ` Micka
  2016-03-24 11:21         ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: Micka @ 2016-03-24 11:19 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, lgirdwood, anish kumar

Mark, the subject of this mail is asoc: add max98371 codex driver.

My questions concerns this patch/codec :

Where I can find your patch ? Will it work under the kernel 4.1 ? And how
do you make it work with the dts file ?

Micka,

Le jeu. 24 mars 2016 à 12:05, Mark Brown <broonie@kernel.org> a écrit :

> On Thu, Mar 24, 2016 at 10:49:59AM +0000, Micka wrote:
> > Hi Mark,
>
> Please don't top post, reply in line with needed context.  This allows
> readers to readily follow the flow of conversation and understand what
> you are talking about and also helps ensure that everything in the
> discussion is being addressed.
>
> > Where I can find your patch ? Will it work under the kernel 4.1 ? And how
> > do you make it work with the dts file ?
>
> I have no idea what you're talking about here, sorry.
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-24 11:19       ` Micka
@ 2016-03-24 11:21         ` Mark Brown
  0 siblings, 0 replies; 27+ messages in thread
From: Mark Brown @ 2016-03-24 11:21 UTC (permalink / raw)
  To: Micka; +Cc: alsa-devel, lgirdwood, anish kumar


[-- Attachment #1.1: Type: text/plain, Size: 381 bytes --]

On Thu, Mar 24, 2016 at 11:19:13AM +0000, Micka wrote:
> Mark, the subject of this mail is asoc: add max98371 codex driver.

> > Please don't top post, reply in line with needed context.  This allows
> > readers to readily follow the flow of conversation and understand what
> > you are talking about and also helps ensure that everything in the
> > discussion is being addressed.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH] ASoC: Add max98371 codec driver
@ 2016-04-27 22:39 anish kumar
  0 siblings, 0 replies; 27+ messages in thread
From: anish kumar @ 2016-04-27 22:39 UTC (permalink / raw)
  To: broonie, lgirdwood; +Cc: alsa-devel, anish kumar

Signed-off-by: anish kumar <yesanishhere@gmail.com>
---
Changed some controls to TLV as Mark suggested.

 .../devicetree/bindings/sound/max98371.txt         |  17 +
 sound/soc/codecs/Kconfig                           |   4 +
 sound/soc/codecs/Makefile                          |   1 +
 sound/soc/codecs/max98371.c                        | 442 +++++++++++++++++++++
 sound/soc/codecs/max98371.h                        |  67 ++++
 5 files changed, 531 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/max98371.txt
 create mode 100644 sound/soc/codecs/max98371.c
 create mode 100644 sound/soc/codecs/max98371.h

diff --git a/Documentation/devicetree/bindings/sound/max98371.txt b/Documentation/devicetree/bindings/sound/max98371.txt
new file mode 100644
index 0000000..6c28523
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/max98371.txt
@@ -0,0 +1,17 @@
+max98371 codec
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "maxim,max98371"
+- reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+	max98371: max98371@0x31 {
+		compatible = "maxim,max98371";
+		reg = <0x31>;
+	};
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 913c83c..ba6c585 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -75,6 +75,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MAX98090 if I2C
 	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX98357A if GPIOLIB
+	select SND_SOC_MAX98371 if I2C
 	select SND_SOC_MAX9867 if I2C
 	select SND_SOC_MAX98925 if I2C
 	select SND_SOC_MAX98926 if I2C
@@ -491,6 +492,9 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX98357A
        tristate
 
+config SND_SOC_MAX98371
+       tristate
+
 config SND_SOC_MAX9867
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f39dee7..9f3587b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -70,6 +70,7 @@ snd-soc-max98088-objs := max98088.o
 snd-soc-max98090-objs := max98090.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max98357a-objs := max98357a.o
+snd-soc-max98371-objs := max98371.o
 snd-soc-max9867-objs := max9867.o
 snd-soc-max98925-objs := max98925.o
 snd-soc-max98926-objs := max98926.o
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
new file mode 100644
index 0000000..21fae09
--- /dev/null
+++ b/sound/soc/codecs/max98371.c
@@ -0,0 +1,442 @@
+/*
+ * max98371.c -- ALSA SoC Stereo MAX98371 driver
+ *
+ * Copyright 2015-16 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98371.h"
+
+static const char *const monomix_text[] = {
+	"Left", "Right", "LeftRightDiv2",
+};
+
+static const char *const hpf_cutoff_txt[] = {
+	"Disable", "DC Block", "50Hz",
+	"100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0,
+		monomix_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0,
+		hpf_cutoff_txt);
+
+static const DECLARE_TLV_DB_RANGE(max98371_dht_min_gain,
+	0, 1, TLV_DB_SCALE_ITEM(537, 66, 0),
+	2, 3, TLV_DB_SCALE_ITEM(677, 82, 0),
+	4, 5, TLV_DB_SCALE_ITEM(852, 104, 0),
+	6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0),
+	8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0),
+	10, 11, TLV_DB_SCALE_ITEM(1699, 101, 0),
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_dht_max_gain,
+	0, 1, TLV_DB_SCALE_ITEM(537, 66, 0),
+	2, 3, TLV_DB_SCALE_ITEM(677, 82, 0),
+	4, 5, TLV_DB_SCALE_ITEM(852, 104, 0),
+	6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0),
+	8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0),
+	10, 11, TLV_DB_SCALE_ITEM(1699, 208, 0),
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_dht_rot_gain,
+	0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0),
+	2, 6, TLV_DB_SCALE_ITEM(-100, -100, 0),
+	7, 8, TLV_DB_SCALE_ITEM(-800, -200, 0),
+	9, 11, TLV_DB_SCALE_ITEM(-1200, -300, 0),
+	12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0),
+	14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0),
+);
+
+static const struct reg_default max98371_reg[] = {
+	{ 0x01, 0x00 },
+	{ 0x02, 0x00 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0A, 0x00 },
+	{ 0x10, 0x06 },
+	{ 0x11, 0x08 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1C, 0x00 },
+	{ 0x1D, 0x00 },
+	{ 0x1E, 0x00 },
+	{ 0x1F, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2A, 0x00 },
+	{ 0x2B, 0x00 },
+	{ 0x2C, 0x00 },
+	{ 0x2D, 0x00 },
+	{ 0x2E, 0x0B },
+	{ 0x31, 0x00 },
+	{ 0x32, 0x18 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x00 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x00 },
+	{ 0x3A, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3C, 0x00 },
+	{ 0x3D, 0x00 },
+	{ 0x3E, 0x00 },
+	{ 0x3F, 0x00 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x42, 0x00 },
+	{ 0x43, 0x00 },
+	{ 0x4A, 0x00 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x4D, 0x00 },
+	{ 0x4E, 0x00 },
+	{ 0x50, 0x00 },
+	{ 0x51, 0x00 },
+	{ 0x55, 0x00 },
+	{ 0x58, 0x00 },
+	{ 0x59, 0x00 },
+	{ 0x5C, 0x00 },
+	{ 0xFF, 0x43 },
+};
+
+static bool max98371_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_IRQ_CLEAR1:
+	case MAX98371_IRQ_CLEAR2:
+	case MAX98371_IRQ_CLEAR3:
+	case MAX98371_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98371_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_SOFT_RESET:
+		return false;
+	default:
+		return true;
+	}
+};
+
+static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(0, 50, 0),
+	8, 10, TLV_DB_SCALE_ITEM(400, 100, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv,
+	0, 11, TLV_DB_SCALE_ITEM(950, 100, 0),
+);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1);
+
+static const struct snd_kcontrol_new max98371_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98371_GAIN,
+			MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
+			max98371_gain_tlv),
+	SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0,
+			(1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv),
+	SOC_SINGLE_TLV("Speaker DHT Max Volume", MAX98371_GAIN,
+			0, (1<<MAX98371_DHT_MAX_WIDTH)-1, 0,
+			max98371_dht_max_gain),
+	SOC_SINGLE_TLV("Speaker DHT Min Volume", MAX98371_DHT_GAIN,
+			0, (1<<MAX98371_DHT_GAIN_WIDTH)-1, 0,
+			max98371_dht_min_gain),
+	SOC_SINGLE_TLV("Speaker DHT Rotation Volume", MAX98371_DHT_GAIN,
+			0, (1<<MAX98371_DHT_ROT_WIDTH)-1, 0,
+			max98371_dht_rot_gain),
+	SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0),
+	SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0),
+	SOC_ENUM("Monomix Select", max98371_monomix),
+	SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff),
+};
+
+static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(codec->dev, "DAI clock mode unsupported");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= 0;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= MAX98371_DAI_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= MAX98371_DAI_LEFT;
+		break;
+	default:
+		dev_err(codec->dev, "DAI wrong mode unsupported");
+		return -EINVAL;
+	}
+	regmap_update_bits(max98371->regmap, MAX98371_FMT,
+			MAX98371_FMT_MODE_MASK, val);
+	return 0;
+}
+
+static int max98371_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	int blr_clk_ratio, ch_size, channels = params_channels(params);
+	int rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* BCLK/LRCLK ratio calculation */
+	blr_clk_ratio = channels * ch_size;
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rate) {
+	case 32000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32);
+		break;
+	case 44100:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44);
+		break;
+	case 48000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48);
+		break;
+	case 88200:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88);
+		break;
+	case 96000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* enabling both the RX channels*/
+	regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC,
+			MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1);
+	regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL,
+			MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", NULL, MAX98371_SPK_ENABLE, 0, 0),
+	SND_SOC_DAPM_SUPPLY("Global Enable", MAX98371_GLOBAL_ENABLE,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98371_audio_map[] = {
+	{"DAC", NULL, "HiFi Playback"},
+	{"SPK_OUT", NULL, "DAC"},
+	{"SPK_OUT", NULL, "Global Enable"},
+};
+
+#define MAX98371_RATES SNDRV_PCM_RATE_8000_48000
+#define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static const struct snd_soc_dai_ops max98371_dai_ops = {
+	.set_fmt = max98371_dai_set_fmt,
+	.hw_params = max98371_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98371_dai[] = {
+	{
+		.name = "max98371-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98371_FORMATS,
+		},
+		.ops = &max98371_dai_ops,
+	}
+};
+
+static const struct snd_soc_codec_driver max98371_codec = {
+	.controls = max98371_snd_controls,
+	.num_controls = ARRAY_SIZE(max98371_snd_controls),
+	.dapm_routes = max98371_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
+	.dapm_widgets = max98371_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+};
+
+static const struct regmap_config max98371_regmap = {
+	.reg_bits         = 8,
+	.val_bits         = 8,
+	.max_register     = MAX98371_VERSION,
+	.reg_defaults     = max98371_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98371_reg),
+	.volatile_reg     = max98371_volatile_register,
+	.readable_reg     = max98371_readable_register,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98371_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct max98371_priv *max98371;
+	int ret, reg;
+
+	max98371 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98371), GFP_KERNEL);
+	if (!max98371)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98371);
+	max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
+	if (IS_ERR(max98371->regmap)) {
+		ret = PTR_ERR(max98371->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
+	if (ret < 0) {
+		dev_info(&i2c->dev, "device error %d\n", ret);
+		return ret;
+	}
+	dev_info(&i2c->dev, "device version %x\n", reg);
+
+	ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
+			max98371_dai, ARRAY_SIZE(max98371_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int max98371_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id max98371_i2c_id[] = {
+	{ "max98371", 0 },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
+
+static const struct of_device_id max98371_of_match[] = {
+	{ .compatible = "maxim,max98371", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98371_of_match);
+
+static struct i2c_driver max98371_i2c_driver = {
+	.driver = {
+		.name = "max98371",
+		.owner = THIS_MODULE,
+		.pm = NULL,
+		.of_match_table = of_match_ptr(max98371_of_match),
+	},
+	.probe  = max98371_i2c_probe,
+	.remove = max98371_i2c_remove,
+	.id_table = max98371_i2c_id,
+};
+
+module_i2c_driver(max98371_i2c_driver);
+
+MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC MAX98371 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h
new file mode 100644
index 0000000..9f63309
--- /dev/null
+++ b/sound/soc/codecs/max98371.h
@@ -0,0 +1,67 @@
+/*
+ * max98371.h -- MAX98371 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98371_H
+#define _MAX98371_H
+
+#define MAX98371_IRQ_CLEAR1			0x01
+#define MAX98371_IRQ_CLEAR2			0x02
+#define MAX98371_IRQ_CLEAR3			0x03
+#define MAX98371_DAI_CLK			0x10
+#define MAX98371_DAI_BSEL_MASK			0xF
+#define MAX98371_DAI_BSEL_32			2
+#define MAX98371_DAI_BSEL_48			3
+#define MAX98371_DAI_BSEL_64			4
+#define MAX98371_SPK_SR				0x11
+#define MAX98371_SPK_SR_MASK			0xF
+#define MAX98371_SPK_SR_32			6
+#define MAX98371_SPK_SR_44			7
+#define MAX98371_SPK_SR_48			8
+#define MAX98371_SPK_SR_88			10
+#define MAX98371_SPK_SR_96			11
+#define MAX98371_DAI_CHANNEL			0x15
+#define MAX98371_CHANNEL_MASK			0x3
+#define MAX98371_MONOMIX_SRC			0x18
+#define MAX98371_MONOMIX_CFG			0x19
+#define MAX98371_HPF				0x1C
+#define MAX98371_MONOMIX_SRC_MASK		0xFF
+#define MONOMIX_RX_0_1				((0x1)<<(4))
+#define M98371_DAI_CHANNEL_I2S			0x3
+#define MAX98371_DIGITAL_GAIN			0x2D
+#define MAX98371_DIGITAL_GAIN_WIDTH		0x7
+#define MAX98371_GAIN				0x2E
+#define MAX98371_GAIN_SHIFT			0x4
+#define MAX98371_GAIN_WIDTH			0x4
+#define MAX98371_DHT_MAX_WIDTH			4
+#define MAX98371_FMT				0x14
+#define MAX98371_CHANSZ_WIDTH			6
+#define MAX98371_FMT_MASK		        ((0x3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_FMT_MODE_MASK		        ((0x7)<<(3))
+#define MAX98371_DAI_LEFT		        ((0x1)<<(3))
+#define MAX98371_DAI_RIGHT		        ((0x2)<<(3))
+#define MAX98371_DAI_CHANSZ_16                  ((1)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_24                  ((2)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_32                  ((3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DHT  0x32
+#define MAX98371_DHT_STEP			0x3
+#define MAX98371_DHT_GAIN			0x31
+#define MAX98371_DHT_GAIN_WIDTH			0x4
+#define MAX98371_DHT_ROT_WIDTH			0x4
+#define MAX98371_SPK_ENABLE			0x4A
+#define MAX98371_GLOBAL_ENABLE			0x50
+#define MAX98371_SOFT_RESET			0x51
+#define MAX98371_VERSION			0xFF
+
+
+struct max98371_priv {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+};
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-26 18:16           ` anish kumar
@ 2016-04-27 16:42             ` Mark Brown
  0 siblings, 0 replies; 27+ messages in thread
From: Mark Brown @ 2016-04-27 16:42 UTC (permalink / raw)
  To: anish kumar; +Cc: Linux-ALSA, Liam Girdwood


[-- Attachment #1.1: Type: text/plain, Size: 375 bytes --]

On Tue, Apr 26, 2016 at 11:16:38AM -0700, anish kumar wrote:

> Discussion of this with hardware team revealed that dynamic headroom
> tracking is the feature which will be controlled with this gain.

> I am also adding two new controls for this: speaker gain min and DHT
> rotation point.

> I will be adding all of this as TLV as this should be configurable.

Sounds good.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-22 15:31         ` Mark Brown
@ 2016-04-26 18:16           ` anish kumar
  2016-04-27 16:42             ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: anish kumar @ 2016-04-26 18:16 UTC (permalink / raw)
  To: Mark Brown; +Cc: Linux-ALSA, Liam Girdwood

On Fri, Apr 22, 2016 at 8:31 AM, Mark Brown <broonie@kernel.org> wrote:
> On Wed, Apr 20, 2016 at 11:14:40AM -0700, anish kumar wrote:
>> On Tue, Apr 19, 2016 at 2:46 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Hrm, that looks like the driver may be able to set it automatically
>> > using the regulator API and just have a switch for the guaranteed.
>
>> Should i pass it via device tree then? I didn't get your statement about
>
> I'd expect to look up the value by looking at the supply voltage if we
> were going to go that way.

Discussion of this with hardware team revealed that dynamic headroom
tracking is the feature which will be controlled with this gain.

I am also adding two new controls for this: speaker gain min and DHT
rotation point.

I will be adding all of this as TLV as this should be configurable.
>
>> "switch".
>
> A switch is an on/off control.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-20 18:14       ` anish kumar
@ 2016-04-22 15:31         ` Mark Brown
  2016-04-26 18:16           ` anish kumar
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-04-22 15:31 UTC (permalink / raw)
  To: anish kumar; +Cc: Linux-ALSA, Liam Girdwood


[-- Attachment #1.1: Type: text/plain, Size: 499 bytes --]

On Wed, Apr 20, 2016 at 11:14:40AM -0700, anish kumar wrote:
> On Tue, Apr 19, 2016 at 2:46 AM, Mark Brown <broonie@kernel.org> wrote:

> > Hrm, that looks like the driver may be able to set it automatically
> > using the regulator API and just have a switch for the guaranteed.

> Should i pass it via device tree then? I didn't get your statement about

I'd expect to look up the value by looking at the supply voltage if we
were going to go that way.

> "switch".

A switch is an on/off control.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-19  9:46     ` Mark Brown
@ 2016-04-20 18:14       ` anish kumar
  2016-04-22 15:31         ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: anish kumar @ 2016-04-20 18:14 UTC (permalink / raw)
  To: Mark Brown; +Cc: Linux-ALSA, Liam Girdwood

On Tue, Apr 19, 2016 at 2:46 AM, Mark Brown <broonie@kernel.org> wrote:
> On Mon, Apr 18, 2016 at 01:20:35PM -0700, anish kumar wrote:
>> On Mon, Apr 18, 2016 at 9:47 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > As I said last time I would expect this to be a TLV control.  As far as
>> > I can tell this is basically functioning as a maximum volume.  Otherwise
>> > this looks good.
>
>> I responded to your comment earlier but there was no reply so I thought
>> it is accepted this way. Excuse my understanding. It is not actually a volume
>> but described as such.
>
> If it's measured in dB I'd still expect a TLV control.
>
>> It is "Speaker No-Load Output Voltage Maximum". It is
>> described here on page 50.
>> https://datasheets.maximintegrated.com/en/ds/MAX98371.pdf
>
> Hrm, that looks like the driver may be able to set it automatically
> using the regulator API and just have a switch for the guaranteed.

Should i pass it via device tree then? I didn't get your statement about
"switch".

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-18 20:20   ` anish kumar
@ 2016-04-19  9:46     ` Mark Brown
  2016-04-20 18:14       ` anish kumar
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-04-19  9:46 UTC (permalink / raw)
  To: anish kumar; +Cc: Linux-ALSA, Liam Girdwood


[-- Attachment #1.1: Type: text/plain, Size: 828 bytes --]

On Mon, Apr 18, 2016 at 01:20:35PM -0700, anish kumar wrote:
> On Mon, Apr 18, 2016 at 9:47 AM, Mark Brown <broonie@kernel.org> wrote:

> > As I said last time I would expect this to be a TLV control.  As far as
> > I can tell this is basically functioning as a maximum volume.  Otherwise
> > this looks good.

> I responded to your comment earlier but there was no reply so I thought
> it is accepted this way. Excuse my understanding. It is not actually a volume
> but described as such.

If it's measured in dB I'd still expect a TLV control.

> It is "Speaker No-Load Output Voltage Maximum". It is
> described here on page 50.
> https://datasheets.maximintegrated.com/en/ds/MAX98371.pdf

Hrm, that looks like the driver may be able to set it automatically
using the regulator API and just have a switch for the guaranteed.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-18 16:47 ` Mark Brown
@ 2016-04-18 20:20   ` anish kumar
  2016-04-19  9:46     ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: anish kumar @ 2016-04-18 20:20 UTC (permalink / raw)
  To: Mark Brown; +Cc: Linux-ALSA, Liam Girdwood

On Mon, Apr 18, 2016 at 9:47 AM, Mark Brown <broonie@kernel.org> wrote:
> On Wed, Apr 13, 2016 at 01:20:47PM -0700, anish kumar wrote:
>
>> +static const char *const voltage_level_text[] = {
>> +     "9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
>> +     "13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
>> +     "18.5dB", "19.5dB", "20.5dB"
>> +};
>
> As I said last time I would expect this to be a TLV control.  As far as
> I can tell this is basically functioning as a maximum volume.  Otherwise
> this looks good.

I responded to your comment earlier but there was no reply so I thought
it is accepted this way. Excuse my understanding. It is not actually a volume
but described as such.

It is "Speaker No-Load Output Voltage Maximum". It is
described here on page 50.
https://datasheets.maximintegrated.com/en/ds/MAX98371.pdf

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-13 20:20 anish kumar
@ 2016-04-18 16:47 ` Mark Brown
  2016-04-18 20:20   ` anish kumar
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-04-18 16:47 UTC (permalink / raw)
  To: anish kumar; +Cc: alsa-devel, lgirdwood


[-- Attachment #1.1: Type: text/plain, Size: 424 bytes --]

On Wed, Apr 13, 2016 at 01:20:47PM -0700, anish kumar wrote:

> +static const char *const voltage_level_text[] = {
> +	"9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
> +	"13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
> +	"18.5dB", "19.5dB", "20.5dB"
> +};

As I said last time I would expect this to be a TLV control.  As far as
I can tell this is basically functioning as a maximum volume.  Otherwise
this looks good.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH] ASoC: Add max98371 codec driver
@ 2016-04-13 20:20 anish kumar
  2016-04-18 16:47 ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: anish kumar @ 2016-04-13 20:20 UTC (permalink / raw)
  To: broonie, lgirdwood; +Cc: alsa-devel, anish kumar

Signed-off-by: anish kumar <yesanishhere@gmail.com>
---
 .../devicetree/bindings/sound/max98371.txt         |  17 +
 sound/soc/codecs/Kconfig                           |   4 +
 sound/soc/codecs/Makefile                          |   1 +
 sound/soc/codecs/max98371.c                        | 419 +++++++++++++++++++++
 sound/soc/codecs/max98371.h                        |  64 ++++
 5 files changed, 505 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/max98371.txt
 create mode 100644 sound/soc/codecs/max98371.c
 create mode 100644 sound/soc/codecs/max98371.h

diff --git a/Documentation/devicetree/bindings/sound/max98371.txt b/Documentation/devicetree/bindings/sound/max98371.txt
new file mode 100644
index 0000000..6c28523
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/max98371.txt
@@ -0,0 +1,17 @@
+max98371 codec
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "maxim,max98371"
+- reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+	max98371: max98371@0x31 {
+		compatible = "maxim,max98371";
+		reg = <0x31>;
+	};
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 913c83c..ba6c585 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -75,6 +75,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MAX98090 if I2C
 	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX98357A if GPIOLIB
+	select SND_SOC_MAX98371 if I2C
 	select SND_SOC_MAX9867 if I2C
 	select SND_SOC_MAX98925 if I2C
 	select SND_SOC_MAX98926 if I2C
@@ -491,6 +492,9 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX98357A
        tristate
 
+config SND_SOC_MAX98371
+       tristate
+
 config SND_SOC_MAX9867
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f39dee7..9f3587b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -70,6 +70,7 @@ snd-soc-max98088-objs := max98088.o
 snd-soc-max98090-objs := max98090.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max98357a-objs := max98357a.o
+snd-soc-max98371-objs := max98371.o
 snd-soc-max9867-objs := max9867.o
 snd-soc-max98925-objs := max98925.o
 snd-soc-max98926-objs := max98926.o
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
new file mode 100644
index 0000000..ce735db
--- /dev/null
+++ b/sound/soc/codecs/max98371.c
@@ -0,0 +1,419 @@
+/*
+ * max98371.c -- ALSA SoC Stereo MAX98371 driver
+ *
+ * Copyright 2015-16 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98371.h"
+
+static const char *const monomix_text[] = {
+	"Left", "Right", "LeftRightDiv2",
+};
+
+static const char *const voltage_level_text[] = {
+	"9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
+	"13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
+	"18.5dB", "19.5dB", "20.5dB"
+};
+
+static const char *const hpf_cutoff_txt[] = {
+	"Disable", "DC Block", "50Hz",
+	"100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98371_voltage, MAX98371_GAIN, 0,
+		voltage_level_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0,
+		monomix_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0,
+		hpf_cutoff_txt);
+
+static const struct reg_default max98371_reg[] = {
+	{ 0x01, 0x00 },
+	{ 0x02, 0x00 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0A, 0x00 },
+	{ 0x10, 0x06 },
+	{ 0x11, 0x08 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1C, 0x00 },
+	{ 0x1D, 0x00 },
+	{ 0x1E, 0x00 },
+	{ 0x1F, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2A, 0x00 },
+	{ 0x2B, 0x00 },
+	{ 0x2C, 0x00 },
+	{ 0x2D, 0x00 },
+	{ 0x2E, 0x0B },
+	{ 0x31, 0x00 },
+	{ 0x32, 0x18 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x00 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x00 },
+	{ 0x3A, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3C, 0x00 },
+	{ 0x3D, 0x00 },
+	{ 0x3E, 0x00 },
+	{ 0x3F, 0x00 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x42, 0x00 },
+	{ 0x43, 0x00 },
+	{ 0x4A, 0x00 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x4D, 0x00 },
+	{ 0x4E, 0x00 },
+	{ 0x50, 0x00 },
+	{ 0x51, 0x00 },
+	{ 0x55, 0x00 },
+	{ 0x58, 0x00 },
+	{ 0x59, 0x00 },
+	{ 0x5C, 0x00 },
+	{ 0xFF, 0x43 },
+};
+
+static bool max98371_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_IRQ_CLEAR1:
+	case MAX98371_IRQ_CLEAR2:
+	case MAX98371_IRQ_CLEAR3:
+	case MAX98371_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98371_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_SOFT_RESET:
+		return false;
+	default:
+		return true;
+	}
+};
+
+static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(0, 50, 0),
+	8, 10, TLV_DB_SCALE_ITEM(400, 100, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv,
+	0, 11, TLV_DB_SCALE_ITEM(950, 100, 0),
+);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1);
+
+static const struct snd_kcontrol_new max98371_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98371_GAIN,
+			MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
+			max98371_gain_tlv),
+	SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0,
+			(1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv),
+	SOC_SINGLE_TLV("Speaker No-load Volume", MAX98371_GAIN,
+			0, (1<<MAX98371_NO_LOAD_WIDTH)-1, 0,
+			max98371_noload_gain_tlv),
+	SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0),
+	SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0),
+	SOC_ENUM("Voltage Level", max98371_voltage),
+	SOC_ENUM("Monomix Select", max98371_monomix),
+	SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff),
+};
+
+static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(codec->dev, "DAI clock mode unsupported");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= 0;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= MAX98371_DAI_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= MAX98371_DAI_LEFT;
+		break;
+	default:
+		dev_err(codec->dev, "DAI wrong mode unsupported");
+		return -EINVAL;
+	}
+	regmap_update_bits(max98371->regmap, MAX98371_FMT,
+			MAX98371_FMT_MODE_MASK, val);
+	return 0;
+}
+
+static int max98371_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	int blr_clk_ratio, ch_size, channels = params_channels(params);
+	int rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* BCLK/LRCLK ratio calculation */
+	blr_clk_ratio = channels * ch_size;
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rate) {
+	case 32000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32);
+		break;
+	case 44100:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44);
+		break;
+	case 48000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48);
+		break;
+	case 88200:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88);
+		break;
+	case 96000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* enabling both the RX channels*/
+	regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC,
+			MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1);
+	regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL,
+			MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", NULL, MAX98371_SPK_ENABLE, 0, 0),
+	SND_SOC_DAPM_SUPPLY("Global Enable", MAX98371_GLOBAL_ENABLE,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98371_audio_map[] = {
+	{"DAC", NULL, "HiFi Playback"},
+	{"SPK_OUT", NULL, "DAC"},
+	{"SPK_OUT", NULL, "Global Enable"},
+};
+
+#define MAX98371_RATES SNDRV_PCM_RATE_8000_48000
+#define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static const struct snd_soc_dai_ops max98371_dai_ops = {
+	.set_fmt = max98371_dai_set_fmt,
+	.hw_params = max98371_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98371_dai[] = {
+	{
+		.name = "max98371-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98371_FORMATS,
+		},
+		.ops = &max98371_dai_ops,
+	}
+};
+
+static const struct snd_soc_codec_driver max98371_codec = {
+	.controls = max98371_snd_controls,
+	.num_controls = ARRAY_SIZE(max98371_snd_controls),
+	.dapm_routes = max98371_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
+	.dapm_widgets = max98371_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+};
+
+static const struct regmap_config max98371_regmap = {
+	.reg_bits         = 8,
+	.val_bits         = 8,
+	.max_register     = MAX98371_VERSION,
+	.reg_defaults     = max98371_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98371_reg),
+	.volatile_reg     = max98371_volatile_register,
+	.readable_reg     = max98371_readable_register,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98371_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct max98371_priv *max98371;
+	int ret, reg;
+
+	max98371 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98371), GFP_KERNEL);
+	if (!max98371)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98371);
+	max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
+	if (IS_ERR(max98371->regmap)) {
+		ret = PTR_ERR(max98371->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
+	if (ret < 0) {
+		dev_info(&i2c->dev, "device error %d\n", ret);
+		return ret;
+	}
+	dev_info(&i2c->dev, "device version %x\n", reg);
+
+	ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
+			max98371_dai, ARRAY_SIZE(max98371_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int max98371_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id max98371_i2c_id[] = {
+	{ "max98371", 0 },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
+
+static const struct of_device_id max98371_of_match[] = {
+	{ .compatible = "maxim,max98371", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98371_of_match);
+
+static struct i2c_driver max98371_i2c_driver = {
+	.driver = {
+		.name = "max98371",
+		.owner = THIS_MODULE,
+		.pm = NULL,
+		.of_match_table = of_match_ptr(max98371_of_match),
+	},
+	.probe  = max98371_i2c_probe,
+	.remove = max98371_i2c_remove,
+	.id_table = max98371_i2c_id,
+};
+
+module_i2c_driver(max98371_i2c_driver);
+
+MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC MAX98371 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h
new file mode 100644
index 0000000..c75b259
--- /dev/null
+++ b/sound/soc/codecs/max98371.h
@@ -0,0 +1,64 @@
+/*
+ * max98371.h -- MAX98371 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98371_H
+#define _MAX98371_H
+
+#define MAX98371_IRQ_CLEAR1			0x01
+#define MAX98371_IRQ_CLEAR2			0x02
+#define MAX98371_IRQ_CLEAR3			0x03
+#define MAX98371_DAI_CLK			0x10
+#define MAX98371_DAI_BSEL_MASK			0xF
+#define MAX98371_DAI_BSEL_32			2
+#define MAX98371_DAI_BSEL_48			3
+#define MAX98371_DAI_BSEL_64			4
+#define MAX98371_SPK_SR				0x11
+#define MAX98371_SPK_SR_MASK			0xF
+#define MAX98371_SPK_SR_32			6
+#define MAX98371_SPK_SR_44			7
+#define MAX98371_SPK_SR_48			8
+#define MAX98371_SPK_SR_88			10
+#define MAX98371_SPK_SR_96			11
+#define MAX98371_DAI_CHANNEL			0x15
+#define MAX98371_CHANNEL_MASK			0x3
+#define MAX98371_MONOMIX_SRC			0x18
+#define MAX98371_MONOMIX_CFG			0x19
+#define MAX98371_HPF				0x1C
+#define MAX98371_MONOMIX_SRC_MASK		0xFF
+#define MONOMIX_RX_0_1				((0x1)<<(4))
+#define M98371_DAI_CHANNEL_I2S			0x3
+#define MAX98371_DIGITAL_GAIN			0x2D
+#define MAX98371_DIGITAL_GAIN_WIDTH		0x7
+#define MAX98371_GAIN				0x2E
+#define MAX98371_GAIN_SHIFT			0x4
+#define MAX98371_GAIN_WIDTH			0x4
+#define MAX98371_NO_LOAD_WIDTH			4
+#define MAX98371_FMT				0x14
+#define MAX98371_CHANSZ_WIDTH			6
+#define MAX98371_FMT_MASK		        ((0x3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_FMT_MODE_MASK		        ((0x7)<<(3))
+#define MAX98371_DAI_LEFT		        ((0x1)<<(3))
+#define MAX98371_DAI_RIGHT		        ((0x2)<<(3))
+#define MAX98371_DAI_CHANSZ_16                  ((1)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_24                  ((2)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_32                  ((3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DHT  0x32
+#define MAX98371_DHT_STEP			0x3
+#define MAX98371_SPK_ENABLE			0x4A
+#define MAX98371_GLOBAL_ENABLE			0x50
+#define MAX98371_SOFT_RESET			0x51
+#define MAX98371_VERSION			0xFF
+
+
+struct max98371_priv {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+};
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-08  3:09 ` Lars-Peter Clausen
  2016-04-08 20:04   ` anish kumar
@ 2016-04-10 18:04   ` Mark Brown
  1 sibling, 0 replies; 27+ messages in thread
From: Mark Brown @ 2016-04-10 18:04 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: alsa-devel, lgirdwood, anish kumar


[-- Attachment #1.1: Type: text/plain, Size: 582 bytes --]

On Fri, Apr 08, 2016 at 05:09:09AM +0200, Lars-Peter Clausen wrote:

> > +	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
> > +	if (ret < 0) {
> > +		dev_info(&i2c->dev, "device error %d\n", ret);
> > +		return ret;
> > +	}
> > +	dev_info(&i2c->dev, "device version %x\n", reg);

> Drop this, it is just noise in the boot log.

It's generally OK to print information about the actual hardware found
in the system, it can be a helpful diagnostic.  Getting all this stuff
into sysfs files would be even better but that doesn't seem to be how we
do things at the minute.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-04-08  3:09 ` Lars-Peter Clausen
@ 2016-04-08 20:04   ` anish kumar
  2016-04-10 18:04   ` Mark Brown
  1 sibling, 0 replies; 27+ messages in thread
From: anish kumar @ 2016-04-08 20:04 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: Linux-ALSA, broonie, Liam Girdwood

On Thu, Apr 7, 2016 at 8:09 PM, Lars-Peter Clausen <lars@metafoo.de> wrote:
> [...]
>> +static struct reg_default max98371_reg[] = {
> const
> [...]
>> +static const unsigned int max98371_gain_tlv[] = {
>> +     0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
>> +     9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
>> +     11, 15, TLV_DB_SCALE_ITEM(0, 0, 0),
>> +};
>
> I don't think this works, you need to define a container. This is best done
> using DECLARE_TLV_DB_RANGE().
>
>> +
>> +static const unsigned int max98371_noload_gain_tlv[] = {
>> +     0, 11, TLV_DB_SCALE_ITEM(0, 100, 0),
>> +};
>
> Again, won't work I think, but since this is a single item, just just
> DECLARE_TLV_DB_SCALE.
>
> [...]
>> +             pr_info("%s: format unsupported %d",
>> +                             __func__, params_format(params));
>
> Not pr_info(), maybe dev_err() or drop it altogether. Same for the other
> pr_info() calls.
>
>> +static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
>> +     SND_SOC_DAPM_AIF_IN("DAI_OUT",
>> +             "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
>
> This doesn't seem to do anything, just drop it.
>
>> +     SND_SOC_DAPM_DAC("DAC Enable",
>
> I'd just call this DAC.
>
>> +             "HiFi Playback", MAX98371_SPK_ENABLE, 0, 0),
>
> Drop the "HiFi Playback" here and connect the DAC in the routes to the "HiFi
> Playback" widget.
>
>> +     SND_SOC_DAPM_SUPPLY("Global Enable",
>> +             MAX98371_GLOBAL_ENABLE, 0, 0, NULL, 0),
>> +     SND_SOC_DAPM_OUTPUT("SPK_OUT"),
>> +};
>> +static struct snd_soc_dai_ops max98371_dai_ops = {
>
> const
>
>> +     .set_fmt = max98371_dai_set_fmt,
>> +     .hw_params = max98371_dai_hw_params,
>> +};
>> +
> [...]
>> +static struct snd_soc_codec_driver max98371_codec = {
>
> const
>
>> +     .controls = max98371_snd_controls,
>> +     .num_controls = ARRAY_SIZE(max98371_snd_controls),
>> +     .dapm_routes = max98371_audio_map,
>> +     .num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
>> +     .dapm_widgets = max98371_dapm_widgets,
>> +     .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
>> +};
>> +
>> +static const struct regmap_config max98371_regmap = {
>> +     .reg_bits         = 8,
>> +     .val_bits         = 8,
>> +     .max_register     = MAX98371_VERSION,
>> +     .reg_defaults     = max98371_reg,
>> +     .num_reg_defaults = ARRAY_SIZE(max98371_reg),
>> +     .volatile_reg     = max98371_volatile_register,
>> +     .readable_reg     = max98371_readable_register,
>> +     .cache_type       = REGCACHE_RBTREE,
>> +};
>> +
>> +static int max98371_i2c_probe(struct i2c_client *i2c,
>> +             const struct i2c_device_id *id)
>> +{
>> +     struct max98371_priv *max98371;
>> +     int ret, reg;
>> +
>> +     max98371 = devm_kzalloc(&i2c->dev,
>> +                     sizeof(*max98371), GFP_KERNEL);
>> +     if (!max98371)
>> +             return -ENOMEM;
>> +
>> +     i2c_set_clientdata(i2c, max98371);
>> +     max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
>> +     if (IS_ERR(max98371->regmap)) {
>> +             ret = PTR_ERR(max98371->regmap);
>> +             dev_err(&i2c->dev,
>> +                             "Failed to allocate regmap: %d\n", ret);
>> +             return ret;
>> +     }
>> +
>> +     ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
>> +     if (ret < 0) {
>> +             dev_info(&i2c->dev, "device error %d\n", ret);
>> +             return ret;
>> +     }
>> +     dev_info(&i2c->dev, "device version %x\n", reg);
>
> Drop this, it is just noise in the boot log.
>
>> +
>> +     ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
>> +                     max98371_dai, ARRAY_SIZE(max98371_dai));
>> +     if (ret < 0) {
>> +             dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
>> +             return ret;
>> +     }
>> +     return ret;
>> +}

Thanks. All comments will be addressed in the next patch.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-22  6:53 anish kumar
  2016-03-28 19:13 ` Mark Brown
@ 2016-04-08  3:09 ` Lars-Peter Clausen
  2016-04-08 20:04   ` anish kumar
  2016-04-10 18:04   ` Mark Brown
  1 sibling, 2 replies; 27+ messages in thread
From: Lars-Peter Clausen @ 2016-04-08  3:09 UTC (permalink / raw)
  To: anish kumar, broonie, lgirdwood; +Cc: alsa-devel

[...]
> +static struct reg_default max98371_reg[] = {
const
[...]
> +static const unsigned int max98371_gain_tlv[] = {
> +	0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
> +	9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
> +	11, 15, TLV_DB_SCALE_ITEM(0, 0, 0),
> +};

I don't think this works, you need to define a container. This is best done
using DECLARE_TLV_DB_RANGE().

> +
> +static const unsigned int max98371_noload_gain_tlv[] = {
> +	0, 11, TLV_DB_SCALE_ITEM(0, 100, 0),
> +};

Again, won't work I think, but since this is a single item, just just
DECLARE_TLV_DB_SCALE.

[...]
> +		pr_info("%s: format unsupported %d",
> +				__func__, params_format(params));

Not pr_info(), maybe dev_err() or drop it altogether. Same for the other
pr_info() calls.

> +static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
> +	SND_SOC_DAPM_AIF_IN("DAI_OUT",
> +		"HiFi Playback", 0, SND_SOC_NOPM, 0, 0),

This doesn't seem to do anything, just drop it.

> +	SND_SOC_DAPM_DAC("DAC Enable",

I'd just call this DAC.

> +		"HiFi Playback", MAX98371_SPK_ENABLE, 0, 0),

Drop the "HiFi Playback" here and connect the DAC in the routes to the "HiFi
Playback" widget.

> +	SND_SOC_DAPM_SUPPLY("Global Enable",
> +		MAX98371_GLOBAL_ENABLE, 0, 0, NULL, 0),
> +	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
> +};
> +static struct snd_soc_dai_ops max98371_dai_ops = {

const

> +	.set_fmt = max98371_dai_set_fmt,
> +	.hw_params = max98371_dai_hw_params,
> +};
> +
[...]
> +static struct snd_soc_codec_driver max98371_codec = {

const

> +	.controls = max98371_snd_controls,
> +	.num_controls = ARRAY_SIZE(max98371_snd_controls),
> +	.dapm_routes = max98371_audio_map,
> +	.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
> +	.dapm_widgets = max98371_dapm_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
> +};
> +
> +static const struct regmap_config max98371_regmap = {
> +	.reg_bits         = 8,
> +	.val_bits         = 8,
> +	.max_register     = MAX98371_VERSION,
> +	.reg_defaults     = max98371_reg,
> +	.num_reg_defaults = ARRAY_SIZE(max98371_reg),
> +	.volatile_reg     = max98371_volatile_register,
> +	.readable_reg     = max98371_readable_register,
> +	.cache_type       = REGCACHE_RBTREE,
> +};
> +
> +static int max98371_i2c_probe(struct i2c_client *i2c,
> +		const struct i2c_device_id *id)
> +{
> +	struct max98371_priv *max98371;
> +	int ret, reg;
> +
> +	max98371 = devm_kzalloc(&i2c->dev,
> +			sizeof(*max98371), GFP_KERNEL);
> +	if (!max98371)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(i2c, max98371);
> +	max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
> +	if (IS_ERR(max98371->regmap)) {
> +		ret = PTR_ERR(max98371->regmap);
> +		dev_err(&i2c->dev,
> +				"Failed to allocate regmap: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
> +	if (ret < 0) {
> +		dev_info(&i2c->dev, "device error %d\n", ret);
> +		return ret;
> +	}
> +	dev_info(&i2c->dev, "device version %x\n", reg);

Drop this, it is just noise in the boot log.

> +
> +	ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
> +			max98371_dai, ARRAY_SIZE(max98371_dai));
> +	if (ret < 0) {
> +		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
> +		return ret;
> +	}
> +	return ret;
> +}

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-28 19:13 ` Mark Brown
@ 2016-04-07 19:34   ` anish kumar
  0 siblings, 0 replies; 27+ messages in thread
From: anish kumar @ 2016-04-07 19:34 UTC (permalink / raw)
  To: Mark Brown; +Cc: Linux-ALSA, Liam Girdwood

On Mon, Mar 28, 2016 at 12:13 PM, Mark Brown <broonie@kernel.org> wrote:
> On Mon, Mar 21, 2016 at 11:53:25PM -0700, anish kumar wrote:
>
>> +static const char *const voltage_level_text[] = {
>> +     "9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
>> +     "13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
>> +     "18.5dB", "19.5dB", "20.5dB"
>> +};
>
> These look like this control is a gain and so I'd expect it to be a
> normal TLV control.  What does this control do exactly?

It is "Speaker No-Load Output Voltage Maximum". It is
described here on page 50.
https://datasheets.maximintegrated.com/en/ds/MAX98371.pdf

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH] ASoC: Add max98371 codec driver
  2016-03-22  6:53 anish kumar
@ 2016-03-28 19:13 ` Mark Brown
  2016-04-07 19:34   ` anish kumar
  2016-04-08  3:09 ` Lars-Peter Clausen
  1 sibling, 1 reply; 27+ messages in thread
From: Mark Brown @ 2016-03-28 19:13 UTC (permalink / raw)
  To: anish kumar; +Cc: alsa-devel, lgirdwood


[-- Attachment #1.1: Type: text/plain, Size: 386 bytes --]

On Mon, Mar 21, 2016 at 11:53:25PM -0700, anish kumar wrote:

> +static const char *const voltage_level_text[] = {
> +	"9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
> +	"13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
> +	"18.5dB", "19.5dB", "20.5dB"
> +};

These look like this control is a gain and so I'd expect it to be a
normal TLV control.  What does this control do exactly?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH] ASoC: Add max98371 codec driver
@ 2016-03-22  6:53 anish kumar
  2016-03-28 19:13 ` Mark Brown
  2016-04-08  3:09 ` Lars-Peter Clausen
  0 siblings, 2 replies; 27+ messages in thread
From: anish kumar @ 2016-03-22  6:53 UTC (permalink / raw)
  To: broonie, lgirdwood; +Cc: alsa-devel, anish kumar

Signed-off-by: anish kumar <yesanishhere@gmail.com>
---
Changes in this version:
1. Removed the probe callback as it was not used.
2. Replaced the control with tlv
 .../devicetree/bindings/sound/max98371.txt         |  17 +
 sound/soc/codecs/max98371.c                        | 427 +++++++++++++++++++++
 sound/soc/codecs/max98371.h                        |  64 +++
 3 files changed, 508 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/max98371.txt
 create mode 100644 sound/soc/codecs/max98371.c
 create mode 100644 sound/soc/codecs/max98371.h

diff --git a/Documentation/devicetree/bindings/sound/max98371.txt b/Documentation/devicetree/bindings/sound/max98371.txt
new file mode 100644
index 0000000..6c28523
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/max98371.txt
@@ -0,0 +1,17 @@
+max98371 codec
+
+This device supports I2C mode only.
+
+Required properties:
+
+- compatible : "maxim,max98371"
+- reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+	max98371: max98371@0x31 {
+		compatible = "maxim,max98371";
+		reg = <0x31>;
+	};
+};
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
new file mode 100644
index 0000000..fe7f08f
--- /dev/null
+++ b/sound/soc/codecs/max98371.c
@@ -0,0 +1,427 @@
+/*
+ * max98371.c -- ALSA SoC Stereo MAX98371 driver
+ *
+ * Copyright 2015-16 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98371.h"
+
+static const char *const monomix_text[] = {
+	"Left", "Right", "LeftRightDiv2",
+};
+
+static const char *const voltage_level_text[] = {
+	"9.5dB", "10.5dB", "11.5dB", "11.5dB", "12.5dB",
+	"13.5dB", "14.5dB", "15.5dB", "16.5dB", "17.5dB",
+	"18.5dB", "19.5dB", "20.5dB"
+};
+
+static const char *const hpf_cutoff_txt[] = {
+	"Disable", "DC Block", "50Hz",
+	"100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98371_voltage, MAX98371_GAIN, 0,
+		voltage_level_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0,
+		monomix_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0,
+		hpf_cutoff_txt);
+
+static struct reg_default max98371_reg[] = {
+	{ 0x01, 0x00 },
+	{ 0x02, 0x00 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0A, 0x00 },
+	{ 0x10, 0x06 },
+	{ 0x11, 0x08 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1C, 0x00 },
+	{ 0x1D, 0x00 },
+	{ 0x1E, 0x00 },
+	{ 0x1F, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2A, 0x00 },
+	{ 0x2B, 0x00 },
+	{ 0x2C, 0x00 },
+	{ 0x2D, 0x00 },
+	{ 0x2E, 0x0B },
+	{ 0x31, 0x00 },
+	{ 0x32, 0x18 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x00 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x00 },
+	{ 0x3A, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3C, 0x00 },
+	{ 0x3D, 0x00 },
+	{ 0x3E, 0x00 },
+	{ 0x3F, 0x00 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x42, 0x00 },
+	{ 0x43, 0x00 },
+	{ 0x4A, 0x00 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x4D, 0x00 },
+	{ 0x4E, 0x00 },
+	{ 0x50, 0x00 },
+	{ 0x51, 0x00 },
+	{ 0x55, 0x00 },
+	{ 0x58, 0x00 },
+	{ 0x59, 0x00 },
+	{ 0x5C, 0x00 },
+	{ 0xFF, 0x43 },
+};
+
+static bool max98371_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_IRQ_CLEAR1:
+	case MAX98371_IRQ_CLEAR2:
+	case MAX98371_IRQ_CLEAR3:
+	case MAX98371_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98371_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_SOFT_RESET:
+		return false;
+	default:
+		return true;
+	}
+};
+
+static const unsigned int max98371_gain_tlv[] = {
+	0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
+	9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
+	11, 15, TLV_DB_SCALE_ITEM(0, 0, 0),
+};
+
+static const unsigned int max98371_noload_gain_tlv[] = {
+	0, 11, TLV_DB_SCALE_ITEM(0, 100, 0),
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1);
+
+static const struct snd_kcontrol_new max98371_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98371_GAIN,
+			MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
+			max98371_gain_tlv),
+	SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0,
+			(1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv),
+	SOC_SINGLE_TLV("Speaker No-load Volume", MAX98371_GAIN,
+			0, (1<<MAX98371_NO_LOAD_WIDTH)-1, 0,
+			max98371_noload_gain_tlv),
+	SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0),
+	SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0),
+	SOC_ENUM("Voltage Level", max98371_voltage),
+	SOC_ENUM("Monomix Select", max98371_monomix),
+	SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff),
+};
+
+static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(codec->dev, "DAI clock mode unsupported");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= 0;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= MAX98371_DAI_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= MAX98371_DAI_LEFT;
+		break;
+	default:
+		dev_err(codec->dev, "DAI wrong mode unsupported");
+		return -EINVAL;
+	}
+	regmap_update_bits(max98371->regmap, MAX98371_FMT,
+			MAX98371_FMT_MODE_MASK, val);
+	return 0;
+}
+
+static int max98371_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec);
+	int blr_clk_ratio, ch_size, channels = params_channels(params);
+	int rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 32;
+		break;
+	default:
+		pr_info("%s: format unsupported %d",
+				__func__, params_format(params));
+		return -EINVAL;
+	}
+
+	/* BCLK/LRCLK ratio calculation */
+	blr_clk_ratio = channels * ch_size;
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64);
+		break;
+	default:
+		pr_info("%s: ratio unsupported %d", __func__, blr_clk_ratio);
+		return -EINVAL;
+	}
+
+	switch (rate) {
+	case 32000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32);
+		break;
+	case 44100:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44);
+		break;
+	case 48000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48);
+		break;
+	case 88200:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88);
+		break;
+	case 96000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96);
+		break;
+	default:
+		pr_info("%s: rate unsupported %d", __func__, rate);
+		return -EINVAL;
+	}
+
+	/* enabling both the RX channels*/
+	regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC,
+			MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1);
+	regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL,
+			MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAI_OUT",
+		"HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Enable",
+		"HiFi Playback", MAX98371_SPK_ENABLE, 0, 0),
+	SND_SOC_DAPM_SUPPLY("Global Enable",
+		MAX98371_GLOBAL_ENABLE, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98371_audio_map[] = {
+	{"DAC Enable", NULL, "DAI_OUT"},
+	{"SPK_OUT", NULL, "DAC Enable"},
+	{"SPK_OUT", NULL, "Global Enable"},
+};
+
+#define MAX98371_RATES SNDRV_PCM_RATE_8000_48000
+#define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static struct snd_soc_dai_ops max98371_dai_ops = {
+	.set_fmt = max98371_dai_set_fmt,
+	.hw_params = max98371_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98371_dai[] = {
+	{
+		.name = "max98371-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98371_FORMATS,
+		},
+		.ops = &max98371_dai_ops,
+	}
+};
+
+static struct snd_soc_codec_driver max98371_codec = {
+	.controls = max98371_snd_controls,
+	.num_controls = ARRAY_SIZE(max98371_snd_controls),
+	.dapm_routes = max98371_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
+	.dapm_widgets = max98371_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
+};
+
+static const struct regmap_config max98371_regmap = {
+	.reg_bits         = 8,
+	.val_bits         = 8,
+	.max_register     = MAX98371_VERSION,
+	.reg_defaults     = max98371_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98371_reg),
+	.volatile_reg     = max98371_volatile_register,
+	.readable_reg     = max98371_readable_register,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98371_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct max98371_priv *max98371;
+	int ret, reg;
+
+	max98371 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98371), GFP_KERNEL);
+	if (!max98371)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98371);
+	max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
+	if (IS_ERR(max98371->regmap)) {
+		ret = PTR_ERR(max98371->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
+	if (ret < 0) {
+		dev_info(&i2c->dev, "device error %d\n", ret);
+		return ret;
+	}
+	dev_info(&i2c->dev, "device version %x\n", reg);
+
+	ret = snd_soc_register_codec(&i2c->dev, &max98371_codec,
+			max98371_dai, ARRAY_SIZE(max98371_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static int max98371_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id max98371_i2c_id[] = {
+	{ "max98371", 0 },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
+
+static const struct of_device_id max98371_of_match[] = {
+	{ .compatible = "maxim,max98371", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98371_of_match);
+
+static struct i2c_driver max98371_i2c_driver = {
+	.driver = {
+		.name = "max98371",
+		.owner = THIS_MODULE,
+		.pm = NULL,
+		.of_match_table = of_match_ptr(max98371_of_match),
+	},
+	.probe  = max98371_i2c_probe,
+	.remove = max98371_i2c_remove,
+	.id_table = max98371_i2c_id,
+};
+
+module_i2c_driver(max98371_i2c_driver);
+
+MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC MAX98371 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h
new file mode 100644
index 0000000..c75b259
--- /dev/null
+++ b/sound/soc/codecs/max98371.h
@@ -0,0 +1,64 @@
+/*
+ * max98371.h -- MAX98371 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98371_H
+#define _MAX98371_H
+
+#define MAX98371_IRQ_CLEAR1			0x01
+#define MAX98371_IRQ_CLEAR2			0x02
+#define MAX98371_IRQ_CLEAR3			0x03
+#define MAX98371_DAI_CLK			0x10
+#define MAX98371_DAI_BSEL_MASK			0xF
+#define MAX98371_DAI_BSEL_32			2
+#define MAX98371_DAI_BSEL_48			3
+#define MAX98371_DAI_BSEL_64			4
+#define MAX98371_SPK_SR				0x11
+#define MAX98371_SPK_SR_MASK			0xF
+#define MAX98371_SPK_SR_32			6
+#define MAX98371_SPK_SR_44			7
+#define MAX98371_SPK_SR_48			8
+#define MAX98371_SPK_SR_88			10
+#define MAX98371_SPK_SR_96			11
+#define MAX98371_DAI_CHANNEL			0x15
+#define MAX98371_CHANNEL_MASK			0x3
+#define MAX98371_MONOMIX_SRC			0x18
+#define MAX98371_MONOMIX_CFG			0x19
+#define MAX98371_HPF				0x1C
+#define MAX98371_MONOMIX_SRC_MASK		0xFF
+#define MONOMIX_RX_0_1				((0x1)<<(4))
+#define M98371_DAI_CHANNEL_I2S			0x3
+#define MAX98371_DIGITAL_GAIN			0x2D
+#define MAX98371_DIGITAL_GAIN_WIDTH		0x7
+#define MAX98371_GAIN				0x2E
+#define MAX98371_GAIN_SHIFT			0x4
+#define MAX98371_GAIN_WIDTH			0x4
+#define MAX98371_NO_LOAD_WIDTH			4
+#define MAX98371_FMT				0x14
+#define MAX98371_CHANSZ_WIDTH			6
+#define MAX98371_FMT_MASK		        ((0x3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_FMT_MODE_MASK		        ((0x7)<<(3))
+#define MAX98371_DAI_LEFT		        ((0x1)<<(3))
+#define MAX98371_DAI_RIGHT		        ((0x2)<<(3))
+#define MAX98371_DAI_CHANSZ_16                  ((1)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_24                  ((2)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_32                  ((3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DHT  0x32
+#define MAX98371_DHT_STEP			0x3
+#define MAX98371_SPK_ENABLE			0x4A
+#define MAX98371_GLOBAL_ENABLE			0x50
+#define MAX98371_SOFT_RESET			0x51
+#define MAX98371_VERSION			0xFF
+
+
+struct max98371_priv {
+	struct regmap *regmap;
+	struct snd_soc_codec *codec;
+};
+#endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2016-04-27 22:39 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-21  1:59 [PATCH] ASoC: Add max98371 codec driver anish kumar
2016-03-21 14:56 ` Mark Brown
2016-03-21 15:29   ` Micka
2016-03-21 15:56     ` Mark Brown
2016-03-21 16:41       ` Micka
2016-03-21 17:05         ` Mark Brown
2016-03-23 12:45           ` Micka
2016-03-23 16:23             ` Amish Kumar
2016-03-24 10:49   ` Micka
2016-03-24 11:05     ` Mark Brown
2016-03-24 11:19       ` Micka
2016-03-24 11:21         ` Mark Brown
2016-03-22  6:53 anish kumar
2016-03-28 19:13 ` Mark Brown
2016-04-07 19:34   ` anish kumar
2016-04-08  3:09 ` Lars-Peter Clausen
2016-04-08 20:04   ` anish kumar
2016-04-10 18:04   ` Mark Brown
2016-04-13 20:20 anish kumar
2016-04-18 16:47 ` Mark Brown
2016-04-18 20:20   ` anish kumar
2016-04-19  9:46     ` Mark Brown
2016-04-20 18:14       ` anish kumar
2016-04-22 15:31         ` Mark Brown
2016-04-26 18:16           ` anish kumar
2016-04-27 16:42             ` Mark Brown
2016-04-27 22:39 anish kumar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.