Merge remote-tracking branch 'asoc/topic/davinci' into asoc-next
This commit is contained in:
Коммит
cf44fba089
|
@ -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";
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -84,6 +84,8 @@ struct snd_platform_data {
|
|||
u8 version;
|
||||
u8 txnumevt;
|
||||
u8 rxnumevt;
|
||||
int tx_dma_channel;
|
||||
int rx_dma_channel;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
@ -23,10 +24,16 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче