[U-Boot] [PATCH v2 10/22] dm: sound: Add conversion to driver model

Simon Glass sjg at chromium.org
Mon Dec 10 17:37:39 UTC 2018


Move the existing hardware drivers over to use driver model.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v2:
- Correct conversion for pit
- Use void * for i2c and sound data

 arch/arm/dts/exynos5250-smdk5250.dts |   1 +
 arch/arm/dts/exynos5420-smdk5420.dts |   1 +
 drivers/sound/Makefile               |   6 +-
 drivers/sound/max98095.c             |  59 +++++++++++++-
 drivers/sound/samsung-i2s.c          | 111 +++++++++++++++++++++++----
 drivers/sound/samsung_sound.c        | 101 ++++++++++++++++++++++++
 drivers/sound/wm8994.c               |  53 ++++++++++++-
 7 files changed, 316 insertions(+), 16 deletions(-)
 create mode 100644 drivers/sound/samsung_sound.c

diff --git a/arch/arm/dts/exynos5250-smdk5250.dts b/arch/arm/dts/exynos5250-smdk5250.dts
index 8b695442b1a..bf60b82d449 100644
--- a/arch/arm/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/dts/exynos5250-smdk5250.dts
@@ -62,6 +62,7 @@
 	i2c at 12C70000 {
 		soundcodec at 1a {
 			reg = <0x1a>;
+			u-boot,i2c-offset-len = <2>;
 			compatible = "wolfson,wm8994-codec";
 		};
 	};
diff --git a/arch/arm/dts/exynos5420-smdk5420.dts b/arch/arm/dts/exynos5420-smdk5420.dts
index cab5ddb61fa..daaa4666964 100644
--- a/arch/arm/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/dts/exynos5420-smdk5420.dts
@@ -84,6 +84,7 @@
 	i2c at 12C70000 {
 		soundcodec at 1a {
 			reg = <0x1a>;
+			u-boot,i2c-offset-len = <2>;
 			compatible = "wolfson,wm8994-codec";
 		};
 	};
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 70d32c6d6f6..75fa31ec534 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -6,9 +6,13 @@
 obj-$(CONFIG_SOUND)	+= sound.o
 obj-$(CONFIG_DM_SOUND)	+= codec-uclass.o
 obj-$(CONFIG_DM_SOUND)	+= i2s-uclass.o
-obj-$(CONFIG_I2S)	+= sound-i2s.o
 obj-$(CONFIG_DM_SOUND)	+= sound-uclass.o
 obj-$(CONFIG_I2S_SAMSUNG)	+= samsung-i2s.o
 obj-$(CONFIG_SOUND_SANDBOX)	+= sandbox.o
+ifdef CONFIG_DM_SOUND
+obj-$(CONFIG_I2S_SAMSUNG)	+= samsung_sound.o
+else
+obj-$(CONFIG_I2S)	+= sound-i2s.o
+endif
 obj-$(CONFIG_SOUND_WM8994)	+= wm8994.o
 obj-$(CONFIG_SOUND_MAX98095)	+= max98095.o
diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c
index 7a3dbd09840..d6710dfaa7a 100644
--- a/drivers/sound/max98095.c
+++ b/drivers/sound/max98095.c
@@ -11,6 +11,8 @@
  */
 
 #include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
 #include <div64.h>
 #include <fdtdec.h>
 #include <i2c.h>
@@ -28,6 +30,7 @@ struct max98095_priv {
 	unsigned int rate;
 	unsigned int fmt;
 	int i2c_addr;
+	struct udevice *dev;
 };
 
 /* Index 0 is reserved. */
