Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/4] ASoC: codecs: some more improvements for adau1701
@ 2013-06-24 14:31 Daniel Mack
  2013-06-24 14:31 ` [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset() Daniel Mack
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Daniel Mack @ 2013-06-24 14:31 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lars, Daniel Mack

v4:
	- added one more patch to move the firmware download,
	  for more clarity.
	- postpone the firmware download to the first call of
	  hw_params(), so we don't need to pass a default pll div in DT.
	- drop adi,pll-clkdiv entirely

v3:
	- fixed documentation for adi,pll-clkdiv
	- droped implicit I2C_M_STOP
	- moved regcache_sync() to adau1761_reset()
	- added regcache_mark_dirty()
	- made gpio_pll_mode and array
	- dropped ADAU1701_CLKDIV_MCLK_LRCLK


Daniel Mack (4):
  ASoC: codecs: adau1701: move firmware download to adau1701_reset()
  ASoC: codecs: adau1701: allow configuration of PLL mode pins
  ASoC: codecs: adau1701: switch to direct regmap API usage
  ASoC: codecs: adau1701: add support for pin muxing

 .../devicetree/bindings/sound/adi,adau1701.txt     |  12 +
 sound/soc/codecs/adau1701.c                        | 277 ++++++++++++++++-----
 2 files changed, 232 insertions(+), 57 deletions(-)

-- 
1.8.1.4

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

* [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset()
  2013-06-24 14:31 [PATCH v4 0/4] ASoC: codecs: some more improvements for adau1701 Daniel Mack
@ 2013-06-24 14:31 ` Daniel Mack
  2013-06-24 17:12   ` Lars-Peter Clausen
  2013-06-24 14:31 ` [PATCH v4 2/4] ASoC: codecs: adau1701: allow configuration of PLL mode pins Daniel Mack
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Daniel Mack @ 2013-06-24 14:31 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lars, Daniel Mack

The chip needs a new download after each reset, so the code to do that
needs to live in adau1701_reset().

Signed-off-by: Daniel Mack <zonque@gmail.com>
---
 sound/soc/codecs/adau1701.c | 32 ++++++++++++--------------------
 1 file changed, 12 insertions(+), 20 deletions(-)

diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index b6b1a77..997fc3b 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -184,27 +184,20 @@ static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
 	return value;
 }
 
-static void adau1701_reset(struct snd_soc_codec *codec)
+static int adau1701_reset(struct snd_soc_codec *codec)
 {
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
-
-	if (!gpio_is_valid(adau1701->gpio_nreset))
-		return;
-
-	gpio_set_value(adau1701->gpio_nreset, 0);
-	/* minimum reset time is 20ns */
-	udelay(1);
-	gpio_set_value(adau1701->gpio_nreset, 1);
-	/* power-up time may be as long as 85ms */
-	mdelay(85);
-}
-
-static int adau1701_init(struct snd_soc_codec *codec)
-{
-	int ret;
 	struct i2c_client *client = to_i2c_client(codec->dev);
+	int ret;
 
-	adau1701_reset(codec);
+	if (gpio_is_valid(adau1701->gpio_nreset)) {
+		gpio_set_value(adau1701->gpio_nreset, 0);
+		/* minimum reset time is 20ns */
+		udelay(1);
+		gpio_set_value(adau1701->gpio_nreset, 1);
+		/* power-up time may be as long as 85ms */
+		mdelay(85);
+	}
 
 	ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
 	if (ret) {
@@ -213,6 +206,7 @@ static int adau1701_init(struct snd_soc_codec *codec)
 	}
 
 	snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+	snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
 
 	return 0;
 }
@@ -498,12 +492,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 
 	codec->control_data = to_i2c_client(codec->dev);
 
-	ret = adau1701_init(codec);
+	ret = adau1701_reset(codec);
 	if (ret)
 		return ret;
 
-	snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
-
 	return 0;
 }
 
-- 
1.8.1.4

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

* [PATCH v4 2/4] ASoC: codecs: adau1701: allow configuration of PLL mode pins
  2013-06-24 14:31 [PATCH v4 0/4] ASoC: codecs: some more improvements for adau1701 Daniel Mack
  2013-06-24 14:31 ` [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset() Daniel Mack
@ 2013-06-24 14:31 ` Daniel Mack
  2013-06-24 14:31 ` [PATCH v4 3/4] ASoC: codecs: adau1701: switch to direct regmap API usage Daniel Mack
  2013-06-24 14:31 ` [PATCH v4 4/4] ASoC: codecs: adau1701: add support for pin muxing Daniel Mack
  3 siblings, 0 replies; 7+ messages in thread
From: Daniel Mack @ 2013-06-24 14:31 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lars, Daniel Mack

The ADAU1701 has 2 hardware pins to configure the PLL mode in accordance
to the MCLK-to-LRCLK ratio. These pins have to be stable before the chip
is released from reset, and a full reset cycle, including a new firmware
download is needed whenever they change.

This patch adds GPIO properties to the DT bindings of the Codec, and
implements makes the set_sysclk memorize the configured sysclk.

Because the run-time parameters are unknown at probe time, the first
firmware download is postponed to the first hw_params call, when the
driver can determine the mclk/lrclk divider. Subsequent downloads
are only issued when the divider configuration changes.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
---
 .../devicetree/bindings/sound/adi,adau1701.txt     |   6 ++
 sound/soc/codecs/adau1701.c                        | 105 +++++++++++++++++++--
 2 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
index 3afeda7..a9fbed1 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau1701.txt
+++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
@@ -11,6 +11,11 @@ Optional properties:
  - reset-gpio: 		A GPIO spec to define which pin is connected to the
 			chip's !RESET pin. If specified, the driver will
 			assert a hardware reset at probe time.
+ - adi,pll-mode-gpios:	An array of two GPIO specs to describe the GPIOs
+			the ADAU's PLL config pins are connected to.
+			The state of the pins are set according to the
+			configured clock divider on ASoC side before the
+			firmware is loaded.
 
 Examples:
 
@@ -19,5 +24,6 @@ Examples:
 			compatible = "adi,adau1701";
 			reg = <0x34>;
 			reset-gpio = <&gpio 23 0>;
+			adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
 		};
 	};
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 997fc3b..770d90e 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -87,11 +87,16 @@
 #define ADAU1701_OSCIPOW_OPD		0x04
 #define ADAU1701_DACSET_DACINIT		1
 
+#define ADAU1707_CLKDIV_UNSET		(-1UL)
+
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
 struct adau1701 {
 	int gpio_nreset;
+	int gpio_pll_mode[2];
 	unsigned int dai_fmt;
+	unsigned int pll_clkdiv;
+	unsigned int sysclk;
 };
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -184,12 +189,38 @@ static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
 	return value;
 }
 
-static int adau1701_reset(struct snd_soc_codec *codec)
+static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
 {
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 	struct i2c_client *client = to_i2c_client(codec->dev);
 	int ret;
 
+	if (clkdiv != ADAU1707_CLKDIV_UNSET &&
+	    gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
+	    gpio_is_valid(adau1701->gpio_pll_mode[1])) {
+		switch (clkdiv) {
+		case 64:
+			gpio_set_value(adau1701->gpio_pll_mode[0], 0);
+			gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+			break;
+		case 256:
+			gpio_set_value(adau1701->gpio_pll_mode[0], 0);
+			gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+			break;
+		case 384:
+			gpio_set_value(adau1701->gpio_pll_mode[0], 1);
+			gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+			break;
+		case 0:	/* fallback */
+		case 512:
+			gpio_set_value(adau1701->gpio_pll_mode[0], 1);
+			gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+			break;
+		}
+	}
+
+	adau1701->pll_clkdiv = clkdiv;
+
 	if (gpio_is_valid(adau1701->gpio_nreset)) {
 		gpio_set_value(adau1701->gpio_nreset, 0);
 		/* minimum reset time is 20ns */
@@ -199,10 +230,16 @@ static int adau1701_reset(struct snd_soc_codec *codec)
 		mdelay(85);
 	}
 
-	ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
-	if (ret) {
-		dev_warn(codec->dev, "Failed to load firmware\n");
-		return ret;
+	/*
+	 * Postpone the firmware download to a point in time when we
+	 * know the correct PLL setup
+	 */
+	if (clkdiv != ADAU1707_CLKDIV_UNSET) {
+		ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
+		if (ret) {
+			dev_warn(codec->dev, "Failed to load firmware\n");
+			return ret;
+		}
 	}
 
 	snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
@@ -285,8 +322,22 @@ static int adau1701_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 adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+	unsigned int clkdiv = adau1701->sysclk / params_rate(params);
 	snd_pcm_format_t format;
 	unsigned int val;
+	int ret;
+
+	/*
+	 * If the mclk/lrclk ratio changes, the chip needs updated PLL
+	 * mode GPIO settings, and a full reset cycle, including a new
+	 * firmware upload.
+	 */
+	if (clkdiv != adau1701->pll_clkdiv) {
+		ret = adau1701_reset(codec, clkdiv);
+		if (ret < 0)
+			return ret;
+	}
 
 	switch (params_rate(params)) {
 	case 192000:
@@ -429,6 +480,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	int source, unsigned int freq, int dir)
 {
 	unsigned int val;
+	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 
 	switch (clk_id) {
 	case ADAU1701_CLK_SRC_OSC:
@@ -442,6 +494,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
 	}
 
 	snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val);
+	adau1701->sysclk = freq;
 
 	return 0;
 }
@@ -489,11 +542,21 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
 static int adau1701_probe(struct snd_soc_codec *codec)
 {
 	int ret;
+	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 
 	codec->control_data = to_i2c_client(codec->dev);
 
-	ret = adau1701_reset(codec);
-	if (ret)
+	/*
+	 * Let the pll_clkdiv variable default to something that won't happen
+	 * at runtime. That way, we can postpone the firmware download from
+	 * adau1701_reset() to a point in time when we know the correct PLL
+	 * mode parameters.
+	 */
+	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
+
+	/* initalize with pre-configured pll mode settings */
+	ret = adau1701_reset(codec, adau1701->pll_clkdiv);
+	if (ret < 0)
 		return ret;
 
 	return 0;
@@ -526,6 +589,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 	struct adau1701 *adau1701;
 	struct device *dev = &client->dev;
 	int gpio_nreset = -EINVAL;
+	int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
 	int ret;
 
 	adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
@@ -536,6 +600,16 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 		gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
 		if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
 			return gpio_nreset;
+
+		gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
+						   "adi,pll-mode-gpios", 0);
+		if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
+			return gpio_pll_mode[0];
+
+		gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
+						   "adi,pll-mode-gpios", 1);
+		if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
+			return gpio_pll_mode[1];
 	}
 
 	if (gpio_is_valid(gpio_nreset)) {
@@ -545,7 +619,24 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 			return ret;
 	}
 
