[PATCH 3/4] ASoC: support pxa168 ssp in ASoC

Eric Miao eric.y.miao at gmail.com
Mon Apr 12 13:32:24 EDT 2010


On Wed, Mar 31, 2010 at 8:48 PM, Haojian Zhuang
<haojian.zhuang at gmail.com> wrote:
> From 76dcbf165f72a620d8460fc43351179388fcb440 Mon Sep 17 00:00:00 2001
> From: Haojian Zhuang <haojian.zhuang at marvell.com>
> Date: Wed, 17 Mar 2010 17:31:04 -0400
> Subject: [PATCH] ASoC: support pxa168 ssp in ASoC
>
> Support pxa168 ssp in ASoC. The SSP bit clock mechanism is totally different
> from pxa2xx series.
>
> Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
> ---
>  arch/arm/mach-mmp/include/mach/regs-mpmu.h |   48 ++++++++
>  sound/soc/pxa/Kconfig                      |    6 +-
>  sound/soc/pxa/Makefile                     |    2 +
>  sound/soc/pxa/pxa168-ssp.c                 |  166 ++++++++++++++++++++++++++++
>  sound/soc/pxa/pxa168-ssp.h                 |   64 +++++++++++
>  5 files changed, 285 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/mach-mmp/include/mach/regs-mpmu.h
>  create mode 100644 sound/soc/pxa/pxa168-ssp.c
>  create mode 100644 sound/soc/pxa/pxa168-ssp.h
>
> diff --git a/arch/arm/mach-mmp/include/mach/regs-mpmu.h
> b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
> new file mode 100644
> index 0000000..0d57236
> --- /dev/null
> +++ b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
> @@ -0,0 +1,48 @@
> +/*
> + * linux/arch/arm/mach-mmp/include/mach/regs-mpmu.h
> + *
> + *   Main Power Management Unit
> + *
> + * 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.
> + */
> +
> +#ifndef __ASM_MACH_REGS_MPMU_H
> +#define __ASM_MACH_REGS_MPMU_H
> +
> +#include <mach/addr-map.h>
> +
> +#define MPMU_VIRT_BASE (APB_VIRT_BASE + 0x50000)
> +#define MPMU_REG(off)  (MPMU_VIRT_BASE + (off))
> +
> +#define MPMU_CPCR      MPMU_REG(0x0000)
> +#define MPMU_FCCR      MPMU_REG(0x0008)
> +#define MPMU_POCR      MPMU_REG(0x000c)
> +#define MPMU_POSR      MPMU_REG(0x0010)
> +#define MPMU_SUCCR     MPMU_REG(0x0014)
> +#define MPMU_VRCR      MPMU_REG(0x0018)
> +#define MPMU_OHCR      MPMU_REG(0x001c)
> +#define MPMU_GPCR      MPMU_REG(0x0030)
> +#define MPMU_PLL2CR    MPMU_REG(0x0034)
> +#define MPMU_SCCR      MPMU_REG(0x0038)
> +#define MPMU_CWUCRM    MPMU_REG(0x004c)
> +#define MPMU_PLL1_REG1 MPMU_REG(0x0050)
> +#define MPMU_PLL1_REG2 MPMU_REG(0x0054)
> +#define MPMU_PLL1_SSC  MPMU_REG(0x0058)
> +#define MPMU_PLL2_REG1 MPMU_REG(0x0060)
> +#define MPMU_PLL2_REG2 MPMU_REG(0x0064)
> +#define MPMU_PLL2_SSC  MPMU_REG(0x0068)
> +#define MPMU_TS                MPMU_REG(0x0080)
> +#define MPMU_WDTPCR    MPMU_REG(0x0200)
> +#define MPMU_APCR      MPMU_REG(0x1000)
> +#define MPMU_APSR      MPMU_REG(0x1004)
> +#define MPMU_APRR      MPMU_REG(0x1020)
> +#define MPMU_ACGR      MPMU_REG(0x1024)
> +#define MPMU_ARSR      MPMU_REG(0x1028)
> +#define MPMU_AWUCRS    MPMU_REG(0x1048)
> +#define MPMU_AWUCRM    MPMU_REG(0x104c)
> +#define MPMU_ASYSDR    MPMU_REG(0x1050)
> +#define MPMU_ASSPDR    MPMU_REG(0x1054)
> +
> +#endif /* __ASM_MACH_REGS_APMU_H */
> diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
> index 7be1d5f..286d52a 100644
> --- a/sound/soc/pxa/Kconfig
> +++ b/sound/soc/pxa/Kconfig
> @@ -1,6 +1,6 @@
>  config SND_PXA2XX_SOC
>        tristate "SoC Audio for the Intel PXA2xx chip"
> -       depends on ARCH_PXA
> +       depends on ARCH_PXA || ARCH_MMP
>        select SND_PXA2XX_LIB
>        help
>          Say Y or M if you want to add support for codecs attached to
> @@ -25,6 +25,10 @@ config SND_PXA2XX_SOC_SSP
>        tristate
>        select PXA_SSP
>
> +config SND_PXA168_SOC_SSP
> +       tristate
> +       select PXA_SSP
> +
>  config SND_PXA2XX_SOC_CORGI
>        tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
>        depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
> diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
> index 33c1579..a74e6c9 100644
> --- a/sound/soc/pxa/Makefile
> +++ b/sound/soc/pxa/Makefile
> @@ -3,11 +3,13 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
>  snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
>  snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
>  snd-soc-pxa2xx-ssp-objs := pxa-ssp.o pxa2xx-ssp.o
> +snd-soc-pxa168-ssp-objs := pxa-ssp.o pxa168-ssp.o
>
>  obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
>  obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
>  obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
>  obj-$(CONFIG_SND_PXA2XX_SOC_SSP) += snd-soc-pxa2xx-ssp.o
> +obj-$(CONFIG_SND_PXA168_SOC_SSP) += snd-soc-pxa168-ssp.o
>
>  # PXA Machine Support
>  snd-soc-corgi-objs := corgi.o
> diff --git a/sound/soc/pxa/pxa168-ssp.c b/sound/soc/pxa/pxa168-ssp.c
> new file mode 100644
> index 0000000..d28d18a
> --- /dev/null
> +++ b/sound/soc/pxa/pxa168-ssp.c
> @@ -0,0 +1,166 @@
> +/*
> + * pxa168-ssp.c  --  ALSA Soc Audio Layer
> + *
> + * Copyright 2009-2010 Marvell International Ltd.
> + *     Haojian Zhuang <haojian.zhuang at marvell.com>
> + *
> + *  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.
> + *
> + * TODO:
> + *  o Test network mode
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +
> +#include <sound/core.h>
> +#include <sound/soc.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/pxa2xx-lib.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/dma.h>
> +#include <mach/regs-apbc.h>
> +#include <mach/regs-apmu.h>
> +#include <mach/regs-mpmu.h>
> +#include <plat/ssp.h>
> +
> +#include "pxa2xx-pcm.h"
> +#include "pxa168-ssp.h"
> +#include "pxa-ssp.h"
> +
> +/*
> + * Set the SSP ports SYSCLK only from Audio SYSCLK.
> + */
> +static int pxa168_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
> +                                    unsigned int freq, int dir)
> +{
> +       struct ssp_priv *priv = cpu_dai->private_data;
> +       struct ssp_device *ssp = priv->ssp;
> +       unsigned int sscr0, data, asysdr, asspdr;
> +
> +       dev_dbg(&ssp->pdev->dev, "%s id: %d, clk_id %d, freq %u\n",
> +               __func__, cpu_dai->id, clk_id, freq);
> +
> +       /* freq is the index of mclk_conf table */
> +       if ((freq < 0) || (freq >= ARRAY_SIZE(mclk_conf))) {
> +               dev_warn(&ssp->pdev->dev, "Wrong frequency index:%d\n", freq);
> +               return -EINVAL;
> +       }
> +       asysdr = (mclk_conf[freq].mclk_num << 16)
> +               | mclk_conf[freq].mclk_denom;
> +       asspdr = 0;
> +       /* If ASYSCLK is supplied by pxa168, ASSPDR should be configured. */
> +       if (dir == SND_SOC_CLOCK_OUT)
> +               asspdr = (mclk_conf[freq].bclk_num << 16)
> +                       | mclk_conf[freq].bclk_denom;
> +
> +       pxa_ssp_disable(ssp);
> +       clk_disable(ssp->clk);                  /* SSP port internal clock */
> +
> +       /* clear ECS, NCS, MOD, ACS */
> +       sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
> +       data = sscr0 & ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
> +       if (sscr0 != data)
> +               pxa_ssp_write_reg(ssp, SSCR0, data);
> +
> +       /* update divider register in MPMU */
> +       __raw_writel(asysdr, MPMU_ASYSDR);
> +       __raw_writel(asspdr, MPMU_ASSPDR);
> +
> +       clk_enable(ssp->clk);                   /* SSP port internal clock */
> +       pxa_ssp_enable(ssp);
> +       return 0;
> +}
> +
> +static int pxa168_ssp_hw_free(struct snd_pcm_substream *substream,
> +                             struct snd_soc_dai *dai)
> +{
> +       struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
> +       struct ssp_priv *priv = cpu_dai->private_data;
> +       struct ssp_device *ssp = priv->ssp;
> +
> +       pxa_ssp_disable(ssp);
> +       /* update divider register in MPMU */
> +       __raw_writel(0, MPMU_ASYSDR);
> +       __raw_writel(0, MPMU_ASSPDR);
> +       return 0;
> +}
> +
> +static struct snd_soc_dai_ops pxa168_ssp_dai_ops = {
> +       .hw_free        = pxa168_ssp_hw_free,
> +       .set_sysclk     = pxa168_ssp_set_dai_sysclk,
> +};
> +
> +#define PXA168_SSP_RATES       SNDRV_PCM_RATE_8000_96000
> +#define PXA168_SSP_FORMATS     (SNDRV_PCM_FMTBIT_S16_LE |      \
> +                               SNDRV_PCM_FMTBIT_S24_LE |       \
> +                               SNDRV_PCM_FMTBIT_S32_LE)
> +
> +#define PXA168_SSP_DAI(_id)                                    \
> +{                                                              \
> +       .name   = "pxa168-ssp",                                 \
> +       .id     = _id,                                          \
> +       .playback = {                                           \
> +               .channels_min = 1,                              \
> +               .channels_max = 2,                              \
> +               .rates = PXA168_SSP_RATES,                      \
> +               .formats = PXA168_SSP_FORMATS,                  \
> +       },                                                      \
> +       .capture = {                                            \
> +               .channels_min = 1,                              \
> +               .channels_max = 2,                              \
> +               .rates = PXA168_SSP_RATES,                      \
> +               .formats = PXA168_SSP_FORMATS,                  \
> +       },                                                      \
> +       .ops = &pxa168_ssp_dai_ops,                             \
> +}
> +
> +struct snd_soc_dai pxa168_ssp_dai[] = {
> +       PXA168_SSP_DAI(PXA168_DAI_SSP1),
> +       PXA168_SSP_DAI(PXA168_DAI_SSP2),
> +       PXA168_SSP_DAI(PXA168_DAI_SSP3),
> +       PXA168_SSP_DAI(PXA168_DAI_SSP4),
> +       PXA168_SSP_DAI(PXA168_DAI_SSP5),
> +};
> +EXPORT_SYMBOL_GPL(pxa168_ssp_dai);
> +
> +static int __init pxa168_ssp_init(void)
> +{
> +       struct snd_soc_dai *dai;
> +       int i, ret;
> +
> +       for (i = 0; i < ARRAY_SIZE(pxa168_ssp_dai); i++) {
> +               dai = &pxa168_ssp_dai[i];
> +               ret = pxa_ssp_register_dai(dai);
> +               if (ret)
> +                       return ret;
> +       }
> +       return ret;
> +}
> +module_init(pxa168_ssp_init);
> +
> +static void __exit pxa168_ssp_exit(void)
> +{
> +       struct snd_soc_dai *dai = NULL;
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(pxa168_ssp_dai); i++) {
> +               dai = &pxa168_ssp_dai[i];
> +               snd_soc_unregister_dai(dai);
> +       }
> +}
> +module_exit(pxa168_ssp_exit);
> +
> +/* Module information */
> +MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang at marvell.com>");
> +MODULE_DESCRIPTION("PXA168 SSP SoC Interface");
> +MODULE_LICENSE("GPL");
> +
> diff --git a/sound/soc/pxa/pxa168-ssp.h b/sound/soc/pxa/pxa168-ssp.h
> new file mode 100644
> index 0000000..bf73137
> --- /dev/null
> +++ b/sound/soc/pxa/pxa168-ssp.h
> @@ -0,0 +1,64 @@
> +/*
> + * ASoC PXA168 SSP port support
> + *
> + * 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.
> + */
> +
> +#ifndef _PXA168_SSP_H
> +#define _PXA168_SSP_H
> +
> +/* pxa DAI SSP IDs */
> +#define PXA168_DAI_SSP1                        0
> +#define PXA168_DAI_SSP2                        1
> +#define PXA168_DAI_SSP3                        2
> +#define PXA168_DAI_SSP4                        3
> +#define PXA168_DAI_SSP5                        4
> +
> +/* PXA168 SSP SYSCLK source */
> +#define PXA168_ASYSCLK_MASTER          0       /* ASYSCLK master -- pxa168 */
> +#define PXA168_ASYSCLK_SLAVE           1       /* ASYSCLK slave -- pxa168 */
> +
> +struct pxa168_ssp_mclk {
> +       unsigned int    rate;
> +       unsigned int    format;
> +       unsigned int    channel;
> +       unsigned int    mclk;
> +       unsigned int    mclk_denom;
> +       unsigned int    mclk_num;
> +       unsigned int    bclk;
> +       unsigned int    bclk_denom;
> +       unsigned int    bclk_num;
> +};
> +
> +/*
> + * This table is used while CPU is clock master.
> + * MCLK = 312MHz * ASYSCLK_DENOM / ASYSCLK_NUM
> + * BCLK = MCLK * SSPSCLK_DENOM / SSPSCLK_NUM
> + */
> +static const struct pxa168_ssp_mclk mclk_conf[] = {
> +       /* rate, fmt, chn, mclk,   den, num, bclk, den, num */
> +       {96000, 16, 2, 12288000,  64, 1625, 6144000,  1,  2},
> +       {96000, 16, 1, 12288000,  64, 1625, 1536000,  1,  8},
> +       {88200, 16, 2, 11289600, 294, 8125, 5644800,  1,  2},
> +       {88200, 16, 1, 11289600, 294, 8125, 1411200,  1,  8},
> +       {48000, 16, 2, 12288000,  64, 1625, 3072000,  1,  4},
> +       {48000, 16, 1, 12288000,  64, 1625,  768000,  1, 16},
> +       {44100, 16, 2, 11289600, 294, 8125, 2822400,  1,  4},
> +       {44100, 16, 1, 11289600, 294, 8125,  705600,  1, 16},
> +       {32000, 16, 2, 12288000,  64, 1625, 2048000,  1,  6},
> +       {32000, 16, 1, 12288000,  64, 1625,  512000,  1, 24},
> +       {22050, 16, 2, 11289600, 294, 8125, 1411200,  1,  8},
> +       {22050, 16, 1, 11289600, 294, 8125,  352800,  1, 32},
> +       {16000, 16, 2, 12288000,  64, 1625, 1024000,  1, 12},
> +       {16000, 16, 1, 12288000,  64, 1625,  256000,  1, 48},
> +       {11025, 16, 2, 11289600, 294, 8125,  705600,  1, 16},
> +       {11025, 16, 1, 11289600, 294, 8125,  176400,  1, 64},
> +       { 8000, 16, 2, 12288000,  64, 1625,  512000,  1, 24},
> +       { 8000, 16, 1, 12288000,  64, 1625,  128000,  1, 96},
> +};
> +

It's not a good idea to have a static array in the header file. And as
Mark pointed out in the comment to the later patch, this array and
the related functions could be well placed into some common places.
And I'm not sure if this applies to pxa910 as well, which could be
well ended up in common.c or pxa{168,910}.c.

> +extern struct snd_soc_dai pxa168_ssp_dai[];
> +
> +#endif
> --
> 1.5.6.5
>



More information about the linux-arm-kernel mailing list