@@ -48,7 +51,12 @@ static int max98095_i2c_write(struct max98095_priv *priv, unsigned int reg,
 {
 	debug("%s: Write Addr : 0x%02X, Data :  0x%02X\n",
 	      __func__, reg, data);
+#ifdef CONFIG_DM_SOUND
+	debug("dev = %s\n", priv->dev->name);
+	return dm_i2c_write(priv->dev, reg, &data, 1);
+#else
 	return i2c_write(priv->i2c_addr, reg, 1, &data, 1);
+#endif
 }
 
 /*
@@ -65,7 +73,11 @@ static unsigned int max98095_i2c_read(struct max98095_priv *priv,
 {
 	int ret;
 
+#ifdef CONFIG_DM_SOUND
+	return dm_i2c_read(priv->dev, reg, data, 1);
+#else
 	ret = i2c_read(priv->i2c_addr, reg, 1, data, 1);
+#endif
 	if (ret != 0) {
 		debug("%s: Error while reading register %#04x\n",
 		      __func__, reg);
@@ -484,7 +496,7 @@ static int max98095_do_init(struct max98095_priv *priv,
 
 	ret = max98095_setup_interface(priv, aif_id);
 	if (ret < 0) {
-		debug("%s: max98095 codec chip init failed\n", __func__);
+		debug("%s: max98095 setup interface failed\n", __func__);
 		return ret;
 	}
 
@@ -507,6 +519,7 @@ static int max98095_do_init(struct max98095_priv *priv,
 	return ret;
 }
 
+#ifndef CONFIG_DM_SOUND
 static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
 				const void *blob)
 {
@@ -582,3 +595,47 @@ int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
 
 	return ret;
 }
+#endif
+
+static int max98095_set_params(struct udevice *dev, int interface, int rate,
+			       int mclk_freq, int bits_per_sample,
+			       uint channels)
+{
+	struct max98095_priv *priv = dev_get_priv(dev);
+
+	return max98095_do_init(priv, interface, rate, mclk_freq,
+				bits_per_sample);
+}
+
+static int max98095_probe(struct udevice *dev)
+{
+	struct max98095_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->dev = dev;
+	ret = max98095_device_init(priv);
+	if (ret < 0) {
+		debug("%s: max98095 codec chip init failed\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct audio_codec_ops max98095_ops = {
+	.set_params	= max98095_set_params,
+};
+
+static const struct udevice_id max98095_ids[] = {
+	{ .compatible = "maxim,max98095" },
+	{ }
+};
+
+U_BOOT_DRIVER(max98095) = {
+	.name		= "max98095",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= max98095_ids,
+	.probe		= max98095_probe,
+	.ops		= &max98095_ops,
+	.priv_auto_alloc_size	= sizeof(struct max98095_priv),
+};
diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c
index 5cd585808ab..c19e08e7e30 100644
--- a/drivers/sound/samsung-i2s.c
+++ b/drivers/sound/samsung-i2s.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <i2s.h>
 #include <sound.h>
 #include <asm/arch/clk.h>
@@ -255,13 +256,13 @@ static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
 	return 0;
 }
 
-int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data,
-			 unsigned long data_size)
+int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
+			 uint data_size)
 {
+	struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+	u32 *ptr;
 	int i;
 	int start;
-	struct i2s_reg *i2s_reg =
-				(struct i2s_reg *)pi2s_tx->base_address;
 
 	if (data_size < FIFO_LENGTH) {
 		debug("%s : Invalid data size\n", __func__);
@@ -269,17 +270,17 @@ int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data,
 	}
 
 	/* fill the tx buffer before stating the tx transmit */
-	for (i = 0; i < FIFO_LENGTH; i++)
-		writel(*data++, &i2s_reg->txd);
+	for (i = 0, ptr = data; i < FIFO_LENGTH; i++)
+		writel(*ptr++, &i2s_reg->txd);
 
-	data_size -= FIFO_LENGTH;
+	data_size -= sizeof(*ptr) * FIFO_LENGTH;
 	i2s_txctrl(i2s_reg, I2S_TX_ON);
 
 	while (data_size > 0) {
 		start = get_timer(0);
 		if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
-			writel(*data++, &i2s_reg->txd);
-			data_size--;
+			writel(*ptr++, &i2s_reg->txd);
+			data_size -= sizeof(*ptr);
 		} else {
 			if (get_timer(start) > TIMEOUT_I2S_TX) {
 				i2s_txctrl(i2s_reg, I2S_TX_OFF);
@@ -296,8 +297,8 @@ int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data,
 int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
 {
 	int ret;
-	struct i2s_reg *i2s_reg =
-				(struct i2s_reg *)pi2s_tx->base_address;
+	struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+
 	if (pi2s_tx->id == 0) {
 		/* Initialize GPIO for I2S-0 */
 		exynos_pinmux_config(PERIPH_ID_I2S0, 0);
@@ -348,8 +349,8 @@ int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
 	}
 
 	/* Configure I2s format */
-	ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-			  SND_SOC_DAIFMT_CBM_CFM));
+	ret = i2s_set_fmt(i2s_reg, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			  SND_SOC_DAIFMT_CBM_CFM);
 	if (ret == 0) {
 		i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
 		ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
@@ -368,3 +369,87 @@ int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
 
 	return ret;
 }
+
+static int samsung_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+	return i2s_transfer_tx_data(priv, data, data_size);
+}
+
+static int samsung_i2s_probe(struct udevice *dev)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+	return i2s_tx_init(priv);
+}
+
+static int samsung_i2s_ofdata_to_platdata(struct udevice *dev)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+	ulong base;
+
+	/*
+	 * Get the pre-defined sound specific values from FDT.
+	 * All of these are expected to be correct otherwise
+	 * wrong register values in i2s setup parameters
+	 * may result in no sound play.
+	 */
+	base = dev_read_addr(dev);
+	if (base == FDT_ADDR_T_NONE) {
+		debug("%s: Missing  i2s base\n", __func__);
+		return -EINVAL;
+	}
+	priv->base_address = base;
+
+	if (dev_read_u32u(dev, "samsung,i2s-epll-clock-frequency",
+			  &priv->audio_pll_clk))
+		goto err;
+	debug("audio_pll_clk = %d\n", priv->audio_pll_clk);
+	if (dev_read_u32u(dev, "samsung,i2s-sampling-rate",
+			  &priv->samplingrate))
+		goto err;
+	debug("samplingrate = %d\n", priv->samplingrate);
+	if (dev_read_u32u(dev, "samsung,i2s-bits-per-sample",
+			  &priv->bitspersample))
+		goto err;
+	debug("bitspersample = %d\n", priv->bitspersample);
+	if (dev_read_u32u(dev, "samsung,i2s-channels", &priv->channels))
+		goto err;
+	debug("channels = %d\n", priv->channels);
+	if (dev_read_u32u(dev, "samsung,i2s-lr-clk-framesize", &priv->rfs))
+		goto err;
+	debug("rfs = %d\n", priv->rfs);
+	if (dev_read_u32u(dev, "samsung,i2s-bit-clk-framesize", &priv->bfs))
+		goto err;
+	debug("bfs = %d\n", priv->bfs);
+
+	if (dev_read_u32u(dev, "samsung,i2s-id", &priv->id))
+		goto err;
+	debug("id = %d\n", priv->id);
+
+	return 0;
+
+err:
+	debug("fail to get sound i2s node properties\n");
+
+	return -EINVAL;
+}
+
+static const struct i2s_ops samsung_i2s_ops = {
+	.tx_data	= samsung_i2s_tx_data,
+};
+
+static const struct udevice_id samsung_i2s_ids[] = {
+	{ .compatible = "samsung,s5pv210-i2s" },
+	{ }
+};
+
+U_BOOT_DRIVER(samsung_i2s) = {
+	.name		= "samsung_i2s",
+	.id		= UCLASS_I2S,
+	.of_match	= samsung_i2s_ids,
+	.probe		= samsung_i2s_probe,
+	.ofdata_to_platdata	= samsung_i2s_ofdata_to_platdata,
+	.ops		= &samsung_i2s_ops,
+};
diff --git a/drivers/sound/samsung_sound.c b/drivers/sound/samsung_sound.c
new file mode 100644
index 00000000000..23b467c1de0
--- /dev/null
+++ b/drivers/sound/samsung_sound.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google, LLC
+ * Written by Simon Glass <sjg at chromium.org>
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+
+static int samsung_sound_setup(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
+	int ret;
+
+	if (uc_priv->setup_done)
+		return -EALREADY;
+	ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
+				     i2c_priv->samplingrate,
+				     i2c_priv->samplingrate * i2c_priv->rfs,
+				     i2c_priv->bitspersample,
+				     i2c_priv->channels);
+	if (ret)
+		return ret;
+	uc_priv->setup_done = true;
+
+	return 0;
+}
+
+static int samsung_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int samsung_sound_probe(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct ofnode_phandle_args args;
+	struct gpio_desc en_gpio;
+	ofnode node;
+	int ret;
+
+	ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+	/* Turn on the GPIO which connects to the codec's "enable" line. */
+	if (!ret)
+		gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
+
+	ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
+					   "samsung,audio-codec",
+					   &uc_priv->codec);
+	if (ret) {
+		debug("Failed to probe audio codec\n");
+		return ret;
+	}
+	node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+	if (ret) {
+		debug("Cannot find i2s: %d\n", ret);
+		return ret;
+	}
+	debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+	      uc_priv->codec->name, uc_priv->i2s->name);
+
+	return 0;
+}
+
+static const struct sound_ops samsung_sound_ops = {
+	.setup	= samsung_sound_setup,
+	.play	= samsung_sound_play,
+};
+
+static const struct udevice_id samsung_sound_ids[] = {
+	{ .compatible = "google,snow-audio-max98095" },
+	{ }
+};
+
+U_BOOT_DRIVER(samsung_sound) = {
+	.name		= "samsung_sound",
+	.id		= UCLASS_SOUND,
+	.of_match	= samsung_sound_ids,
+	.probe		= samsung_sound_probe,
+	.ops		= &samsung_sound_ops,
+};
diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c
index 1714f430f39..d731a0dd863 100644
--- a/drivers/sound/wm8994.c
+++ b/drivers/sound/wm8994.c
@@ -4,6 +4,8 @@
  * R. Chandrasekar <rcsekar at samsung.com>
  */
 #include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
 #include <div64.h>
 #include <fdtdec.h>
 #include <i2c.h>