+	if (gpio_is_valid(gpio_pll_mode[0]) &&
+	    gpio_is_valid(gpio_pll_mode[1])) {
+		ret = devm_gpio_request_one(dev, gpio_pll_mode[0],
+					    GPIOF_OUT_INIT_LOW,
+					    "ADAU1701 PLL mode 0");
+		if (ret < 0)
+			return ret;
+
+		ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
+					    GPIOF_OUT_INIT_LOW,
+					    "ADAU1701 PLL mode 1");
+		if (ret < 0)
+			return ret;
+	}
+
 	adau1701->gpio_nreset = gpio_nreset;
+	adau1701->gpio_pll_mode[0] = gpio_pll_mode[0];
+	adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
 
 	i2c_set_clientdata(client, adau1701);
 	ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
-- 
1.8.1.4

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

* [PATCH v4 3/4] ASoC: codecs: adau1701: switch to direct regmap API usage
  2013-06-24 14:31 [PATCH v4 0/4] ASoC: codecs: some more improvements for adau1701 Daniel Mack
  2013-06-24 14:31 ` [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset() Daniel Mack
  2013-06-24 14:31 ` [PATCH v4 2/4] ASoC: codecs: adau1701: allow configuration of PLL mode pins Daniel Mack
@ 2013-06-24 14:31 ` Daniel Mack
  2013-06-24 17:08   ` Lars-Peter Clausen
  2013-06-24 14:31 ` [PATCH v4 4/4] ASoC: codecs: adau1701: add support for pin muxing Daniel Mack
  3 siblings, 1 reply; 7+ messages in thread
From: Daniel Mack @ 2013-06-24 14:31 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lars, Daniel Mack

The hardware I/O has to be open-coded due to registers of unequal sizes.
Other than that, the transition is straight forward.

Signed-off-by: Daniel Mack <zonque@gmail.com>
---
 sound/soc/codecs/adau1701.c | 118 +++++++++++++++++++++++++++++++-------------
 1 file changed, 85 insertions(+), 33 deletions(-)

diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 770d90e..881bab4 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -24,16 +25,16 @@
 #include "sigmadsp.h"
 #include "adau1701.h"
 
-#define ADAU1701_DSPCTRL	0x1c
-#define ADAU1701_SEROCTL	0x1e
-#define ADAU1701_SERICTL	0x1f
+#define ADAU1701_DSPCTRL	0x081c
+#define ADAU1701_SEROCTL	0x081e
+#define ADAU1701_SERICTL	0x081f
 
-#define ADAU1701_AUXNPOW	0x22
+#define ADAU1701_AUXNPOW	0x0822
 
-#define ADAU1701_OSCIPOW	0x26
-#define ADAU1701_DACSET		0x27
+#define ADAU1701_OSCIPOW	0x0826
+#define ADAU1701_DACSET		0x0827
 
-#define ADAU1701_NUM_REGS	0x28
+#define ADAU1701_MAX_REGISTER	0x0828
 
 #define ADAU1701_DSPCTRL_CR		(1 << 2)
 #define ADAU1701_DSPCTRL_DAM		(1 << 3)
@@ -97,6 +98,7 @@ struct adau1701 {
 	unsigned int dai_fmt;
 	unsigned int pll_clkdiv;
 	unsigned int sysclk;
+	struct regmap *regmap;
 };
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -128,7 +130,7 @@ static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
 	{ "ADC", NULL, "IN1" },
 };
 
-static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
+static unsigned int adau1701_register_size(struct device *dev,
 		unsigned int reg)
 {
 	switch (reg) {
@@ -142,33 +144,42 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
 		return 1;
 	}
 
-	dev_err(codec->dev, "Unsupported register address: %d\n", reg);
+	dev_err(dev, "Unsupported register address: %d\n", reg);
 	return 0;
 }
 
-static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
-		unsigned int value)
+static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
 {
+	switch (reg) {
+	case ADAU1701_DACSET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int adau1701_reg_write(void *context, unsigned int reg,
+			      unsigned int value)
+{
+	struct i2c_client *client = context;
 	unsigned int i;
 	unsigned int size;
 	uint8_t buf[4];
 	int ret;
 
-	size = adau1701_register_size(codec, reg);
+	size = adau1701_register_size(&client->dev, reg);
 	if (size == 0)
 		return -EINVAL;
 
-	snd_soc_cache_write(codec, reg, value);
-
-	buf[0] = 0x08;
-	buf[1] = reg;
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
 
 	for (i = size + 1; i >= 2; --i) {
 		buf[i] = value;
 		value >>= 8;
 	}
 
-	ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2);
+	ret = i2c_master_send(client, buf, size + 2);
 	if (ret == size + 2)
 		return 0;
 	else if (ret < 0)
@@ -177,16 +188,45 @@ static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
 		return -EIO;
 }
 
-static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
+static int adau1701_reg_read(void *context, unsigned int reg,
+			     unsigned int *value)
 {
-	unsigned int value;
-	unsigned int ret;
+	int ret;
+	unsigned int i;
+	unsigned int size;
+	uint8_t send_buf[2], recv_buf[3];
+	struct i2c_client *client = context;
+	struct i2c_msg msgs[2];
+
+	size = adau1701_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
 
-	ret = snd_soc_cache_read(codec, reg, &value);
-	if (ret)
+	send_buf[0] = reg >> 8;
+	send_buf[1] = reg & 0xff;
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(send_buf);
+	msgs[0].buf = send_buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = size;
+	msgs[1].buf = recv_buf;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
 		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*value = 0;
+
+	for (i = 0; i < size; i++)
+		*value |= recv_buf[i] << (i * 8);
 
-	return value;
+	return 0;
 }
 
 static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
@@ -242,8 +282,11 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
 		}
 	}
 
-	snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
-	snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+	regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+	regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+
+	regcache_mark_dirty(adau1701->regmap);
+	regcache_sync(adau1701->regmap);
 
 	return 0;
 }
@@ -429,8 +472,8 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
 	adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
-	snd_soc_write(codec, ADAU1701_SERICTL, serictl);
-	snd_soc_update_bits(codec, ADAU1701_SEROCTL,
+	regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl);
+	regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL,
 		~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
 
 	return 0;
@@ -567,9 +610,6 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
 	.set_bias_level		= adau1701_set_bias_level,
 	.idle_bias_off		= true,
 
-	.reg_cache_size		= ADAU1701_NUM_REGS,
-	.reg_word_size		= sizeof(u16),
-
 	.controls		= adau1701_controls,
 	.num_controls		= ARRAY_SIZE(adau1701_controls),
 	.dapm_widgets		= adau1701_dapm_widgets,
@@ -577,12 +617,19 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
 	.dapm_routes		= adau1701_dapm_routes,
 	.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
 
-	.write			= adau1701_write,
-	.read			= adau1701_read,
-
 	.set_sysclk		= adau1701_set_sysclk,
 };
 
+static const struct regmap_config adau1701_regmap = {
+	.reg_bits		= 16,
+	.val_bits		= 32,
+	.max_register		= ADAU1701_MAX_REGISTER,
+	.cache_type		= REGCACHE_RBTREE,
+	.volatile_reg		= adau1701_volatile_reg,
+	.reg_write		= adau1701_reg_write,
+	.reg_read		= adau1701_reg_read,
+};
+
 static int adau1701_i2c_probe(struct i2c_client *client,
 			      const struct i2c_device_id *id)
 {
@@ -596,6 +643,11 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 	if (!adau1701)
 		return -ENOMEM;
 
+	adau1701->regmap = devm_regmap_init(dev, NULL, client,
+					    &adau1701_regmap);
+	if (IS_ERR(adau1701->regmap))
+		return PTR_ERR(adau1701->regmap);
+
 	if (dev->of_node) {
 		gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
 		if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
-- 
1.8.1.4

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

* [PATCH v4 4/4] ASoC: codecs: adau1701: add support for pin muxing
  2013-06-24 14:31 [PATCH v4 0/4] ASoC: codecs: some more improvements for adau1701 Daniel Mack
                   ` (2 preceding siblings ...)
  2013-06-24 14:31 ` [PATCH v4 3/4] ASoC: codecs: adau1701: switch to direct regmap API usage Daniel Mack
@ 2013-06-24 14:31 ` Daniel Mack
  3 siblings, 0 replies; 7+ messages in thread
