linux/sound/soc/img/img-i2s-in.c
<<
>>
Prefs
   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_get_sync(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(rtd->cpu_dai, 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        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 436        base = devm_ioremap_resource(dev, res);
 437        if (IS_ERR(base))
 438                return PTR_ERR(base);
 439
 440        i2s->base = base;
 441
 442        if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
 443                        &i2s->max_i2s_chan)) {
 444                dev_err(dev, "No img,i2s-channels property\n");
 445                return -EINVAL;
 446        }
 447
 448        max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
 449
 450        i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
 451
 452        i2s->clk_sys = devm_clk_get(dev, "sys");
 453        if (IS_ERR(i2s->clk_sys)) {
 454                if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
 455                        dev_err(dev, "Failed to acquire clock 'sys'\n");
 456                return PTR_ERR(i2s->clk_sys);
 457        }
 458
 459        pm_runtime_enable(&pdev->dev);
 460        if (!pm_runtime_enabled(&pdev->dev)) {
 461                ret = img_i2s_in_runtime_resume(&pdev->dev);
 462                if (ret)
 463                        goto err_pm_disable;
 464        }
 465        ret = pm_runtime_get_sync(&pdev->dev);
 466        if (ret < 0)
 467                goto err_suspend;
 468
 469        i2s->active_channels = 1;
 470        i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
 471        i2s->dma_data.addr_width = 4;
 472
 473        i2s->dai_driver.probe = img_i2s_in_dai_probe;
 474        i2s->dai_driver.capture.channels_min = 2;
 475        i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
 476        i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
 477        i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
 478                SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
 479        i2s->dai_driver.ops = &img_i2s_in_dai_ops;
 480
 481        rst = devm_reset_control_get_exclusive(dev, "rst");
 482        if (IS_ERR(rst)) {
 483                if (PTR_ERR(rst) == -EPROBE_DEFER) {
 484                        ret = -EPROBE_DEFER;
 485                        goto err_suspend;
 486                }
 487
 488                dev_dbg(dev, "No top level reset found\n");
 489
 490                img_i2s_in_disable(i2s);
 491
 492                for (i = 0; i < i2s->max_i2s_chan; i++)
 493                        img_i2s_in_ch_disable(i2s, i);
 494        } else {
 495                reset_control_assert(rst);
 496                reset_control_deassert(rst);
 497        }
 498
 499        img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
 500
 501        for (i = 0; i < i2s->max_i2s_chan; i++)
 502                img_i2s_in_ch_writel(i2s, i,
 503                        (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
 504                        IMG_I2S_IN_CH_CTL_JUST_MASK |
 505                        IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
 506
 507        pm_runtime_put(&pdev->dev);
 508
 509        i2s->suspend_ch_ctl = devm_kcalloc(dev,
 510                i2s->max_i2s_chan, sizeof(*i2s->suspend_ch_ctl), GFP_KERNEL);
 511        if (!i2s->suspend_ch_ctl) {
 512                ret = -ENOMEM;
 513                goto err_suspend;
 514        }
 515
 516        ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
 517                                                &i2s->dai_driver, 1);
 518        if (ret)
 519                goto err_suspend;
 520
 521        ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
 522        if (ret)
 523                goto err_suspend;
 524
 525        return 0;
 526
 527err_suspend:
 528        if (!pm_runtime_enabled(&pdev->dev))
 529                img_i2s_in_runtime_suspend(&pdev->dev);
 530err_pm_disable:
 531        pm_runtime_disable(&pdev->dev);
 532
 533        return ret;
 534}
 535
 536static int img_i2s_in_dev_remove(struct platform_device *pdev)
 537{
 538        pm_runtime_disable(&pdev->dev);
 539        if (!pm_runtime_status_suspended(&pdev->dev))
 540                img_i2s_in_runtime_suspend(&pdev->dev);
 541
 542        return 0;
 543}
 544
 545#ifdef CONFIG_PM_SLEEP
 546static int img_i2s_in_suspend(struct device *dev)
 547{
 548        struct img_i2s_in *i2s = dev_get_drvdata(dev);
 549        int i, ret;
 550        u32 reg;
 551
 552        if (pm_runtime_status_suspended(dev)) {
 553                ret = img_i2s_in_runtime_resume(dev);
 554                if (ret)
 555                        return ret;
 556        }
 557
 558        for (i = 0; i < i2s->max_i2s_chan; i++) {
 559                reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
 560                i2s->suspend_ch_ctl[i] = reg;
 561        }
 562
 563        i2s->suspend_ctl = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
 564
 565        img_i2s_in_runtime_suspend(dev);
 566
 567        return 0;
 568}
 569
 570static int img_i2s_in_resume(struct device *dev)
 571{
 572        struct img_i2s_in *i2s = dev_get_drvdata(dev);
 573        int i, ret;
 574        u32 reg;
 575
 576        ret = img_i2s_in_runtime_resume(dev);
 577        if (ret)
 578                return ret;
 579
 580        for (i = 0; i < i2s->max_i2s_chan; i++) {
 581                reg = i2s->suspend_ch_ctl[i];
 582                img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
 583        }
 584
 585        img_i2s_in_writel(i2s, i2s->suspend_ctl, IMG_I2S_IN_CTL);
 586
 587        if (pm_runtime_status_suspended(dev))
 588                img_i2s_in_runtime_suspend(dev);
 589
 590        return 0;
 591}
 592#endif
 593
 594static const struct of_device_id img_i2s_in_of_match[] = {
 595        { .compatible = "img,i2s-in" },
 596        {}
 597};
 598MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
 599
 600static const struct dev_pm_ops img_i2s_in_pm_ops = {
 601        SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend,
 602                           img_i2s_in_runtime_resume, NULL)
 603        SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume)
 604};
 605
 606static struct platform_driver img_i2s_in_driver = {
 607        .driver = {
 608                .name = "img-i2s-in",
 609                .of_match_table = img_i2s_in_of_match,
 610                .pm = &img_i2s_in_pm_ops
 611        },
 612        .probe = img_i2s_in_probe,
 613        .remove = img_i2s_in_dev_remove
 614};
 615module_platform_driver(img_i2s_in_driver);
 616
 617MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
 618MODULE_DESCRIPTION("IMG I2S Input Driver");
 619MODULE_LICENSE("GPL v2");
 620