cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sun4i-codec.c (59628B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2014 Emilio López <emilio@elopez.com.ar>
      4 * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
      5 * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
      6 * Copyright 2015 Adam Sampson <ats@offog.org>
      7 * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
      8 *
      9 * Based on the Allwinner SDK driver, released under the GPL.
     10 */
     11
     12#include <linux/init.h>
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/platform_device.h>
     16#include <linux/delay.h>
     17#include <linux/slab.h>
     18#include <linux/of.h>
     19#include <linux/of_address.h>
     20#include <linux/of_device.h>
     21#include <linux/of_platform.h>
     22#include <linux/clk.h>
     23#include <linux/regmap.h>
     24#include <linux/reset.h>
     25#include <linux/gpio/consumer.h>
     26
     27#include <sound/core.h>
     28#include <sound/pcm.h>
     29#include <sound/pcm_params.h>
     30#include <sound/soc.h>
     31#include <sound/tlv.h>
     32#include <sound/initval.h>
     33#include <sound/dmaengine_pcm.h>
     34
     35/* Codec DAC digital controls and FIFO registers */
     36#define SUN4I_CODEC_DAC_DPC			(0x00)
     37#define SUN4I_CODEC_DAC_DPC_EN_DA			(31)
     38#define SUN4I_CODEC_DAC_DPC_DVOL			(12)
     39#define SUN4I_CODEC_DAC_FIFOC			(0x04)
     40#define SUN4I_CODEC_DAC_FIFOC_DAC_FS			(29)
     41#define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION		(28)
     42#define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT		(26)
     43#define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE		(24)
     44#define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT		(21)
     45#define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL		(8)
     46#define SUN4I_CODEC_DAC_FIFOC_MONO_EN			(6)
     47#define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS		(5)
     48#define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN		(4)
     49#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH		(0)
     50#define SUN4I_CODEC_DAC_FIFOS			(0x08)
     51#define SUN4I_CODEC_DAC_TXDATA			(0x0c)
     52
     53/* Codec DAC side analog signal controls */
     54#define SUN4I_CODEC_DAC_ACTL			(0x10)
     55#define SUN4I_CODEC_DAC_ACTL_DACAENR			(31)
     56#define SUN4I_CODEC_DAC_ACTL_DACAENL			(30)
     57#define SUN4I_CODEC_DAC_ACTL_MIXEN			(29)
     58#define SUN4I_CODEC_DAC_ACTL_LNG			(26)
     59#define SUN4I_CODEC_DAC_ACTL_FMG			(23)
     60#define SUN4I_CODEC_DAC_ACTL_MICG			(20)
     61#define SUN4I_CODEC_DAC_ACTL_LLNS			(19)
     62#define SUN4I_CODEC_DAC_ACTL_RLNS			(18)
     63#define SUN4I_CODEC_DAC_ACTL_LFMS			(17)
     64#define SUN4I_CODEC_DAC_ACTL_RFMS			(16)
     65#define SUN4I_CODEC_DAC_ACTL_LDACLMIXS			(15)
     66#define SUN4I_CODEC_DAC_ACTL_RDACRMIXS			(14)
     67#define SUN4I_CODEC_DAC_ACTL_LDACRMIXS			(13)
     68#define SUN4I_CODEC_DAC_ACTL_MIC1LS			(12)
     69#define SUN4I_CODEC_DAC_ACTL_MIC1RS			(11)
     70#define SUN4I_CODEC_DAC_ACTL_MIC2LS			(10)
     71#define SUN4I_CODEC_DAC_ACTL_MIC2RS			(9)
     72#define SUN4I_CODEC_DAC_ACTL_DACPAS			(8)
     73#define SUN4I_CODEC_DAC_ACTL_MIXPAS			(7)
     74#define SUN4I_CODEC_DAC_ACTL_PA_MUTE			(6)
     75#define SUN4I_CODEC_DAC_ACTL_PA_VOL			(0)
     76#define SUN4I_CODEC_DAC_TUNE			(0x14)
     77#define SUN4I_CODEC_DAC_DEBUG			(0x18)
     78
     79/* Codec ADC digital controls and FIFO registers */
     80#define SUN4I_CODEC_ADC_FIFOC			(0x1c)
     81#define SUN4I_CODEC_ADC_FIFOC_ADC_FS			(29)
     82#define SUN4I_CODEC_ADC_FIFOC_EN_AD			(28)
     83#define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE		(24)
     84#define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL		(8)
     85#define SUN4I_CODEC_ADC_FIFOC_MONO_EN			(7)
     86#define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS		(6)
     87#define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN		(4)
     88#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH		(0)
     89#define SUN4I_CODEC_ADC_FIFOS			(0x20)
     90#define SUN4I_CODEC_ADC_RXDATA			(0x24)
     91
     92/* Codec ADC side analog signal controls */
     93#define SUN4I_CODEC_ADC_ACTL			(0x28)
     94#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN			(31)
     95#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN			(30)
     96#define SUN4I_CODEC_ADC_ACTL_PREG1EN			(29)
     97#define SUN4I_CODEC_ADC_ACTL_PREG2EN			(28)
     98#define SUN4I_CODEC_ADC_ACTL_VMICEN			(27)
     99#define SUN4I_CODEC_ADC_ACTL_PREG1			(25)
    100#define SUN4I_CODEC_ADC_ACTL_PREG2			(23)
    101#define SUN4I_CODEC_ADC_ACTL_VADCG			(20)
    102#define SUN4I_CODEC_ADC_ACTL_ADCIS			(17)
    103#define SUN4I_CODEC_ADC_ACTL_LNPREG			(13)
    104#define SUN4I_CODEC_ADC_ACTL_PA_EN			(4)
    105#define SUN4I_CODEC_ADC_ACTL_DDE			(3)
    106#define SUN4I_CODEC_ADC_DEBUG			(0x2c)
    107
    108/* FIFO counters */
    109#define SUN4I_CODEC_DAC_TXCNT			(0x30)
    110#define SUN4I_CODEC_ADC_RXCNT			(0x34)
    111
    112/* Calibration register (sun7i only) */
    113#define SUN7I_CODEC_AC_DAC_CAL			(0x38)
    114
    115/* Microphone controls (sun7i only) */
    116#define SUN7I_CODEC_AC_MIC_PHONE_CAL		(0x3c)
    117
    118#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1		(29)
    119#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2		(26)
    120
    121/*
    122 * sun6i specific registers
    123 *
    124 * sun6i shares the same digital control and FIFO registers as sun4i,
    125 * but only the DAC digital controls are at the same offset. The others
    126 * have been moved around to accommodate extra analog controls.
    127 */
    128
    129/* Codec DAC digital controls and FIFO registers */
    130#define SUN6I_CODEC_ADC_FIFOC			(0x10)
    131#define SUN6I_CODEC_ADC_FIFOC_EN_AD			(28)
    132#define SUN6I_CODEC_ADC_FIFOS			(0x14)
    133#define SUN6I_CODEC_ADC_RXDATA			(0x18)
    134
    135/* Output mixer and gain controls */
    136#define SUN6I_CODEC_OM_DACA_CTRL		(0x20)
    137#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN		(31)
    138#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN		(30)
    139#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN			(29)
    140#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN			(28)
    141#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1		(23)
    142#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2		(22)
    143#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE		(21)
    144#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP		(20)
    145#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR		(19)
    146#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR		(18)
    147#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL		(17)
    148#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1		(16)
    149#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2		(15)
    150#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE		(14)
    151#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN		(13)
    152#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL		(12)
    153#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL		(11)
    154#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR		(10)
    155#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS			(9)
    156#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS			(8)
    157#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE		(7)
    158#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE		(6)
    159#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL			(0)
    160#define SUN6I_CODEC_OM_PA_CTRL			(0x24)
    161#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN			(31)
    162#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL		(29)
    163#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN			(28)
    164#define SUN6I_CODEC_OM_PA_CTRL_MIC1G			(15)
    165#define SUN6I_CODEC_OM_PA_CTRL_MIC2G			(12)
    166#define SUN6I_CODEC_OM_PA_CTRL_LINEING			(9)
    167#define SUN6I_CODEC_OM_PA_CTRL_PHONEG			(6)
    168#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG			(3)
    169#define SUN6I_CODEC_OM_PA_CTRL_PHONENG			(0)
    170
    171/* Microphone, line out and phone out controls */
    172#define SUN6I_CODEC_MIC_CTRL			(0x28)
    173#define SUN6I_CODEC_MIC_CTRL_HBIASEN			(31)
    174#define SUN6I_CODEC_MIC_CTRL_MBIASEN			(30)
    175#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN			(28)
    176#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST			(25)
    177#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN			(24)
    178#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST			(21)
    179#define SUN6I_CODEC_MIC_CTRL_MIC2SLT			(20)
    180#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN			(19)
    181#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN			(18)
    182#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC		(17)
    183#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC		(16)
    184#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC			(11)
    185#define SUN6I_CODEC_MIC_CTRL_PHONEPREG			(8)
    186
    187/* ADC mixer controls */
    188#define SUN6I_CODEC_ADC_ACTL			(0x2c)
    189#define SUN6I_CODEC_ADC_ACTL_ADCREN			(31)
    190#define SUN6I_CODEC_ADC_ACTL_ADCLEN			(30)
    191#define SUN6I_CODEC_ADC_ACTL_ADCRG			(27)
    192#define SUN6I_CODEC_ADC_ACTL_ADCLG			(24)
    193#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1		(13)
    194#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2		(12)
    195#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE		(11)
    196#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP		(10)
    197#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR		(9)
    198#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR		(8)
    199#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL		(7)
    200#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1		(6)
    201#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2		(5)
    202#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE		(4)
    203#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN		(3)
    204#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL		(2)
    205#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL		(1)
    206#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR		(0)
    207
    208/* Analog performance tuning controls */
    209#define SUN6I_CODEC_ADDA_TUNE			(0x30)
    210
    211/* Calibration controls */
    212#define SUN6I_CODEC_CALIBRATION			(0x34)
    213
    214/* FIFO counters */
    215#define SUN6I_CODEC_DAC_TXCNT			(0x40)
    216#define SUN6I_CODEC_ADC_RXCNT			(0x44)
    217
    218/* headset jack detection and button support registers */
    219#define SUN6I_CODEC_HMIC_CTL			(0x50)
    220#define SUN6I_CODEC_HMIC_DATA			(0x54)
    221
    222/* TODO sun6i DAP (Digital Audio Processing) bits */
    223
    224/* FIFO counters moved on A23 */
    225#define SUN8I_A23_CODEC_DAC_TXCNT		(0x1c)
    226#define SUN8I_A23_CODEC_ADC_RXCNT		(0x20)
    227
    228/* TX FIFO moved on H3 */
    229#define SUN8I_H3_CODEC_DAC_TXDATA		(0x20)
    230#define SUN8I_H3_CODEC_DAC_DBG			(0x48)
    231#define SUN8I_H3_CODEC_ADC_DBG			(0x4c)
    232
    233/* TODO H3 DAP (Digital Audio Processing) bits */
    234
    235struct sun4i_codec {
    236	struct device	*dev;
    237	struct regmap	*regmap;
    238	struct clk	*clk_apb;
    239	struct clk	*clk_module;
    240	struct reset_control *rst;
    241	struct gpio_desc *gpio_pa;
    242
    243	/* ADC_FIFOC register is at different offset on different SoCs */
    244	struct regmap_field *reg_adc_fifoc;
    245
    246	struct snd_dmaengine_dai_dma_data	capture_dma_data;
    247	struct snd_dmaengine_dai_dma_data	playback_dma_data;
    248};
    249
    250static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
    251{
    252	/* Flush TX FIFO */
    253	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    254			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
    255			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
    256
    257	/* Enable DAC DRQ */
    258	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    259			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
    260			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
    261}
    262
    263static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
    264{
    265	/* Disable DAC DRQ */
    266	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    267			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
    268			   0);
    269}
    270
    271static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
    272{
    273	/* Enable ADC DRQ */
    274	regmap_field_update_bits(scodec->reg_adc_fifoc,
    275				 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
    276				 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
    277}
    278
    279static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
    280{
    281	/* Disable ADC DRQ */
    282	regmap_field_update_bits(scodec->reg_adc_fifoc,
    283				 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
    284}
    285
    286static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
    287			       struct snd_soc_dai *dai)
    288{
    289	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    290	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
    291
    292	switch (cmd) {
    293	case SNDRV_PCM_TRIGGER_START:
    294	case SNDRV_PCM_TRIGGER_RESUME:
    295	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    296		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    297			sun4i_codec_start_playback(scodec);
    298		else
    299			sun4i_codec_start_capture(scodec);
    300		break;
    301
    302	case SNDRV_PCM_TRIGGER_STOP:
    303	case SNDRV_PCM_TRIGGER_SUSPEND:
    304	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    305		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    306			sun4i_codec_stop_playback(scodec);
    307		else
    308			sun4i_codec_stop_capture(scodec);
    309		break;
    310
    311	default:
    312		return -EINVAL;
    313	}
    314
    315	return 0;
    316}
    317
    318static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
    319				       struct snd_soc_dai *dai)
    320{
    321	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    322	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
    323
    324
    325	/* Flush RX FIFO */
    326	regmap_field_update_bits(scodec->reg_adc_fifoc,
    327				 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
    328				 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
    329
    330
    331	/* Set RX FIFO trigger level */
    332	regmap_field_update_bits(scodec->reg_adc_fifoc,
    333				 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
    334				 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
    335
    336	/*
    337	 * FIXME: Undocumented in the datasheet, but
    338	 *        Allwinner's code mentions that it is
    339	 *        related to microphone gain
    340	 */
    341	if (of_device_is_compatible(scodec->dev->of_node,
    342				    "allwinner,sun4i-a10-codec") ||
    343	    of_device_is_compatible(scodec->dev->of_node,
    344				    "allwinner,sun7i-a20-codec")) {
    345		regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
    346				   0x3 << 25,
    347				   0x1 << 25);
    348	}
    349
    350	if (of_device_is_compatible(scodec->dev->of_node,
    351				    "allwinner,sun7i-a20-codec"))
    352		/* FIXME: Undocumented bits */
    353		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
    354				   0x3 << 8,
    355				   0x1 << 8);
    356
    357	return 0;
    358}
    359
    360static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
    361					struct snd_soc_dai *dai)
    362{
    363	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    364	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
    365	u32 val;
    366
    367	/* Flush the TX FIFO */
    368	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    369			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
    370			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
    371
    372	/* Set TX FIFO Empty Trigger Level */
    373	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    374			   0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
    375			   0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
    376
    377	if (substream->runtime->rate > 32000)
    378		/* Use 64 bits FIR filter */
    379		val = 0;
    380	else
    381		/* Use 32 bits FIR filter */
    382		val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
    383
    384	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    385			   BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
    386			   val);
    387
    388	/* Send zeros when we have an underrun */
    389	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    390			   BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
    391			   0);
    392
    393	return 0;
    394};
    395
    396static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
    397			       struct snd_soc_dai *dai)
    398{
    399	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    400		return sun4i_codec_prepare_playback(substream, dai);
    401
    402	return sun4i_codec_prepare_capture(substream, dai);
    403}
    404
    405static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
    406{
    407	unsigned int rate = params_rate(params);
    408
    409	switch (rate) {
    410	case 176400:
    411	case 88200:
    412	case 44100:
    413	case 33075:
    414	case 22050:
    415	case 14700:
    416	case 11025:
    417	case 7350:
    418		return 22579200;
    419
    420	case 192000:
    421	case 96000:
    422	case 48000:
    423	case 32000:
    424	case 24000:
    425	case 16000:
    426	case 12000:
    427	case 8000:
    428		return 24576000;
    429
    430	default:
    431		return 0;
    432	}
    433}
    434
    435static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
    436{
    437	unsigned int rate = params_rate(params);
    438
    439	switch (rate) {
    440	case 192000:
    441	case 176400:
    442		return 6;
    443
    444	case 96000:
    445	case 88200:
    446		return 7;
    447
    448	case 48000:
    449	case 44100:
    450		return 0;
    451
    452	case 32000:
    453	case 33075:
    454		return 1;
    455
    456	case 24000:
    457	case 22050:
    458		return 2;
    459
    460	case 16000:
    461	case 14700:
    462		return 3;
    463
    464	case 12000:
    465	case 11025:
    466		return 4;
    467
    468	case 8000:
    469	case 7350:
    470		return 5;
    471
    472	default:
    473		return -EINVAL;
    474	}
    475}
    476
    477static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
    478					 struct snd_pcm_hw_params *params,
    479					 unsigned int hwrate)
    480{
    481	/* Set ADC sample rate */
    482	regmap_field_update_bits(scodec->reg_adc_fifoc,
    483				 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
    484				 hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
    485
    486	/* Set the number of channels we want to use */
    487	if (params_channels(params) == 1)
    488		regmap_field_update_bits(scodec->reg_adc_fifoc,
    489					 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
    490					 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
    491	else
    492		regmap_field_update_bits(scodec->reg_adc_fifoc,
    493					 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
    494					 0);
    495
    496	/* Set the number of sample bits to either 16 or 24 bits */
    497	if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
    498		regmap_field_update_bits(scodec->reg_adc_fifoc,
    499				   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
    500				   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
    501
    502		regmap_field_update_bits(scodec->reg_adc_fifoc,
    503				   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
    504				   0);
    505
    506		scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
    507	} else {
    508		regmap_field_update_bits(scodec->reg_adc_fifoc,
    509				   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
    510				   0);
    511
    512		/* Fill most significant bits with valid data MSB */
    513		regmap_field_update_bits(scodec->reg_adc_fifoc,
    514				   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
    515				   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
    516
    517		scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
    518	}
    519
    520	return 0;
    521}
    522
    523static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
    524					  struct snd_pcm_hw_params *params,
    525					  unsigned int hwrate)
    526{
    527	u32 val;
    528
    529	/* Set DAC sample rate */
    530	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    531			   7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
    532			   hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
    533
    534	/* Set the number of channels we want to use */
    535	if (params_channels(params) == 1)
    536		val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
    537	else
    538		val = 0;
    539
    540	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    541			   BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
    542			   val);
    543
    544	/* Set the number of sample bits to either 16 or 24 bits */
    545	if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
    546		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    547				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
    548				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
    549
    550		/* Set TX FIFO mode to padding the LSBs with 0 */
    551		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    552				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
    553				   0);
    554
    555		scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
    556	} else {
    557		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    558				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
    559				   0);
    560
    561		/* Set TX FIFO mode to repeat the MSB */
    562		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    563				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
    564				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
    565
    566		scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
    567	}
    568
    569	return 0;
    570}
    571
    572static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
    573				 struct snd_pcm_hw_params *params,
    574				 struct snd_soc_dai *dai)
    575{
    576	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    577	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
    578	unsigned long clk_freq;
    579	int ret, hwrate;
    580
    581	clk_freq = sun4i_codec_get_mod_freq(params);
    582	if (!clk_freq)
    583		return -EINVAL;
    584
    585	ret = clk_set_rate(scodec->clk_module, clk_freq);
    586	if (ret)
    587		return ret;
    588
    589	hwrate = sun4i_codec_get_hw_rate(params);
    590	if (hwrate < 0)
    591		return hwrate;
    592
    593	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    594		return sun4i_codec_hw_params_playback(scodec, params,
    595						      hwrate);
    596
    597	return sun4i_codec_hw_params_capture(scodec, params,
    598					     hwrate);
    599}
    600
    601
    602static unsigned int sun4i_codec_src_rates[] = {
    603	8000, 11025, 12000, 16000, 22050, 24000, 32000,
    604	44100, 48000, 96000, 192000
    605};
    606
    607
    608static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
    609	.count  = ARRAY_SIZE(sun4i_codec_src_rates),
    610	.list   = sun4i_codec_src_rates,
    611};
    612
    613
    614static int sun4i_codec_startup(struct snd_pcm_substream *substream,
    615			       struct snd_soc_dai *dai)
    616{
    617	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    618	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
    619
    620	snd_pcm_hw_constraint_list(substream->runtime, 0,
    621				SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
    622
    623	/*
    624	 * Stop issuing DRQ when we have room for less than 16 samples
    625	 * in our TX FIFO
    626	 */
    627	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
    628			   3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
    629			   3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
    630
    631	return clk_prepare_enable(scodec->clk_module);
    632}
    633
    634static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
    635				 struct snd_soc_dai *dai)
    636{
    637	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    638	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
    639
    640	clk_disable_unprepare(scodec->clk_module);
    641}
    642
    643static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
    644	.startup	= sun4i_codec_startup,
    645	.shutdown	= sun4i_codec_shutdown,
    646	.trigger	= sun4i_codec_trigger,
    647	.hw_params	= sun4i_codec_hw_params,
    648	.prepare	= sun4i_codec_prepare,
    649};
    650
    651static struct snd_soc_dai_driver sun4i_codec_dai = {
    652	.name	= "Codec",
    653	.ops	= &sun4i_codec_dai_ops,
    654	.playback = {
    655		.stream_name	= "Codec Playback",
    656		.channels_min	= 1,
    657		.channels_max	= 2,
    658		.rate_min	= 8000,
    659		.rate_max	= 192000,
    660		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
    661		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
    662				  SNDRV_PCM_FMTBIT_S32_LE,
    663		.sig_bits	= 24,
    664	},
    665	.capture = {
    666		.stream_name	= "Codec Capture",
    667		.channels_min	= 1,
    668		.channels_max	= 2,
    669		.rate_min	= 8000,
    670		.rate_max	= 48000,
    671		.rates		= SNDRV_PCM_RATE_CONTINUOUS,
    672		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
    673				  SNDRV_PCM_FMTBIT_S32_LE,
    674		.sig_bits	= 24,
    675	},
    676};
    677
    678/*** sun4i Codec ***/
    679static const struct snd_kcontrol_new sun4i_codec_pa_mute =
    680	SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
    681			SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
    682
    683static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
    684static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150,
    685			    0);
    686static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300,
    687			    0);
    688static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150,
    689			    0);
    690static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150,
    691			    0);
    692static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale,
    693			    0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
    694			    1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0));
    695static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale,
    696			    0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
    697			    1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0));
    698
    699static const struct snd_kcontrol_new sun4i_codec_controls[] = {
    700	SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
    701		       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
    702		       sun4i_codec_pa_volume_scale),
    703	SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
    704		       SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
    705		       sun4i_codec_linein_loopback_gain_scale),
    706	SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
    707		       SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
    708		       sun4i_codec_linein_preamp_gain_scale),
    709	SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
    710		       SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
    711		       sun4i_codec_fmin_loopback_gain_scale),
    712	SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
    713		       SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
    714		       sun4i_codec_micin_loopback_gain_scale),
    715	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL,
    716		       SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0,
    717		       sun4i_codec_micin_preamp_gain_scale),
    718	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL,
    719		       SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0,
    720		       sun4i_codec_micin_preamp_gain_scale),
    721};
    722
    723static const struct snd_kcontrol_new sun7i_codec_controls[] = {
    724	SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
    725		       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
    726		       sun4i_codec_pa_volume_scale),
    727	SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL,
    728		       SUN4I_CODEC_DAC_ACTL_LNG, 1, 0,
    729		       sun4i_codec_linein_loopback_gain_scale),
    730	SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL,
    731		       SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0,
    732		       sun4i_codec_linein_preamp_gain_scale),
    733	SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL,
    734		       SUN4I_CODEC_DAC_ACTL_FMG, 3, 0,
    735		       sun4i_codec_fmin_loopback_gain_scale),
    736	SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL,
    737		       SUN4I_CODEC_DAC_ACTL_MICG, 7, 0,
    738		       sun4i_codec_micin_loopback_gain_scale),
    739	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
    740		       SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0,
    741		       sun7i_codec_micin_preamp_gain_scale),
    742	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL,
    743		       SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0,
    744		       sun7i_codec_micin_preamp_gain_scale),
    745};
    746
    747static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = {
    748	SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch",
    749			SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS,
    750			1, 0),
    751	SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch",
    752			SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS,
    753			1, 0),
    754	SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch",
    755			SUN4I_CODEC_DAC_ACTL,
    756			SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
    757	SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL,
    758			SUN4I_CODEC_DAC_ACTL_LLNS,
    759			SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0),
    760	SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL,
    761			SUN4I_CODEC_DAC_ACTL_LFMS,
    762			SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0),
    763	SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL,
    764			SUN4I_CODEC_DAC_ACTL_MIC1LS,
    765			SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0),
    766	SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL,
    767			SUN4I_CODEC_DAC_ACTL_MIC2LS,
    768			SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0),
    769};
    770
    771static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
    772	SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
    773			SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
    774	SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
    775			SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
    776};
    777
    778static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
    779	/* Digital parts of the ADCs */
    780	SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
    781			    SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
    782			    NULL, 0),
    783
    784	/* Digital parts of the DACs */
    785	SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
    786			    SUN4I_CODEC_DAC_DPC_EN_DA, 0,
    787			    NULL, 0),
    788
    789	/* Analog parts of the ADCs */
    790	SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
    791			 SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
    792	SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
    793			 SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
    794
    795	/* Analog parts of the DACs */
    796	SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
    797			 SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
    798	SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
    799			 SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
    800
    801	/* Mixers */
    802	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
    803			   sun4i_codec_mixer_controls,
    804			   ARRAY_SIZE(sun4i_codec_mixer_controls)),
    805	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
    806			   sun4i_codec_mixer_controls,
    807			   ARRAY_SIZE(sun4i_codec_mixer_controls)),
    808
    809	/* Global Mixer Enable */
    810	SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
    811			    SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
    812
    813	/* VMIC */
    814	SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
    815			    SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
    816
    817	/* Mic Pre-Amplifiers */
    818	SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
    819			 SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
    820	SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
    821			 SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0),
    822
    823	/* Power Amplifier */
    824	SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
    825			   SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
    826			   sun4i_codec_pa_mixer_controls,
    827			   ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
    828	SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
    829			    &sun4i_codec_pa_mute),
    830
    831	SND_SOC_DAPM_INPUT("Line Right"),
    832	SND_SOC_DAPM_INPUT("Line Left"),
    833	SND_SOC_DAPM_INPUT("FM Right"),
    834	SND_SOC_DAPM_INPUT("FM Left"),
    835	SND_SOC_DAPM_INPUT("Mic1"),
    836	SND_SOC_DAPM_INPUT("Mic2"),
    837
    838	SND_SOC_DAPM_OUTPUT("HP Right"),
    839	SND_SOC_DAPM_OUTPUT("HP Left"),
    840};
    841
    842static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
    843	/* Left ADC / DAC Routes */
    844	{ "Left ADC", NULL, "ADC" },
    845	{ "Left DAC", NULL, "DAC" },
    846
    847	/* Right ADC / DAC Routes */
    848	{ "Right ADC", NULL, "ADC" },
    849	{ "Right DAC", NULL, "DAC" },
    850
    851	/* Right Mixer Routes */
    852	{ "Right Mixer", NULL, "Mixer Enable" },
    853	{ "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" },
    854	{ "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" },
    855	{ "Right Mixer", "Line Playback Switch", "Line Right" },
    856	{ "Right Mixer", "FM Playback Switch", "FM Right" },
    857	{ "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
    858	{ "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
    859
    860	/* Left Mixer Routes */
    861	{ "Left Mixer", NULL, "Mixer Enable" },
    862	{ "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" },
    863	{ "Left Mixer", "Line Playback Switch", "Line Left" },
    864	{ "Left Mixer", "FM Playback Switch", "FM Left" },
    865	{ "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" },
    866	{ "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" },
    867
    868	/* Power Amplifier Routes */
    869	{ "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
    870	{ "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
    871	{ "Power Amplifier", "DAC Playback Switch", "Left DAC" },
    872	{ "Power Amplifier", "DAC Playback Switch", "Right DAC" },
    873
    874	/* Headphone Output Routes */
    875	{ "Power Amplifier Mute", "Switch", "Power Amplifier" },
    876	{ "HP Right", NULL, "Power Amplifier Mute" },
    877	{ "HP Left", NULL, "Power Amplifier Mute" },
    878
    879	/* Mic1 Routes */
    880	{ "Left ADC", NULL, "MIC1 Pre-Amplifier" },
    881	{ "Right ADC", NULL, "MIC1 Pre-Amplifier" },
    882	{ "MIC1 Pre-Amplifier", NULL, "Mic1"},
    883	{ "Mic1", NULL, "VMIC" },
    884
    885	/* Mic2 Routes */
    886	{ "Left ADC", NULL, "MIC2 Pre-Amplifier" },
    887	{ "Right ADC", NULL, "MIC2 Pre-Amplifier" },
    888	{ "MIC2 Pre-Amplifier", NULL, "Mic2"},
    889	{ "Mic2", NULL, "VMIC" },
    890};
    891
    892static const struct snd_soc_component_driver sun4i_codec_codec = {
    893	.controls		= sun4i_codec_controls,
    894	.num_controls		= ARRAY_SIZE(sun4i_codec_controls),
    895	.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
    896	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
    897	.dapm_routes		= sun4i_codec_codec_dapm_routes,
    898	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
    899	.idle_bias_on		= 1,
    900	.use_pmdown_time	= 1,
    901	.endianness		= 1,
    902	.non_legacy_dai_naming	= 1,
    903};
    904
    905static const struct snd_soc_component_driver sun7i_codec_codec = {
    906	.controls		= sun7i_codec_controls,
    907	.num_controls		= ARRAY_SIZE(sun7i_codec_controls),
    908	.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
    909	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
    910	.dapm_routes		= sun4i_codec_codec_dapm_routes,
    911	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
    912	.idle_bias_on		= 1,
    913	.use_pmdown_time	= 1,
    914	.endianness		= 1,
    915	.non_legacy_dai_naming	= 1,
    916};
    917
    918/*** sun6i Codec ***/
    919
    920/* mixer controls */
    921static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
    922	SOC_DAPM_DOUBLE("DAC Playback Switch",
    923			SUN6I_CODEC_OM_DACA_CTRL,
    924			SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
    925			SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
    926	SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
    927			SUN6I_CODEC_OM_DACA_CTRL,
    928			SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
    929			SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
    930	SOC_DAPM_DOUBLE("Line In Playback Switch",
    931			SUN6I_CODEC_OM_DACA_CTRL,
    932			SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
    933			SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
    934	SOC_DAPM_DOUBLE("Mic1 Playback Switch",
    935			SUN6I_CODEC_OM_DACA_CTRL,
    936			SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
    937			SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
    938	SOC_DAPM_DOUBLE("Mic2 Playback Switch",
    939			SUN6I_CODEC_OM_DACA_CTRL,
    940			SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
    941			SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
    942};
    943
    944/* ADC mixer controls */
    945static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
    946	SOC_DAPM_DOUBLE("Mixer Capture Switch",
    947			SUN6I_CODEC_ADC_ACTL,
    948			SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
    949			SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
    950	SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
    951			SUN6I_CODEC_ADC_ACTL,
    952			SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
    953			SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
    954	SOC_DAPM_DOUBLE("Line In Capture Switch",
    955			SUN6I_CODEC_ADC_ACTL,
    956			SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
    957			SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
    958	SOC_DAPM_DOUBLE("Mic1 Capture Switch",
    959			SUN6I_CODEC_ADC_ACTL,
    960			SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
    961			SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
    962	SOC_DAPM_DOUBLE("Mic2 Capture Switch",
    963			SUN6I_CODEC_ADC_ACTL,
    964			SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
    965			SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
    966};
    967
    968/* headphone controls */
    969static const char * const sun6i_codec_hp_src_enum_text[] = {
    970	"DAC", "Mixer",
    971};
    972
    973static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
    974			    SUN6I_CODEC_OM_DACA_CTRL,
    975			    SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
    976			    SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
    977			    sun6i_codec_hp_src_enum_text);
    978
    979static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
    980	SOC_DAPM_ENUM("Headphone Source Playback Route",
    981		      sun6i_codec_hp_src_enum),
    982};
    983
    984/* microphone controls */
    985static const char * const sun6i_codec_mic2_src_enum_text[] = {
    986	"Mic2", "Mic3",
    987};
    988
    989static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
    990			    SUN6I_CODEC_MIC_CTRL,
    991			    SUN6I_CODEC_MIC_CTRL_MIC2SLT,
    992			    sun6i_codec_mic2_src_enum_text);
    993
    994static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
    995	SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
    996		      sun6i_codec_mic2_src_enum),
    997};
    998
    999/* line out controls */
   1000static const char * const sun6i_codec_lineout_src_enum_text[] = {
   1001	"Stereo", "Mono Differential",
   1002};
   1003
   1004static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
   1005			    SUN6I_CODEC_MIC_CTRL,
   1006			    SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
   1007			    SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
   1008			    sun6i_codec_lineout_src_enum_text);
   1009
   1010static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
   1011	SOC_DAPM_ENUM("Line Out Source Playback Route",
   1012		      sun6i_codec_lineout_src_enum),
   1013};
   1014
   1015/* volume / mute controls */
   1016static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
   1017static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
   1018static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
   1019				  -450, 150, 0);
   1020static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale,
   1021	0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
   1022	2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
   1023);
   1024static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
   1025	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
   1026	1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
   1027);
   1028
   1029static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
   1030	SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
   1031		       SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
   1032		       sun6i_codec_dvol_scale),
   1033	SOC_SINGLE_TLV("Headphone Playback Volume",
   1034		       SUN6I_CODEC_OM_DACA_CTRL,
   1035		       SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
   1036		       sun6i_codec_hp_vol_scale),
   1037	SOC_SINGLE_TLV("Line Out Playback Volume",
   1038		       SUN6I_CODEC_MIC_CTRL,
   1039		       SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
   1040		       sun6i_codec_lineout_vol_scale),
   1041	SOC_DOUBLE("Headphone Playback Switch",
   1042		   SUN6I_CODEC_OM_DACA_CTRL,
   1043		   SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
   1044		   SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
   1045	SOC_DOUBLE("Line Out Playback Switch",
   1046		   SUN6I_CODEC_MIC_CTRL,
   1047		   SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
   1048		   SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
   1049	/* Mixer pre-gains */
   1050	SOC_SINGLE_TLV("Line In Playback Volume",
   1051		       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
   1052		       0x7, 0, sun6i_codec_out_mixer_pregain_scale),
   1053	SOC_SINGLE_TLV("Mic1 Playback Volume",
   1054		       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
   1055		       0x7, 0, sun6i_codec_out_mixer_pregain_scale),
   1056	SOC_SINGLE_TLV("Mic2 Playback Volume",
   1057		       SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
   1058		       0x7, 0, sun6i_codec_out_mixer_pregain_scale),
   1059
   1060	/* Microphone Amp boost gains */
   1061	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
   1062		       SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
   1063		       sun6i_codec_mic_gain_scale),
   1064	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
   1065		       SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
   1066		       sun6i_codec_mic_gain_scale),
   1067	SOC_DOUBLE_TLV("ADC Capture Volume",
   1068		       SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
   1069		       SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
   1070		       sun6i_codec_out_mixer_pregain_scale),
   1071};
   1072
   1073static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
   1074	/* Microphone inputs */
   1075	SND_SOC_DAPM_INPUT("MIC1"),
   1076	SND_SOC_DAPM_INPUT("MIC2"),
   1077	SND_SOC_DAPM_INPUT("MIC3"),
   1078
   1079	/* Microphone Bias */
   1080	SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
   1081			    SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
   1082	SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
   1083			    SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
   1084
   1085	/* Mic input path */
   1086	SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
   1087			 SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
   1088	SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
   1089			 SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
   1090	SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
   1091			 SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
   1092
   1093	/* Line In */
   1094	SND_SOC_DAPM_INPUT("LINEIN"),
   1095
   1096	/* Digital parts of the ADCs */
   1097	SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
   1098			    SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
   1099			    NULL, 0),
   1100
   1101	/* Analog parts of the ADCs */
   1102	SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
   1103			 SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
   1104	SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
   1105			 SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
   1106
   1107	/* ADC Mixers */
   1108	SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
   1109			sun6i_codec_adc_mixer_controls),
   1110	SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
   1111			sun6i_codec_adc_mixer_controls),
   1112
   1113	/* Digital parts of the DACs */
   1114	SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
   1115			    SUN4I_CODEC_DAC_DPC_EN_DA, 0,
   1116			    NULL, 0),
   1117
   1118	/* Analog parts of the DACs */
   1119	SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
   1120			 SUN6I_CODEC_OM_DACA_CTRL,
   1121			 SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
   1122	SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
   1123			 SUN6I_CODEC_OM_DACA_CTRL,
   1124			 SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
   1125
   1126	/* Mixers */
   1127	SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
   1128			SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
   1129			sun6i_codec_mixer_controls),
   1130	SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
   1131			SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
   1132			sun6i_codec_mixer_controls),
   1133
   1134	/* Headphone output path */
   1135	SND_SOC_DAPM_MUX("Headphone Source Playback Route",
   1136			 SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
   1137	SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
   1138			     SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
   1139	SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
   1140			    SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
   1141	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
   1142			 SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
   1143	SND_SOC_DAPM_OUTPUT("HP"),
   1144
   1145	/* Line Out path */
   1146	SND_SOC_DAPM_MUX("Line Out Source Playback Route",
   1147			 SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
   1148	SND_SOC_DAPM_OUTPUT("LINEOUT"),
   1149};
   1150
   1151static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
   1152	/* DAC Routes */
   1153	{ "Left DAC", NULL, "DAC Enable" },
   1154	{ "Right DAC", NULL, "DAC Enable" },
   1155
   1156	/* Microphone Routes */
   1157	{ "Mic1 Amplifier", NULL, "MIC1"},
   1158	{ "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
   1159	{ "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
   1160	{ "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
   1161
   1162	/* Left Mixer Routes */
   1163	{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
   1164	{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
   1165	{ "Left Mixer", "Line In Playback Switch", "LINEIN" },
   1166	{ "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
   1167	{ "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
   1168
   1169	/* Right Mixer Routes */
   1170	{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
   1171	{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
   1172	{ "Right Mixer", "Line In Playback Switch", "LINEIN" },
   1173	{ "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
   1174	{ "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
   1175
   1176	/* Left ADC Mixer Routes */
   1177	{ "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
   1178	{ "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
   1179	{ "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
   1180	{ "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
   1181	{ "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
   1182
   1183	/* Right ADC Mixer Routes */
   1184	{ "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
   1185	{ "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
   1186	{ "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
   1187	{ "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
   1188	{ "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
   1189
   1190	/* Headphone Routes */
   1191	{ "Headphone Source Playback Route", "DAC", "Left DAC" },
   1192	{ "Headphone Source Playback Route", "DAC", "Right DAC" },
   1193	{ "Headphone Source Playback Route", "Mixer", "Left Mixer" },
   1194	{ "Headphone Source Playback Route", "Mixer", "Right Mixer" },
   1195	{ "Headphone Amp", NULL, "Headphone Source Playback Route" },
   1196	{ "HP", NULL, "Headphone Amp" },
   1197	{ "HPCOM", NULL, "HPCOM Protection" },
   1198
   1199	/* Line Out Routes */
   1200	{ "Line Out Source Playback Route", "Stereo", "Left Mixer" },
   1201	{ "Line Out Source Playback Route", "Stereo", "Right Mixer" },
   1202	{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
   1203	{ "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
   1204	{ "LINEOUT", NULL, "Line Out Source Playback Route" },
   1205
   1206	/* ADC Routes */
   1207	{ "Left ADC", NULL, "ADC Enable" },
   1208	{ "Right ADC", NULL, "ADC Enable" },
   1209	{ "Left ADC", NULL, "Left ADC Mixer" },
   1210	{ "Right ADC", NULL, "Right ADC Mixer" },
   1211};
   1212
   1213static const struct snd_soc_component_driver sun6i_codec_codec = {
   1214	.controls		= sun6i_codec_codec_widgets,
   1215	.num_controls		= ARRAY_SIZE(sun6i_codec_codec_widgets),
   1216	.dapm_widgets		= sun6i_codec_codec_dapm_widgets,
   1217	.num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
   1218	.dapm_routes		= sun6i_codec_codec_dapm_routes,
   1219	.num_dapm_routes	= ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
   1220	.idle_bias_on		= 1,
   1221	.use_pmdown_time	= 1,
   1222	.endianness		= 1,
   1223	.non_legacy_dai_naming	= 1,
   1224};
   1225
   1226/* sun8i A23 codec */
   1227static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
   1228	SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
   1229		       SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
   1230		       sun6i_codec_dvol_scale),
   1231};
   1232
   1233static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
   1234	/* Digital parts of the ADCs */
   1235	SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
   1236			    SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
   1237	/* Digital parts of the DACs */
   1238	SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
   1239			    SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
   1240
   1241};
   1242
   1243static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
   1244	.controls		= sun8i_a23_codec_codec_controls,
   1245	.num_controls		= ARRAY_SIZE(sun8i_a23_codec_codec_controls),
   1246	.dapm_widgets		= sun8i_a23_codec_codec_widgets,
   1247	.num_dapm_widgets	= ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
   1248	.idle_bias_on		= 1,
   1249	.use_pmdown_time	= 1,
   1250	.endianness		= 1,
   1251	.non_legacy_dai_naming	= 1,
   1252};
   1253
   1254static const struct snd_soc_component_driver sun4i_codec_component = {
   1255	.name = "sun4i-codec",
   1256};
   1257
   1258#define SUN4I_CODEC_RATES	SNDRV_PCM_RATE_CONTINUOUS
   1259#define SUN4I_CODEC_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
   1260				 SNDRV_PCM_FMTBIT_S32_LE)
   1261
   1262static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
   1263{
   1264	struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
   1265	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
   1266
   1267	snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
   1268				  &scodec->capture_dma_data);
   1269
   1270	return 0;
   1271}
   1272
   1273static struct snd_soc_dai_driver dummy_cpu_dai = {
   1274	.name	= "sun4i-codec-cpu-dai",
   1275	.probe	= sun4i_codec_dai_probe,
   1276	.playback = {
   1277		.stream_name	= "Playback",
   1278		.channels_min	= 1,
   1279		.channels_max	= 2,
   1280		.rates		= SUN4I_CODEC_RATES,
   1281		.formats	= SUN4I_CODEC_FORMATS,
   1282		.sig_bits	= 24,
   1283	},
   1284	.capture = {
   1285		.stream_name	= "Capture",
   1286		.channels_min	= 1,
   1287		.channels_max	= 2,
   1288		.rates 		= SUN4I_CODEC_RATES,
   1289		.formats 	= SUN4I_CODEC_FORMATS,
   1290		.sig_bits	= 24,
   1291	 },
   1292};
   1293
   1294static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
   1295							int *num_links)
   1296{
   1297	struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
   1298						     GFP_KERNEL);
   1299	struct snd_soc_dai_link_component *dlc = devm_kzalloc(dev,
   1300						3 * sizeof(*dlc), GFP_KERNEL);
   1301	if (!link || !dlc)
   1302		return NULL;
   1303
   1304	link->cpus	= &dlc[0];
   1305	link->codecs	= &dlc[1];
   1306	link->platforms	= &dlc[2];
   1307
   1308	link->num_cpus		= 1;
   1309	link->num_codecs	= 1;
   1310	link->num_platforms	= 1;
   1311
   1312	link->name		= "cdc";
   1313	link->stream_name	= "CDC PCM";
   1314	link->codecs->dai_name	= "Codec";
   1315	link->cpus->dai_name	= dev_name(dev);
   1316	link->codecs->name	= dev_name(dev);
   1317	link->platforms->name	= dev_name(dev);
   1318	link->dai_fmt		= SND_SOC_DAIFMT_I2S;
   1319
   1320	*num_links = 1;
   1321
   1322	return link;
   1323};
   1324
   1325static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
   1326				 struct snd_kcontrol *k, int event)
   1327{
   1328	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
   1329
   1330	gpiod_set_value_cansleep(scodec->gpio_pa,
   1331				 !!SND_SOC_DAPM_EVENT_ON(event));
   1332
   1333	if (SND_SOC_DAPM_EVENT_ON(event)) {
   1334		/*
   1335		 * Need a delay to wait for DAC to push the data. 700ms seems
   1336		 * to be the best compromise not to feel this delay while
   1337		 * playing a sound.
   1338		 */
   1339		msleep(700);
   1340	}
   1341
   1342	return 0;
   1343}
   1344
   1345static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
   1346	SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
   1347};
   1348
   1349static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
   1350	{ "Speaker", NULL, "HP Right" },
   1351	{ "Speaker", NULL, "HP Left" },
   1352};
   1353
   1354static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
   1355{
   1356	struct snd_soc_card *card;
   1357
   1358	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
   1359	if (!card)
   1360		return ERR_PTR(-ENOMEM);
   1361
   1362	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
   1363	if (!card->dai_link)
   1364		return ERR_PTR(-ENOMEM);
   1365
   1366	card->dev		= dev;
   1367	card->owner		= THIS_MODULE;
   1368	card->name		= "sun4i-codec";
   1369	card->dapm_widgets	= sun4i_codec_card_dapm_widgets;
   1370	card->num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
   1371	card->dapm_routes	= sun4i_codec_card_dapm_routes;
   1372	card->num_dapm_routes	= ARRAY_SIZE(sun4i_codec_card_dapm_routes);
   1373
   1374	return card;
   1375};
   1376
   1377static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
   1378	SND_SOC_DAPM_HP("Headphone", NULL),
   1379	SND_SOC_DAPM_LINE("Line In", NULL),
   1380	SND_SOC_DAPM_LINE("Line Out", NULL),
   1381	SND_SOC_DAPM_MIC("Headset Mic", NULL),
   1382	SND_SOC_DAPM_MIC("Mic", NULL),
   1383	SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
   1384};
   1385
   1386static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
   1387{
   1388	struct snd_soc_card *card;
   1389	int ret;
   1390
   1391	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
   1392	if (!card)
   1393		return ERR_PTR(-ENOMEM);
   1394
   1395	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
   1396	if (!card->dai_link)
   1397		return ERR_PTR(-ENOMEM);
   1398
   1399	card->dev		= dev;
   1400	card->owner		= THIS_MODULE;
   1401	card->name		= "A31 Audio Codec";
   1402	card->dapm_widgets	= sun6i_codec_card_dapm_widgets;
   1403	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
   1404	card->fully_routed	= true;
   1405
   1406	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
   1407	if (ret)
   1408		dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
   1409
   1410	return card;
   1411};
   1412
   1413/* Connect digital side enables to analog side widgets */
   1414static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
   1415	/* ADC Routes */
   1416	{ "Left ADC", NULL, "ADC Enable" },
   1417	{ "Right ADC", NULL, "ADC Enable" },
   1418	{ "Codec Capture", NULL, "Left ADC" },
   1419	{ "Codec Capture", NULL, "Right ADC" },
   1420
   1421	/* DAC Routes */
   1422	{ "Left DAC", NULL, "DAC Enable" },
   1423	{ "Right DAC", NULL, "DAC Enable" },
   1424	{ "Left DAC", NULL, "Codec Playback" },
   1425	{ "Right DAC", NULL, "Codec Playback" },
   1426};
   1427
   1428static struct snd_soc_aux_dev aux_dev = {
   1429	.dlc = COMP_EMPTY(),
   1430};
   1431
   1432static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
   1433{
   1434	struct snd_soc_card *card;
   1435	int ret;
   1436
   1437	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
   1438	if (!card)
   1439		return ERR_PTR(-ENOMEM);
   1440
   1441	aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
   1442						 "allwinner,codec-analog-controls",
   1443						 0);
   1444	if (!aux_dev.dlc.of_node) {
   1445		dev_err(dev, "Can't find analog controls for codec.\n");
   1446		return ERR_PTR(-EINVAL);
   1447	}
   1448
   1449	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
   1450	if (!card->dai_link)
   1451		return ERR_PTR(-ENOMEM);
   1452
   1453	card->dev		= dev;
   1454	card->owner		= THIS_MODULE;
   1455	card->name		= "A23 Audio Codec";
   1456	card->dapm_widgets	= sun6i_codec_card_dapm_widgets;
   1457	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
   1458	card->dapm_routes	= sun8i_codec_card_routes;
   1459	card->num_dapm_routes	= ARRAY_SIZE(sun8i_codec_card_routes);
   1460	card->aux_dev		= &aux_dev;
   1461	card->num_aux_devs	= 1;
   1462	card->fully_routed	= true;
   1463
   1464	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
   1465	if (ret)
   1466		dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
   1467
   1468	return card;
   1469};
   1470
   1471static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
   1472{
   1473	struct snd_soc_card *card;
   1474	int ret;
   1475
   1476	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
   1477	if (!card)
   1478		return ERR_PTR(-ENOMEM);
   1479
   1480	aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
   1481						 "allwinner,codec-analog-controls",
   1482						 0);
   1483	if (!aux_dev.dlc.of_node) {
   1484		dev_err(dev, "Can't find analog controls for codec.\n");
   1485		return ERR_PTR(-EINVAL);
   1486	}
   1487
   1488	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
   1489	if (!card->dai_link)
   1490		return ERR_PTR(-ENOMEM);
   1491
   1492	card->dev		= dev;
   1493	card->owner		= THIS_MODULE;
   1494	card->name		= "H3 Audio Codec";
   1495	card->dapm_widgets	= sun6i_codec_card_dapm_widgets;
   1496	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
   1497	card->dapm_routes	= sun8i_codec_card_routes;
   1498	card->num_dapm_routes	= ARRAY_SIZE(sun8i_codec_card_routes);
   1499	card->aux_dev		= &aux_dev;
   1500	card->num_aux_devs	= 1;
   1501	card->fully_routed	= true;
   1502
   1503	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
   1504	if (ret)
   1505		dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
   1506
   1507	return card;
   1508};
   1509
   1510static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
   1511{
   1512	struct snd_soc_card *card;
   1513	int ret;
   1514
   1515	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
   1516	if (!card)
   1517		return ERR_PTR(-ENOMEM);
   1518
   1519	aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
   1520						 "allwinner,codec-analog-controls",
   1521						 0);
   1522	if (!aux_dev.dlc.of_node) {
   1523		dev_err(dev, "Can't find analog controls for codec.\n");
   1524		return ERR_PTR(-EINVAL);
   1525	}
   1526
   1527	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
   1528	if (!card->dai_link)
   1529		return ERR_PTR(-ENOMEM);
   1530
   1531	card->dev		= dev;
   1532	card->owner		= THIS_MODULE;
   1533	card->name		= "V3s Audio Codec";
   1534	card->dapm_widgets	= sun6i_codec_card_dapm_widgets;
   1535	card->num_dapm_widgets	= ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
   1536	card->dapm_routes	= sun8i_codec_card_routes;
   1537	card->num_dapm_routes	= ARRAY_SIZE(sun8i_codec_card_routes);
   1538	card->aux_dev		= &aux_dev;
   1539	card->num_aux_devs	= 1;
   1540	card->fully_routed	= true;
   1541
   1542	ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
   1543	if (ret)
   1544		dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
   1545
   1546	return card;
   1547};
   1548
   1549static const struct regmap_config sun4i_codec_regmap_config = {
   1550	.reg_bits	= 32,
   1551	.reg_stride	= 4,
   1552	.val_bits	= 32,
   1553	.max_register	= SUN4I_CODEC_ADC_RXCNT,
   1554};
   1555
   1556static const struct regmap_config sun6i_codec_regmap_config = {
   1557	.reg_bits	= 32,
   1558	.reg_stride	= 4,
   1559	.val_bits	= 32,
   1560	.max_register	= SUN6I_CODEC_HMIC_DATA,
   1561};
   1562
   1563static const struct regmap_config sun7i_codec_regmap_config = {
   1564	.reg_bits	= 32,
   1565	.reg_stride	= 4,
   1566	.val_bits	= 32,
   1567	.max_register	= SUN7I_CODEC_AC_MIC_PHONE_CAL,
   1568};
   1569
   1570static const struct regmap_config sun8i_a23_codec_regmap_config = {
   1571	.reg_bits	= 32,
   1572	.reg_stride	= 4,
   1573	.val_bits	= 32,
   1574	.max_register	= SUN8I_A23_CODEC_ADC_RXCNT,
   1575};
   1576
   1577static const struct regmap_config sun8i_h3_codec_regmap_config = {
   1578	.reg_bits	= 32,
   1579	.reg_stride	= 4,
   1580	.val_bits	= 32,
   1581	.max_register	= SUN8I_H3_CODEC_ADC_DBG,
   1582};
   1583
   1584static const struct regmap_config sun8i_v3s_codec_regmap_config = {
   1585	.reg_bits	= 32,
   1586	.reg_stride	= 4,
   1587	.val_bits	= 32,
   1588	.max_register	= SUN8I_H3_CODEC_ADC_DBG,
   1589};
   1590
   1591struct sun4i_codec_quirks {
   1592	const struct regmap_config *regmap_config;
   1593	const struct snd_soc_component_driver *codec;
   1594	struct snd_soc_card * (*create_card)(struct device *dev);
   1595	struct reg_field reg_adc_fifoc;	/* used for regmap_field */
   1596	unsigned int reg_dac_txdata;	/* TX FIFO offset for DMA config */
   1597	unsigned int reg_adc_rxdata;	/* RX FIFO offset for DMA config */
   1598	bool has_reset;
   1599};
   1600
   1601static const struct sun4i_codec_quirks sun4i_codec_quirks = {
   1602	.regmap_config	= &sun4i_codec_regmap_config,
   1603	.codec		= &sun4i_codec_codec,
   1604	.create_card	= sun4i_codec_create_card,
   1605	.reg_adc_fifoc	= REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
   1606	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
   1607	.reg_adc_rxdata	= SUN4I_CODEC_ADC_RXDATA,
   1608};
   1609
   1610static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
   1611	.regmap_config	= &sun6i_codec_regmap_config,
   1612	.codec		= &sun6i_codec_codec,
   1613	.create_card	= sun6i_codec_create_card,
   1614	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
   1615	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
   1616	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
   1617	.has_reset	= true,
   1618};
   1619
   1620static const struct sun4i_codec_quirks sun7i_codec_quirks = {
   1621	.regmap_config	= &sun7i_codec_regmap_config,
   1622	.codec		= &sun7i_codec_codec,
   1623	.create_card	= sun4i_codec_create_card,
   1624	.reg_adc_fifoc	= REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
   1625	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
   1626	.reg_adc_rxdata	= SUN4I_CODEC_ADC_RXDATA,
   1627};
   1628
   1629static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
   1630	.regmap_config	= &sun8i_a23_codec_regmap_config,
   1631	.codec		= &sun8i_a23_codec_codec,
   1632	.create_card	= sun8i_a23_codec_create_card,
   1633	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
   1634	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
   1635	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
   1636	.has_reset	= true,
   1637};
   1638
   1639static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
   1640	.regmap_config	= &sun8i_h3_codec_regmap_config,
   1641	/*
   1642	 * TODO Share the codec structure with A23 for now.
   1643	 * This should be split out when adding digital audio
   1644	 * processing support for the H3.
   1645	 */
   1646	.codec		= &sun8i_a23_codec_codec,
   1647	.create_card	= sun8i_h3_codec_create_card,
   1648	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
   1649	.reg_dac_txdata	= SUN8I_H3_CODEC_DAC_TXDATA,
   1650	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
   1651	.has_reset	= true,
   1652};
   1653
   1654static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
   1655	.regmap_config	= &sun8i_v3s_codec_regmap_config,
   1656	/*
   1657	 * TODO The codec structure should be split out, like
   1658	 * H3, when adding digital audio processing support.
   1659	 */
   1660	.codec		= &sun8i_a23_codec_codec,
   1661	.create_card	= sun8i_v3s_codec_create_card,
   1662	.reg_adc_fifoc	= REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
   1663	.reg_dac_txdata	= SUN8I_H3_CODEC_DAC_TXDATA,
   1664	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
   1665	.has_reset	= true,
   1666};
   1667
   1668static const struct of_device_id sun4i_codec_of_match[] = {
   1669	{
   1670		.compatible = "allwinner,sun4i-a10-codec",
   1671		.data = &sun4i_codec_quirks,
   1672	},
   1673	{
   1674		.compatible = "allwinner,sun6i-a31-codec",
   1675		.data = &sun6i_a31_codec_quirks,
   1676	},
   1677	{
   1678		.compatible = "allwinner,sun7i-a20-codec",
   1679		.data = &sun7i_codec_quirks,
   1680	},
   1681	{
   1682		.compatible = "allwinner,sun8i-a23-codec",
   1683		.data = &sun8i_a23_codec_quirks,
   1684	},
   1685	{
   1686		.compatible = "allwinner,sun8i-h3-codec",
   1687		.data = &sun8i_h3_codec_quirks,
   1688	},
   1689	{
   1690		.compatible = "allwinner,sun8i-v3s-codec",
   1691		.data = &sun8i_v3s_codec_quirks,
   1692	},
   1693	{}
   1694};
   1695MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
   1696
   1697static int sun4i_codec_probe(struct platform_device *pdev)
   1698{
   1699	struct snd_soc_card *card;
   1700	struct sun4i_codec *scodec;
   1701	const struct sun4i_codec_quirks *quirks;
   1702	struct resource *res;
   1703	void __iomem *base;
   1704	int ret;
   1705
   1706	scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
   1707	if (!scodec)
   1708		return -ENOMEM;
   1709
   1710	scodec->dev = &pdev->dev;
   1711
   1712	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
   1713	if (IS_ERR(base))
   1714		return PTR_ERR(base);
   1715
   1716	quirks = of_device_get_match_data(&pdev->dev);
   1717	if (quirks == NULL) {
   1718		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
   1719		return -ENODEV;
   1720	}
   1721
   1722	scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
   1723					       quirks->regmap_config);
   1724	if (IS_ERR(scodec->regmap)) {
   1725		dev_err(&pdev->dev, "Failed to create our regmap\n");
   1726		return PTR_ERR(scodec->regmap);
   1727	}
   1728
   1729	/* Get the clocks from the DT */
   1730	scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
   1731	if (IS_ERR(scodec->clk_apb)) {
   1732		dev_err(&pdev->dev, "Failed to get the APB clock\n");
   1733		return PTR_ERR(scodec->clk_apb);
   1734	}
   1735
   1736	scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
   1737	if (IS_ERR(scodec->clk_module)) {
   1738		dev_err(&pdev->dev, "Failed to get the module clock\n");
   1739		return PTR_ERR(scodec->clk_module);
   1740	}
   1741
   1742	if (quirks->has_reset) {
   1743		scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
   1744							       NULL);
   1745		if (IS_ERR(scodec->rst)) {
   1746			dev_err(&pdev->dev, "Failed to get reset control\n");
   1747			return PTR_ERR(scodec->rst);
   1748		}
   1749	}
   1750
   1751	scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
   1752						  GPIOD_OUT_LOW);
   1753	if (IS_ERR(scodec->gpio_pa)) {
   1754		ret = PTR_ERR(scodec->gpio_pa);
   1755		dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n");
   1756		return ret;
   1757	}
   1758
   1759	/* reg_field setup */
   1760	scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
   1761							scodec->regmap,
   1762							quirks->reg_adc_fifoc);
   1763	if (IS_ERR(scodec->reg_adc_fifoc)) {
   1764		ret = PTR_ERR(scodec->reg_adc_fifoc);
   1765		dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
   1766			ret);
   1767		return ret;
   1768	}
   1769
   1770	/* Enable the bus clock */
   1771	if (clk_prepare_enable(scodec->clk_apb)) {
   1772		dev_err(&pdev->dev, "Failed to enable the APB clock\n");
   1773		return -EINVAL;
   1774	}
   1775
   1776	/* Deassert the reset control */
   1777	if (scodec->rst) {
   1778		ret = reset_control_deassert(scodec->rst);
   1779		if (ret) {
   1780			dev_err(&pdev->dev,
   1781				"Failed to deassert the reset control\n");
   1782			goto err_clk_disable;
   1783		}
   1784	}
   1785
   1786	/* DMA configuration for TX FIFO */
   1787	scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
   1788	scodec->playback_dma_data.maxburst = 8;
   1789	scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
   1790
   1791	/* DMA configuration for RX FIFO */
   1792	scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
   1793	scodec->capture_dma_data.maxburst = 8;
   1794	scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
   1795
   1796	ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
   1797				     &sun4i_codec_dai, 1);
   1798	if (ret) {
   1799		dev_err(&pdev->dev, "Failed to register our codec\n");
   1800		goto err_assert_reset;
   1801	}
   1802
   1803	ret = devm_snd_soc_register_component(&pdev->dev,
   1804					      &sun4i_codec_component,
   1805					      &dummy_cpu_dai, 1);
   1806	if (ret) {
   1807		dev_err(&pdev->dev, "Failed to register our DAI\n");
   1808		goto err_assert_reset;
   1809	}
   1810
   1811	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
   1812	if (ret) {
   1813		dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
   1814		goto err_assert_reset;
   1815	}
   1816
   1817	card = quirks->create_card(&pdev->dev);
   1818	if (IS_ERR(card)) {
   1819		ret = PTR_ERR(card);
   1820		dev_err(&pdev->dev, "Failed to create our card\n");
   1821		goto err_assert_reset;
   1822	}
   1823
   1824	snd_soc_card_set_drvdata(card, scodec);
   1825
   1826	ret = snd_soc_register_card(card);
   1827	if (ret) {
   1828		dev_err(&pdev->dev, "Failed to register our card\n");
   1829		goto err_assert_reset;
   1830	}
   1831
   1832	return 0;
   1833
   1834err_assert_reset:
   1835	if (scodec->rst)
   1836		reset_control_assert(scodec->rst);
   1837err_clk_disable:
   1838	clk_disable_unprepare(scodec->clk_apb);
   1839	return ret;
   1840}
   1841
   1842static int sun4i_codec_remove(struct platform_device *pdev)
   1843{
   1844	struct snd_soc_card *card = platform_get_drvdata(pdev);
   1845	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
   1846
   1847	snd_soc_unregister_card(card);
   1848	if (scodec->rst)
   1849		reset_control_assert(scodec->rst);
   1850	clk_disable_unprepare(scodec->clk_apb);
   1851
   1852	return 0;
   1853}
   1854
   1855static struct platform_driver sun4i_codec_driver = {
   1856	.driver = {
   1857		.name = "sun4i-codec",
   1858		.of_match_table = sun4i_codec_of_match,
   1859	},
   1860	.probe = sun4i_codec_probe,
   1861	.remove = sun4i_codec_remove,
   1862};
   1863module_platform_driver(sun4i_codec_driver);
   1864
   1865MODULE_DESCRIPTION("Allwinner A10 codec driver");
   1866MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
   1867MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
   1868MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
   1869MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
   1870MODULE_LICENSE("GPL");