From: Daniel Mack @ 2013-06-24 14:31 UTC (permalink / raw)
  To: alsa-devel; +Cc: broonie, lars, Daniel Mack

The ADAU1701 has 12 pins that can be configured depending on the system
configuration. Allow settting the corresponding registers from DT.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
---
 .../devicetree/bindings/sound/adi,adau1701.txt     |  6 ++++
 sound/soc/codecs/adau1701.c                        | 32 ++++++++++++++++++++--
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
index a9fbed1..547a49b 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau1701.txt
+++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
@@ -16,6 +16,10 @@ Optional properties:
 			The state of the pins are set according to the
 			configured clock divider on ASoC side before the
 			firmware is loaded.
+ - adi,pin-config:	An array of 12 numerical values selecting one of the
+			pin configurations as described in the datasheet,
+			table 53. Note that the value of this property has
+			to be prefixed with '/bits/ 8'.
 
 Examples:
 
@@ -25,5 +29,7 @@ Examples:
 			reg = <0x34>;
 			reset-gpio = <&gpio 23 0>;
 			adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
+			adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
+                                                   0x4 0x4 0x4 0x4 0x4 0x4>;
 		};
 	};
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 881bab4..0e250f1 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -30,6 +30,9 @@
 #define ADAU1701_SERICTL	0x081f
 
 #define ADAU1701_AUXNPOW	0x0822
