04.10.2016, 17:54, "Mylène Josserand" <mylene.josserand@xxxxxxxxxxxxxxxxxx>: > Add the digital sun8i audio codec which handles the base register > (without DAI). > The driver handles only the basic playback of the A33 codec, from > the DAC to the headphones. All other features (microphone, capture, > etc) will be added later. > > Signed-off-by: Mylène Josserand <mylene.josserand@xxxxxxxxxxxxxxxxxx> > --- > sound/soc/sunxi/Kconfig | 9 + > sound/soc/sunxi/Makefile | 1 + > sound/soc/sunxi/sun8i-codec.c | 492 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 502 insertions(+) > create mode 100644 sound/soc/sunxi/sun8i-codec.c > > diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig > index 7aee95a..9e287b0 100644 > --- a/sound/soc/sunxi/Kconfig > +++ b/sound/soc/sunxi/Kconfig > @@ -27,6 +27,15 @@ config SND_SUN4I_SPDIF > Say Y or M to add support for the S/PDIF audio block in the Allwinner > A10 and affiliated SoCs. > > +config SND_SUN8I_CODEC > + tristate "Allwinner SUN8I audio codec" > + select REGMAP_MMIO > + help > + This option enables the digital part of the internal audio codec for > + Allwinner sun8i SoC. > + > + Say Y or M if you want to add sun8i digital audio codec support. > + > config SND_SUN8I_CODEC_ANALOG > tristate "Allwinner SUN8I analog codec" > select REGMAP_MMIO > diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile > index 241c0df..1da63d3 100644 > --- a/sound/soc/sunxi/Makefile > +++ b/sound/soc/sunxi/Makefile > @@ -1,4 +1,5 @@ > obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o > obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o > obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o > +obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o > obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o > diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c > new file mode 100644 > index 0000000..e157f89 > --- /dev/null > +++ b/sound/soc/sunxi/sun8i-codec.c > @@ -0,0 +1,492 @@ > +/* > + * This driver supports the digital controls for the internal codec > + * found in Allwinner's A33 and A23 SoCs. > + * > + * (C) Copyright 2010-2016 > + * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com> > + * huangxin <huangxin@xxxxxxxxxxxxxxxxx> > + * Mylène Josserand <mylene.josserand@xxxxxxxxxxxxxxxxxx> > + * > + * 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/delay.h> > +#include <linux/clk.h> > +#include <linux/io.h> > +#include <linux/regmap.h> > + > +#include <sound/pcm_params.h> > +#include <sound/soc.h> > +#include <sound/soc-dapm.h> > + > +/* CODEC_OFFSET represents the offset of the codec registers > + * and not all the DAI registers > + */ > +#define CODEC_OFFSET 0x200 > +#define CODEC_BASSADDRESS 0x01c22c00 I don't think this kind of absolute address should exist here... It should exist in device tree... > +#define SUN8I_SYSCLK_CTL (0x20c - CODEC_OFFSET) > +#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA (11) > +#define SUN8I_SYSCLK_CTL_SYSCLK_ENA (3) > +#define SUN8I_SYSCLK_CTL_SYSCLK_SRC (0) > +#define SUN8I_MOD_CLK_ENA (0x210 - CODEC_OFFSET) > +#define SUN8I_MOD_CLK_ENA_AIF1 (15) > +#define SUN8I_MOD_CLK_ENA_DAC (2) > +#define SUN8I_MOD_RST_CTL (0x214 - CODEC_OFFSET) > +#define SUN8I_MOD_RST_CTL_AIF1 (15) > +#define SUN8I_MOD_RST_CTL_DAC (2) > +#define SUN8I_SYS_SR_CTRL (0x218 - CODEC_OFFSET) > +#define SUN8I_SYS_SR_CTRL_AIF1_FS (12) > +#define SUN8I_SYS_SR_CTRL_AIF2_FS (8) > +#define SUN8I_AIF1CLK_CTRL (0x240 - CODEC_OFFSET) > +#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD (15) > +#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV (14) > +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV (13) > +#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV (9) > +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV (6) > +#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ (4) > +#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT (2) > +#define SUN8I_AIF1_DACDAT_CTRL (0x248 - CODEC_OFFSET) > +#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA (15) > +#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA (14) > +#define SUN8I_DAC_DIG_CTRL (0x320 - CODEC_OFFSET) > +#define SUN8I_DAC_DIG_CTRL_ENDA (15) > +#define SUN8I_DAC_MXR_SRC (0x330 - CODEC_OFFSET) > +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L (15) > +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L (14) > +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL (13) > +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL (12) > +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R (11) > +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R (10) > +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR (9) > +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR (8) > + > +struct sun8i_codec { > + struct device *dev; > + struct regmap *regmap; > + struct clk *clk_module; > + struct clk *clk_apb; > +}; > + > +static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) > +{ > + unsigned int rate = params_rate(params); > + > + switch (rate) { > + case 8000: > + case 7350: > + return 0x0; > + case 11025: > + return 0x1; > + case 12000: > + return 0x2; > + case 16000: > + return 0x3; > + case 22050: > + return 0x4; > + case 24000: > + return 0x5; > + case 32000: > + return 0x6; > + case 44100: > + return 0x7; > + case 48000: > + return 0x8; > + case 96000: > + return 0x9; > + case 192000: > + return 0xa; > + default: > + return -EINVAL; > + } > +} > + > +static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) > +{ > + struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); > + unsigned long value; > + > + /* clock masters */ > + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { > + case SND_SOC_DAIFMT_CBS_CFS: /* DAI Slave */ > + value = 0x0; /* Codec Master */ > + break; > + case SND_SOC_DAIFMT_CBM_CFM: /* DAI Master */ > + value = 0x1; /* Codec Slave */ > + break; > + default: > + return -EINVAL; > + } > + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, > + BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD), > + value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD); > + > + /* clock inversion */ > + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { > + case SND_SOC_DAIFMT_NB_NF: /* Normal */ > + value = 0x0; > + break; > + case SND_SOC_DAIFMT_IB_IF: /* Inversion */ > + value = 0x1; > + break; > + default: > + return -EINVAL; > + } > + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, > + BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV), > + value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); > + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, > + BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), > + value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); > + > + /* DAI format */ > + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { > + case SND_SOC_DAIFMT_I2S: > + value = 0x0; > + break; > + case SND_SOC_DAIFMT_LEFT_J: > + value = 0x1; > + break; > + case SND_SOC_DAIFMT_RIGHT_J: > + value = 0x2; > + break; > + case SND_SOC_DAIFMT_DSP_A: > + case SND_SOC_DAIFMT_DSP_B: > + value = 0x3; > + break; > + default: > + return -EINVAL; > + } > + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, > + BIT(SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT), > + value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); > + > + return 0; > +} > + > +static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, > + struct snd_pcm_hw_params *params, > + struct snd_soc_dai *dai) > +{ > + int rs_value = 0; > + u32 bclk_lrck_div = 0, sample_resolution; > + int sample_rate = 0; > + struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); > + > + switch (params_format(params)) { > + case SNDRV_PCM_FORMAT_S16_LE: > + sample_resolution = 16; > + break; > + case SNDRV_PCM_FORMAT_S20_3LE: > + case SNDRV_PCM_FORMAT_S24_LE: > + case SNDRV_PCM_FORMAT_S32_LE: > + sample_resolution = 24; > + break; > + default: > + return -EINVAL; > + } > + > + /*calculate word select bit*/ > + switch (sample_resolution) { > + case 8: > + rs_value = 0x0; > + break; > + case 16: > + rs_value = 0x1; > + break; > + case 20: > + rs_value = 0x2; > + break; > + case 24: > + rs_value = 0x3; > + break; > + default: > + break; > + } > + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, > + 0x3 << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ, > + rs_value << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ); > + > + /* calculate bclk_lrck_div Ratio */ > + bclk_lrck_div = sample_resolution * 2; > + switch (bclk_lrck_div) { > + case 16: > + bclk_lrck_div = 0; > + break; > + case 32: > + bclk_lrck_div = 1; > + break; > + case 64: > + bclk_lrck_div = 2; > + break; > + case 128: > + bclk_lrck_div = 3; > + break; > + case 256: > + bclk_lrck_div = 4; > + break; > + default: > + break; > + } > + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, > + 0x7 << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV, > + bclk_lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); > + > + sample_rate = sun8i_codec_get_hw_rate(params); > + if (sample_rate < 0) > + return sample_rate; > + > + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, > + 0xf << SUN8I_SYS_SR_CTRL_AIF1_FS, > + sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); > + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, > + 0xf << SUN8I_SYS_SR_CTRL_AIF2_FS, > + sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS); > + > + return 0; > +} > + > +static const struct snd_kcontrol_new sun8i_output_left_mixer_controls[] = { > + SOC_DAPM_SINGLE("LSlot 0", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, 1, 0), > + SOC_DAPM_SINGLE("LSlot 1", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, 1, 0), > + SOC_DAPM_SINGLE("DACL", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, 1, 0), > + SOC_DAPM_SINGLE("ADCL", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, 1, 0), > +}; > + > +static const struct snd_kcontrol_new sun8i_output_right_mixer_controls[] = { > + SOC_DAPM_SINGLE("RSlot 0", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0), > + SOC_DAPM_SINGLE("RSlot 1", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0), > + SOC_DAPM_SINGLE("DACR", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0), > + SOC_DAPM_SINGLE("ADCR", SUN8I_DAC_MXR_SRC, > + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0), > +}; > + > +static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { > + /* Digital parts of the DACs */ > + SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA, > + 0, NULL, 0), > + > + /* Analog DAC */ > + SND_SOC_DAPM_DAC("Left DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL, > + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), > + SND_SOC_DAPM_DAC("Right DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL, > + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), > + > + /* DAC Mixers */ > + SND_SOC_DAPM_MIXER("Left DAC Mixer", SND_SOC_NOPM, 0, 0, > + sun8i_output_left_mixer_controls, > + ARRAY_SIZE(sun8i_output_left_mixer_controls)), > + SND_SOC_DAPM_MIXER("Right DAC Mixer", SND_SOC_NOPM, 0, 0, > + sun8i_output_right_mixer_controls, > + ARRAY_SIZE(sun8i_output_right_mixer_controls)), > + > + /* Clocks */ > + SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA, > + SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), > + SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA, > + SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), > + SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL, > + SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), > + SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL, > + SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), > + > + SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL, 0x9, 0, NULL, 0), > + /* Inversion as 0=AIF1, 1=AIF2 */ > + SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL, > + SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0), > + > + /* Module reset */ > + SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL, > + SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), > + SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL, > + SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), > + > + /* Headphone outputs */ > + SND_SOC_DAPM_OUTPUT("HPOUTL"), > + SND_SOC_DAPM_OUTPUT("HPOUTR"), > + > +}; > + > +static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { > + /* Clock Routes */ > + { "AIF1", NULL, "SYSCLK AIF1" }, > + { "AIF1 PLL", NULL, "AIF1" }, > + { "RST AIF1", NULL, "AIF1 PLL" }, > + { "MODCLK AFI1", NULL, "RST AIF1" }, > + { "DAC", NULL, "MODCLK AFI1" }, > + > + { "RST DAC", NULL, "SYSCLK" }, > + { "MODCLK DAC", NULL, "RST DAC" }, > + { "DAC", NULL, "MODCLK DAC" }, > + > + /* DAC Routes */ > + { "Left DAC", NULL, "DAC" }, > + { "Right DAC", NULL, "DAC" }, > + > + /* DAC Mixer Routes */ > + { "Left DAC Mixer", "LSlot 0", "Left DAC"}, > + { "Right DAC Mixer", "RSlot 0", "Right DAC"}, > + > + /* End of route : HP out */ > + { "HPOUTL", NULL, "Left DAC Mixer" }, > + { "HPOUTR", NULL, "Right DAC Mixer" }, > +}; > + > +static struct snd_soc_dai_ops sun8i_codec_dai_ops = { > + .hw_params = sun8i_codec_hw_params, > + .set_fmt = sun8i_set_fmt, > +}; > + > +static struct snd_soc_dai_driver sun8i_codec_dai = { > + .name = "sun8i", > + /* playback capabilities */ > + .playback = { > + .stream_name = "Playback", > + .channels_min = 1, > + .channels_max = 2, > + .rates = SNDRV_PCM_RATE_8000_192000 | > + SNDRV_PCM_RATE_KNOT, > + .formats = SNDRV_PCM_FMTBIT_S8 | > + SNDRV_PCM_FMTBIT_S16_LE | > + SNDRV_PCM_FMTBIT_S18_3LE | > + SNDRV_PCM_FMTBIT_S20_3LE | > + SNDRV_PCM_FMTBIT_S24_LE | > + SNDRV_PCM_FMTBIT_S32_LE, > + }, > + /* pcm operations */ > + .ops = &sun8i_codec_dai_ops, > +}; > +EXPORT_SYMBOL(sun8i_codec_dai); > + > +static int sun8i_soc_probe(struct snd_soc_codec *codec) > +{ > + return 0; > +} > + > +/* power down chip */ > +static int sun8i_soc_remove(struct snd_soc_codec *codec) > +{ > + return 0; > +} > + > +static struct snd_soc_codec_driver sun8i_soc_codec = { > + .probe = sun8i_soc_probe, > + .remove = sun8i_soc_remove, > + .component_driver = { > + .dapm_widgets = sun8i_codec_dapm_widgets, > + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), > + .dapm_routes = sun8i_codec_dapm_routes, > + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), > + }, > +}; > + > +static const struct regmap_config sun8i_codec_regmap_config = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > + .max_register = SUN8I_DAC_MXR_SRC, > +}; > + > +static int sun8i_codec_probe(struct platform_device *pdev) > +{ > + struct resource *res_base; > + struct sun8i_codec *scodec; > + void __iomem *base; > + > + scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL); > + if (!scodec) > + return -ENOMEM; > + > + scodec->dev = &pdev->dev; > + > + /* Get the clocks from the DT */ > + scodec->clk_module = devm_clk_get(&pdev->dev, "codec"); > + if (IS_ERR(scodec->clk_module)) { > + dev_err(&pdev->dev, "Failed to get the module clock\n"); > + return PTR_ERR(scodec->clk_module); > + } > + if (clk_prepare_enable(scodec->clk_module)) > + pr_err("err:open failed;\n"); > + > + scodec->clk_apb = devm_clk_get(&pdev->dev, "apb"); > + if (IS_ERR(scodec->clk_apb)) { > + dev_err(&pdev->dev, "Failed to get the apb clock\n"); > + return PTR_ERR(scodec->clk_apb); > + } > + if (clk_prepare_enable(scodec->clk_apb)) > + pr_err("err:open failed;\n"); > + > + /* Get base resources, registers and regmap */ > + res_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audio"); > + base = devm_ioremap_resource(&pdev->dev, res_base); > + if (IS_ERR(base)) { > + dev_err(&pdev->dev, "Failed to map the registers\n"); > + return PTR_ERR(base); > + } > + > + scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, > + &sun8i_codec_regmap_config); > + if (IS_ERR(scodec->regmap)) { > + dev_err(&pdev->dev, "Failed to create our regmap\n"); > + return PTR_ERR(scodec->regmap); > + } > + > + /* Set the codec data as driver data */ > + dev_set_drvdata(&pdev->dev, scodec); > + > + snd_soc_register_codec(&pdev->dev, &sun8i_soc_codec, &sun8i_codec_dai, > + 1); > + > + return 0; > +} > + > +static int sun8i_codec_remove(struct platform_device *pdev) > +{ > + struct snd_soc_card *card = platform_get_drvdata(pdev); > + struct sun8i_codec *scodec = snd_soc_card_get_drvdata(card); > + > + snd_soc_unregister_codec(&pdev->dev); > + clk_disable_unprepare(scodec->clk_module); > + clk_disable_unprepare(scodec->clk_apb); > + > + return 0; > +} > + > +static const struct of_device_id sun8i_codec_of_match[] = { > + { .compatible = "allwinner,sun8i-a33-codec" }, > + { .compatible = "allwinner,sun8i-a23-codec" }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); > + > +static struct platform_driver sun8i_codec_driver = { > + .driver = { > + .name = "sun8i-codec", > + .owner = THIS_MODULE, > + .of_match_table = sun8i_codec_of_match, > + }, > + .probe = sun8i_codec_probe, > + .remove = sun8i_codec_remove, > +}; > +module_platform_driver(sun8i_codec_driver); > + > +MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver"); > +MODULE_AUTHOR("huanxin<huanxin@xxxxxxxxxxxxxxxxx>"); > +MODULE_AUTHOR("Mylène Josserand <mylene.josserand@xxxxxxxxxxxxxxxxxx>"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:sun8i-codec"); > -- > 2.9.3 > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel