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

img-spdif-in.c (22855B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * IMG SPDIF input controller driver
      4 *
      5 * Copyright (C) 2015 Imagination Technologies Ltd.
      6 *
      7 * Author: Damien Horsley <Damien.Horsley@imgtec.com>
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/init.h>
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/of.h>
     15#include <linux/platform_device.h>
     16#include <linux/pm_runtime.h>
     17#include <linux/reset.h>
     18
     19#include <sound/core.h>
     20#include <sound/dmaengine_pcm.h>
     21#include <sound/initval.h>
     22#include <sound/pcm.h>
     23#include <sound/pcm_params.h>
     24#include <sound/soc.h>
     25
     26#define IMG_SPDIF_IN_RX_FIFO_OFFSET		0
     27
     28#define IMG_SPDIF_IN_CTL			0x4
     29#define IMG_SPDIF_IN_CTL_LOCKLO_MASK		0xff
     30#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT		0
     31#define IMG_SPDIF_IN_CTL_LOCKHI_MASK		0xff00
     32#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT		8
     33#define IMG_SPDIF_IN_CTL_TRK_MASK		0xff0000
     34#define IMG_SPDIF_IN_CTL_TRK_SHIFT		16
     35#define IMG_SPDIF_IN_CTL_SRD_MASK		0x70000000
     36#define IMG_SPDIF_IN_CTL_SRD_SHIFT		28
     37#define IMG_SPDIF_IN_CTL_SRT_MASK		BIT(31)
     38
     39#define IMG_SPDIF_IN_STATUS			0x8
     40#define IMG_SPDIF_IN_STATUS_SAM_MASK		0x7000
     41#define IMG_SPDIF_IN_STATUS_SAM_SHIFT		12
     42#define IMG_SPDIF_IN_STATUS_LOCK_MASK		BIT(15)
     43#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT		15
     44
     45#define IMG_SPDIF_IN_CLKGEN			0x1c
     46#define IMG_SPDIF_IN_CLKGEN_NOM_MASK		0x3ff
     47#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT		0
     48#define IMG_SPDIF_IN_CLKGEN_HLD_MASK		0x3ff0000
     49#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT		16
     50
     51#define IMG_SPDIF_IN_CSL			0x20
     52
     53#define IMG_SPDIF_IN_CSH			0x24
     54#define IMG_SPDIF_IN_CSH_MASK			0xff
     55#define IMG_SPDIF_IN_CSH_SHIFT			0
     56
     57#define IMG_SPDIF_IN_SOFT_RESET			0x28
     58#define IMG_SPDIF_IN_SOFT_RESET_MASK		BIT(0)
     59
     60#define IMG_SPDIF_IN_ACLKGEN_START		0x2c
     61#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK		0x3ff
     62#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT		0
     63#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK		0xffc00
     64#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT		10
     65#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK		0xff00000
     66#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT		20
     67
     68#define IMG_SPDIF_IN_NUM_ACLKGEN		4
     69
     70struct img_spdif_in {
     71	spinlock_t lock;
     72	void __iomem *base;
     73	struct clk *clk_sys;
     74	struct snd_dmaengine_dai_dma_data dma_data;
     75	struct device *dev;
     76	unsigned int trk;
     77	bool multi_freq;
     78	int lock_acquire;
     79	int lock_release;
     80	unsigned int single_freq;
     81	unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
     82	bool active;
     83	u32 suspend_clkgen;
     84	u32 suspend_ctl;
     85
     86	/* Write-only registers */
     87	unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
     88};
     89
     90static int img_spdif_in_runtime_suspend(struct device *dev)
     91{
     92	struct img_spdif_in *spdif = dev_get_drvdata(dev);
     93
     94	clk_disable_unprepare(spdif->clk_sys);
     95
     96	return 0;
     97}
     98
     99static int img_spdif_in_runtime_resume(struct device *dev)
    100{
    101	struct img_spdif_in *spdif = dev_get_drvdata(dev);
    102	int ret;
    103
    104	ret = clk_prepare_enable(spdif->clk_sys);
    105	if (ret) {
    106		dev_err(dev, "Unable to enable sys clock\n");
    107		return ret;
    108	}
    109
    110	return 0;
    111}
    112
    113static inline void img_spdif_in_writel(struct img_spdif_in *spdif,
    114					u32 val, u32 reg)
    115{
    116	writel(val, spdif->base + reg);
    117}
    118
    119static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg)
    120{
    121	return readl(spdif->base + reg);
    122}
    123
    124static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif,
    125						u32 index)
    126{
    127	img_spdif_in_writel(spdif, spdif->aclkgen_regs[index],
    128			IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4));
    129}
    130
    131static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif,
    132		unsigned int sample_rate, unsigned long *actual_freq)
    133{
    134	unsigned long min_freq, freq_t;
    135
    136	/* Clock rate must be at least 24x the bit rate */
    137	min_freq = sample_rate * 2 * 32 * 24;
    138
    139	freq_t = clk_get_rate(spdif->clk_sys);
    140
    141	if (freq_t < min_freq)
    142		return -EINVAL;
    143
    144	*actual_freq = freq_t;
    145
    146	return 0;
    147}
    148
    149static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom,
    150		unsigned int *phld, unsigned long clk_rate)
    151{
    152	unsigned int ori, nom, hld;
    153
    154	/*
    155	 * Calculate oversampling ratio, nominal phase increment and hold
    156	 * increment for the given rate / frequency
    157	 */
    158
    159	if (!rate)
    160		return -EINVAL;
    161
    162	ori = clk_rate / (rate * 64);
    163
    164	if (!ori)
    165		return -EINVAL;
    166
    167	nom = (4096 / ori) + 1;
    168	do
    169		hld = 4096 - (--nom * (ori - 1));
    170	while (hld < 120);
    171
    172	*pnom = nom;
    173	*phld = hld;
    174
    175	return 0;
    176}
    177
    178static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif,
    179		unsigned int rate)
    180{
    181	unsigned int nom, hld;
    182	unsigned long flags, clk_rate;
    183	int ret = 0;
    184	u32 reg;
    185
    186	ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate);
    187	if (ret)
    188		return ret;
    189
    190	ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
    191	if (ret)
    192		return ret;
    193
    194	reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) &
    195		IMG_SPDIF_IN_CLKGEN_NOM_MASK;
    196	reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) &
    197		IMG_SPDIF_IN_CLKGEN_HLD_MASK;
    198
    199	spin_lock_irqsave(&spdif->lock, flags);
    200
    201	if (spdif->active) {
    202		spin_unlock_irqrestore(&spdif->lock, flags);
    203		return -EBUSY;
    204	}
    205
    206	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN);
    207
    208	spdif->single_freq = rate;
    209
    210	spin_unlock_irqrestore(&spdif->lock, flags);
    211
    212	return 0;
    213}
    214
    215static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif,
    216		unsigned int multi_freqs[])
    217{
    218	unsigned int nom, hld, rate, max_rate = 0;
    219	unsigned long flags, clk_rate;
    220	int i, ret = 0;
    221	u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
    222
    223	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
    224		if (multi_freqs[i] > max_rate)
    225			max_rate = multi_freqs[i];
    226
    227	ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate);
    228	if (ret)
    229		return ret;
    230
    231	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
    232		rate = multi_freqs[i];
    233
    234		ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
    235		if (ret)
    236			return ret;
    237
    238		reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) &
    239			IMG_SPDIF_IN_ACLKGEN_NOM_MASK;
    240		reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) &
    241			IMG_SPDIF_IN_ACLKGEN_HLD_MASK;
    242		temp_regs[i] = reg;
    243	}
    244
    245	spin_lock_irqsave(&spdif->lock, flags);
    246
    247	if (spdif->active) {
    248		spin_unlock_irqrestore(&spdif->lock, flags);
    249		return -EBUSY;
    250	}
    251
    252	trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT;
    253
    254	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
    255		spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg;
    256		img_spdif_in_aclkgen_writel(spdif, i);
    257	}
    258
    259	spdif->multi_freq = true;
    260	spdif->multi_freqs[0] = multi_freqs[0];
    261	spdif->multi_freqs[1] = multi_freqs[1];
    262	spdif->multi_freqs[2] = multi_freqs[2];
    263	spdif->multi_freqs[3] = multi_freqs[3];
    264
    265	spin_unlock_irqrestore(&spdif->lock, flags);
    266
    267	return 0;
    268}
    269
    270static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol,
    271		struct snd_ctl_elem_info *uinfo)
    272{
    273	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
    274	uinfo->count = 1;
    275
    276	return 0;
    277}
    278
    279static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol,
    280				       struct snd_ctl_elem_value *ucontrol)
    281{
    282	ucontrol->value.iec958.status[0] = 0xff;
    283	ucontrol->value.iec958.status[1] = 0xff;
    284	ucontrol->value.iec958.status[2] = 0xff;
    285	ucontrol->value.iec958.status[3] = 0xff;
    286	ucontrol->value.iec958.status[4] = 0xff;
    287
    288	return 0;
    289}
    290
    291static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol,
    292				  struct snd_ctl_elem_value *ucontrol)
    293{
    294	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    295	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    296	u32 reg;
    297
    298	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL);
    299	ucontrol->value.iec958.status[0] = reg & 0xff;
    300	ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
    301	ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
    302	ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
    303	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH);
    304	ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK)
    305		>> IMG_SPDIF_IN_CSH_SHIFT;
    306
    307	return 0;
    308}
    309
    310static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol,
    311		struct snd_ctl_elem_info *uinfo)
    312{
    313	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    314	uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN;
    315	uinfo->value.integer.min = 0;
    316	uinfo->value.integer.max = LONG_MAX;
    317
    318	return 0;
    319}
    320
    321static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol,
    322				  struct snd_ctl_elem_value *ucontrol)
    323{
    324	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    325	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    326	unsigned long flags;
    327
    328	spin_lock_irqsave(&spdif->lock, flags);
    329	if (spdif->multi_freq) {
    330		ucontrol->value.integer.value[0] = spdif->multi_freqs[0];
    331		ucontrol->value.integer.value[1] = spdif->multi_freqs[1];
    332		ucontrol->value.integer.value[2] = spdif->multi_freqs[2];
    333		ucontrol->value.integer.value[3] = spdif->multi_freqs[3];
    334	} else {
    335		ucontrol->value.integer.value[0] = 0;
    336		ucontrol->value.integer.value[1] = 0;
    337		ucontrol->value.integer.value[2] = 0;
    338		ucontrol->value.integer.value[3] = 0;
    339	}
    340	spin_unlock_irqrestore(&spdif->lock, flags);
    341
    342	return 0;
    343}
    344
    345static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol,
    346				  struct snd_ctl_elem_value *ucontrol)
    347{
    348	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    349	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    350	unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
    351	bool multi_freq;
    352	unsigned long flags;
    353
    354	if ((ucontrol->value.integer.value[0] == 0) &&
    355			(ucontrol->value.integer.value[1] == 0) &&
    356			(ucontrol->value.integer.value[2] == 0) &&
    357			(ucontrol->value.integer.value[3] == 0)) {
    358		multi_freq = false;
    359	} else {
    360		multi_freqs[0] = ucontrol->value.integer.value[0];
    361		multi_freqs[1] = ucontrol->value.integer.value[1];
    362		multi_freqs[2] = ucontrol->value.integer.value[2];
    363		multi_freqs[3] = ucontrol->value.integer.value[3];
    364		multi_freq = true;
    365	}
    366
    367	if (multi_freq)
    368		return img_spdif_in_do_clkgen_multi(spdif, multi_freqs);
    369
    370	spin_lock_irqsave(&spdif->lock, flags);
    371
    372	if (spdif->active) {
    373		spin_unlock_irqrestore(&spdif->lock, flags);
    374		return -EBUSY;
    375	}
    376
    377	spdif->multi_freq = false;
    378
    379	spin_unlock_irqrestore(&spdif->lock, flags);
    380
    381	return 0;
    382}
    383
    384static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol,
    385		struct snd_ctl_elem_info *uinfo)
    386{
    387	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    388	uinfo->count = 1;
    389	uinfo->value.integer.min = 0;
    390	uinfo->value.integer.max = LONG_MAX;
    391
    392	return 0;
    393}
    394
    395static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol,
    396				  struct snd_ctl_elem_value *uc)
    397{
    398	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    399	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    400	u32 reg;
    401	int i;
    402	unsigned long flags;
    403
    404	spin_lock_irqsave(&spdif->lock, flags);
    405
    406	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS);
    407	if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) {
    408		if (spdif->multi_freq) {
    409			i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >>
    410					IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1;
    411			uc->value.integer.value[0] = spdif->multi_freqs[i];
    412		} else {
    413			uc->value.integer.value[0] = spdif->single_freq;
    414		}
    415	} else {
    416		uc->value.integer.value[0] = 0;
    417	}
    418
    419	spin_unlock_irqrestore(&spdif->lock, flags);
    420
    421	return 0;
    422}
    423
    424static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol,
    425		struct snd_ctl_elem_info *uinfo)
    426{
    427	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    428	uinfo->count = 1;
    429	uinfo->value.integer.min = 0;
    430	uinfo->value.integer.max = 255;
    431
    432	return 0;
    433}
    434
    435static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol,
    436				  struct snd_ctl_elem_value *ucontrol)
    437{
    438	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    439	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    440
    441	ucontrol->value.integer.value[0] = spdif->trk;
    442
    443	return 0;
    444}
    445
    446static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol,
    447				  struct snd_ctl_elem_value *ucontrol)
    448{
    449	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    450	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    451	unsigned long flags;
    452	int i;
    453	u32 reg;
    454
    455	spin_lock_irqsave(&spdif->lock, flags);
    456
    457	if (spdif->active) {
    458		spin_unlock_irqrestore(&spdif->lock, flags);
    459		return -EBUSY;
    460	}
    461
    462	spdif->trk = ucontrol->value.integer.value[0];
    463
    464	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
    465	reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK;
    466	reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT;
    467	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
    468
    469	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
    470		spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] &
    471			~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) |
    472			(spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT);
    473
    474		img_spdif_in_aclkgen_writel(spdif, i);
    475	}
    476
    477	spin_unlock_irqrestore(&spdif->lock, flags);
    478
    479	return 0;
    480}
    481
    482static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol,
    483		struct snd_ctl_elem_info *uinfo)
    484{
    485	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    486	uinfo->count = 1;
    487	uinfo->value.integer.min = -128;
    488	uinfo->value.integer.max = 127;
    489
    490	return 0;
    491}
    492
    493static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol,
    494				  struct snd_ctl_elem_value *ucontrol)
    495{
    496	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    497	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    498
    499	ucontrol->value.integer.value[0] = spdif->lock_acquire;
    500
    501	return 0;
    502}
    503
    504static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol,
    505				  struct snd_ctl_elem_value *ucontrol)
    506{
    507	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    508	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    509	unsigned long flags;
    510	u32 reg;
    511
    512	spin_lock_irqsave(&spdif->lock, flags);
    513
    514	if (spdif->active) {
    515		spin_unlock_irqrestore(&spdif->lock, flags);
    516		return -EBUSY;
    517	}
    518
    519	spdif->lock_acquire = ucontrol->value.integer.value[0];
    520
    521	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
    522	reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK;
    523	reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
    524		IMG_SPDIF_IN_CTL_LOCKHI_MASK;
    525	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
    526
    527	spin_unlock_irqrestore(&spdif->lock, flags);
    528
    529	return 0;
    530}
    531
    532static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol,
    533				  struct snd_ctl_elem_value *ucontrol)
    534{
    535	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    536	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    537
    538	ucontrol->value.integer.value[0] = spdif->lock_release;
    539
    540	return 0;
    541}
    542
    543static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol,
    544				  struct snd_ctl_elem_value *ucontrol)
    545{
    546	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
    547	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
    548	unsigned long flags;
    549	u32 reg;
    550
    551	spin_lock_irqsave(&spdif->lock, flags);
    552
    553	if (spdif->active) {
    554		spin_unlock_irqrestore(&spdif->lock, flags);
    555		return -EBUSY;
    556	}
    557
    558	spdif->lock_release = ucontrol->value.integer.value[0];
    559
    560	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
    561	reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK;
    562	reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
    563		IMG_SPDIF_IN_CTL_LOCKLO_MASK;
    564	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
    565
    566	spin_unlock_irqrestore(&spdif->lock, flags);
    567
    568	return 0;
    569}
    570
    571static struct snd_kcontrol_new img_spdif_in_controls[] = {
    572	{
    573		.access = SNDRV_CTL_ELEM_ACCESS_READ,
    574		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    575		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
    576		.info = img_spdif_in_iec958_info,
    577		.get = img_spdif_in_get_status_mask
    578	},
    579	{
    580		.access = SNDRV_CTL_ELEM_ACCESS_READ |
    581			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
    582		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    583		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
    584		.info = img_spdif_in_iec958_info,
    585		.get = img_spdif_in_get_status
    586	},
    587	{
    588		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    589		.name = "SPDIF In Multi Frequency Acquire",
    590		.info = img_spdif_in_info_multi_freq,
    591		.get = img_spdif_in_get_multi_freq,
    592		.put = img_spdif_in_set_multi_freq
    593	},
    594	{
    595		.access = SNDRV_CTL_ELEM_ACCESS_READ |
    596			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
    597		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    598		.name = "SPDIF In Lock Frequency",
    599		.info = img_spdif_in_info_lock_freq,
    600		.get = img_spdif_in_get_lock_freq
    601	},
    602	{
    603		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    604		.name = "SPDIF In Lock TRK",
    605		.info = img_spdif_in_info_trk,
    606		.get = img_spdif_in_get_trk,
    607		.put = img_spdif_in_set_trk
    608	},
    609	{
    610		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    611		.name = "SPDIF In Lock Acquire Threshold",
    612		.info = img_spdif_in_info_lock,
    613		.get = img_spdif_in_get_lock_acquire,
    614		.put = img_spdif_in_set_lock_acquire
    615	},
    616	{
    617		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
    618		.name = "SPDIF In Lock Release Threshold",
    619		.info = img_spdif_in_info_lock,
    620		.get = img_spdif_in_get_lock_release,
    621		.put = img_spdif_in_set_lock_release
    622	}
    623};
    624
    625static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
    626	struct snd_soc_dai *dai)
    627{
    628	unsigned long flags;
    629	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
    630	int ret = 0;
    631	u32 reg;
    632
    633	spin_lock_irqsave(&spdif->lock, flags);
    634
    635	switch (cmd) {
    636	case SNDRV_PCM_TRIGGER_START:
    637	case SNDRV_PCM_TRIGGER_RESUME:
    638	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    639		reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
    640		if (spdif->multi_freq)
    641			reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK;
    642		else
    643			reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT);
    644		reg |= IMG_SPDIF_IN_CTL_SRT_MASK;
    645		img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
    646		spdif->active = true;
    647		break;
    648	case SNDRV_PCM_TRIGGER_STOP:
    649	case SNDRV_PCM_TRIGGER_SUSPEND:
    650	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    651		reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
    652		reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK;
    653		img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
    654		spdif->active = false;
    655		break;
    656	default:
    657		ret = -EINVAL;
    658	}
    659
    660	spin_unlock_irqrestore(&spdif->lock, flags);
    661
    662	return ret;
    663}
    664
    665static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
    666	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
    667{
    668	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
    669	unsigned int rate, channels;
    670	snd_pcm_format_t format;
    671
    672	rate = params_rate(params);
    673	channels = params_channels(params);
    674	format = params_format(params);
    675
    676	if (format != SNDRV_PCM_FORMAT_S32_LE)
    677		return -EINVAL;
    678
    679	if (channels != 2)
    680		return -EINVAL;
    681
    682	return img_spdif_in_do_clkgen_single(spdif, rate);
    683}
    684
    685static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
    686	.trigger = img_spdif_in_trigger,
    687	.hw_params = img_spdif_in_hw_params
    688};
    689
    690static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
    691{
    692	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
    693
    694	snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data);
    695
    696	snd_soc_add_dai_controls(dai, img_spdif_in_controls,
    697			ARRAY_SIZE(img_spdif_in_controls));
    698
    699	return 0;
    700}
    701
    702static struct snd_soc_dai_driver img_spdif_in_dai = {
    703	.probe = img_spdif_in_dai_probe,
    704	.capture = {
    705		.channels_min = 2,
    706		.channels_max = 2,
    707		.rates = SNDRV_PCM_RATE_8000_192000,
    708		.formats = SNDRV_PCM_FMTBIT_S32_LE
    709	},
    710	.ops = &img_spdif_in_dai_ops
    711};
    712
    713static const struct snd_soc_component_driver img_spdif_in_component = {
    714	.name = "img-spdif-in"
    715};
    716
    717static int img_spdif_in_probe(struct platform_device *pdev)
    718{
    719	struct img_spdif_in *spdif;
    720	struct resource *res;
    721	void __iomem *base;
    722	int ret;
    723	struct reset_control *rst;
    724	u32 reg;
    725	struct device *dev = &pdev->dev;
    726
    727	spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
    728	if (!spdif)
    729		return -ENOMEM;
    730
    731	platform_set_drvdata(pdev, spdif);
    732
    733	spdif->dev = &pdev->dev;
    734
    735	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
    736	if (IS_ERR(base))
    737		return PTR_ERR(base);
    738
    739	spdif->base = base;
    740
    741	spdif->clk_sys = devm_clk_get(dev, "sys");
    742	if (IS_ERR(spdif->clk_sys))
    743		return dev_err_probe(dev, PTR_ERR(spdif->clk_sys),
    744				     "Failed to acquire clock 'sys'\n");
    745
    746	pm_runtime_enable(&pdev->dev);
    747	if (!pm_runtime_enabled(&pdev->dev)) {
    748		ret = img_spdif_in_runtime_resume(&pdev->dev);
    749		if (ret)
    750			goto err_pm_disable;
    751	}
    752	ret = pm_runtime_resume_and_get(&pdev->dev);
    753	if (ret < 0)
    754		goto err_suspend;
    755
    756	rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
    757	if (IS_ERR(rst)) {
    758		if (PTR_ERR(rst) == -EPROBE_DEFER) {
    759			ret = -EPROBE_DEFER;
    760			goto err_pm_put;
    761		}
    762		dev_dbg(dev, "No top level reset found\n");
    763		img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK,
    764				IMG_SPDIF_IN_SOFT_RESET);
    765		img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET);
    766	} else {
    767		reset_control_assert(rst);
    768		reset_control_deassert(rst);
    769	}
    770
    771	spin_lock_init(&spdif->lock);
    772
    773	spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET;
    774	spdif->dma_data.addr_width = 4;
    775	spdif->dma_data.maxburst = 4;
    776	spdif->trk = 0x80;
    777	spdif->lock_acquire = 4;
    778	spdif->lock_release = -128;
    779
    780	reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
    781		IMG_SPDIF_IN_CTL_LOCKHI_MASK;
    782	reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
    783		IMG_SPDIF_IN_CTL_LOCKLO_MASK;
    784	reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) &
    785		IMG_SPDIF_IN_CTL_TRK_MASK;
    786	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
    787
    788	pm_runtime_put(&pdev->dev);
    789
    790	ret = devm_snd_soc_register_component(&pdev->dev,
    791			&img_spdif_in_component, &img_spdif_in_dai, 1);
    792	if (ret)
    793		goto err_suspend;
    794
    795	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
    796	if (ret)
    797		goto err_suspend;
    798
    799	return 0;
    800
    801err_pm_put:
    802	pm_runtime_put(&pdev->dev);
    803err_suspend:
    804	if (!pm_runtime_enabled(&pdev->dev))
    805		img_spdif_in_runtime_suspend(&pdev->dev);
    806err_pm_disable:
    807	pm_runtime_disable(&pdev->dev);
    808
    809	return ret;
    810}
    811
    812static int img_spdif_in_dev_remove(struct platform_device *pdev)
    813{
    814	pm_runtime_disable(&pdev->dev);
    815	if (!pm_runtime_status_suspended(&pdev->dev))
    816		img_spdif_in_runtime_suspend(&pdev->dev);
    817
    818	return 0;
    819}
    820
    821#ifdef CONFIG_PM_SLEEP
    822static int img_spdif_in_suspend(struct device *dev)
    823{
    824	struct img_spdif_in *spdif = dev_get_drvdata(dev);
    825	int ret;
    826
    827	if (pm_runtime_status_suspended(dev)) {
    828		ret = img_spdif_in_runtime_resume(dev);
    829		if (ret)
    830			return ret;
    831	}
    832
    833	spdif->suspend_clkgen = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CLKGEN);
    834	spdif->suspend_ctl = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
    835
    836	img_spdif_in_runtime_suspend(dev);
    837
    838	return 0;
    839}
    840
    841static int img_spdif_in_resume(struct device *dev)
    842{
    843	struct img_spdif_in *spdif = dev_get_drvdata(dev);
    844	int i, ret;
    845
    846	ret = img_spdif_in_runtime_resume(dev);
    847	if (ret)
    848		return ret;
    849
    850	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
    851		img_spdif_in_aclkgen_writel(spdif, i);
    852
    853	img_spdif_in_writel(spdif, spdif->suspend_clkgen, IMG_SPDIF_IN_CLKGEN);
    854	img_spdif_in_writel(spdif, spdif->suspend_ctl, IMG_SPDIF_IN_CTL);
    855
    856	if (pm_runtime_status_suspended(dev))
    857		img_spdif_in_runtime_suspend(dev);
    858
    859	return 0;
    860}
    861#endif
    862
    863static const struct of_device_id img_spdif_in_of_match[] = {
    864	{ .compatible = "img,spdif-in" },
    865	{}
    866};
    867MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
    868
    869static const struct dev_pm_ops img_spdif_in_pm_ops = {
    870	SET_RUNTIME_PM_OPS(img_spdif_in_runtime_suspend,
    871			   img_spdif_in_runtime_resume, NULL)
    872	SET_SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume)
    873};
    874
    875static struct platform_driver img_spdif_in_driver = {
    876	.driver = {
    877		.name = "img-spdif-in",
    878		.of_match_table = img_spdif_in_of_match,
    879		.pm = &img_spdif_in_pm_ops
    880	},
    881	.probe = img_spdif_in_probe,
    882	.remove = img_spdif_in_dev_remove
    883};
    884module_platform_driver(img_spdif_in_driver);
    885
    886MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
    887MODULE_DESCRIPTION("IMG SPDIF Input driver");
    888MODULE_LICENSE("GPL v2");