+#define ADAU1701_PINCONF_0	0x0820
+#define ADAU1701_PINCONF_1	0x0821
+#define ADAU1701_AUXNPOW	0x0822
 
 #define ADAU1701_OSCIPOW	0x0826
 #define ADAU1701_DACSET		0x0827
@@ -99,6 +102,7 @@ struct adau1701 {
 	unsigned int pll_clkdiv;
 	unsigned int sysclk;
 	struct regmap *regmap;
+	u8 pin_config[12];
 };
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -134,6 +138,9 @@ static unsigned int adau1701_register_size(struct device *dev,
 		unsigned int reg)
 {
 	switch (reg) {
+	case ADAU1701_PINCONF_0:
+	case ADAU1701_PINCONF_1:
+		return 3;
 	case ADAU1701_DSPCTRL:
 	case ADAU1701_SEROCTL:
 	case ADAU1701_AUXNPOW:
@@ -164,7 +171,7 @@ static int adau1701_reg_write(void *context, unsigned int reg,
 	struct i2c_client *client = context;
 	unsigned int i;
 	unsigned int size;
-	uint8_t buf[4];
+	uint8_t buf[5];
 	int ret;
 
 	size = adau1701_register_size(&client->dev, reg);
@@ -584,7 +591,8 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
 
 static int adau1701_probe(struct snd_soc_codec *codec)
 {
-	int ret;
+	int i, ret;
+	unsigned int val;
 	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 
 	codec->control_data = to_i2c_client(codec->dev);
@@ -602,6 +610,19 @@ static int adau1701_probe(struct snd_soc_codec *codec)
 	if (ret < 0)
 		return ret;
 
+	/* set up pin config */
+	val = 0;
+	for (i = 0; i < 6; i++)
+		val |= adau1701->pin_config[i] << (i * 4);
+
+	regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val);
+
+	val = 0;
+	for (i = 0; i < 6; i++)
+		val |= adau1701->pin_config[i + 6] << (i * 4);
+
+	regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
+
 	return 0;
 }
 
@@ -662,6 +683,13 @@ static int adau1701_i2c_probe(struct i2c_client *client,
 						   "adi,pll-mode-gpios", 1);
 		if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
 			return gpio_pll_mode[1];
+
+		of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
+				     &adau1701->pll_clkdiv);
+
+		of_property_read_u8_array(dev->of_node, "adi,pin-config",
+					  adau1701->pin_config,
+					  ARRAY_SIZE(adau1701->pin_config));
 	}
 
 	if (gpio_is_valid(gpio_nreset)) {
-- 
1.8.1.4

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

* Re: [PATCH v4 3/4] ASoC: codecs: adau1701: switch to direct regmap API usage
  2013-06-24 14:31 ` [PATCH v4 3/4] ASoC: codecs: adau1701: switch to direct regmap API usage Daniel Mack
@ 2013-06-24 17:08   ` Lars-Peter Clausen
  0 siblings, 0 replies; 7+ messages in thread
From: Lars-Peter Clausen @ 2013-06-24 17:08 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-devel, broonie

On 06/24/2013 04:31 PM, Daniel Mack wrote:
> The hardware I/O has to be open-coded due to registers of unequal sizes.
> Other than that, the transition is straight forward.
> 
> Signed-off-by: Daniel Mack <zonque@gmail.com>

Acked-by: Lars-Peter Clausen <lars@metafoo.de>

> ---
>  sound/soc/codecs/adau1701.c | 118 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 85 insertions(+), 33 deletions(-)
> 
> diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
> index 770d90e..881bab4 100644
> --- a/sound/soc/codecs/adau1701.c
> +++ b/sound/soc/codecs/adau1701.c
> @@ -16,6 +16,7 @@
>  #include <linux/of.h>
>  #include <linux/of_gpio.h>
>  #include <linux/of_device.h>
> +#include <linux/regmap.h>
>  #include <sound/core.h>
>  #include <sound/pcm.h>
>  #include <sound/pcm_params.h>
> @@ -24,16 +25,16 @@
>  #include "sigmadsp.h"
>  #include "adau1701.h"
>  
> -#define ADAU1701_DSPCTRL	0x1c
> -#define ADAU1701_SEROCTL	0x1e
> -#define ADAU1701_SERICTL	0x1f
> +#define ADAU1701_DSPCTRL	0x081c
> +#define ADAU1701_SEROCTL	0x081e
> +#define ADAU1701_SERICTL	0x081f
>  
> -#define ADAU1701_AUXNPOW	0x22
> +#define ADAU1701_AUXNPOW	0x0822
>  
> -#define ADAU1701_OSCIPOW	0x26
> -#define ADAU1701_DACSET		0x27
> +#define ADAU1701_OSCIPOW	0x0826
> +#define ADAU1701_DACSET		0x0827
>  
> -#define ADAU1701_NUM_REGS	0x28
> +#define ADAU1701_MAX_REGISTER	0x0828
>  
>  #define ADAU1701_DSPCTRL_CR		(1 << 2)
>  #define ADAU1701_DSPCTRL_DAM		(1 << 3)
> @@ -97,6 +98,7 @@ struct adau1701 {
>  	unsigned int dai_fmt;
>  	unsigned int pll_clkdiv;
>  	unsigned int sysclk;
> +	struct regmap *regmap;
>  };
>  
>  static const struct snd_kcontrol_new adau1701_controls[] = {
> @@ -128,7 +130,7 @@ static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
>  	{ "ADC", NULL, "IN1" },
>  };
>  
> -static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
> +static unsigned int adau1701_register_size(struct device *dev,
>  		unsigned int reg)
>  {
>  	switch (reg) {
> @@ -142,33 +144,42 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
>  		return 1;
>  	}
>  
> -	dev_err(codec->dev, "Unsupported register address: %d\n", reg);
> +	dev_err(dev, "Unsupported register address: %d\n", reg);
>  	return 0;
>  }
>  
> -static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
> -		unsigned int value)
> +static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
>  {
> +	switch (reg) {
> +	case ADAU1701_DACSET:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static int adau1701_reg_write(void *context, unsigned int reg,
> +			      unsigned int value)
> +{
> +	struct i2c_client *client = context;
>  	unsigned int i;
>  	unsigned int size;
>  	uint8_t buf[4];
>  	int ret;
>  
> -	size = adau1701_register_size(codec, reg);
> +	size = adau1701_register_size(&client->dev, reg);
>  	if (size == 0)
>  		return -EINVAL;
>  
> -	snd_soc_cache_write(codec, reg, value);
> -
> -	buf[0] = 0x08;
> -	buf[1] = reg;
> +	buf[0] = reg >> 8;
> +	buf[1] = reg & 0xff;
>  
>  	for (i = size + 1; i >= 2; --i) {
>  		buf[i] = value;
>  		value >>= 8;
>  	}
>  
> -	ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2);
> +	ret = i2c_master_send(client, buf, size + 2);
>  	if (ret == size + 2)
>  		return 0;
>  	else if (ret < 0)
> @@ -177,16 +188,45 @@ static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
>  		return -EIO;
>  }
>  
> -static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
> +static int adau1701_reg_read(void *context, unsigned int reg,
> +			     unsigned int *value)
>  {
> -	unsigned int value;
> -	unsigned int ret;
> +	int ret;
> +	unsigned int i;
> +	unsigned int size;
> +	uint8_t send_buf[2], recv_buf[3];
> +	struct i2c_client *client = context;
> +	struct i2c_msg msgs[2];
> +
> +	size = adau1701_register_size(&client->dev, reg);
> +	if (size == 0)
> +		return -EINVAL;
>  
> -	ret = snd_soc_cache_read(codec, reg, &value);
> -	if (ret)
> +	send_buf[0] = reg >> 8;
> +	send_buf[1] = reg & 0xff;
> +
> +	msgs[0].addr = client->addr;
> +	msgs[0].len = sizeof(send_buf);
> +	msgs[0].buf = send_buf;
> +	msgs[0].flags = 0;
> +
> +	msgs[1].addr = client->addr;
> +	msgs[1].len = size;
> +	msgs[1].buf = recv_buf;
> +	msgs[1].flags = I2C_M_RD;
> +
> +	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> +	if (ret < 0)
>  		return ret;
> +	else if (ret != ARRAY_SIZE(msgs))
> +		return -EIO;
> +
> +	*value = 0;
> +
> +	for (i = 0; i < size; i++)
> +		*value |= recv_buf[i] << (i * 8);
>  
> -	return value;
> +	return 0;
>  }
>  
>  static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
> @@ -242,8 +282,11 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
>  		}
>  	}
>  
> -	snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
> -	snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
> +	regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
> +	regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
> +
> +	regcache_mark_dirty(adau1701->regmap);
> +	regcache_sync(adau1701->regmap);
>  
>  	return 0;
>  }
> @@ -429,8 +472,8 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
>  
>  	adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
>  
> -	snd_soc_write(codec, ADAU1701_SERICTL, serictl);
> -	snd_soc_update_bits(codec, ADAU1701_SEROCTL,
> +	regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl);
> +	regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL,
>  		~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
>  
>  	return 0;
> @@ -567,9 +610,6 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
>  	.set_bias_level		= adau1701_set_bias_level,
>  	.idle_bias_off		= true,
>  
> -	.reg_cache_size		= ADAU1701_NUM_REGS,
> -	.reg_word_size		= sizeof(u16),
> -
>  	.controls		= adau1701_controls,
>  	.num_controls		= ARRAY_SIZE(adau1701_controls),
>  	.dapm_widgets		= adau1701_dapm_widgets,
> @@ -577,12 +617,19 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
>  	.dapm_routes		= adau1701_dapm_routes,
>  	.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
>  
> -	.write			= adau1701_write,
> -	.read			= adau1701_read,
> -
>  	.set_sysclk		= adau1701_set_sysclk,
>  };
>  
> +static const struct regmap_config adau1701_regmap = {
> +	.reg_bits		= 16,
> +	.val_bits		= 32,
> +	.max_register		= ADAU1701_MAX_REGISTER,
> +	.cache_type		= REGCACHE_RBTREE,
> +	.volatile_reg		= adau1701_volatile_reg,
> +	.reg_write		= adau1701_reg_write,
> +	.reg_read		= adau1701_reg_read,
> +};
> +
>  static int adau1701_i2c_probe(struct i2c_client *client,
>  			      const struct i2c_device_id *id)
>  {
> @@ -596,6 +643,11 @@ static int adau1701_i2c_probe(struct i2c_client *client,
>  	if (!adau1701)
>  		return -ENOMEM;
>  
> +	adau1701->regmap = devm_regmap_init(dev, NULL, client,
> +					    &adau1701_regmap);
> +	if (IS_ERR(adau1701->regmap))
> +		return PTR_ERR(adau1701->regmap);
> +
>  	if (dev->of_node) {
>  		gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
>  		if (gpio_nreset < 0 && gpio_nreset != -ENOENT)

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

* Re: [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset()
  2013-06-24 14:31 ` [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset() Daniel Mack
@ 2013-06-24 17:12   ` Lars-Peter Clausen
  0 siblings, 0 replies; 7+ messages in thread
From: Lars-Peter Clausen @ 2013-06-24 17:12 UTC (permalink / raw)
  To: Daniel Mack; +Cc: alsa-devel, broonie

On 06/24/2013 04:31 PM, Daniel Mack wrote:
> The chip needs a new download after each reset, so the code to do that
> needs to live in adau1701_reset().
> 
> Signed-off-by: Daniel Mack <zonque@gmail.com>

Acked-by: Lars-Peter Clausen <lars@metafoo.de>

> ---
>  sound/soc/codecs/adau1701.c | 32 ++++++++++++--------------------
>  1 file changed, 12 insertions(+), 20 deletions(-)
> 
> diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
> index b6b1a77..997fc3b 100644
> --- a/sound/soc/codecs/adau1701.c
> +++ b/sound/soc/codecs/adau1701.c
> @@ -184,27 +184,20 @@ static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
>  	return value;
>  }
>  
> -static void adau1701_reset(struct snd_soc_codec *codec)
> +static int adau1701_reset(struct snd_soc_codec *codec)
>  {
>  	struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
> -
> -	if (!gpio_is_valid(adau1701->gpio_nreset))
> -		return;
> -
> -	gpio_set_value(adau1701->gpio_nreset, 0);
> -	/* minimum reset time is 20ns */
> -	udelay(1);
> -	gpio_set_value(adau1701->gpio_nreset, 1);
> -	/* power-up time may be as long as 85ms */
> -	mdelay(85);
> -}
> -
> -static int adau1701_init(struct snd_soc_codec *codec)
> -{
> -	int ret;
>  	struct i2c_client *client = to_i2c_client(codec->dev);
> +	int ret;
>  
> -	adau1701_reset(codec);
> +	if (gpio_is_valid(adau1701->gpio_nreset)) {
> +		gpio_set_value(adau1701->gpio_nreset, 0);
> +		/* minimum reset time is 20ns */
> +		udelay(1);
> +		gpio_set_value(adau1701->gpio_nreset, 1);
> +		/* power-up time may be as long as 85ms */
> +		mdelay(85);
> +	}
>  
>  	ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
>  	if (ret) {
> @@ -213,6 +206,7 @@ static int adau1701_init(struct snd_soc_codec *codec)
>  	}
>  
>  	snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
> +	snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
>  
>  	return 0;
>  }
> @@ -498,12 +492,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
>  
>  	codec->control_data = to_i2c_client(codec->dev);
>  
> -	ret = adau1701_init(codec);
> +	ret = adau1701_reset(codec);
>  	if (ret)
>  		return ret;
>  
> -	snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
> -
>  	return 0;
>  }
>  

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

end of thread, other threads:[~2013-06-24 17:12 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-24 14:31 [PATCH v4 0/4] ASoC: codecs: some more improvements for adau1701 Daniel Mack
2013-06-24 14:31 ` [PATCH v4 1/4] ASoC: codecs: adau1701: move firmware download to adau1701_reset() Daniel Mack
2013-06-24 17:12   ` Lars-Peter Clausen
2013-06-24 14:31 ` [PATCH v4 2/4] ASoC: codecs: adau1701: allow configuration of PLL mode pins Daniel Mack
2013-06-24 14:31 ` [PATCH v4 3/4] ASoC: codecs: adau1701: switch to direct regmap API usage Daniel Mack
2013-06-24 17:08   ` Lars-Peter Clausen
2013-06-24 14:31 ` [PATCH v4 4/4] ASoC: codecs: adau1701: add support for pin muxing Daniel Mack

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox