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                pm_runtime_put_noidle(i2s->dev);
 348                return ret;
 349        }
 350
 351        for (i = 0; i < i2s->active_channels; i++)
 352                img_i2s_in_ch_disable(i2s, i);
 353
 354        /*
 355         * BLKP and LRD must be set during separate register writes
 356         */
 357        for (i = 0; i < i2s->max_i2s_chan; i++) {
 358                reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
 359                reg = (reg & ~chan_control_mask) | chan_control_set;
 360                img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
 361                reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set;
 362                img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
 363                reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set;
 364                img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
 365        }
 366
 367        for (i = 0; i < i2s->active_channels; i++)
 368                img_i2s_in_ch_enable(i2s, i);
 369
 370        pm_runtime_put(i2s->dev);
 371
 372        return 0;
 373}
 374
 375static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
 376        .trigger = img_i2s_in_trigger,
 377        .hw_params = img_i2s_in_hw_params,
 378        .set_fmt = img_i2s_in_set_fmt
 379};
 380
 381static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
 382{
 383        struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
 384
 385        snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data);
 386
 387        return 0;
 388}
 389
 390static const struct snd_soc_component_driver img_i2s_in_component = {
 391        .name = "img-i2s-in"
 392};
 393
 394static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
 395        struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
 396{
 397        unsigned int i2s_channels = params_channels(params) / 2;
 398        struct snd_soc_pcm_runtime *rtd = st->private_data;
 399        struct snd_dmaengine_dai_dma_data *dma_data;
 400        int ret;
 401
 402        dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), st);
 403
 404        ret = snd_hwparams_to_dma_slave_config(st, params, sc);
 405        if (ret)
 406                return ret;
 407
 408        sc->src_addr = dma_data->addr;
 409        sc->src_addr_width = dma_data->addr_width;
 410        sc->src_maxburst = 4 * i2s_channels;
 411
 412        return 0;
 413}
 414
 415static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
 416        .prepare_slave_config = img_i2s_in_dma_prepare_slave_config
 417};
 418
 419static int img_i2s_in_probe(struct platform_device *pdev)
 420{
 421        struct img_i2s_in *i2s;
 422        struct resource *res;
 423        void __iomem *base;
 424        int ret, i;
 425        struct reset_control *rst;
 426        unsigned int max_i2s_chan_pow_2;
 427        struct device *dev = &pdev->dev;
 428
 429        i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
 430        if (!i2s)
 431                return -ENOMEM;
 432
 433        platform_set_drvdata(pdev, i2s);
 434
 435        i2s->dev = dev;
 436
 437        base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 438        if (IS_ERR(base))
 439                return PTR_ERR(base);
 440
 441        i2s->base = base;
 442
 443        if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
 444                        &i2s->max_i2s_chan)) {
 445                dev_err(dev, "No img,i2s-channels property\n");
 446                return -EINVAL;
 447        }
 448
 449        max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
 450
 451        i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
 452
 453        i2s->clk_sys = devm_clk_get(dev, "sys");
 454        if (IS_ERR(i2s->clk_sys)) {
 455                if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
 456                        dev_err(dev, "Failed to acquire clock 'sys'\n");
 457                return PTR_ERR(i2s->clk_sys);
 458        }
 459
 460        pm_runtime_enable(&pdev->dev);
 461        if (!pm_runtime_enabled(&pdev->dev)) {
 462                ret = img_i2s_in_runtime_resume(&pdev->dev);
 463                if (ret)
 464                        goto err_pm_disable;
 465        }
 466        ret = pm_runtime_resume_and_get(&pdev->dev);
 467        if (ret < 0)
 468                goto err_suspend;
 469
 470        i2s->active_channels = 1;
 471        i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
 472        i2s->dma_data.addr_width = 4;
 473
 474        i2s->dai_driver.probe = img_i2s_in_dai_probe;
 475        i2s->dai_driver.capture.channels_min = 2;
 476        i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
 477        i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
 478        i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
 479                SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
 480        i2s->dai_driver.ops = &img_i2s_in_dai_ops;
 481
 482        rst = devm_reset_control_get_exclusive(dev, "rst");
 483        if (IS_ERR(rst)) {
 484                if (PTR_ERR(rst) == -EPROBE_DEFER) {
 485                        ret = -EPROBE_DEFER;
 486                        pm_runtime_put(&pdev->dev);
 487                        goto err_suspend;
 488                }
 489
 490                dev_dbg(dev, "No top level reset found\n");
 491
 492                img_i2s_in_disable(i2s);
 493
 494                for (i = 0; i < i2s->max_i2s_chan; i++)
 495                        img_i2s_in_ch_disable(i2s, i);
 496        } else {
 497                reset_control_assert(rst);
 498                reset_control_deassert(rst);
 499        }
 500
 501        img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
 502
 503        for (i = 0; i < i2s->max_i2s_chan; i++)
 504                img_i2s_in_ch_writel(i2s, i,
 505                        (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
 506                        IMG_I2S_IN_CH_CTL_JUST_MASK |
 507                        IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
 508
 509        pm_runtime_put(&pdev->dev);
 510
 511        i2s->suspend_ch_ctl = devm_kcalloc(dev,
 512                i2s->max_i2s_chan, sizeof(*i2s->suspend_ch_ctl), GFP_KERNEL);
 513        if (!i2s->suspend_ch_ctl) {
 514                ret = -ENOMEM;
 515                goto err_suspend;
 516        }
 517
 518        ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
 519                                                &i2s->dai_driver, 1);
 520        if (ret)
 521                goto err_suspend;
 522
 523        ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
 524        if (ret)
 525                goto err_suspend;
 526
 527        return 0;
 528
 529err_suspend:
 530        if (!pm_runtime_enabled(&pdev->dev))
 531                img_i2s_in_runtime_suspend(&pdev->dev);
 532err_pm_disable:
 533        pm_runtime_disable(&pdev->dev);
 534
 535        return ret;
 536}
 537
 538static int img_i2s_in_dev_remove(struct platform_device *pdev)
 539{
 540        pm_runtime_disable(&pdev->dev);
 541        if (!pm_runtime_status_suspended(&pdev->dev))
 542                img_i2s_in_runtime_suspend(&pdev->dev);
 543
 544        return 0;
 545}
 546
 547#ifdef CONFIG_PM_SLEEP
 548static int img_i2s_in_suspend(struct device *dev)
 549{
 550        struct img_i2s_in *i2s = dev_get_drvdata(dev);
 551        int i, ret;
 552        u32 reg;
 553
 554        if (pm_runtime_status_suspended(dev)) {
 555                ret = img_i2s_in_runtime_resume(dev);
 556                if (ret)
 557                        return ret;
 558        }
 559
 560        for (i = 0; i < i2s->max_i2s_chan; i++) {
 561                reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
 562                i2s->suspend_ch_ctl[i] = reg;
 563        }
 564
 565        i2s->suspend_ctl = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
 566
 567        img_i2s_in_runtime_suspend(dev);
 568
 569        return 0;
 570}
 571
 572static int img_i2s_in_resume(struct device *dev)
 573{
 574        struct img_i2s_in *i2s = dev_get_drvdata(dev);
 575        int i, ret;
 576        u32 reg;
 577
 578        ret = img_i2s_in_runtime_resume(dev);
 579        if (ret)
 580                return ret;
 581
 582        for (i = 0; i < i2s->max_i2s_chan; i++) {
 583                reg = i2s->suspend_ch_ctl[i];
 584                img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
 585        }
 586
 587        img_i2s_in_writel(i2s, i2s->suspend_ctl, IMG_I2S_IN_CTL);
 588
 589        if (pm_runtime_status_suspended(dev))
 590                img_i2s_in_runtime_suspend(dev);
 591
 592        return 0;
 593}
 594#endif
 595
 596static const struct of_device_id img_i2s_in_of_match[] = {
 597        { .compatible = "img,i2s-in" },
 598        {}
 599};
 600MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
 601
 602static const struct dev_pm_ops img_i2s_in_pm_ops = {
 603        SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend,
 604                           img_i2s_in_runtime_resume, NULL)
 605        SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume)
 606};
 607
 608static struct platform_driver img_i2s_in_driver = {
 609        .driver = {
 610                .name = "img-i2s-in",
 611                .of_match_table = img_i2s_in_of_match,
 612                .pm = &img_i2s_in_pm_ops
 613        },
 614        .probe = img_i2s_in_probe,
 615        .remove = img_i2s_in_dev_remove
 616};
 617module_platform_driver(img_i2s_in_driver);
 618
 619MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
 620MODULE_DESCRIPTION("IMG I2S Input Driver");
 621MODULE_LICENSE("GPL v2");
 622