Browse Source

Merge remote-tracking branches 'asoc/topic/headers', 'asoc/topic/intel', 'asoc/topic/jz4740', 'asoc/topic/max98090', 'asoc/topic/max98095', 'asoc/topic/mc13783' and 'asoc/topic/multicodec' into asoc-next

Mark Brown 11 years ago

+ 3 - 0
Documentation/devicetree/bindings/mfd/mc13xxx.txt

@@ -10,6 +10,9 @@ Optional properties:
 - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
 
 Sub-nodes:
+- codec: Contain the Audio Codec node.
+  - adc-port: Contain PMIC SSI port number used for ADC.
+  - dac-port: Contain PMIC SSI port number used for DAC.
 - leds : Contain the led nodes and initial register values in property
   "led-control". Number of register depends of used IC, for MC13783 is 6,
   for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of

+ 16 - 0
Documentation/devicetree/bindings/sound/max98095.txt

@@ -0,0 +1,16 @@
+MAX98095 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "maxim,max98095".
+
+- reg : The I2C address of the device.
+
+Example:
+
+max98095: codec@11 {
+	compatible = "maxim,max98095";
+	reg = <0x11>;
+};

+ 0 - 2
arch/mips/include/asm/mach-jz4740/dma.h

@@ -22,8 +22,6 @@ enum jz4740_dma_request_type {
 	JZ4740_DMA_TYPE_UART_RECEIVE	= 21,
 	JZ4740_DMA_TYPE_SPI_TRANSMIT	= 22,
 	JZ4740_DMA_TYPE_SPI_RECEIVE	= 23,
-	JZ4740_DMA_TYPE_AIC_TRANSMIT	= 24,
-	JZ4740_DMA_TYPE_AIC_RECEIVE	= 25,
 	JZ4740_DMA_TYPE_MMC_TRANSMIT	= 26,
 	JZ4740_DMA_TYPE_MMC_RECEIVE	= 27,
 	JZ4740_DMA_TYPE_TCU		= 28,

+ 11 - 0
arch/mips/jz4740/board-qi_lb60.c

@@ -425,6 +425,15 @@ static struct platform_device qi_lb60_audio_device = {
 	.id = -1,
 };
 
+static struct gpiod_lookup_table qi_lb60_audio_gpio_table = {
+	.dev_id = "qi-lb60-audio",
+	.table = {
+		GPIO_LOOKUP("Bank B", 29, "snd", 0),
+		GPIO_LOOKUP("Bank D", 4, "amp", 0),
+		{ },
+	},
+};
+
 static struct platform_device *jz_platform_devices[] __initdata = {
 	&jz4740_udc_device,
 	&jz4740_udc_xceiv_device,
@@ -461,6 +470,8 @@ static int __init qi_lb60_init_platform_devices(void)
 	jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
 	jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
 
+	gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
+
 	jz4740_serial_device_register();
 
 	spi_register_board_info(qi_lb60_spi_board_info,

+ 7 - 3
drivers/mfd/mc13xxx-core.c

@@ -673,9 +673,13 @@ int mc13xxx_common_init(struct device *dev)
 	if (mc13xxx->flags & MC13XXX_USE_ADC)
 		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
 
-	if (mc13xxx->flags & MC13XXX_USE_CODEC)
-		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
-					pdata->codec, sizeof(*pdata->codec));
+	if (mc13xxx->flags & MC13XXX_USE_CODEC) {
+		if (pdata)
+			mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+				pdata->codec, sizeof(*pdata->codec));
+		else
+			mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+	}
 
 	if (mc13xxx->flags & MC13XXX_USE_RTC)
 		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");

+ 1 - 0
sound/soc/codecs/hdmi.c

@@ -20,6 +20,7 @@
  */
 #include <linux/module.h>
 #include <sound/soc.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
 
 #define DRV_NAME "hdmi-audio-codec"

+ 35 - 12
sound/soc/codecs/max98090.c

@@ -11,10 +11,12 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/acpi.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -1674,6 +1676,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 				M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
 			snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
 				M98090_USE_M1_MASK, 0);
+			max98090->master = false;
 			break;
 		case SND_SOC_DAIFMT_CBM_CFM:
 			/* Set to master mode */
@@ -1690,6 +1693,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
 				regval |= M98090_MAS_MASK |
 					M98090_BSEL_32;
 			}
+			max98090->master = true;
 			break;
 		case SND_SOC_DAIFMT_CBS_CFM:
 		case SND_SOC_DAIFMT_CBM_CFS:
@@ -1793,13 +1797,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
-			/*
-			 * Set to normal bias level.
-			 */
-			snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
-				M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
-		}
 		break;
 
 	case SND_SOC_BIAS_PREPARE:
@@ -1873,7 +1870,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 	}
 
-	max98090_configure_bclk(codec);
+	if (max98090->master)
+		max98090_configure_bclk(codec);
 
 	cdata->rate = max98090->lrclk;
 
@@ -1952,8 +1950,6 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
 
 	max98090->sysclk = freq;
 
-	max98090_configure_bclk(codec);
-
 	return 0;
 }
 
@@ -2225,6 +2221,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	/* Initialize private data */
 
 	max98090->sysclk = (unsigned)-1;
+	max98090->master = false;
 
 	cdata = &max98090->dai[0];
 	cdata->rate = (unsigned)-1;
@@ -2294,6 +2291,9 @@ static int max98090_probe(struct snd_soc_codec *codec)
 	snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
 		M98090_VCM_MODE_MASK);
 
+	snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
+		M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
+
 	max98090_handle_pdata(codec);
 
 	max98090_add_widgets(codec);
@@ -2330,9 +2330,11 @@ static const struct regmap_config max98090_regmap = {
 };
 
 static int max98090_i2c_probe(struct i2c_client *i2c,
-				 const struct i2c_device_id *id)
+				 const struct i2c_device_id *i2c_id)
 {
 	struct max98090_priv *max98090;
+	const struct acpi_device_id *acpi_id;
+	kernel_ulong_t driver_data = 0;
 	int ret;
 
 	pr_debug("max98090_i2c_probe\n");
@@ -2342,7 +2344,19 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
 	if (max98090 == NULL)
 		return -ENOMEM;
 
-	max98090->devtype = id->driver_data;
+	if (ACPI_HANDLE(&i2c->dev)) {
+		acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
+					    &i2c->dev);
+		if (!acpi_id) {
+			dev_err(&i2c->dev, "No driver data\n");
+			return -EINVAL;
+		}
+		driver_data = acpi_id->driver_data;
+	} else if (i2c_id) {
+		driver_data = i2c_id->driver_data;
+	}
+
+	max98090->devtype = driver_data;
 	i2c_set_clientdata(i2c, max98090);
 	max98090->pdata = i2c->dev.platform_data;
 	max98090->irq = i2c->irq;
