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-i2s-in.c (15596B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * IMG I2S 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_I2S_IN_RX_FIFO			0x0
     27
     28#define IMG_I2S_IN_CTL				0x4
     29#define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK		0xfffffffc
     30#define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT		2
     31#define IMG_I2S_IN_CTL_16PACK_MASK		BIT(1)
     32#define IMG_I2S_IN_CTL_ME_MASK			BIT(0)
     33
     34#define IMG_I2S_IN_CH_CTL			0x4
     35#define IMG_I2S_IN_CH_CTL_CCDEL_MASK		0x38000
     36#define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT		15
     37#define IMG_I2S_IN_CH_CTL_FEN_MASK		BIT(14)
     38#define IMG_I2S_IN_CH_CTL_FMODE_MASK		BIT(13)
     39#define IMG_I2S_IN_CH_CTL_16PACK_MASK		BIT(12)
     40#define IMG_I2S_IN_CH_CTL_JUST_MASK		BIT(10)
     41#define IMG_I2S_IN_CH_CTL_PACKH_MASK		BIT(9)
     42#define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK	BIT(8)
     43#define IMG_I2S_IN_CH_CTL_BLKP_MASK		BIT(7)
     44#define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK	BIT(6)
     45#define IMG_I2S_IN_CH_CTL_LRD_MASK		BIT(3)
     46#define IMG_I2S_IN_CH_CTL_FW_MASK		BIT(2)
     47#define IMG_I2S_IN_CH_CTL_SW_MASK		BIT(1)
     48#define IMG_I2S_IN_CH_CTL_ME_MASK		BIT(0)
     49
     50#define IMG_I2S_IN_CH_STRIDE			0x20
     51
     52struct img_i2s_in {
     53	void __iomem *base;
     54	struct clk *clk_sys;
     55	struct snd_dmaengine_dai_dma_data dma_data;
     56	struct device *dev;
     57	unsigned int max_i2s_chan;
     58	void __iomem *channel_base;
     59	unsigned int active_channels;
     60	struct snd_soc_dai_driver dai_driver;
     61	u32 suspend_ctl;
     62	u32 *suspend_ch_ctl;
     63};
     64
     65static int img_i2s_in_runtime_suspend(struct device *dev)
     66{
     67	struct img_i2s_in *i2s = dev_get_drvdata(dev);
     68
     69	clk_disable_unprepare(i2s->clk_sys);
     70
     71	return 0;
     72}
     73
     74static int img_i2s_in_runtime_resume(struct device *dev)
     75{
     76	struct img_i2s_in *i2s = dev_get_drvdata(dev);
     77	int ret;
     78
     79	ret = clk_prepare_enable(i2s->clk_sys);
     80	if (ret) {
     81		dev_err(dev, "Unable to enable sys clock\n");
     82		return ret;
     83	}
     84
     85	return 0;
     86}
     87
     88static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
     89{
     90	writel(val, i2s->base + reg);
     91}
     92
     93static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg)
     94{
     95	return readl(i2s->base + reg);
     96}
     97
     98static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan,
     99					u32 val, u32 reg)
    100{
    101	writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
    102}
    103
    104static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan,
    105					u32 reg)
    106{
    107	return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
    108}
    109
    110static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan)
    111{
    112	u32 reg;
    113
    114	reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
    115	reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK;
    116	img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
    117}
    118
    119static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan)
    120{
    121	u32 reg;
    122
    123	reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
    124	reg |= IMG_I2S_IN_CH_CTL_ME_MASK;
    125	img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
    126}
    127
    128static inline void img_i2s_in_disable(struct img_i2s_in *i2s)
    129{
    130	u32 reg;
    131
    132	reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
    133	reg &= ~IMG_I2S_IN_CTL_ME_MASK;
    134	img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
    135}
    136
    137static inline void img_i2s_in_enable(struct img_i2s_in *i2s)
    138{
    139	u32 reg;
    140
    141	reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
    142	reg |= IMG_I2S_IN_CTL_ME_MASK;
    143	img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
    144}
    145
    146static inline void img_i2s_in_flush(struct img_i2s_in *i2s)
    147{
    148	int i;
    149	u32 reg;
    150
    151	for (i = 0; i < i2s->active_channels; i++) {
    152		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
    153		reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
    154		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    155		reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
    156		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    157	}
    158}
    159
    160static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd,
    161	struct snd_soc_dai *dai)
    162{
    163	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
    164
    165	switch (cmd) {
    166	case SNDRV_PCM_TRIGGER_START:
    167	case SNDRV_PCM_TRIGGER_RESUME:
    168	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    169		img_i2s_in_enable(i2s);
    170		break;
    171
    172	case SNDRV_PCM_TRIGGER_STOP:
    173	case SNDRV_PCM_TRIGGER_SUSPEND:
    174	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    175		img_i2s_in_disable(i2s);
    176		break;
    177	default:
    178		return -EINVAL;
    179	}
    180
    181	return 0;
    182}
    183
    184static int img_i2s_in_check_rate(struct img_i2s_in *i2s,
    185		unsigned int sample_rate, unsigned int frame_size,
    186		unsigned int *bclk_filter_enable,
    187		unsigned int *bclk_filter_value)
    188{
    189	unsigned int bclk_freq, cur_freq;
    190
    191	bclk_freq = sample_rate * frame_size;
    192
    193	cur_freq = clk_get_rate(i2s->clk_sys);
    194
    195	if (cur_freq >= bclk_freq * 8) {
    196		*bclk_filter_enable = 1;
    197		*bclk_filter_value = 0;
    198	} else if (cur_freq >= bclk_freq * 7) {
    199		*bclk_filter_enable = 1;
    200		*bclk_filter_value = 1;
    201	} else if (cur_freq >= bclk_freq * 6) {
    202		*bclk_filter_enable = 0;
    203		*bclk_filter_value = 0;
    204	} else {
    205		dev_err(i2s->dev,
    206			"Sys clock rate %u insufficient for sample rate %u\n",
    207			cur_freq, sample_rate);
    208		return -EINVAL;
    209	}
    210
    211	return 0;
    212}
    213
    214static int img_i2s_in_hw_params(struct snd_pcm_substream *substream,
    215	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
    216{
    217	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
    218	unsigned int rate, channels, i2s_channels, frame_size;
    219	unsigned int bclk_filter_enable, bclk_filter_value;
    220	int i, ret = 0;
    221	u32 reg, control_mask, chan_control_mask;
    222	u32 control_set = 0, chan_control_set = 0;
    223	snd_pcm_format_t format;
    224
    225	rate = params_rate(params);
    226	format = params_format(params);
    227	channels = params_channels(params);
    228	i2s_channels = channels / 2;
    229
    230	switch (format) {
    231	case SNDRV_PCM_FORMAT_S32_LE:
    232		frame_size = 64;
    233		chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
    234		chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
    235		chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK;
    236		break;
    237	case SNDRV_PCM_FORMAT_S24_LE:
    238		frame_size = 64;
    239		chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
    240		chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
    241		break;
    242	case SNDRV_PCM_FORMAT_S16_LE:
    243		frame_size = 32;
    244		control_set |= IMG_I2S_IN_CTL_16PACK_MASK;
    245		chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK;
    246		break;
    247	default:
    248		return -EINVAL;
    249	}
    250
    251	if ((channels < 2) ||
    252	    (channels > (i2s->max_i2s_chan * 2)) ||
    253	    (channels % 2))
    254		return -EINVAL;
    255
    256	control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT);
    257
    258	ret = img_i2s_in_check_rate(i2s, rate, frame_size,
    259			&bclk_filter_enable, &bclk_filter_value);
    260	if (ret < 0)
    261		return ret;
    262
    263	if (bclk_filter_enable)
    264		chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK;
    265
    266	if (bclk_filter_value)
    267		chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK;
    268
    269	control_mask = IMG_I2S_IN_CTL_16PACK_MASK |
    270		       IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK;
    271
    272	chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK |
    273			    IMG_I2S_IN_CH_CTL_FEN_MASK |
    274			    IMG_I2S_IN_CH_CTL_FMODE_MASK |
    275			    IMG_I2S_IN_CH_CTL_SW_MASK |
    276			    IMG_I2S_IN_CH_CTL_FW_MASK |
    277			    IMG_I2S_IN_CH_CTL_PACKH_MASK;
    278
    279	reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
    280	reg = (reg & ~control_mask) | control_set;
    281	img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
    282
    283	for (i = 0; i < i2s->active_channels; i++)
    284		img_i2s_in_ch_disable(i2s, i);
    285
    286	for (i = 0; i < i2s->max_i2s_chan; i++) {
    287		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
    288		reg = (reg & ~chan_control_mask) | chan_control_set;
    289		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    290	}
    291
    292	i2s->active_channels = i2s_channels;
    293
    294	img_i2s_in_flush(i2s);
    295
    296	for (i = 0; i < i2s->active_channels; i++)
    297		img_i2s_in_ch_enable(i2s, i);
    298
    299	return 0;
    300}
    301
    302static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
    303{
    304	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
    305	int i, ret;
    306	u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0;
    307	u32 reg;
    308
    309	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
    310	case SND_SOC_DAIFMT_NB_NF:
    311		lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
    312		break;
    313	case SND_SOC_DAIFMT_NB_IF:
    314		break;
    315	case SND_SOC_DAIFMT_IB_NF:
    316		lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
    317		blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
    318		break;
    319	case SND_SOC_DAIFMT_IB_IF:
    320		blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
    321		break;
    322	default:
    323		return -EINVAL;
    324	}
    325
    326	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    327	case SND_SOC_DAIFMT_I2S:
    328		chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
    329		break;
    330	case SND_SOC_DAIFMT_LEFT_J:
    331		break;
    332	default:
    333		return -EINVAL;
    334	}
    335
    336	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    337	case SND_SOC_DAIFMT_CBM_CFM:
    338		break;
    339	default:
    340		return -EINVAL;
    341	}
    342
    343	chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
    344
    345	ret = pm_runtime_resume_and_get(i2s->dev);
    346	if (ret < 0)
    347		return ret;
    348
    349	for (i = 0; i < i2s->active_channels; i++)
    350		img_i2s_in_ch_disable(i2s, i);
    351
    352	/*
    353	 * BLKP and LRD must be set during separate register writes
    354	 */
    355	for (i = 0; i < i2s->max_i2s_chan; i++) {
    356		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
    357		reg = (reg & ~chan_control_mask) | chan_control_set;
    358		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    359		reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set;
    360		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    361		reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set;
    362		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    363	}
    364
    365	for (i = 0; i < i2s->active_channels; i++)
    366		img_i2s_in_ch_enable(i2s, i);
    367
    368	pm_runtime_put(i2s->dev);
    369
    370	return 0;
    371}
    372
    373static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
    374	.trigger = img_i2s_in_trigger,
    375	.hw_params = img_i2s_in_hw_params,
    376	.set_fmt = img_i2s_in_set_fmt
    377};
    378
    379static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
    380{
    381	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
    382
    383	snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data);
    384
    385	return 0;
    386}
    387
    388static const struct snd_soc_component_driver img_i2s_in_component = {
    389	.name = "img-i2s-in"
    390};
    391
    392static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
    393	struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
    394{
    395	unsigned int i2s_channels = params_channels(params) / 2;
    396	struct snd_soc_pcm_runtime *rtd = st->private_data;
    397	struct snd_dmaengine_dai_dma_data *dma_data;
    398	int ret;
    399
    400	dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), st);
    401
    402	ret = snd_hwparams_to_dma_slave_config(st, params, sc);
    403	if (ret)
    404		return ret;
    405
    406	sc->src_addr = dma_data->addr;
    407	sc->src_addr_width = dma_data->addr_width;
    408	sc->src_maxburst = 4 * i2s_channels;
    409
    410	return 0;
    411}
    412
    413static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
    414	.prepare_slave_config = img_i2s_in_dma_prepare_slave_config
    415};
    416
    417static int img_i2s_in_probe(struct platform_device *pdev)
    418{
    419	struct img_i2s_in *i2s;
    420	struct resource *res;
    421	void __iomem *base;
    422	int ret, i;
    423	struct reset_control *rst;
    424	unsigned int max_i2s_chan_pow_2;
    425	struct device *dev = &pdev->dev;
    426
    427	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
    428	if (!i2s)
    429		return -ENOMEM;
    430
    431	platform_set_drvdata(pdev, i2s);
    432
    433	i2s->dev = dev;
    434
    435	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
    436	if (IS_ERR(base))
    437		return PTR_ERR(base);
    438
    439	i2s->base = base;
    440
    441	if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
    442			&i2s->max_i2s_chan)) {
    443		dev_err(dev, "No img,i2s-channels property\n");
    444		return -EINVAL;
    445	}
    446
    447	max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
    448
    449	i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
    450
    451	i2s->clk_sys = devm_clk_get(dev, "sys");
    452	if (IS_ERR(i2s->clk_sys))
    453		return dev_err_probe(dev, PTR_ERR(i2s->clk_sys),
    454				     "Failed to acquire clock 'sys'\n");
    455
    456	pm_runtime_enable(&pdev->dev);
    457	if (!pm_runtime_enabled(&pdev->dev)) {
    458		ret = img_i2s_in_runtime_resume(&pdev->dev);
    459		if (ret)
    460			goto err_pm_disable;
    461	}
    462	ret = pm_runtime_resume_and_get(&pdev->dev);
    463	if (ret < 0)
    464		goto err_suspend;
    465
    466	i2s->active_channels = 1;
    467	i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
    468	i2s->dma_data.addr_width = 4;
    469
    470	i2s->dai_driver.probe = img_i2s_in_dai_probe;
    471	i2s->dai_driver.capture.channels_min = 2;
    472	i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
    473	i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
    474	i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
    475		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
    476	i2s->dai_driver.ops = &img_i2s_in_dai_ops;
    477
    478	rst = devm_reset_control_get_exclusive(dev, "rst");
    479	if (IS_ERR(rst)) {
    480		if (PTR_ERR(rst) == -EPROBE_DEFER) {
    481			ret = -EPROBE_DEFER;
    482			pm_runtime_put(&pdev->dev);
    483			goto err_suspend;
    484		}
    485
    486		dev_dbg(dev, "No top level reset found\n");
    487
    488		img_i2s_in_disable(i2s);
    489
    490		for (i = 0; i < i2s->max_i2s_chan; i++)
    491			img_i2s_in_ch_disable(i2s, i);
    492	} else {
    493		reset_control_assert(rst);
    494		reset_control_deassert(rst);
    495	}
    496
    497	img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
    498
    499	for (i = 0; i < i2s->max_i2s_chan; i++)
    500		img_i2s_in_ch_writel(i2s, i,
    501			(4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
    502			IMG_I2S_IN_CH_CTL_JUST_MASK |
    503			IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
    504
    505	pm_runtime_put(&pdev->dev);
    506
    507	i2s->suspend_ch_ctl = devm_kcalloc(dev,
    508		i2s->max_i2s_chan, sizeof(*i2s->suspend_ch_ctl), GFP_KERNEL);
    509	if (!i2s->suspend_ch_ctl) {
    510		ret = -ENOMEM;
    511		goto err_suspend;
    512	}
    513
    514	ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
    515						&i2s->dai_driver, 1);
    516	if (ret)
    517		goto err_suspend;
    518
    519	ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
    520	if (ret)
    521		goto err_suspend;
    522
    523	return 0;
    524
    525err_suspend:
    526	if (!pm_runtime_enabled(&pdev->dev))
    527		img_i2s_in_runtime_suspend(&pdev->dev);
    528err_pm_disable:
    529	pm_runtime_disable(&pdev->dev);
    530
    531	return ret;
    532}
    533
    534static int img_i2s_in_dev_remove(struct platform_device *pdev)
    535{
    536	pm_runtime_disable(&pdev->dev);
    537	if (!pm_runtime_status_suspended(&pdev->dev))
    538		img_i2s_in_runtime_suspend(&pdev->dev);
    539
    540	return 0;
    541}
    542
    543#ifdef CONFIG_PM_SLEEP
    544static int img_i2s_in_suspend(struct device *dev)
    545{
    546	struct img_i2s_in *i2s = dev_get_drvdata(dev);
    547	int i, ret;
    548	u32 reg;
    549
    550	if (pm_runtime_status_suspended(dev)) {
    551		ret = img_i2s_in_runtime_resume(dev);
    552		if (ret)
    553			return ret;
    554	}
    555
    556	for (i = 0; i < i2s->max_i2s_chan; i++) {
    557		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
    558		i2s->suspend_ch_ctl[i] = reg;
    559	}
    560
    561	i2s->suspend_ctl = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
    562
    563	img_i2s_in_runtime_suspend(dev);
    564
    565	return 0;
    566}
    567
    568static int img_i2s_in_resume(struct device *dev)
    569{
    570	struct img_i2s_in *i2s = dev_get_drvdata(dev);
    571	int i, ret;
    572	u32 reg;
    573
    574	ret = img_i2s_in_runtime_resume(dev);
    575	if (ret)
    576		return ret;
    577
    578	for (i = 0; i < i2s->max_i2s_chan; i++) {
    579		reg = i2s->suspend_ch_ctl[i];
    580		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
    581	}
    582
    583	img_i2s_in_writel(i2s, i2s->suspend_ctl, IMG_I2S_IN_CTL);
    584
    585	if (pm_runtime_status_suspended(dev))
    586		img_i2s_in_runtime_suspend(dev);
    587
    588	return 0;
    589}
    590#endif
    591
    592static const struct of_device_id img_i2s_in_of_match[] = {
    593	{ .compatible = "img,i2s-in" },
    594	{}
    595};
    596MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
    597
    598static const struct dev_pm_ops img_i2s_in_pm_ops = {
    599	SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend,
    600			   img_i2s_in_runtime_resume, NULL)
    601	SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume)
    602};
    603
    604static struct platform_driver img_i2s_in_driver = {
    605	.driver = {
    606		.name = "img-i2s-in",
    607		.of_match_table = img_i2s_in_of_match,
    608		.pm = &img_i2s_in_pm_ops
    609	},
    610	.probe = img_i2s_in_probe,
    611	.remove = img_i2s_in_dev_remove
    612};
    613module_platform_driver(img_i2s_in_driver);
    614
    615MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
    616MODULE_DESCRIPTION("IMG I2S Input Driver");
    617MODULE_LICENSE("GPL v2");