]> Pileus Git - ~andy/linux/commitdiff
Merge remote-tracking branch 'asoc/topic/davinci' into asoc-next
authorMark Brown <broonie@linaro.org>
Fri, 8 Nov 2013 10:43:27 +0000 (10:43 +0000)
committerMark Brown <broonie@linaro.org>
Fri, 8 Nov 2013 10:43:27 +0000 (10:43 +0000)
Documentation/devicetree/bindings/sound/davinci-evm-audio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
include/linux/platform_data/davinci_asp.h
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h

diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
new file mode 100644 (file)
index 0000000..865178d
--- /dev/null
@@ -0,0 +1,42 @@
+* Texas Instruments SoC audio setups with TLV320AIC3X Codec
+
+Required properties:
+- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
+- ti,model : The user-visible name of this sound complex.
+- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
+- ti,mcasp-controller : The phandle of the McASP controller
+- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
+- ti,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the codec's pins, and the jacks on the board:
+
+  Board connectors:
+
+  * Headphone Jack
+  * Line Out
+  * Mic Jack
+  * Line In
+
+
+Example:
+
+sound {
+       compatible = "ti,da830-evm-audio";
+       ti,model = "DA830 EVM";
+       ti,audio-codec = <&tlv320aic3x>;
+       ti,mcasp-controller = <&mcasp1>;
+       ti,codec-clock-rate = <12000000>;
+       ti,audio-routing =
+               "Headphone Jack",       "HPLOUT",
+               "Headphone Jack",       "HPROUT",
+               "Line Out",             "LLOUT",
+               "Line Out",             "RLOUT",
+               "MIC3L",                "Mic Bias 2V",
+               "MIC3R",                "Mic Bias 2V",
+               "Mic Bias 2V",          "Mic Jack",
+               "LINE1L",               "Line In",
+               "LINE2L",               "Line In",
+               "LINE1R",               "Line In",
+               "LINE2R",               "Line In";
+};
index 374e145c2ef170ceaa32055cf01836bfb3f8c3ef..ed785b3f67beacb6973ff1758b1b0d5b9b5f16dd 100644 (file)
@@ -4,17 +4,25 @@ Required properties:
 - compatible :
        "ti,dm646x-mcasp-audio" : for DM646x platforms
        "ti,da830-mcasp-audio"  : for both DA830 & DA850 platforms
-       "ti,omap2-mcasp-audio"  : for OMAP2 platforms (TI81xx, AM33xx)
-
-- reg : Should contain McASP registers offset and length
-- interrupts : Interrupt number for McASP
-- op-mode : I2S/DIT ops mode.
-- tdm-slots : Slots for TDM operation.
-- num-serializer : Serializers used by McASP.
-- serial-dir : A list of serializer pin mode. The list number should be equal
-               to "num-serializer" parameter. Each entry is a number indication
-               serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX)
+       "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, TI81xx)
 
+- reg : Should contain reg specifiers for the entries in the reg-names property.
+- reg-names : Should contain:
+         * "mpu" for the main registers (required). For compatibility with
+           existing software, it is recommended this is the first entry.
+         * "dat" for separate data port register access (optional).
+- op-mode : I2S/DIT ops mode. 0 for I2S mode. 1 for DIT mode used for S/PDIF,
+           IEC60958-1, and AES-3 formats.
+- tdm-slots : Slots for TDM operation. Indicates number of channels transmitted
+             or received over one serializer.
+- serial-dir : A list of serializer configuration. Each entry is a number
+               indication for serializer pin direction.
+               (0 - INACTIVE, 1 - TX, 2 - RX)
+- dmas: two element list of DMA controller phandles and DMA request line
+        ordered pairs.
+- dma-names: identifier string for each DMA request line in the dmas property.
+            These strings correspond 1:1 with the ordered pairs in dmas. The dma
+            identifiers must be "rx" and "tx".
 
 Optional properties:
 
@@ -23,18 +31,23 @@ Optional properties:
 - rx-num-evt : FIFO levels.
 - sram-size-playback : size of sram to be allocated during playback
 - sram-size-capture  : size of sram to be allocated during capture
+- interrupts : Interrupt numbers for McASP, currently not used by the driver
+- interrupt-names : Known interrupt names are "tx" and "rx"
+- pinctrl-0: Should specify pin control group used for this controller.
+- pinctrl-names: Should contain only one value - "default", for more details
+                please refer to pinctrl-bindings.txt
+  
 
 Example:
 
 mcasp0: mcasp0@1d00000 {
        compatible = "ti,da830-mcasp-audio";
-       #address-cells = <1>;
-       #size-cells = <0>;
        reg = <0x100000 0x3000>;
-       interrupts = <82 83>;
+       reg-names "mpu";
+       interrupts = <82>, <83>;
+       interrupts-names = "tx", "rx";
        op-mode = <0>;          /* MCASP_IIS_MODE */
        tdm-slots = <2>;
-       num-serializer = <16>;
        serial-dir = <
                        0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */
                        0 0 0 0
index 8db5ae03b6e3f679c16988e492e8241f1567b2f5..689a856b86f90e1329515cf1ad9b80d3e2e7cdf5 100644 (file)
@@ -84,6 +84,8 @@ struct snd_platform_data {
        u8 version;
        u8 txnumevt;
        u8 rxnumevt;
+       int tx_dma_channel;
+       int rx_dma_channel;
 };
 
 enum {
index c82f89c9475b2f7301ecd1d753c65d85431f3cc6..95970f5db3eca228df66a55f5e357f14b26209c9 100644 (file)
@@ -1,9 +1,10 @@
 config SND_DAVINCI_SOC
-       tristate "SoC Audio for the TI DAVINCI chip"
-       depends on ARCH_DAVINCI
+       tristate "SoC Audio for the TI DAVINCI or AM33XX chip"
+       depends on ARCH_DAVINCI || SOC_AM33XX
        help
+         Platform driver for daVinci or AM33xx
          Say Y or M if you want to add support for codecs attached to
-         the DAVINCI AC97 or I2S interface. You will also need
+         the DAVINCI AC97, I2S, or McASP interface. You will also need
          to select the audio interfaces to support below.
 
 config SND_DAVINCI_SOC_I2S
@@ -15,6 +16,17 @@ config SND_DAVINCI_SOC_MCASP
 config SND_DAVINCI_SOC_VCIF
        tristate
 
+config SND_AM33XX_SOC_EVM
+       tristate "SoC Audio for the AM33XX chip based boards"
+       depends on SND_DAVINCI_SOC && SOC_AM33XX
+       select SND_SOC_TLV320AIC3X
+       select SND_DAVINCI_SOC_MCASP
+       help
+         Say Y or M if you want to add support for SoC audio on AM33XX
+         boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
+         AM335X-EVMSK, and BeagelBone with AudioCape boards have this
+         setup.
+
 config SND_DAVINCI_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
        depends on SND_DAVINCI_SOC
index a396ab6d6d5efaa6f11ec5d1da6716cb4a1db0ac..bc81e79fc301b8357cddd5edf7e707beb33a0723 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
 snd-soc-evm-objs := davinci-evm.o
 
 obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_AM33XX_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o
index fd7c45b9ed5a3836323a4d54af31df6f2929d050..623eb5e7c08981c08f31f2d51863c0426c1a7416 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_data/edma.h>
 #include <linux/i2c.h>
+#include <linux/of_platform.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <asm/dma.h>
 #include <asm/mach-types.h>
 
+#include <linux/edma.h>
+
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 #include "davinci-mcasp.h"
 
+struct snd_soc_card_drvdata_davinci {
+       unsigned sysclk;
+};
+
 #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
                SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
 static int evm_hw_params(struct snd_pcm_substream *substream,
@@ -35,27 +42,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *soc_card = codec->card;
        int ret = 0;
-       unsigned sysclk;
-
-       /* ASP1 on DM355 EVM is clocked by an external oscillator */
-       if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() ||
-           machine_is_davinci_dm365_evm())
-               sysclk = 27000000;
-
-       /* ASP0 in DM6446 EVM is clocked by U55, as configured by
-        * board-dm644x-evm.c using GPIOs from U18.  There are six
-        * options; here we "know" we use a 48 KHz sample rate.
-        */
-       else if (machine_is_davinci_evm())
-               sysclk = 12288000;
-
-       else if (machine_is_davinci_da830_evm() ||
-                               machine_is_davinci_da850_evm())
-               sysclk = 24576000;
-
-       else
-               return -EINVAL;
+       unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
+                          snd_soc_card_get_drvdata(soc_card))->sysclk;
 
        /* set codec DAI configuration */
        ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
@@ -133,13 +124,22 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct device_node *np = codec->card->dev->of_node;
+       int ret;
 
        /* Add davinci-evm specific widgets */
        snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
-       /* Set up davinci-evm specific audio path audio_map */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+       if (np) {
+               ret = snd_soc_of_parse_audio_routing(codec->card,
+                                                       "ti,audio-routing");
+               if (ret)
+                       return ret;
+       } else {
+               /* Set up davinci-evm specific audio path audio_map */
+               snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+       }
 
        /* not connected */
        snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
@@ -243,35 +243,65 @@ static struct snd_soc_dai_link da850_evm_dai = {
 };
 
 /* davinci dm6446 evm audio machine driver */
+/*
+ * ASP0 in DM6446 EVM is clocked by U55, as configured by
+ * board-dm644x-evm.c using GPIOs from U18.  There are six
+ * options; here we "know" we use a 48 KHz sample rate.
+ */
+static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
+       .sysclk = 12288000,
+};
+
 static struct snd_soc_card dm6446_snd_soc_card_evm = {
        .name = "DaVinci DM6446 EVM",
        .owner = THIS_MODULE,
        .dai_link = &dm6446_evm_dai,
        .num_links = 1,
+       .drvdata = &dm6446_snd_soc_card_drvdata,
 };
 
 /* davinci dm355 evm audio machine driver */
+/* ASP1 on DM355 EVM is clocked by an external oscillator */
+static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
+       .sysclk = 27000000,
+};
+
 static struct snd_soc_card dm355_snd_soc_card_evm = {
        .name = "DaVinci DM355 EVM",
        .owner = THIS_MODULE,
        .dai_link = &dm355_evm_dai,
        .num_links = 1,
+       .drvdata = &dm355_snd_soc_card_drvdata,
 };
 
 /* davinci dm365 evm audio machine driver */
+static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
+       .sysclk = 27000000,
+};
+
 static struct snd_soc_card dm365_snd_soc_card_evm = {
        .name = "DaVinci DM365 EVM",
        .owner = THIS_MODULE,
        .dai_link = &dm365_evm_dai,
        .num_links = 1,
+       .drvdata = &dm365_snd_soc_card_drvdata,
 };
 
 /* davinci dm6467 evm audio machine driver */
+static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
+       .sysclk = 27000000,
+};
+
 static struct snd_soc_card dm6467_snd_soc_card_evm = {
        .name = "DaVinci DM6467 EVM",
        .owner = THIS_MODULE,
        .dai_link = dm6467_evm_dai,
        .num_links = ARRAY_SIZE(dm6467_evm_dai),
+       .drvdata = &dm6467_snd_soc_card_drvdata,
+};
+
+static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
+       .sysclk = 24576000,
 };
 
 static struct snd_soc_card da830_snd_soc_card = {
@@ -279,6 +309,11 @@ static struct snd_soc_card da830_snd_soc_card = {
        .owner = THIS_MODULE,
        .dai_link = &da830_evm_dai,
        .num_links = 1,
+       .drvdata = &da830_snd_soc_card_drvdata,
+};
+
+static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
+       .sysclk = 24576000,
 };
 
 static struct snd_soc_card da850_snd_soc_card = {
@@ -286,8 +321,101 @@ static struct snd_soc_card da850_snd_soc_card = {
        .owner = THIS_MODULE,
        .dai_link = &da850_evm_dai,
        .num_links = 1,
+       .drvdata = &da850_snd_soc_card_drvdata,
+};
+
+#if defined(CONFIG_OF)
+
+/*
+ * The struct is used as place holder. It will be completely
+ * filled with data from dt node.
+ */
+static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
+       .name           = "TLV320AIC3X",
+       .stream_name    = "AIC3X",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .ops            = &evm_ops,
+       .init           = evm_aic3x_init,
+};
+
+static const struct of_device_id davinci_evm_dt_ids[] = {
+       {
+               .compatible = "ti,da830-evm-audio",
+               .data = (void *) &evm_dai_tlv320aic3x,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
+
+/* davinci evm audio machine driver */
+static struct snd_soc_card evm_soc_card = {
+       .owner = THIS_MODULE,
+       .num_links = 1,
 };
 
+static int davinci_evm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
+       struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
+       struct snd_soc_card_drvdata_davinci *drvdata = NULL;
+       int ret = 0;
+
+       evm_soc_card.dai_link = dai;
+
+       dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
+       if (!dai->codec_of_node)
+               return -EINVAL;
+
+       dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
+       if (!dai->cpu_of_node)
+               return -EINVAL;
+
+       dai->platform_of_node = dai->cpu_of_node;
+
+       evm_soc_card.dev = &pdev->dev;
+       ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
+       if (ret)
+               return ret;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
+       if (ret < 0)
+               return -EINVAL;
+
+       snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
+       ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
+
+       if (ret)
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+
+       return ret;
+}
+
+static int davinci_evm_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver davinci_evm_driver = {
+       .probe          = davinci_evm_probe,
+       .remove         = davinci_evm_remove,
+       .driver         = {
+               .name   = "davinci_evm",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(davinci_evm_dt_ids),
+       },
+};
+#endif
+
 static struct platform_device *evm_snd_device;
 
 static int __init evm_init(void)
@@ -296,6 +424,15 @@ static int __init evm_init(void)
        int index;
        int ret;
 
+       /*
+        * If dtb is there, the devices will be created dynamically.
+        * Only register platfrom driver structure.
+        */
+#if defined(CONFIG_OF)
+       if (of_have_populated_dt())
+               return platform_driver_register(&davinci_evm_driver);
+#endif
+
        if (machine_is_davinci_evm()) {
                evm_snd_dev_data = &dm6446_snd_soc_card_evm;
                index = 0;
@@ -331,6 +468,13 @@ static int __init evm_init(void)
 
 static void __exit evm_exit(void)
 {
+#if defined(CONFIG_OF)
+       if (of_have_populated_dt()) {
+               platform_driver_unregister(&davinci_evm_driver);
+               return;
+       }
+#endif
+
        platform_device_unregister(evm_snd_device);
 }
 
index 32ddb7fe5034865a7f13dc7243f1f8161482c7f2..71e14bb3a8cd11b4465567d088a05820e0ecdb74 100644 (file)
@@ -1001,18 +1001,40 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
        .name           = "davinci-mcasp",
 };
 
+/* Some HW specific values and defaults. The rest is filled in from DT. */
+static struct snd_platform_data dm646x_mcasp_pdata = {
+       .tx_dma_offset = 0x400,
+       .rx_dma_offset = 0x400,
+       .asp_chan_q = EVENTQ_0,
+       .version = MCASP_VERSION_1,
+};
+
+static struct snd_platform_data da830_mcasp_pdata = {
+       .tx_dma_offset = 0x2000,
+       .rx_dma_offset = 0x2000,
+       .asp_chan_q = EVENTQ_0,
+       .version = MCASP_VERSION_2,
+};
+
+static struct snd_platform_data omap2_mcasp_pdata = {
+       .tx_dma_offset = 0,
+       .rx_dma_offset = 0,
+       .asp_chan_q = EVENTQ_0,
+       .version = MCASP_VERSION_3,
+};
+
 static const struct of_device_id mcasp_dt_ids[] = {
        {
                .compatible = "ti,dm646x-mcasp-audio",
-               .data = (void *)MCASP_VERSION_1,
+               .data = &dm646x_mcasp_pdata,
        },
        {
                .compatible = "ti,da830-mcasp-audio",
-               .data = (void *)MCASP_VERSION_2,
+               .data = &da830_mcasp_pdata,
        },
        {
-               .compatible = "ti,omap2-mcasp-audio",
-               .data = (void *)MCASP_VERSION_3,
+               .compatible = "ti,am33xx-mcasp-audio",
+               .data = &omap2_mcasp_pdata,
        },
        { /* sentinel */ }
 };
@@ -1025,9 +1047,9 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
        struct snd_platform_data *pdata = NULL;
        const struct of_device_id *match =
                        of_match_device(mcasp_dt_ids, &pdev->dev);
+       struct of_phandle_args dma_spec;
 
        const u32 *of_serial_dir32;
-       u8 *of_serial_dir;
        u32 val;
        int i, ret = 0;
 
@@ -1035,20 +1057,13 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata = pdev->dev.platform_data;
                return pdata;
        } else if (match) {
-               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata) {
-                       ret = -ENOMEM;
-                       goto nodata;
-               }
+               pdata = (struct snd_platform_data *) match->data;
        } else {
                /* control shouldn't reach here. something is wrong */
                ret = -EINVAL;
                goto nodata;
        }
 
