2019-06-01 10:08:38 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-12-14 17:58:56 +09:00
/*
* Copyright ( C ) 2012 Samsung Electronics Co . Ltd
* Authors :
* YoungJun Cho < yj44 . cho @ samsung . com >
* Eunchul Kim < chulspro . kim @ samsung . com >
*/
2019-06-24 22:06:28 +09:00
# include <linux/clk.h>
2018-05-09 10:59:23 +02:00
# include <linux/component.h>
2012-12-14 17:58:56 +09:00
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/io.h>
2019-06-24 22:06:28 +09:00
# include <linux/kernel.h>
2016-04-01 15:17:43 +02:00
# include <linux/of_device.h>
2019-06-24 22:06:28 +09:00
# include <linux/platform_device.h>
2012-12-14 17:58:56 +09:00
# include <linux/pm_runtime.h>
2019-08-21 20:28:43 +09:00
# include <linux/sizes.h>
2012-12-14 17:58:56 +09:00
2019-08-21 20:28:43 +09:00
# include <drm/drm_fourcc.h>
2012-12-14 17:58:56 +09:00
# include <drm/exynos_drm.h>
2019-06-24 22:06:28 +09:00
2013-08-13 00:46:40 +01:00
# include "exynos_drm_drv.h"
2012-12-14 17:58:56 +09:00
# include "exynos_drm_ipp.h"
2019-06-24 22:06:28 +09:00
# include "regs-rotator.h"
2012-12-14 17:58:56 +09:00
/*
* Rotator supports image crop / rotator and input / output DMA operations .
* input DMA reads image data from the memory .
* output DMA writes image data to memory .
*/
2018-05-09 10:59:23 +02:00
# define ROTATOR_AUTOSUSPEND_DELAY 2000
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
# define rot_read(offset) readl(rot->regs + (offset))
2012-12-14 17:58:56 +09:00
# define rot_write(cfg, offset) writel(cfg, rot->regs + (offset))
enum rot_irq_status {
ROT_IRQ_STATUS_COMPLETE = 8 ,
ROT_IRQ_STATUS_ILLEGAL = 9 ,
} ;
2018-05-09 10:59:23 +02:00
struct rot_variant {
const struct exynos_drm_ipp_formats * formats ;
unsigned int num_formats ;
2012-12-14 17:58:56 +09:00
} ;
/*
* A structure of rotator context .
* @ ippdrv : prepare initialization using ippdrv .
* @ regs : memory mapped io registers .
* @ clock : rotator gate clock .
* @ limit_tbl : limitation of rotator .
* @ irq : irq number .
*/
struct rot_context {
2018-05-09 10:59:23 +02:00
struct exynos_drm_ipp ipp ;
struct drm_device * drm_dev ;
struct device * dev ;
2012-12-14 17:58:56 +09:00
void __iomem * regs ;
struct clk * clock ;
2018-05-09 10:59:23 +02:00
const struct exynos_drm_ipp_formats * formats ;
unsigned int num_formats ;
struct exynos_drm_ipp_task * task ;
2012-12-14 17:58:56 +09:00
} ;
static void rotator_reg_set_irq ( struct rot_context * rot , bool enable )
{
u32 val = rot_read ( ROT_CONFIG ) ;
if ( enable = = true )
val | = ROT_CONFIG_IRQ ;
else
val & = ~ ROT_CONFIG_IRQ ;
rot_write ( val , ROT_CONFIG ) ;
}
static enum rot_irq_status rotator_reg_get_irq_status ( struct rot_context * rot )
{
u32 val = rot_read ( ROT_STATUS ) ;
val = ROT_STATUS_IRQ ( val ) ;
if ( val = = ROT_STATUS_IRQ_VAL_COMPLETE )
return ROT_IRQ_STATUS_COMPLETE ;
return ROT_IRQ_STATUS_ILLEGAL ;
}
static irqreturn_t rotator_irq_handler ( int irq , void * arg )
{
struct rot_context * rot = arg ;
enum rot_irq_status irq_status ;
u32 val ;
/* Get execution result */
irq_status = rotator_reg_get_irq_status ( rot ) ;
/* clear status */
val = rot_read ( ROT_STATUS ) ;
val | = ROT_STATUS_IRQ_PENDING ( ( u32 ) irq_status ) ;
rot_write ( val , ROT_STATUS ) ;
2018-05-09 10:59:23 +02:00
if ( rot - > task ) {
struct exynos_drm_ipp_task * task = rot - > task ;
rot - > task = NULL ;
pm_runtime_mark_last_busy ( rot - > dev ) ;
pm_runtime_put_autosuspend ( rot - > dev ) ;
exynos_drm_ipp_task_done ( task ,
irq_status = = ROT_IRQ_STATUS_COMPLETE ? 0 : - EINVAL ) ;
2014-04-17 19:09:00 +09:00
}
2012-12-14 17:58:56 +09:00
return IRQ_HANDLED ;
}
2018-05-09 10:59:23 +02:00
static void rotator_src_set_fmt ( struct rot_context * rot , u32 fmt )
2012-12-14 17:58:56 +09:00
{
u32 val ;
val = rot_read ( ROT_CONTROL ) ;
val & = ~ ROT_CONTROL_FMT_MASK ;
switch ( fmt ) {
case DRM_FORMAT_NV12 :
val | = ROT_CONTROL_FMT_YCBCR420_2P ;
break ;
case DRM_FORMAT_XRGB8888 :
val | = ROT_CONTROL_FMT_RGB888 ;
break ;
}
rot_write ( val , ROT_CONTROL ) ;
}
2018-05-09 10:59:23 +02:00
static void rotator_src_set_buf ( struct rot_context * rot ,
struct exynos_drm_ipp_buffer * buf )
2012-12-14 17:58:56 +09:00
{
u32 val ;
/* Set buffer size configuration */
2018-05-09 10:59:23 +02:00
val = ROT_SET_BUF_SIZE_H ( buf - > buf . height ) |
ROT_SET_BUF_SIZE_W ( buf - > buf . pitch [ 0 ] / buf - > format - > cpp [ 0 ] ) ;
2012-12-14 17:58:56 +09:00
rot_write ( val , ROT_SRC_BUF_SIZE ) ;
/* Set crop image position configuration */
2018-05-09 10:59:23 +02:00
val = ROT_CROP_POS_Y ( buf - > rect . y ) | ROT_CROP_POS_X ( buf - > rect . x ) ;
2012-12-14 17:58:56 +09:00
rot_write ( val , ROT_SRC_CROP_POS ) ;
2018-05-09 10:59:23 +02:00
val = ROT_SRC_CROP_SIZE_H ( buf - > rect . h ) |
ROT_SRC_CROP_SIZE_W ( buf - > rect . w ) ;
2012-12-14 17:58:56 +09:00
rot_write ( val , ROT_SRC_CROP_SIZE ) ;
2018-05-09 10:59:23 +02:00
/* Set buffer DMA address */
rot_write ( buf - > dma_addr [ 0 ] , ROT_SRC_BUF_ADDR ( 0 ) ) ;
rot_write ( buf - > dma_addr [ 1 ] , ROT_SRC_BUF_ADDR ( 1 ) ) ;
2012-12-14 17:58:56 +09:00
}
2018-05-09 10:59:23 +02:00
static void rotator_dst_set_transf ( struct rot_context * rot ,
unsigned int rotation )
2012-12-14 17:58:56 +09:00
{
u32 val ;
/* Set transform configuration */
val = rot_read ( ROT_CONTROL ) ;
val & = ~ ROT_CONTROL_FLIP_MASK ;
2018-05-09 10:59:23 +02:00
if ( rotation & DRM_MODE_REFLECT_X )
val | = ROT_CONTROL_FLIP_VERTICAL ;
2018-06-07 13:06:07 +02:00
if ( rotation & DRM_MODE_REFLECT_Y )
val | = ROT_CONTROL_FLIP_HORIZONTAL ;
2012-12-14 17:58:56 +09:00
val & = ~ ROT_CONTROL_ROT_MASK ;
2018-05-09 10:59:23 +02:00
if ( rotation & DRM_MODE_ROTATE_90 )
2012-12-14 17:58:56 +09:00
val | = ROT_CONTROL_ROT_90 ;
2018-05-09 10:59:23 +02:00
else if ( rotation & DRM_MODE_ROTATE_180 )
2012-12-14 17:58:56 +09:00
val | = ROT_CONTROL_ROT_180 ;
2018-05-09 10:59:23 +02:00
else if ( rotation & DRM_MODE_ROTATE_270 )
2012-12-14 17:58:56 +09:00
val | = ROT_CONTROL_ROT_270 ;
rot_write ( val , ROT_CONTROL ) ;
}
2018-05-09 10:59:23 +02:00
static void rotator_dst_set_buf ( struct rot_context * rot ,
struct exynos_drm_ipp_buffer * buf )
2012-12-14 17:58:56 +09:00
{
2018-05-09 10:59:23 +02:00
u32 val ;
2012-12-14 17:58:56 +09:00
/* Set buffer size configuration */
2018-05-09 10:59:23 +02:00
val = ROT_SET_BUF_SIZE_H ( buf - > buf . height ) |
ROT_SET_BUF_SIZE_W ( buf - > buf . pitch [ 0 ] / buf - > format - > cpp [ 0 ] ) ;
2012-12-14 17:58:56 +09:00
rot_write ( val , ROT_DST_BUF_SIZE ) ;
/* Set crop image position configuration */
2018-05-09 10:59:23 +02:00
val = ROT_CROP_POS_Y ( buf - > rect . y ) | ROT_CROP_POS_X ( buf - > rect . x ) ;
2012-12-14 17:58:56 +09:00
rot_write ( val , ROT_DST_CROP_POS ) ;
2018-05-09 10:59:23 +02:00
/* Set buffer DMA address */
rot_write ( buf - > dma_addr [ 0 ] , ROT_DST_BUF_ADDR ( 0 ) ) ;
rot_write ( buf - > dma_addr [ 1 ] , ROT_DST_BUF_ADDR ( 1 ) ) ;
2012-12-14 17:58:56 +09:00
}
2018-05-09 10:59:23 +02:00
static void rotator_start ( struct rot_context * rot )
2012-12-14 17:58:56 +09:00
{
2018-05-09 10:59:23 +02:00
u32 val ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
/* Set interrupt enable */
rotator_reg_set_irq ( rot , true ) ;
val = rot_read ( ROT_CONTROL ) ;
val | = ROT_CONTROL_START ;
rot_write ( val , ROT_CONTROL ) ;
2012-12-14 17:58:56 +09:00
}
2018-05-09 10:59:23 +02:00
static int rotator_commit ( struct exynos_drm_ipp * ipp ,
struct exynos_drm_ipp_task * task )
{
struct rot_context * rot =
container_of ( ipp , struct rot_context , ipp ) ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
pm_runtime_get_sync ( rot - > dev ) ;
rot - > task = task ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
rotator_src_set_fmt ( rot , task - > src . buf . fourcc ) ;
rotator_src_set_buf ( rot , & task - > src ) ;
rotator_dst_set_transf ( rot , task - > transform . rotation ) ;
rotator_dst_set_buf ( rot , & task - > dst ) ;
rotator_start ( rot ) ;
2012-12-14 17:58:56 +09:00
return 0 ;
}
2018-05-09 10:59:23 +02:00
static const struct exynos_drm_ipp_funcs ipp_funcs = {
. commit = rotator_commit ,
} ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
static int rotator_bind ( struct device * dev , struct device * master , void * data )
2012-12-14 17:58:56 +09:00
{
2018-05-09 10:59:23 +02:00
struct rot_context * rot = dev_get_drvdata ( dev ) ;
struct drm_device * drm_dev = data ;
struct exynos_drm_ipp * ipp = & rot - > ipp ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
rot - > drm_dev = drm_dev ;
2019-04-15 17:13:38 +09:00
ipp - > drm_dev = drm_dev ;
2018-10-12 12:53:41 +02:00
exynos_drm_register_dma ( drm_dev , dev ) ;
2012-12-14 17:58:56 +09:00
2019-04-15 17:13:38 +09:00
exynos_drm_ipp_register ( dev , ipp , & ipp_funcs ,
2018-05-09 10:59:23 +02:00
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE ,
rot - > formats , rot - > num_formats , " rotator " ) ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
dev_info ( dev , " The exynos rotator has been probed successfully \n " ) ;
2012-12-14 17:58:56 +09:00
return 0 ;
}
2018-05-09 10:59:23 +02:00
static void rotator_unbind ( struct device * dev , struct device * master ,
void * data )
2012-12-14 17:58:56 +09:00
{
struct rot_context * rot = dev_get_drvdata ( dev ) ;
2018-05-09 10:59:23 +02:00
struct exynos_drm_ipp * ipp = & rot - > ipp ;
2012-12-14 17:58:56 +09:00
2019-04-15 17:13:38 +09:00
exynos_drm_ipp_unregister ( dev , ipp ) ;
2018-10-12 12:53:43 +02:00
exynos_drm_unregister_dma ( rot - > drm_dev , rot - > dev ) ;
2012-12-14 17:58:56 +09:00
}
2018-05-09 10:59:23 +02:00
static const struct component_ops rotator_component_ops = {
. bind = rotator_bind ,
. unbind = rotator_unbind ,
2013-08-13 14:12:56 +09:00
} ;
2012-12-21 15:09:25 -08:00
static int rotator_probe ( struct platform_device * pdev )
2012-12-14 17:58:56 +09:00
{
struct device * dev = & pdev - > dev ;
2018-05-09 10:59:23 +02:00
struct resource * regs_res ;
2012-12-14 17:58:56 +09:00
struct rot_context * rot ;
2018-05-09 10:59:23 +02:00
const struct rot_variant * variant ;
int irq ;
2012-12-14 17:58:56 +09:00
int ret ;
rot = devm_kzalloc ( dev , sizeof ( * rot ) , GFP_KERNEL ) ;
2013-08-19 19:04:55 +09:00
if ( ! rot )
2012-12-14 17:58:56 +09:00
return - ENOMEM ;
2018-05-09 10:59:23 +02:00
variant = of_device_get_match_data ( dev ) ;
rot - > formats = variant - > formats ;
rot - > num_formats = variant - > num_formats ;
rot - > dev = dev ;
regs_res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
rot - > regs = devm_ioremap_resource ( dev , regs_res ) ;
2013-01-21 11:09:02 +01:00
if ( IS_ERR ( rot - > regs ) )
return PTR_ERR ( rot - > regs ) ;
2012-12-14 17:58:56 +09:00
2018-05-09 10:59:23 +02:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
2012-12-14 17:58:56 +09:00
dev_err ( dev , " failed to get irq \n " ) ;
2018-05-09 10:59:23 +02:00
return irq ;
2012-12-14 17:58:56 +09:00
}
2018-05-09 10:59:23 +02:00
ret = devm_request_irq ( dev , irq , rotator_irq_handler , 0 , dev_name ( dev ) ,
rot ) ;
2012-12-14 17:58:56 +09:00
if ( ret < 0 ) {
dev_err ( dev , " failed to request irq \n " ) ;
2012-12-24 14:03:46 +05:30
return ret ;
2012-12-14 17:58:56 +09:00
}
2012-12-24 14:03:48 +05:30
rot - > clock = devm_clk_get ( dev , " rotator " ) ;
2013-03-21 15:33:59 +05:30
if ( IS_ERR ( rot - > clock ) ) {
2012-12-14 17:58:56 +09:00
dev_err ( dev , " failed to get clock \n " ) ;
2013-05-22 21:14:17 +09:00
return PTR_ERR ( rot - > clock ) ;
2012-12-14 17:58:56 +09:00
}
2018-05-09 10:59:23 +02:00
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_set_autosuspend_delay ( dev , ROTATOR_AUTOSUSPEND_DELAY ) ;
2012-12-14 17:58:56 +09:00
pm_runtime_enable ( dev ) ;
platform_set_drvdata ( pdev , rot ) ;
2018-05-09 10:59:23 +02:00
ret = component_add ( dev , & rotator_component_ops ) ;
if ( ret )
goto err_component ;
2012-12-14 17:58:56 +09:00
return 0 ;
2018-05-09 10:59:23 +02:00
err_component :
pm_runtime_dont_use_autosuspend ( dev ) ;
2012-12-14 17:58:56 +09:00
pm_runtime_disable ( dev ) ;
return ret ;
}
2012-12-21 15:09:25 -08:00
static int rotator_remove ( struct platform_device * pdev )
2012-12-14 17:58:56 +09:00
{
struct device * dev = & pdev - > dev ;
2018-05-09 10:59:23 +02:00
component_del ( dev , & rotator_component_ops ) ;
pm_runtime_dont_use_autosuspend ( dev ) ;
2012-12-14 17:58:56 +09:00
pm_runtime_disable ( dev ) ;
return 0 ;
}
2015-09-24 12:14:15 +02:00
# ifdef CONFIG_PM
2012-12-14 17:58:56 +09:00
static int rotator_runtime_suspend ( struct device * dev )
{
struct rot_context * rot = dev_get_drvdata ( dev ) ;
2018-05-09 10:59:23 +02:00
clk_disable_unprepare ( rot - > clock ) ;
return 0 ;
2012-12-14 17:58:56 +09:00
}
static int rotator_runtime_resume ( struct device * dev )
{
struct rot_context * rot = dev_get_drvdata ( dev ) ;
2018-05-09 10:59:23 +02:00
return clk_prepare_enable ( rot - > clock ) ;
2012-12-14 17:58:56 +09:00
}
# endif
2018-12-19 16:57:02 +01:00
static const struct drm_exynos_ipp_limit rotator_s5pv210_rbg888_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 8 , SZ_16K } , . v = { 8 , SZ_16K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 2 , . v . align = 2 ) } ,
} ;
2018-05-09 10:59:23 +02:00
static const struct drm_exynos_ipp_limit rotator_4210_rbg888_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 8 , SZ_16K } , . v = { 8 , SZ_16K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 4 , . v . align = 4 ) } ,
} ;
static const struct drm_exynos_ipp_limit rotator_4412_rbg888_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 8 , SZ_8K } , . v = { 8 , SZ_8K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 4 , . v . align = 4 ) } ,
} ;
static const struct drm_exynos_ipp_limit rotator_5250_rbg888_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 8 , SZ_8K } , . v = { 8 , SZ_8K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 2 , . v . align = 2 ) } ,
} ;
2018-12-19 16:57:02 +01:00
static const struct drm_exynos_ipp_limit rotator_s5pv210_yuv_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 32 , SZ_64K } , . v = { 32 , SZ_64K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 8 , . v . align = 8 ) } ,
} ;
2018-05-09 10:59:23 +02:00
static const struct drm_exynos_ipp_limit rotator_4210_yuv_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 32 , SZ_64K } , . v = { 32 , SZ_64K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 8 , . v . align = 8 ) } ,
} ;
static const struct drm_exynos_ipp_limit rotator_4412_yuv_limits [ ] = {
{ IPP_SIZE_LIMIT ( BUFFER , . h = { 32 , SZ_32K } , . v = { 32 , SZ_32K } ) } ,
{ IPP_SIZE_LIMIT ( AREA , . h . align = 8 , . v . align = 8 ) } ,
} ;
2018-12-19 16:57:02 +01:00
static const struct exynos_drm_ipp_formats rotator_s5pv210_formats [ ] = {
{ IPP_SRCDST_FORMAT ( XRGB8888 , rotator_s5pv210_rbg888_limits ) } ,
{ IPP_SRCDST_FORMAT ( NV12 , rotator_s5pv210_yuv_limits ) } ,
} ;
2018-05-09 10:59:23 +02:00
static const struct exynos_drm_ipp_formats rotator_4210_formats [ ] = {
{ IPP_SRCDST_FORMAT ( XRGB8888 , rotator_4210_rbg888_limits ) } ,
{ IPP_SRCDST_FORMAT ( NV12 , rotator_4210_yuv_limits ) } ,
} ;
static const struct exynos_drm_ipp_formats rotator_4412_formats [ ] = {
{ IPP_SRCDST_FORMAT ( XRGB8888 , rotator_4412_rbg888_limits ) } ,
{ IPP_SRCDST_FORMAT ( NV12 , rotator_4412_yuv_limits ) } ,
} ;
static const struct exynos_drm_ipp_formats rotator_5250_formats [ ] = {
{ IPP_SRCDST_FORMAT ( XRGB8888 , rotator_5250_rbg888_limits ) } ,
{ IPP_SRCDST_FORMAT ( NV12 , rotator_4412_yuv_limits ) } ,
} ;
2018-12-19 16:57:02 +01:00
static const struct rot_variant rotator_s5pv210_data = {
. formats = rotator_s5pv210_formats ,
. num_formats = ARRAY_SIZE ( rotator_s5pv210_formats ) ,
} ;
2018-05-09 10:59:23 +02:00
static const struct rot_variant rotator_4210_data = {
. formats = rotator_4210_formats ,
. num_formats = ARRAY_SIZE ( rotator_4210_formats ) ,
} ;
static const struct rot_variant rotator_4412_data = {
. formats = rotator_4412_formats ,
. num_formats = ARRAY_SIZE ( rotator_4412_formats ) ,
} ;
static const struct rot_variant rotator_5250_data = {
. formats = rotator_5250_formats ,
. num_formats = ARRAY_SIZE ( rotator_5250_formats ) ,
} ;
static const struct of_device_id exynos_rotator_match [ ] = {
{
2018-12-19 16:57:02 +01:00
. compatible = " samsung,s5pv210-rotator " ,
. data = & rotator_s5pv210_data ,
} , {
2018-05-09 10:59:23 +02:00
. compatible = " samsung,exynos4210-rotator " ,
. data = & rotator_4210_data ,
} , {
. compatible = " samsung,exynos4212-rotator " ,
. data = & rotator_4412_data ,
} , {
. compatible = " samsung,exynos5250-rotator " ,
. data = & rotator_5250_data ,
} , {
} ,
} ;
MODULE_DEVICE_TABLE ( of , exynos_rotator_match ) ;
2012-12-14 17:58:56 +09:00
static const struct dev_pm_ops rotator_pm_ops = {
2016-08-31 14:55:56 +02:00
SET_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend ,
pm_runtime_force_resume )
2012-12-14 17:58:56 +09:00
SET_RUNTIME_PM_OPS ( rotator_runtime_suspend , rotator_runtime_resume ,
NULL )
} ;
struct platform_driver rotator_driver = {
. probe = rotator_probe ,
2012-12-21 15:09:25 -08:00
. remove = rotator_remove ,
2012-12-14 17:58:56 +09:00
. driver = {
2018-05-09 10:59:23 +02:00
. name = " exynos-rotator " ,
2012-12-14 17:58:56 +09:00
. owner = THIS_MODULE ,
. pm = & rotator_pm_ops ,
2013-08-13 14:12:56 +09:00
. of_match_table = exynos_rotator_match ,
2012-12-14 17:58:56 +09:00
} ,
} ;