Route Bluetooth pcm through audmux

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Route Bluetooth pcm through audmux

1,389 Views
philippedeswert
Contributor I

Hi all,

We're trying to get some PCM audio routed from a BT chip through the audmux. We have checked that the bt chip indeed sends out PCM data. However despite having configured the audmux and a fake audio card we still don't seem to be getting any audio.

We have the BT connected with a 4 wire interface as master to port6 of the audmux, we would like to connect this to ssi2 on port2. The BT chip is master, so we put ssi2 in slave mode (devicetree) Currently the audmux ports are configured as follows:

port2:

PDCR: 0000a000
PTCR: ad400800
TxFS output from SSI6, TxClk output from SSI6

Port is symmetric

Data recieved from SSI6

port6:

PDCR: 00002000
PTCR: 00000800
TxFS input, TxClk input
Port is symmetric
Data received from imx-ssi.1

However we do not get any action on our dummy audio driver.

The extra driver we have is a simple platform driver, which registers one instance of an audio card, which also does the aumux setting (read from devicetree) and the ssi (also read from devicetree).

We have set the pads as inputs (device tree 0x0130b0 and in imx6-pinfunc.h

Relevant parts of the driver

audmux setting

static int imx_audmux_config(int slave, int master)

{

    unsigned int ptcr, pdcr;

    /*

     * The port numbering in the hardware manual starts at 1, while

     * the audmux API expects it starts at 0.

     */

     slave = slave - 1;

     master = master - 1;

     ptcr = IMX_AUDMUX_V2_PTCR_SYN |

            IMX_AUDMUX_V2_PTCR_TFSDIR |

            IMX_AUDMUX_V2_PTCR_TFSEL(master) |

            IMX_AUDMUX_V2_PTCR_TCLKDIR |

            IMX_AUDMUX_V2_PTCR_TCSEL(master);

     pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master);

     imx_audmux_v2_configure_port(slave, ptcr, pdcr);

     ptcr = IMX_AUDMUX_V2_PTCR_SYN;

     pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave);

     imx_audmux_v2_configure_port(master, ptcr, pdcr);

     return 0;

}

Reading of port numbers and setting ssi and sound card

static int bt_imx_fake_audio_probe(struct platform_device *pdev)

{

    struct device_node *ssi_np, *np = pdev->dev.of_node;

    struct bt_imx_fake_audio_data *data;

    struct platform_device *ssi_pdev;

    int ret = 0, int_port, ext_port;

    dev_info(&pdev->dev, "Probing bt_imx_fake_audio\n");

    ret = of_property_read_u32(np, "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(np, "mux-ext-port", &ext_port);

    if (ret) {

        dev_err(&pdev->dev,  "mux-ext-port missing or invalid\n");

        return ret;

    }

    dev_info(&pdev->dev, "Using audmux ports %d and %d \n", int_port, ext_port);

    imx_audmux_config(int_port, ext_port);

    ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);

    if (!ssi_np) {

        dev_err(&pdev->dev,  "phandle missing or invalid\n");

        ret = -EINVAL;

        goto fail;

    }

    ssi_pdev = of_find_device_by_node(ssi_np);

    if (!ssi_pdev) {

        dev_err(&pdev->dev,  "failed to find SSI platform device\n");

        ret = -EINVAL;

        goto fail;

    }

    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);

    if (!data) {

        dev_err(&pdev->dev,  "failed to allocate memory\n");

        ret = -ENOMEM;

       goto fail;

    }

   data->dai.name = "BT HFP";

    data->dai.stream_name = "Bluetooth HFP";

    data->dai.codec_dai_name = "snd-soc-dummy-dai";

    data->dai.codec_name = "snd-soc-dummy";

    data->dai.cpu_of_node = ssi_np;

    data->dai.platform_of_node = ssi_np;

    data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |

                        SND_SOC_DAIFMT_CBM_CFM;

    data->card.dev = &pdev->dev;

    data->card.num_links = 1;

    data->card.dai_link = &data->dai;

    data->pdev = platform_device_register_simple("bluetooth", -1, NULL, 0);

    if (IS_ERR(data->pdev)) {

        ret = PTR_ERR(data->pdev);

        dev_err(&pdev->dev,  "register failed: %d\n", ret);

        goto fail;

    }

    //Fill in the card details

    ret = snd_soc_of_parse_card_name(&data->card, "model");

    if (ret)

        goto fail;

    data->card.num_links = 1;

    data->card.owner = THIS_MODULE;

    data->card.dai_link = &data->dai;

    platform_set_drvdata(pdev, &data->card);

    snd_soc_card_set_drvdata(&data->card, data);

    ret = snd_soc_register_card(&data->card);

    if (ret) {

        dev_err(&pdev->dev,  "snd_soc_register_card failed: %d\n", ret);

        goto fail;

    }

    // Done, set the driver data.

    platform_set_drvdata(pdev, data);

    printk(KERN_INFO "Imx fake bluetooth audio driver version 0.1 loaded\n");

fail:

    if (ssi_np)

        of_node_put(ssi_np);

    return ret;

}

The sound card is there, Alsa lists it nicely. Now when we start bluetooth audio, we can see with the scope we have traffic but no sound comes out. Anybody having any idea what we're missing?

Thanks!

Labels (3)
0 Kudos
Reply
1 Reply

602 Views
igorpadykov
NXP Employee
NXP Employee

HI Philippe

one can check if bit/frame clocks are provided to ssi2, if sdma is configured for ssi2 channel

and debug it using (AN4553 http://www.nxp.com/files/32bit/doc/app_note/AN4553.pdf )

for example working case with some board with sgtl5000, like sabrelite imx6qdl-sabrelite.dtsi

linux-imx6/imx6q-sabrelite.dts at boundary-imx_4.1.15_1.0.0_ga · boundarydevices/linux-imx6 · GitHub 

One can ty to remove i2c references from driver to imitate "fake audio card".

Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply