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