Re: Imx6 i2s master driver without i2c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Ok I'm almost there

Now I have an audio driver that works in both recording / playing

The only bug that I have is this:

I have this function that set the clock based on the stream properties
i tested it with:   speaker-test -r 48000

Playback device is default
Stream parameters are 48000Hz, S16_LE, 1 channels
Using 16 octaves of pink noise
Rate set to 48000Hz (requested 48000Hz)
Buffer size range from 3840 to 17280
Period size range from 1920 to 1920
Using max buffer size 17280


but my function get everytime 44100 no matter what I put in -r parameter as
playback frequency!!!!

configuration rate=44100, format=2, channels=2, bclk=2822400
fsl-ssi-dai 202c000.ssi: set tdm slots channels=2
fsl-ssi-dai 202c000.ssi: set ssi bclk NAME=202c000.ssi

what I'm missing??

and the function

snd_soc_dai_set_pll(cpu_dai, 0, 0, 24000000, itel_audio_fmts[i].sysclk);

is correct??? I need to set pll4 frequency based on rate

/*****************************************************************************************************************************************************
static int imx_itel_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 *cpu_dai = rtd->cpu_dai;
    snd_pcm_format_t format = params_format(params);
    u32 channels = params_channels(params);
    u32 rate     = params_rate(params);
    u32 bclk = rate * channels * 32;
    int ret = 0, i;

    dev_info(cpu_dai->dev, "set cpu DAI configuration rate=%d, format=%d,
channels=%d, bclk=%d\n", rate, format, channels, bclk);

    /* find the correct audio parameters */
    for (i = 0; i < ARRAY_SIZE(itel_audio_fmts); i++) {
        if (rate == itel_audio_fmts[i].rate)
        {
            ret = 1;
            break;
        }
    }
    if (!ret)
        return -EINVAL;

    /* codec FLL input is 14.75 MHz from MCLK */
    /**
     * snd_soc_dai_set_pll - configure DAI PLL.
     * @dai: DAI
     * @pll_id: DAI specific PLL ID
     * @source: DAI specific source for the PLL
     * @freq_in: PLL input clock frequency in Hz
     * @freq_out: requested PLL output clock frequency in Hz
     *
     * Configures and enables PLL to generate output clock based on input
clock.
     */
    // snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out);

    snd_soc_dai_set_pll(cpu_dai, 0, 0, 24000000, itel_audio_fmts[i].sysclk);

    /* set cpu DAI configuration */
    ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
    if (ret) {
        dev_err(cpu_dai->dev, "failed to set dai fmt\n");
        return ret;
    }

    dev_info(cpu_dai->dev, "set tdm slots channels=%d", channels);

    ret = snd_soc_dai_set_tdm_slot(cpu_dai, channels == 1 ? 0xfffffffe :
0xfffffffc, channels == 1 ? 0xfffffffe : 0xfffffffc, 2, 32);
    if (ret) {
        dev_err(cpu_dai->dev, "failed to set dai tdm slot\n");
        return ret;
    }

    dev_info(cpu_dai->dev, "set ssi bclk NAME=%s \n",cpu_dai->name);
    /* set clock */
    ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, bclk,
SND_SOC_CLOCK_OUT);
    if (ret)
        dev_err(cpu_dai->dev, "failed to set sysclk\n");

    return ret;
}



2016-05-13 21:30 GMT+02:00 Caleb Crome <caleb@xxxxxxxxx>:

>
>
> On Fri, May 13, 2016 at 12:59 AM, nick83ola <nick83ola@xxxxxxxxx> wrote:
>
>> Caleb thanks for your help!!!! the documentation is really orrible!!!!
>>
>> but now I'm getting something out of TXD!!!!
>>
>
> Wooo!
>
>
>>
>> only no clock and very fast (I think that I need to configure the
>> oscillator/pll and iomux???)
>>
>
> Right, I wish I understood how to do that.  I don't.  It's got something
> to do with some function called 'clock' I bet :-)  Or maybe 'clk'.  Or
> maybe in the DTS and not a function call...
>
>
>>
>> In my kernel (3.14.28-1.0.0_ga+g91cf351) some of the statement in you dts
>> are not supported in simple driver so I stripped down the imx-si476 driver
>> and use with your dummy codec driver
>>
>
> Yeah, that's the problem with old kernels.  I try to just look towards the
> future :-)
>
> I'm glad things are working, and thanks for posting your working DTS.
> Having your DTS here may help the next guy with an old kernel.
>
> Cheers
> -Caleb
>
>
>>
>> &audmux {
>>     pinctrl-names = "default";
>>     pinctrl-0 = <&pinctrl_audmux_4>;
>>     status = "okay";
>> };
>>
>> &ssi2 {
>>     assigned-clocks = <&clks IMX6QDL_CLK_SSI2_SEL>;
>>     assigned-clock-parents = <&clks IMX6QDL_CLK_PLL4_AUDIO_DIV>;
>>     assigned-clock-rates = <0>;
>>     fsl,mode = "i2s-master";
>>     status = "okay";
>> };
>>
>>
>> / {
>>     model = "Engicam i.CoreM6 DualLite/Solo starterkit";
>>     compatible = "fsl,imx6-icore", "fsl,imx6dl";
>>
>>     codec_test: codec_test {
>>         compatible = "linux,snd-soc-dummy";
>>         status = "okay";
>>     };
>>
>>     sound {
>>         compatible = "fsl,imx-audio-itel";
>>         model = "imx-itel";
>>         ssi-controller = <&ssi2>;
>>         audio-codec = <&codec_test>;
>>         mux-int-port = <4>;
>>         mux-ext-port = <2>;
>>         status = "okay";
>>     };
>>
>>     sound-hdmi {
>>         status = "disabled";
>>     };
>> };
>>
>>
>> &iomuxc {
>>     audmux {
>>         pinctrl_audmux_4: audmux-4 {
>>             fsl,pins = <
>>                 MX6QDL_PAD_DISP0_DAT20__AUD4_TXC  0x130b0
>>                 MX6QDL_PAD_DISP0_DAT21__AUD4_TXD 0x110b0
>>                 MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS  0x130b0
>>                 MX6QDL_PAD_DISP0_DAT23__AUD4_RXD  0x130b0
>>             >;
>>         };
>>     };
>> };
>>
>>
>> ======================================================================================================================
>> imx-itel.c
>>
>> ======================================================================================================================
>>
>>
>> /*
>>  * Copyright (C) 2013 Freescale Semiconductor, Inc.
>>  *
>>  * The code contained herein is licensed under the GNU General Public
>>  * License. You may obtain a copy of the GNU General Public License
>>  * Version 2 or later at the following locations:
>>  *
>>  * http://www.opensource.org/licenses/gpl-license.html
>>  * http://www.gnu.org/copyleft/gpl.html
>>  */
>>
>> #define DEBUG 1
>>
>> #include <linux/module.h>
>> #include <linux/of.h>
>> #include <linux/of_platform.h>
>> #include <linux/device.h>
>> #include <linux/clk.h>
>> #include <sound/core.h>
>> #include <sound/pcm.h>
>> #include <sound/soc.h>
>> #include <sound/initval.h>
>> #include <sound/pcm_params.h>
>>
>> #include "imx-audmux.h"
>>
>> struct imx_itel_data {
>>     struct snd_soc_dai_link dai;
>>     struct snd_soc_card card;
>> };
>>
>>
>> static int imx_audmux_config(int slave, int master)
>> {
>>     unsigned int ptcr, pdcr;
>>     slave = slave - 1;
>>     master = master - 1;
>>
>>     ptcr = IMX_AUDMUX_V2_PTCR_SYN |
>>         IMX_AUDMUX_V2_PTCR_TFSDIR |
>>         IMX_AUDMUX_V2_PTCR_TFSEL(slave) |
>>         IMX_AUDMUX_V2_PTCR_TCLKDIR |
>>         IMX_AUDMUX_V2_PTCR_TCSEL(slave);
>>     pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave);
>>
>>     imx_audmux_v2_configure_port(master, ptcr, pdcr);
>>
>>     /*
>>      * According to RM, RCLKDIR and SYN should not be changed at same
>> time.
>>      * So separate to two step for configuring this port.
>>      */
>>     ptcr |= IMX_AUDMUX_V2_PTCR_RFSDIR |
>>         IMX_AUDMUX_V2_PTCR_RFSEL(slave) |
>>         IMX_AUDMUX_V2_PTCR_RCLKDIR |
>>         IMX_AUDMUX_V2_PTCR_RCSEL(slave);
>>     imx_audmux_v2_configure_port(master, ptcr, pdcr);
>>
>>     printk(KERN_ERR "--> ITEL imx-audmux-confic ext-port port=%#010x
>> ptcr=%#010x pdcr=%#010x\n", master, ptcr, pdcr);
>>
>>     ptcr = IMX_AUDMUX_V2_PTCR_SYN;
>>     pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master);
>>
>>     printk(KERN_ERR "--> ITEL imx-audmux-config int-port port=%#010x
>> ptcr=%#010x pdcr=%#010x\n", master, ptcr, pdcr);
>>     imx_audmux_v2_configure_port(slave, ptcr, pdcr);
>>
>>     return 0;
>> }
>>
>>
>> static int imx_itel_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 *cpu_dai = rtd->cpu_dai;
>>     u32 channels = params_channels(params);
>>     u32 rate = params_rate(params);
>>     u32 bclk = rate * channels * 32;
>>     int ret = 0;
>>
>>     printk(KERN_ERR "--> ITEL imx-itel-hw-params NAME=%s  \n
>> VALUE=%#010x  "
>>                         "SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
>> SND_SOC_DAIFMT_CBS_CFS\n",
>>                         cpu_dai->name,
>>                         (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
>> SND_SOC_DAIFMT_CBS_CFS));
>>
>>     /* set cpu DAI configuration */
>>     ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
>>             | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
>>     if (ret) {
>>         dev_err(cpu_dai->dev, "failed to set dai fmt\n");
>>         return ret;
>>     }
>>     printk(KERN_ERR "--> ITEL imx-itel-hw-params set tdm slots
>> channels=%d", channels);
>>
>>     ret = snd_soc_dai_set_tdm_slot(cpu_dai,
>>             channels == 1 ? 0xfffffffe : 0xfffffffc,
>>             channels == 1 ? 0xfffffffe : 0xfffffffc,
>>             2, 32);
>>     if (ret) {
>>         dev_err(cpu_dai->dev, "failed to set dai tdm slot\n");
>>         return ret;
>>     }
>>
>>     printk(KERN_ERR "--> ITEL imx-audmux-config set sysclk NAME=%s
>> \n",cpu_dai->name);
>>
>>     ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT);
>>     if (ret)
>>         dev_err(cpu_dai->dev, "failed to set sysclk\n");
>>
>>     return ret;
>> }
>>
>>
>> static struct snd_soc_ops imx_itel_ops = {
>>     .hw_params = imx_itel_hw_params,
>> };
>>
>>
>> static struct snd_soc_dai_link imx_itel_dai[] = {
>>     {
>>         .name            = "Hifi",
>>         .stream_name     = "Hifi",
>>         .codec_dai_name     = "snd-soc-dummy-dai",
>>         //.codec_name         = "snd-soc-dummy",
>>         .ops             = &imx_itel_ops,
>>         // .symmetric_rates = 1,
>>     },
>> };
>>
>> static struct snd_soc_card snd_soc_card_imx_itel = {
>>     .name       = "imx-audio-itel",
>>     .dai_link   = imx_itel_dai,
>>     .num_links    = ARRAY_SIZE(imx_itel_dai),
>>     .owner      = THIS_MODULE,
>> };
>>
>>
>> static int imx_itel_probe(struct platform_device *pdev)
>> {
>>     struct snd_soc_card *card = &snd_soc_card_imx_itel;
>>     struct device_node *ssi_np;
>>     struct platform_device *ssi_pdev;
>>     struct device_node *codec_np;
>>     // struct imx_itel_data *data = NULL;
>>     int int_port, ext_port, ret;
>>
>>     printk(KERN_ERR "--> ITEL imx_itel_probe");
>>
>>     ret = of_property_read_u32(pdev->dev.of_node, "mux-int-port",
>> &int_port);
>>     if (ret) {
>>         dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
>>         return ret;
>>     }
>>
>>
>>     ret = of_property_read_u32(pdev->dev.of_node, "mux-ext-port",
>> &ext_port);
>>     if (ret) {
>>         dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
>>         return ret;
>>     }
>>
>>     printk(KERN_ERR "--> ITEL Configuro audmux\n");
>>     imx_audmux_config(int_port, ext_port);
>>
>>     /* find value in devicetree for ssi controller */
>>     ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
>>     if (!ssi_np) {
>>         dev_err(&pdev->dev, "ssi-controller missing or invalid\n");
>>         ret = -EINVAL;
>>         goto fail;
>>     }
>>
>>     /* find SSI platform driver */
>>     ssi_pdev = of_find_device_by_node(ssi_np);
>>     if (!ssi_pdev) {
>>         dev_err(&pdev->dev, "failed to find SSI platform device\n");
>>         ret = -EPROBE_DEFER;
>>         goto fail;
>>     }
>>
>>     codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
>>     if (!codec_np) {
>>         dev_err(&pdev->dev, "codec missing or invalid\n");
>>         ret = -EINVAL;
>>         goto fail;
>>     }
>>
>>     // codec_dev = NULL;
>>
>>     card->dev = &pdev->dev;
>>     card->dai_link->cpu_dai_name = dev_name(&ssi_pdev->dev);
>>     card->dai_link->platform_of_node = ssi_np;
>>     card->dai_link->codec_of_node = codec_np;
>>
>>     platform_set_drvdata(pdev, card);
>>     snd_soc_card_set_drvdata(card, &snd_soc_card_imx_itel);
>>
>>     printk(KERN_ERR "--> ITEL imx-probe registro card\n");
>>
>>     ret = snd_soc_register_card(card);
>>     if (ret) {
>>         dev_err(&pdev->dev, "Failed to register card: %d\n", ret);
>>         goto fail;
>>     }
>>
>>     printk(KERN_ERR "--> ITEL imx-probe of ssi\n");
>>     of_node_put(ssi_np);
>>     printk(KERN_ERR "--> ITEL imx-probe of codec\n");
>>     of_node_put(codec_np);
>>
>>     return 0;
>>
>> fail:
>>     if (ssi_np)
>>         of_node_put(ssi_np);
>>     if (codec_np)
>>         of_node_put(codec_np);
>>
>>     return ret;
>> }
>>
>> static int imx_itel_remove(struct platform_device *pdev)
>> {
>>     struct snd_soc_card *card = &snd_soc_card_imx_itel;
>>
>>     snd_soc_unregister_card(card);
>>
>>     return 0;
>> }
>>
>> static const struct of_device_id imx_itel_dt_ids[] = {
>>     { .compatible = "fsl,imx-audio-itel", },
>>     { /* sentinel */ }
>> };
>> MODULE_DEVICE_TABLE(of, imx_itel_dt_ids);
>>
>> static struct platform_driver imx_itel_driver = {
>>     .driver = {
>>         .name = "imx-itel",
>>         .owner = THIS_MODULE,
>>         .pm = &snd_soc_pm_ops,
>>         .of_match_table = imx_itel_dt_ids,
>>     },
>>     .probe = imx_itel_probe,
>>     .remove = imx_itel_remove,
>> };
>>
>> module_platform_driver(imx_itel_driver);
>>
>> MODULE_AUTHOR("Nicola Lunghi");
>> MODULE_DESCRIPTION("ITEL I2S Platform Driver");
>> MODULE_LICENSE("GPL v2");
>> MODULE_ALIAS("platform:imx-itel");
>>
>> 2016-05-12 9:55 GMT+02:00 nick83ola <nick83ola@xxxxxxxxx>:
>>
>>> I am using ssi1 because I have an example of setting master mode on
>>> sabre board dts
>>>
>>> I have a problem with iomux/pinctrl  I think because
>>>
>>> root@icorem6solo:/sys/kernel/debug/pinctrl/20e0000.iomuxc# cat
>>> pinmux-pins |grep audmux
>>> pin 57 (MX6DL_PAD_DISP0_DAT20): 2028000.ssi (GPIO UNCLAIMED) function
>>> audmux group audmux-4
>>> pin 58 (MX6DL_PAD_DISP0_DAT21): 2028000.ssi (GPIO UNCLAIMED) function
>>> audmux group audmux-4
>>> pin 59 (MX6DL_PAD_DISP0_DAT22): 2028000.ssi (GPIO UNCLAIMED) function
>>> audmux group audmux-4
>>> pin 60 (MX6DL_PAD_DISP0_DAT23): 2028000.ssi (GPIO UNCLAIMED) function
>>> audmux group audmux-4
>>>
>>> says: GPIO_UNCLAIMED? it is correct??
>>>
>>> /sys/kernel/debug/pinctrl/20e0000.iomuxc# cat pinconf-groups |grep -A 1
>>> audmux
>>> 1 (audmux-1):
>>> MX6DL_PAD_SD2_DAT0: 0x17070MX6DL_PAD_SD2_DAT3:
>>> 0x17070MX6DL_PAD_SD2_DAT2: 0x17070MX6DL_PAD_SD2_DAT1: 0x17070
>>> 2 (audmux-2):
>>> MX6DL_PAD_CSI0_DAT7: 0x1b0b0MX6DL_PAD_CSI0_DAT4:
>>> 0x1b0b0MX6DL_PAD_CSI0_DAT5: 0x1b0b0MX6DL_PAD_CSI0_DAT6: 0x1b0b0
>>> 3 (audmux-3):
>>> MX6DL_PAD_DISP0_DAT16: 0x10MX6DL_PAD_DISP0_DAT18:
>>> 0x1b0b0MX6DL_PAD_DISP0_DAT19: 0x1b0b0
>>> 4 (audmux-4):
>>> MX6DL_PAD_DISP0_DAT20: 0x130b0MX6DL_PAD_DISP0_DAT21:
>>> 0x110b0MX6DL_PAD_DISP0_DAT22: 0x130b0MX6DL_PAD_DISP0_DAT23: 0x130b0
>>>
>>> 0x130b0?
>>>
>>> audmux# cat ssi0
>>>     PDCR: 0000a000
>>>     PTCR: ad400800
>>>     TxFS output from SSI6, TxClk output from SSI6
>>>     Port is symmetric
>>>     Data received from SSI6
>>> root@icorem6solo:/sys/kernel/debug/audmux# cat ssi1
>>>     PDCR: 00008000
>>>     PTCR: 00000800
>>>     TxFS input, TxClk input
>>>     Port is symmetric
>>>     Data received from SSI5
>>> root@icorem6solo:/sys/kernel/debug/audmux# cat ssi2
>>>     PDCR: 00006000
>>>     PTCR: 9cc00800
>>>     TxFS output from SSI4, TxClk output from SSI4
>>>     Port is symmetric
>>>     Data received from SSI4
>>> root@icorem6solo:/sys/kernel/debug/audmux# cat ssi3
>>>     PDCR: 00004000
>>>     PTCR: 00000800
>>>     TxFS input, TxClk input
>>>     Port is symmetric
>>>     Data received from SSI3
>>> root@icorem6solo:/sys/kernel/debug/audmux# cat ssi4
>>>     PDCR: 00002000
>>>     PTCR: 8c400800
>>>     TxFS output from imx-ssi.1, TxClk output from imx-ssi.1
>>>     Port is symmetric
>>>     Data received from imx-ssi.1
>>> root@icorem6solo:/sys/kernel/debug/audmux# cat ssi5
>>>     PDCR: 00000000
>>>     PTCR: 00000800
>>>     TxFS input, TxClk input
>>>     Port is symmetric
>>>     Data received from imx-ssi.0
>>> root@icorem6solo:/sys/kernel/debug/audmux# cat ssi6
>>>     PDCR: 0000c000
>>>     PTCR: 00000800
>>>     TxFS input, TxClk input
>>>     Port is symmetric
>>>     Data received from UNKNOWN
>>>
>>>
>>>
>>
>>
>> --
>>
>> P.S. Le informazioni trasmesse attraverso la presente comunicazione sono
>> di esclusiva
>> spettanza dell'effettivo destinatario. Nel caso in cui le stesse
>> raggiungessero, per
>> qualunque motivo, soggetti non interessati, questi ultimi vorranno darne
>> immediata
>> notizia al mittente. In ogni caso, eventuali soggetti diversi dai
>> legittimi destinatari
>> della presente comunicazione e dei dati contenuti negli allegati, possono
>> essere
>> sanzionati ai sensi del T.U. sul trattamento dei dati personali d.lgs.
>> 196/2003, sia ai
>> sensi dell'art. 616 del Codice Penale che disciplina la violazione del
>> segreto sulla
>> corrispondenza.
>>
>
>