@@ -2433,12 +2447,21 @@ static const struct of_device_id max98090_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, max98090_of_match);
 
+#ifdef CONFIG_ACPI
+static struct acpi_device_id max98090_acpi_match[] = {
+	{ "193C9890", MAX98090 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
+#endif
+
 static struct i2c_driver max98090_i2c_driver = {
 	.driver = {
 		.name = "max98090",
 		.owner = THIS_MODULE,
 		.pm = &max98090_pm,
 		.of_match_table = of_match_ptr(max98090_of_match),
+		.acpi_match_table = ACPI_PTR(max98090_acpi_match),
 	},
 	.probe  = max98090_i2c_probe,
 	.remove = max98090_i2c_remove,

+ 1 - 0
sound/soc/codecs/max98090.h

@@ -1540,6 +1540,7 @@ struct max98090_priv {
 	unsigned int pa2en;
 	unsigned int extmic_mux;
 	unsigned int sidetone;
+	bool master;
 };
 
 int max98090_mic_detect(struct snd_soc_codec *codec,

+ 7 - 0
sound/soc/codecs/max98095.c

@@ -2399,10 +2399,17 @@ static const struct i2c_device_id max98095_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
 
+static const struct of_device_id max98095_of_match[] = {
+	{ .compatible = "maxim,max98095", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98095_of_match);
+
 static struct i2c_driver max98095_i2c_driver = {
 	.driver = {
 		.name = "max98095",
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(max98095_of_match),
 	},
 	.probe  = max98095_i2c_probe,
 	.remove = max98095_i2c_remove,

+ 13 - 1
sound/soc/codecs/mc13783.c

@@ -22,6 +22,7 @@
  */
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mfd/mc13xxx.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -748,6 +749,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
 {
 	struct mc13783_priv *priv;
 	struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node *np;
 	int ret;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -758,7 +760,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
 		priv->adc_ssi_port = pdata->adc_ssi_port;
 		priv->dac_ssi_port = pdata->dac_ssi_port;
 	} else {
-		return -ENOSYS;
+		np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
+		if (!np)
+			return -ENOSYS;
+
+		ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
+		if (ret)
+			return ret;
+
+		ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
+		if (ret)
+			return ret;
 	}
 
 	dev_set_drvdata(&pdev->dev, priv);

+ 1 - 0
sound/soc/codecs/rt5640.c

@@ -18,6 +18,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>

+ 1 - 0
sound/soc/codecs/tlv320aic23-i2c.c

@@ -13,6 +13,7 @@
 
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 

+ 1 - 0
sound/soc/codecs/tlv320aic31xx.c

@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>

+ 1 - 0
sound/soc/codecs/tpa6130a2.c

@@ -30,6 +30,7 @@
 #include <sound/tpa6130a2-plat.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
+#include <linux/of.h>
 #include <linux/of_gpio.h>
 
 #include "tpa6130a2.h"

+ 1 - 1
sound/soc/intel/Makefile

@@ -2,7 +2,7 @@
 snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
 snd-soc-sst-acpi-objs := sst-acpi.o
 
-snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o
 snd-soc-mfld-machine-objs := mfld_machine.o
 
 obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o

+ 13 - 15
sound/soc/intel/byt-rt5640.c

@@ -111,27 +111,13 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
 	{
 		.name = "Baytrail Audio",
 		.stream_name = "Audio",
-		.cpu_dai_name = "Front-cpu-dai",
+		.cpu_dai_name = "baytrail-pcm-audio",
 		.codec_dai_name = "rt5640-aif1",
 		.codec_name = "i2c-10EC5640:00",
 		.platform_name = "baytrail-pcm-audio",
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 			   SND_SOC_DAIFMT_CBS_CFS,
 		.init = byt_rt5640_init,
-		.ignore_suspend = 1,
-		.ops = &byt_rt5640_ops,
-	},
-	{
-		.name = "Baytrail Voice",
-		.stream_name = "Voice",
-		.cpu_dai_name = "Mic1-cpu-dai",
-		.codec_dai_name = "rt5640-aif1",
-		.codec_name = "i2c-10EC5640:00",
-		.platform_name = "baytrail-pcm-audio",
-		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-			   SND_SOC_DAIFMT_CBS_CFS,
-		.init = NULL,
-		.ignore_suspend = 1,
 		.ops = &byt_rt5640_ops,
 	},
 };
@@ -146,6 +132,17 @@ static struct snd_soc_card byt_rt5640_card = {
 	.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
 };
 
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops byt_rt5640_pm_ops = {
+	.suspend = snd_soc_suspend,
+	.resume = snd_soc_resume,
+};
+
+#define BYT_RT5640_PM_OPS	(&byt_rt5640_pm_ops)
+#else
+#define BYT_RT5640_PM_OPS	NULL
+#endif
+
 static int byt_rt5640_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = &byt_rt5640_card;
@@ -171,6 +168,7 @@ static struct platform_driver byt_rt5640_audio = {
 	.driver = {
 		.name = "byt-rt5640",
 		.owner = THIS_MODULE,
+		.pm = BYT_RT5640_PM_OPS,
 	},
 };
 module_platform_driver(byt_rt5640_audio)

+ 7 - 7
sound/soc/intel/sst-baytrail-dsp.c

@@ -214,6 +214,13 @@ static void sst_byt_boot(struct sst_dsp *sst)
 {
 	int tries = 10;
 
+	/*
+	 * save the physical address of extended firmware block in the first
+	 * 4 bytes of the mailbox
+	 */
+	memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
+	       &sst->pdata->fw_base, sizeof(u32));
+
 	/* release stall and wait to unstall */
 	sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
 	while (tries--) {
@@ -317,13 +324,6 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
 		return ret;
 	}
 
-	/*
-	 * save the physical address of extended firmware block in the first
-	 * 4 bytes of the mailbox
-	 */
-	memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
-	       &pdata->fw_base, sizeof(u32));
-
 	ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
 	if (ret)
 		return ret;

+ 104 - 20
sound/soc/intel/sst-baytrail-ipc.c

@@ -173,6 +173,7 @@ struct sst_byt {
 	/* boot */
 	wait_queue_head_t boot_wait;
 	bool boot_complete;
+	struct sst_fw *fw;
 
 	/* IPC messaging */
 	struct list_head tx_list;
@@ -299,6 +300,24 @@ static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
 		wake_up(&msg->waitq);
 }
 
+static void sst_byt_drop_all(struct sst_byt *byt)
+{
+	struct ipc_message *msg, *tmp;
+	unsigned long flags;
+
+	/* drop all TX and Rx messages before we stall + reset DSP */
+	spin_lock_irqsave(&byt->dsp->spinlock, flags);
+	list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) {
+		list_move(&msg->list, &byt->empty_list);
+	}
+
+	list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) {
+		list_move(&msg->list, &byt->empty_list);
+	}
+
+	spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+}
+
 static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
 				void *rx_data)
 {
@@ -661,36 +680,33 @@ out:
 static int sst_byt_stream_operations(struct sst_byt *byt, int type,
 				     int stream_id, int wait)
 {
-	struct sst_byt_start_stream_params start_stream;
 	u64 header;
-	void *tx_msg = NULL;
-	size_t size = 0;
-
-	if (type != IPC_IA_START_STREAM) {
-		header = sst_byt_header(type, 0, false, stream_id);
-	} else {
-		start_stream.byte_offset = 0;
-		header = sst_byt_header(IPC_IA_START_STREAM,
-					sizeof(start_stream) + sizeof(u32),
-					true, stream_id);
-		tx_msg = &start_stream;
-		size = sizeof(start_stream);
-	}
 
+	header = sst_byt_header(type, 0, false, stream_id);
 	if (wait)
-		return sst_byt_ipc_tx_msg_wait(byt, header,
-					       tx_msg, size, NULL, 0);
+		return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
 	else
-		return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
+		return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0);
 }
 
 /* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream)
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+			 u32 start_offset)
 {
+	struct sst_byt_start_stream_params start_stream;
+	void *tx_msg;
+	size_t size;
+	u64 header;
 	int ret;
 
-	ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM,
-					stream->str_id, 0);
+	start_stream.byte_offset = start_offset;
+	header = sst_byt_header(IPC_IA_START_STREAM,
+				sizeof(start_stream) + sizeof(u32),
+				true, stream->str_id);
+	tx_msg = &start_stream;
+	size = sizeof(start_stream);
+
+	ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
 	if (ret < 0)
 		dev_err(byt->dev, "ipc: error failed to start stream %d\n",
 			stream->str_id);
@@ -782,6 +798,73 @@ static struct sst_dsp_device byt_dev = {
 	.ops = &sst_byt_ops,
 };
 
+int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
+{
+	struct sst_byt *byt = pdata->dsp;
+
+	dev_dbg(byt->dev, "dsp reset\n");
+	sst_dsp_reset(byt->dsp);
+	sst_byt_drop_all(byt);
+	dev_dbg(byt->dev, "dsp in reset\n");
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
+
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
+{
+	struct sst_byt *byt = pdata->dsp;
+
+	dev_dbg(byt->dev, "free all blocks and unload fw\n");
+	sst_fw_unload(byt->fw);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
+
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
+{
+	struct sst_byt *byt = pdata->dsp;
+	int ret;
+
+	dev_dbg(byt->dev, "reload dsp fw\n");
+
+	sst_dsp_reset(byt->dsp);
+
+	ret = sst_fw_reload(byt->fw);
+	if (ret <  0) {
+		dev_err(dev, "error: failed to reload firmware\n");
+		return ret;
+	}
+
+	/* wait for DSP boot completion */
+	byt->boot_complete = false;
+	sst_dsp_boot(byt->dsp);
+	dev_dbg(byt->dev, "dsp booting...\n");
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
+
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
+{
+	struct sst_byt *byt = pdata->dsp;
+	int err;
+
+	dev_dbg(byt->dev, "wait for dsp reboot\n");
+
+	err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+				 msecs_to_jiffies(IPC_BOOT_MSECS));
+	if (err == 0) {
+		dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+		return -EIO;
+	}
+
+	dev_dbg(byt->dev, "dsp rebooted\n");
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
+
 int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
 {
 	struct sst_byt *byt;
@@ -848,6 +931,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
 	}
 
 	pdata->dsp = byt;
+	byt->fw = byt_sst_fw;
 
 	return 0;
 

+ 6 - 1
sound/soc/intel/sst-baytrail-ipc.h

@@ -53,7 +53,8 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
 int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
 
 /* stream ALSA trigger operations */
-int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
+			 u32 start_offset);
 int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
 int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
 int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
@@ -65,5 +66,9 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
 int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
 void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
 struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
+int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
+int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
 
 #endif

+ 132 - 30
sound/soc/intel/sst-baytrail-pcm.c

@@ -45,6 +45,11 @@ struct sst_byt_pcm_data {
 	struct sst_byt_stream *stream;
 	struct snd_pcm_substream *substream;
 	struct mutex mutex;
+
+	/* latest DSP DMA hw pointer */
+	u32 hw_ptr;
+
+	struct work_struct work;
 };
 
 /* private data for the driver */
@@ -63,7 +68,7 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct sst_byt_priv_data *pdata =
 		snd_soc_platform_get_drvdata(rtd->platform);
-	struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 	u32 rate, bits;
 	u8 channels;
@@ -130,21 +135,56 @@ static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
+static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sst_byt_priv_data *pdata =
+		snd_soc_platform_get_drvdata(rtd->platform);
+	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
+	struct sst_byt *byt = pdata->byt;
+	int ret;
+
+	/* commit stream using existing stream params */
+	ret = sst_byt_stream_commit(byt, pcm_data->stream);
+	if (ret < 0) {
+		dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+		return ret;
+	}
+
+	sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
+
+	dev_dbg(rtd->dev, "stream context restored at offset %d\n",
+		pcm_data->hw_ptr);
+
+	return 0;
+}
+
+static void sst_byt_pcm_work(struct work_struct *work)
+{
+	struct sst_byt_pcm_data *pcm_data =
+		container_of(work, struct sst_byt_pcm_data, work);
+
+	if (snd_pcm_running(pcm_data->substream))
+		sst_byt_pcm_restore_stream_context(pcm_data->substream);
+}
+
 static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct sst_byt_priv_data *pdata =
 		snd_soc_platform_get_drvdata(rtd->platform);
-	struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 
 	dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		sst_byt_stream_start(byt, pcm_data->stream);
+		sst_byt_stream_start(byt, pcm_data->stream, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_RESUME:
+		schedule_work(&pcm_data->work);
+		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		sst_byt_stream_resume(byt, pcm_data->stream);
 		break;
@@ -168,13 +208,19 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
 	struct snd_pcm_substream *substream = pcm_data->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	u32 pos;
+	struct sst_byt_priv_data *pdata =
+		snd_soc_platform_get_drvdata(rtd->platform);
+	struct sst_byt *byt = pdata->byt;
+	u32 pos, hw_pos;
 
+	hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
+					  snd_pcm_lib_buffer_bytes(substream));
+	pcm_data->hw_ptr = hw_pos;
 	pos = frames_to_bytes(runtime,
 			      (runtime->control->appl_ptr %
 			       runtime->buffer_size));
 
-	dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+	dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
 
 	snd_pcm_period_elapsed(substream);
 	return pos;
@@ -186,18 +232,11 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct sst_byt_priv_data *pdata =
 		snd_soc_platform_get_drvdata(rtd->platform);
-	struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
-	struct sst_byt *byt = pdata->byt;
-	snd_pcm_uframes_t offset;
-	int pos;
+	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 
-	pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
-				       snd_pcm_lib_buffer_bytes(substream));
-	offset = bytes_to_frames(runtime, pos);
+	dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
 
-	dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
-		frames_to_bytes(runtime, (u32)offset));
-	return offset;
+	return bytes_to_frames(runtime, pcm_data->hw_ptr);
 }
 
 static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
@@ -205,20 +244,18 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct sst_byt_priv_data *pdata =
 		snd_soc_platform_get_drvdata(rtd->platform);
-	struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 
 	dev_dbg(rtd->dev, "PCM: open\n");
 
-	pcm_data = &pdata->pcm[rtd->cpu_dai->id];
 	mutex_lock(&pcm_data->mutex);
 
-	snd_soc_pcm_set_drvdata(rtd, pcm_data);
 	pcm_data->substream = substream;
 
 	snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
 
-	pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
+	pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
 					      byt_notify_pointer, pcm_data);
 	if (pcm_data->stream == NULL) {
 		dev_err(rtd->dev, "failed to create stream\n");
@@ -235,12 +272,13 @@ static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct sst_byt_priv_data *pdata =
 		snd_soc_platform_get_drvdata(rtd->platform);
-	struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+	struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
 	struct sst_byt *byt = pdata->byt;
 	int ret;
 
 	dev_dbg(rtd->dev, "PCM: close\n");
 
+	cancel_work_sync(&pcm_data->work);
 	mutex_lock(&pcm_data->mutex);
 	ret = sst_byt_stream_free(byt, pcm_data->stream);
 	if (ret < 0) {
@@ -283,18 +321,16 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_pcm *pcm = rtd->pcm;
 	size_t size;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct sst_pdata *pdata = dev_get_platdata(platform->dev);
 	int ret = 0;
 
-	ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
 	    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
 		size = sst_byt_pcm_hardware.buffer_bytes_max;
 		ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
 							    SNDRV_DMA_TYPE_DEV,
-							    rtd->card->dev,
+							    pdata->dma_dev,
 							    size, size);
 		if (ret) {
 			dev_err(rtd->dev, "dma buffer allocation failed %d\n",
@@ -308,7 +344,7 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
 
 static struct snd_soc_dai_driver byt_dais[] = {
 	{
-		.name  = "Front-cpu-dai",
+		.name  = "Baytrail PCM",
 		.playback = {
 			.stream_name = "System Playback",
 			.channels_min = 2,
@@ -317,9 +353,6 @@ static struct snd_soc_dai_driver byt_dais[] = {
 			.formats = SNDRV_PCM_FMTBIT_S24_3LE |
 				   SNDRV_PCM_FMTBIT_S16_LE,
 		},
-	},
-	{
-		.name  = "Mic1-cpu-dai",
 		.capture = {
 			.stream_name = "Analog Capture",
 			.channels_min = 2,
@@ -344,8 +377,10 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
 	priv_data->byt = plat_data->dsp;
 	snd_soc_platform_set_drvdata(platform, priv_data);
 
-	for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
+	for (i = 0; i < BYT_PCM_COUNT; i++) {
 		mutex_init(&priv_data->pcm[i].mutex);
+		INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
+	}
 
 	return 0;
 }
@@ -367,6 +402,72 @@ static const struct snd_soc_component_driver byt_dai_component = {
 	.name		= "byt-dai",
 };
 
+#ifdef CONFIG_PM
+static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
+{
+	struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+	int ret;
+
+	dev_dbg(dev, "suspending noirq\n");
+
+	/* at this point all streams will be stopped and context saved */
+	ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
+	if (ret < 0) {
+		dev_err(dev, "failed to suspend %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int sst_byt_pcm_dev_suspend_late(struct device *dev)
+{
+	struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+	int ret;
+
+	dev_dbg(dev, "suspending late\n");
+
+	ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
+	if (ret < 0) {
+		dev_err(dev, "failed to suspend %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int sst_byt_pcm_dev_resume_early(struct device *dev)
+{
+	struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+
+	dev_dbg(dev, "resume early\n");
+
+	/* load fw and boot DSP */
+	return sst_byt_dsp_boot(dev, sst_pdata);
+}
+
+static int sst_byt_pcm_dev_resume(struct device *dev)
+{
+	struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+
+	dev_dbg(dev, "resume\n");
+
+	/* wait for FW to finish booting */
+	return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
+}
+
+static const struct dev_pm_ops sst_byt_pm_ops = {
+	.suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
+	.suspend_late = sst_byt_pcm_dev_suspend_late,
+	.resume_early = sst_byt_pcm_dev_resume_early,
+	.resume = sst_byt_pcm_dev_resume,
+};
+
+#define SST_BYT_PM_OPS	(&sst_byt_pm_ops)
+#else
+#define SST_BYT_PM_OPS	NULL
+#endif
+
 static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
@@ -409,6 +510,7 @@ static struct platform_driver sst_byt_pcm_driver = {
 	.driver = {
 		.name = "baytrail-pcm-audio",
 		.owner = THIS_MODULE,
+		.pm = SST_BYT_PM_OPS,
 	},
 
 	.probe = sst_byt_pcm_dev_probe,

+ 2 - 0
sound/soc/intel/sst-dsp-priv.h

@@ -284,6 +284,8 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
 	const struct firmware *fw, void *private);
 void sst_fw_free(struct sst_fw *sst_fw);
 void sst_fw_free_all(struct sst_dsp *dsp);
+int sst_fw_reload(struct sst_fw *sst_fw);
+void sst_fw_unload(struct sst_fw *sst_fw);
 
 /* Create/Free firmware modules */
 struct sst_module *sst_module_new(struct sst_fw *sst_fw,

+ 39 - 3
sound/soc/intel/sst-firmware.c

@@ -30,6 +30,8 @@
 #include "sst-dsp.h"
 #include "sst-dsp-priv.h"
 
+static void block_module_remove(struct sst_module *module);
+
 static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
 {
 	u32 i;
@@ -91,6 +93,42 @@ parse_err:
 }
 EXPORT_SYMBOL_GPL(sst_fw_new);
 
+int sst_fw_reload(struct sst_fw *sst_fw)
+{
+	struct sst_dsp *dsp = sst_fw->dsp;
+	int ret;
+
+	dev_dbg(dsp->dev, "reloading firmware\n");
+
+	/* call core specific FW paser to load FW data into DSP */
+	ret = dsp->ops->parse_fw(sst_fw);
+	if (ret < 0)
+		dev_err(dsp->dev, "error: parse fw failed %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sst_fw_reload);
+
+void sst_fw_unload(struct sst_fw *sst_fw)
+{
+        struct sst_dsp *dsp = sst_fw->dsp;
+        struct sst_module *module, *tmp;
+
+        dev_dbg(dsp->dev, "unloading firmware\n");
+
+        mutex_lock(&dsp->mutex);
+        list_for_each_entry_safe(module, tmp, &dsp->module_list, list) {
+                if (module->sst_fw == sst_fw) {
+                        block_module_remove(module);
+                        list_del(&module->list);
+                        kfree(module);
+                }
+        }
+
+        mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_fw_unload);
+
 /* free single firmware object */
 void sst_fw_free(struct sst_fw *sst_fw)
 {
@@ -496,9 +534,7 @@ struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
 
 	/* calculate required scratch size */
 	list_for_each_entry(sst_module, &dsp->module_list, list) {
-		if (scratch->s.size > sst_module->s.size)
-			scratch->s.size = scratch->s.size;
-		else
+		if (scratch->s.size < sst_module->s.size)
 			scratch->s.size = sst_module->s.size;
 	}
 

+ 0 - 8
sound/soc/intel/sst-mfld-dsp.h

@@ -16,10 +16,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  *  General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
@@ -40,7 +36,6 @@ enum stream_type {
 };
 
 struct snd_pcm_params {
-	u16 codec;	/* codec type */
 	u8 num_chan;	/* 1=Mono, 2=Stereo */
 	u8 pcm_wd_sz;	/* 16/24 - bit*/
 	u32 reserved;	/* Bitrate in bits per second */
@@ -53,7 +48,6 @@ struct snd_pcm_params {
 
 /* MP3 Music Parameters Message */
 struct snd_mp3_params {
-	u16 codec;
 	u8  num_chan;	/* 1=Mono, 2=Stereo	*/
 	u8  pcm_wd_sz; /* 16/24 - bit*/
 	u8  crc_check; /* crc_check - disable (0) or enable (1) */
@@ -67,7 +61,6 @@ struct snd_mp3_params {
 
 /* AAC Music Parameters Message */
 struct snd_aac_params {
-	u16 codec;
 	u8 num_chan; /* 1=Mono, 2=Stereo*/
 	u8 pcm_wd_sz; /* 16/24 - bit*/
 	u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
@@ -81,7 +74,6 @@ struct snd_aac_params {
 
 /* WMA Music Parameters Message */
 struct snd_wma_params {
-	u16 codec;
 	u8  num_chan;	/* 1=Mono, 2=Stereo */
 	u8  pcm_wd_sz;	/* 16/24 - bit*/
 	u32 brate;	/* Use the hard coded value. */

+ 237 - 0
sound/soc/intel/sst-mfld-platform-compress.c

@@ -0,0 +1,237 @@
+/*
+ *  sst_mfld_platform.c - Intel MID Platform driver
+ *
+ *  Copyright (C) 2010-2014 Intel Corp
+ *  Author: Vinod Koul <vinod.koul@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include "sst-mfld-platform.h"
+
+/* compress stream operations */
+static void sst_compr_fragment_elapsed(void *arg)
+{
+	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+	pr_debug("fragment elapsed by driver\n");
+	if (cstream)
+		snd_compr_fragment_elapsed(cstream);
+}
+
+static void sst_drain_notify(void *arg)
+{
+	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+	pr_debug("drain notify by driver\n");
+	if (cstream)
+		snd_compr_drain_notify(cstream);
+}
+
+static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+{
+
+	int ret_val = 0;
+	struct snd_compr_runtime *runtime = cstream->runtime;
+	struct sst_runtime_stream *stream;
+
+	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (!stream)
+		return -ENOMEM;
+
+	spin_lock_init(&stream->status_lock);
+
+	/* get the sst ops */
+	if (!sst || !try_module_get(sst->dev->driver->owner)) {
+		pr_err("no device available to run\n");
+		ret_val = -ENODEV;
+		goto out_ops;
+	}
+	stream->compr_ops = sst->compr_ops;
+
+	stream->id = 0;
+	sst_set_stream_status(stream, SST_PLATFORM_INIT);
+	runtime->private_data = stream;
+	return 0;
+out_ops:
+	kfree(stream);
+	return ret_val;
+}
+
+static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+{
+	struct sst_runtime_stream *stream;
+	int ret_val = 0, str_id;
+
+	stream = cstream->runtime->private_data;
+	/*need to check*/
+	str_id = stream->id;
+	if (str_id)
+		ret_val = stream->compr_ops->close(str_id);
+	module_put(sst->dev->driver->owner);
+	kfree(stream);
+	pr_debug("%s: %d\n", __func__, ret_val);
+	return 0;
+}
+
+static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
+					struct snd_compr_params *params)
+{
+	struct sst_runtime_stream *stream;
+	int retval;
+	struct snd_sst_params str_params;
+	struct sst_compress_cb cb;
+
+	stream = cstream->runtime->private_data;
+	/* construct fw structure for this*/
+	memset(&str_params, 0, sizeof(str_params));
+
+	str_params.ops = STREAM_OPS_PLAYBACK;
+	str_params.stream_type = SST_STREAM_TYPE_MUSIC;
+	str_params.device_type = SND_SST_DEVICE_COMPRESS;
+
+	switch (params->codec.id) {
+	case SND_AUDIOCODEC_MP3: {
+		str_params.codec = SST_CODEC_TYPE_MP3;
+		str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
+		str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
+		break;
+	}
+
+	case SND_AUDIOCODEC_AAC: {
+		str_params.codec = SST_CODEC_TYPE_AAC;
+		str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
+		str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
+		if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
+			str_params.sparams.uc.aac_params.bs_format =
+							AAC_BIT_STREAM_ADTS;
+		else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
+			str_params.sparams.uc.aac_params.bs_format =
+							AAC_BIT_STREAM_RAW;
+		else {
+			pr_err("Undefined format%d\n", params->codec.format);
+			return -EINVAL;
+		}
+		str_params.sparams.uc.aac_params.externalsr =
+						params->codec.sample_rate;
+		break;
+	}
+
+	default:
+		pr_err("codec not supported, id =%d\n", params->codec.id);
+		return -EINVAL;
+	}
+
+	str_params.aparams.ring_buf_info[0].addr  =
+					virt_to_phys(cstream->runtime->buffer);
+	str_params.aparams.ring_buf_info[0].size =
+					cstream->runtime->buffer_size;
+	str_params.aparams.sg_count = 1;
+	str_params.aparams.frag_size = cstream->runtime->fragment_size;
+
+	cb.param = cstream;
+	cb.compr_cb = sst_compr_fragment_elapsed;
+	cb.drain_cb_param = cstream;
+	cb.drain_notify = sst_drain_notify;
+
+	retval = stream->compr_ops->open(&str_params, &cb);
+	if (retval < 0) {
+		pr_err("stream allocation failed %d\n", retval);
+		return retval;
+	}
+
+	stream->id = retval;
+	return 0;
+}
+
+static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+	struct sst_runtime_stream *stream =
+		cstream->runtime->private_data;
+
+	return stream->compr_ops->control(cmd, stream->id);
+}
+
+static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
+					struct snd_compr_tstamp *tstamp)
+{
+	struct sst_runtime_stream *stream;
+
+	stream  = cstream->runtime->private_data;
+	stream->compr_ops->tstamp(stream->id, tstamp);
+	tstamp->byte_offset = tstamp->copied_total %
+				 (u32)cstream->runtime->buffer_size;
+	pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+	return 0;
+}
+
+static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
+					size_t bytes)
+{
+	struct sst_runtime_stream *stream;
+
+	stream  = cstream->runtime->private_data;
+	stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+	stream->bytes_written += bytes;
+
+	return 0;
+}
+
+static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
+					struct snd_compr_caps *caps)
+{
+	struct sst_runtime_stream *stream =
+		cstream->runtime->private_data;
+
+	return stream->compr_ops->get_caps(caps);
+}
+
+static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+					struct snd_compr_codec_caps *codec)
+{
+	struct sst_runtime_stream *stream =
+		cstream->runtime->private_data;
+
+	return stream->compr_ops->get_codec_caps(codec);
+}
+
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+					struct snd_compr_metadata *metadata)
+{
+	struct sst_runtime_stream *stream  =
+		 cstream->runtime->private_data;
+
+	return stream->compr_ops->set_metadata(stream->id, metadata);
+}
+
+struct snd_compr_ops sst_platform_compr_ops = {
+
+	.open = sst_platform_compr_open,
+	.free = sst_platform_compr_free,
+	.set_params = sst_platform_compr_set_params,
+	.set_metadata = sst_platform_compr_set_metadata,
+	.trigger = sst_platform_compr_trigger,
+	.pointer = sst_platform_compr_pointer,
+	.ack = sst_platform_compr_ack,
+	.get_caps = sst_platform_compr_get_caps,
+	.get_codec_caps = sst_platform_compr_get_codec_caps,
+};

+ 8 - 242
sound/soc/intel/sst-mfld-platform.c → sound/soc/intel/sst-mfld-platform-pcm.c

@@ -15,13 +15,7 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  *  General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -35,8 +29,9 @@
 #include <sound/compress_driver.h>
 #include "sst-mfld-platform.h"
 
-static struct sst_device *sst;
+struct sst_device *sst;
 static DEFINE_MUTEX(sst_lock);
+extern struct snd_compr_ops sst_platform_compr_ops;
 
 int sst_register_dsp(struct sst_device *dev)
 {
@@ -115,36 +110,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
 	},
 },
-{
-	.name = "Speaker-cpu-dai",
-	.id = 1,
-	.playback = {
-		.channels_min = SST_MONO,
-		.channels_max = SST_STEREO,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S24_LE,
-	},
-},
-{
-	.name = "Vibra1-cpu-dai",
-	.id = 2,
-	.playback = {
-		.channels_min = SST_MONO,
-		.channels_max = SST_MONO,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S24_LE,
-	},
-},
-{
-	.name = "Vibra2-cpu-dai",
-	.id = 3,
-	.playback = {
-		.channels_min = SST_MONO,
-		.channels_max = SST_STEREO,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S24_LE,
-	},
-},
 {
 	.name = "Compress-cpu-dai",
 	.compress_dai = 1,
@@ -157,12 +122,8 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 },
 };
 
-static const struct snd_soc_component_driver sst_component = {
-	.name		= "sst",
-};
-
 /* helper functions */
-static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
+void sst_set_stream_status(struct sst_runtime_stream *stream,
 					int state)
 {
 	unsigned long flags;
@@ -186,7 +147,6 @@ static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
 				struct sst_pcm_params *param)
 {
 
-	param->codec = SST_CODEC_TYPE_PCM;
 	param->num_chan = (u8) substream->runtime->channels;
 	param->pcm_wd_sz = substream->runtime->sample_bits;
 	param->reserved = 0;
@@ -471,205 +431,6 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 	return retval;
 }
 
-/* compress stream operations */
-static void sst_compr_fragment_elapsed(void *arg)
-{
-	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
-
-	pr_debug("fragment elapsed by driver\n");
-	if (cstream)
-		snd_compr_fragment_elapsed(cstream);
-}
-
-static int sst_platform_compr_open(struct snd_compr_stream *cstream)
-{
-
-	int ret_val = 0;
-	struct snd_compr_runtime *runtime = cstream->runtime;
-	struct sst_runtime_stream *stream;
-
-	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-	if (!stream)
-		return -ENOMEM;
-
-	spin_lock_init(&stream->status_lock);
-
-	/* get the sst ops */
-	if (!sst || !try_module_get(sst->dev->driver->owner)) {
-		pr_err("no device available to run\n");
-		ret_val = -ENODEV;
-		goto out_ops;
-	}
-	stream->compr_ops = sst->compr_ops;
-
-	stream->id = 0;
-	sst_set_stream_status(stream, SST_PLATFORM_INIT);
-	runtime->private_data = stream;
-	return 0;
-out_ops:
-	kfree(stream);
-	return ret_val;
-}
-
-static int sst_platform_compr_free(struct snd_compr_stream *cstream)
-{
-	struct sst_runtime_stream *stream;
-	int ret_val = 0, str_id;
-
-	stream = cstream->runtime->private_data;
-	/*need to check*/
-	str_id = stream->id;
-	if (str_id)
-		ret_val = stream->compr_ops->close(str_id);
-	module_put(sst->dev->driver->owner);
-	kfree(stream);
-	pr_debug("%s: %d\n", __func__, ret_val);
-	return 0;
-}
-
-static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
-					struct snd_compr_params *params)
-{
-	struct sst_runtime_stream *stream;
-	int retval;
-	struct snd_sst_params str_params;
-	struct sst_compress_cb cb;
-
-	stream = cstream->runtime->private_data;
-	/* construct fw structure for this*/
-	memset(&str_params, 0, sizeof(str_params));
-
-	str_params.ops = STREAM_OPS_PLAYBACK;
-	str_params.stream_type = SST_STREAM_TYPE_MUSIC;
-	str_params.device_type = SND_SST_DEVICE_COMPRESS;
-
-	switch (params->codec.id) {
-	case SND_AUDIOCODEC_MP3: {
-		str_params.codec = SST_CODEC_TYPE_MP3;
-		str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
-		str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
-		str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
-		break;
-	}
-
-	case SND_AUDIOCODEC_AAC: {
-		str_params.codec = SST_CODEC_TYPE_AAC;
-		str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
-		str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
-		str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
-		if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
-			str_params.sparams.uc.aac_params.bs_format =
-							AAC_BIT_STREAM_ADTS;
-		else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
-			str_params.sparams.uc.aac_params.bs_format =
-							AAC_BIT_STREAM_RAW;
-		else {
-			pr_err("Undefined format%d\n", params->codec.format);
-			return -EINVAL;
-		}
-		str_params.sparams.uc.aac_params.externalsr =
-						params->codec.sample_rate;
-		break;
-	}
-
-	default:
-		pr_err("codec not supported, id =%d\n", params->codec.id);
-		return -EINVAL;
-	}
-
-	str_params.aparams.ring_buf_info[0].addr  =
-					virt_to_phys(cstream->runtime->buffer);
-	str_params.aparams.ring_buf_info[0].size =
-					cstream->runtime->buffer_size;
-	str_params.aparams.sg_count = 1;
-	str_params.aparams.frag_size = cstream->runtime->fragment_size;
-
-	cb.param = cstream;
-	cb.compr_cb = sst_compr_fragment_elapsed;
-
-	retval = stream->compr_ops->open(&str_params, &cb);
-	if (retval < 0) {
-		pr_err("stream allocation failed %d\n", retval);
-		return retval;
-	}
-
-	stream->id = retval;
-	return 0;
-}
-
-static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
-{
-	struct sst_runtime_stream *stream =
-		cstream->runtime->private_data;
-
-	return stream->compr_ops->control(cmd, stream->id);
-}
-
-static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
-					struct snd_compr_tstamp *tstamp)
-{
-	struct sst_runtime_stream *stream;
-
-	stream  = cstream->runtime->private_data;
-	stream->compr_ops->tstamp(stream->id, tstamp);
-	tstamp->byte_offset = tstamp->copied_total %
-				 (u32)cstream->runtime->buffer_size;
-	pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
-	return 0;
-}
-
-static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
-					size_t bytes)
-{
-	struct sst_runtime_stream *stream;
-
-	stream  = cstream->runtime->private_data;
-	stream->compr_ops->ack(stream->id, (unsigned long)bytes);
-	stream->bytes_written += bytes;
-
-	return 0;
-}
-
-static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
-					struct snd_compr_caps *caps)
-{
-	struct sst_runtime_stream *stream =
-		cstream->runtime->private_data;
-
-	return stream->compr_ops->get_caps(caps);
-}
-
-static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
-					struct snd_compr_codec_caps *codec)
-{
-	struct sst_runtime_stream *stream =
-		cstream->runtime->private_data;
-
-	return stream->compr_ops->get_codec_caps(codec);
-}
-
-static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
-					struct snd_compr_metadata *metadata)
-{
-	struct sst_runtime_stream *stream  =
-		 cstream->runtime->private_data;
-
-	return stream->compr_ops->set_metadata(stream->id, metadata);
-}
-
-static struct snd_compr_ops sst_platform_compr_ops = {
-
-	.open = sst_platform_compr_open,
-	.free = sst_platform_compr_free,
-	.set_params = sst_platform_compr_set_params,
-	.set_metadata = sst_platform_compr_set_metadata,
-	.trigger = sst_platform_compr_trigger,
-	.pointer = sst_platform_compr_pointer,
-	.ack = sst_platform_compr_ack,
-	.get_caps = sst_platform_compr_get_caps,
-	.get_codec_caps = sst_platform_compr_get_codec_caps,
-};
-
 static struct snd_soc_platform_driver sst_soc_platform_drv = {
 	.ops		= &sst_platform_ops,
 	.compr_ops	= &sst_platform_compr_ops,
@@ -677,6 +438,11 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = {
 	.pcm_free	= sst_pcm_free,
 };
 
+static const struct snd_soc_component_driver sst_component = {
+	.name		= "sst",
+};
+
+
 static int sst_platform_probe(struct platform_device *pdev)
 {
 	int ret;

+ 5 - 6
sound/soc/intel/sst-mfld-platform.h

@@ -15,13 +15,7 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  *  General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *
  */
 
 #ifndef __SST_PLATFORMDRV_H__
@@ -29,6 +23,8 @@
 
 #include "sst-mfld-dsp.h"
 
+extern struct sst_device *sst;
+
 #define SST_MONO		1
 #define SST_STEREO		2
 #define SST_MAX_CAP		5
@@ -108,6 +104,8 @@ struct sst_stream_params {
 struct sst_compress_cb {
 	void *param;
 	void (*compr_cb)(void *param);
+	void *drain_cb_param;
+	void (*drain_notify)(void *param);
 };
 
 struct compress_sst_ops {
@@ -148,6 +146,7 @@ struct sst_device {
 	struct compress_sst_ops *compr_ops;
 };
 
+void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
 int sst_register_dsp(struct sst_device *sst);
 int sst_unregister_dsp(struct sst_device *sst);
 #endif

+ 8 - 3
sound/soc/jz4740/Kconfig

@@ -1,24 +1,29 @@
 config SND_JZ4740_SOC
 	tristate "SoC Audio for Ingenic JZ4740 SoC"
-	depends on MACH_JZ4740 && SND_SOC
+	depends on MACH_JZ4740 || COMPILE_TEST
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the JZ4740 I2S interface. You will also need to select the audio
 	  interfaces to support below.
 
+if SND_JZ4740_SOC
+
 config SND_JZ4740_SOC_I2S
-	depends on SND_JZ4740_SOC
 	tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
+	depends on HAS_IOMEM
 	help
 	  Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
 	  based boards.
 
 config SND_JZ4740_SOC_QI_LB60
 	tristate "SoC Audio support for Qi LB60"
-	depends on SND_JZ4740_SOC && JZ4740_QI_LB60
+	depends on HAS_IOMEM
+	depends on JZ4740_QI_LB60 || COMPILE_TEST
 	select SND_JZ4740_SOC_I2S
     select SND_SOC_JZ4740_CODEC
 	help
 	  Say Y if you want to add support for ASoC audio on the Qi LB60 board
 	  a.k.a Qi Ben NanoNote.
+
+endif

+ 3 - 2
sound/soc/jz4740/jz4740-i2s.c

@@ -31,10 +31,11 @@
 #include <sound/initval.h>
 #include <sound/dmaengine_pcm.h>
 
-#include <asm/mach-jz4740/dma.h>
-
 #include "jz4740-i2s.h"
 
+#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
+#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
+
 #define JZ_REG_AIC_CONF		0x00
 #define JZ_REG_AIC_CTRL		0x04
 #define JZ_REG_AIC_I2S_FMT	0x10

+ 31 - 53
sound/soc/jz4740/qi_lb60.c

@@ -19,18 +19,21 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 
-#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
-#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
+struct qi_lb60 {
+	struct gpio_desc *snd_gpio;
+	struct gpio_desc *amp_gpio;
+};
 
 static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
 			     struct snd_kcontrol *ctrl, int event)
 {
+	struct qi_lb60 *qi_lb60 = snd_soc_card_get_drvdata(widget->dapm->card);
 	int on = !SND_SOC_DAPM_EVENT_OFF(event);
 
-	gpio_set_value(QI_LB60_SND_GPIO, on);
-	gpio_set_value(QI_LB60_AMP_GPIO, on);
+	gpiod_set_value_cansleep(qi_lb60->snd_gpio, on);
+	gpiod_set_value_cansleep(qi_lb60->amp_gpio, on);
 
 	return 0;
 }
@@ -46,29 +49,6 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = {
 	{"Speaker", NULL, "ROUT"},
 };
 
-#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \
-			SND_SOC_DAIFMT_NB_NF | \
-			SND_SOC_DAIFMT_CBM_CFM)
-
-static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	int ret;
-
-	snd_soc_dapm_nc_pin(dapm, "LIN");
-	snd_soc_dapm_nc_pin(dapm, "RIN");
-
-	ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
 static struct snd_soc_dai_link qi_lb60_dai = {
 	.name = "jz4740",
 	.stream_name = "jz4740",
@@ -76,10 +56,11 @@ static struct snd_soc_dai_link qi_lb60_dai = {
 	.platform_name = "jz4740-i2s",
 	.codec_dai_name = "jz4740-hifi",
 	.codec_name = "jz4740-codec",
-	.init = qi_lb60_codec_init,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		SND_SOC_DAIFMT_CBM_CFM,
 };
 
-static struct snd_soc_card qi_lb60 = {
+static struct snd_soc_card qi_lb60_card = {
 	.name = "QI LB60",
 	.owner = THIS_MODULE,
 	.dai_link = &qi_lb60_dai,
@@ -89,40 +70,38 @@ static struct snd_soc_card qi_lb60 = {
 	.num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets),
 	.dapm_routes = qi_lb60_routes,
 	.num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
-};
-
-static const struct gpio qi_lb60_gpios[] = {
-	{ QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
-	{ QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
+	.fully_routed = true,
 };
 
 static int qi_lb60_probe(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = &qi_lb60;
+	struct qi_lb60 *qi_lb60;
+	struct snd_soc_card *card = &qi_lb60_card;
 	int ret;
 
-	ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
+	qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL);
+	if (!qi_lb60)
+		return -ENOMEM;
+
+	qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd");
+	if (IS_ERR(qi_lb60->snd_gpio))
+		return PTR_ERR(qi_lb60->snd_gpio);
+	ret = gpiod_direction_output(qi_lb60->snd_gpio, 0);
 	if (ret)
 		return ret;
 
-	card->dev = &pdev->dev;
+	qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp");
+	if (IS_ERR(qi_lb60->amp_gpio))
+		return PTR_ERR(qi_lb60->amp_gpio);
+	ret = gpiod_direction_output(qi_lb60->amp_gpio, 0);
+	if (ret)
+		return ret;
 
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
-			ret);
-		gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
-	}
-	return ret;
-}
+	card->dev = &pdev->dev;
 
-static int qi_lb60_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	snd_soc_card_set_drvdata(card, qi_lb60);
 
-	snd_soc_unregister_card(card);
-	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
-	return 0;
+	return devm_snd_soc_register_card(&pdev->dev, card);
 }
 
 static struct platform_driver qi_lb60_driver = {
@@ -131,7 +110,6 @@ static struct platform_driver qi_lb60_driver = {
 		.owner	= THIS_MODULE,
 	},
 	.probe		= qi_lb60_probe,
-	.remove		= qi_lb60_remove,
 };
 
 module_platform_driver(qi_lb60_driver);

+ 46 - 8
sound/soc/soc-core.c

@@ -1266,6 +1266,50 @@ static void rtd_release(struct device *dev)
 	kfree(dev);
 }
 
+static int soc_aux_dev_init(struct snd_soc_card *card,
+			    struct snd_soc_codec *codec,
+			    int num)
+{
+	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
+	int ret;
+
+	rtd->card = card;
+
+	/* do machine specific initialization */
+	if (aux_dev->init) {
+		ret = aux_dev->init(&codec->dapm);
+		if (ret < 0)
+			return ret;
+	}
+
+	rtd->codec = codec;
+
+	return 0;
+}
+
+static int soc_dai_link_init(struct snd_soc_card *card,
+			     struct snd_soc_codec *codec,
+			     int num)
+{
+	struct snd_soc_dai_link *dai_link =  &card->dai_link[num];
+	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+	int ret;
+
+	rtd->card = card;
+
+	/* do machine specific initialization */
+	if (dai_link->init) {
+		ret = dai_link->init(rtd);
+		if (ret < 0)
+			return ret;
+	}
+
+	rtd->codec = codec;
+
+	return 0;
+}
+
 static int soc_post_component_init(struct snd_soc_card *card,
 				   struct snd_soc_codec *codec,
 				   int num, int dailess)
@@ -1280,26 +1324,20 @@ static int soc_post_component_init(struct snd_soc_card *card,
 		dai_link = &card->dai_link[num];
 		rtd = &card->rtd[num];
 		name = dai_link->name;
+		ret = soc_dai_link_init(card, codec, num);
 	} else {
 		aux_dev = &card->aux_dev[num];
 		rtd = &card->rtd_aux[num];
 		name = aux_dev->name;
+		ret = soc_aux_dev_init(card, codec, num);
 	}
-	rtd->card = card;
 
-	/* do machine specific initialization */
-	if (!dailess && dai_link->init)
-		ret = dai_link->init(rtd);
-	else if (dailess && aux_dev->init)
-		ret = aux_dev->init(&codec->dapm);
 	if (ret < 0) {
 		dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);
 		return ret;
 	}
 
 	/* register the rtd device */
-	rtd->codec = codec;
-
 	rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 	if (!rtd->dev)
 		return -ENOMEM;

+ 5 - 14
sound/soc/soc-pcm.c

@@ -1018,21 +1018,12 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
 }
 
 static inline struct snd_soc_dapm_widget *
-	rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+	dai_get_widget(struct snd_soc_dai *dai, int stream)
 {
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		return rtd->cpu_dai->playback_widget;
+		return dai->playback_widget;
 	else
-		return rtd->cpu_dai->capture_widget;
-}
-
-static inline struct snd_soc_dapm_widget *
-	rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
-{
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		return rtd->codec_dai->playback_widget;
-	else
-		return rtd->codec_dai->capture_widget;
+		return dai->capture_widget;
 }
 
 static int widget_in_list(struct snd_soc_dapm_widget_list *list,
@@ -1082,14 +1073,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
 	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
 
 		/* is there a valid CPU DAI widget for this BE */
-		widget = rtd_get_cpu_widget(dpcm->be, stream);
+		widget = dai_get_widget(dpcm->be->cpu_dai, stream);
 
 		/* prune the BE if it's no longer in our active list */
 		if (widget && widget_in_list(list, widget))
 			continue;
 
 		/* is there a valid CODEC DAI widget for this BE */
-		widget = rtd_get_codec_widget(dpcm->be, stream);
+		widget = dai_get_widget(dpcm->be->codec_dai, stream);
 
 		/* prune the BE if it's no longer in our active list */
 		if (widget && widget_in_list(list, widget))