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-spdif.c (20062B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * ALSA SoC SPDIF Audio Layer
      4 *
      5 * Copyright 2015 Andrea Venturi <be17068@iperbole.bo.it>
      6 * Copyright 2015 Marcus Cooper <codekipper@gmail.com>
      7 *
      8 * Based on the Allwinner SDK driver, released under the GPL.
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/delay.h>
     13#include <linux/device.h>
     14#include <linux/kernel.h>
     15#include <linux/init.h>
     16#include <linux/regmap.h>
     17#include <linux/of_address.h>
     18#include <linux/of_device.h>
     19#include <linux/ioport.h>
     20#include <linux/module.h>
     21#include <linux/platform_device.h>
     22#include <linux/pm_runtime.h>
     23#include <linux/reset.h>
     24#include <linux/spinlock.h>
     25#include <sound/asoundef.h>
     26#include <sound/dmaengine_pcm.h>
     27#include <sound/pcm_params.h>
     28#include <sound/soc.h>
     29
     30#define	SUN4I_SPDIF_CTL		(0x00)
     31	#define SUN4I_SPDIF_CTL_MCLKDIV(v)		((v) << 4) /* v even */
     32	#define SUN4I_SPDIF_CTL_MCLKOUTEN		BIT(2)
     33	#define SUN4I_SPDIF_CTL_GEN			BIT(1)
     34	#define SUN4I_SPDIF_CTL_RESET			BIT(0)
     35
     36#define SUN4I_SPDIF_TXCFG	(0x04)
     37	#define SUN4I_SPDIF_TXCFG_SINGLEMOD		BIT(31)
     38	#define SUN4I_SPDIF_TXCFG_ASS			BIT(17)
     39	#define SUN4I_SPDIF_TXCFG_NONAUDIO		BIT(16)
     40	#define SUN4I_SPDIF_TXCFG_TXRATIO(v)		((v) << 4)
     41	#define SUN4I_SPDIF_TXCFG_TXRATIO_MASK		GENMASK(8, 4)
     42	#define SUN4I_SPDIF_TXCFG_FMTRVD		GENMASK(3, 2)
     43	#define SUN4I_SPDIF_TXCFG_FMT16BIT		(0 << 2)
     44	#define SUN4I_SPDIF_TXCFG_FMT20BIT		(1 << 2)
     45	#define SUN4I_SPDIF_TXCFG_FMT24BIT		(2 << 2)
     46	#define SUN4I_SPDIF_TXCFG_CHSTMODE		BIT(1)
     47	#define SUN4I_SPDIF_TXCFG_TXEN			BIT(0)
     48
     49#define SUN4I_SPDIF_RXCFG	(0x08)
     50	#define SUN4I_SPDIF_RXCFG_LOCKFLAG		BIT(4)
     51	#define SUN4I_SPDIF_RXCFG_CHSTSRC		BIT(3)
     52	#define SUN4I_SPDIF_RXCFG_CHSTCP		BIT(1)
     53	#define SUN4I_SPDIF_RXCFG_RXEN			BIT(0)
     54
     55#define SUN4I_SPDIF_TXFIFO	(0x0C)
     56
     57#define SUN4I_SPDIF_RXFIFO	(0x10)
     58
     59#define SUN4I_SPDIF_FCTL	(0x14)
     60	#define SUN4I_SPDIF_FCTL_FIFOSRC		BIT(31)
     61	#define SUN4I_SPDIF_FCTL_FTX			BIT(17)
     62	#define SUN4I_SPDIF_FCTL_FRX			BIT(16)
     63	#define SUN4I_SPDIF_FCTL_TXTL(v)		((v) << 8)
     64	#define SUN4I_SPDIF_FCTL_TXTL_MASK		GENMASK(12, 8)
     65	#define SUN4I_SPDIF_FCTL_RXTL(v)		((v) << 3)
     66	#define SUN4I_SPDIF_FCTL_RXTL_MASK		GENMASK(7, 3)
     67	#define SUN4I_SPDIF_FCTL_TXIM			BIT(2)
     68	#define SUN4I_SPDIF_FCTL_RXOM(v)		((v) << 0)
     69	#define SUN4I_SPDIF_FCTL_RXOM_MASK		GENMASK(1, 0)
     70
     71#define SUN50I_H6_SPDIF_FCTL (0x14)
     72	#define SUN50I_H6_SPDIF_FCTL_HUB_EN		BIT(31)
     73	#define SUN50I_H6_SPDIF_FCTL_FTX		BIT(30)
     74	#define SUN50I_H6_SPDIF_FCTL_FRX		BIT(29)
     75	#define SUN50I_H6_SPDIF_FCTL_TXTL(v)		((v) << 12)
     76	#define SUN50I_H6_SPDIF_FCTL_TXTL_MASK		GENMASK(19, 12)
     77	#define SUN50I_H6_SPDIF_FCTL_RXTL(v)		((v) << 4)
     78	#define SUN50I_H6_SPDIF_FCTL_RXTL_MASK		GENMASK(10, 4)
     79	#define SUN50I_H6_SPDIF_FCTL_TXIM		BIT(2)
     80	#define SUN50I_H6_SPDIF_FCTL_RXOM(v)		((v) << 0)
     81	#define SUN50I_H6_SPDIF_FCTL_RXOM_MASK		GENMASK(1, 0)
     82
     83#define SUN4I_SPDIF_FSTA	(0x18)
     84	#define SUN4I_SPDIF_FSTA_TXE			BIT(14)
     85	#define SUN4I_SPDIF_FSTA_TXECNTSHT		(8)
     86	#define SUN4I_SPDIF_FSTA_RXA			BIT(6)
     87	#define SUN4I_SPDIF_FSTA_RXACNTSHT		(0)
     88
     89#define SUN4I_SPDIF_INT		(0x1C)
     90	#define SUN4I_SPDIF_INT_RXLOCKEN		BIT(18)
     91	#define SUN4I_SPDIF_INT_RXUNLOCKEN		BIT(17)
     92	#define SUN4I_SPDIF_INT_RXPARERREN		BIT(16)
     93	#define SUN4I_SPDIF_INT_TXDRQEN			BIT(7)
     94	#define SUN4I_SPDIF_INT_TXUIEN			BIT(6)
     95	#define SUN4I_SPDIF_INT_TXOIEN			BIT(5)
     96	#define SUN4I_SPDIF_INT_TXEIEN			BIT(4)
     97	#define SUN4I_SPDIF_INT_RXDRQEN			BIT(2)
     98	#define SUN4I_SPDIF_INT_RXOIEN			BIT(1)
     99	#define SUN4I_SPDIF_INT_RXAIEN			BIT(0)
    100
    101#define SUN4I_SPDIF_ISTA	(0x20)
    102	#define SUN4I_SPDIF_ISTA_RXLOCKSTA		BIT(18)
    103	#define SUN4I_SPDIF_ISTA_RXUNLOCKSTA		BIT(17)
    104	#define SUN4I_SPDIF_ISTA_RXPARERRSTA		BIT(16)
    105	#define SUN4I_SPDIF_ISTA_TXUSTA			BIT(6)
    106	#define SUN4I_SPDIF_ISTA_TXOSTA			BIT(5)
    107	#define SUN4I_SPDIF_ISTA_TXESTA			BIT(4)
    108	#define SUN4I_SPDIF_ISTA_RXOSTA			BIT(1)
    109	#define SUN4I_SPDIF_ISTA_RXASTA			BIT(0)
    110
    111#define SUN8I_SPDIF_TXFIFO	(0x20)
    112
    113#define SUN4I_SPDIF_TXCNT	(0x24)
    114
    115#define SUN4I_SPDIF_RXCNT	(0x28)
    116
    117#define SUN4I_SPDIF_TXCHSTA0	(0x2C)
    118	#define SUN4I_SPDIF_TXCHSTA0_CLK(v)		((v) << 28)
    119	#define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v)		((v) << 24)
    120	#define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK	GENMASK(27, 24)
    121	#define SUN4I_SPDIF_TXCHSTA0_CHNUM(v)		((v) << 20)
    122	#define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK		GENMASK(23, 20)
    123	#define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v)		((v) << 16)
    124	#define SUN4I_SPDIF_TXCHSTA0_CATACOD(v)		((v) << 8)
    125	#define SUN4I_SPDIF_TXCHSTA0_MODE(v)		((v) << 6)
    126	#define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v)	((v) << 3)
    127	#define SUN4I_SPDIF_TXCHSTA0_CP			BIT(2)
    128	#define SUN4I_SPDIF_TXCHSTA0_AUDIO		BIT(1)
    129	#define SUN4I_SPDIF_TXCHSTA0_PRO		BIT(0)
    130
    131#define SUN4I_SPDIF_TXCHSTA1	(0x30)
    132	#define SUN4I_SPDIF_TXCHSTA1_CGMSA(v)		((v) << 8)
    133	#define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v)	((v) << 4)
    134	#define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK	GENMASK(7, 4)
    135	#define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v)	((v) << 1)
    136	#define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN		BIT(0)
    137
    138#define SUN4I_SPDIF_RXCHSTA0	(0x34)
    139	#define SUN4I_SPDIF_RXCHSTA0_CLK(v)		((v) << 28)
    140	#define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v)		((v) << 24)
    141	#define SUN4I_SPDIF_RXCHSTA0_CHNUM(v)		((v) << 20)
    142	#define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v)		((v) << 16)
    143	#define SUN4I_SPDIF_RXCHSTA0_CATACOD(v)		((v) << 8)
    144	#define SUN4I_SPDIF_RXCHSTA0_MODE(v)		((v) << 6)
    145	#define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v)	((v) << 3)
    146	#define SUN4I_SPDIF_RXCHSTA0_CP			BIT(2)
    147	#define SUN4I_SPDIF_RXCHSTA0_AUDIO		BIT(1)
    148	#define SUN4I_SPDIF_RXCHSTA0_PRO		BIT(0)
    149
    150#define SUN4I_SPDIF_RXCHSTA1	(0x38)
    151	#define SUN4I_SPDIF_RXCHSTA1_CGMSA(v)		((v) << 8)
    152	#define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v)	((v) << 4)
    153	#define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v)	((v) << 1)
    154	#define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN		BIT(0)
    155
    156/* Defines for Sampling Frequency */
    157#define SUN4I_SPDIF_SAMFREQ_44_1KHZ		0x0
    158#define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED	0x1
    159#define SUN4I_SPDIF_SAMFREQ_48KHZ		0x2
    160#define SUN4I_SPDIF_SAMFREQ_32KHZ		0x3
    161#define SUN4I_SPDIF_SAMFREQ_22_05KHZ		0x4
    162#define SUN4I_SPDIF_SAMFREQ_24KHZ		0x6
    163#define SUN4I_SPDIF_SAMFREQ_88_2KHZ		0x8
    164#define SUN4I_SPDIF_SAMFREQ_76_8KHZ		0x9
    165#define SUN4I_SPDIF_SAMFREQ_96KHZ		0xa
    166#define SUN4I_SPDIF_SAMFREQ_176_4KHZ		0xc
    167#define SUN4I_SPDIF_SAMFREQ_192KHZ		0xe
    168
    169/**
    170 * struct sun4i_spdif_quirks - Differences between SoC variants.
    171 *
    172 * @reg_dac_txdata: TX FIFO offset for DMA config.
    173 * @has_reset: SoC needs reset deasserted.
    174 * @val_fctl_ftx: TX FIFO flush bitmask.
    175 */
    176struct sun4i_spdif_quirks {
    177	unsigned int reg_dac_txdata;
    178	bool has_reset;
    179	unsigned int val_fctl_ftx;
    180};
    181
    182struct sun4i_spdif_dev {
    183	struct platform_device *pdev;
    184	struct clk *spdif_clk;
    185	struct clk *apb_clk;
    186	struct reset_control *rst;
    187	struct snd_soc_dai_driver cpu_dai_drv;
    188	struct regmap *regmap;
    189	struct snd_dmaengine_dai_dma_data dma_params_tx;
    190	const struct sun4i_spdif_quirks *quirks;
    191	spinlock_t lock;
    192};
    193
    194static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
    195{
    196	const struct sun4i_spdif_quirks *quirks = host->quirks;
    197
    198	/* soft reset SPDIF */
    199	regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
    200
    201	/* flush TX FIFO */
    202	regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
    203			   quirks->val_fctl_ftx, quirks->val_fctl_ftx);
    204
    205	/* clear TX counter */
    206	regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
    207}
    208
    209static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
    210				struct sun4i_spdif_dev *host)
    211{
    212	if (substream->runtime->channels == 1)
    213		regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
    214				   SUN4I_SPDIF_TXCFG_SINGLEMOD,
    215				   SUN4I_SPDIF_TXCFG_SINGLEMOD);
    216
    217	/* SPDIF TX ENABLE */
    218	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
    219			   SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);
    220
    221	/* DRQ ENABLE */
    222	regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
    223			   SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);
    224
    225	/* Global enable */
    226	regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
    227			   SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
    228}
    229
    230static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
    231				 struct sun4i_spdif_dev *host)
    232{
    233	/* SPDIF TX DISABLE */
    234	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
    235			   SUN4I_SPDIF_TXCFG_TXEN, 0);
    236
    237	/* DRQ DISABLE */
    238	regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
    239			   SUN4I_SPDIF_INT_TXDRQEN, 0);
    240
    241	/* Global disable */
    242	regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
    243			   SUN4I_SPDIF_CTL_GEN, 0);
    244}
    245
    246static int sun4i_spdif_startup(struct snd_pcm_substream *substream,
    247			       struct snd_soc_dai *cpu_dai)
    248{
    249	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    250	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    251
    252	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
    253		return -EINVAL;
    254
    255	sun4i_spdif_configure(host);
    256
    257	return 0;
    258}
    259
    260static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
    261				 struct snd_pcm_hw_params *params,
    262				 struct snd_soc_dai *cpu_dai)
    263{
    264	int ret = 0;
    265	int fmt;
    266	unsigned long rate = params_rate(params);
    267	u32 mclk_div = 0;
    268	unsigned int mclk = 0;
    269	u32 reg_val;
    270	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
    271	struct platform_device *pdev = host->pdev;
    272
    273	/* Add the PCM and raw data select interface */
    274	switch (params_channels(params)) {
    275	case 1: /* PCM mode */
    276	case 2:
    277		fmt = 0;
    278		break;
    279	case 4: /* raw data mode */
    280		fmt = SUN4I_SPDIF_TXCFG_NONAUDIO;
    281		break;
    282	default:
    283		return -EINVAL;
    284	}
    285
    286	switch (params_format(params)) {
    287	case SNDRV_PCM_FORMAT_S16_LE:
    288		fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
    289		break;
    290	case SNDRV_PCM_FORMAT_S20_3LE:
    291		fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
    292		break;
    293	case SNDRV_PCM_FORMAT_S24_LE:
    294		fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
    295		break;
    296	default:
    297		return -EINVAL;
    298	}
    299
    300	switch (rate) {
    301	case 22050:
    302	case 44100:
    303	case 88200:
    304	case 176400:
    305		mclk = 22579200;
    306		break;
    307	case 24000:
    308	case 32000:
    309	case 48000:
    310	case 96000:
    311	case 192000:
    312		mclk = 24576000;
    313		break;
    314	default:
    315		return -EINVAL;
    316	}
    317
    318	ret = clk_set_rate(host->spdif_clk, mclk);
    319	if (ret < 0) {
    320		dev_err(&pdev->dev,
    321			"Setting SPDIF clock rate for %d Hz failed!\n", mclk);
    322		return ret;
    323	}
    324
    325	regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
    326			   SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
    327
    328	switch (rate) {
    329	case 22050:
    330	case 24000:
    331		mclk_div = 8;
    332		break;
    333	case 32000:
    334		mclk_div = 6;
    335		break;
    336	case 44100:
    337	case 48000:
    338		mclk_div = 4;
    339		break;
    340	case 88200:
    341	case 96000:
    342		mclk_div = 2;
    343		break;
    344	case 176400:
    345	case 192000:
    346		mclk_div = 1;
    347		break;
    348	default:
    349		return -EINVAL;
    350	}
    351
    352	reg_val = 0;
    353	reg_val |= SUN4I_SPDIF_TXCFG_ASS;
    354	reg_val |= fmt; /* set non audio and bit depth */
    355	reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE;
    356	reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1);
    357	regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val);
    358
    359	return 0;
    360}
    361
    362static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
    363			       struct snd_soc_dai *dai)
    364{
    365	int ret = 0;
    366	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
    367
    368	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
    369		return -EINVAL;
    370
    371	switch (cmd) {
    372	case SNDRV_PCM_TRIGGER_START:
    373	case SNDRV_PCM_TRIGGER_RESUME:
    374	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    375		sun4i_snd_txctrl_on(substream, host);
    376		break;
    377
    378	case SNDRV_PCM_TRIGGER_STOP:
    379	case SNDRV_PCM_TRIGGER_SUSPEND:
    380	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    381		sun4i_snd_txctrl_off(substream, host);
    382		break;
    383
    384	default:
    385		ret = -EINVAL;
    386		break;
    387	}
    388	return ret;
    389}
    390
    391static int sun4i_spdif_info(struct snd_kcontrol *kcontrol,
    392			    struct snd_ctl_elem_info *uinfo)
    393{
    394	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
    395	uinfo->count = 1;
    396
    397	return 0;
    398}
    399
    400static int sun4i_spdif_get_status_mask(struct snd_kcontrol *kcontrol,
    401				       struct snd_ctl_elem_value *ucontrol)
    402{
    403	u8 *status = ucontrol->value.iec958.status;
    404
    405	status[0] = 0xff;
    406	status[1] = 0xff;
    407	status[2] = 0xff;
    408	status[3] = 0xff;
    409	status[4] = 0xff;
    410	status[5] = 0x03;
    411
    412	return 0;
    413}
    414
    415static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
    416				  struct snd_ctl_elem_value *ucontrol)
    417{
    418	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    419	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
    420	u8 *status = ucontrol->value.iec958.status;
    421	unsigned long flags;
    422	unsigned int reg;
    423
    424	spin_lock_irqsave(&host->lock, flags);
    425
    426	regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, &reg);
    427
    428	status[0] = reg & 0xff;
    429	status[1] = (reg >> 8) & 0xff;
    430	status[2] = (reg >> 16) & 0xff;
    431	status[3] = (reg >> 24) & 0xff;
    432
    433	regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, &reg);
    434
    435	status[4] = reg & 0xff;
    436	status[5] = (reg >> 8) & 0x3;
    437
    438	spin_unlock_irqrestore(&host->lock, flags);
    439
    440	return 0;
    441}
    442
    443static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol,
    444				  struct snd_ctl_elem_value *ucontrol)
    445{
    446	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    447	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
    448	u8 *status = ucontrol->value.iec958.status;
    449	unsigned long flags;
    450	unsigned int reg;
    451	bool chg0, chg1;
    452
    453	spin_lock_irqsave(&host->lock, flags);
    454
    455	reg = (u32)status[3] << 24;
    456	reg |= (u32)status[2] << 16;
    457	reg |= (u32)status[1] << 8;
    458	reg |= (u32)status[0];
    459
    460	regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
    461				 GENMASK(31,0), reg, &chg0);
    462
    463	reg = (u32)status[5] << 8;
    464	reg |= (u32)status[4];
    465
    466	regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
    467				 GENMASK(9,0), reg, &chg1);
    468
    469	reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
    470	if (status[0] & IEC958_AES0_NONAUDIO)
    471		reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
    472
    473	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
    474			   SUN4I_SPDIF_TXCFG_CHSTMODE |
    475			   SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
    476
    477	spin_unlock_irqrestore(&host->lock, flags);
    478
    479	return chg0 || chg1;
    480}
    481
    482static struct snd_kcontrol_new sun4i_spdif_controls[] = {
    483	{
    484		.access = SNDRV_CTL_ELEM_ACCESS_READ,
    485		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    486		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
    487		.info = sun4i_spdif_info,
    488		.get = sun4i_spdif_get_status_mask
    489	},
    490	{
    491		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    492		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
    493		.info = sun4i_spdif_info,
    494		.get = sun4i_spdif_get_status,
    495		.put = sun4i_spdif_set_status
    496	}
    497};
    498
    499static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
    500{
    501	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
    502
    503	snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
    504	snd_soc_add_dai_controls(dai, sun4i_spdif_controls,
    505				 ARRAY_SIZE(sun4i_spdif_controls));
    506
    507	return 0;
    508}
    509
    510static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
    511	.startup	= sun4i_spdif_startup,
    512	.trigger	= sun4i_spdif_trigger,
    513	.hw_params	= sun4i_spdif_hw_params,
    514};
    515
    516static const struct regmap_config sun4i_spdif_regmap_config = {
    517	.reg_bits = 32,
    518	.reg_stride = 4,
    519	.val_bits = 32,
    520	.max_register = SUN4I_SPDIF_RXCHSTA1,
    521};
    522
    523#define SUN4I_RATES	SNDRV_PCM_RATE_8000_192000
    524
    525#define SUN4I_FORMATS	(SNDRV_PCM_FORMAT_S16_LE | \
    526				SNDRV_PCM_FORMAT_S20_3LE | \
    527				SNDRV_PCM_FORMAT_S24_LE)
    528
    529static struct snd_soc_dai_driver sun4i_spdif_dai = {
    530	.playback = {
    531		.channels_min = 1,
    532		.channels_max = 2,
    533		.rates = SUN4I_RATES,
    534		.formats = SUN4I_FORMATS,
    535	},
    536	.probe = sun4i_spdif_soc_dai_probe,
    537	.ops = &sun4i_spdif_dai_ops,
    538	.name = "spdif",
    539};
    540
    541static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
    542	.reg_dac_txdata	= SUN4I_SPDIF_TXFIFO,
    543	.val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
    544};
    545
    546static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
    547	.reg_dac_txdata	= SUN4I_SPDIF_TXFIFO,
    548	.val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
    549	.has_reset	= true,
    550};
    551
    552static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
    553	.reg_dac_txdata	= SUN8I_SPDIF_TXFIFO,
    554	.val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
    555	.has_reset	= true,
    556};
    557
    558static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
    559	.reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
    560	.val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
    561	.has_reset      = true,
    562};
    563
    564static const struct of_device_id sun4i_spdif_of_match[] = {
    565	{
    566		.compatible = "allwinner,sun4i-a10-spdif",
    567		.data = &sun4i_a10_spdif_quirks,
    568	},
    569	{
    570		.compatible = "allwinner,sun6i-a31-spdif",
    571		.data = &sun6i_a31_spdif_quirks,
    572	},
    573	{
    574		.compatible = "allwinner,sun8i-h3-spdif",
    575		.data = &sun8i_h3_spdif_quirks,
    576	},
    577	{
    578		.compatible = "allwinner,sun50i-h6-spdif",
    579		.data = &sun50i_h6_spdif_quirks,
    580	},
    581	{ /* sentinel */ }
    582};
    583MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
    584
    585static const struct snd_soc_component_driver sun4i_spdif_component = {
    586	.name		= "sun4i-spdif",
    587};
    588
    589static int sun4i_spdif_runtime_suspend(struct device *dev)
    590{
    591	struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
    592
    593	clk_disable_unprepare(host->spdif_clk);
    594	clk_disable_unprepare(host->apb_clk);
    595
    596	return 0;
    597}
    598
    599static int sun4i_spdif_runtime_resume(struct device *dev)
    600{
    601	struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
    602	int ret;
    603
    604	ret = clk_prepare_enable(host->spdif_clk);
    605	if (ret)
    606		return ret;
    607	ret = clk_prepare_enable(host->apb_clk);
    608	if (ret)
    609		clk_disable_unprepare(host->spdif_clk);
    610
    611	return ret;
    612}
    613
    614static int sun4i_spdif_probe(struct platform_device *pdev)
    615{
    616	struct sun4i_spdif_dev *host;
    617	struct resource *res;
    618	const struct sun4i_spdif_quirks *quirks;
    619	int ret;
    620	void __iomem *base;
    621
    622	dev_dbg(&pdev->dev, "Entered %s\n", __func__);
    623
    624	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
    625	if (!host)
    626		return -ENOMEM;
    627
    628	host->pdev = pdev;
    629	spin_lock_init(&host->lock);
    630
    631	/* Initialize this copy of the CPU DAI driver structure */
    632	memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
    633	host->cpu_dai_drv.name = dev_name(&pdev->dev);
    634
    635	/* Get the addresses */
    636	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
    637	if (IS_ERR(base))
    638		return PTR_ERR(base);
    639
    640	quirks = of_device_get_match_data(&pdev->dev);
    641	if (quirks == NULL) {
    642		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
    643		return -ENODEV;
    644	}
    645	host->quirks = quirks;
    646
    647	host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
    648						&sun4i_spdif_regmap_config);
    649
    650	/* Clocks */
    651	host->apb_clk = devm_clk_get(&pdev->dev, "apb");
    652	if (IS_ERR(host->apb_clk)) {
    653		dev_err(&pdev->dev, "failed to get a apb clock.\n");
    654		return PTR_ERR(host->apb_clk);
    655	}
    656
    657	host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
    658	if (IS_ERR(host->spdif_clk)) {
    659		dev_err(&pdev->dev, "failed to get a spdif clock.\n");
    660		return PTR_ERR(host->spdif_clk);
    661	}
    662
    663	host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
    664	host->dma_params_tx.maxburst = 8;
    665	host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
    666
    667	platform_set_drvdata(pdev, host);
    668
    669	if (quirks->has_reset) {
    670		host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
    671								      NULL);
    672		if (PTR_ERR(host->rst) == -EPROBE_DEFER) {
    673			ret = -EPROBE_DEFER;
    674			dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
    675			return ret;
    676		}
    677		if (!IS_ERR(host->rst))
    678			reset_control_deassert(host->rst);
    679	}
    680
    681	ret = devm_snd_soc_register_component(&pdev->dev,
    682				&sun4i_spdif_component, &sun4i_spdif_dai, 1);
    683	if (ret)
    684		return ret;
    685
    686	pm_runtime_enable(&pdev->dev);
    687	if (!pm_runtime_enabled(&pdev->dev)) {
    688		ret = sun4i_spdif_runtime_resume(&pdev->dev);
    689		if (ret)
    690			goto err_unregister;
    691	}
    692
    693	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
    694	if (ret)
    695		goto err_suspend;
    696	return 0;
    697err_suspend:
    698	if (!pm_runtime_status_suspended(&pdev->dev))
    699		sun4i_spdif_runtime_suspend(&pdev->dev);
    700err_unregister:
    701	pm_runtime_disable(&pdev->dev);
    702	return ret;
    703}
    704
    705static int sun4i_spdif_remove(struct platform_device *pdev)
    706{
    707	pm_runtime_disable(&pdev->dev);
    708	if (!pm_runtime_status_suspended(&pdev->dev))
    709		sun4i_spdif_runtime_suspend(&pdev->dev);
    710
    711	return 0;
    712}
    713
    714static const struct dev_pm_ops sun4i_spdif_pm = {
    715	SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
    716			   sun4i_spdif_runtime_resume, NULL)
    717};
    718
    719static struct platform_driver sun4i_spdif_driver = {
    720	.driver		= {
    721		.name	= "sun4i-spdif",
    722		.of_match_table = of_match_ptr(sun4i_spdif_of_match),
    723		.pm	= &sun4i_spdif_pm,
    724	},
    725	.probe		= sun4i_spdif_probe,
    726	.remove		= sun4i_spdif_remove,
    727};
    728
    729module_platform_driver(sun4i_spdif_driver);
    730
    731MODULE_AUTHOR("Marcus Cooper <codekipper@gmail.com>");
    732MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
    733MODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface");
    734MODULE_LICENSE("GPL");
    735MODULE_ALIAS("platform:sun4i-spdif");