root/sound/soc/img/img-i2s-in.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. img_i2s_in_runtime_suspend
  2. img_i2s_in_runtime_resume
  3. img_i2s_in_writel
  4. img_i2s_in_readl
  5. img_i2s_in_ch_writel
  6. img_i2s_in_ch_readl
  7. img_i2s_in_ch_disable
  8. img_i2s_in_ch_enable
  9. img_i2s_in_disable
  10. img_i2s_in_enable
  11. img_i2s_in_flush
  12. img_i2s_in_trigger
  13. img_i2s_in_check_rate
  14. img_i2s_in_hw_params
  15. img_i2s_in_set_fmt
  16. img_i2s_in_dai_probe
  17. img_i2s_in_dma_prepare_slave_config
  18. img_i2s_in_probe
  19. img_i2s_in_dev_remove
  20. img_i2s_in_suspend
  21. img_i2s_in_resume

   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 
  52 struct 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 
  65 static 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 
  74 static 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 
  88 static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
  89 {
  90         writel(val, i2s->base + reg);
  91 }
  92 
  93 static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg)
  94 {
  95         return readl(i2s->base + reg);
  96 }
  97 
  98 static 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 
 104 static 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 
 110 static 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 
 119 static 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 
 128 static 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 
 137 static 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 
 146 static 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 
 160 static 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 
 184 static 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 
 214 static 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 
 302 static 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 
 373 static 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 
 379 static 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 
 388 static const struct snd_soc_component_driver img_i2s_in_component = {
 389         .name = "img-i2s-in"
 390 };
 391 
 392 static 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 
 413 static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
 414         .prepare_slave_config = img_i2s_in_dma_prepare_slave_config
 415 };
 416 
 417 static 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 
 527 err_suspend:
 528         if (!pm_runtime_enabled(&pdev->dev))
 529                 img_i2s_in_runtime_suspend(&pdev->dev);
 530 err_pm_disable:
 531         pm_runtime_disable(&pdev->dev);
 532 
 533         return ret;
 534 }
 535 
 536 static 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
 546 static 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 
 570 static 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 
 594 static const struct of_device_id img_i2s_in_of_match[] = {
 595         { .compatible = "img,i2s-in" },
 596         {}
 597 };
 598 MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
 599 
 600 static 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 
 606 static 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 };
 615 module_platform_driver(img_i2s_in_driver);
 616 
 617 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
 618 MODULE_DESCRIPTION("IMG I2S Input Driver");
 619 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */