Thanks very much, that was a problem. But now another error appears:
"davinci_evm sound: ASoC: machine hw_params failed: -524". Do you know what
it means, or where can i find the meaning? I assume this means there is
something wrong when i created the pcm3168_hw_params in the alsa machine
layer... but i don't know the problem... where did you look for info? only
in that TI guide? I attach my files, and if is not much trouble for you i
would be grateful if you help me...
i've noticed that some functions you used in davinci_evm.c where not
explained in that guide... and it's very difficult for a noob like me in
this subject for understainding what to do... I've just based my pcm3168.c
in another driver, and i really don't quite understand much of what is
going on, nor found any simple documentation about it. If you could give me
some hints it would be great!
Thanks very much..
2016-01-07 17:30 GMT-03:00 Robin Scheibler <[email protected]>:
> Hi Pablo,
>
> With McASP it is not possible to capture less than 2 channels. Try with -c
> 2 argument.
>
> Best,
> Robin
>
> On 7 janv. 2016, at 20:16, [email protected] wrote:
>
> Hi Robin:
>
> I'm doing a similar project, but with a PCM3168 codec... I also followed
> the guide
> http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_DAC_Example
> Anyway there are lots of things that are not very clear for me...
> <http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_DAC_Example>
>
> In my case, i use codec as clock slave, and synch, so the problem you had
> should not affect to me... But when i try to record it says:
>
> arecord -D hw:0,0 -f S24_LE -c 1 -r 96000 -t wav test.wav
> Recording WAVE 'test.wav' : Signed 24 bit Little Endian, Rate 96000 Hz,
> Mono
> arecord: set_params:1239: Channels count non available
>
> Could you help me?
>
> On Sunday, May 24, 2015 at 4:38:43 AM UTC-3, Robin Scheibler wrote:
>>
>> Dear all,
>>
>> I have created a custom cape around the STA321MP
>> <http://www.st.com/web/en/catalog/sense_power/FM125/CL935/SC534/PF251500d.d24>
>> chip from ST Microelectronics. It has 6 MEMS microphones and outputs them
>> on an I2S bus with 3 data lines. I am trying to use mcasp0 on the boneblack
>> side to receive the data. I am now to the point where the codec
>> configuration happens correctly (I can see the i2s signals with a logic
>> analyzer) and a soundcard is detected. However, when I try to record sound
>> with arecord, I get the following error:
>>
>> root@beaglebone:~# arecord -l
>>> **** List of CAPTURE Hardware Devices ****
>>> card 0: EVM [STA321MP EVM], device 0: STA321MP sta321mp-audio-0 []
>>> Subdevices: 1/1
>>> Subdevice #0: subdevice #0
>>> root@beaglebone:~# arecord -D hw:0,0 -f S24_LE -c 6 -r 44100 -t wav
>>> test.wav
>>> Recording WAVE 'test.wav' : Signed 24 bit Little Endian, Rate 44100 Hz,
>>> Channels 6
>>> arecord: pcm_read:1801: read error: Input/output error
>>>
>>
>> Let me know provide more details.
>>
>> - The codec is frame and bit clocks master
>> - The connection to mcasp0 is the following:
>> - Bit clock <=> P9_12 (mcasp0_aclkr_mux3)
>> - Frame sync clock (L/R) <=> P9_27 (mcasp0_fsr)
>> - Data <=> P9_28 (mcasp0_axr2)
>> - Data <=> P9_30 (mcasp0_axr0)
>> - Data <=> P9_25 (mcasp0_axr3)
>> - I am using kernel 3.14.41 (because 3.8 doesn't have support for
>> mcasp with >2 channels)
>> - I am using dtb-builder to add my device to the device tree
>>
>> All the code I have added to the kernel (codec and machine code) and to
>> the device tree is on github. Here are the links to the specific changes I
>> have made.
>>
>> kernel:
>> https://github.com/fakufaku/linux/commit/3a6680960412ef0fc3fbcc6f2c0021350039cc92
>>
>> device tree:
>> https://github.com/fakufaku/dtb-rebuilder/commit/127dbf3c82c78cc602058308ed72978b170c99a6
>>
>> It is my first time trying to code audio driver so please be indulgent :)
>> I have spent a lot of time on this but it seems I am now completely stuck.
>> I'd really appreciate some help. I'd be happy to provide more
>> clarifications on anything.
>> One thing I do not understand is if I need to add mixer bindings. And
>> also the audio routing (jack vs codec pins, etc).
>>
>> Thank you in advance!
>> Robin
>>
>
> --
> For more options, visit http://beagleboard.org/discuss
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "BeagleBoard" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/beagleboard/pptZ_9PTqMY/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> [email protected].
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> For more options, visit http://beagleboard.org/discuss
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "BeagleBoard" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/beagleboard/pptZ_9PTqMY/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> [email protected].
> For more options, visit https://groups.google.com/d/optout.
>
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
/*
* PCM3168 ASoC codec driver
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#define PCM3168_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
#define PCM3168_PCM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
SNDRV_PCM_RATE_96000)
#define PCM3168_DEEMPH_CONTROL 0x46
#define PCM3168_ATT_CONTROL(X) (X <=6 ? X : X+9)
#define PCM3168_SOFT_MUTE_CONTROL 0x44
#define PCM3168_DAC_FMT_CONTROL 0x41
#define PCM3168_DEEMPH_MASK 0x01
#define PCM3168_DEEMPH_RATE_MASK 0x30
static const struct reg_default pcm3168_reg_defaults[] = {
{ 0x40, 0xC2 },
{ 0x41, 0x06 },
{ 0x42, 0x00 },
{ 0x43, 0x00 },
{ 0x44, 0x00 },
{ 0x46, 0x18 },
{ 0x47, 0xff },
{ 0x48, 0xff },
{ 0x49, 0xff },
{ 0x4A, 0xff },
{ 0x4B, 0xff },
{ 0x4C, 0xff },
{ 0x4D, 0xff },
{ 0x4E, 0xff },
{ 0x4F, 0xff },
{ 0x50, 0x02 },
{ 0x51, 0x06 },
{ 0x52, 0x00 },
{ 0x53, 0x00 },
{ 0x54, 0x00 },
{ 0x55, 0x00 },
{ 0x57, 0x00 },
{ 0x58, 0xD7 },
{ 0x59, 0xD7 },
{ 0x5A, 0xD7 },
{ 0x5B, 0xD7 },
{ 0x5C, 0xD7 },
{ 0x5D, 0xD7 },
{ 0x5E, 0xD7 },
};
static bool pcm3168_accessible_reg(struct device *dev, unsigned int reg)
{
return !((reg < 0x40) || (reg > 0x5E));
}
static bool pcm3168_writeable_reg(struct device *dev, unsigned register reg)
{
return pcm3168_accessible_reg(dev, reg) &&
(reg != 0x45) && (reg != 56);
}
struct pcm3168_private {
struct regmap *regmap;
unsigned int format;
/* Current deemphasis status */
unsigned int deemph;
/* Current rate for deemphasis control */
unsigned int rate;
};
static const int pcm3168_deemph[] = {0, 44100, 48000, 32000 };
static int pcm3168_set_deemph(struct snd_soc_codec *codec)
{
struct pcm3168_private *priv = snd_soc_codec_get_drvdata(codec);
int i = 0, val = -1;
if (priv->deemph)
for (i = 0; i < ARRAY_SIZE(pcm3168_deemph); i++)
if (pcm3168_deemph[i] == priv->rate)
val = i;
return regmap_update_bits(priv->regmap, PCM3168_DEEMPH_CONTROL,
PCM3168_DEEMPH_RATE_MASK, val << 4);
}
static int pcm3168_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm3168_private *priv = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = priv->deemph;
return 0;
}
static int pcm3168_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm3168_private *priv = snd_soc_codec_get_drvdata(codec);
priv->deemph = ucontrol->value.integer.value[0];
return pcm3168_set_deemph(codec);
}
static int pcm3168_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int format)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct pcm3168_private *priv = snd_soc_codec_get_drvdata(codec);
priv->format = format;
return 0;
}
static int pcm3168_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct pcm3168_private *priv = snd_soc_codec_get_drvdata(codec);
int val=mute;
return regmap_write(priv->regmap, PCM3168_SOFT_MUTE_CONTROL, val);
}
static int pcm3168_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = dai->codec;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct pcm3168_private *priv = snd_soc_codec_get_drvdata(codec);
int val = 0, ret;
priv->rate = params_rate(params);
switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
switch (params_width(params)) {
case 24:
val = 0x02;
break;
case 16:
val = 0x03;
break;
default:
return -EINVAL;
}
break;
case SND_SOC_DAIFMT_I2S:
val = 0x00;
break;
case SND_SOC_DAIFMT_LEFT_J:
val = 0x01;
default:
dev_err(codec->dev, "Invalid DAI format\n");
return -EINVAL;
}
ret = regmap_update_bits(priv->regmap, PCM3168_DAC_FMT_CONTROL, 0x0f, val);
if (ret < 0)
return ret;
return pcm3168_set_deemph(codec);
}
static const struct snd_soc_dai_ops pcm3168_dai_ops = {
.set_fmt = pcm3168_set_dai_fmt,
.hw_params = pcm3168_hw_params,
.digital_mute = pcm3168_digital_mute,
};
static const struct snd_soc_dapm_widget pcm3168_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("VOUT1"),
SND_SOC_DAPM_OUTPUT("VOUT2"),
SND_SOC_DAPM_OUTPUT("VOUT3"),
SND_SOC_DAPM_OUTPUT("VOUT4"),
SND_SOC_DAPM_OUTPUT("VOUT5"),
SND_SOC_DAPM_OUTPUT("VOUT6"),
SND_SOC_DAPM_OUTPUT("VOUT7"),
SND_SOC_DAPM_OUTPUT("VOUT8"),
SND_SOC_DAPM_INPUT("VIN1"),
SND_SOC_DAPM_INPUT("VIN2"),
SND_SOC_DAPM_INPUT("VIN3"),
SND_SOC_DAPM_INPUT("VIN4"),
SND_SOC_DAPM_INPUT("VIN5"),
SND_SOC_DAPM_INPUT("VIN6"),
};
static const struct snd_soc_dapm_route pcm3168_dapm_routes[] = {
{ "VOUT1", NULL, "Playback" },
{ "VOUT2", NULL, "Playback" },
{ "VOUT3", NULL, "Playback" },
{ "VOUT4", NULL, "Playback" },
{ "VOUT5", NULL, "Playback" },
{ "VOUT6", NULL, "Playback" },
{ "VOUT7", NULL, "Playback" },
{ "VOUT8", NULL, "Playback" },
{ "VIN1", NULL, "Capture" },
{ "VIN2", NULL, "Capture" },
{ "VIN3", NULL, "Capture" },
{ "VIN4", NULL, "Capture" },
{ "VIN5", NULL, "Capture" },
{ "VIN6", NULL, "Capture" },
};
static const DECLARE_TLV_DB_SCALE(pcm3168_dac_tlv, -6350, 50, 1);
static const DECLARE_TLV_DB_SCALE(pcm3168_adc_tlv, -6350, 50, 1);
static const struct snd_kcontrol_new pcm3168_controls[] = {
SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
PCM3168_ATT_CONTROL(1), PCM3168_ATT_CONTROL(2), 0,
0x7f, 0, pcm3168_dac_tlv),
SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
PCM3168_ATT_CONTROL(3), PCM3168_ATT_CONTROL(4), 0,
0x7f, 0, pcm3168_dac_tlv),
SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
PCM3168_ATT_CONTROL(5), PCM3168_ATT_CONTROL(6), 0,
0x7f, 0, pcm3168_dac_tlv),
SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume",
PCM3168_ATT_CONTROL(7), PCM3168_ATT_CONTROL(8), 0,
0x7f, 0, pcm3168_dac_tlv),
SOC_DOUBLE_R_TLV("Channel 1/2 Capture Volume",
PCM3168_ATT_CONTROL(9), PCM3168_ATT_CONTROL(10), 0,
0x7f, 0, pcm3168_adc_tlv),
SOC_DOUBLE_R_TLV("Channel 3/4 Capture Volume",
PCM3168_ATT_CONTROL(11), PCM3168_ATT_CONTROL(12), 0,
0x7f, 0, pcm3168_adc_tlv),
SOC_DOUBLE_R_TLV("Channel 5/6 Capture Volume",
PCM3168_ATT_CONTROL(13), PCM3168_ATT_CONTROL(14), 0,
0x7f, 0, pcm3168_adc_tlv),
SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
pcm3168_get_deemph, pcm3168_put_deemph),
};
static struct snd_soc_dai_driver pcm3168_dai = {
.name = "pcm3168-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 8,
.rates = PCM3168_PCM_RATES,
.formats = PCM3168_PCM_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 6,
.rates = PCM3168_PCM_RATES,
.formats = PCM3168_PCM_FORMATS,
},
.ops = &pcm3168_dai_ops,
};
#ifdef CONFIG_OF
static const struct of_device_id pcm3168_dt_ids[] = {
{ .compatible = "ti,pcm3168", },
{ }
};
MODULE_DEVICE_TABLE(of, pcm3168_dt_ids);
#endif
static const struct regmap_config pcm3168_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x5E,
.reg_defaults = pcm3168_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(pcm3168_reg_defaults),
.writeable_reg = pcm3168_writeable_reg,
.readable_reg = pcm3168_accessible_reg,
};
static struct snd_soc_codec_driver soc_codec_dev_pcm3168 = {
.controls = pcm3168_controls,
.num_controls = ARRAY_SIZE(pcm3168_controls),
.dapm_widgets = pcm3168_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(pcm3168_dapm_widgets),
.dapm_routes = pcm3168_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(pcm3168_dapm_routes),
};
static const struct i2c_device_id pcm3168_i2c_id[] = {
{"pcm3168", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pcm3168_i2c_id);
static int pcm3168_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct pcm3168_private *priv;
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = devm_regmap_init_i2c(client, &pcm3168_regmap);
if (IS_ERR(priv->regmap)) {
ret = PTR_ERR(priv->regmap);
dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
return ret;
}
i2c_set_clientdata(client, priv);
return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm3168,
&pcm3168_dai, 1);
}
static int pcm3168_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
return 0;
}
static struct i2c_driver pcm3168_i2c_driver = {
.driver = {
.name = "pcm3168",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcm3168_dt_ids),
},
.id_table = pcm3168_i2c_id,
.probe = pcm3168_i2c_probe,
.remove = pcm3168_i2c_remove,
};
module_i2c_driver(pcm3168_i2c_driver);
MODULE_DESCRIPTION("Texas Instruments PCM3168 ALSA SoC Codec Driver");
MODULE_AUTHOR("Pablo Fonovich");
MODULE_LICENSE("GPL");
/*
* ASoC driver for TI DAVINCI EVM platform
*
* Author: Vladimir Barinov, <[email protected]>
* Copyright: (C) 2007 MontaVista Software, Inc., <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/dma.h>
#include <asm/mach-types.h>
struct snd_soc_card_drvdata_davinci {
struct clk *mclk;
unsigned sysclk;
};
static int evm_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *soc_card = rtd->card;
struct snd_soc_card_drvdata_davinci *drvdata =
snd_soc_card_get_drvdata(soc_card);
if (drvdata->mclk)
return clk_prepare_enable(drvdata->mclk);
return 0;
}
static void evm_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *soc_card = rtd->card;
struct snd_soc_card_drvdata_davinci *drvdata =
snd_soc_card_get_drvdata(soc_card);
if (drvdata->mclk)
clk_disable_unprepare(drvdata->mclk);
}
static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
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_card *soc_card = rtd->card;
int ret = 0;
unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
snd_soc_card_get_drvdata(soc_card))->sysclk;
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
/* set the CPU system clock */
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
return 0;
}
static int pcm3168_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
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 = rtd->card;
struct platform_device *pdev = to_platform_device(soc_card->dev);
int ret = 0;
unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
snd_soc_card_get_drvdata(soc_card))->sysclk;
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
/* set the CPU system clock */
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_ops evm_ops = {
.startup = evm_startup,
.shutdown = evm_shutdown,
.hw_params = evm_hw_params,
};
static struct snd_soc_ops pcm3168_ops = {
.startup = evm_startup,
.shutdown = evm_shutdown,
.hw_params = pcm3168_hw_params,
};
/* davinci-evm machine dapm widgets */
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
/* davinci-evm machine audio_mapnections to the codec pins */
static const struct snd_soc_dapm_route audio_map[] = {
/* Headphone connected to HPLOUT, HPROUT */
{"Headphone Jack", NULL, "HPLOUT"},
{"Headphone Jack", NULL, "HPROUT"},
/* Line Out connected to LLOUT, RLOUT */
{"Line Out", NULL, "LLOUT"},
{"Line Out", NULL, "RLOUT"},
/* Mic connected to (MIC3L | MIC3R) */
{"MIC3L", NULL, "Mic Bias"},
{"MIC3R", NULL, "Mic Bias"},
{"Mic Bias", NULL, "Mic Jack"},
/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
{"LINE1L", NULL, "Line In"},
{"LINE2L", NULL, "Line In"},
{"LINE1R", NULL, "Line In"},
{"LINE2R", NULL, "Line In"},
};
/* Logic for a aic3x as connected on a davinci-evm */
static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct device_node *np = card->dev->of_node;
int ret;
/* Add davinci-evm specific widgets */
snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
if (np) {
ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
if (ret)
return ret;
} else {
/* Set up davinci-evm specific audio path audio_map */
snd_soc_dapm_add_routes(&card->dapm, audio_map,
ARRAY_SIZE(audio_map));
}
/* not connected */
snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT");
snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM");
snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM");
return 0;
}
/* davinci-evm digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link dm6446_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcbsp",
.codec_dai_name = "tlv320aic3x-hifi",
.codec_name = "tlv320aic3x-codec.1-001b",
.platform_name = "davinci-mcbsp",
.init = evm_aic3x_init,
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
};
//Agregado por mi/////////////////////////////////////////////////////////////////
static struct snd_soc_dai_link evm_dai_pcm3168 = {
.name = "PCM3168",
.stream_name = "Playback",
.codec_dai_name = "pcm3168-hifi",
.ops = &pcm3168_ops,
.dai_fmt = (SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_IB_NF),
};
//////////////////////////////////////////////////////////////////////////////////
static struct snd_soc_dai_link dm355_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcbsp.1",
.codec_dai_name = "tlv320aic3x-hifi",
.codec_name = "tlv320aic3x-codec.1-001b",
.platform_name = "davinci-mcbsp.1",
.init = evm_aic3x_init,
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
};
static struct snd_soc_dai_link dm365_evm_dai = {
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcbsp",
.codec_dai_name = "tlv320aic3x-hifi",
.codec_name = "tlv320aic3x-codec.1-0018",
.platform_name = "davinci-mcbsp",
.init = evm_aic3x_init,
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.stream_name = "CQ93",
.cpu_dai_name = "davinci-vcif",
.codec_dai_name = "cq93vc-hifi",
.codec_name = "cq93vc-codec",
.platform_name = "davinci-vcif",
#endif
};
static struct snd_soc_dai_link dm6467_evm_dai[] = {
{
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name= "davinci-mcasp.0",
.codec_dai_name = "tlv320aic3x-hifi",
.platform_name = "davinci-mcasp.0",
.codec_name = "tlv320aic3x-codec.0-001a",
.init = evm_aic3x_init,
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
},
{
.name = "McASP",
.stream_name = "spdif",
.cpu_dai_name= "davinci-mcasp.1",
.codec_dai_name = "dit-hifi",
.codec_name = "spdif_dit",
.platform_name = "davinci-mcasp.1",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
},
};
static struct snd_soc_dai_link da830_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcasp.1",
.codec_dai_name = "tlv320aic3x-hifi",
.codec_name = "tlv320aic3x-codec.1-0018",
.platform_name = "davinci-mcasp.1",
.init = evm_aic3x_init,
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
};
static struct snd_soc_dai_link da850_evm_dai = {
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name= "davinci-mcasp.0",
.codec_dai_name = "tlv320aic3x-hifi",
.codec_name = "tlv320aic3x-codec.1-0018",
.platform_name = "davinci-mcasp.0",
.init = evm_aic3x_init,
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
};
/* 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 = {
.name = "DA830/OMAP-L137 EVM",
.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 = {
.name = "DA850/OMAP-L138 EVM",
.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,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
};
static const struct of_device_id davinci_evm_dt_ids[] = {
{
.compatible = "ti,da830-evm-audio",
.data = (void *) &evm_dai_tlv320aic3x,
},
{
.compatible= "ti,pcm3168-evm-audio",
.data = &evm_dai_pcm3168,
},
{
.compatible = "ti,da830-evm-audio",
.data = &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;
struct clk *mclk;
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;
mclk = devm_clk_get(&pdev->dev, "mclk");
if (PTR_ERR(mclk) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (IS_ERR(mclk)) {
dev_dbg(&pdev->dev, "mclk not found.\n");
mclk = NULL;
}
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->mclk = mclk;
ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
if (ret < 0) {
if (!drvdata->mclk) {
dev_err(&pdev->dev,
"No clock or clock rate defined.\n");
return -EINVAL;
}
drvdata->sysclk = clk_get_rate(drvdata->mclk);
} else if (drvdata->mclk) {
unsigned int requestd_rate = drvdata->sysclk;
clk_set_rate(drvdata->mclk, drvdata->sysclk);
drvdata->sysclk = clk_get_rate(drvdata->mclk);
if (drvdata->sysclk != requestd_rate)
dev_warn(&pdev->dev,
"Could not get requested rate %u using %u.\n",
requestd_rate, drvdata->sysclk);
}
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 struct platform_driver davinci_evm_driver = {
.probe = davinci_evm_probe,
.driver = {
.name = "davinci_evm",
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(davinci_evm_dt_ids),
},
};
#endif
static struct platform_device *evm_snd_device;
static int __init evm_init(void)
{
struct snd_soc_card *evm_snd_dev_data;
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;
} else if (machine_is_davinci_dm355_evm()) {
evm_snd_dev_data = &dm355_snd_soc_card_evm;
index = 1;
} else if (machine_is_davinci_dm365_evm()) {
evm_snd_dev_data = &dm365_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_dm6467_evm()) {
evm_snd_dev_data = &dm6467_snd_soc_card_evm;
index = 0;
} else if (machine_is_davinci_da830_evm()) {
evm_snd_dev_data = &da830_snd_soc_card;
index = 1;
} else if (machine_is_davinci_da850_evm()) {
evm_snd_dev_data = &da850_snd_soc_card;
index = 0;
} else
return -EINVAL;
evm_snd_device = platform_device_alloc("soc-audio", index);
if (!evm_snd_device)
return -ENOMEM;
platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
ret = platform_device_add(evm_snd_device);
if (ret)
platform_device_put(evm_snd_device);
return ret;
}
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);
}
module_init(evm_init);
module_exit(evm_exit);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
MODULE_LICENSE("GPL");