All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] devicetree: Add devicetree bindings documentation for the ADAU1977
@ 2014-02-03 14:57 Lars-Peter Clausen
  2014-02-03 14:57 ` [PATCH 2/2] ASoC: Add ADAU1977 driver Lars-Peter Clausen
       [not found] ` <1391439428-3198-1-git-send-email-lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
  0 siblings, 2 replies; 9+ messages in thread
From: Lars-Peter Clausen @ 2014-02-03 14:57 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, Lars-Peter Clausen,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA

The ADAU1977 is a four channel audio ADC. It can either be connected to an I2C
or a SPI bus. Both bindings are described in this document. Other than the
standard I2C and SPI bus properties a regulator for the AVDD supply needs to be
specified in the bindings. Optionally, if present in the hardware design, a
regulator for the DVDD supply and a GPIO connected to the chips reset pin can be
specified. The bindings also allow to specify the microphone bias voltage that
should be used with the hardware design.

Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Ian Campbell <ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
Cc: Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
---
 .../devicetree/bindings/sound/adi,adau1977.txt     | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/adi,adau1977.txt

diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.txt b/Documentation/devicetree/bindings/sound/adi,adau1977.txt
new file mode 100644
index 0000000..3cf03d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/adi,adau1977.txt
@@ -0,0 +1,58 @@
+Analog Devices ADAU1977, ADAU1978, ADAU1979 devicetree bindings
+
+The ADAU1977 is a four channel audio ADC. It can either be connected to an I2C
+or a SPI bus. Both bindings are described in this document. Depending on the bus
+type different properties must/can be specified.
+
+Shared required properties:
+ - compatible: Must be "adi,adau1977", "adi,adau1978" or adi,adau1979"
+ - AVDD-supply: A handle to the power supply connected to the AVDD pin
+
+Shared optional properties:
+ - DVDD-supply: A handle to the power supply connected to the DVDD pin. If
+   specified the internal LDO will be disabled.
+ - reset-gpios: GPIO chip handle and specifier that define which GPIO is
+   connected to the chips PD/RST pin. If not specified the reset pin is assumed
+   to be hardwired to VCC.
+ - adi,micbias: Configures the voltage setting for the MICBIAS pin. If not
+   specified the default value will be 8.5 Volts. This property is only valid
+   for the ADAU1977.
+   Valid values for this property are:
+	0: 5.0V
+	1: 5.5V
+	2: 6.0V
+	3: 6.5V
+	4: 7.0V
+	5: 7.5V
+	6: 8.0V
+	7: 8.5V
+	8: 9.0V
+
+I2C required properties:
+ - reg: The I2C address of the chip
+
+SPI required properties:
+ - reg: The SPI chipselect signal of the SPI master associated with this chip
+ - spi-max-frequency: Maximum spi frequency to use.
+
+Examples:
+
+&i2c_bus {
+	adau1977: codec@11 {
+		compatible = "adi,adau1977";
+		reg = <0x11>;
+		reset-gpios = <&gpio 5 0>;
+		AVDD-supply = <&codec_avdd_supply>;
+		DVDD-supply = <&codec_dvdd_supply>;
+	};
+};
+
+&spi_bus {
+	adau1977: codec@1 {
+		compatible = "adi,adau1977";
+		reg = <0x1>;
+		spi-max-frequency = <10000000>;
+		AVDD-supply = <&codec_avdd_supply>;
+		adi,micbias = <5>;
+	};
+};
-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/2] ASoC: Add ADAU1977 driver
  2014-02-03 14:57 [PATCH 1/2] devicetree: Add devicetree bindings documentation for the ADAU1977 Lars-Peter Clausen
@ 2014-02-03 14:57 ` Lars-Peter Clausen
  2014-02-03 18:40   ` Mark Brown
       [not found] ` <1391439428-3198-1-git-send-email-lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
  1 sibling, 1 reply; 9+ messages in thread
From: Lars-Peter Clausen @ 2014-02-03 14:57 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood; +Cc: alsa-devel, Lars-Peter Clausen

This patch adds support for the ADAU1977, ADAU1978 and ADAU1979 audio CODEC
devices. They are a family of 4-channel differntial input audio ADC devices.
They can be connected to either a SPI or I2C bus.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 include/linux/platform_data/adau1977.h |  45 ++
 sound/soc/codecs/Kconfig               |  13 +
 sound/soc/codecs/Makefile              |   6 +
 sound/soc/codecs/adau1977-i2c.c        |  58 ++
 sound/soc/codecs/adau1977-spi.c        |  73 +++
 sound/soc/codecs/adau1977.c            | 994 +++++++++++++++++++++++++++++++++
 sound/soc/codecs/adau1977.h            |  37 ++
 7 files changed, 1226 insertions(+)
 create mode 100644 include/linux/platform_data/adau1977.h
 create mode 100644 sound/soc/codecs/adau1977-i2c.c
 create mode 100644 sound/soc/codecs/adau1977-spi.c
 create mode 100644 sound/soc/codecs/adau1977.c
 create mode 100644 sound/soc/codecs/adau1977.h

diff --git a/include/linux/platform_data/adau1977.h b/include/linux/platform_data/adau1977.h
new file mode 100644
index 0000000..bed11d9
--- /dev/null
+++ b/include/linux/platform_data/adau1977.h
@@ -0,0 +1,45 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__
+#define __LINUX_PLATFORM_DATA_ADAU1977_H__
+
+/**
+ * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting
+ * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V
+ * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V
+ * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V
+ * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V
+ * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V
+ * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V
+ * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V
+ * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V
+ * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V
+ */
+enum adau1977_micbias {
+	ADAU1977_MICBIAS_5V0 = 0x0,
+	ADAU1977_MICBIAS_5V5 = 0x1,
+	ADAU1977_MICBIAS_6V0 = 0x2,
+	ADAU1977_MICBIAS_6V5 = 0x3,
+	ADAU1977_MICBIAS_7V0 = 0x4,
+	ADAU1977_MICBIAS_7V5 = 0x5,
+	ADAU1977_MICBIAS_8V0 = 0x6,
+	ADAU1977_MICBIAS_8V5 = 0x7,
+	ADAU1977_MICBIAS_9V0 = 0x8,
+};
+
+/**
+ * struct adau1977_platform_data - Platform configuration data for the ADAU1977
+ * @micbias: Specifies the voltage for the MICBIAS pin
+ */
+struct adau1977_platform_data {
+	enum adau1977_micbias micbias;
+};
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 983d087a..f4f2907 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -20,6 +20,8 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
 	select SND_SOC_AD73311
 	select SND_SOC_ADAU1373 if I2C
+	select SND_SOC_ADAU1977_SPI if SPI_MASTER
+	select SND_SOC_ADAU1977_I2C if I2C
 	select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_ADAU1701 if I2C
 	select SND_SOC_ADS117X
@@ -195,6 +197,17 @@ config SND_SOC_ADAU1701
 config SND_SOC_ADAU1373
 	tristate
 
+config SND_SOC_ADAU1977
+	tristate
+
+config SND_SOC_ADAU1977_I2C
+	tristate
+	select SND_SOC_ADAU1977
+
+config SND_SOC_ADAU1977_SPI
+	tristate
+	select SND_SOC_ADAU1977
+
 config SND_SOC_ADAV80X
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bc12676..423c0f5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -7,6 +7,9 @@ snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
 snd-soc-adau1701-objs := adau1701.o
 snd-soc-adau1373-objs := adau1373.o
+snd-soc-adau1977-objs := adau1977.o
+snd-soc-adau1977-spi-objs := adau1977-spi.o
+snd-soc-adau1977-i2c-objs := adau1977-i2c.o
 snd-soc-adav80x-objs := adav80x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
@@ -137,6 +140,9 @@ obj-$(CONFIG_SND_SOC_AD193X)	+= snd-soc-ad193x.o
 obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADAU1373)	+= snd-soc-adau1373.o
+obj-$(CONFIG_SND_SOC_ADAU1977)		+= snd-soc-adau1977.o
+obj-$(CONFIG_SND_SOC_ADAU1977_SPI)	+= snd-soc-adau1977-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1977_I2C)	+= snd-soc-adau1977-i2c.o
 obj-$(CONFIG_SND_SOC_ADAU1701)  += snd-soc-adau1701.o
 obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
new file mode 100644
index 0000000..96d6161
--- /dev/null
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -0,0 +1,58 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "adau1977.h"
+
+static int adau1977_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = adau1977_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 8;
+
+	return adau1977_probe(&client->dev,
+		devm_regmap_init_i2c(client, &config),
+		id->driver_data, NULL);
+}
+
+static int adau1977_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id adau1977_i2c_ids[] = {
+	{ "adau1977", ADAU1977 },
+	{ "adau1978", ADAU1978 },
+	{ "adau1979", ADAU1978 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
+
+static struct i2c_driver adau1977_i2c_driver = {
+	.driver = {
+		.name = "adau1977",
+		.owner = THIS_MODULE,
+	},
+	.probe = adau1977_i2c_probe,
+	.remove = adau1977_i2c_remove,
+	.id_table = adau1977_i2c_ids,
+};
+module_i2c_driver(adau1977_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c
new file mode 100644
index 0000000..c7e0fbf
--- /dev/null
+++ b/sound/soc/codecs/adau1977-spi.c
@@ -0,0 +1,73 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static void adau1977_spi_switch_mode(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	/*
+	 * To get the device into SPI mode CLATCH has to be pulled low three
+	 * times.  Do this by issuing three dummy reads.
+	 */
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+}
+
+static int adau1977_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap_config config;
+
+	config = adau1977_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 16;
+	config.read_flag_mask = 0x1;
+
+	return adau1977_probe(&spi->dev,
+		devm_regmap_init_spi(spi, &config),
+		id->driver_data, adau1977_spi_switch_mode);
+}
+
+static int adau1977_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	return 0;
+}
+
+static const struct spi_device_id adau1977_spi_ids[] = {
+	{ "adau1977", ADAU1977 },
+	{ "adau1978", ADAU1978 },
+	{ "adau1979", ADAU1978 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adau1977_spi_ids);
+
+static struct spi_driver adau1977_spi_driver = {
+	.driver = {
+		.name = "adau1977",
+		.owner = THIS_MODULE,
+	},
+	.probe = adau1977_spi_probe,
+	.remove = adau1977_spi_remove,
+	.id_table = adau1977_spi_ids,
+};
+module_spi_driver(adau1977_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
new file mode 100644
index 0000000..568cb45
--- /dev/null
+++ b/sound/soc/codecs/adau1977.c
@@ -0,0 +1,994 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_data/adau1977.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "adau1977.h"
+
+#define ADAU1977_REG_POWER		0x00
+#define ADAU1977_REG_PLL		0x01
+#define ADAU1977_REG_BOOST		0x02
+#define ADAU1977_REG_MICBIAS		0x03
+#define ADAU1977_REG_BLOCK_POWER_SAI	0x04
+#define ADAU1977_REG_SAI_CTRL0		0x05
+#define ADAU1977_REG_SAI_CTRL1		0x06
+#define ADAU1977_REG_CMAP12		0x07
+#define ADAU1977_REG_CMAP34		0x08
+#define ADAU1977_REG_SAI_OVERTEMP	0x09
+#define ADAU1977_REG_POST_ADC_GAIN(x)	(0x0a + (x))
+#define ADAU1977_REG_MISC_CONTROL	0x0e
+#define ADAU1977_REG_DIAG_CONTROL	0x10
+#define ADAU1977_REG_STATUS(x)		(0x11 + (x))
+#define ADAU1977_REG_DIAG_IRQ1		0x15
+#define ADAU1977_REG_DIAG_IRQ2		0x16
+#define ADAU1977_REG_ADJUST1		0x17
+#define ADAU1977_REG_ADJUST2		0x18
+#define ADAU1977_REG_ADC_CLIP		0x19
+#define ADAU1977_REG_DC_HPF_CAL		0x1a
+
+#define ADAU1977_POWER_RESET			BIT(7)
+#define ADAU1977_POWER_PWUP			BIT(0)
+
+#define ADAU1977_PLL_CLK_S			BIT(4)
+#define ADAU1977_PLL_MCS_MASK			0x7
+
+#define ADAU1977_MICBIAS_MB_VOLTS_MASK		0xf0
+#define ADAU1977_MICBIAS_MB_VOLTS_OFFSET	4
+
+#define ADAU1977_BLOCK_POWER_SAI_LR_POL		BIT(7)
+#define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE	BIT(6)
+#define ADAU1977_BLOCK_POWER_SAI_LDO_EN		BIT(5)
+
+#define ADAU1977_SAI_CTRL0_FMT_MASK		(0x3 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_I2S		(0x0 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_LJ		(0x1 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT		(0x2 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT		(0x3 << 6)
+
+#define ADAU1977_SAI_CTRL0_SAI_MASK		(0x7 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_I2S		(0x0 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_2		(0x1 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_4		(0x2 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_8		(0x3 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_16		(0x4 << 3)
+
+#define ADAU1977_SAI_CTRL0_FS_MASK		(0x7)
+#define ADAU1977_SAI_CTRL0_FS_8000_12000	(0x0)
+#define ADAU1977_SAI_CTRL0_FS_16000_24000	(0x1)
+#define ADAU1977_SAI_CTRL0_FS_32000_48000	(0x2)
+#define ADAU1977_SAI_CTRL0_FS_64000_96000	(0x3)
+#define ADAU1977_SAI_CTRL0_FS_128000_192000	(0x4)
+
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK	(0x3 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32	(0x0 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24	(0x1 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16	(0x2 << 5)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK	(0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT	(0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT	(0x0 << 4)
+#define ADAU1977_SAI_CTRL1_LRCLK_PULSE		BIT(3)
+#define ADAU1977_SAI_CTRL1_MSB			BIT(2)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_16		(0x1 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_32		(0x0 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_MASK	(0x1 << 1)
+#define ADAU1977_SAI_CTRL1_MASTER		BIT(0)
+
+#define ADAU1977_SAI_OVERTEMP_DRV_C(x)		BIT(4 + (x))
+#define ADAU1977_SAI_OVERTEMP_DRV_HIZ		BIT(3)
+
+#define ADAU1977_MISC_CONTROL_SUM_MODE_MASK	(0x3 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_1CH	(0x2 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_2CH	(0x1 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_4CH	(0x0 << 6)
+#define ADAU1977_MISC_CONTROL_MMUTE		BIT(4)
+#define ADAU1977_MISC_CONTROL_DC_CAL		BIT(0)
+
+#define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET	4
+#define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET	0
+
+struct adau1977 {
+	struct regmap *regmap;
+	bool right_j;
+	unsigned int sysclk;
+	enum adau1977_sysclk_src sysclk_src;
+	struct gpio_desc *reset_gpio;
+	enum adau1977_type type;
+
+	struct regulator *avdd_reg;
+	struct regulator *dvdd_reg;
+
+	struct snd_pcm_hw_constraint_list constraints;
+
+	struct device *dev;
+	void (*switch_mode)(struct device *dev);
+
+	unsigned int max_master_fs;
+	unsigned int slot_width;
+	bool enabled;
+	bool master;
+};
+
+static const struct reg_default adau1977_reg_defaults[] = {
+	{ 0x00, 0x00 },
+	{ 0x01, 0x41 },
+	{ 0x02, 0x4a },
+	{ 0x03, 0x7d },
+	{ 0x04, 0x3d },
+	{ 0x05, 0x02 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x10 },
+	{ 0x08, 0x32 },
+	{ 0x09, 0xf0 },
+	{ 0x0a, 0xa0 },
+	{ 0x0b, 0xa0 },
+	{ 0x0c, 0xa0 },
+	{ 0x0d, 0xa0 },
+	{ 0x0e, 0x02 },
+	{ 0x10, 0x0f },
+	{ 0x15, 0x20 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x1a, 0x00 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000);
+
+static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS,
+		3, 0, NULL, 0)
+};
+
+static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI,
+		4, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0),
+	SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0),
+	SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0),
+
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+	SND_SOC_DAPM_INPUT("AIN4"),
+
+	SND_SOC_DAPM_OUTPUT("VREF"),
+};
+
+static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
+	{ "ADC1", NULL, "AIN1" },
+	{ "ADC2", NULL, "AIN2" },
+	{ "ADC3", NULL, "AIN3" },
+	{ "ADC4", NULL, "AIN4" },
+
+	{ "ADC1", NULL, "Vref" },
+	{ "ADC2", NULL, "Vref" },
+	{ "ADC3", NULL, "Vref" },
+	{ "ADC4", NULL, "Vref" },
+
+	{ "VREF", NULL, "Vref" },
+};
+
+#define ADAU1977_VOLUME(x) \
+	SOC_SINGLE_TLV("ADC" #x " Capture Volume", \
+		ADAU1977_REG_POST_ADC_GAIN((x) - 1), \
+		0, 255, 1, adau1977_adc_gain)
+
+#define ADAU1977_HPF_SWITCH(x) \
+	SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \
+		ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
+
+#define ADAU1977_DC_SUB_SWITCH(x) \
+	SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \
+		ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
+
+static const struct snd_kcontrol_new adau1977_snd_controls[] = {
+	ADAU1977_VOLUME(1),
+	ADAU1977_VOLUME(2),
+	ADAU1977_VOLUME(3),
+	ADAU1977_VOLUME(4),
+
+	ADAU1977_HPF_SWITCH(1),
+	ADAU1977_HPF_SWITCH(2),
+	ADAU1977_HPF_SWITCH(3),
+	ADAU1977_HPF_SWITCH(4),
+
+	ADAU1977_DC_SUB_SWITCH(1),
+	ADAU1977_DC_SUB_SWITCH(2),
+	ADAU1977_DC_SUB_SWITCH(3),
+	ADAU1977_DC_SUB_SWITCH(4),
+};
+
+static int adau1977_reset(struct adau1977 *adau1977)
+{
+	int ret;
+
+	/*
+	 * The reset bit is obviously volatile, but we need to be able to cache
+	 * the other bits in the register, so we can't just mark the whole
+	 * register as volatile. Since this is the only place where we'll ever
+	 * touch the reset bit just bypass the cache for this operation.
+	 */
+	regcache_cache_bypass(adau1977->regmap, true);
+	ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
+			ADAU1977_POWER_RESET);
+	regcache_cache_bypass(adau1977->regmap, false);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate)
+{
+	unsigned int mcs;
+
+	if (rate >= 8000 && rate <= 12000)
+		rate *= 512;
+	else if (rate >= 16000 && rate <= 24000)
+		rate *= 256;
+	else if (rate >= 32000 && rate <= 48000)
+		rate *= 128;
+	else if (rate >= 64000 && rate <= 96000)
+		rate *= 64;
+	else if (rate >= 128000 && rate <= 192000)
+		rate *= 32;
+	else
+		return -EINVAL;
+
+	if (adau1977->sysclk % rate != 0)
+		return -EINVAL;
+
+	mcs = adau1977->sysclk / rate;
+
+	/* The factors configured by MCS are 1, 2, 3, 4, 6 */
+	if (mcs < 1 || mcs > 6 || mcs == 5)
+		return -EINVAL;
+
+	mcs = mcs - 1;
+	if (mcs == 5)
+		mcs = 4;
+
+	return mcs;
+}
+
+static int adau1977_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 adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	unsigned int rate = params_rate(params);
+	unsigned int slot_width;
+	unsigned int ctrl0, ctrl0_mask;
+	unsigned int ctrl1;
+	int mcs;
+	int ret;
+
+	if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) {
+		mcs = adau1977_lookup_mcs(adau1977, rate);
+		if (mcs < 0)
+			return mcs;
+	} else {
+		mcs = 0;
+	}
+
+	ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK;
+
+	if (rate >= 8000 && rate <= 12000)
+		ctrl0 = ADAU1977_SAI_CTRL0_FS_8000_12000;
+	else if (rate >= 16000 && rate <= 24000)
+		ctrl0 = ADAU1977_SAI_CTRL0_FS_16000_24000;
+	else if (rate >= 32000 && rate <= 48000)
+		ctrl0 = ADAU1977_SAI_CTRL0_FS_32000_48000;
+	else if (rate >= 64000 && rate <= 96000)
+		ctrl0 = ADAU1977_SAI_CTRL0_FS_64000_96000;
+	else if (rate >= 128000 && rate <= 192000)
+		ctrl0 = ADAU1977_SAI_CTRL0_FS_128000_192000;
+	else
+		return -EINVAL;
+
+	if (adau1977->right_j) {
+		switch (params_width(params)) {
+		case 16:
+			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT;
+			break;
+		case 24:
+			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK;
+	}
+
+	if (adau1977->master) {
+		switch (params_width(params)) {
+		case 16:
+			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT;
+			slot_width = 16;
+			break;
+		case 24:
+		case 32:
+			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT;
+			slot_width = 32;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* In TDM mode there is a fixed slot width */
+		if (adau1977->slot_width)
+			slot_width = adau1977->slot_width;
+
+		if (slot_width == 16)
+			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16;
+		else
+			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32;
+
+		ret = regmap_update_bits(adau1977->regmap,
+			ADAU1977_REG_SAI_CTRL1,
+			ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK |
+			ADAU1977_SAI_CTRL1_BCLKRATE_MASK,
+			ctrl1);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+				ctrl0_mask, ctrl0);
+	if (ret < 0)
+		return ret;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+				ADAU1977_PLL_MCS_MASK, mcs);
+}
+
+static int adau1977_set_power(struct adau1977 *adau1977, bool enable)
+{
+	unsigned int val;
+	int ret = 0;
+
+	if (enable == adau1977->enabled)
+		return 0;
+
+	if (!enable) {
+		ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+			ADAU1977_POWER_PWUP, 0);
+		regcache_mark_dirty(adau1977->regmap);
+	} else {
+		ret = regulator_enable(adau1977->avdd_reg);
+		if (ret)
+			return ret;
+		if (adau1977->dvdd_reg) {
+			ret = regulator_enable(adau1977->dvdd_reg);
+			if (ret)
+				goto err_disable_avdd;
+		}
+	}
+
+	if (adau1977->reset_gpio)
+		gpiod_set_value(adau1977->reset_gpio, enable);
+
+	regcache_cache_only(adau1977->regmap, !enable);
+
+	if (enable) {
+		if (adau1977->switch_mode)
+			adau1977->switch_mode(adau1977->dev);
+
+		ret = adau1977_reset(adau1977);
+		if (ret)
+			goto err_disable_dvdd;
+		ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+			ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP);
+		if (ret)
+			goto err_disable_dvdd;
+		ret = regcache_sync(adau1977->regmap);
+		if (ret)
+			goto err_disable_dvdd;
+
+		/*
+		 * The PLL register is not affected by the software reset. It is
+		 * possible that the value of the register was changed to the
+		 * default value while we were in cache only mode. In this case
+		 * regcache_sync will skip over it and we have to manually sync
+		 * it.
+		 */
+		ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val);
+		if (ret)
+			goto err_disable_dvdd;
+		if (val == 0x41) {
+			regcache_cache_bypass(adau1977->regmap, true);
+			ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL,
+				0x41);
+			if (ret)
+				goto err_disable_dvdd;
+			regcache_cache_bypass(adau1977->regmap, false);
+		}
+	} else {
+		regulator_disable(adau1977->avdd_reg);
+		if (adau1977->dvdd_reg)
+			regulator_disable(adau1977->dvdd_reg);
+	}
+
+	adau1977->enabled = enable;
+
+	return ret;
+
+err_disable_dvdd:
+	if (adau1977->dvdd_reg)
+		regulator_disable(adau1977->dvdd_reg);
+err_disable_avdd:
+		regulator_disable(adau1977->avdd_reg);
+	return ret;
+}
+
+static int adau1977_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			ret = adau1977_set_power(adau1977, true);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = adau1977_set_power(adau1977, false);
+		break;
+	}
+
+	if (ret)
+		return ret;
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+	unsigned int rx_mask, int slots, int width)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	unsigned int ctrl0, ctrl1, drv;
+	unsigned int slot[4];
+	unsigned int i;
+	int ret;
+
+	if (slots == 0) {
+		/* 0 = No fixed slot width */
+		adau1977->slot_width = 0;
+		adau1977->max_master_fs = 192000;
+		return regmap_update_bits(adau1977->regmap,
+			ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK,
+			ADAU1977_SAI_CTRL0_SAI_I2S);
+	}
+
+	if (rx_mask == 0 || tx_mask != 0)
+		return -EINVAL;
+
+	drv = 0;
+	for (i = 0; i < 4; i++) {
+		slot[i] = __ffs(rx_mask);
+		drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i);
+		rx_mask &= ~(1 << slot[i]);
+		if (slot[i] >= slots)
+			return -EINVAL;
+		if (rx_mask == 0)
+			break;
+	}
+
+	if (rx_mask != 0)
+		return -EINVAL;
+
+	switch (width) {
+	case 16:
+		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16;
+		break;
+	case 24:
+		/* We can only generate 16 bit or 32 bit wide slots */
+		if (adau1977->master)
+			return -EINVAL;
+		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24;
+		break;
+	case 32:
+		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slots) {
+	case 2:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2;
+		break;
+	case 4:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4;
+		break;
+	case 8:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8;
+		break;
+	case 16:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+		ADAU1977_SAI_OVERTEMP_DRV_C(0) |
+		ADAU1977_SAI_OVERTEMP_DRV_C(1) |
+		ADAU1977_SAI_OVERTEMP_DRV_C(2) |
+		ADAU1977_SAI_OVERTEMP_DRV_C(3), drv);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12,
+		(slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+		(slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34,
+		(slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+		(slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+		ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+		ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1);
+	if (ret)
+		return ret;
+
+	adau1977->slot_width = width;
+
+	/* In master mode the maximum bitclock is 24.576 MHz */
+	adau1977->max_master_fs = min(192000, 24576000 / width / slots);
+
+	return 0;
+}
+
+static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	unsigned int val;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return 0;
+
+	if (mute)
+		val = ADAU1977_MISC_CONTROL_MMUTE;
+	else
+		val = 0;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL,
+			ADAU1977_MISC_CONTROL_MMUTE, val);
+}
+
+static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0;
+	bool invert_lrclk;
+	int ret;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		adau1977->master = false;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl1 |= ADAU1977_SAI_CTRL1_MASTER;
+		adau1977->master = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert_lrclk = true;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+		invert_lrclk = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adau1977->right_j = false;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+		invert_lrclk = !invert_lrclk;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+		adau1977->right_j = true;
+		invert_lrclk = !invert_lrclk;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+		invert_lrclk = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (invert_lrclk)
+		block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+		ADAU1977_BLOCK_POWER_SAI_LR_POL |
+		ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+		ADAU1977_SAI_CTRL0_FMT_MASK,
+		ctrl0);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+		ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE,
+		ctrl1);
+}
+
+static int adau1977_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	u64 formats = 0;
+
+	if (adau1977->slot_width == 16)
+		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE;
+	else if (adau1977->right_j || adau1977->slot_width == 24)
+		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints);
+
+	if (adau1977->master)
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+			SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs);
+
+	if (formats != 0)
+		snd_pcm_hw_constraint_mask64(substream->runtime,
+			SNDRV_PCM_HW_PARAM_FORMAT, formats);
+
+	return 0;
+}
+
+static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+	unsigned int val;
+
+	if (tristate)
+		val = ADAU1977_SAI_OVERTEMP_DRV_HIZ;
+	else
+		val = 0;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+		ADAU1977_SAI_OVERTEMP_DRV_HIZ, val);
+}
+
+#define ADAU1977_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops adau1977_dai_ops = {
+	.startup	= adau1977_startup,
+	.hw_params	= adau1977_hw_params,
+	.mute_stream	= adau1977_mute,
+	.set_fmt	= adau1977_set_dai_fmt,
+	.set_tdm_slot	= adau1977_set_tdm_slot,
+	.set_tristate	= adau1977_set_tristate,
+};
+
+static struct snd_soc_dai_driver adau1977_dai = {
+	.name = "adau1977-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = ADAU1977_FORMATS,
+		.sig_bits = 24,
+	},
+	.ops = &adau1977_dai_ops,
+};
+
+static const unsigned int adau1977_rates[] = {
+	8000, 16000, 32000, 64000, 128000,
+	11025, 22050, 44100, 88200, 172400,
+	12000, 24000, 48000, 96000, 192000,
+};
+
+#define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f
+#define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0
+#define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00
+/* All rates >= 32000 */
+#define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c
+
+static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq)
+{
+	unsigned int mcs;
+
+	if (mclk % (base_freq * 128) != 0)
+		return false;
+
+	mcs = mclk / (128 * base_freq);
+	if (mcs < 1 || mcs > 6 || mcs == 5)
+		return false;
+
+	return true;
+}
+
+static int adau1977_set_sysclk(struct snd_soc_codec *codec,
+	int clk_id, int source, unsigned int freq, int dir)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	unsigned int mask = 0;
+	unsigned int clk_src;
+	unsigned int ret;
+
+	if (dir != SND_SOC_CLOCK_IN)
+		return -EINVAL;
+
+	if (clk_id != ADAU1977_SYSCLK)
+		return -EINVAL;
+
+	switch (source) {
+	case ADAU1977_SYSCLK_SRC_MCLK:
+		clk_src = 0;
+		break;
+	case ADAU1977_SYSCLK_SRC_LRCLK:
+		clk_src = ADAU1977_PLL_CLK_S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) {
+		if (freq < 4000000 || freq > 36864000)
+			return -EINVAL;
+
+		if (adau1977_check_sysclk(freq, 32000))
+			mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000;
+		if (adau1977_check_sysclk(freq, 44100))
+			mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100;
+		if (adau1977_check_sysclk(freq, 48000))
+			mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000;
+
+		if (mask == 0)
+			return -EINVAL;
+	} else if (source == ADAU1977_SYSCLK_SRC_LRCLK) {
+		mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK;
+	}
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+		ADAU1977_PLL_CLK_S, clk_src);
+	if (ret)
+		return ret;
+
+	adau1977->constraints.mask = mask;
+	adau1977->sysclk_src = source;
+	adau1977->sysclk = freq;
+
+	return 0;
+}
+
+static int adau1977_codec_probe(struct snd_soc_codec *codec)
+{
+	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	switch (adau1977->type) {
+	case ADAU1977:
+		ret = snd_soc_dapm_new_controls(&codec->dapm,
+			adau1977_micbias_dapm_widgets,
+			ARRAY_SIZE(adau1977_micbias_dapm_widgets));
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver adau1977_codec_driver = {
+	.probe = adau1977_codec_probe,
+	.set_bias_level = adau1977_set_bias_level,
+	.set_sysclk = adau1977_set_sysclk,
+	.idle_bias_off = true,
+
+	.controls = adau1977_snd_controls,
+	.num_controls = ARRAY_SIZE(adau1977_snd_controls),
+	.dapm_widgets = adau1977_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets),
+	.dapm_routes = adau1977_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes),
+};
+
+static int adau1977_setup_micbias(struct adau1977 *adau1977)
+{
+	struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
+	struct device_node *np = adau1977->dev->of_node;
+	u32 micbias = ADAU1977_MICBIAS_8V5;
+
+	if (pdata)
+		micbias = pdata->micbias;
+	else if (np)
+		of_property_read_u32(np, "adi,micbias", &micbias);
+
+	if (micbias > ADAU1977_MICBIAS_9V0)
+		return -EINVAL;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS,
+		ADAU1977_MICBIAS_MB_VOLTS_MASK,
+		micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET);
+}
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+	enum adau1977_type type, void (*switch_mode)(struct device *dev))
+{
+	unsigned int power_off_mask;
+	struct adau1977 *adau1977;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL);
+	if (adau1977 == NULL)
+		return -ENOMEM;
+
+	adau1977->dev = dev;
+	adau1977->type = type;
+	adau1977->regmap = regmap;
+	adau1977->switch_mode = switch_mode;
+	adau1977->max_master_fs = 192000;
+
+	adau1977->constraints.list = adau1977_rates;
+	adau1977->constraints.count = ARRAY_SIZE(adau1977_rates);
+
+	adau1977->avdd_reg = devm_regulator_get(dev, "AVDD");
+	if (IS_ERR(adau1977->avdd_reg))
+		return PTR_ERR(adau1977->avdd_reg);
+
+	adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD");
+	if (IS_ERR(adau1977->dvdd_reg)) {
+		if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV)
+			return PTR_ERR(adau1977->dvdd_reg);
+		adau1977->dvdd_reg = NULL;
+	}
+
+	adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
+	if (IS_ERR(adau1977->reset_gpio)) {
+		if (PTR_ERR(adau1977->reset_gpio) != -ENOENT)
+			return PTR_ERR(adau1977->reset_gpio);
+		adau1977->reset_gpio = NULL;
+	}
+
+	dev_set_drvdata(dev, adau1977);
+
+	if (adau1977->reset_gpio) {
+		ret = gpiod_direction_output(adau1977->reset_gpio, 0);
+		if (ret)
+			return ret;
+		ndelay(100);
+	}
+
+	ret = adau1977_set_power(adau1977, true);
+	if (ret)
+		return ret;
+
+	if (type == ADAU1977) {
+		ret = adau1977_setup_micbias(adau1977);
+		if (ret)
+			goto err_poweroff;
+	}
+
+	if (adau1977->dvdd_reg)
+		power_off_mask = ~0;
+	else
+		power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+				power_off_mask, 0x00);
+	if (ret)
+		goto err_poweroff;
+
+	ret = adau1977_set_power(adau1977, false);
+	if (ret)
+		return ret;
+
+	return snd_soc_register_codec(dev, &adau1977_codec_driver,
+			&adau1977_dai, 1);
+
+err_poweroff:
+	adau1977_set_power(adau1977, false);
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(adau1977_probe);
+
+static bool adau1977_register_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1977_REG_STATUS(0):
+	case ADAU1977_REG_STATUS(1):
+	case ADAU1977_REG_STATUS(2):
+	case ADAU1977_REG_STATUS(3):
+	case ADAU1977_REG_ADC_CLIP:
+		return true;
+	}
+
+	return false;
+}
+
+const struct regmap_config adau1977_regmap_config = {
+	.max_register = ADAU1977_REG_DC_HPF_CAL,
+	.volatile_reg = adau1977_register_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = adau1977_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
+};
+EXPORT_SYMBOL_GPL(adau1977_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h
new file mode 100644
index 0000000..95e7143
--- /dev/null
+++ b/sound/soc/codecs/adau1977.h
@@ -0,0 +1,37 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1977_H__
+#define __SOUND_SOC_CODECS_ADAU1977_H__
+
+#include <linux/regmap.h>
+
+struct device;
+
+enum adau1977_type {
+	ADAU1977,
+	ADAU1978,
+	ADAU1979,
+};
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+	enum adau1977_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1977_regmap_config;
+
+enum adau1977_clk_id {
+	ADAU1977_SYSCLK,
+};
+
+enum adau1977_sysclk_src {
+	ADAU1977_SYSCLK_SRC_MCLK,
+	ADAU1977_SYSCLK_SRC_LRCLK,
+};
+
+#endif
-- 
1.8.0

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

* Re: [PATCH 1/2] devicetree: Add devicetree bindings documentation for the ADAU1977
       [not found] ` <1391439428-3198-1-git-send-email-lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