@@ -39,6 +41,7 @@ struct wm8994_priv {
 	int aifclk[WM8994_MAX_AIF];	/* audio interface clock in Hz   */
 	struct wm8994_fll_config fll[2]; /* fll config to configure fll */
 	int i2c_addr;
+	struct udevice *dev;
 };
 
 /* wm 8994 supported sampling rate values */
@@ -79,7 +82,12 @@ static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
 	val[1] = (unsigned char)(data & 0xff);
 	debug("Write Addr : 0x%04X, Data :  0x%04X\n", reg, data);
 
+#ifdef CONFIG_DM_SOUND
+	debug("dev = %s\n", priv->dev->name);
+	return dm_i2c_write(priv->dev, reg, val, 2);
+#else
 	return i2c_write(priv->i2c_addr, reg, 2, val, 2);
+#endif
 }
 
 /*
@@ -97,7 +105,11 @@ static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
 	unsigned char val[2];
 	int ret;
 
+#ifdef CONFIG_DM_SOUND
+	ret = dm_i2c_read(priv->dev, reg, val, 1);
+#else
 	ret = i2c_read(priv->i2c_addr, reg, 2, val, 2);
+#endif
 	if (ret != 0) {
 		debug("%s: Error while reading register %#04x\n",
 		      __func__, reg);
@@ -807,6 +819,7 @@ err:
 	return -1;
 }
 
+#ifndef CONFIG_DM_SOUND
 /*
  * Gets fdt values for wm8994 config parameters
  *
@@ -859,6 +872,7 @@ static int get_codec_values(struct sound_codec_info *pcodec_info,
 
 	return 0;
 }
+#endif
 
 static int _wm8994_init(struct wm8994_priv *priv,
 			enum en_audio_interface aif_id, int sampling_rate,
@@ -873,7 +887,7 @@ static int _wm8994_init(struct wm8994_priv *priv,
 		return ret;
 	}
 
-	ret =  wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
+	ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
 	if (ret < 0) {
 		debug("%s: wm8994 codec set sys clock failed\n", __func__);
 		return ret;
@@ -891,6 +905,7 @@ static int _wm8994_init(struct wm8994_priv *priv,
 	return ret;
 }
 
+#ifndef CONFIG_DM_SOUND
 /* WM8994 Device Initialisation */
 int wm8994_init(const void *blob, enum en_audio_interface aif_id,
 		int sampling_rate, int mclk_freq, int bits_per_sample,
@@ -918,3 +933,39 @@ int wm8994_init(const void *blob, enum en_audio_interface aif_id,
 	return _wm8994_init(&wm8994_info, aif_id, sampling_rate, mclk_freq,
 			    bits_per_sample, channels);
 }
+#endif
+
+static int wm8994_set_params(struct udevice *dev, int interface, int rate,
+			     int mclk_freq, int bits_per_sample, uint channels)
+{
+	struct wm8994_priv *priv = dev_get_priv(dev);
+
+	return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample,
+			    channels);
+}
+
+static int wm8994_probe(struct udevice *dev)
+{
+	struct wm8994_priv *priv = dev_get_priv(dev);
+
+	priv->dev = dev;
+	return wm8994_device_init(priv);
+}
+
+static const struct audio_codec_ops wm8994_ops = {
+	.set_params	= wm8994_set_params,
+};
+
+static const struct udevice_id wm8994_ids[] = {
+	{ .compatible = "wolfson,wm8994" },
+	{ }
+};
+
+U_BOOT_DRIVER(wm8994) = {
+	.name		= "wm8994",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= wm8994_ids,
+	.probe		= wm8994_probe,
+	.ops		= &wm8994_ops,
+	.priv_auto_alloc_size	= sizeof(struct wm8994_priv),
+};
-- 
2.20.0.rc2.403.gdbc3b29805-goog



More information about the U-Boot mailing list