2013-06-04 11:22:30 -03:00
/*
* vsp1_rwpf . c - - R - Car VSP1 Read and Write Pixel Formatters
*
2014-02-06 14:42:31 -03:00
* Copyright ( C ) 2013 - 2014 Renesas Electronics Corporation
2013-06-04 11:22:30 -03:00
*
* Contact : Laurent Pinchart ( laurent . pinchart @ ideasonboard . com )
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <media/v4l2-subdev.h>
# include "vsp1.h"
# include "vsp1_rwpf.h"
# include "vsp1_video.h"
# define RWPF_MIN_WIDTH 1
# define RWPF_MIN_HEIGHT 1
2015-11-22 13:37:45 -02:00
struct v4l2_rect * vsp1_rwpf_get_crop ( struct vsp1_rwpf * rwpf ,
struct v4l2_subdev_pad_config * config )
{
return v4l2_subdev_get_try_crop ( & rwpf - > entity . subdev , config ,
RWPF_PAD_SINK ) ;
}
2013-06-04 11:22:30 -03:00
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Pad Operations
*/
2015-11-22 13:37:45 -02:00
static int vsp1_rwpf_enum_mbus_code ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_mbus_code_enum * code )
2013-06-04 11:22:30 -03:00
{
static const unsigned int codes [ ] = {
2014-11-10 14:28:31 -03:00
MEDIA_BUS_FMT_ARGB8888_1X32 ,
MEDIA_BUS_FMT_AYUV8_1X32 ,
2013-06-04 11:22:30 -03:00
} ;
if ( code - > index > = ARRAY_SIZE ( codes ) )
return - EINVAL ;
code - > code = codes [ code - > index ] ;
return 0 ;
}
2015-11-22 13:37:45 -02:00
static int vsp1_rwpf_enum_frame_size ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_frame_size_enum * fse )
2013-06-04 11:22:30 -03:00
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
2016-02-24 20:25:42 -03:00
return vsp1_subdev_enum_frame_size ( subdev , cfg , fse , RWPF_MIN_WIDTH ,
RWPF_MIN_HEIGHT , rwpf - > max_width ,
rwpf - > max_height ) ;
2013-06-04 11:22:30 -03:00
}
2015-11-22 13:37:45 -02:00
static int vsp1_rwpf_set_format ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_format * fmt )
2013-06-04 11:22:30 -03:00
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
2015-11-15 19:14:22 -02:00
struct v4l2_subdev_pad_config * config ;
2013-06-04 11:22:30 -03:00
struct v4l2_mbus_framefmt * format ;
2013-08-24 20:49:58 -03:00
struct v4l2_rect * crop ;
2016-06-26 08:09:31 -03:00
int ret = 0 ;
mutex_lock ( & rwpf - > entity . lock ) ;
2013-06-04 11:22:30 -03:00
2015-11-15 19:14:22 -02:00
config = vsp1_entity_get_pad_config ( & rwpf - > entity , cfg , fmt - > which ) ;
2016-06-26 08:09:31 -03:00
if ( ! config ) {
ret = - EINVAL ;
goto done ;
}
2015-11-15 19:14:22 -02:00
2013-06-04 11:22:30 -03:00
/* Default to YUV if the requested format is not supported. */
2014-11-10 14:28:31 -03:00
if ( fmt - > format . code ! = MEDIA_BUS_FMT_ARGB8888_1X32 & &
fmt - > format . code ! = MEDIA_BUS_FMT_AYUV8_1X32 )
fmt - > format . code = MEDIA_BUS_FMT_AYUV8_1X32 ;
2013-06-04 11:22:30 -03:00
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , config , fmt - > pad ) ;
2013-06-04 11:22:30 -03:00
if ( fmt - > pad = = RWPF_PAD_SOURCE ) {
/* The RWPF performs format conversion but can't scale, only the
* format code can be changed on the source pad .
*/
format - > code = fmt - > format . code ;
fmt - > format = * format ;
2016-06-26 08:09:31 -03:00
goto done ;
2013-06-04 11:22:30 -03:00
}
format - > code = fmt - > format . code ;
format - > width = clamp_t ( unsigned int , fmt - > format . width ,
RWPF_MIN_WIDTH , rwpf - > max_width ) ;
format - > height = clamp_t ( unsigned int , fmt - > format . height ,
RWPF_MIN_HEIGHT , rwpf - > max_height ) ;
format - > field = V4L2_FIELD_NONE ;
format - > colorspace = V4L2_COLORSPACE_SRGB ;
fmt - > format = * format ;
2013-08-24 20:49:58 -03:00
/* Update the sink crop rectangle. */
2015-11-15 19:14:22 -02:00
crop = vsp1_rwpf_get_crop ( rwpf , config ) ;
2013-08-24 20:49:58 -03:00
crop - > left = 0 ;
crop - > top = 0 ;
crop - > width = fmt - > format . width ;
crop - > height = fmt - > format . height ;
2013-06-04 11:22:30 -03:00
/* Propagate the format to the source pad. */
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , config ,
RWPF_PAD_SOURCE ) ;
2013-06-04 11:22:30 -03:00
* format = fmt - > format ;
2016-06-26 08:09:31 -03:00
done :
mutex_unlock ( & rwpf - > entity . lock ) ;
return ret ;
2013-06-04 11:22:30 -03:00
}
2013-08-24 20:49:58 -03:00
2015-11-22 13:37:45 -02:00
static int vsp1_rwpf_get_selection ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_selection * sel )
2013-08-24 20:49:58 -03:00
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
2015-11-15 19:14:22 -02:00
struct v4l2_subdev_pad_config * config ;
2013-08-24 20:49:58 -03:00
struct v4l2_mbus_framefmt * format ;
2016-06-26 08:09:31 -03:00
int ret = 0 ;
2013-08-24 20:49:58 -03:00
/* Cropping is implemented on the sink pad. */
if ( sel - > pad ! = RWPF_PAD_SINK )
return - EINVAL ;
2016-06-26 08:09:31 -03:00
mutex_lock ( & rwpf - > entity . lock ) ;
2015-11-15 19:14:22 -02:00
config = vsp1_entity_get_pad_config ( & rwpf - > entity , cfg , sel - > which ) ;
2016-06-26 08:09:31 -03:00
if ( ! config ) {
ret = - EINVAL ;
goto done ;
}
2015-11-15 19:14:22 -02:00
2013-08-24 20:49:58 -03:00
switch ( sel - > target ) {
case V4L2_SEL_TGT_CROP :
2015-11-15 19:14:22 -02:00
sel - > r = * vsp1_rwpf_get_crop ( rwpf , config ) ;
2013-08-24 20:49:58 -03:00
break ;
case V4L2_SEL_TGT_CROP_BOUNDS :
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , config ,
RWPF_PAD_SINK ) ;
2013-08-24 20:49:58 -03:00
sel - > r . left = 0 ;
sel - > r . top = 0 ;
sel - > r . width = format - > width ;
sel - > r . height = format - > height ;
break ;
default :
2016-06-26 08:09:31 -03:00
ret = - EINVAL ;
break ;
2013-08-24 20:49:58 -03:00
}
2016-06-26 08:09:31 -03:00
done :
mutex_unlock ( & rwpf - > entity . lock ) ;
return ret ;
2013-08-24 20:49:58 -03:00
}
2015-11-22 13:37:45 -02:00
static int vsp1_rwpf_set_selection ( struct v4l2_subdev * subdev ,
struct v4l2_subdev_pad_config * cfg ,
struct v4l2_subdev_selection * sel )
2013-08-24 20:49:58 -03:00
{
struct vsp1_rwpf * rwpf = to_rwpf ( subdev ) ;
2015-11-15 19:14:22 -02:00
struct v4l2_subdev_pad_config * config ;
2013-08-24 20:49:58 -03:00
struct v4l2_mbus_framefmt * format ;
struct v4l2_rect * crop ;
2016-06-26 08:09:31 -03:00
int ret = 0 ;
2013-08-24 20:49:58 -03:00
/* Cropping is implemented on the sink pad. */
if ( sel - > pad ! = RWPF_PAD_SINK )
return - EINVAL ;
if ( sel - > target ! = V4L2_SEL_TGT_CROP )
return - EINVAL ;
2016-06-26 08:09:31 -03:00
mutex_lock ( & rwpf - > entity . lock ) ;
2015-11-15 19:14:22 -02:00
config = vsp1_entity_get_pad_config ( & rwpf - > entity , cfg , sel - > which ) ;
2016-06-26 08:09:31 -03:00
if ( ! config ) {
ret = - EINVAL ;
goto done ;
}
2015-11-15 19:14:22 -02:00
2013-08-24 20:49:58 -03:00
/* Make sure the crop rectangle is entirely contained in the image. The
* WPF top and left offsets are limited to 255.
*/
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , config ,
RWPF_PAD_SINK ) ;
2015-05-28 09:59:39 -03:00
/* Restrict the crop rectangle coordinates to multiples of 2 to avoid
* shifting the color plane .
*/
if ( format - > code = = MEDIA_BUS_FMT_AYUV8_1X32 ) {
sel - > r . left = ALIGN ( sel - > r . left , 2 ) ;
sel - > r . top = ALIGN ( sel - > r . top , 2 ) ;
sel - > r . width = round_down ( sel - > r . width , 2 ) ;
sel - > r . height = round_down ( sel - > r . height , 2 ) ;
}
2013-08-24 20:49:58 -03:00
sel - > r . left = min_t ( unsigned int , sel - > r . left , format - > width - 2 ) ;
sel - > r . top = min_t ( unsigned int , sel - > r . top , format - > height - 2 ) ;
if ( rwpf - > entity . type = = VSP1_ENTITY_WPF ) {
sel - > r . left = min_t ( unsigned int , sel - > r . left , 255 ) ;
sel - > r . top = min_t ( unsigned int , sel - > r . top , 255 ) ;
}
sel - > r . width = min_t ( unsigned int , sel - > r . width ,
format - > width - sel - > r . left ) ;
sel - > r . height = min_t ( unsigned int , sel - > r . height ,
format - > height - sel - > r . top ) ;
2015-11-15 19:14:22 -02:00
crop = vsp1_rwpf_get_crop ( rwpf , config ) ;
2013-08-24 20:49:58 -03:00
* crop = sel - > r ;
/* Propagate the format to the source pad. */
2015-11-15 19:14:22 -02:00
format = vsp1_entity_get_pad_format ( & rwpf - > entity , config ,
RWPF_PAD_SOURCE ) ;
2013-08-24 20:49:58 -03:00
format - > width = crop - > width ;
format - > height = crop - > height ;
2016-06-26 08:09:31 -03:00
done :
mutex_unlock ( & rwpf - > entity . lock ) ;
return ret ;
2013-08-24 20:49:58 -03:00
}
2015-11-01 12:19:42 -02:00
2015-11-22 13:37:45 -02:00
const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
. init_cfg = vsp1_entity_init_cfg ,
. enum_mbus_code = vsp1_rwpf_enum_mbus_code ,
. enum_frame_size = vsp1_rwpf_enum_frame_size ,
2016-02-24 21:10:13 -03:00
. get_fmt = vsp1_subdev_get_pad_format ,
2015-11-22 13:37:45 -02:00
. set_fmt = vsp1_rwpf_set_format ,
. get_selection = vsp1_rwpf_get_selection ,
. set_selection = vsp1_rwpf_set_selection ,
} ;
2015-11-01 12:19:42 -02:00
/* -----------------------------------------------------------------------------
* Controls
*/
static int vsp1_rwpf_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct vsp1_rwpf * rwpf =
container_of ( ctrl - > handler , struct vsp1_rwpf , ctrls ) ;
switch ( ctrl - > id ) {
case V4L2_CID_ALPHA_COMPONENT :
rwpf - > alpha = ctrl - > val ;
break ;
}
return 0 ;
}
static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
. s_ctrl = vsp1_rwpf_s_ctrl ,
} ;
2016-05-26 05:14:22 -03:00
int vsp1_rwpf_init_ctrls ( struct vsp1_rwpf * rwpf , unsigned int ncontrols )
2015-11-01 12:19:42 -02:00
{
2016-05-26 05:14:22 -03:00
v4l2_ctrl_handler_init ( & rwpf - > ctrls , ncontrols + 1 ) ;
2015-11-01 12:19:42 -02:00
v4l2_ctrl_new_std ( & rwpf - > ctrls , & vsp1_rwpf_ctrl_ops ,
V4L2_CID_ALPHA_COMPONENT , 0 , 255 , 1 , 255 ) ;
rwpf - > entity . subdev . ctrl_handler = & rwpf - > ctrls ;
return rwpf - > ctrls . error ;
}