-- 

P.S. Le informazioni trasmesse attraverso la presente comunicazione sono di
esclusiva
spettanza dell'effettivo destinatario. Nel caso in cui le stesse
raggiungessero, per
qualunque motivo, soggetti non interessati, questi ultimi vorranno darne
immediata
notizia al mittente. In ogni caso, eventuali soggetti diversi dai legittimi
destinatari
della presente comunicazione e dei dati contenuti negli allegati, possono
essere
sanzionati ai sensi del T.U. sul trattamento dei dati personali d.lgs.
196/2003, sia ai
sensi dell'art. 616 del Codice Penale che disciplina la violazione del
segreto sulla
corrispondenza.

Attachment: imx6dl-icore.dts
Description: audio/vnd.dts

/*
 * Copyright (C) 2013 Freescale Semiconductor, Inc.
 *
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/device.h>
#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>

#include "imx-ssi.h"

struct imx_itel_data {
	struct snd_soc_dai_link dai;
	struct snd_soc_card card;
};


struct _itel_audio_fmts {
	unsigned int rate;
	unsigned int sysclk;
};

/* in order of power consumption per rate (lowest first) */
static const struct _itel_audio_fmts itel_audio_fmts[] = {
/*channels format               rate	    sysclk div2 psr pm lr_rate; */
    /* 16 Bit multiple of 8k */
	{8000,      12288000},
	{16000,     12288000},
	{32000,     12288000},
	{48000,     12288000},
	{96000,     24576000},
	{192000,    49152000},

    /* 16 bit 44100 multiples */
	{11025,     11289600},
	{22050,     11289600},
	{44100,     11289600},
	{88200,     22579200},
};


static int imx_itel_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 *cpu_dai = rtd->cpu_dai;
	snd_pcm_format_t format = params_format(params);
	u32 channels = params_channels(params);
	u32 rate     = params_rate(params);
	u32 bclk = rate * channels * 32;
	int ret = 0, i;

    dev_info(cpu_dai->dev, "set cpu DAI configuration rate=%d, format=%d, channels=%d, bclk=%d\n", rate, format, channels, bclk);

	/* find the correct audio parameters */
	for (i = 0; i < ARRAY_SIZE(itel_audio_fmts); i++) {
		if (rate == itel_audio_fmts[i].rate)
		{
		    ret = 1;
		    break;
		}
	}
	if (!ret)
		return -EINVAL;

	/* codec FLL input is 14.75 MHz from MCLK */
    /**
     * snd_soc_dai_set_pll - configure DAI PLL.
     * @dai: DAI
     * @pll_id: DAI specific PLL ID
     * @source: DAI specific source for the PLL
     * @freq_in: PLL input clock frequency in Hz
     * @freq_out: requested PLL output clock frequency in Hz
     *
     * Configures and enables PLL to generate output clock based on input clock.
     */
    // snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out);

	snd_soc_dai_set_pll(cpu_dai, 0, 0, 24000000, itel_audio_fmts[i].sysclk);

	/* set cpu DAI configuration */
	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
	if (ret) {
		dev_err(cpu_dai->dev, "failed to set dai fmt\n");
		return ret;
	}

    dev_info(cpu_dai->dev, "set tdm slots channels=%d", channels);

	ret = snd_soc_dai_set_tdm_slot(cpu_dai, channels == 1 ? 0xfffffffe : 0xfffffffc, channels == 1 ? 0xfffffffe : 0xfffffffc, 2, 32);
	if (ret) {
		dev_err(cpu_dai->dev, "failed to set dai tdm slot\n");
		return ret;
	}

    dev_info(cpu_dai->dev, "set ssi bclk NAME=%s \n",cpu_dai->name);
    /* set clock */
	ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, bclk, SND_SOC_CLOCK_OUT);
	if (ret)
		dev_err(cpu_dai->dev, "failed to set sysclk\n");

	return ret;
}


static struct snd_soc_ops imx_itel_ops = {
	.hw_params = imx_itel_hw_params,
};


static const struct snd_soc_dapm_widget imx_itel_dapm_widgets[] = {
//	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
//	SND_SOC_DAPM_LINE("Line In Jack", NULL),
};

static struct snd_soc_dai_link imx_itel_dai[] = {
	{
		.name            = "Hifi",
		.stream_name	 = "Hifi",
		.codec_dai_name	 = "snd-soc-itel-dai",
		//.codec_name	     = "snd-soc-itel",
		.ops		     = &imx_itel_ops,
		.symmetric_rates = 1,
	},
};

static struct snd_soc_card snd_soc_card_imx_itel = {
	.name               = "imx-audio-itel",
	.dai_link           = imx_itel_dai,
	.num_links	        = ARRAY_SIZE(imx_itel_dai),
	.dapm_widgets       = imx_itel_dapm_widgets,
	.num_dapm_widgets   = ARRAY_SIZE(imx_itel_dapm_widgets),
    .owner              = THIS_MODULE,
};


static int imx_itel_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card = &snd_soc_card_imx_itel;
	struct device_node *ssi_np;
	struct platform_device *ssi_pdev;
	struct device_node *codec_np;
	struct platform_device *codec_pdev;
	// struct imx_itel_data *data = NULL;
	int int_port, ext_port, ret;

    dev_info(&pdev->dev,"enter imx_itel_probe");

	ret = of_property_read_u32(pdev->dev.of_node, "mux-int-port", &int_port);
	if (ret) {
		dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
		return ret;
	}
   

	ret = of_property_read_u32(pdev->dev.of_node, "mux-ext-port", &ext_port);
	if (ret) {
		dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
		return ret;
	}

    /* find value in devicetree for ssi controller */
	ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
	if (!ssi_np) {
		dev_err(&pdev->dev, "ssi-controller missing or invalid\n");
		ret = -EINVAL;
		goto fail;
	}

    /* find SSI platform driver */
	ssi_pdev = of_find_device_by_node(ssi_np);
	if (!ssi_pdev) {
		dev_err(&pdev->dev, "failed to find SSI platform device\n");
		ret = -EPROBE_DEFER;
		goto fail;
	}

	codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
	if (!codec_np) {
		dev_err(&pdev->dev, "codec missing or invalid\n");
		ret = -EINVAL;
		goto fail;
	}

    /* find SSI platform driver */
	codec_pdev = of_find_device_by_node(codec_np);
	if (!codec_pdev) {
		dev_err(&pdev->dev, "failed to find codec platform device\n");
		ret = -EPROBE_DEFER;
		goto fail;
	}

	card->dev = &pdev->dev;
	card->dai_link->cpu_dai_name = dev_name(&ssi_pdev->dev);
	card->dai_link->platform_of_node = ssi_np;
	card->dai_link->codec_of_node = codec_np;
	card->dai_link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;


	platform_set_drvdata(pdev, card);
	snd_soc_card_set_drvdata(card, &snd_soc_card_imx_itel);

    dev_info(&pdev->dev,"registro la scheda\n");

	ret = snd_soc_register_card(card);
	if (ret) {
		dev_err(&pdev->dev, "Failed to register card: %d\n", ret);
		goto fail;
    }

	of_node_put(ssi_np);
	of_node_put(codec_np);

	return 0;
	
fail:
	if (ssi_np)
		of_node_put(ssi_np);
	if (codec_np)
		of_node_put(codec_np);

	return ret;
}

static int imx_itel_remove(struct platform_device *pdev)
{
	struct snd_soc_card *card = &snd_soc_card_imx_itel;

	snd_soc_unregister_card(card);

	return 0;
}

static const struct of_device_id imx_itel_dt_ids[] = {
	{ .compatible = "fsl,imx-audio-itel", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_itel_dt_ids);

static struct platform_driver imx_itel_driver = {
	.driver = {
		.name = "imx-itel",
		.owner = THIS_MODULE,
		.pm = &snd_soc_pm_ops,
		.of_match_table = imx_itel_dt_ids,
	},
	.probe = imx_itel_probe,
	.remove = imx_itel_remove,
};

module_platform_driver(imx_itel_driver);

MODULE_AUTHOR("Nicola Lunghi");
MODULE_DESCRIPTION("ITEL I2S Platform Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:imx-itel");
/*
 * itel.c  --  ALSA SoC Audio Layer utility functions
 *
 * Copyright 2009 Wolfson Microelectronics PLC.
 *
 * Author: Mark Brown <broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
 *         Liam Girdwood <lrg@xxxxxxxxxxxxxxx>
 *         
 *
 *  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.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <linux/of.h>

static struct snd_soc_platform_driver itel_platform = {
	//.ops = &dummy_dma_ops,
};

#define ITEL_RX_RATES	SNDRV_PCM_RATE_8000_192000
#define ITEL_RX_FORMATS	(   SNDRV_PCM_FMTBIT_S16_LE |   \
			                SNDRV_PCM_FMTBIT_S20_3LE|   \
			                SNDRV_PCM_FMTBIT_S24_LE |   \
			                SNDRV_PCM_FMTBIT_S32_LE )

#define ITEL_TX_RATES	SNDRV_PCM_RATE_8000_192000
#define ITEL_TX_FORMATS	(   SNDRV_PCM_FMTBIT_S16_LE |   \
			                SNDRV_PCM_FMTBIT_S20_3LE|   \
			                SNDRV_PCM_FMTBIT_S24_LE |   \
			                SNDRV_PCM_FMTBIT_S32_LE)

static const struct snd_soc_dapm_widget itel_widgets[] = {
	SND_SOC_DAPM_INPUT("i2s-in"),
	SND_SOC_DAPM_OUTPUT("i2s-out"),
};

static const struct snd_soc_dapm_route itel_routes[] = {
	{ "Capture", NULL, "i2s-in" },
	{ "i2s-out", NULL, "Playback" },
};

static struct snd_soc_codec_driver itel_codec = {
	.dapm_widgets = itel_widgets,
	.num_dapm_widgets = ARRAY_SIZE(itel_widgets),
	.dapm_routes = itel_routes,
	.num_dapm_routes = ARRAY_SIZE(itel_routes),
};

static struct snd_soc_dai_driver itel_dai = {
	.name = "snd-soc-itel-dai",
	.playback = {
		.stream_name	= "Playback",
		.channels_min	= 1,
		.channels_max	= 2,
		.rates		= ITEL_TX_RATES,
		.formats	= ITEL_TX_FORMATS,
	},
	.capture = {
		.stream_name	= "Capture",
		.channels_min	= 1,
		.channels_max	= 2,
		.rates = ITEL_RX_RATES,
		.formats = ITEL_RX_FORMATS,
	 },
};

static int snd_soc_itel_probe(struct platform_device *pdev)
{
	int ret;

	return snd_soc_register_codec(&pdev->dev, &itel_codec, &itel_dai, 1);
	if (ret < 0)
		return ret;

	ret = snd_soc_register_platform(&pdev->dev, &itel_platform);
	if (ret < 0) {
		snd_soc_unregister_codec(&pdev->dev);
		return ret;
	}

	return ret;
}

static int snd_soc_itel_remove(struct platform_device *pdev)
{
	snd_soc_unregister_platform(&pdev->dev);
	snd_soc_unregister_codec(&pdev->dev);
	return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id soc_itel_ids[] = {
    { .compatible = "fsl,snd-soc-itel", },
    { }
};
MODULE_DEVICE_TABLE(of, soc_itel_ids);
#endif

static struct platform_driver soc_itel_driver = {
	.probe = snd_soc_itel_probe,
	.remove = snd_soc_itel_remove,
	.driver = {
		.name = "snd-soc-itel",
		.owner = THIS_MODULE,
        .of_match_table = of_match_ptr(soc_itel_ids),
	},
};

module_platform_driver(soc_itel_driver);

MODULE_AUTHOR("Nicola Lunghi <nicola.lunghi@xxxxxxx>");
MODULE_DESCRIPTION("ITEL I2S Codec Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:snd-soc-itel");
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux