[PATCH v6 01/10] ASoC: phycore-ac97: Add DT support
Shawn Guo
shawn.guo at linaro.org
Wed May 29 09:53:45 EDT 2013
On Tue, May 28, 2013 at 04:47:49PM +0200, Markus Pargmann wrote:
> Add devicetree support for this audio soc fabric driver.
>
> platform_of_node and cpu_of_node are set according to the fsl,audmux
> phandle.
>
> This patch adds handling of ac97 reset functions according to fsl ac97
> support. They are setup from here to avoid board specific code in the
> generic fsl-ssi driver.
>
> This patch changes the handling of pca100 boards from non-DT to DT only.
> pcm043 is still handled without DT.
>
> Signed-off-by: Markus Pargmann <mpa at pengutronix.de>
> ---
>
> Notes:
> Changes in v6:
> - phycore-ac97 now manages the ac97 reset functions of the boards using
> this combination of ssi-codec.
> - Removed preprocessor ifs for DT, non-DT distinction. pcm043 is now
> non-DT only and pca100 DT only.
>
> Changes in v4:
> - New property phytec,audmux to check which audmux setup should be
> executed. Checking for fsl,imx21-audmux and fsl,imx31-audmux.
>
> Changes in v3:
> - Add some more information in the commit message.
>
> Changes in v2:
> - Simplify the driver, by combining audmux port configurations. The
> audmux driver actually knows on which platform he is running and
> will return the appropriate error code if we use functions for
> another platform. So we don't need to have the knowledge about it
> in phycore-ac97 and can try both functions. This removes the need
> of different compatibilities and renames it to phycore-ac97.
> - Use a phandle for the cpu_dai link.
> - Add devicetree binding documentation.
> - Rename binding to phytec,phycore-ac97 and fsl,ssi to phytec,ssi
>
> Changes in v2:
> - Simplify the driver, by combining audmux port configurations. The
> audmux driver actually knows on which platform he is running and
> will return the appropriate error code if we use functions for
> another platform. So we don't need to have the knowledge about it
> in phycore-ac97 and can try both functions. This removes the need
> of different compatibilities and renames it to imx27-ac97.
> - Use a phandle for the cpu_dai link.
> - Add devicetree binding documentation.
> - Rename binding to phytec,phycore-ac97 and fsl,ssi to phytec,ssi
>
> .../bindings/sound/phytec,phycore-ac97.txt | 14 ++
> sound/soc/fsl/phycore-ac97.c | 241 ++++++++++++++++++---
> 2 files changed, 229 insertions(+), 26 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/sound/phytec,phycore-ac97.txt
>
> diff --git a/Documentation/devicetree/bindings/sound/phytec,phycore-ac97.txt b/Documentation/devicetree/bindings/sound/phytec,phycore-ac97.txt
> new file mode 100644
> index 0000000..41201ff
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/phytec,phycore-ac97.txt
> @@ -0,0 +1,14 @@
> +Phytec phycore AC97
> +
> +Required properties:
> +- compatible: "phytec,phycore-ac97"
> +- phytec,ssi: A phandle to the ssi device that is connected to ac97.
> +- phytec,audmux: A phandle to the audmux device.
> +
> +Example:
> +
> +sound {
> + compatible = "phytec,phycore-ac97";
> + phytec,ssi = <&ssi1>;
> + phytec,audmux = <&audmux>;
> +};
> diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
> index ae403c2..bf2c600 100644
> --- a/sound/soc/fsl/phycore-ac97.c
> +++ b/sound/soc/fsl/phycore-ac97.c
> @@ -20,8 +20,14 @@
> #include <asm/mach-types.h>
>
> #include "imx-audmux.h"
> +#include "fsl_ssi.h"
> +
> +#define DRV_NAME "phycore-audio-fabric"
>
> static struct snd_soc_card imx_phycore;
> +static struct device_node *phycore_dai_cpu_node;
> +static void (*phycore_ac97_reset) (struct snd_ac97 *ac97);
> +static void (*phycore_ac97_warm_reset)(struct snd_ac97 *ac97);
>
> static struct snd_soc_ops imx_phycore_hifi_ops = {
> };
> @@ -32,12 +38,12 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
> .stream_name = "HiFi",
> .codec_dai_name = "wm9712-hifi",
> .codec_name = "wm9712-codec",
> - .cpu_dai_name = "imx-ssi.0",
> - .platform_name = "imx-ssi.0",
I do not think these and phycore_ac97_plat_name changes are necessary,
since of_node will always take precedence over name in match.
> .ops = &imx_phycore_hifi_ops,
> },
> };
>
> +static const char phycore_ac97_plat_name[] = "imx-ssi.0";
> +
> static struct snd_soc_card imx_phycore = {
> .name = "PhyCORE-ac97-audio",
> .owner = THIS_MODULE,
> @@ -45,40 +51,52 @@ static struct snd_soc_card imx_phycore = {
> .num_links = ARRAY_SIZE(imx_phycore_dai_ac97),
> };
>
> -static struct platform_device *imx_phycore_snd_ac97_device;
> +static void phycore_ac97_imx21_audmux(void)
> +{
> + imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
> + IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
> + IMX_AUDMUX_V1_PCR_TFCSEL(3) |
> + IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
> + IMX_AUDMUX_V1_PCR_RXDSEL(3));
> + imx_audmux_v1_configure_port(3,
> + IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
> + IMX_AUDMUX_V1_PCR_TFCSEL(0) |
> + IMX_AUDMUX_V1_PCR_TFSDIR |
> + IMX_AUDMUX_V1_PCR_RXDSEL(0));
> +}
> +
> +static void phycore_ac97_imx31_audmux(void)
> +{
> + imx_audmux_v2_configure_port(3,
> + IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
> + IMX_AUDMUX_V2_PTCR_TFSEL(0) |
> + IMX_AUDMUX_V2_PTCR_TFSDIR,
> + IMX_AUDMUX_V2_PDCR_RXDSEL(0));
> + imx_audmux_v2_configure_port(0,
> + IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
> + IMX_AUDMUX_V2_PTCR_TCSEL(3) |
> + IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
> + IMX_AUDMUX_V2_PDCR_RXDSEL(3));
> +}
> +
> static struct platform_device *imx_phycore_snd_device;
>
> +static struct platform_device *imx_phycore_snd_ac97_device;
> +
> static int __init imx_phycore_init(void)
> {
> int ret;
>
> - if (machine_is_pca100()) {
> - imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
> - IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
> - IMX_AUDMUX_V1_PCR_TFCSEL(3) |
> - IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
> - IMX_AUDMUX_V1_PCR_RXDSEL(3));
> - imx_audmux_v1_configure_port(3,
> - IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
> - IMX_AUDMUX_V1_PCR_TFCSEL(0) |
> - IMX_AUDMUX_V1_PCR_TFSDIR |
> - IMX_AUDMUX_V1_PCR_RXDSEL(0));
> - } else if (machine_is_pcm043()) {
> - imx_audmux_v2_configure_port(3,
> - IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
> - IMX_AUDMUX_V2_PTCR_TFSEL(0) |
> - IMX_AUDMUX_V2_PTCR_TFSDIR,
> - IMX_AUDMUX_V2_PDCR_RXDSEL(0));
> - imx_audmux_v2_configure_port(0,
> - IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
> - IMX_AUDMUX_V2_PTCR_TCSEL(3) |
> - IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
> - IMX_AUDMUX_V2_PDCR_RXDSEL(3));
> + if (machine_is_pcm043()) {
> + phycore_ac97_imx31_audmux();
> } else {
> /* return happy. We might run on a totally different machine */
> return 0;
> }
>
> + imx_phycore_dai_ac97[0].cpu_dai_name = phycore_ac97_plat_name;
> + imx_phycore_dai_ac97[0].platform_name = phycore_ac97_plat_name;
> +
> imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1);
> if (!imx_phycore_snd_ac97_device)
> return -ENOMEM;
> @@ -108,18 +126,189 @@ fail2:
> platform_device_del(imx_phycore_snd_ac97_device);
> fail1:
> platform_device_put(imx_phycore_snd_ac97_device);
> + imx_phycore_dai_ac97[0].cpu_dai_name = NULL;
> + imx_phycore_dai_ac97[0].platform_name = NULL;
> return ret;
> }
>
> static void __exit imx_phycore_exit(void)
> {
> + if (!machine_is_pcm043())
> + return;
> +
> platform_device_unregister(imx_phycore_snd_device);
> platform_device_unregister(imx_phycore_snd_ac97_device);
> +
> + imx_phycore_dai_ac97[0].cpu_dai_name = NULL;
> + imx_phycore_dai_ac97[0].platform_name = NULL;
> }
>
> late_initcall(imx_phycore_init);
> module_exit(imx_phycore_exit);
>
> +
> +static const struct of_device_id imx_phycore_ac97_of_dev_id[] = {
> + {
> + .compatible = "phytec,phycore-ac97",
> + }, {
> + /* sentinel */
> + }
> +};
> +MODULE_DEVICE_TABLE(of, imx_phycore_ac97_of_dev_id);
> +
> +
> +/*
> + * Pointer to AC97 reset functions for specific boards
> + */
> +#if IS_ENABLED(CONFIG_MACH_PCA100)
> +extern void pca100_ac97_cold_reset(struct snd_ac97 *ac97);
> +extern void pca100_ac97_warm_reset(struct snd_ac97 *ac97);
> +#else
> +void pca100_ac97_cold_reset(struct snd_ac97 *ac97) { }
> +void pca100_ac97_warm_reset(struct snd_ac97 *ac97) { }
static?
> +#endif
> +
> +#if IS_ENABLED(CONFIG_MACH_PCM043)
> +extern void pcm043_ac97_cold_reset(struct snd_ac97 *ac97);
> +extern void pcm043_ac97_warm_reset(struct snd_ac97 *ac97);
> +#else
> +void pcm043_ac97_cold_reset(struct snd_ac97 *ac97) { }
> +void pcm043_ac97_warm_reset(struct snd_ac97 *ac97) { }
> +#endif
> +
> +static void phycore_soc_ac97_reset(struct snd_ac97 *ac97)
> +{
> + if (phycore_ac97_reset)
> + phycore_ac97_reset(ac97);
> + /* First read sometimes fails, do a dummy read */
> + fsl_ssi_ac97_read(ac97, 0);
This function is unavailable until patch #7, right?
> +}
> +
> +static void phycore_soc_ac97_warm_reset(struct snd_ac97 *ac97)
> +{
> + if (phycore_ac97_warm_reset)
> + phycore_ac97_warm_reset(ac97);
> +
> + /* First read sometimes fails, do a dummy read */
> + fsl_ssi_ac97_read(ac97, 0);
> +}
> +
> +static int phycore_ac97_setup_devices(struct platform_device *pdev)
> +{
> + int ret;
> +
> + imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
> + if (!imx_phycore_snd_device)
> + return -ENOMEM;
> +
> + ret = platform_device_add(imx_phycore_snd_device);
> + if (ret) {
> + dev_err(&pdev->dev, "ASoC: Platform device allocation failed\n");
> + goto fail1;
> + }
> +
> + ret = snd_soc_register_card(&imx_phycore);
> + if (ret) {
> + dev_err(&pdev->dev, "ASoC: soc card registration failed\n");
> + goto fail2;
> + }
> + return 0;
> +
> +fail2:
> + platform_device_del(imx_phycore_snd_device);
> +fail1:
> + platform_device_put(imx_phycore_snd_device);
> + return ret;
> +}
> +
> +static int imx_phycore_ac97_probe(struct platform_device *pdev)
> +{
> + int ret;
> + struct device_node *ssi_np;
> + struct device_node *audmux_np;
> + const char *sprop;
> + const char *p;
> +
> + imx_phycore.dev = &pdev->dev;
> +
> + audmux_np = of_parse_phandle(pdev->dev.of_node, "phytec,audmux", 0);
> + if (!audmux_np) {
> + dev_err(&pdev->dev, "Failed to parse phytec,audmux phandle\n");
> + return -EINVAL;
> + }
> +
> + if (of_device_is_compatible(audmux_np, "fsl,imx21-audmux")) {
> + phycore_ac97_imx21_audmux();
> + } else if (of_device_is_compatible(audmux_np, "fsl,imx31-audmux")) {
> + phycore_ac97_imx31_audmux();
> + } else {
> + dev_err(&pdev->dev, "Unknown audmux, failed to setup audmux\n");
> + of_node_put(audmux_np);
> + return -EINVAL;
> + }
> + of_node_put(audmux_np);
> +
> + ssi_np = of_parse_phandle(pdev->dev.of_node, "phytec,ssi", 0);
> + if (!ssi_np) {
> + dev_err(&pdev->dev, "No valid ssi phandle found\n");
> + return -EINVAL;
> + }
> +
> + imx_phycore_dai_ac97[0].cpu_of_node = ssi_np;
> + imx_phycore_dai_ac97[0].platform_of_node = ssi_np;
> + phycore_dai_cpu_node = ssi_np;
> +
> + sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL);
> + p = strrchr(sprop, ',');
> + if (p)
> + sprop = p + 1;
> +
> + if (!strcmp(sprop, "imx27-pca100")) {
Since this is a phycore/phytec specific ASoC-machine driver, what's the
problem with matching the machine compatible string by simply calling
of_machine_is_compatible()?
> + phycore_ac97_reset = pca100_ac97_cold_reset;
> + phycore_ac97_warm_reset = pca100_ac97_warm_reset;
> + } else if (!strcmp(sprop, "imx35-pcm043")) {
> + phycore_ac97_reset = pcm043_ac97_cold_reset;
> + phycore_ac97_warm_reset = pcm043_ac97_warm_reset;
> + } else {
> + dev_err(&pdev->dev, "Failed to set AC97 reset functions, unknown board.\n");
> + return -EINVAL;
> + }
> +
> + fsl_ssi_ac97_set_reset(phycore_soc_ac97_reset,
> + phycore_soc_ac97_warm_reset);
> +
> + ret = phycore_ac97_setup_devices(pdev);
> + if (ret)
> + of_node_put(phycore_dai_cpu_node);
> +
> + return ret;
> +}
> +
> +static int imx_phycore_ac97_remove(struct platform_device *pdev)
> +{
> + of_node_put(phycore_dai_cpu_node);
> + phycore_dai_cpu_node = NULL;
> +
> + platform_device_unregister(imx_phycore_snd_device);
snd_soc_unregister_card() call is missing?
Shawn
> +
> + phycore_ac97_reset = NULL;
> + phycore_ac97_warm_reset = NULL;
> +
> + return 0;
> +}
> +
> +static struct platform_driver imx_phycore_ac97_driver = {
> + .probe = imx_phycore_ac97_probe,
> + .remove = imx_phycore_ac97_remove,
> + .driver = {
> + .name = DRV_NAME,
> + .owner = THIS_MODULE,
> + .of_match_table = imx_phycore_ac97_of_dev_id,
> + },
> +};
> +
> +module_platform_driver(imx_phycore_ac97_driver);
> +
> MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
> -MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
> +MODULE_DESCRIPTION(DRV_NAME ": PhyCORE ALSA SoC fabric driver");
> MODULE_LICENSE("GPL");
> --
> 1.8.2.1
>
More information about the linux-arm-kernel
mailing list