18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ALSA SoC SPDIF Audio Layer
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2015 Andrea Venturi <be17068@iperbole.bo.it>
68c2ecf20Sopenharmony_ci * Copyright 2015 Marcus Cooper <codekipper@gmail.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Based on the Allwinner SDK driver, released under the GPL.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/clk.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/device.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/regmap.h>
178c2ecf20Sopenharmony_ci#include <linux/of_address.h>
188c2ecf20Sopenharmony_ci#include <linux/of_device.h>
198c2ecf20Sopenharmony_ci#include <linux/ioport.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
238c2ecf20Sopenharmony_ci#include <linux/reset.h>
248c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h>
258c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
268c2ecf20Sopenharmony_ci#include <sound/soc.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define	SUN4I_SPDIF_CTL		(0x00)
298c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_CTL_MCLKDIV(v)		((v) << 4) /* v even */
308c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_CTL_MCLKOUTEN		BIT(2)
318c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_CTL_GEN			BIT(1)
328c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_CTL_RESET			BIT(0)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_TXCFG	(0x04)
358c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_SINGLEMOD		BIT(31)
368c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_ASS			BIT(17)
378c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_NONAUDIO		BIT(16)
388c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_TXRATIO(v)		((v) << 4)
398c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_TXRATIO_MASK		GENMASK(8, 4)
408c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_FMTRVD		GENMASK(3, 2)
418c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_FMT16BIT		(0 << 2)
428c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_FMT20BIT		(1 << 2)
438c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_FMT24BIT		(2 << 2)
448c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_CHSTMODE		BIT(1)
458c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCFG_TXEN			BIT(0)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_RXCFG	(0x08)
488c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCFG_LOCKFLAG		BIT(4)
498c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCFG_CHSTSRC		BIT(3)
508c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCFG_CHSTCP		BIT(1)
518c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCFG_RXEN			BIT(0)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_TXFIFO	(0x0C)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_RXFIFO	(0x10)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_FCTL	(0x14)
588c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_FIFOSRC		BIT(31)
598c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_FTX			BIT(17)
608c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_FRX			BIT(16)
618c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_TXTL(v)		((v) << 8)
628c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_TXTL_MASK		GENMASK(12, 8)
638c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_RXTL(v)		((v) << 3)
648c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_RXTL_MASK		GENMASK(7, 3)
658c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_TXIM			BIT(2)
668c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_RXOM(v)		((v) << 0)
678c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FCTL_RXOM_MASK		GENMASK(1, 0)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define SUN50I_H6_SPDIF_FCTL (0x14)
708c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_HUB_EN		BIT(31)
718c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_FTX		BIT(30)
728c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_FRX		BIT(29)
738c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_TXTL(v)		((v) << 12)
748c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_TXTL_MASK		GENMASK(19, 12)
758c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_RXTL(v)		((v) << 4)
768c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_RXTL_MASK		GENMASK(10, 4)
778c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_TXIM		BIT(2)
788c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_RXOM(v)		((v) << 0)
798c2ecf20Sopenharmony_ci	#define SUN50I_H6_SPDIF_FCTL_RXOM_MASK		GENMASK(1, 0)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_FSTA	(0x18)
828c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FSTA_TXE			BIT(14)
838c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FSTA_TXECNTSHT		(8)
848c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FSTA_RXA			BIT(6)
858c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_FSTA_RXACNTSHT		(0)
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_INT		(0x1C)
888c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_RXLOCKEN		BIT(18)
898c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_RXUNLOCKEN		BIT(17)
908c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_RXPARERREN		BIT(16)
918c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_TXDRQEN			BIT(7)
928c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_TXUIEN			BIT(6)
938c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_TXOIEN			BIT(5)
948c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_TXEIEN			BIT(4)
958c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_RXDRQEN			BIT(2)
968c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_RXOIEN			BIT(1)
978c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_INT_RXAIEN			BIT(0)
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_ISTA	(0x20)
1008c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_RXLOCKSTA		BIT(18)
1018c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_RXUNLOCKSTA		BIT(17)
1028c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_RXPARERRSTA		BIT(16)
1038c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_TXUSTA			BIT(6)
1048c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_TXOSTA			BIT(5)
1058c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_TXESTA			BIT(4)
1068c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_RXOSTA			BIT(1)
1078c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_ISTA_RXASTA			BIT(0)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define SUN8I_SPDIF_TXFIFO	(0x20)
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_TXCNT	(0x24)
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_RXCNT	(0x28)
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_TXCHSTA0	(0x2C)
1168c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_CLK(v)		((v) << 28)
1178c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v)		((v) << 24)
1188c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK	GENMASK(27, 24)
1198c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_CHNUM(v)		((v) << 20)
1208c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK		GENMASK(23, 20)
1218c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v)		((v) << 16)
1228c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_CATACOD(v)		((v) << 8)
1238c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_MODE(v)		((v) << 6)
1248c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v)	((v) << 3)
1258c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_CP			BIT(2)
1268c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_AUDIO		BIT(1)
1278c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA0_PRO		BIT(0)
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_TXCHSTA1	(0x30)
1308c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA1_CGMSA(v)		((v) << 8)
1318c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v)	((v) << 4)
1328c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK	GENMASK(7, 4)
1338c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v)	((v) << 1)
1348c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN		BIT(0)
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_RXCHSTA0	(0x34)
1378c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_CLK(v)		((v) << 28)
1388c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v)		((v) << 24)
1398c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_CHNUM(v)		((v) << 20)
1408c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v)		((v) << 16)
1418c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_CATACOD(v)		((v) << 8)
1428c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_MODE(v)		((v) << 6)
1438c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v)	((v) << 3)
1448c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_CP			BIT(2)
1458c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_AUDIO		BIT(1)
1468c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA0_PRO		BIT(0)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_RXCHSTA1	(0x38)
1498c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA1_CGMSA(v)		((v) << 8)
1508c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v)	((v) << 4)
1518c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v)	((v) << 1)
1528c2ecf20Sopenharmony_ci	#define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN		BIT(0)
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/* Defines for Sampling Frequency */
1558c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_44_1KHZ		0x0
1568c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED	0x1
1578c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_48KHZ		0x2
1588c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_32KHZ		0x3
1598c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_22_05KHZ		0x4
1608c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_24KHZ		0x6
1618c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_88_2KHZ		0x8
1628c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_76_8KHZ		0x9
1638c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_96KHZ		0xa
1648c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_176_4KHZ		0xc
1658c2ecf20Sopenharmony_ci#define SUN4I_SPDIF_SAMFREQ_192KHZ		0xe
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/**
1688c2ecf20Sopenharmony_ci * struct sun4i_spdif_quirks - Differences between SoC variants.
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * @reg_dac_txdata: TX FIFO offset for DMA config.
1718c2ecf20Sopenharmony_ci * @has_reset: SoC needs reset deasserted.
1728c2ecf20Sopenharmony_ci * @val_fctl_ftx: TX FIFO flush bitmask.
1738c2ecf20Sopenharmony_ci */
1748c2ecf20Sopenharmony_cistruct sun4i_spdif_quirks {
1758c2ecf20Sopenharmony_ci	unsigned int reg_dac_txdata;
1768c2ecf20Sopenharmony_ci	bool has_reset;
1778c2ecf20Sopenharmony_ci	unsigned int val_fctl_ftx;
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistruct sun4i_spdif_dev {
1818c2ecf20Sopenharmony_ci	struct platform_device *pdev;
1828c2ecf20Sopenharmony_ci	struct clk *spdif_clk;
1838c2ecf20Sopenharmony_ci	struct clk *apb_clk;
1848c2ecf20Sopenharmony_ci	struct reset_control *rst;
1858c2ecf20Sopenharmony_ci	struct snd_soc_dai_driver cpu_dai_drv;
1868c2ecf20Sopenharmony_ci	struct regmap *regmap;
1878c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data dma_params_tx;
1888c2ecf20Sopenharmony_ci	const struct sun4i_spdif_quirks *quirks;
1898c2ecf20Sopenharmony_ci};
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	const struct sun4i_spdif_quirks *quirks = host->quirks;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* soft reset SPDIF */
1968c2ecf20Sopenharmony_ci	regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/* flush TX FIFO */
1998c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
2008c2ecf20Sopenharmony_ci			   quirks->val_fctl_ftx, quirks->val_fctl_ftx);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* clear TX counter */
2038c2ecf20Sopenharmony_ci	regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream,
2078c2ecf20Sopenharmony_ci				struct sun4i_spdif_dev *host)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	if (substream->runtime->channels == 1)
2108c2ecf20Sopenharmony_ci		regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
2118c2ecf20Sopenharmony_ci				   SUN4I_SPDIF_TXCFG_SINGLEMOD,
2128c2ecf20Sopenharmony_ci				   SUN4I_SPDIF_TXCFG_SINGLEMOD);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* SPDIF TX ENABLE */
2158c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
2168c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* DRQ ENABLE */
2198c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
2208c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* Global enable */
2238c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
2248c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream,
2288c2ecf20Sopenharmony_ci				 struct sun4i_spdif_dev *host)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	/* SPDIF TX DISABLE */
2318c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
2328c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_TXCFG_TXEN, 0);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/* DRQ DISABLE */
2358c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_INT,
2368c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_INT_TXDRQEN, 0);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Global disable */
2398c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL,
2408c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_CTL_GEN, 0);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int sun4i_spdif_startup(struct snd_pcm_substream *substream,
2448c2ecf20Sopenharmony_ci			       struct snd_soc_dai *cpu_dai)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2478c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
2508c2ecf20Sopenharmony_ci		return -EINVAL;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	sun4i_spdif_configure(host);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return 0;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
2588c2ecf20Sopenharmony_ci				 struct snd_pcm_hw_params *params,
2598c2ecf20Sopenharmony_ci				 struct snd_soc_dai *cpu_dai)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	int ret = 0;
2628c2ecf20Sopenharmony_ci	int fmt;
2638c2ecf20Sopenharmony_ci	unsigned long rate = params_rate(params);
2648c2ecf20Sopenharmony_ci	u32 mclk_div = 0;
2658c2ecf20Sopenharmony_ci	unsigned int mclk = 0;
2668c2ecf20Sopenharmony_ci	u32 reg_val;
2678c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
2688c2ecf20Sopenharmony_ci	struct platform_device *pdev = host->pdev;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/* Add the PCM and raw data select interface */
2718c2ecf20Sopenharmony_ci	switch (params_channels(params)) {
2728c2ecf20Sopenharmony_ci	case 1: /* PCM mode */
2738c2ecf20Sopenharmony_ci	case 2:
2748c2ecf20Sopenharmony_ci		fmt = 0;
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	case 4: /* raw data mode */
2778c2ecf20Sopenharmony_ci		fmt = SUN4I_SPDIF_TXCFG_NONAUDIO;
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	default:
2808c2ecf20Sopenharmony_ci		return -EINVAL;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	switch (params_format(params)) {
2848c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
2858c2ecf20Sopenharmony_ci		fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S20_3LE:
2888c2ecf20Sopenharmony_ci		fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
2898c2ecf20Sopenharmony_ci		break;
2908c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
2918c2ecf20Sopenharmony_ci		fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
2928c2ecf20Sopenharmony_ci		break;
2938c2ecf20Sopenharmony_ci	default:
2948c2ecf20Sopenharmony_ci		return -EINVAL;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	switch (rate) {
2988c2ecf20Sopenharmony_ci	case 22050:
2998c2ecf20Sopenharmony_ci	case 44100:
3008c2ecf20Sopenharmony_ci	case 88200:
3018c2ecf20Sopenharmony_ci	case 176400:
3028c2ecf20Sopenharmony_ci		mclk = 22579200;
3038c2ecf20Sopenharmony_ci		break;
3048c2ecf20Sopenharmony_ci	case 24000:
3058c2ecf20Sopenharmony_ci	case 32000:
3068c2ecf20Sopenharmony_ci	case 48000:
3078c2ecf20Sopenharmony_ci	case 96000:
3088c2ecf20Sopenharmony_ci	case 192000:
3098c2ecf20Sopenharmony_ci		mclk = 24576000;
3108c2ecf20Sopenharmony_ci		break;
3118c2ecf20Sopenharmony_ci	default:
3128c2ecf20Sopenharmony_ci		return -EINVAL;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	ret = clk_set_rate(host->spdif_clk, mclk);
3168c2ecf20Sopenharmony_ci	if (ret < 0) {
3178c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
3188c2ecf20Sopenharmony_ci			"Setting SPDIF clock rate for %d Hz failed!\n", mclk);
3198c2ecf20Sopenharmony_ci		return ret;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
3238c2ecf20Sopenharmony_ci			   SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	switch (rate) {
3268c2ecf20Sopenharmony_ci	case 22050:
3278c2ecf20Sopenharmony_ci	case 24000:
3288c2ecf20Sopenharmony_ci		mclk_div = 8;
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	case 32000:
3318c2ecf20Sopenharmony_ci		mclk_div = 6;
3328c2ecf20Sopenharmony_ci		break;
3338c2ecf20Sopenharmony_ci	case 44100:
3348c2ecf20Sopenharmony_ci	case 48000:
3358c2ecf20Sopenharmony_ci		mclk_div = 4;
3368c2ecf20Sopenharmony_ci		break;
3378c2ecf20Sopenharmony_ci	case 88200:
3388c2ecf20Sopenharmony_ci	case 96000:
3398c2ecf20Sopenharmony_ci		mclk_div = 2;
3408c2ecf20Sopenharmony_ci		break;
3418c2ecf20Sopenharmony_ci	case 176400:
3428c2ecf20Sopenharmony_ci	case 192000:
3438c2ecf20Sopenharmony_ci		mclk_div = 1;
3448c2ecf20Sopenharmony_ci		break;
3458c2ecf20Sopenharmony_ci	default:
3468c2ecf20Sopenharmony_ci		return -EINVAL;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	reg_val = 0;
3508c2ecf20Sopenharmony_ci	reg_val |= SUN4I_SPDIF_TXCFG_ASS;
3518c2ecf20Sopenharmony_ci	reg_val |= fmt; /* set non audio and bit depth */
3528c2ecf20Sopenharmony_ci	reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE;
3538c2ecf20Sopenharmony_ci	reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1);
3548c2ecf20Sopenharmony_ci	regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return 0;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
3608c2ecf20Sopenharmony_ci			       struct snd_soc_dai *dai)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	int ret = 0;
3638c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
3668c2ecf20Sopenharmony_ci		return -EINVAL;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	switch (cmd) {
3698c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
3708c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
3718c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3728c2ecf20Sopenharmony_ci		sun4i_snd_txctrl_on(substream, host);
3738c2ecf20Sopenharmony_ci		break;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
3768c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
3778c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3788c2ecf20Sopenharmony_ci		sun4i_snd_txctrl_off(substream, host);
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	default:
3828c2ecf20Sopenharmony_ci		ret = -EINVAL;
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	return ret;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL);
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
3978c2ecf20Sopenharmony_ci	.startup	= sun4i_spdif_startup,
3988c2ecf20Sopenharmony_ci	.trigger	= sun4i_spdif_trigger,
3998c2ecf20Sopenharmony_ci	.hw_params	= sun4i_spdif_hw_params,
4008c2ecf20Sopenharmony_ci};
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic const struct regmap_config sun4i_spdif_regmap_config = {
4038c2ecf20Sopenharmony_ci	.reg_bits = 32,
4048c2ecf20Sopenharmony_ci	.reg_stride = 4,
4058c2ecf20Sopenharmony_ci	.val_bits = 32,
4068c2ecf20Sopenharmony_ci	.max_register = SUN4I_SPDIF_RXCHSTA1,
4078c2ecf20Sopenharmony_ci};
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci#define SUN4I_RATES	SNDRV_PCM_RATE_8000_192000
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci#define SUN4I_FORMATS	(SNDRV_PCM_FORMAT_S16_LE | \
4128c2ecf20Sopenharmony_ci				SNDRV_PCM_FORMAT_S20_3LE | \
4138c2ecf20Sopenharmony_ci				SNDRV_PCM_FORMAT_S24_LE)
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver sun4i_spdif_dai = {
4168c2ecf20Sopenharmony_ci	.playback = {
4178c2ecf20Sopenharmony_ci		.channels_min = 1,
4188c2ecf20Sopenharmony_ci		.channels_max = 2,
4198c2ecf20Sopenharmony_ci		.rates = SUN4I_RATES,
4208c2ecf20Sopenharmony_ci		.formats = SUN4I_FORMATS,
4218c2ecf20Sopenharmony_ci	},
4228c2ecf20Sopenharmony_ci	.probe = sun4i_spdif_soc_dai_probe,
4238c2ecf20Sopenharmony_ci	.ops = &sun4i_spdif_dai_ops,
4248c2ecf20Sopenharmony_ci	.name = "spdif",
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
4288c2ecf20Sopenharmony_ci	.reg_dac_txdata	= SUN4I_SPDIF_TXFIFO,
4298c2ecf20Sopenharmony_ci	.val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
4308c2ecf20Sopenharmony_ci};
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
4338c2ecf20Sopenharmony_ci	.reg_dac_txdata	= SUN4I_SPDIF_TXFIFO,
4348c2ecf20Sopenharmony_ci	.val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
4358c2ecf20Sopenharmony_ci	.has_reset	= true,
4368c2ecf20Sopenharmony_ci};
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
4398c2ecf20Sopenharmony_ci	.reg_dac_txdata	= SUN8I_SPDIF_TXFIFO,
4408c2ecf20Sopenharmony_ci	.val_fctl_ftx   = SUN4I_SPDIF_FCTL_FTX,
4418c2ecf20Sopenharmony_ci	.has_reset	= true,
4428c2ecf20Sopenharmony_ci};
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
4458c2ecf20Sopenharmony_ci	.reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
4468c2ecf20Sopenharmony_ci	.val_fctl_ftx   = SUN50I_H6_SPDIF_FCTL_FTX,
4478c2ecf20Sopenharmony_ci	.has_reset      = true,
4488c2ecf20Sopenharmony_ci};
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic const struct of_device_id sun4i_spdif_of_match[] = {
4518c2ecf20Sopenharmony_ci	{
4528c2ecf20Sopenharmony_ci		.compatible = "allwinner,sun4i-a10-spdif",
4538c2ecf20Sopenharmony_ci		.data = &sun4i_a10_spdif_quirks,
4548c2ecf20Sopenharmony_ci	},
4558c2ecf20Sopenharmony_ci	{
4568c2ecf20Sopenharmony_ci		.compatible = "allwinner,sun6i-a31-spdif",
4578c2ecf20Sopenharmony_ci		.data = &sun6i_a31_spdif_quirks,
4588c2ecf20Sopenharmony_ci	},
4598c2ecf20Sopenharmony_ci	{
4608c2ecf20Sopenharmony_ci		.compatible = "allwinner,sun8i-h3-spdif",
4618c2ecf20Sopenharmony_ci		.data = &sun8i_h3_spdif_quirks,
4628c2ecf20Sopenharmony_ci	},
4638c2ecf20Sopenharmony_ci	{
4648c2ecf20Sopenharmony_ci		.compatible = "allwinner,sun50i-h6-spdif",
4658c2ecf20Sopenharmony_ci		.data = &sun50i_h6_spdif_quirks,
4668c2ecf20Sopenharmony_ci	},
4678c2ecf20Sopenharmony_ci	{ /* sentinel */ }
4688c2ecf20Sopenharmony_ci};
4698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sun4i_spdif_component = {
4728c2ecf20Sopenharmony_ci	.name		= "sun4i-spdif",
4738c2ecf20Sopenharmony_ci};
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int sun4i_spdif_runtime_suspend(struct device *dev)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	clk_disable_unprepare(host->spdif_clk);
4808c2ecf20Sopenharmony_ci	clk_disable_unprepare(host->apb_clk);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	return 0;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic int sun4i_spdif_runtime_resume(struct device *dev)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host  = dev_get_drvdata(dev);
4888c2ecf20Sopenharmony_ci	int ret;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(host->spdif_clk);
4918c2ecf20Sopenharmony_ci	if (ret)
4928c2ecf20Sopenharmony_ci		return ret;
4938c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(host->apb_clk);
4948c2ecf20Sopenharmony_ci	if (ret)
4958c2ecf20Sopenharmony_ci		clk_disable_unprepare(host->spdif_clk);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return ret;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic int sun4i_spdif_probe(struct platform_device *pdev)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct sun4i_spdif_dev *host;
5038c2ecf20Sopenharmony_ci	struct resource *res;
5048c2ecf20Sopenharmony_ci	const struct sun4i_spdif_quirks *quirks;
5058c2ecf20Sopenharmony_ci	int ret;
5068c2ecf20Sopenharmony_ci	void __iomem *base;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "Entered %s\n", __func__);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
5118c2ecf20Sopenharmony_ci	if (!host)
5128c2ecf20Sopenharmony_ci		return -ENOMEM;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	host->pdev = pdev;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	/* Initialize this copy of the CPU DAI driver structure */
5178c2ecf20Sopenharmony_ci	memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai));
5188c2ecf20Sopenharmony_ci	host->cpu_dai_drv.name = dev_name(&pdev->dev);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	/* Get the addresses */
5218c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5228c2ecf20Sopenharmony_ci	base = devm_ioremap_resource(&pdev->dev, res);
5238c2ecf20Sopenharmony_ci	if (IS_ERR(base))
5248c2ecf20Sopenharmony_ci		return PTR_ERR(base);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	quirks = of_device_get_match_data(&pdev->dev);
5278c2ecf20Sopenharmony_ci	if (quirks == NULL) {
5288c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
5298c2ecf20Sopenharmony_ci		return -ENODEV;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci	host->quirks = quirks;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
5348c2ecf20Sopenharmony_ci						&sun4i_spdif_regmap_config);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* Clocks */
5378c2ecf20Sopenharmony_ci	host->apb_clk = devm_clk_get(&pdev->dev, "apb");
5388c2ecf20Sopenharmony_ci	if (IS_ERR(host->apb_clk)) {
5398c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to get a apb clock.\n");
5408c2ecf20Sopenharmony_ci		return PTR_ERR(host->apb_clk);
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	host->spdif_clk = devm_clk_get(&pdev->dev, "spdif");
5448c2ecf20Sopenharmony_ci	if (IS_ERR(host->spdif_clk)) {
5458c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to get a spdif clock.\n");
5468c2ecf20Sopenharmony_ci		return PTR_ERR(host->spdif_clk);
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
5508c2ecf20Sopenharmony_ci	host->dma_params_tx.maxburst = 8;
5518c2ecf20Sopenharmony_ci	host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, host);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (quirks->has_reset) {
5568c2ecf20Sopenharmony_ci		host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
5578c2ecf20Sopenharmony_ci								      NULL);
5588c2ecf20Sopenharmony_ci		if (PTR_ERR(host->rst) == -EPROBE_DEFER) {
5598c2ecf20Sopenharmony_ci			ret = -EPROBE_DEFER;
5608c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
5618c2ecf20Sopenharmony_ci			return ret;
5628c2ecf20Sopenharmony_ci		}
5638c2ecf20Sopenharmony_ci		if (!IS_ERR(host->rst))
5648c2ecf20Sopenharmony_ci			reset_control_deassert(host->rst);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev,
5688c2ecf20Sopenharmony_ci				&sun4i_spdif_component, &sun4i_spdif_dai, 1);
5698c2ecf20Sopenharmony_ci	if (ret)
5708c2ecf20Sopenharmony_ci		return ret;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
5738c2ecf20Sopenharmony_ci	if (!pm_runtime_enabled(&pdev->dev)) {
5748c2ecf20Sopenharmony_ci		ret = sun4i_spdif_runtime_resume(&pdev->dev);
5758c2ecf20Sopenharmony_ci		if (ret)
5768c2ecf20Sopenharmony_ci			goto err_unregister;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
5808c2ecf20Sopenharmony_ci	if (ret)
5818c2ecf20Sopenharmony_ci		goto err_suspend;
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_cierr_suspend:
5848c2ecf20Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev))
5858c2ecf20Sopenharmony_ci		sun4i_spdif_runtime_suspend(&pdev->dev);
5868c2ecf20Sopenharmony_cierr_unregister:
5878c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
5888c2ecf20Sopenharmony_ci	return ret;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic int sun4i_spdif_remove(struct platform_device *pdev)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
5948c2ecf20Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev))
5958c2ecf20Sopenharmony_ci		sun4i_spdif_runtime_suspend(&pdev->dev);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return 0;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sun4i_spdif_pm = {
6018c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
6028c2ecf20Sopenharmony_ci			   sun4i_spdif_runtime_resume, NULL)
6038c2ecf20Sopenharmony_ci};
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic struct platform_driver sun4i_spdif_driver = {
6068c2ecf20Sopenharmony_ci	.driver		= {
6078c2ecf20Sopenharmony_ci		.name	= "sun4i-spdif",
6088c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(sun4i_spdif_of_match),
6098c2ecf20Sopenharmony_ci		.pm	= &sun4i_spdif_pm,
6108c2ecf20Sopenharmony_ci	},
6118c2ecf20Sopenharmony_ci	.probe		= sun4i_spdif_probe,
6128c2ecf20Sopenharmony_ci	.remove		= sun4i_spdif_remove,
6138c2ecf20Sopenharmony_ci};
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cimodule_platform_driver(sun4i_spdif_driver);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marcus Cooper <codekipper@gmail.com>");
6188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
6198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface");
6208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6218c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sun4i-spdif");
622