@ 2014-02-03 15:15   ` Geert Uytterhoeven
       [not found]     ` <CAMuHMdVQGZE+1YuWCnJefzy08kb6vNmRN8k+1-K82BubOBAOxQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Geert Uytterhoeven @ 2014-02-03 15:15 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Mark Brown, Liam Girdwood, alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On Mon, Feb 3, 2014 at 3:57 PM, Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org> wrote:
> + - adi,micbias: Configures the voltage setting for the MICBIAS pin. If not
> +   specified the default value will be 8.5 Volts. This property is only valid
> +   for the ADAU1977.
> +   Valid values for this property are:
> +       0: 5.0V
> +       1: 5.5V
> +       2: 6.0V
> +       3: 6.5V
> +       4: 7.0V
> +       5: 7.5V
> +       6: 8.0V
> +       7: 8.5V
> +       8: 9.0V

This means the casual DTS reader need to know about the meaning of
the values. You can avoid that by:
  1. Using preprocessor defines. Drawback is that you have to add an
     include file.
  2. Using mV, and specify minimum, maximum, and incrementals in the
     bindings, cfr.
Documentation/devicetree/bindings/power_supply/ti,bq24735.txt
     Drawback is that the user can easily specify invalid values.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 2/2] ASoC: Add ADAU1977 driver
  2014-02-03 14:57 ` [PATCH 2/2] ASoC: Add ADAU1977 driver Lars-Peter Clausen
@ 2014-02-03 18:40   ` Mark Brown
  2014-02-04 11:16     ` Lars-Peter Clausen
  0 siblings, 1 reply; 9+ messages in thread
From: Mark Brown @ 2014-02-03 18:40 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: alsa-devel, Liam Girdwood


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

On Mon, Feb 03, 2014 at 03:57:08PM +0100, Lars-Peter Clausen wrote:
> This patch adds support for the ADAU1977, ADAU1978 and ADAU1979 audio CODEC
> devices. They are a family of 4-channel differntial input audio ADC devices.
> They can be connected to either a SPI or I2C bus.

To avoid tedious iteration of the driver for the DT bindings it's
generally helpful to submit the DT bindings as a separate patch.

>  sound/soc/codecs/adau1977-i2c.c        |  58 ++
>  sound/soc/codecs/adau1977-spi.c        |  73 +++

This isn't the general style, if we want to do that we should be
converting all the other drivers.

> +config SND_SOC_ADAU1977
> +	tristate
> +
> +config SND_SOC_ADAU1977_I2C
> +	tristate
> +	select SND_SOC_ADAU1977
> +
> +config SND_SOC_ADAU1977_SPI
> +	tristate
> +	select SND_SOC_ADAU1977
> +

Please make these user visible if OF is in use.

> +static struct i2c_driver adau1977_i2c_driver = {
> +	.driver = {
> +		.name = "adau1977",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = adau1977_i2c_probe,
> +	.remove = adau1977_i2c_remove,
> +	.id_table = adau1977_i2c_ids,
> +};

You should have explicit OF IDs.

> +	if (rate >= 8000 && rate <= 12000)
> +		ctrl0 = ADAU1977_SAI_CTRL0_FS_8000_12000;
> +	else if (rate >= 16000 && rate <= 24000)
> +		ctrl0 = ADAU1977_SAI_CTRL0_FS_16000_24000;
> +	else if (rate >= 32000 && rate <= 48000)
> +		ctrl0 = ADAU1977_SAI_CTRL0_FS_32000_48000;
> +	else if (rate >= 64000 && rate <= 96000)
> +		ctrl0 = ADAU1977_SAI_CTRL0_FS_64000_96000;
> +	else if (rate >= 128000 && rate <= 192000)
> +		ctrl0 = ADAU1977_SAI_CTRL0_FS_128000_192000;
> +	else
> +		return -EINVAL;

There's a couple of these rate range if trees - how about a lookup in an
array?

> +	if (!enable) {
> +		ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
> +			ADAU1977_POWER_PWUP, 0);
> +		regcache_mark_dirty(adau1977->regmap);
> +	} else {
> +		ret = regulator_enable(adau1977->avdd_reg);
> +		if (ret)
> +			return ret;
> +		if (adau1977->dvdd_reg) {
> +			ret = regulator_enable(adau1977->dvdd_reg);
> +			if (ret)
> +				goto err_disable_avdd;
> +		}
> +	}
> +
> +	if (adau1977->reset_gpio)
> +		gpiod_set_value(adau1977->reset_gpio, enable);

_cansleep().

I'm not sure all this enable/disable logic within the function is
helping clarity here.  There seems to be no meaningful sharing between
the two branches, separate functions for power up and power down is
probably going to be clearer.

> +static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
> +{
> +	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
> +	unsigned int val;
> +
> +	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		return 0;

Why would this ever be called for an ADC?

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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



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

* Re: [PATCH 2/2] ASoC: Add ADAU1977 driver
  2014-02-03 18:40   ` Mark Brown
@ 2014-02-04 11:16     ` Lars-Peter Clausen
  2014-02-04 12:12       ` Mark Brown
  0 siblings, 1 reply; 9+ messages in thread
From: Lars-Peter Clausen @ 2014-02-04 11:16 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Liam Girdwood

On 02/03/2014 07:40 PM, Mark Brown wrote:
>>   sound/soc/codecs/adau1977-i2c.c        |  58 ++
>>   sound/soc/codecs/adau1977-spi.c        |  73 +++
>
> This isn't the general style, if we want to do that we should be
> converting all the other drivers.
>

I think we want to change it. Cause as it is right now we always get issues 
when the SPI core is build-in, but the I2C core is built as a module. Using 
the scheme used in this driver the core module for the driver does not 
depend on either framework, but provides a library to the bus specific 
modules. E.g. if SPI is built-in and the SPI driver for the ADAU1977 is 
built-in the core will also be built-in, but it is still possible to build 
I2C as a module and also build the ADAU1977 I2C driver as a module. And I 
know there is SND_SOC_I2C_AND_SPI, but in my opinion it's a hack to work 
around the issue. E.g. if you have a board driver and the board driver 
selects the CODEC driver, the board driver also has to depend on 
SND_SOC_I2C_AND_SPI to avoid any issues (None of the board drivers do this 
right now).

>> +config SND_SOC_ADAU1977
>> +	tristate
>> +
>> +config SND_SOC_ADAU1977_I2C
>> +	tristate
>> +	select SND_SOC_ADAU1977
>> +
>> +config SND_SOC_ADAU1977_SPI
>> +	tristate
>> +	select SND_SOC_ADAU1977
>> +
>
> Please make these user visible if OF is in use.

Was there a resolution on how to best do this? Make them always visible, or 
only when CONFIG_OF is selected?

- Lars

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

* Re: [PATCH 1/2] devicetree: Add devicetree bindings documentation for the ADAU1977
       [not found]     ` <CAMuHMdVQGZE+1YuWCnJefzy08kb6vNmRN8k+1-K82BubOBAOxQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-02-04 11:48       ` Lars-Peter Clausen
  0 siblings, 0 replies; 9+ messages in thread
From: Lars-Peter Clausen @ 2014-02-04 11:48 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Mark Brown, Liam Girdwood, alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

On 02/03/2014 04:15 PM, Geert Uytterhoeven wrote:
> On Mon, Feb 3, 2014 at 3:57 PM, Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org> wrote:
>> + - adi,micbias: Configures the voltage setting for the MICBIAS pin. If not
>> +   specified the default value will be 8.5 Volts. This property is only valid
>> +   for the ADAU1977.
>> +   Valid values for this property are:
>> +       0: 5.0V
>> +       1: 5.5V
>> +       2: 6.0V
>> +       3: 6.5V
>> +       4: 7.0V
>> +       5: 7.5V
>> +       6: 8.0V
>> +       7: 8.5V
>> +       8: 9.0V
>
> This means the casual DTS reader need to know about the meaning of
> the values. You can avoid that by:
>    1. Using preprocessor defines. Drawback is that you have to add an
>       include file.
>    2. Using mV, and specify minimum, maximum, and incrementals in the
>       bindings, cfr.
> Documentation/devicetree/bindings/power_supply/ti,bq24735.txt
>       Drawback is that the user can easily specify invalid values.


