All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH, RFC 0/3] magician fix and UDA1380 i2c device registration change
@ 2009-06-14 10:51 Philipp Zabel
       [not found] ` <1244976692-5189-2-git-send-email-philipp.zabel@gmail.com>
  0 siblings, 1 reply; 14+ messages in thread
From: Philipp Zabel @ 2009-06-14 10:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Mark Brown

Hi Mark,

Patch 1/3 is a follow-up fix to commit a820532002e70e3a06f1ea7133e9b02443d07382
"ASoC: pxa-ssp.c fix clock/frame invert".

Patch 2/3 removes the I2C board info registration from the UDA1380 driver.
Instead, device instantiation will be done via global i2c_board_info from
board files (patch 3/3). At the same time, platform specific configuration
is moved to platform data. Common power/reset GPIO handling moves into the
codec driver, which will allow to completely power down the codec depending
on ASoC power state in the future.

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

* [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity
       [not found] ` <1244976692-5189-2-git-send-email-philipp.zabel@gmail.com>
@ 2009-06-14 10:51   ` Philipp Zabel
  2009-06-14 10:51     ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Philipp Zabel
  2009-06-14 14:23     ` [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity Mark Brown
  0 siblings, 2 replies; 14+ messages in thread
From: Philipp Zabel @ 2009-06-14 10:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Mark Brown, Philipp Zabel

Follow-up fix needed since "ASoC: pxa-ssp.c fix clock/frame invert".

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
---
 sound/soc/pxa/magician.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index a04ddc3..fa0e7e6 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -183,7 +183,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
 
 	/* set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-			SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBS_CFS);
+			SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
 	if (ret < 0)
 		return ret;
 
-- 
1.6.3.1

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

* [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata
  2009-06-14 10:51   ` [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity Philipp Zabel
@ 2009-06-14 10:51     ` Philipp Zabel
  2009-06-14 10:51       ` [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380 Philipp Zabel
  2009-06-14 14:51       ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Mark Brown
  2009-06-14 14:23     ` [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity Mark Brown
  1 sibling, 2 replies; 14+ messages in thread
From: Philipp Zabel @ 2009-06-14 10:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Mark Brown, Philipp Zabel

This patch removes the I2C board info registration from the codec driver.
Instead, device instantiation will be done via global i2c_board_info from
board files. At the same time, platform specific configuration is moved
to platform data and common power/reset GPIO handling moves into the
codec driver.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
---
 include/sound/uda1380.h    |   22 ++++++++++
 sound/soc/codecs/uda1380.c |   95 +++++++++++++++++++++----------------------
 sound/soc/codecs/uda1380.h |   13 ------
 sound/soc/pxa/magician.c   |   26 ------------
 4 files changed, 68 insertions(+), 88 deletions(-)
 create mode 100644 include/sound/uda1380.h

diff --git a/include/sound/uda1380.h b/include/sound/uda1380.h
new file mode 100644
index 0000000..69f8775
--- /dev/null
+++ b/include/sound/uda1380.h
@@ -0,0 +1,22 @@
+/*
+ * UDA1380 ALSA SoC Codec driver
+ *
+ * Copyright 2009 Philipp Zabel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _UDA1380_H
+#define _UDA1380_H
+
+struct uda1380_platform_data {
+	int gpio_power;
+	int gpio_reset;
+	int dac_clk;
+#define UDA1380_DAC_CLK_SYSCLK 0
+#define UDA1380_DAC_CLK_WSPLL  1
+};
+
+#endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 5b21594..87f3e12 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -19,20 +19,19 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
-#include <linux/ioctl.h>
+#include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/initval.h>
-#include <sound/info.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
+#include <sound/uda1380.h>
 
 #include "uda1380.h"
 
@@ -740,28 +739,59 @@ static struct snd_soc_device *uda1380_socdev;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 
-static int uda1380_i2c_probe(struct i2c_client *i2c,
+static int uda1380_i2c_probe(struct i2c_client *client,
 			     const struct i2c_device_id *id)
 {
+	struct uda1380_platform_data *pdata = client->dev.platform_data;
 	struct snd_soc_device *socdev = uda1380_socdev;
-	struct uda1380_setup_data *setup = socdev->codec_data;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	int ret;
 
-	i2c_set_clientdata(i2c, codec);
-	codec->control_data = i2c;
+	if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
+		return -EINVAL;
+
+	ret = gpio_request(pdata->gpio_power, "uda1380 power");
+	if (ret)
+		goto err_power;
+	ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+	if (ret)
+		goto err_reset;
+
+	gpio_direction_output(pdata->gpio_power, 1);
 
-	ret = uda1380_init(socdev, setup->dac_clk);
-	if (ret < 0)
+	/* we may need to have the clock running here - pH5 */
+	gpio_direction_output(pdata->gpio_reset, 1);
+	udelay(5);
+	gpio_set_value(pdata->gpio_reset, 0);
+
+	i2c_set_clientdata(client, codec);
+	codec->control_data = client;
+
+	ret = uda1380_init(socdev, pdata->dac_clk);
+	if (ret) {
 		pr_err("uda1380: failed to initialise UDA1380\n");
+		goto err_init;
+	}
 
+	return 0;
+
+err_init:
+	gpio_free(pdata->gpio_reset);
+err_reset:
+	gpio_free(pdata->gpio_power);
+err_power:
 	return ret;
 }
 
 static int uda1380_i2c_remove(struct i2c_client *client)
 {
+	struct uda1380_platform_data *pdata = client->dev.platform_data;
 	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+
 	kfree(codec->reg_cache);
+	gpio_set_value(pdata->gpio_power, 0);
+	gpio_free(pdata->gpio_reset);
+	gpio_free(pdata->gpio_power);
 	return 0;
 }
 
@@ -781,55 +811,24 @@ static struct i2c_driver uda1380_i2c_driver = {
 	.id_table = uda1380_i2c_id,
 };
 
-static int uda1380_add_i2c_device(struct platform_device *pdev,
-				  const struct uda1380_setup_data *setup)
+static int uda1380_add_i2c_device(struct platform_device *pdev)
 {
-	struct i2c_board_info info;
-	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	int ret;
+	int ret = 0;
 
 	ret = i2c_add_driver(&uda1380_i2c_driver);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "can't add i2c driver\n");
-		return ret;
-	}
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = setup->i2c_address;
-	strlcpy(info.type, "uda1380", I2C_NAME_SIZE);
-
-	adapter = i2c_get_adapter(setup->i2c_bus);
-	if (!adapter) {
-		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-			setup->i2c_bus);
-		goto err_driver;
-	}
-
-	client = i2c_new_device(adapter, &info);
-	i2c_put_adapter(adapter);
-	if (!client) {
-		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-			(unsigned int)info.addr);
-		goto err_driver;
-	}
-
-	return 0;
+	if (ret != 0)
+		dev_err(&pdev->dev, "can't add i2c driver: %d\n", ret);
 
-err_driver:
-	i2c_del_driver(&uda1380_i2c_driver);
-	return -ENODEV;
+	return ret;
 }
 #endif
 
 static int uda1380_probe(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct uda1380_setup_data *setup;
 	struct snd_soc_codec *codec;
 	int ret;
 
-	setup = socdev->codec_data;
 	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
 	if (codec == NULL)
 		return -ENOMEM;
@@ -843,10 +842,8 @@ static int uda1380_probe(struct platform_device *pdev)
 	ret = -ENODEV;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = uda1380_add_i2c_device(pdev, setup);
-	}
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	ret = uda1380_add_i2c_device(pdev);
 #endif
 
 	if (ret != 0)
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index c55c17a..d7904c5 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -8,9 +8,6 @@
  * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
  */
 
-#ifndef _UDA1380_H
-#define _UDA1380_H
-
 #define UDA1380_CLK	0x00
 #define UDA1380_IFACE	0x01
 #define UDA1380_PM	0x02
@@ -72,19 +69,9 @@
 #define R22_SKIP_DCFIL	0x0002
 #define R23_AGC_EN	0x0001
 
-struct uda1380_setup_data {
-	int            i2c_bus;
-	unsigned short i2c_address;
-	int            dac_clk;
-#define UDA1380_DAC_CLK_SYSCLK 0
-#define UDA1380_DAC_CLK_WSPLL  1
-};
-
 #define UDA1380_DAI_DUPLEX	0 /* playback and capture on single DAI */
 #define UDA1380_DAI_PLAYBACK	1 /* playback DAI */
 #define UDA1380_DAI_CAPTURE	2 /* capture DAI */
 
 extern struct snd_soc_dai uda1380_dai[3];
 extern struct snd_soc_codec_device soc_codec_dev_uda1380;
-
-#endif /* _UDA1380_H */
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index fa0e7e6..cc7dbe5 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -448,17 +448,10 @@ static struct snd_soc_card snd_soc_card_magician = {
 	.platform = &pxa2xx_soc_platform,
 };
 
-/* magician audio private data */
-static struct uda1380_setup_data magician_uda1380_setup = {
-	.i2c_address = 0x18,
-	.dac_clk = UDA1380_DAC_CLK_WSPLL,
-};
-
 /* magician audio subsystem */
 static struct snd_soc_device magician_snd_devdata = {
 	.card = &snd_soc_card_magician,
 	.codec_dev = &soc_codec_dev_uda1380,
-	.codec_data = &magician_uda1380_setup,
 };
 
 static struct platform_device *magician_snd_device;
@@ -470,12 +463,6 @@ static int __init magician_init(void)
 	if (!machine_is_magician())
 		return -ENODEV;
 
-	ret = gpio_request(EGPIO_MAGICIAN_CODEC_POWER, "CODEC_POWER");
-	if (ret)
-		goto err_request_power;
-	ret = gpio_request(EGPIO_MAGICIAN_CODEC_RESET, "CODEC_RESET");
-	if (ret)
-		goto err_request_reset;
 	ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
 	if (ret)
 		goto err_request_spk;
@@ -492,14 +479,8 @@ static int __init magician_init(void)
 	if (ret)
 		goto err_request_in_sel1;
 
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 1);
 	gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
 
-	/* we may need to have the clock running here - pH5 */
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 1);
-	udelay(5);
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 0);
-
 	magician_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!magician_snd_device) {
 		ret = -ENOMEM;
@@ -527,10 +508,6 @@ err_request_mic:
 err_request_ep:
 	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
 err_request_spk:
-	gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
-err_request_reset:
-	gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
-err_request_power:
 	return ret;
 }
 
@@ -541,15 +518,12 @@ static void __exit magician_exit(void)
 	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
 	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
 	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 0);
 
 	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
 	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
 	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
 	gpio_free(EGPIO_MAGICIAN_EP_POWER);
 	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
-	gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
-	gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
 }
 
 module_init(magician_init);
-- 
1.6.3.1

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

* [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380
  2009-06-14 10:51     ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Philipp Zabel
@ 2009-06-14 10:51       ` Philipp Zabel
  2009-06-14 15:00         ` Mark Brown
  2009-06-14 14:51       ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Mark Brown
  1 sibling, 1 reply; 14+ messages in thread
From: Philipp Zabel @ 2009-06-14 10:51 UTC (permalink / raw)
  To: alsa-devel; +Cc: Mark Brown, Philipp Zabel

Configures I2C address, power/reset GPIOs and DAC clock from WSPLL.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
---
 arch/arm/mach-pxa/magician.c |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 869f083..3da8284 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -43,6 +43,8 @@
 #include <mach/irda.h>
 #include <mach/ohci.h>
 
+#include <sound/uda1380.h>
+
 #include "devices.h"
 #include "generic.h"
 
@@ -862,9 +864,22 @@ static struct platform_device calypso = {
 };
 
 /*
- * I2C
+ * Philips UDA1380 on I2C
  */
 
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
+	.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
+	.dac_clk    = UDA1380_DAC_CLK_WSPLL,
+};
+
+static struct i2c_board_info i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x18),
+		.platform_data = &uda1380_info,
+	},
+};
+
 static struct i2c_pxa_platform_data i2c_info = {
 	.fast_mode = 1,
 };
@@ -906,6 +921,7 @@ static void __init magician_init(void)
 	}
 	pxa27x_set_i2c_power_info(NULL);
 	pxa_set_i2c_info(&i2c_info);
+	i2c_register_board_info(0, ARRAY_AND_SIZE(i2c_board_info));
 	i2c_register_board_info(1, ARRAY_AND_SIZE(pi2c_board_info));
 	pxa_set_mci_info(&magician_mci_info);
 	pxa_set_ohci_info(&magician_ohci_info);
-- 
1.6.3.1

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

* Re: [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity
  2009-06-14 10:51   ` [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity Philipp Zabel
  2009-06-14 10:51     ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Philipp Zabel
@ 2009-06-14 14:23     ` Mark Brown
  1 sibling, 0 replies; 14+ messages in thread
From: Mark Brown @ 2009-06-14 14:23 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: alsa-devel

On Sun, Jun 14, 2009 at 12:51:30PM +0200, Philipp Zabel wrote:
> Follow-up fix needed since "ASoC: pxa-ssp.c fix clock/frame invert".
> 
> Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>

Applied, thanks.

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

* Re: [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata
  2009-06-14 10:51     ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Philipp Zabel
  2009-06-14 10:51       ` [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380 Philipp Zabel
@ 2009-06-14 14:51       ` Mark Brown
  2009-06-14 20:52         ` pHilipp Zabel
  2009-06-15 20:18         ` [PATCH] ASoC: UDA1380: refactor device registration Philipp Zabel
  1 sibling, 2 replies; 14+ messages in thread
From: Mark Brown @ 2009-06-14 14:51 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: alsa-devel

On Sun, Jun 14, 2009 at 12:51:31PM +0200, Philipp Zabel wrote:
> This patch removes the I2C board info registration from the codec driver.
> Instead, device instantiation will be done via global i2c_board_info from
> board files. At the same time, platform specific configuration is moved
> to platform data and common power/reset GPIO handling moves into the
> codec driver.

Thanks for doing this.  This should probably either be squashed in with
the arch patch that follows.

> +struct uda1380_platform_data {
> +	int gpio_power;
> +	int gpio_reset;
> +	int dac_clk;
> +#define UDA1380_DAC_CLK_SYSCLK 0
> +#define UDA1380_DAC_CLK_WSPLL  1

Is it worth changing this to make both options non-zero so that there's
no possibility that it could be left zero by default?

> +static int uda1380_add_i2c_device(struct platform_device *pdev)
>  {

...

>  	ret = i2c_add_driver(&uda1380_i2c_driver);

If you're doing this conversion the ideal thing is to convert the driver
completely so that the driver is registered when the module loads and
does the DAI registration once the I2C device probes.  The I2C device
probe should also do any other initialisation that can be done without
the rest of the ASoC subsystem such as registering the GPIOs.

This implies a bit more rearrangment of the registration functions -
most of the initialisation can stay in the I2C function but anything
that uses the entire ASoC device and the final instantiation of the card
should be moved into the ASoC probe function which will be called once
the entire card has started.  WM8731 is a good template to look at here.

> --- a/sound/soc/codecs/uda1380.h
> +++ b/sound/soc/codecs/uda1380.h
> @@ -8,9 +8,6 @@
>   * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
>   */
>  
> -#ifndef _UDA1380_H
> -#define _UDA1380_H
> -

Best practice would be to keep these with a different name.

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

* Re: [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380
  2009-06-14 10:51       ` [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380 Philipp Zabel
@ 2009-06-14 15:00         ` Mark Brown
  2009-06-15  2:06           ` Eric Miao
  0 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2009-06-14 15:00 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: alsa-devel, Eric Miao

On Sun, Jun 14, 2009 at 12:51:32PM +0200, Philipp Zabel wrote:
> Configures I2C address, power/reset GPIOs and DAC clock from WSPLL.
> 
> Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>

Eric, I don't know how you want to deal with the cross tree issues for
this patch?  It's part of a conversion of the UDA1380 driver to the
standard device model so it'll depend on ASoC changes to the UDA1380
driver but obviously there's arch/arm/mach-pxa changes too.

One way of making sure there aren't any problem would be for one of us
to apply both patches to a branch which can then be pulled in to both
the ASoC and PXA trees.  Does that sound sane?

> ---
>  arch/arm/mach-pxa/magician.c |   18 +++++++++++++++++-
>  1 files changed, 17 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
> index 869f083..3da8284 100644
> --- a/arch/arm/mach-pxa/magician.c
> +++ b/arch/arm/mach-pxa/magician.c
> @@ -43,6 +43,8 @@
>  #include <mach/irda.h>
>  #include <mach/ohci.h>
>  
> +#include <sound/uda1380.h>
> +
>  #include "devices.h"
>  #include "generic.h"
>  
> @@ -862,9 +864,22 @@ static struct platform_device calypso = {
>  };
>  
>  /*
> - * I2C
> + * Philips UDA1380 on I2C
>   */
>  
> +static struct uda1380_platform_data uda1380_info = {
> +	.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
> +	.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
> +	.dac_clk    = UDA1380_DAC_CLK_WSPLL,
> +};
> +
> +static struct i2c_board_info i2c_board_info[] = {
> +	{
> +		I2C_BOARD_INFO("uda1380", 0x18),
> +		.platform_data = &uda1380_info,
> +	},
> +};
> +
>  static struct i2c_pxa_platform_data i2c_info = {
>  	.fast_mode = 1,
>  };
> @@ -906,6 +921,7 @@ static void __init magician_init(void)
>  	}
>  	pxa27x_set_i2c_power_info(NULL);
>  	pxa_set_i2c_info(&i2c_info);
> +	i2c_register_board_info(0, ARRAY_AND_SIZE(i2c_board_info));
>  	i2c_register_board_info(1, ARRAY_AND_SIZE(pi2c_board_info));
>  	pxa_set_mci_info(&magician_mci_info);
>  	pxa_set_ohci_info(&magician_ohci_info);
> -- 
> 1.6.3.1
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 

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

* Re: [PATCH, RFC 2/3] ASoC: UDA1380: register from board  files, configure via pdata
  2009-06-14 14:51       ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Mark Brown
@ 2009-06-14 20:52         ` pHilipp Zabel
  2009-06-15  4:56           ` Can't use bluetooth headset after upgrade of alsa/bluez with fedora 11 Ted T. Logan
  2009-06-15 20:18         ` [PATCH] ASoC: UDA1380: refactor device registration Philipp Zabel
  1 sibling, 1 reply; 14+ messages in thread
From: pHilipp Zabel @ 2009-06-14 20:52 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel

On Sun, Jun 14, 2009 at 4:51 PM, Mark
Brown<broonie@opensource.wolfsonmicro.com> wrote:
> On Sun, Jun 14, 2009 at 12:51:31PM +0200, Philipp Zabel wrote:
>> This patch removes the I2C board info registration from the codec driver.
>> Instead, device instantiation will be done via global i2c_board_info from
>> board files. At the same time, platform specific configuration is moved
>> to platform data and common power/reset GPIO handling moves into the
>> codec driver.
>
> Thanks for doing this.  This should probably either be squashed in with
> the arch patch that follows.

Ok. If Eric agrees, I'll squash as you propose.

>> +struct uda1380_platform_data {
>> +     int gpio_power;
>> +     int gpio_reset;
>> +     int dac_clk;
>> +#define UDA1380_DAC_CLK_SYSCLK 0
>> +#define UDA1380_DAC_CLK_WSPLL  1
>
> Is it worth changing this to make both options non-zero so that there's
> no possibility that it could be left zero by default?

I think this is fine as-is: SYSCLK is the default setting for DAC
clock input when the chip comes out of reset.

>> +static int uda1380_add_i2c_device(struct platform_device *pdev)
>>  {
>
> ...
>
>>       ret = i2c_add_driver(&uda1380_i2c_driver);
>
> If you're doing this conversion the ideal thing is to convert the driver
> completely so that the driver is registered when the module loads and
> does the DAI registration once the I2C device probes.  The I2C device
> probe should also do any other initialisation that can be done without
> the rest of the ASoC subsystem such as registering the GPIOs.

Ok.

> This implies a bit more rearrangment of the registration functions -
> most of the initialisation can stay in the I2C function but anything
> that uses the entire ASoC device and the final instantiation of the card
> should be moved into the ASoC probe function which will be called once
> the entire card has started.  WM8731 is a good template to look at here.

I'll look at WM8731 for guidance, thanks.

>> --- a/sound/soc/codecs/uda1380.h
>> +++ b/sound/soc/codecs/uda1380.h
>> @@ -8,9 +8,6 @@
>>   * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
>>   */
>>
>> -#ifndef _UDA1380_H
>> -#define _UDA1380_H
>> -
>
> Best practice would be to keep these with a different name.

uda1380.h is only a one-time private header file, but I won't say no
to best practice.

cheers
Philipp

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

* Re: [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380
  2009-06-14 15:00         ` Mark Brown
@ 2009-06-15  2:06           ` Eric Miao
  2009-06-15 10:26             ` Mark Brown
  0 siblings, 1 reply; 14+ messages in thread
From: Eric Miao @ 2009-06-15  2:06 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Philipp Zabel

On Sun, Jun 14, 2009 at 11:00 PM, Mark
Brown<broonie@opensource.wolfsonmicro.com> wrote:
> On Sun, Jun 14, 2009 at 12:51:32PM +0200, Philipp Zabel wrote:
>> Configures I2C address, power/reset GPIOs and DAC clock from WSPLL.
>>
>> Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
>
> Eric, I don't know how you want to deal with the cross tree issues for
> this patch?  It's part of a conversion of the UDA1380 driver to the
> standard device model so it'll depend on ASoC changes to the UDA1380
> driver but obviously there's arch/arm/mach-pxa changes too.
>
> One way of making sure there aren't any problem would be for one of us
> to apply both patches to a branch which can then be pulled in to both
> the ASoC and PXA trees.  Does that sound sane?

Normally, I'll queue such patch in my pending branch and will be pushed
out until the other patch(es) with dependency has been merged upstream.
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

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

* Can't use bluetooth headset after upgrade of alsa/bluez with fedora 11
  2009-06-14 20:52         ` pHilipp Zabel
@ 2009-06-15  4:56           ` Ted T. Logan
  2009-06-15  5:38             ` busy device issue when it is not busy! Guilherme
  0 siblings, 1 reply; 14+ messages in thread
From: Ted T. Logan @ 2009-06-15  4:56 UTC (permalink / raw)
  Cc: alsa-devel

ALSA lib pcm_bluetooth.c:1607:(audioservice_expect) BT_OPEN failed : 
Invalid argument(22)

** WARNING **: alsa_setup(): Unable to install hw params

I get this all the time now.  What does this error mean?



arecord -D bluetoothh550 -f S16_LE | aplay -D bluetoothh550 -f S16_LE
Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono
ALSA lib pcm_bluetooth.c:1607:(audioservice_expect) BT_OPEN failed : 
Invalid argument(22)
arecord: set_params:1041: Unable to install hw params:
ACCESS:  RW_INTERLEAVED
FORMAT:  S16_LE
SUBFORMAT:  STD
SAMPLE_BITS: 16
FRAME_BITS: 16
CHANNELS: 1
RATE: 8000
PERIOD_TIME: 125000
PERIOD_SIZE: 1000
PERIOD_BYTES: 2000
PERIODS: 4
BUFFER_TIME: 500000
BUFFER_SIZE: 4000
BUFFER_BYTES: 8000
TICK_TIME: [0 0]
aplay: playback:2297: read error



and here with mplayer


Playing skypering.wav.
Audio only file format detected.
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 16000 Hz, 2 ch, s16le, 512.0 kbit/100.00% (ratio: 64000->64000)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
[AO_ALSA] alsa-lib: pcm_bluetooth.c:1607:(audioservice_expect) BT_OPEN 
failed : Invalid argument(22)
[AO_ALSA] Unable to set hw-parameters: Invalid argument
Failed to initialize audio driver 'alsa:device=bluetoothh550'
Could not open/initialize audio device -> no sound.
Audio: no sound
Video: no video

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

* busy device issue when it is not busy!
  2009-06-15  4:56           ` Can't use bluetooth headset after upgrade of alsa/bluez with fedora 11 Ted T. Logan
@ 2009-06-15  5:38             ` Guilherme
  0 siblings, 0 replies; 14+ messages in thread
From: Guilherme @ 2009-06-15  5:38 UTC (permalink / raw)
  To: alsa-devel

Mates...

I am running a simple app that I found called pcm.c and I can't get 
through with that.  It creates  and send  simple sine wave to the speakers!

When I run the app I get the following error:

guilherme@lap:/home/guilherme/Experimentos# ./PCM
Playback device is plughw:0,0
Stream parameters are 44100Hz, S16_LE, 1 channels
sine wave rate is 0 0.0000Hz
Using transfer method: write
Playback open error: Device or resource busy

Every application I start playbacks the sound without a problem. Is 
there any special conf I should do to free the Device?

Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <alsa/asoundlib.h>
#include <sys/time.h>
#include <math.h>

static char *device = "plughw:0,0";                    //playback device 
aplay -l
static snd_pcm_format_t format = SND_PCM_FORMAT_S16;   //sample format 
unsigned 16 bit endian
static unsigned int rate = 44100;                      //stream rate
static unsigned int channels = 1;                       //contagem dos 
canais
static unsigned int buffer_time = 500000;              //ring buffer 
length on us
static unsigned int period_time = 100000;              //period time in us
static double freq = 400;                              // frequencia da 
senóide em Hz
static int verbose = 0;                                //verbose flag
static int resample = 1;                               //abilitar 
alsa-lib resampling
static int period_event = 0;                           // produz um 
event pool a cada periodo

static snd_pcm_sframes_t buffer_size;                  //quantidade de 
buffers frames
static snd_pcm_sframes_t period_size;                  //quantidade de 
periods frames
static snd_output_t *output = NULL;                    //ALSA usa esse 
ponteiro para lidar com output objects


static void generate_sine(const snd_pcm_channel_area_t *areas,
                                          snd_pcm_uframes_t offset,
                                          int count, double *_phase)
{
        static double max_phase = 2. * M_PI;
        double phase = *_phase;
        double step = max_phase*freq / (double)rate;
        double res;
        unsigned char *samples[channels], *tmp;
        int steps[channels];
        unsigned int chn, byte;
       
        union {
                int i;
                unsigned char c[4];
        } ires;
        unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1;
        int bps = snd_pcm_format_width(format) / 8; //bits per sample
       
        /*verificar e preparar o conteúdo das areas*/
        for (chn = 0; chn < channels; chn++) {
            if ((areas[chn].first % 8) != 0) {
                    printf("areas[%i].first == %i, abortando...\n", chn, 
areas[chn].first);
                    exit(EXIT_FAILURE);
            }
            //pega endereço e offset da area
            samples[chn] = /*(signed short *)*/(((unsigned char 
*)areas[chn].addr) + (areas[chn].first / 8));
           
         if ((areas[chn].step % 16) != 0) {
                printf("areas[%i].step == %i, aborting...\n", chn, 
areas[chn].step);
                exit(EXIT_FAILURE);
         }
           
                steps[chn] = areas[chn].step / 8;
                samples[chn] += offset * steps[chn];
        }
       
        //completa os channels da area
        while(count-- > 0) {
            res = sin(phase) * maxval;
            ires.i = res;
            tmp = ires.c;
            for (chn = 0; chn < channels; chn++) {
                    for (byte = 0; byte < (unsigned int)bps; byte++) 
*(samples[chn] + byte) = tmp[byte];
                        samples[chn] += steps[chn];
                    }
                    phase += step;
                    if (phase >= max_phase)
                            phase -= max_phase;
                    }
                    *_phase = phase;
  
}                               


static int set_hwparams(snd_pcm_t *handle,
                                snd_pcm_hw_params_t *params,
                                snd_pcm_access_t access)
{
        unsigned int rrate;
        snd_pcm_uframes_t size;
        int err, dir;
       
        /*escolha todos os parametros*/
        err = snd_pcm_hw_params_any(handle, params);
        if (err < 0) {
                printf("Broken configuration for playback: no 
configuration available: %s\n", snd_strerror(err));
                return err;
        }
       
        /*set hardware resampling*/
        err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
        if (err < 0) {
                printf("Resampling setup failed for playback: %s\n", 
snd_strerror(err));
                return err;
        }
       
      /* set the interleaved read/write format */
      err = snd_pcm_hw_params_set_access(handle, params, access);
      if (err < 0) {
            printf("Access type not available for playback: %s\n", 
snd_strerror(err));
            return err;
       }
      
      /* set the sample format SND_PCM_FORMAT_S16 */
       err = snd_pcm_hw_params_set_format(handle, params, format);
       if (err < 0) {
             printf("Sample format not available for playback: %s\n", 
snd_strerror(err));
             return err;
      }
     
        /* set the count of channels 1  */
       err = snd_pcm_hw_params_set_channels(handle, params, channels);
       if (err < 0) {
             printf("Channels count (%i) not available for playbacks: 
%s\n", channels, snd_strerror(err));
             return err;
      }
     
      /* set the stream rate */
       rrate = rate;
       err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
       if (err < 0) {
             printf("Rate %iHz not available for playback: %s\n", rate, 
snd_strerror(err));
             return err;
      }
      if (rrate != rate) {
             printf("Rate doesn't match (requested %iHz, get %iHz)\n", 
rate, err);
            return -EINVAL;
      }
      /* set the buffer time */
      err = snd_pcm_hw_params_set_buffer_time_near(handle, params, 
&buffer_time, &dir);
      if (err < 0) {
           printf("Unable to set buffer time %i for playback: %s\n", 
buffer_time, snd_strerror(err));
           return err;
      }
      err = snd_pcm_hw_params_get_buffer_size(params, &size);
      if (err < 0) {
           printf("Unable to get buffer size for playback: %s\n", 
snd_strerror(err));
           return err;
      }
      buffer_size = size;
      /* set the period time */
      err = snd_pcm_hw_params_set_period_time_near(handle, params, 
&period_time, &dir);
      if (err < 0) {
           printf("Unable to set period time %i for playback: %s\n", 
period_time, snd_strerror(err));
           return err;
      }
      err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
      if (err < 0) {
           printf("Unable to get period size for playback: %s\n", 
snd_strerror(err));
           return err;
      }
      period_size = size;
      /* write the parameters to device */
      err = snd_pcm_hw_params(handle, params);
      if (err < 0) {
           printf("Unable to set hw params for playback: %s\n", 
snd_strerror(err));
           return err;
      }
      return 0;
}



static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) {

            int err;
           
            /*pegar os parametros atuais swparams*/
            err = snd_pcm_sw_params_current(handle, swparams);
            if (err < 0) {
                printf("Unable to determine current swparams for 
playback: %s\n", snd_strerror(err));
                return err;
            }
            /*Começa a transferência quando o buffer está quase cheio*/
            /*(buffer_size / avail_min) * avail_min */
            err = snd_pcm_sw_params_set_avail_min(handle, swparams, 
(buffer_size / period_size) * period_size);
            if (err < 0) {
                printf("Unable to set start threshold mode for playback: 
%s\n", snd_strerror(err));
                return err;
            }
            /* allow the transfer when at least period_size samples can 
be processed */
          /* or disable this mechanism when period event is enabled (aka 
interrupt like style processing) */
          err = snd_pcm_sw_params_set_avail_min(handle, swparams, 
period_event ? buffer_size : period_size);
          if (err < 0) {
                 printf("Unable to set avail min for playback: %s\n", 
snd_strerror(err));
                  return err;
         }
          /* enable period events when requested */
         if (period_event) {
                  err = snd_pcm_sw_params_set_period_event(handle, 
swparams, 1);
                  if (err < 0) {
                          printf("Unable to set period event: %s\n", 
snd_strerror(err));
                          return err;
                 }
          }
          /* write the parameters to the playback device */
          err = snd_pcm_sw_params(handle, swparams);
          if (err < 0) {
                  printf("Unable to set sw params for playback: %s\n", 
snd_strerror(err));
                  return err;
          }
          return 0;
 }

/* Tenta recuperar estados de underrun e suspend */

static int xrun_recovery(snd_pcm_t *handle, int err)
{
            if (verbose)
                    printf("stream recovery\n");
            if (err == -EPIPE) {      //under-run*/
                    err = snd_pcm_prepare(handle);
                    if (err < 0)
                                printf("Can't recovery from underrun, 
prepare failed: %s\n", snd_strerror(err));
                    return 0;
            } else if (err == -ESTRPIPE) {
                    while ((err = snd_pcm_resume(handle)) == -EAGAIN)
                            sleep(1); /*espera pela release flag*/
                    if (err < 0) {
                            err = snd_pcm_prepare(handle);
                            if (err < 0)
                                    printf("Can't recovery from suspend, 
prepare failed: %s\n", snd_strerror(err));
                            }
                            return 0;
                    }
                    return err;
}

/* Metodo de transferência *WRITE-ONLY* */
static int write_loop(snd_pcm_t *handle,
                             signed short *samples,
                             snd_pcm_channel_area_t *areas)
{
        double phase = 0;
        signed short *ptr;
        int err, cptr;
       
        while(1) {
            generate_sine(areas, 0, period_size, &phase);
            ptr = samples;
            cptr = period_size;
            while (cptr > 0) {
                    err = snd_pcm_writei(handle, ptr, cptr);
                    if (err == -EAGAIN)
                                 continue;
                    if (err < 0) {
                         if (xrun_recovery(handle, err) < 0) {
                                 printf("Write error: %s\n", 
snd_strerror(err));
                                 exit(EXIT_FAILURE);
                         }//if
                         ptr += err * channels;
                         cptr -= err;
                   }//if
                    }//if

         }//while
}


 /*
 *   Método de transferência - write and wait por espaço no buffer
 */

static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, 
unsigned int count)
{
        unsigned short revents;

        while (1) {
                 poll(ufds, count, -1);
                 snd_pcm_poll_descriptors_revents(handle, ufds, count, 
&revents);
                 if (revents & POLLERR)
                        return -EIO;
                 if (revents & POLLOUT)
                        return 0;
        }
}


static int write_and_poll_loop(snd_pcm_t *handle,
                                 signed short *samples,
                                 snd_pcm_channel_area_t *areas)
  {
          struct pollfd *ufds;
          double phase = 0;
          signed short *ptr;
          int err, count, cptr, init;
 
          count = snd_pcm_poll_descriptors_count (handle);
          if (count <= 0) {
                  printf("Invalid poll descriptors count\n");
                  return count;
          }
 
          ufds = malloc(sizeof(struct pollfd) * count);
          if (ufds == NULL) {
                  printf("No enough memory\n");
                  return -ENOMEM;
          }
          if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) {
                  printf("Unable to obtain poll descriptors for 
playback: %s\n", snd_strerror(err));
                  return err;
          }
 
          init = 1;
          while (1) {
                  if (!init) {
                          err = wait_for_poll(handle, ufds, count);
                          if (err < 0) {
                                 if (snd_pcm_state(handle) == 
SND_PCM_STATE_XRUN ||
                                      snd_pcm_state(handle) == 
SND_PCM_STATE_SUSPENDED) {
                                          err = snd_pcm_state(handle) == 
SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
                                          if (xrun_recovery(handle, err) 
< 0) {
                                                  printf("Write error: 
%s\n", snd_strerror(err));
                                                  exit(EXIT_FAILURE);
                                          }
                                          init = 1;
                                  } else {
                                          printf("Wait for poll failed\n");
                                         return err;
                                  }
                          }
                  }
 
                  generate_sine(areas, 0, period_size, &phase);
                  ptr = samples;
                 cptr = period_size;
                  while (cptr > 0) {
                          err = snd_pcm_writei(handle, ptr, cptr);
                          if (err < 0) {
                                  if (xrun_recovery(handle, err) < 0) {
                                          printf("Write error: %s\n", 
snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                                  init = 1;
                                 break;  /* skip one period */
                          }
                          if (snd_pcm_state(handle) == 
SND_PCM_STATE_RUNNING)
                                  init = 0;
                          ptr += err * channels;
                          cptr -= err;
                         if (cptr == 0)
                                  break;
                           /* it is possible, that the initial buffer 
cannot store */
                          /* all data from the last period, so wait 
awhile */
                          err = wait_for_poll(handle, ufds, count);
                          if (err < 0) {
                                  if (snd_pcm_state(handle) == 
SND_PCM_STATE_XRUN ||
                                     snd_pcm_state(handle) == 
SND_PCM_STATE_SUSPENDED) {
                                          err = snd_pcm_state(handle) == 
SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
                                          if (xrun_recovery(handle, err) 
< 0) {
                                                  printf("Write error: 
%s\n", snd_strerror(err));
                                                  exit(EXIT_FAILURE);
                                          }
                                          init = 1;
                                  } else {
                                          printf("Wait for poll failed\n");
                                         return err;
                                  }
                          }
                 }
          }
}



/*
*  Metodo de transferencia - Notificação assincrona
*/


 struct async_private_data {
         signed short *samples;
         snd_pcm_channel_area_t *areas;
         double phase;
 };
 

static void async_callback(snd_async_handler_t *ahandler)
{
         snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
         struct async_private_data *data = 
snd_async_handler_get_callback_private(ahandler);
          signed short *samples = data->samples;
          snd_pcm_channel_area_t *areas = data->areas;
         snd_pcm_sframes_t avail;
          int err;
         
         avail = snd_pcm_avail_update(handle);
          while (avail >= period_size) {
                 generate_sine(areas, 0, period_size, &data->phase);
                  err = snd_pcm_writei(handle, samples, period_size);
                  if (err < 0) {
                          printf("Write error: %s\n", snd_strerror(err));
                         exit(EXIT_FAILURE);
                 }
                  if (err != period_size) {
                          printf("Write error: written %i expected 
%li\n", err, period_size);
                         exit(EXIT_FAILURE);
                 }
                  avail = snd_pcm_avail_update(handle);
          }
}


static int async_loop(snd_pcm_t *handle,
                        signed short *samples,
                       snd_pcm_channel_area_t *areas)
  {
          struct async_private_data data;
         snd_async_handler_t *ahandler;
          int err, count;
 
         data.samples = samples;
          data.areas = areas;
         data.phase = 0;
          err = snd_async_add_pcm_handler(&ahandler, handle, 
async_callback, &data);
          if (err < 0) {
                  printf("Unable to register async handler\n");
                  exit(EXIT_FAILURE);
         }
         for (count = 0; count < 2; count++) {
                 generate_sine(areas, 0, period_size, &data.phase);
                  err = snd_pcm_writei(handle, samples, period_size);
                  if (err < 0) {
                         printf("Initial write error: %s\n", 
snd_strerror(err));
                         exit(EXIT_FAILURE);
                  }
                  if (err != period_size) {
                          printf("Initial write error: written %i 
expected %li\n", err, period_size);
                         exit(EXIT_FAILURE);
                  }
          }
          if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) {
                  err = snd_pcm_start(handle);
                  if (err < 0) {
                         printf("Start error: %s\n", snd_strerror(err));
                          exit(EXIT_FAILURE);
                  }
          }
 
         /* because all other work is done in the signal handler,
             suspend the process */
          while (1) {
                  sleep(1);
          }
}

 /*
 *   Transfer method - asynchronous notification + direct write
 */
 
  static void async_direct_callback(snd_async_handler_t *ahandler)
  {
          snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
          struct async_private_data *data = 
snd_async_handler_get_callback_private(ahandler);
          const snd_pcm_channel_area_t *my_areas;
          snd_pcm_uframes_t offset, frames, size;
          snd_pcm_sframes_t avail, commitres;
          snd_pcm_state_t state;
          int first = 0, err;
         
          while (1) {
                  state = snd_pcm_state(handle);
                  if (state == SND_PCM_STATE_XRUN) {
                          err = xrun_recovery(handle, -EPIPE);
                          if (err < 0) {
                                  printf("XRUN recovery failed: %s\n", 
snd_strerror(err));
                                  exit(EXIT_FAILURE);
                          }
                          first = 1;
                  } else if (state == SND_PCM_STATE_SUSPENDED) {
                          err = xrun_recovery(handle, -ESTRPIPE);
                          if (err < 0) {
                                  printf("SUSPEND recovery failed: 
%s\n", snd_strerror(err));
                                  exit(EXIT_FAILURE);
                          }
                  }
                  avail = snd_pcm_avail_update(handle);
                  if (avail < 0) {
                          err = xrun_recovery(handle, avail);
                          if (err < 0) {
                                  printf("avail update failed: %s\n", 
snd_strerror(err));
                                   exit(EXIT_FAILURE);
                          }
                          first = 1;
                          continue;
                  }
                  if (avail < period_size) {
                          if (first) {
                                  first = 0;
                                  err = snd_pcm_start(handle);
                                  if (err < 0) {
                                          printf("Start error: %s\n", 
snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                 }
                         } else {
                                  break;
                          }
                          continue;
                  }
                 size = period_size;
                  while (size > 0) {
                          frames = size;
                          err = snd_pcm_mmap_begin(handle, &my_areas, 
&offset, &frames);
                          if (err < 0) {
                                  if ((err = xrun_recovery(handle, err)) 
< 0) {
                                          printf("MMAP begin avail 
error: %s\n", snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                                  first = 1;
                          }
                          generate_sine(my_areas, offset, frames, 
&data->phase);
                          commitres = snd_pcm_mmap_commit(handle, 
offset, frames);
                          if (commitres < 0 || 
(snd_pcm_uframes_t)commitres != frames) {
                                  if ((err = xrun_recovery(handle, 
commitres >= 0 ? -EPIPE : commitres)) < 0) {
                                          printf("MMAP commit error: 
%s\n", snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                                  first = 1;
                          }
                          size -= frames;
                  }
         }
}


static int async_direct_loop(snd_pcm_t *handle,
                               signed short *samples ATTRIBUTE_UNUSED,
                               snd_pcm_channel_area_t *areas 
ATTRIBUTE_UNUSED)
  {
          struct async_private_data data;
          snd_async_handler_t *ahandler;
          const snd_pcm_channel_area_t *my_areas;
          snd_pcm_uframes_t offset, frames, size;
          snd_pcm_sframes_t commitres;
          int err, count;
 
          data.samples = NULL;    /* we do not require the global sample 
area for direct write */
          data.areas = NULL;      /* we do not require the global areas 
for direct write */
          data.phase = 0;
         err = snd_async_add_pcm_handler(&ahandler, handle, 
async_direct_callback, &data);
          if (err < 0) {
                  printf("Unable to register async handler\n");
                  exit(EXIT_FAILURE);
          }
          for (count = 0; count < 2; count++) {
                  size = period_size;
                  while (size > 0) {
                          frames = size;
                          err = snd_pcm_mmap_begin(handle, &my_areas, 
&offset, &frames);
                          if (err < 0) {
                                  if ((err = xrun_recovery(handle, err)) 
< 0) {
                                          printf("MMAP begin avail 
error: %s\n", snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                 }
                         }
                          generate_sine(my_areas, offset, frames, 
&data.phase);
                          commitres = snd_pcm_mmap_commit(handle, 
offset, frames);
                          if (commitres < 0 || 
(snd_pcm_uframes_t)commitres != frames) {
                                  if ((err = xrun_recovery(handle, 
commitres >= 0 ? -EPIPE : commitres)) < 0) {
                                          printf("MMAP commit error: 
%s\n", snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                          }
                          size -= frames;
                   }
          }
          err = snd_pcm_start(handle);
          if (err < 0) {
                  printf("Start error: %s\n", snd_strerror(err));
                  exit(EXIT_FAILURE);
          }
 
         /* because all other work is done in the signal handler,
             suspend the process */
          while (1) {
                  sleep(1);
          }
}

 /*
 *   Transfer method - direct write only
 */
 
 static int direct_loop(snd_pcm_t *handle,
                         signed short *samples ATTRIBUTE_UNUSED,
                         snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED)
  {
          double phase = 0;
         const snd_pcm_channel_area_t *my_areas;
          snd_pcm_uframes_t offset, frames, size;
         snd_pcm_sframes_t avail, commitres;
          snd_pcm_state_t state;
          int err, first = 1;
 
          while (1) {
                  state = snd_pcm_state(handle);
                  if (state == SND_PCM_STATE_XRUN) {
                          err = xrun_recovery(handle, -EPIPE);
                          if (err < 0) {
                                 printf("XRUN recovery failed: %s\n", 
snd_strerror(err));
                                  return err;
                          }
                          first = 1;
                 } else if (state == SND_PCM_STATE_SUSPENDED) {
                         err = xrun_recovery(handle, -ESTRPIPE);
                          if (err < 0) {
                                  printf("SUSPEND recovery failed: 
%s\n", snd_strerror(err));
                                   return err;
                          }
                  }
                  avail = snd_pcm_avail_update(handle);
                  if (avail < 0) {
                          err = xrun_recovery(handle, avail);
                          if (err < 0) {
                                  printf("avail update failed: %s\n", 
snd_strerror(err));
                                  return err;
                          }
                          first = 1;
                          continue;
                  }
                  if (avail < period_size) {
                          if (first) {
                                  first = 0;
                                  err = snd_pcm_start(handle);
                                  if (err < 0) {
                                          printf("Start error: %s\n", 
snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                          } else {
                                  err = snd_pcm_wait(handle, -1);
                                  if (err < 0) {
                                          if ((err = 
xrun_recovery(handle, err)) < 0) {
                                                  printf("snd_pcm_wait 
error: %s\n", snd_strerror(err));
                                                  exit(EXIT_FAILURE);
                                          }
                                          first = 1;
                                  }
                          }
                          continue;
                  }
                  size = period_size;
                  while (size > 0) {
                           frames = size;
                          err = snd_pcm_mmap_begin(handle, &my_areas, 
&offset, &frames);
                          if (err < 0) {
                                 if ((err = xrun_recovery(handle, err)) 
< 0) {
                                          printf("MMAP begin avail 
error: %s\n", snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                                  first = 1;
                         }
                          generate_sine(my_areas, offset, frames, &phase);
                          commitres = snd_pcm_mmap_commit(handle, 
offset, frames);
                          if (commitres < 0 || 
(snd_pcm_uframes_t)commitres != frames) {
                                 if ((err = xrun_recovery(handle, 
commitres >= 0 ? -EPIPE : commitres)) < 0) {
                                          printf("MMAP commit error: 
%s\n", snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                  }
                                 first = 1;
                          }
                          size -= frames;
                  }
          }
}

/*
 *   Transfer method - direct write only using mmap_write functions
 */
 
 static int direct_write_loop(snd_pcm_t *handle,
                               signed short *samples,
                              snd_pcm_channel_area_t *areas)
 {
         double phase = 0;
          signed short *ptr;
          int err, cptr;
 
          while (1) {
                  generate_sine(areas, 0, period_size, &phase);
                 ptr = samples;
                  cptr = period_size;
                  while (cptr > 0) {
                          err = snd_pcm_mmap_writei(handle, ptr, cptr);
                          if (err == -EAGAIN)
                                  continue;
                          if (err < 0) {
                                  if (xrun_recovery(handle, err) < 0) {
                                          printf("Write error: %s\n", 
snd_strerror(err));
                                          exit(EXIT_FAILURE);
                                 }
                                 break;  /* skip one period */
                         }
                          ptr += err * channels;
                          cptr -= err;
                  }
          }
}

struct transfer_method {
       const char *name;
       snd_pcm_access_t access;
       int (*transfer_loop)(snd_pcm_t *handle,
                            signed short *samples,
                            snd_pcm_channel_area_t *areas);
};

static struct transfer_method transfer_methods[] = {
          { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop },
          { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, 
write_and_poll_loop },
          { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop },
          { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, 
async_direct_loop },
          { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, 
direct_loop },
          { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, 
direct_loop },
          { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, 
direct_write_loop },
          { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL }
};



static void help(void)
{
         int k;
          printf(
  "Usage: pcm [OPTION]... [FILE]...\n"
  "-h,--help      help\n"
  "-D,--device    playback device\n"
  "-r,--rate      stream rate in Hz\n"
  "-c,--channels  count of channels in stream\n"
  "-f,--frequency sine wave frequency in Hz\n"
  "-b,--buffer    ring buffer size in us\n"
  "-p,--period    period size in us\n"
  "-m,--method    transfer method\n"
  "-o,--format    sample format\n"
  "-v,--verbose   show the PCM setup parameters\n"
  "-n,--noresample  do not resample\n"
  "-e,--pevent    enable poll event after each period\n"
  "\n");
          printf("Recognized sample formats are:");
         for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
                  const char *s = snd_pcm_format_name(k);
                  if (s)
                          printf(" %s", s);
          }
          printf("\n");
          printf("Recognized transfer methods are:");
          for (k = 0; transfer_methods[k].name; k++)
                  printf(" %s", transfer_methods[k].name);
          printf("\n");
}



int main (int argc, char *argv[])
{
            struct option long_option[] =
                {
                     {"help", 0, NULL, 'h'},
                     {"device", 1, NULL, 'd'},
                     {"rate", 1, NULL, 'r'},
                     {"channels", 1, NULL, 'c'},
                     {"frequency", 1, NULL, 'f'},
                     {"buffer", 1, NULL, 'b'},
                     {"period", 1, NULL, 'p'},
                     {"method", 1, NULL, 'm'},
                     {"format", 1, NULL, 'o'},
                     {"verbose", 1, NULL, 'v'},
                     {"noresample", 1, NULL, 'n'},
                     {"pevent", 1, NULL, 'e'},
                     {NULL, 0, NULL, 0},
                };
               
                snd_pcm_t *handle;                            //ponteiro 
para pcm handle
                int err, morehelp;
                snd_pcm_hw_params_t *hwparams;                
//parametros de hardware
                snd_pcm_sw_params_t *swparams;                
//parametros de software
                int method = 0;
                signed short *samples;
                unsigned int chn;
                snd_pcm_channel_area_t *areas;

                //snd_pcm_hw_params_alloca(&hwparams);
                //snd_pcm_sw_params_alloca(&swparams);
               
                morehelp = 0;
                while (1) {
                            int c;
                            if ((c = getopt_long(argc, argv, 
"hd:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0)
                                    break;
                            switch(c) {
                            case 'h':
                                        morehelp++;
                                        break;
                            case 'd':
                                        device = strdup(optarg);
                                        break;
                            case 'r':
                                        rate = atoi(optarg);
                                        rate = rate < 4000 ? 4000 : rate;
                                        rate = rate > 196000 ? 19600 : rate;
                                        break;
                         case 'c':
                              channels = atoi(optarg);
                              channels = channels < 1 ? 1 : channels;
                              channels = channels > 1024 ? 1024 : channels;
                              break;
                     case 'f':
                              freq = atoi(optarg);
                              freq = freq < 50 ? 50 : freq;
                              freq = freq > 5000 ? 5000 : freq;
                              break;
                     case 'b':
                              buffer_time = atoi(optarg);
                              buffer_time = buffer_time < 1000 ? 1000 : 
buffer_time;
                              buffer_time = buffer_time > 1000000 ? 
1000000 : buffer_time;
                              break;
                     case 'p':
                              period_time = atoi(optarg);
                              period_time = period_time < 1000 ? 1000 : 
period_time;
                              period_time = period_time > 1000000 ? 
1000000 : period_time;
                              break;
                     case 'm':
                              for (method = 0; 
transfer_methods[method].name; method++)
                                              if 
(!strcasecmp(transfer_methods[method].name, optarg))
                                              break;
                              if (transfer_methods[method].name == NULL)
                                      method = 0;
                              break;
                     case 'o':
                              for (format = 0; format < 
SND_PCM_FORMAT_LAST; format++) {
                                      const char *format_name = 
snd_pcm_format_name(format);
                                      if (format_name)
                                              if 
(!strcasecmp(format_name, optarg))
                                              break;
                              }
                              if (format == SND_PCM_FORMAT_LAST)
                                     format = SND_PCM_FORMAT_S16;
                              break;
                     case 'v':
                              verbose = 1;
                              break;
                     case 'n':
                              resample = 0;
                              break;
                      case 'e':
                              period_event = 1;
                              break;
                     }//switch
              }//while
             
              if(morehelp) {
                          help();
                          return 0;
              }

                //cria um novo output objeto
                err = snd_output_stdio_attach(&output, &stdout, 0);
                if (err < 0) {
                        printf("Output failed: %s\n", snd_strerror(err));
                        return 0;
                }
               
                printf("Playback device is %s\n", device);
                printf("Stream parameters are %iHz, %s, %i channels\n", 
rate, snd_pcm_format_name(format), channels);
                printf("sine wave rate is %i %.4fHz\n", freq);
                printf("Using transfer method: %s\n", 
transfer_methods[method].name);
               
                if ((err = snd_pcm_open(&handle, device, 
SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
                        printf("Playback open error: %s\n", 
snd_strerror(err));
                        return 0;
                }
               
                if ((err = set_hwparams(handle, hwparams, 
transfer_methods[method].access)) < 0) {
                  printf("Setting of hwparams failed: %s\n", 
snd_strerror(err));
                  exit(EXIT_FAILURE);
            }
            if ((err = set_swparams(handle, swparams)) < 0) {
                  printf("Setting of swparams failed: %s\n", 
snd_strerror(err));
                  exit(EXIT_FAILURE);
           }
 
            if (verbose > 0)
                  snd_pcm_dump(handle, output);
               
            samples = malloc((period_size * channels * 
snd_pcm_format_physical_width(format)) / 8);
            if (samples == NULL) {
                  printf("No enough memory\n");
                  exit(EXIT_FAILURE);
            }
         
            areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
            if (areas == NULL) {
                  printf("No enough memory\n");
                  exit(EXIT_FAILURE);
            }
            for (chn = 0; chn < channels; chn++) {
                  areas[chn].addr = samples;
                  areas[chn].first = chn * 
snd_pcm_format_physical_width(format);
                  areas[chn].step = channels * 
snd_pcm_format_physical_width(format);
             }
 
            err = transfer_methods[method].transfer_loop(handle, 
samples, areas);
            if (err < 0)
                  printf("Transfer failed: %s\n", snd_strerror(err));
 
            free(areas);
            free(samples);
            snd_pcm_close(handle);
            return 0;
}


Thanks in advance;



Tks!

-------------------

Guilherme Longo
Dept. Eng. da Computação
Unaerp

Linux User - #484927

*Before Asking
http://www.istf.com.br/?page=perguntas

!- I'd rather die on my feet than live on my knees -!



Ted T. Logan wrote:
> ALSA lib pcm_bluetooth.c:1607:(audioservice_expect) BT_OPEN failed : 
> Invalid argument(22)
>
> ** WARNING **: alsa_setup(): Unable to install hw params
>
> I get this all the time now.  What does this error mean?
>
>
>
> arecord -D bluetoothh550 -f S16_LE | aplay -D bluetoothh550 -f S16_LE
> Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono
> ALSA lib pcm_bluetooth.c:1607:(audioservice_expect) BT_OPEN failed : 
> Invalid argument(22)
> arecord: set_params:1041: Unable to install hw params:
> ACCESS:  RW_INTERLEAVED
> FORMAT:  S16_LE
> SUBFORMAT:  STD
> SAMPLE_BITS: 16
> FRAME_BITS: 16
> CHANNELS: 1
> RATE: 8000
> PERIOD_TIME: 125000
> PERIOD_SIZE: 1000
> PERIOD_BYTES: 2000
> PERIODS: 4
> BUFFER_TIME: 500000
> BUFFER_SIZE: 4000
> BUFFER_BYTES: 8000
> TICK_TIME: [0 0]
> aplay: playback:2297: read error
>
>
>
> and here with mplayer
>
>
> Playing skypering.wav.
> Audio only file format detected.
> ==========================================================================
> Opening audio decoder: [pcm] Uncompressed PCM audio decoder
> AUDIO: 16000 Hz, 2 ch, s16le, 512.0 kbit/100.00% (ratio: 64000->64000)
> Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
> ==========================================================================
> [AO_ALSA] alsa-lib: pcm_bluetooth.c:1607:(audioservice_expect) BT_OPEN 
> failed : Invalid argument(22)
> [AO_ALSA] Unable to set hw-parameters: Invalid argument
> Failed to initialize audio driver 'alsa:device=bluetoothh550'
> Could not open/initialize audio device -> no sound.
> Audio: no sound
> Video: no video
>
>
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
>   

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

* Re: [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380
  2009-06-15  2:06           ` Eric Miao
@ 2009-06-15 10:26             ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2009-06-15 10:26 UTC (permalink / raw)
  To: Eric Miao; +Cc: alsa-devel, Philipp Zabel

On Mon, Jun 15, 2009 at 10:06:21AM +0800, Eric Miao wrote:

> Normally, I'll queue such patch in my pending branch and will be pushed
> out until the other patch(es) with dependency has been merged upstream.

That's fine for me.

Philipp, if you want to avoid bisection issues I'd suggest making the
first patch shuffle the registration code into the ASoC machine driver
then have your PXA patch shuffle that into arch/arm.  I did something
similar for wm8731 when converting that.

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

* [PATCH] ASoC: UDA1380: refactor device registration
  2009-06-14 14:51       ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Mark Brown
  2009-06-14 20:52         ` pHilipp Zabel
@ 2009-06-15 20:18         ` Philipp Zabel
  2009-06-15 21:10           ` Mark Brown
  1 sibling, 1 reply; 14+ messages in thread
From: Philipp Zabel @ 2009-06-15 20:18 UTC (permalink / raw)
  To: alsa-devel; +Cc: Mark Brown, Philipp Zabel

This patch mostly follows commit 5998102b9095fdb7c67755812038612afea315c5
"ASoC: Refactor WM8731 device registration" to make UDA1380 use standard
device instantiation. Similarly, the I2C device registration temporarily
moves into the magician machine driver before it will find its final
resting place in the board file.

At the same time, platform specific configuration is moved to platform data
and common power/reset GPIO handling moves into the codec driver.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
---
 include/sound/uda1380.h    |   22 +++
 sound/soc/codecs/uda1380.c |  313 ++++++++++++++++++++++++--------------------
 sound/soc/codecs/uda1380.h |    8 -
 sound/soc/pxa/magician.c   |   54 ++++----
 4 files changed, 221 insertions(+), 176 deletions(-)
 create mode 100644 include/sound/uda1380.h

diff --git a/include/sound/uda1380.h b/include/sound/uda1380.h
new file mode 100644
index 0000000..381319c
--- /dev/null
+++ b/include/sound/uda1380.h
@@ -0,0 +1,22 @@
+/*
+ * UDA1380 ALSA SoC Codec driver
+ *
+ * Copyright 2009 Philipp Zabel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __UDA1380_H
+#define __UDA1380_H
+
+struct uda1380_platform_data {
+	int gpio_power;
+	int gpio_reset;
+	int dac_clk;
+#define UDA1380_DAC_CLK_SYSCLK 0
+#define UDA1380_DAC_CLK_WSPLL  1
+};
+
+#endif /* __UDA1380_H */
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 5b21594..92ec034 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -5,9 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
- * Improved support for DAPM and audio routing/mixing capabilities,
- * added TLV support.
+ * Copyright (c) 2007-2009 Philipp Zabel <philipp.zabel@gmail.com>
  *
  * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC
  * codec model.
@@ -19,26 +17,32 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
-#include <linux/ioctl.h>
+#include <linux/gpio.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/initval.h>
-#include <sound/info.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
+#include <sound/uda1380.h>
 
 #include "uda1380.h"
 
-static struct work_struct uda1380_work;
 static struct snd_soc_codec *uda1380_codec;
 
+/* codec private data */
+struct uda1380_priv {
+	struct snd_soc_codec codec;
+	u16 reg_cache[UDA1380_CACHEREGNUM];
+	unsigned int dac_clk;
+	struct work_struct work;
+};
+
 /*
  * uda1380 register cache
  */
@@ -473,6 +477,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
+	struct uda1380_priv *uda1380 = codec->private_data;
 	int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
 
 	switch (cmd) {
@@ -480,13 +485,13 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		uda1380_write_reg_cache(codec, UDA1380_MIXER,
 					mixer & ~R14_SILENCE);
-		schedule_work(&uda1380_work);
+		schedule_work(&uda1380->work);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		uda1380_write_reg_cache(codec, UDA1380_MIXER,
 					mixer | R14_SILENCE);
-		schedule_work(&uda1380_work);
+		schedule_work(&uda1380->work);
 		break;
 	}
 	return 0;
@@ -670,44 +675,33 @@ static int uda1380_resume(struct platform_device *pdev)
 	return 0;
 }
 
-/*
- * initialise the UDA1380 driver
- * register mixer and dsp interfaces with the kernel
- */
-static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
+static int uda1380_probe(struct platform_device *pdev)
 {
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	struct uda1380_platform_data *pdata;
 	int ret = 0;
 
-	codec->name = "UDA1380";
-	codec->owner = THIS_MODULE;
-	codec->read = uda1380_read_reg_cache;
-	codec->write = uda1380_write;
-	codec->set_bias_level = uda1380_set_bias_level;
-	codec->dai = uda1380_dai;
-	codec->num_dai = ARRAY_SIZE(uda1380_dai);
-	codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg),
-				   GFP_KERNEL);
-	if (codec->reg_cache == NULL)
-		return -ENOMEM;
-	codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
-	codec->reg_cache_step = 1;
-	uda1380_reset(codec);
+	if (uda1380_codec == NULL) {
+		dev_err(&pdev->dev, "Codec device not registered\n");
+		return -ENODEV;
+	}
 
-	uda1380_codec = codec;
-	INIT_WORK(&uda1380_work, uda1380_flush_work);
+	socdev->card->codec = uda1380_codec;
+	codec = uda1380_codec;
+	pdata = codec->dev->platform_data;
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
-		pr_err("uda1380: failed to create pcms\n");
+		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
 		goto pcm_err;
 	}
 
 	/* power on device */
 	uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	/* set clock input */
-	switch (dac_clk) {
+	switch (pdata->dac_clk) {
 	case UDA1380_DAC_CLK_SYSCLK:
 		uda1380_write(codec, UDA1380_CLK, 0);
 		break;
@@ -716,13 +710,12 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
 		break;
 	}
 
-	/* uda1380 init */
 	snd_soc_add_controls(codec, uda1380_snd_controls,
 				ARRAY_SIZE(uda1380_snd_controls));
 	uda1380_add_widgets(codec);
 	ret = snd_soc_init_card(socdev);
 	if (ret < 0) {
-		pr_err("uda1380: failed to register card\n");
+		dev_err(codec->dev, "failed to register card: %d\n", ret);
 		goto card_err;
 	}
 
@@ -732,165 +725,201 @@ card_err:
 	snd_soc_free_pcms(socdev);
 	snd_soc_dapm_free(socdev);
 pcm_err:
-	kfree(codec->reg_cache);
 	return ret;
 }
 
-static struct snd_soc_device *uda1380_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int uda1380_i2c_probe(struct i2c_client *i2c,
-			     const struct i2c_device_id *id)
+/* power down chip */
+static int uda1380_remove(struct platform_device *pdev)
 {
-	struct snd_soc_device *socdev = uda1380_socdev;
-	struct uda1380_setup_data *setup = socdev->codec_data;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->card->codec;
-	int ret;
-
-	i2c_set_clientdata(i2c, codec);
-	codec->control_data = i2c;
 
-	ret = uda1380_init(socdev, setup->dac_clk);
-	if (ret < 0)
-		pr_err("uda1380: failed to initialise UDA1380\n");
+	if (codec->control_data)
+		uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-	return ret;
-}
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
 
-static int uda1380_i2c_remove(struct i2c_client *client)
-{
-	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	kfree(codec->reg_cache);
 	return 0;
 }
 
-static const struct i2c_device_id uda1380_i2c_id[] = {
-	{ "uda1380", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
-
-static struct i2c_driver uda1380_i2c_driver = {
-	.driver = {
-		.name =  "UDA1380 I2C Codec",
-		.owner = THIS_MODULE,
-	},
-	.probe =    uda1380_i2c_probe,
-	.remove =   uda1380_i2c_remove,
-	.id_table = uda1380_i2c_id,
+struct snd_soc_codec_device soc_codec_dev_uda1380 = {
+	.probe = 	uda1380_probe,
+	.remove = 	uda1380_remove,
+	.suspend = 	uda1380_suspend,
+	.resume =	uda1380_resume,
 };
+EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
 
-static int uda1380_add_i2c_device(struct platform_device *pdev,
-				  const struct uda1380_setup_data *setup)
+static int uda1380_register(struct uda1380_priv *uda1380)
 {
-	struct i2c_board_info info;
-	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	int ret;
+	int ret, i;
+	struct snd_soc_codec *codec = &uda1380->codec;
+	struct uda1380_platform_data *pdata = codec->dev->platform_data;
 
-	ret = i2c_add_driver(&uda1380_i2c_driver);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "can't add i2c driver\n");
-		return ret;
+	if (uda1380_codec) {
+		dev_err(codec->dev, "Another UDA1380 is registered\n");
+		return -EINVAL;
+	}
+
+	if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
+		return -EINVAL;
+
+	ret = gpio_request(pdata->gpio_power, "uda1380 power");
+	if (ret)
+		goto err_out;
+	ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+	if (ret)
+		goto err_gpio;
+
+	gpio_direction_output(pdata->gpio_power, 1);
+
+	/* we may need to have the clock running here - pH5 */
+	gpio_direction_output(pdata->gpio_reset, 1);
+	udelay(5);
+	gpio_set_value(pdata->gpio_reset, 0);
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->private_data = uda1380;
+	codec->name = "UDA1380";
+	codec->owner = THIS_MODULE;
+	codec->read = uda1380_read_reg_cache;
+	codec->write = uda1380_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = uda1380_set_bias_level;
+	codec->dai = uda1380_dai;
+	codec->num_dai = ARRAY_SIZE(uda1380_dai);
+	codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
+	codec->reg_cache = &uda1380->reg_cache;
+	codec->reg_cache_step = 1;
+
+	memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
+
+	ret = uda1380_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset\n");
+		goto err_reset;
 	}
 
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = setup->i2c_address;
-	strlcpy(info.type, "uda1380", I2C_NAME_SIZE);
+	INIT_WORK(&uda1380->work, uda1380_flush_work);
+
+	for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
+		uda1380_dai[i].dev = codec->dev;
 
-	adapter = i2c_get_adapter(setup->i2c_bus);
-	if (!adapter) {
-		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-			setup->i2c_bus);
-		goto err_driver;
+	uda1380_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		goto err_reset;
 	}
 
-	client = i2c_new_device(adapter, &info);
-	i2c_put_adapter(adapter);
-	if (!client) {
-		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-			(unsigned int)info.addr);
-		goto err_driver;
+	ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
+		goto err_dai;
 	}
 
 	return 0;
 
-err_driver:
-	i2c_del_driver(&uda1380_i2c_driver);
-	return -ENODEV;
+err_dai:
+	snd_soc_unregister_codec(codec);
+err_reset:
+	gpio_set_value(pdata->gpio_power, 0);
+	gpio_free(pdata->gpio_reset);
+err_gpio:
+	gpio_free(pdata->gpio_power);
+err_out:
+	return ret;
 }
-#endif
 
-static int uda1380_probe(struct platform_device *pdev)
+static void uda1380_unregister(struct uda1380_priv *uda1380)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct uda1380_setup_data *setup;
+	struct snd_soc_codec *codec = &uda1380->codec;
+	struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+	snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+	snd_soc_unregister_codec(&uda1380->codec);
+
+	gpio_set_value(pdata->gpio_power, 0);
+	gpio_free(pdata->gpio_reset);
+	gpio_free(pdata->gpio_power);
+
+	kfree(uda1380);
+	uda1380_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct uda1380_priv *uda1380;
 	struct snd_soc_codec *codec;
 	int ret;
 
-	setup = socdev->codec_data;
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
+	uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
+	if (uda1380 == NULL)
 		return -ENOMEM;
 
-	socdev->card->codec = codec;
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
+	codec = &uda1380->codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
 
-	uda1380_socdev = socdev;
-	ret = -ENODEV;
+	i2c_set_clientdata(i2c, uda1380);
+	codec->control_data = i2c;
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = uda1380_add_i2c_device(pdev, setup);
-	}
-#endif
+	codec->dev = &i2c->dev;
 
+	ret = uda1380_register(uda1380);
 	if (ret != 0)
-		kfree(codec);
+		kfree(uda1380);
+
 	return ret;
 }
 
-/* power down chip */
-static int uda1380_remove(struct platform_device *pdev)
+static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	if (codec->control_data)
-		uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	i2c_unregister_device(codec->control_data);
-	i2c_del_driver(&uda1380_i2c_driver);
-#endif
-	kfree(codec);
-
+	struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
+	uda1380_unregister(uda1380);
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_uda1380 = {
-	.probe = 	uda1380_probe,
-	.remove = 	uda1380_remove,
-	.suspend = 	uda1380_suspend,
-	.resume =	uda1380_resume,
+static const struct i2c_device_id uda1380_i2c_id[] = {
+	{ "uda1380", 0 },
+	{ }
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
+MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
+
+static struct i2c_driver uda1380_i2c_driver = {
+	.driver = {
+		.name =  "UDA1380 I2C Codec",
+		.owner = THIS_MODULE,
+	},
+	.probe =    uda1380_i2c_probe,
+	.remove =   __devexit_p(uda1380_i2c_remove),
+	.id_table = uda1380_i2c_id,
+};
+#endif
 
 static int __init uda1380_modinit(void)
 {
-	return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+	int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	ret = i2c_add_driver(&uda1380_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
+#endif
+	return 0;
 }
 module_init(uda1380_modinit);
 
 static void __exit uda1380_exit(void)
 {
-	snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	i2c_del_driver(&uda1380_i2c_driver);
+#endif
 }
 module_exit(uda1380_exit);
 
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
index c55c17a..9cefa8a 100644
--- a/sound/soc/codecs/uda1380.h
+++ b/sound/soc/codecs/uda1380.h
@@ -72,14 +72,6 @@
 #define R22_SKIP_DCFIL	0x0002
 #define R23_AGC_EN	0x0001
 
-struct uda1380_setup_data {
-	int            i2c_bus;
-	unsigned short i2c_address;
-	int            dac_clk;
-#define UDA1380_DAC_CLK_SYSCLK 0
-#define UDA1380_DAC_CLK_WSPLL  1
-};
-
 #define UDA1380_DAI_DUPLEX	0 /* playback and capture on single DAI */
 #define UDA1380_DAI_PLAYBACK	1 /* playback DAI */
 #define UDA1380_DAI_CAPTURE	2 /* capture DAI */
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index c89a3cd..9fe4ad2 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -20,12 +20,14 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/i2c.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/uda1380.h>
 
 #include <mach/magician.h>
 #include <asm/mach-types.h>
@@ -447,34 +449,47 @@ static struct snd_soc_card snd_soc_card_magician = {
 	.platform = &pxa2xx_soc_platform,
 };
 
-/* magician audio private data */
-static struct uda1380_setup_data magician_uda1380_setup = {
-	.i2c_address = 0x18,
-	.dac_clk = UDA1380_DAC_CLK_WSPLL,
-};
-
 /* magician audio subsystem */
 static struct snd_soc_device magician_snd_devdata = {
 	.card = &snd_soc_card_magician,
 	.codec_dev = &soc_codec_dev_uda1380,
-	.codec_data = &magician_uda1380_setup,
 };
 
 static struct platform_device *magician_snd_device;
 
+/*
+ * FIXME: move into magician board file once merged into the pxa tree
+ */
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
+	.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
+	.dac_clk    = UDA1380_DAC_CLK_WSPLL,
+};
+
+static struct i2c_board_info i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x18),
+		.platform_data = &uda1380_info,
+	},
+};
+
 static int __init magician_init(void)
 {
 	int ret;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
 
 	if (!machine_is_magician())
 		return -ENODEV;
 
-	ret = gpio_request(EGPIO_MAGICIAN_CODEC_POWER, "CODEC_POWER");
-	if (ret)
-		goto err_request_power;
-	ret = gpio_request(EGPIO_MAGICIAN_CODEC_RESET, "CODEC_RESET");
-	if (ret)
-		goto err_request_reset;
+	adapter = i2c_get_adapter(0);
+	if (!adapter)
+		return -ENODEV;
+	client = i2c_new_device(adapter, i2c_board_info);
+	i2c_put_adapter(adapter);
+	if (!client)
+		return -ENODEV;
+
 	ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
 	if (ret)
 		goto err_request_spk;
@@ -491,14 +506,8 @@ static int __init magician_init(void)
 	if (ret)
 		goto err_request_in_sel1;
 
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 1);
 	gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
 
-	/* we may need to have the clock running here - pH5 */
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 1);
-	udelay(5);
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 0);
-
 	magician_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!magician_snd_device) {
 		ret = -ENOMEM;
@@ -526,10 +535,6 @@ err_request_mic:
 err_request_ep:
 	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
 err_request_spk:
-	gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
-err_request_reset:
-	gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
-err_request_power:
 	return ret;
 }
 
@@ -540,15 +545,12 @@ static void __exit magician_exit(void)
 	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
 	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
 	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
-	gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 0);
 
 	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
 	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
 	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
 	gpio_free(EGPIO_MAGICIAN_EP_POWER);
 	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
-	gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
-	gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
 }
 
 module_init(magician_init);
-- 
1.6.3.1

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

* Re: [PATCH] ASoC: UDA1380: refactor device registration
  2009-06-15 20:18         ` [PATCH] ASoC: UDA1380: refactor device registration Philipp Zabel
@ 2009-06-15 21:10           ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2009-06-15 21:10 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: alsa-devel

On Mon, Jun 15, 2009 at 10:18:23PM +0200, Philipp Zabel wrote:
> This patch mostly follows commit 5998102b9095fdb7c67755812038612afea315c5
> "ASoC: Refactor WM8731 device registration" to make UDA1380 use standard
> device instantiation. Similarly, the I2C device registration temporarily
> moves into the magician machine driver before it will find its final
> resting place in the board file.
> 
> At the same time, platform specific configuration is moved to platform data
> and common power/reset GPIO handling moves into the codec driver.

> Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>

Great stuff, applied thanks.

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

end of thread, other threads:[~2009-06-15 21:10 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-14 10:51 [PATCH, RFC 0/3] magician fix and UDA1380 i2c device registration change Philipp Zabel
     [not found] ` <1244976692-5189-2-git-send-email-philipp.zabel@gmail.com>
2009-06-14 10:51   ` [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity Philipp Zabel
2009-06-14 10:51     ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Philipp Zabel
2009-06-14 10:51       ` [PATCH, RFC 3/3] pxa/magician: add I2C board info and platform data for UDA1380 Philipp Zabel
2009-06-14 15:00         ` Mark Brown
2009-06-15  2:06           ` Eric Miao
2009-06-15 10:26             ` Mark Brown
2009-06-14 14:51       ` [PATCH, RFC 2/3] ASoC: UDA1380: register from board files, configure via pdata Mark Brown
2009-06-14 20:52         ` pHilipp Zabel
2009-06-15  4:56           ` Can't use bluetooth headset after upgrade of alsa/bluez with fedora 11 Ted T. Logan
2009-06-15  5:38             ` busy device issue when it is not busy! Guilherme
2009-06-15 20:18         ` [PATCH] ASoC: UDA1380: refactor device registration Philipp Zabel
2009-06-15 21:10           ` Mark Brown
2009-06-14 14:23     ` [PATCH 1/3] ASoC: magician: fix PXA SSP clock polarity Mark Brown

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.