Linux 6.7-rc7
[linux-modified.git] / sound / soc / img / img-i2s-out.c
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 int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
380 {
381         struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
382
383         snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL);
384
385         return 0;
386 }
387
388 static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
389         .probe          = img_i2s_out_dai_probe,
390         .trigger        = img_i2s_out_trigger,
391         .hw_params      = img_i2s_out_hw_params,
392         .set_fmt        = img_i2s_out_set_fmt
393 };
394
395 static const struct snd_soc_component_driver img_i2s_out_component = {
396         .name = "img-i2s-out",
397         .legacy_dai_naming = 1,
398 };
399
400 static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st,
401         struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
402 {
403         unsigned int i2s_channels = params_channels(params) / 2;
404         struct snd_soc_pcm_runtime *rtd = st->private_data;
405         struct snd_dmaengine_dai_dma_data *dma_data;
406         int ret;
407
408         dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), st);
409
410         ret = snd_hwparams_to_dma_slave_config(st, params, sc);
411         if (ret)
412                 return ret;
413
414         sc->dst_addr = dma_data->addr;
415         sc->dst_addr_width = dma_data->addr_width;
416         sc->dst_maxburst = 4 * i2s_channels;
417
418         return 0;
419 }
420
421 static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = {
422         .prepare_slave_config = img_i2s_out_dma_prepare_slave_config
423 };
424
425 static int img_i2s_out_probe(struct platform_device *pdev)
426 {
427         struct img_i2s_out *i2s;
428         struct resource *res;
429         void __iomem *base;
430         int i, ret;
431         unsigned int max_i2s_chan_pow_2;
432         u32 reg;
433         struct device *dev = &pdev->dev;
434
435         i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
436         if (!i2s)
437                 return -ENOMEM;
438
439         platform_set_drvdata(pdev, i2s);
440
441         i2s->dev = &pdev->dev;
442
443         base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
444         if (IS_ERR(base))
445                 return PTR_ERR(base);
446
447         i2s->base = base;
448
449         if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
450                         &i2s->max_i2s_chan)) {
451                 dev_err(&pdev->dev, "No img,i2s-channels property\n");
452                 return -EINVAL;
453         }
454
455         max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
456
457         i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
458
459         i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
460         if (IS_ERR(i2s->rst))
461                 return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst),
462                                      "No top level reset found\n");
463
464         i2s->clk_sys = devm_clk_get(&pdev->dev, "sys");
465         if (IS_ERR(i2s->clk_sys))
466                 return dev_err_probe(dev, PTR_ERR(i2s->clk_sys),
467                                      "Failed to acquire clock 'sys'\n");
468
469         i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
470         if (IS_ERR(i2s->clk_ref))
471                 return dev_err_probe(dev, PTR_ERR(i2s->clk_ref),
472                                      "Failed to acquire clock 'ref'\n");
473
474         i2s->suspend_ch_ctl = devm_kcalloc(dev,
475                 i2s->max_i2s_chan, sizeof(*i2s->suspend_ch_ctl), GFP_KERNEL);
476         if (!i2s->suspend_ch_ctl)
477                 return -ENOMEM;
478
479         pm_runtime_enable(&pdev->dev);
480         if (!pm_runtime_enabled(&pdev->dev)) {
481                 ret = img_i2s_out_runtime_resume(&pdev->dev);
482                 if (ret)
483                         goto err_pm_disable;
484         }
485         ret = pm_runtime_resume_and_get(&pdev->dev);
486         if (ret < 0)
487                 goto err_suspend;
488
489         reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
490         img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
491
492         reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK |
493                 IMG_I2S_OUT_CHAN_CTL_LT_MASK |
494                 IMG_I2S_OUT_CHAN_CTL_CH_MASK |
495                 (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT);
496
497         for (i = 0; i < i2s->max_i2s_chan; i++)
498                 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
499
500         img_i2s_out_reset(i2s);
501         pm_runtime_put(&pdev->dev);
502
503         i2s->active_channels = 1;
504         i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
505         i2s->dma_data.addr_width = 4;
506         i2s->dma_data.maxburst = 4;
507
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 void 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
542 #ifdef CONFIG_PM_SLEEP
543 static int img_i2s_out_suspend(struct device *dev)
544 {
545         struct img_i2s_out *i2s = dev_get_drvdata(dev);
546         int i, ret;
547         u32 reg;
548
549         if (pm_runtime_status_suspended(dev)) {
550                 ret = img_i2s_out_runtime_resume(dev);
551                 if (ret)
552                         return ret;
553         }
554
555         for (i = 0; i < i2s->max_i2s_chan; i++) {
556                 reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL);
557                 i2s->suspend_ch_ctl[i] = reg;
558         }
559
560         i2s->suspend_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
561
562         img_i2s_out_runtime_suspend(dev);
563
564         return 0;
565 }
566
567 static int img_i2s_out_resume(struct device *dev)
568 {
569         struct img_i2s_out *i2s = dev_get_drvdata(dev);
570         int i, ret;
571         u32 reg;
572
573         ret = img_i2s_out_runtime_resume(dev);
574         if (ret)
575                 return ret;
576
577         for (i = 0; i < i2s->max_i2s_chan; i++) {
578                 reg = i2s->suspend_ch_ctl[i];
579                 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
580         }
581
582         img_i2s_out_writel(i2s, i2s->suspend_ctl, IMG_I2S_OUT_CTL);
583
584         if (pm_runtime_status_suspended(dev))
585                 img_i2s_out_runtime_suspend(dev);
586
587         return 0;
588 }
589 #endif
590
591 static const struct of_device_id img_i2s_out_of_match[] = {
592         { .compatible = "img,i2s-out" },
593         {}
594 };
595 MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
596
597 static const struct dev_pm_ops img_i2s_out_pm_ops = {
598         SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend,
599                            img_i2s_out_runtime_resume, NULL)
600         SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume)
601 };
602
603 static struct platform_driver img_i2s_out_driver = {
604         .driver = {
605                 .name = "img-i2s-out",
606                 .of_match_table = img_i2s_out_of_match,
607                 .pm = &img_i2s_out_pm_ops
608         },
609         .probe = img_i2s_out_probe,
610         .remove_new = img_i2s_out_dev_remove
611 };
612 module_platform_driver(img_i2s_out_driver);
613
614 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
615 MODULE_DESCRIPTION("IMG I2S Output Driver");
616 MODULE_LICENSE("GPL v2");