Is there a preference for either of them?

Thanks,
- Lars

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 2/2] ASoC: Add ADAU1977 driver
  2014-02-04 11:16     ` Lars-Peter Clausen
@ 2014-02-04 12:12       ` Mark Brown
  2014-02-04 13:31         ` Lars-Peter Clausen
  0 siblings, 1 reply; 9+ messages in thread
From: Mark Brown @ 2014-02-04 12:12 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: alsa-devel, Liam Girdwood


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

On Tue, Feb 04, 2014 at 12:16:38PM +0100, Lars-Peter Clausen wrote:
> On 02/03/2014 07:40 PM, Mark Brown wrote:

> >>  sound/soc/codecs/adau1977-i2c.c        |  58 ++
> >>  sound/soc/codecs/adau1977-spi.c        |  73 +++

> >This isn't the general style, if we want to do that we should be
> >converting all the other drivers.

> I think we want to change it. Cause as it is right now we always get
> issues when the SPI core is build-in, but the I2C core is built as a
> module. Using the scheme used in this driver the core module for the
> driver does not depend on either framework, but provides a library
> to the bus specific modules. E.g. if SPI is built-in and the SPI
> driver for the ADAU1977 is built-in the core will also be built-in,
> but it is still possible to build I2C as a module and also build the
> ADAU1977 I2C driver as a module. And I know there is
> SND_SOC_I2C_AND_SPI, but in my opinion it's a hack to work around
> the issue. E.g. if you have a board driver and the board driver
> selects the CODEC driver, the board driver also has to depend on
> SND_SOC_I2C_AND_SPI to avoid any issues (None of the board drivers
> do this right now).

I'm having a hard time seeing that as a meaningful issue to be honest -
only I2C has the modular option and I'm never terribly convinced about
the realism of scenarios that trigger this.  In any case the main thing
is that we shouldn't be silently putting something like this into driver
submissions, we should be actively making the change to all drivers.

> >Please make these user visible if OF is in use.

> Was there a resolution on how to best do this? Make them always
> visible, or only when CONFIG_OF is selected?

Always visible if their dependencies are enabled.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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



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

* Re: [PATCH 2/2] ASoC: Add ADAU1977 driver
  2014-02-04 12:12       ` Mark Brown