-       if (match->data)
-               pdata->version = (u8)((int)match->data);
-
        ret = of_property_read_u32(np, "op-mode", &val);
        if (ret >= 0)
                pdata->op_mode = val;
@@ -1065,35 +1080,46 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata->tdm_slots = val;
        }
 
-       ret = of_property_read_u32(np, "num-serializer", &val);
-       if (ret >= 0)
-               pdata->num_serializer = val;
-
        of_serial_dir32 = of_get_property(np, "serial-dir", &val);
        val /= sizeof(u32);
-       if (val != pdata->num_serializer) {
-               dev_err(&pdev->dev,
-                               "num-serializer(%d) != serial-dir size(%d)\n",
-                               pdata->num_serializer, val);
-               ret = -EINVAL;
-               goto nodata;
-       }
-
        if (of_serial_dir32) {
-               of_serial_dir = devm_kzalloc(&pdev->dev,
-                                               (sizeof(*of_serial_dir) * val),
-                                               GFP_KERNEL);
+               u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
+                                                (sizeof(*of_serial_dir) * val),
+                                                GFP_KERNEL);
                if (!of_serial_dir) {
                        ret = -ENOMEM;
                        goto nodata;
                }
 
-               for (i = 0; i < pdata->num_serializer; i++)
+               for (i = 0; i < val; i++)
                        of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
 
+               pdata->num_serializer = val;
                pdata->serial_dir = of_serial_dir;
        }
 
+       ret = of_property_match_string(np, "dma-names", "tx");
+       if (ret < 0)
+               goto nodata;
+
+       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+                                        &dma_spec);
+       if (ret < 0)
+               goto nodata;
+
+       pdata->tx_dma_channel = dma_spec.args[0];
+
+       ret = of_property_match_string(np, "dma-names", "rx");
+       if (ret < 0)
+               goto nodata;
+
+       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+                                        &dma_spec);
+       if (ret < 0)
+               goto nodata;
+
+       pdata->rx_dma_channel = dma_spec.args[0];
+
        ret = of_property_read_u32(np, "tx-num-evt", &val);
        if (ret >= 0)
                pdata->txnumevt = val;
@@ -1124,7 +1150,7 @@ nodata:
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
        struct davinci_pcm_dma_params *dma_data;
-       struct resource *mem, *ioarea, *res;
+       struct resource *mem, *ioarea, *res, *dat;
        struct snd_platform_data *pdata;
        struct davinci_audio_dev *dev;
        int ret;
@@ -1145,10 +1171,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
        if (!mem) {
-               dev_err(&pdev->dev, "no mem resource?\n");
-               return -ENODEV;
+               dev_warn(dev->dev,
+                        "\"mpu\" mem resource not found, using index 0\n");
+               mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (!mem) {
+                       dev_err(&pdev->dev, "no mem resource?\n");
+                       return -ENODEV;
+               }
        }
 
        ioarea = devm_request_mem_region(&pdev->dev, mem->start,
@@ -1182,40 +1213,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        dev->rxnumevt = pdata->rxnumevt;
        dev->dev = &pdev->dev;
 
+       dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+       if (!dat)
+               dat = mem;
+
        dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data->asp_chan_q = pdata->asp_chan_q;
        dma_data->ram_chan_q = pdata->ram_chan_q;
        dma_data->sram_pool = pdata->sram_pool;
        dma_data->sram_size = pdata->sram_size_playback;
-       dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
-                                                       mem->start);
+       dma_data->dma_addr = dat->start + pdata->tx_dma_offset;
 
-       /* first TX, then RX */
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no DMA resource\n");
-               ret = -ENODEV;
-               goto err_release_clk;
-       }
-
-       dma_data->channel = res->start;
+       if (res)
+               dma_data->channel = res->start;
+       else
+               dma_data->channel = pdata->tx_dma_channel;
 
        dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
        dma_data->asp_chan_q = pdata->asp_chan_q;
        dma_data->ram_chan_q = pdata->ram_chan_q;
        dma_data->sram_pool = pdata->sram_pool;
        dma_data->sram_size = pdata->sram_size_capture;
-       dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
-                                                       mem->start);
+       dma_data->dma_addr = dat->start + pdata->rx_dma_offset;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!res) {
-               dev_err(&pdev->dev, "no DMA resource\n");
-               ret = -ENODEV;
-               goto err_release_clk;
-       }
+       if (res)
+               dma_data->channel = res->start;
+       else
+               dma_data->channel = pdata->rx_dma_channel;
 
-       dma_data->channel = res->start;
        dev_set_drvdata(&pdev->dev, dev);
        ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
                                         &davinci_mcasp_dai[pdata->op_mode], 1);
@@ -1251,12 +1278,51 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int davinci_mcasp_suspend(struct device *dev)
+{
+       struct davinci_audio_dev *a = dev_get_drvdata(dev);
+       void __iomem *base = a->base;
+
+       a->context.txfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_TXFMCTL_REG);
+       a->context.rxfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_RXFMCTL_REG);
+       a->context.txfmt = mcasp_get_reg(base + DAVINCI_MCASP_TXFMT_REG);
+       a->context.rxfmt = mcasp_get_reg(base + DAVINCI_MCASP_RXFMT_REG);
+       a->context.aclkxctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKXCTL_REG);
+       a->context.aclkrctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKRCTL_REG);
+       a->context.pdir = mcasp_get_reg(base + DAVINCI_MCASP_PDIR_REG);
+
+       return 0;
+}
+
+static int davinci_mcasp_resume(struct device *dev)
+{
+       struct davinci_audio_dev *a = dev_get_drvdata(dev);
+       void __iomem *base = a->base;
+
+       mcasp_set_reg(base + DAVINCI_MCASP_TXFMCTL_REG, a->context.txfmtctl);
+       mcasp_set_reg(base + DAVINCI_MCASP_RXFMCTL_REG, a->context.rxfmtctl);
+       mcasp_set_reg(base + DAVINCI_MCASP_TXFMT_REG, a->context.txfmt);
+       mcasp_set_reg(base + DAVINCI_MCASP_RXFMT_REG, a->context.rxfmt);
+       mcasp_set_reg(base + DAVINCI_MCASP_ACLKXCTL_REG, a->context.aclkxctl);
+       mcasp_set_reg(base + DAVINCI_MCASP_ACLKRCTL_REG, a->context.aclkrctl);
+       mcasp_set_reg(base + DAVINCI_MCASP_PDIR_REG, a->context.pdir);
+
+       return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
+                 davinci_mcasp_suspend,
+                 davinci_mcasp_resume);
+
 static struct platform_driver davinci_mcasp_driver = {
        .probe          = davinci_mcasp_probe,
        .remove         = davinci_mcasp_remove,
        .driver         = {
                .name   = "davinci-mcasp",
                .owner  = THIS_MODULE,
+               .pm     = &davinci_mcasp_pm_ops,
                .of_match_table = mcasp_dt_ids,
        },
 };
@@ -1266,4 +1332,3 @@ module_platform_driver(davinci_mcasp_driver);
 MODULE_AUTHOR("Steve Chen");
 MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
 MODULE_LICENSE("GPL");
-
index a9ac0c11da71dd784ed26286e46d064f0cca66c9..a2e27e1c32f3b28a8600ea0bb5325a35f7fe9741 100644 (file)
@@ -43,6 +43,18 @@ struct davinci_audio_dev {
        /* McASP FIFO related */
        u8      txnumevt;
        u8      rxnumevt;
+
+#ifdef CONFIG_PM_SLEEP
+       struct {
+               u32     txfmtctl;
+               u32     rxfmtctl;
+               u32     txfmt;
+               u32     rxfmt;
+               u32     aclkxctl;
+               u32     aclkrctl;
+               u32     pdir;
+       } context;
+#endif
 };
 
 #endif /* DAVINCI_MCASP_H */