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
->cmd
;
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
:
518 DRM_DEBUG_KMS("%s:invalid flip\n", __func__
);
523 static int rotator_ippdrv_check_property(struct device
*dev
,
524 struct drm_exynos_ipp_property
*property
)
526 struct drm_exynos_ipp_config
*src_config
=
527 &property
->config
[EXYNOS_DRM_OPS_SRC
];
528 struct drm_exynos_ipp_config
*dst_config
=
529 &property
->config
[EXYNOS_DRM_OPS_DST
];
530 struct drm_exynos_pos
*src_pos
= &src_config
->pos
;
531 struct drm_exynos_pos
*dst_pos
= &dst_config
->pos
;
532 struct drm_exynos_sz
*src_sz
= &src_config
->sz
;
533 struct drm_exynos_sz
*dst_sz
= &dst_config
->sz
;
536 /* Check format configuration */
537 if (src_config
->fmt
!= dst_config
->fmt
) {
538 DRM_DEBUG_KMS("%s:not support csc feature\n", __func__
);
542 if (!rotator_check_drm_fmt(dst_config
->fmt
)) {
543 DRM_DEBUG_KMS("%s:invalid format\n", __func__
);
547 /* Check transform configuration */
548 if (src_config
->degree
!= EXYNOS_DRM_DEGREE_0
) {
549 DRM_DEBUG_KMS("%s:not support source-side rotation\n",
554 switch (dst_config
->degree
) {
555 case EXYNOS_DRM_DEGREE_90
:
556 case EXYNOS_DRM_DEGREE_270
:
558 case EXYNOS_DRM_DEGREE_0
:
559 case EXYNOS_DRM_DEGREE_180
:
563 DRM_DEBUG_KMS("%s:invalid degree\n", __func__
);
567 if (src_config
->flip
!= EXYNOS_DRM_FLIP_NONE
) {
568 DRM_DEBUG_KMS("%s:not support source-side flip\n", __func__
);
572 if (!rotator_check_drm_flip(dst_config
->flip
)) {
573 DRM_DEBUG_KMS("%s:invalid flip\n", __func__
);
577 /* Check size configuration */
578 if ((src_pos
->x
+ src_pos
->w
> src_sz
->hsize
) ||
579 (src_pos
->y
+ src_pos
->h
> src_sz
->vsize
)) {
580 DRM_DEBUG_KMS("%s:out of source buffer bound\n", __func__
);
585 if ((dst_pos
->x
+ dst_pos
->h
> dst_sz
->vsize
) ||
586 (dst_pos
->y
+ dst_pos
->w
> dst_sz
->hsize
)) {
587 DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
592 if ((src_pos
->w
!= dst_pos
->h
) || (src_pos
->h
!= dst_pos
->w
)) {
593 DRM_DEBUG_KMS("%s:not support scale feature\n",
598 if ((dst_pos
->x
+ dst_pos
->w
> dst_sz
->hsize
) ||
599 (dst_pos
->y
+ dst_pos
->h
> dst_sz
->vsize
)) {
600 DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
605 if ((src_pos
->w
!= dst_pos
->w
) || (src_pos
->h
!= dst_pos
->h
)) {
606 DRM_DEBUG_KMS("%s:not support scale feature\n",
615 static int rotator_ippdrv_start(struct device
*dev
, enum drm_exynos_ipp_cmd cmd
)
617 struct rot_context
*rot
= dev_get_drvdata(dev
);
620 if (rot
->suspended
) {
621 DRM_ERROR("suspended state\n");
625 if (cmd
!= IPP_CMD_M2M
) {
626 DRM_ERROR("not support cmd: %d\n", cmd
);
630 /* Set interrupt enable */
631 rotator_reg_set_irq(rot
, true);
633 val
= rot_read(ROT_CONTROL
);
634 val
|= ROT_CONTROL_START
;
636 rot_write(val
, ROT_CONTROL
);
641 static int __devinit
rotator_probe(struct platform_device
*pdev
)
643 struct device
*dev
= &pdev
->dev
;
644 struct rot_context
*rot
;
645 struct exynos_drm_ippdrv
*ippdrv
;
648 rot
= devm_kzalloc(dev
, sizeof(*rot
), GFP_KERNEL
);
650 dev_err(dev
, "failed to allocate rot\n");
654 rot
->limit_tbl
= (struct rot_limit_table
*)
655 platform_get_device_id(pdev
)->driver_data
;
657 rot
->regs_res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
658 if (!rot
->regs_res
) {
659 dev_err(dev
, "failed to find registers\n");
661 goto err_get_resource
;
664 rot
->regs
= devm_request_and_ioremap(dev
, rot
->regs_res
);
666 dev_err(dev
, "failed to map register\n");
668 goto err_get_resource
;
671 rot
->irq
= platform_get_irq(pdev
, 0);
673 dev_err(dev
, "failed to get irq\n");
678 ret
= request_threaded_irq(rot
->irq
, NULL
, rotator_irq_handler
,
679 IRQF_ONESHOT
, "drm_rotator", rot
);
681 dev_err(dev
, "failed to request irq\n");
685 rot
->clock
= clk_get(dev
, "rotator");
686 if (IS_ERR_OR_NULL(rot
->clock
)) {
687 dev_err(dev
, "failed to get clock\n");
688 ret
= PTR_ERR(rot
->clock
);
692 pm_runtime_enable(dev
);
694 ippdrv
= &rot
->ippdrv
;
696 ippdrv
->ops
[EXYNOS_DRM_OPS_SRC
] = &rot_src_ops
;
697 ippdrv
->ops
[EXYNOS_DRM_OPS_DST
] = &rot_dst_ops
;
698 ippdrv
->check_property
= rotator_ippdrv_check_property
;
699 ippdrv
->start
= rotator_ippdrv_start
;
700 ret
= rotator_init_prop_list(ippdrv
);
702 dev_err(dev
, "failed to init property list.\n");
703 goto err_ippdrv_register
;
706 DRM_DEBUG_KMS("%s:ippdrv[0x%x]\n", __func__
, (int)ippdrv
);
708 platform_set_drvdata(pdev
, rot
);
710 ret
= exynos_drm_ippdrv_register(ippdrv
);
712 dev_err(dev
, "failed to register drm rotator device\n");
713 goto err_ippdrv_register
;
716 dev_info(dev
, "The exynos rotator is probed successfully\n");
721 devm_kfree(dev
, ippdrv
->prop_list
);
722 pm_runtime_disable(dev
);
725 free_irq(rot
->irq
, rot
);
727 devm_iounmap(dev
, rot
->regs
);
729 devm_kfree(dev
, rot
);
733 static int __devexit
rotator_remove(struct platform_device
*pdev
)
735 struct device
*dev
= &pdev
->dev
;
736 struct rot_context
*rot
= dev_get_drvdata(dev
);
737 struct exynos_drm_ippdrv
*ippdrv
= &rot
->ippdrv
;
739 devm_kfree(dev
, ippdrv
->prop_list
);
740 exynos_drm_ippdrv_unregister(ippdrv
);
742 pm_runtime_disable(dev
);
745 free_irq(rot
->irq
, rot
);
746 devm_iounmap(dev
, rot
->regs
);
748 devm_kfree(dev
, rot
);
753 struct rot_limit_table rot_limit_tbl
= {
770 struct platform_device_id rotator_driver_ids
[] = {
772 .name
= "exynos-rot",
773 .driver_data
= (unsigned long)&rot_limit_tbl
,
778 static int rotator_clk_crtl(struct rot_context
*rot
, bool enable
)
780 DRM_DEBUG_KMS("%s\n", __func__
);
783 clk_enable(rot
->clock
);
784 rot
->suspended
= false;
786 clk_disable(rot
->clock
);
787 rot
->suspended
= true;
794 #ifdef CONFIG_PM_SLEEP
795 static int rotator_suspend(struct device
*dev
)
797 struct rot_context
*rot
= dev_get_drvdata(dev
);
799 DRM_DEBUG_KMS("%s\n", __func__
);
801 if (pm_runtime_suspended(dev
))
804 return rotator_clk_crtl(rot
, false);
807 static int rotator_resume(struct device
*dev
)
809 struct rot_context
*rot
= dev_get_drvdata(dev
);
811 DRM_DEBUG_KMS("%s\n", __func__
);
813 if (!pm_runtime_suspended(dev
))
814 return rotator_clk_crtl(rot
, true);
820 #ifdef CONFIG_PM_RUNTIME
821 static int rotator_runtime_suspend(struct device
*dev
)
823 struct rot_context
*rot
= dev_get_drvdata(dev
);
825 DRM_DEBUG_KMS("%s\n", __func__
);
827 return rotator_clk_crtl(rot
, false);
830 static int rotator_runtime_resume(struct device
*dev
)
832 struct rot_context
*rot
= dev_get_drvdata(dev
);
834 DRM_DEBUG_KMS("%s\n", __func__
);
836 return rotator_clk_crtl(rot
, true);
840 static const struct dev_pm_ops rotator_pm_ops
= {
841 SET_SYSTEM_SLEEP_PM_OPS(rotator_suspend
, rotator_resume
)
842 SET_RUNTIME_PM_OPS(rotator_runtime_suspend
, rotator_runtime_resume
,
846 struct platform_driver rotator_driver
= {
847 .probe
= rotator_probe
,
848 .remove
= __devexit_p(rotator_remove
),
849 .id_table
= rotator_driver_ids
,
851 .name
= "exynos-rot",
852 .owner
= THIS_MODULE
,
853 .pm
= &rotator_pm_ops
,