@ 2014-02-04 13:31         ` Lars-Peter Clausen
  2014-02-04 14:10           ` Mark Brown
  0 siblings, 1 reply; 9+ messages in thread
From: Lars-Peter Clausen @ 2014-02-04 13:31 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Liam Girdwood

On 02/04/2014 01:12 PM, Mark Brown wrote:
> On Tue, Feb 04, 2014 at 12:16:38PM +0100, Lars-Peter Clausen wrote:
>> On 02/03/2014 07:40 PM, Mark Brown wrote:
>
>>>>   sound/soc/codecs/adau1977-i2c.c        |  58 ++
>>>>   sound/soc/codecs/adau1977-spi.c        |  73 +++
>
>>> This isn't the general style, if we want to do that we should be
>>> converting all the other drivers.
>
>> I think we want to change it. Cause as it is right now we always get
>> issues when the SPI core is build-in, but the I2C core is built as a
>> module. Using the scheme used in this driver the core module for the
>> driver does not depend on either framework, but provides a library
>> to the bus specific modules. E.g. if SPI is built-in and the SPI
>> driver for the ADAU1977 is built-in the core will also be built-in,
>> but it is still possible to build I2C as a module and also build the
>> ADAU1977 I2C driver as a module. And I know there is
>> SND_SOC_I2C_AND_SPI, but in my opinion it's a hack to work around
>> the issue. E.g. if you have a board driver and the board driver
>> selects the CODEC driver, the board driver also has to depend on
>> SND_SOC_I2C_AND_SPI to avoid any issues (None of the board drivers
>> do this right now).
>
> I'm having a hard time seeing that as a meaningful issue to be honest -
> only I2C has the modular option and I'm never terribly convinced about
> the realism of scenarios that trigger this.  In any case the main thing
> is that we shouldn't be silently putting something like this into driver
> submissions, we should be actively making the change to all drivers.

I think this is the cleaner approach rather than the #ifdef mess we 
currently find in drivers with more than one interface. And there is the 
thing that you can actually build a config that results in a build error 
which triggers the occasional randconfig build failures for ASoC. Once the 
last three drivers that still soc-io have been converted to regmap I think 
we should move the selection of REGMAP_I2C and REGMAP_SPI to the individual 
drivers rather letting the core select them unconditionally. Using this new 
scheme will make it easier to avoid the situation where you end up selection 
REGMAP_I2C or REGMAP_SPI even though I2S or SPI_MASTER is not selected. I 
don't have a problem with updating the other drivers to use the new scheme, 
but it's not like we have to update them all at once in one atomic step. And 
you have to start somewhere.

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

* Re: [PATCH 2/2] ASoC: Add ADAU1977 driver
  2014-02-04 13:31         ` Lars-Peter Clausen
@ 2014-02-04 14:10           ` Mark Brown
  0 siblings, 0 replies; 9+ messages in thread
From: Mark Brown @ 2014-02-04 14:10 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: alsa-devel, Liam Girdwood


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

On Tue, Feb 04, 2014 at 02:31:19PM +0100, Lars-Peter Clausen wrote:

> currently find in drivers with more than one interface. And there is
> the thing that you can actually build a config that results in a build
> error which triggers the occasional randconfig build failures for
> for ASoC. Once the last three drivers that still soc-io have been

Those randconfig failures are for configurations that no human would
ever generate, it's really hard to care.

> converted to regmap I think we should move the selection of
> REGMAP_I2C and REGMAP_SPI to the individual drivers rather letting
> the core select them unconditionally. Using this new scheme will

That's the idea, it does need the drivers handling first though.  The
fact that not everything works through select (there's the ignored
dependencies thing and I think some other stuff) isn't helpful with this
stuff either, it makes it all too fragile.

> make it easier to avoid the situation where you end up selection
> REGMAP_I2C or REGMAP_SPI even though I2S or SPI_MASTER is not

The core only enables the regmap code if the bus is being built, we
don't have a problem with that bit - that bit at least is fine.

> selected. I don't have a problem with updating the other drivers to
> use the new scheme, but it's not like we have to update them all at
> once in one atomic step. And you have to start somewhere.

Right, but that somewhere shouldn't be doing it in a new driver without
even mentioning that it's being done - it's not something that should be
coming as a surprise in the middle of a review of something that should
be unrelated.  That's the biggest problem here, it wasn't even called
out in the changelog so people wouldn't be able to figure out why this
driver was being different.  

An explicit conversion patch for at least one driver (possibly even this
one on the end of the series) would be ideal, or adding a note in the
changelog saying something like "We should do this in general because X
but I didn't get round to starting yet" so that it's visible.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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



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

end of thread, other threads:[~2014-02-04 14:10 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-03 14:57 [PATCH 1/2] devicetree: Add devicetree bindings documentation for the ADAU1977 Lars-Peter Clausen
2014-02-03 14:57 ` [PATCH 2/2] ASoC: Add ADAU1977 driver Lars-Peter Clausen
2014-02-03 18:40   ` Mark Brown
2014-02-04 11:16     ` Lars-Peter Clausen
2014-02-04 12:12       ` Mark Brown
2014-02-04 13:31         ` Lars-Peter Clausen
2014-02-04 14:10           ` Mark Brown
     [not found] ` <1391439428-3198-1-git-send-email-lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
2014-02-03 15:15   ` [PATCH 1/2] devicetree: Add devicetree bindings documentation for the ADAU1977 Geert Uytterhoeven
     [not found]     ` <CAMuHMdVQGZE+1YuWCnJefzy08kb6vNmRN8k+1-K82BubOBAOxQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-02-04 11:48       ` Lars-Peter Clausen

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.