1 /* 2 * IMG I2S output controller driver 3 * 4 * Copyright (C) 2015 Imagination Technologies Ltd. 5 * 6 * Author: Damien Horsley <Damien.Horsley@imgtec.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2, as published by the Free Software Foundation. 11 */ 12 13 #include <linux/clk.h> 14 #include <linux/init.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/pm_runtime.h> 20 #include <linux/reset.h> 21 22 #include <sound/core.h> 23 #include <sound/dmaengine_pcm.h> 24 #include <sound/initval.h> 25 #include <sound/pcm.h> 26 #include <sound/pcm_params.h> 27 #include <sound/soc.h> 28 29 #define IMG_I2S_OUT_TX_FIFO 0x0 30 31 #define IMG_I2S_OUT_CTL 0x4 32 #define IMG_I2S_OUT_CTL_DATA_EN_MASK BIT(24) 33 #define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK 0xffe000 34 #define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT 13 35 #define IMG_I2S_OUT_CTL_FRM_SIZE_MASK BIT(8) 36 #define IMG_I2S_OUT_CTL_MASTER_MASK BIT(6) 37 #define IMG_I2S_OUT_CTL_CLK_MASK BIT(5) 38 #define IMG_I2S_OUT_CTL_CLK_EN_MASK BIT(4) 39 #define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK BIT(3) 40 #define IMG_I2S_OUT_CTL_BCLK_POL_MASK BIT(2) 41 #define IMG_I2S_OUT_CTL_ME_MASK BIT(0) 42 43 #define IMG_I2S_OUT_CH_CTL 0x4 44 #define IMG_I2S_OUT_CHAN_CTL_CH_MASK BIT(11) 45 #define IMG_I2S_OUT_CHAN_CTL_LT_MASK BIT(10) 46 #define IMG_I2S_OUT_CHAN_CTL_FMT_MASK 0xf0 47 #define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT 4 48 #define IMG_I2S_OUT_CHAN_CTL_JUST_MASK BIT(3) 49 #define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK BIT(1) 50 #define IMG_I2S_OUT_CHAN_CTL_ME_MASK BIT(0) 51 52 #define IMG_I2S_OUT_CH_STRIDE 0x20 53 54 struct img_i2s_out { 55 void __iomem *base; 56 struct clk *clk_sys; 57 struct clk *clk_ref; 58 struct snd_dmaengine_dai_dma_data dma_data; 59 struct device *dev; 60 unsigned int max_i2s_chan; 61 void __iomem *channel_base; 62 bool force_clk_active; 63 unsigned int active_channels; 64 struct reset_control *rst; 65 struct snd_soc_dai_driver dai_driver; 66 u32 suspend_ctl; 67 u32 *suspend_ch_ctl; 68 }; 69 70 static int img_i2s_out_runtime_suspend(struct device *dev) 71 { 72 struct img_i2s_out *i2s = dev_get_drvdata(dev); 73 74 clk_disable_unprepare(i2s->clk_ref); 75 clk_disable_unprepare(i2s->clk_sys); 76 77 return 0; 78 } 79 80 static int img_i2s_out_runtime_resume(struct device *dev) 81 { 82 struct img_i2s_out *i2s = dev_get_drvdata(dev); 83 int ret; 84 85 ret = clk_prepare_enable(i2s->clk_sys); 86 if (ret) { 87 dev_err(dev, "clk_enable failed: %d\n", ret); 88 return ret; 89 } 90 91 ret = clk_prepare_enable(i2s->clk_ref); 92 if (ret) { 93 dev_err(dev, "clk_enable failed: %d\n", ret); 94 clk_disable_unprepare(i2s->clk_sys); 95 return ret; 96 } 97 98 return 0; 99 } 100 101 static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val, 102 u32 reg) 103 { 104 writel(val, i2s->base + reg); 105 } 106 107 static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg) 108 { 109 return readl(i2s->base + reg); 110 } 111 112 static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s, 113 u32 chan, u32 val, u32 reg) 114 { 115 writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); 116 } 117 118 static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan, 119 u32 reg) 120 { 121 return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); 122 } 123 124 static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan) 125 { 126 u32 reg; 127 128 reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); 129 reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; 130 img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); 131 } 132 133 static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan) 134 { 135 u32 reg; 136 137 reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); 138 reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK; 139 img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); 140 } 141 142 static inline void img_i2s_out_disable(struct img_i2s_out *i2s) 143 { 144 u32 reg; 145 146 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 147 reg &= ~IMG_I2S_OUT_CTL_ME_MASK; 148 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 149 } 150 151 static inline void img_i2s_out_enable(struct img_i2s_out *i2s) 152 { 153 u32 reg; 154 155 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 156 reg |= IMG_I2S_OUT_CTL_ME_MASK; 157 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 158 } 159 160 static void img_i2s_out_reset(struct img_i2s_out *i2s) 161 { 162 int i; 163 u32 core_ctl, chan_ctl; 164 165 core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) & 166 ~IMG_I2S_OUT_CTL_ME_MASK & 167 ~IMG_I2S_OUT_CTL_DATA_EN_MASK; 168 169 if (!i2s->force_clk_active) 170 core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK; 171 172 chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) & 173 ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; 174 175 reset_control_assert(i2s->rst); 176 reset_control_deassert(i2s->rst); 177 178 for (i = 0; i < i2s->max_i2s_chan; i++) 179 img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL); 180 181 for (i = 0; i < i2s->active_channels; i++) 182 img_i2s_out_ch_enable(i2s, i); 183 184 img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL); 185 img_i2s_out_enable(i2s); 186 } 187 188 static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd, 189 struct snd_soc_dai *dai) 190 { 191 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 192 u32 reg; 193 194 switch (cmd) { 195 case SNDRV_PCM_TRIGGER_START: 196 case SNDRV_PCM_TRIGGER_RESUME: 197 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 198 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 199 if (!i2s->force_clk_active) 200 reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK; 201 reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK; 202 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 203 break; 204 case SNDRV_PCM_TRIGGER_STOP: 205 case SNDRV_PCM_TRIGGER_SUSPEND: 206 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 207 img_i2s_out_reset(i2s); 208 break; 209 default: 210 return -EINVAL; 211 } 212 213 return 0; 214 } 215 216 static int img_i2s_out_hw_params(struct snd_pcm_substream *substream, 217 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 218 { 219 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 220 unsigned int channels, i2s_channels; 221 long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate; 222 int i; 223 u32 reg, control_mask, control_set = 0; 224 snd_pcm_format_t format; 225 226 rate = params_rate(params); 227 format = params_format(params); 228 channels = params_channels(params); 229 i2s_channels = channels / 2; 230 231 if (format != SNDRV_PCM_FORMAT_S32_LE) 232 return -EINVAL; 233 234 if ((channels < 2) || 235 (channels > (i2s->max_i2s_chan * 2)) || 236 (channels % 2)) 237 return -EINVAL; 238 239 pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256); 240 if (pre_div_a < 0) 241 return pre_div_a; 242 pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384); 243 if (pre_div_b < 0) 244 return pre_div_b; 245 246 diff_a = abs((pre_div_a / 256) - rate); 247 diff_b = abs((pre_div_b / 384) - rate); 248 249 /* If diffs are equal, use lower clock rate */ 250 if (diff_a > diff_b) 251 clk_set_rate(i2s->clk_ref, pre_div_b); 252 else 253 clk_set_rate(i2s->clk_ref, pre_div_a); 254 255 /* 256 * Another driver (eg alsa machine driver) may have rejected the above 257 * change. Get the current rate and set the register bit according to 258 * the new minimum diff 259 */ 260 clk_rate = clk_get_rate(i2s->clk_ref); 261 262 diff_a = abs((clk_rate / 256) - rate); 263 diff_b = abs((clk_rate / 384) - rate); 264 265 if (diff_a > diff_b) 266 control_set |= IMG_I2S_OUT_CTL_CLK_MASK; 267 268 control_set |= ((i2s_channels - 1) << 269 IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) & 270 IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; 271 272 control_mask = IMG_I2S_OUT_CTL_CLK_MASK | 273 IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; 274 275 img_i2s_out_disable(i2s); 276 277 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 278 reg = (reg & ~control_mask) | control_set; 279 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 280 281 for (i = 0; i < i2s_channels; i++) 282 img_i2s_out_ch_enable(i2s, i); 283 284 for (; i < i2s->max_i2s_chan; i++) 285 img_i2s_out_ch_disable(i2s, i); 286 287 img_i2s_out_enable(i2s); 288 289 i2s->active_channels = i2s_channels; 290 291 return 0; 292 } 293 294 static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 295 { 296 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 297 int i, ret; 298 bool force_clk_active; 299 u32 chan_control_mask, control_mask, chan_control_set = 0; 300 u32 reg, control_set = 0; 301 302 force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) == 303 SND_SOC_DAIFMT_CONT); 304 305 if (force_clk_active) 306 control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK; 307 308 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 309 case SND_SOC_DAIFMT_CBM_CFM: 310 break; 311 case SND_SOC_DAIFMT_CBS_CFS: 312 control_set |= IMG_I2S_OUT_CTL_MASTER_MASK; 313 break; 314 default: 315 return -EINVAL; 316 } 317 318 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 319 case SND_SOC_DAIFMT_NB_NF: 320 control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; 321 break; 322 case SND_SOC_DAIFMT_NB_IF: 323 control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; 324 control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; 325 break; 326 case SND_SOC_DAIFMT_IB_NF: 327 break; 328 case SND_SOC_DAIFMT_IB_IF: 329 control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; 330 break; 331 default: 332 return -EINVAL; 333 } 334 335 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 336 case SND_SOC_DAIFMT_I2S: 337 chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; 338 break; 339 case SND_SOC_DAIFMT_LEFT_J: 340 break; 341 default: 342 return -EINVAL; 343 } 344 345 control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK | 346 IMG_I2S_OUT_CTL_MASTER_MASK | 347 IMG_I2S_OUT_CTL_BCLK_POL_MASK | 348 IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; 349 350 chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; 351 352 ret = pm_runtime_get_sync(i2s->dev); 353 if (ret < 0) 354 return ret; 355 356 img_i2s_out_disable(i2s); 357 358 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 359 reg = (reg & ~control_mask) | control_set; 360 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 361 362 for (i = 0; i < i2s->active_channels; i++) 363 img_i2s_out_ch_disable(i2s, i); 364 365 for (i = 0; i < i2s->max_i2s_chan; i++) { 366 reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); 367 reg = (reg & ~chan_control_mask) | chan_control_set; 368 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); 369 } 370 371 for (i = 0; i < i2s->active_channels; i++) 372 img_i2s_out_ch_enable(i2s, i); 373 374 img_i2s_out_enable(i2s); 375 pm_runtime_put(i2s->dev); 376 377 i2s->force_clk_active = force_clk_active; 378 379 return 0; 380 } 381 382 static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { 383 .trigger = img_i2s_out_trigger, 384 .hw_params = img_i2s_out_hw_params, 385 .set_fmt = img_i2s_out_set_fmt 386 }; 387 388 static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) 389 { 390 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 391 392 snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL); 393 394 return 0; 395 } 396 397 static const struct snd_soc_component_driver img_i2s_out_component = { 398 .name = "img-i2s-out" 399 }; 400 401 static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st, 402 struct snd_pcm_hw_params *params, struct dma_slave_config *sc) 403 { 404 unsigned int i2s_channels = params_channels(params) / 2; 405 struct snd_soc_pcm_runtime *rtd = st->private_data; 406 struct snd_dmaengine_dai_dma_data *dma_data; 407 int ret; 408 409 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); 410 411 ret = snd_hwparams_to_dma_slave_config(st, params, sc); 412 if (ret) 413 return ret; 414 415 sc->dst_addr = dma_data->addr; 416 sc->dst_addr_width = dma_data->addr_width; 417 sc->dst_maxburst = 4 * i2s_channels; 418 419 return 0; 420 } 421 422 static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = { 423 .prepare_slave_config = img_i2s_out_dma_prepare_slave_config 424 }; 425 426 static int img_i2s_out_probe(struct platform_device *pdev) 427 { 428 struct img_i2s_out *i2s; 429 struct resource *res; 430 void __iomem *base; 431 int i, ret; 432 unsigned int max_i2s_chan_pow_2; 433 u32 reg; 434 struct device *dev = &pdev->dev; 435 436 i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 437 if (!i2s) 438 return -ENOMEM; 439 440 platform_set_drvdata(pdev, i2s); 441 442 i2s->dev = &pdev->dev; 443 444 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 445 base = devm_ioremap_resource(&pdev->dev, res); 446 if (IS_ERR(base)) 447 return PTR_ERR(base); 448 449 i2s->base = base; 450 451 if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", 452 &i2s->max_i2s_chan)) { 453 dev_err(&pdev->dev, "No img,i2s-channels property\n"); 454 return -EINVAL; 455 } 456 457 max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); 458 459 i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); 460 461 i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst"); 462 if (IS_ERR(i2s->rst)) { 463 if (PTR_ERR(i2s->rst) != -EPROBE_DEFER) 464 dev_err(&pdev->dev, "No top level reset found\n"); 465 return PTR_ERR(i2s->rst); 466 } 467 468 i2s->clk_sys = devm_clk_get(&pdev->dev, "sys"); 469 if (IS_ERR(i2s->clk_sys)) { 470 if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) 471 dev_err(dev, "Failed to acquire clock 'sys'\n"); 472 return PTR_ERR(i2s->clk_sys); 473 } 474 475 i2s->clk_ref = devm_clk_get(&pdev->dev, "ref"); 476 if (IS_ERR(i2s->clk_ref)) { 477 if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER) 478 dev_err(dev, "Failed to acquire clock 'ref'\n"); 479 return PTR_ERR(i2s->clk_ref); 480 } 481 482 i2s->suspend_ch_ctl = devm_kzalloc(dev, 483 sizeof(*i2s->suspend_ch_ctl) * i2s->max_i2s_chan, GFP_KERNEL); 484 if (!i2s->suspend_ch_ctl) 485 return -ENOMEM; 486 487 pm_runtime_enable(&pdev->dev); 488 if (!pm_runtime_enabled(&pdev->dev)) { 489 ret = img_i2s_out_runtime_resume(&pdev->dev); 490 if (ret) 491 goto err_pm_disable; 492 } 493 ret = pm_runtime_get_sync(&pdev->dev); 494 if (ret < 0) 495 goto err_suspend; 496 497 reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK; 498 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 499 500 reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK | 501 IMG_I2S_OUT_CHAN_CTL_LT_MASK | 502 IMG_I2S_OUT_CHAN_CTL_CH_MASK | 503 (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT); 504 505 for (i = 0; i < i2s->max_i2s_chan; i++) 506 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); 507 508 img_i2s_out_reset(i2s); 509 pm_runtime_put(&pdev->dev); 510 511 i2s->active_channels = 1; 512 i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO; 513 i2s->dma_data.addr_width = 4; 514 i2s->dma_data.maxburst = 4; 515 516 i2s->dai_driver.probe = img_i2s_out_dai_probe; 517 i2s->dai_driver.playback.channels_min = 2; 518 i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; 519 i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; 520 i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE; 521 i2s->dai_driver.ops = &img_i2s_out_dai_ops; 522 523 ret = devm_snd_soc_register_component(&pdev->dev, 524 &img_i2s_out_component, &i2s->dai_driver, 1); 525 if (ret) 526 goto err_suspend; 527 528 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, 529 &img_i2s_out_dma_config, 0); 530 if (ret) 531 goto err_suspend; 532 533 return 0; 534 535 err_suspend: 536 if (!pm_runtime_status_suspended(&pdev->dev)) 537 img_i2s_out_runtime_suspend(&pdev->dev); 538 err_pm_disable: 539 pm_runtime_disable(&pdev->dev); 540 541 return ret; 542 } 543 544 static int img_i2s_out_dev_remove(struct platform_device *pdev) 545 { 546 pm_runtime_disable(&pdev->dev); 547 if (!pm_runtime_status_suspended(&pdev->dev)) 548 img_i2s_out_runtime_suspend(&pdev->dev); 549 550 return 0; 551 } 552 553 #ifdef CONFIG_PM_SLEEP 554 static int img_i2s_out_suspend(struct device *dev) 555 { 556 struct img_i2s_out *i2s = dev_get_drvdata(dev); 557 int i, ret; 558 u32 reg; 559 560 if (pm_runtime_status_suspended(dev)) { 561 ret = img_i2s_out_runtime_resume(dev); 562 if (ret) 563 return ret; 564 } 565 566 for (i = 0; i < i2s->max_i2s_chan; i++) { 567 reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); 568 i2s->suspend_ch_ctl[i] = reg; 569 } 570 571 i2s->suspend_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 572 573 img_i2s_out_runtime_suspend(dev); 574 575 return 0; 576 } 577 578 static int img_i2s_out_resume(struct device *dev) 579 { 580 struct img_i2s_out *i2s = dev_get_drvdata(dev); 581 int i, ret; 582 u32 reg; 583 584 ret = img_i2s_out_runtime_resume(dev); 585 if (ret) 586 return ret; 587 588 for (i = 0; i < i2s->max_i2s_chan; i++) { 589 reg = i2s->suspend_ch_ctl[i]; 590 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); 591 } 592 593 img_i2s_out_writel(i2s, i2s->suspend_ctl, IMG_I2S_OUT_CTL); 594 595 if (pm_runtime_status_suspended(dev)) 596 img_i2s_out_runtime_suspend(dev); 597 598 return 0; 599 } 600 #endif 601 602 static const struct of_device_id img_i2s_out_of_match[] = { 603 { .compatible = "img,i2s-out" }, 604 {} 605 }; 606 MODULE_DEVICE_TABLE(of, img_i2s_out_of_match); 607 608 static const struct dev_pm_ops img_i2s_out_pm_ops = { 609 SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend, 610 img_i2s_out_runtime_resume, NULL) 611 SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume) 612 }; 613 614 static struct platform_driver img_i2s_out_driver = { 615 .driver = { 616 .name = "img-i2s-out", 617 .of_match_table = img_i2s_out_of_match, 618 .pm = &img_i2s_out_pm_ops 619 }, 620 .probe = img_i2s_out_probe, 621 .remove = img_i2s_out_dev_remove 622 }; 623 module_platform_driver(img_i2s_out_driver); 624 625 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 626 MODULE_DESCRIPTION("IMG I2S Output Driver"); 627 MODULE_LICENSE("GPL v2"); 628