2 * Copyright (C) 2012 Samsung Electronics Co.Ltd
4 * YoungJun Cho <yj44.cho@samsung.com>
5 * Eunchul Kim <chulspro.kim@samsung.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundationr
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/err.h>
15 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <linux/pm_runtime.h>
22 #include <drm/exynos_drm.h>
23 #include "regs-rotator.h"
24 #include "exynos_drm.h"
25 #include "exynos_drm_ipp.h"
28 * Rotator supports image crop/rotator and input/output DMA operations.
29 * input DMA reads image data from the memory.
30 * output DMA writes image data to memory.
32 * M2M operation : supports crop/scale/rotation/csc so on.
33 * Memory ----> Rotator H/W ----> Memory.
38 * 1. check suspend/resume api if needed.
39 * 2. need to check use case platform_device_id.
40 * 3. check src/dst size with, height.
41 * 4. need to add supported list in prop_list.
44 #define get_rot_context(dev) platform_get_drvdata(to_platform_device(dev))
45 #define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
46 struct rot_context, ippdrv);
47 #define rot_read(offset) readl(rot->regs + (offset))
48 #define rot_write(cfg, offset) writel(cfg, rot->regs + (offset))
51 ROT_IRQ_STATUS_COMPLETE
= 8,
52 ROT_IRQ_STATUS_ILLEGAL
= 9,
56 * A structure of limitation.
58 * @min_w: minimum width.
59 * @min_h: minimum height.
60 * @max_w: maximum width.
61 * @max_h: maximum height.
73 * A structure of limitation table.
75 * @ycbcr420_2p: case of YUV.
76 * @rgb888: case of RGB.
78 struct rot_limit_table
{
79 struct rot_limit ycbcr420_2p
;
80 struct rot_limit rgb888
;
84 * A structure of rotator context.
85 * @ippdrv: prepare initialization using ippdrv.
86 * @regs_res: register resources.
87 * @regs: memory mapped io registers.
88 * @clock: rotator gate clock.
89 * @limit_tbl: limitation of rotator.
91 * @cur_buf_id: current operation buffer id.
92 * @suspended: suspended state.
95 struct exynos_drm_ippdrv ippdrv
;
96 struct resource
*regs_res
;
99 struct rot_limit_table
*limit_tbl
;
101 int cur_buf_id
[EXYNOS_DRM_OPS_MAX
];
105 static void rotator_reg_set_irq(struct rot_context
*rot
, bool enable
)
107 u32 val
= rot_read(ROT_CONFIG
);
110 val
|= ROT_CONFIG_IRQ
;
112 val
&= ~ROT_CONFIG_IRQ
;
114 rot_write(val
, ROT_CONFIG
);
117 static u32
rotator_reg_get_fmt(struct rot_context
*rot
)
119 u32 val
= rot_read(ROT_CONTROL
);
121 val
&= ROT_CONTROL_FMT_MASK
;
126 static enum rot_irq_status
rotator_reg_get_irq_status(struct rot_context
*rot
)
128 u32 val
= rot_read(ROT_STATUS
);
130 val
= ROT_STATUS_IRQ(val
);
132 if (val
== ROT_STATUS_IRQ_VAL_COMPLETE
)
133 return ROT_IRQ_STATUS_COMPLETE
;
135 return ROT_IRQ_STATUS_ILLEGAL
;
138 static irqreturn_t
rotator_irq_handler(int irq
, void *arg
)
140 struct rot_context
*rot
= arg
;
141 struct exynos_drm_ippdrv
*ippdrv
= &rot
->ippdrv
;
142 struct drm_exynos_ipp_cmd_node
*c_node
= ippdrv
->c_node
;
143 struct drm_exynos_ipp_event_work
*event_work
= c_node
->event_work
;
144 enum rot_irq_status irq_status
;
147 /* Get execution result */
148 irq_status
= rotator_reg_get_irq_status(rot
);
151 val
= rot_read(ROT_STATUS
);
152 val
|= ROT_STATUS_IRQ_PENDING((u32
)irq_status
);
153 rot_write(val
, ROT_STATUS
);
155 if (irq_status
== ROT_IRQ_STATUS_COMPLETE
) {
156 event_work
->ippdrv
= ippdrv
;
157 event_work
->buf_id
[EXYNOS_DRM_OPS_DST
] =
158 rot
->cur_buf_id
[EXYNOS_DRM_OPS_DST
];
159 queue_work(ippdrv
->event_workq
,
160 (struct work_struct
*)event_work
);
162 DRM_ERROR("the SFR is set illegally\n");
167 static void rotator_align_size(struct rot_context
*rot
, u32 fmt
, u32
*hsize
,
170 struct rot_limit_table
*limit_tbl
= rot
->limit_tbl
;
171 struct rot_limit
*limit
;
175 if (fmt
== ROT_CONTROL_FMT_RGB888
)
176 limit
= &limit_tbl
->rgb888
;
178 limit
= &limit_tbl
->ycbcr420_2p
;
180 /* Get mask for rounding to nearest aligned val */
181 mask
= ~((1 << limit
->align
) - 1);
183 /* Set aligned width */
184 val
= ROT_ALIGN(*hsize
, limit
->align
, mask
);
185 if (val
< limit
->min_w
)
186 *hsize
= ROT_MIN(limit
->min_w
, mask
);
187 else if (val
> limit
->max_w
)
188 *hsize
= ROT_MAX(limit
->max_w
, mask
);
192 /* Set aligned height */
193 val
= ROT_ALIGN(*vsize
, limit
->align
, mask
);
194 if (val
< limit
->min_h
)
195 *vsize
= ROT_MIN(limit
->min_h
, mask
);
196 else if (val
> limit
->max_h
)
197 *vsize
= ROT_MAX(limit
->max_h
, mask
);
202 static int rotator_src_set_fmt(struct device
*dev
, u32 fmt
)
204 struct rot_context
*rot
= dev_get_drvdata(dev
);
207 val
= rot_read(ROT_CONTROL
);
208 val
&= ~ROT_CONTROL_FMT_MASK
;
211 case DRM_FORMAT_NV12
:
212 val
|= ROT_CONTROL_FMT_YCBCR420_2P
;
214 case DRM_FORMAT_XRGB8888
:
215 val
|= ROT_CONTROL_FMT_RGB888
;
218 DRM_ERROR("invalid image format\n");
222 rot_write(val
, ROT_CONTROL
);
227 static inline bool rotator_check_reg_fmt(u32 fmt
)
229 if ((fmt
== ROT_CONTROL_FMT_YCBCR420_2P
) ||
230 (fmt
== ROT_CONTROL_FMT_RGB888
))
236 static int rotator_src_set_size(struct device
*dev
, int swap
,
237 struct drm_exynos_pos
*pos
,
238 struct drm_exynos_sz
*sz
)
240 struct rot_context
*rot
= dev_get_drvdata(dev
);
241 u32 fmt
, hsize
, vsize
;
245 fmt
= rotator_reg_get_fmt(rot
);
246 if (!rotator_check_reg_fmt(fmt
)) {
247 DRM_ERROR("%s:invalid format.\n", __func__
);
251 /* Align buffer size */
254 rotator_align_size(rot
, fmt
, &hsize
, &vsize
);
256 /* Set buffer size configuration */
257 val
= ROT_SET_BUF_SIZE_H(vsize
) | ROT_SET_BUF_SIZE_W(hsize
);
258 rot_write(val
, ROT_SRC_BUF_SIZE
);
260 /* Set crop image position configuration */
261 val
= ROT_CROP_POS_Y(pos
->y
) | ROT_CROP_POS_X(pos
->x
);
262 rot_write(val
, ROT_SRC_CROP_POS
);
263 val
= ROT_SRC_CROP_SIZE_H(pos
->h
) | ROT_SRC_CROP_SIZE_W(pos
->w
);
264 rot_write(val
, ROT_SRC_CROP_SIZE
);
269 static int rotator_src_set_addr(struct device
*dev
,
270 struct drm_exynos_ipp_buf_info
*buf_info
,
271 u32 buf_id
, enum drm_exynos_ipp_buf_type buf_type
)
273 struct rot_context
*rot
= dev_get_drvdata(dev
);
274 dma_addr_t addr
[EXYNOS_DRM_PLANAR_MAX
];
275 u32 val
, fmt
, hsize
, vsize
;
278 /* Set current buf_id */
279 rot
->cur_buf_id
[EXYNOS_DRM_OPS_SRC
] = buf_id
;
282 case IPP_BUF_ENQUEUE
:
283 /* Set address configuration */
284 for_each_ipp_planar(i
)
285 addr
[i
] = buf_info
->base
[i
];
288 fmt
= rotator_reg_get_fmt(rot
);
289 if (!rotator_check_reg_fmt(fmt
)) {
290 DRM_ERROR("%s:invalid format.\n", __func__
);
294 /* Re-set cb planar for NV12 format */
295 if ((fmt
== ROT_CONTROL_FMT_YCBCR420_2P
) &&
296 !addr
[EXYNOS_DRM_PLANAR_CB
]) {
298 val
= rot_read(ROT_SRC_BUF_SIZE
);
299 hsize
= ROT_GET_BUF_SIZE_W(val
);
300 vsize
= ROT_GET_BUF_SIZE_H(val
);
303 addr
[EXYNOS_DRM_PLANAR_CB
] =
304 addr
[EXYNOS_DRM_PLANAR_Y
] + hsize
* vsize
;
307 for_each_ipp_planar(i
)
308 rot_write(addr
[i
], ROT_SRC_BUF_ADDR(i
));
310 case IPP_BUF_DEQUEUE
:
311 for_each_ipp_planar(i
)
312 rot_write(0x0, ROT_SRC_BUF_ADDR(i
));
322 static int rotator_dst_set_transf(struct device
*dev
,
323 enum drm_exynos_degree degree
,
324 enum drm_exynos_flip flip
, bool *swap
)
326 struct rot_context
*rot
= dev_get_drvdata(dev
);
329 /* Set transform configuration */
330 val
= rot_read(ROT_CONTROL
);
331 val
&= ~ROT_CONTROL_FLIP_MASK
;
334 case EXYNOS_DRM_FLIP_VERTICAL
:
335 val
|= ROT_CONTROL_FLIP_VERTICAL
;
337 case EXYNOS_DRM_FLIP_HORIZONTAL
:
338 val
|= ROT_CONTROL_FLIP_HORIZONTAL
;
345 val
&= ~ROT_CONTROL_ROT_MASK
;
348 case EXYNOS_DRM_DEGREE_90
:
349 val
|= ROT_CONTROL_ROT_90
;
351 case EXYNOS_DRM_DEGREE_180
:
352 val
|= ROT_CONTROL_ROT_180
;
354 case EXYNOS_DRM_DEGREE_270
:
355 val
|= ROT_CONTROL_ROT_270
;
358 /* Rotation 0 Degree */
362 rot_write(val
, ROT_CONTROL
);
364 /* Check degree for setting buffer size swap */
365 if ((degree
== EXYNOS_DRM_DEGREE_90
) ||
366 (degree
== EXYNOS_DRM_DEGREE_270
))
374 static int rotator_dst_set_size(struct device
*dev
, int swap
,
375 struct drm_exynos_pos
*pos
,
376 struct drm_exynos_sz
*sz
)
378 struct rot_context
*rot
= dev_get_drvdata(dev
);
379 u32 val
, fmt
, hsize
, vsize
;
382 fmt
= rotator_reg_get_fmt(rot
);
383 if (!rotator_check_reg_fmt(fmt
)) {
384 DRM_ERROR("%s:invalid format.\n", __func__
);
388 /* Align buffer size */
391 rotator_align_size(rot
, fmt
, &hsize
, &vsize
);
393 /* Set buffer size configuration */
394 val
= ROT_SET_BUF_SIZE_H(vsize
) | ROT_SET_BUF_SIZE_W(hsize
);
395 rot_write(val
, ROT_DST_BUF_SIZE
);
397 /* Set crop image position configuration */
398 val
= ROT_CROP_POS_Y(pos
->y
) | ROT_CROP_POS_X(pos
->x
);
399 rot_write(val
, ROT_DST_CROP_POS
);
404 static int rotator_dst_set_addr(struct device
*dev
,
405 struct drm_exynos_ipp_buf_info
*buf_info
,
406 u32 buf_id
, enum drm_exynos_ipp_buf_type buf_type
)
408 struct rot_context
*rot
= dev_get_drvdata(dev
);
409 dma_addr_t addr
[EXYNOS_DRM_PLANAR_MAX
];
410 u32 val
, fmt
, hsize
, vsize
;
413 /* Set current buf_id */
414 rot
->cur_buf_id
[EXYNOS_DRM_OPS_DST
] = buf_id
;
417 case IPP_BUF_ENQUEUE
:
418 /* Set address configuration */
419 for_each_ipp_planar(i
)
420 addr
[i
] = buf_info
->base
[i
];
423 fmt
= rotator_reg_get_fmt(rot
);
424 if (!rotator_check_reg_fmt(fmt
)) {
425 DRM_ERROR("%s:invalid format.\n", __func__
);
429 /* Re-set cb planar for NV12 format */
430 if ((fmt
== ROT_CONTROL_FMT_YCBCR420_2P
) &&
431 !addr
[EXYNOS_DRM_PLANAR_CB
]) {
433 val
= rot_read(ROT_DST_BUF_SIZE
);
435 hsize
= ROT_GET_BUF_SIZE_W(val
);
436 vsize
= ROT_GET_BUF_SIZE_H(val
);
439 addr
[EXYNOS_DRM_PLANAR_CB
] =
440 addr
[EXYNOS_DRM_PLANAR_Y
] + hsize
* vsize
;
443 for_each_ipp_planar(i
)
444 rot_write(addr
[i
], ROT_DST_BUF_ADDR(i
));
446 case IPP_BUF_DEQUEUE
:
447 for_each_ipp_planar(i
)
448 rot_write(0x0, ROT_DST_BUF_ADDR(i
));
458 static struct exynos_drm_ipp_ops rot_src_ops
= {
459 .set_fmt
= rotator_src_set_fmt
,
460 .set_size
= rotator_src_set_size
,
461 .set_addr
= rotator_src_set_addr
,
464 static struct exynos_drm_ipp_ops rot_dst_ops
= {
465 .set_transf
= rotator_dst_set_transf
,
466 .set_size
= rotator_dst_set_size
,
467 .set_addr
= rotator_dst_set_addr
,
470 static int rotator_init_prop_list(struct exynos_drm_ippdrv
*ippdrv
)
472 struct drm_exynos_ipp_prop_list
*prop_list
;
474 DRM_DEBUG_KMS("%s\n", __func__
);
476 prop_list
= devm_kzalloc(ippdrv
->dev
, sizeof(*prop_list
), GFP_KERNEL
);
478 DRM_ERROR("failed to alloc property list.\n");
482 prop_list
->version
= 1;
483 prop_list
->flip
= (1 << EXYNOS_DRM_FLIP_VERTICAL
) |
484 (1 << EXYNOS_DRM_FLIP_HORIZONTAL
);
485 prop_list
->degree
= (1 << EXYNOS_DRM_DEGREE_0
) |
486 (1 << EXYNOS_DRM_DEGREE_90
) |
487 (1 << EXYNOS_DRM_DEGREE_180
) |
488 (1 << EXYNOS_DRM_DEGREE_270
);
491 prop_list
->scale
= 0;
493 ippdrv
->prop_list
= prop_list
;
498 static inline bool rotator_check_drm_fmt(u32 fmt
)
501 case DRM_FORMAT_XRGB8888
:
502 case DRM_FORMAT_NV12
:
505 DRM_DEBUG_KMS("%s:not support format\n", __func__
);
510 static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip
)
513 case EXYNOS_DRM_FLIP_NONE
:
514 case EXYNOS_DRM_FLIP_VERTICAL
:
515 case EXYNOS_DRM_FLIP_HORIZONTAL
:
516 case EXYNOS_DRM_FLIP_BOTH
:
519 DRM_DEBUG_KMS("%s:invalid flip\n", __func__
);
524 static int rotator_ippdrv_check_property(struct device
*dev
,
525 struct drm_exynos_ipp_property
*property
)
527 struct drm_exynos_ipp_config
*src_config
=
528 &property
->config
[EXYNOS_DRM_OPS_SRC
];
529 struct drm_exynos_ipp_config
*dst_config
=
530 &property
->config
[EXYNOS_DRM_OPS_DST
];
531 struct drm_exynos_pos
*src_pos
= &src_config
->pos
;
532 struct drm_exynos_pos
*dst_pos
= &dst_config
->pos
;
533 struct drm_exynos_sz
*src_sz
= &src_config
->sz
;
534 struct drm_exynos_sz
*dst_sz
= &dst_config
->sz
;
537 /* Check format configuration */
538 if (src_config
->fmt
!= dst_config
->fmt
) {
539 DRM_DEBUG_KMS("%s:not support csc feature\n", __func__
);
543 if (!rotator_check_drm_fmt(dst_config
->fmt
)) {
544 DRM_DEBUG_KMS("%s:invalid format\n", __func__
);
548 /* Check transform configuration */
549 if (src_config
->degree
!= EXYNOS_DRM_DEGREE_0
) {
550 DRM_DEBUG_KMS("%s:not support source-side rotation\n",
555 switch (dst_config
->degree
) {
556 case EXYNOS_DRM_DEGREE_90
:
557 case EXYNOS_DRM_DEGREE_270
:
559 case EXYNOS_DRM_DEGREE_0
:
560 case EXYNOS_DRM_DEGREE_180
:
564 DRM_DEBUG_KMS("%s:invalid degree\n", __func__
);
568 if (src_config
->flip
!= EXYNOS_DRM_FLIP_NONE
) {
569 DRM_DEBUG_KMS("%s:not support source-side flip\n", __func__
);
573 if (!rotator_check_drm_flip(dst_config
->flip
)) {
574 DRM_DEBUG_KMS("%s:invalid flip\n", __func__
);
578 /* Check size configuration */
579 if ((src_pos
->x
+ src_pos
->w
> src_sz
->hsize
) ||
580 (src_pos
->y
+ src_pos
->h
> src_sz
->vsize
)) {
581 DRM_DEBUG_KMS("%s:out of source buffer bound\n", __func__
);
586 if ((dst_pos
->x
+ dst_pos
->h
> dst_sz
->vsize
) ||
587 (dst_pos
->y
+ dst_pos
->w
> dst_sz
->hsize
)) {
588 DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
593 if ((src_pos
->w
!= dst_pos
->h
) || (src_pos
->h
!= dst_pos
->w
)) {
594 DRM_DEBUG_KMS("%s:not support scale feature\n",
599 if ((dst_pos
->x
+ dst_pos
->w
> dst_sz
->hsize
) ||
600 (dst_pos
->y
+ dst_pos
->h
> dst_sz
->vsize
)) {
601 DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
606 if ((src_pos
->w
!= dst_pos
->w
) || (src_pos
->h
!= dst_pos
->h
)) {
607 DRM_DEBUG_KMS("%s:not support scale feature\n",
616 static int rotator_ippdrv_start(struct device
*dev
, enum drm_exynos_ipp_cmd cmd
)
618 struct rot_context
*rot
= dev_get_drvdata(dev
);
621 if (rot
->suspended
) {
622 DRM_ERROR("suspended state\n");
626 if (cmd
!= IPP_CMD_M2M
) {
627 DRM_ERROR("not support cmd: %d\n", cmd
);
631 /* Set interrupt enable */
632 rotator_reg_set_irq(rot
, true);
634 val
= rot_read(ROT_CONTROL
);
635 val
|= ROT_CONTROL_START
;
637 rot_write(val
, ROT_CONTROL
);
642 static int rotator_probe(struct platform_device
*pdev
)
644 struct device
*dev
= &pdev
->dev
;
645 struct rot_context
*rot
;
646 struct exynos_drm_ippdrv
*ippdrv
;
649 rot
= devm_kzalloc(dev
, sizeof(*rot
), GFP_KERNEL
);
651 dev_err(dev
, "failed to allocate rot\n");
655 rot
->limit_tbl
= (struct rot_limit_table
*)
656 platform_get_device_id(pdev
)->driver_data
;
658 rot
->regs_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
659 rot
->regs
= devm_ioremap_resource(dev
, rot
->regs_res
);
660 if (IS_ERR(rot
->regs
))
661 return PTR_ERR(rot
->regs
);
663 rot
->irq
= platform_get_irq(pdev
, 0);
665 dev_err(dev
, "failed to get irq\n");
669 ret
= devm_request_threaded_irq(dev
, rot
->irq
, NULL
,
670 rotator_irq_handler
, IRQF_ONESHOT
, "drm_rotator", rot
);
672 dev_err(dev
, "failed to request irq\n");
676 rot
->clock
= devm_clk_get(dev
, "rotator");
677 if (IS_ERR(rot
->clock
)) {
678 dev_err(dev
, "failed to get clock\n");
679 return PTR_ERR(rot
->clock
);
682 pm_runtime_enable(dev
);
684 ippdrv
= &rot
->ippdrv
;
686 ippdrv
->ops
[EXYNOS_DRM_OPS_SRC
] = &rot_src_ops
;
687 ippdrv
->ops
[EXYNOS_DRM_OPS_DST
] = &rot_dst_ops
;
688 ippdrv
->check_property
= rotator_ippdrv_check_property
;
689 ippdrv
->start
= rotator_ippdrv_start
;
690 ret
= rotator_init_prop_list(ippdrv
);
692 dev_err(dev
, "failed to init property list.\n");
693 goto err_ippdrv_register
;
696 DRM_DEBUG_KMS("%s:ippdrv[0x%x]\n", __func__
, (int)ippdrv
);
698 platform_set_drvdata(pdev
, rot
);
700 ret
= exynos_drm_ippdrv_register(ippdrv
);
702 dev_err(dev
, "failed to register drm rotator device\n");
703 goto err_ippdrv_register
;
706 dev_info(dev
, "The exynos rotator is probed successfully\n");
711 pm_runtime_disable(dev
);
715 static int rotator_remove(struct platform_device
*pdev
)
717 struct device
*dev
= &pdev
->dev
;
718 struct rot_context
*rot
= dev_get_drvdata(dev
);
719 struct exynos_drm_ippdrv
*ippdrv
= &rot
->ippdrv
;
721 exynos_drm_ippdrv_unregister(ippdrv
);
723 pm_runtime_disable(dev
);
728 static struct rot_limit_table rot_limit_tbl
= {
745 static struct platform_device_id rotator_driver_ids
[] = {
747 .name
= "exynos-rot",
748 .driver_data
= (unsigned long)&rot_limit_tbl
,
753 static int rotator_clk_crtl(struct rot_context
*rot
, bool enable
)
755 DRM_DEBUG_KMS("%s\n", __func__
);
758 clk_enable(rot
->clock
);
759 rot
->suspended
= false;
761 clk_disable(rot
->clock
);
762 rot
->suspended
= true;
769 #ifdef CONFIG_PM_SLEEP
770 static int rotator_suspend(struct device
*dev
)
772 struct rot_context
*rot
= dev_get_drvdata(dev
);
774 DRM_DEBUG_KMS("%s\n", __func__
);
776 if (pm_runtime_suspended(dev
))
779 return rotator_clk_crtl(rot
, false);
782 static int rotator_resume(struct device
*dev
)
784 struct rot_context
*rot
= dev_get_drvdata(dev
);
786 DRM_DEBUG_KMS("%s\n", __func__
);
788 if (!pm_runtime_suspended(dev
))
789 return rotator_clk_crtl(rot
, true);
795 #ifdef CONFIG_PM_RUNTIME
796 static int rotator_runtime_suspend(struct device
*dev
)
798 struct rot_context
*rot
= dev_get_drvdata(dev
);
800 DRM_DEBUG_KMS("%s\n", __func__
);
802 return rotator_clk_crtl(rot
, false);
805 static int rotator_runtime_resume(struct device
*dev
)
807 struct rot_context
*rot
= dev_get_drvdata(dev
);
809 DRM_DEBUG_KMS("%s\n", __func__
);
811 return rotator_clk_crtl(rot
, true);
815 static const struct dev_pm_ops rotator_pm_ops
= {
816 SET_SYSTEM_SLEEP_PM_OPS(rotator_suspend
, rotator_resume
)
817 SET_RUNTIME_PM_OPS(rotator_runtime_suspend
, rotator_runtime_resume
,
821 struct platform_driver rotator_driver
= {
822 .probe
= rotator_probe
,
823 .remove
= rotator_remove
,
824 .id_table
= rotator_driver_ids
,
826 .name
= "exynos-rot",
827 .owner
= THIS_MODULE
,
828 .pm
= &rotator_pm_ops
,