2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-01-03 14:07:30 +03:00
/*
* Driver for SiliconFile NOON010PC30 CIF ( 1 / 11 " ) Image Sensor with ISP
*
2011-09-16 19:33:08 +04:00
* Copyright ( C ) 2010 - 2011 Samsung Electronics Co . , Ltd .
2011-01-03 14:07:30 +03:00
* Contact : Sylwester Nawrocki , < s . nawrocki @ samsung . com >
*
* Initial register configuration based on a driver authored by
* HeungJun Kim < riverful . kim @ samsung . com > .
*/
# include <linux/delay.h>
2022-02-24 03:11:29 +03:00
# include <linux/gpio/consumer.h>
2011-01-03 14:07:30 +03:00
# include <linux/i2c.h>
# include <linux/slab.h>
# include <linux/regulator/consumer.h>
2015-11-10 17:01:44 +03:00
# include <media/i2c/noon010pc30.h>
2011-01-03 14:07:30 +03:00
# include <linux/videodev2.h>
2011-07-03 22:03:12 +04:00
# include <linux/module.h>
2011-01-03 14:07:30 +03:00
# include <media/v4l2-ctrls.h>
# include <media/v4l2-device.h>
# include <media/v4l2-mediabus.h>
# include <media/v4l2-subdev.h>
static int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Enable module debug trace. Set to 1 to enable. " ) ;
# define MODULE_NAME "NOON010PC30"
/*
* Register offsets within a page
* b15 . . b8 - page id , b7 . . b0 - register address
*/
# define POWER_CTRL_REG 0x0001
# define PAGEMODE_REG 0x03
# define DEVICE_ID_REG 0x0004
# define NOON010PC30_ID 0x86
# define VDO_CTL_REG(n) (0x0010 + (n))
# define SYNC_CTL_REG 0x0012
/* Window size and position */
# define WIN_ROWH_REG 0x0013
# define WIN_ROWL_REG 0x0014
# define WIN_COLH_REG 0x0015
# define WIN_COLL_REG 0x0016
# define WIN_HEIGHTH_REG 0x0017
# define WIN_HEIGHTL_REG 0x0018
# define WIN_WIDTHH_REG 0x0019
# define WIN_WIDTHL_REG 0x001A
# define HBLANKH_REG 0x001B
# define HBLANKL_REG 0x001C
# define VSYNCH_REG 0x001D
# define VSYNCL_REG 0x001E
/* VSYNC control */
# define VS_CTL_REG(n) (0x00A1 + (n))
/* page 1 */
# define ISP_CTL_REG(n) (0x0110 + (n))
# define YOFS_REG 0x0119
# define DARK_YOFS_REG 0x011A
# define SAT_CTL_REG 0x0120
# define BSAT_REG 0x0121
# define RSAT_REG 0x0122
/* Color correction */
# define CMC_CTL_REG 0x0130
# define CMC_OFSGH_REG 0x0133
# define CMC_OFSGL_REG 0x0135
# define CMC_SIGN_REG 0x0136
# define CMC_GOFS_REG 0x0137
# define CMC_COEF_REG(n) (0x0138 + (n))
# define CMC_OFS_REG(n) (0x0141 + (n))
/* Gamma correction */
# define GMA_CTL_REG 0x0160
# define GMA_COEF_REG(n) (0x0161 + (n))
/* Lens Shading */
# define LENS_CTRL_REG 0x01D0
# define LENS_XCEN_REG 0x01D1
# define LENS_YCEN_REG 0x01D2
# define LENS_RC_REG 0x01D3
# define LENS_GC_REG 0x01D4
# define LENS_BC_REG 0x01D5
# define L_AGON_REG 0x01D6
# define L_AGOFF_REG 0x01D7
/* Page 3 - Auto Exposure */
# define AE_CTL_REG(n) (0x0310 + (n))
# define AE_CTL9_REG 0x032C
# define AE_CTL10_REG 0x032D
# define AE_YLVL_REG 0x031C
# define AE_YTH_REG(n) (0x031D + (n))
# define AE_WGT_REG 0x0326
# define EXP_TIMEH_REG 0x0333
# define EXP_TIMEM_REG 0x0334
# define EXP_TIMEL_REG 0x0335
# define EXP_MMINH_REG 0x0336
# define EXP_MMINL_REG 0x0337
# define EXP_MMAXH_REG 0x0338
# define EXP_MMAXM_REG 0x0339
# define EXP_MMAXL_REG 0x033A
/* Page 4 - Auto White Balance */
# define AWB_CTL_REG(n) (0x0410 + (n))
# define AWB_ENABE 0x80
# define AWB_WGHT_REG 0x0419
# define BGAIN_PAR_REG(n) (0x044F + (n))
/* Manual white balance, when AWB_CTL2[0]=1 */
# define MWB_RGAIN_REG 0x0466
# define MWB_BGAIN_REG 0x0467
/* The token to mark an array end */
# define REG_TERM 0xFFFF
struct noon010_format {
2014-11-10 20:28:29 +03:00
u32 code ;
2011-01-03 14:07:30 +03:00
enum v4l2_colorspace colorspace ;
u16 ispctl1_reg ;
} ;
struct noon010_frmsize {
u16 width ;
u16 height ;
int vid_ctl1 ;
} ;
static const char * const noon010_supply_name [ ] = {
" vdd_core " , " vddio " , " vdda "
} ;
# define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name)
struct noon010_info {
struct v4l2_subdev sd ;
2011-09-16 19:33:08 +04:00
struct media_pad pad ;
2011-01-03 14:07:30 +03:00
struct v4l2_ctrl_handler hdl ;
2011-09-16 19:33:08 +04:00
struct regulator_bulk_data supply [ NOON010_NUM_SUPPLIES ] ;
2022-02-24 03:11:29 +03:00
struct gpio_desc * reset ;
struct gpio_desc * stby ;
2011-09-16 19:33:08 +04:00
/* Protects the struct members below */
struct mutex lock ;
2011-01-03 14:07:30 +03:00
const struct noon010_format * curr_fmt ;
const struct noon010_frmsize * curr_win ;
2011-09-16 19:33:08 +04:00
unsigned int apply_new_cfg : 1 ;
unsigned int streaming : 1 ;
2011-01-03 14:07:30 +03:00
unsigned int hflip : 1 ;
unsigned int vflip : 1 ;
unsigned int power : 1 ;
u8 i2c_reg_page ;
} ;
struct i2c_regval {
u16 addr ;
u16 val ;
} ;
/* Supported resolutions. */
static const struct noon010_frmsize noon010_sizes [ ] = {
{
. width = 352 ,
. height = 288 ,
. vid_ctl1 = 0 ,
} , {
. width = 176 ,
. height = 144 ,
. vid_ctl1 = 0x10 ,
} , {
. width = 88 ,
. height = 72 ,
. vid_ctl1 = 0x20 ,
} ,
} ;
/* Supported pixel formats. */
static const struct noon010_format noon010_formats [ ] = {
{
2014-11-10 20:28:29 +03:00
. code = MEDIA_BUS_FMT_YUYV8_2X8 ,
2011-01-03 14:07:30 +03:00
. colorspace = V4L2_COLORSPACE_JPEG ,
. ispctl1_reg = 0x03 ,
} , {
2014-11-10 20:28:29 +03:00
. code = MEDIA_BUS_FMT_YVYU8_2X8 ,
2011-01-03 14:07:30 +03:00
. colorspace = V4L2_COLORSPACE_JPEG ,
. ispctl1_reg = 0x02 ,
} , {
2014-11-10 20:28:29 +03:00
. code = MEDIA_BUS_FMT_VYUY8_2X8 ,
2011-01-03 14:07:30 +03:00
. colorspace = V4L2_COLORSPACE_JPEG ,
. ispctl1_reg = 0 ,
} , {
2014-11-10 20:28:29 +03:00
. code = MEDIA_BUS_FMT_UYVY8_2X8 ,
2011-01-03 14:07:30 +03:00
. colorspace = V4L2_COLORSPACE_JPEG ,
. ispctl1_reg = 0x01 ,
} , {
2014-11-10 20:28:29 +03:00
. code = MEDIA_BUS_FMT_RGB565_2X8_BE ,
2011-01-03 14:07:30 +03:00
. colorspace = V4L2_COLORSPACE_JPEG ,
. ispctl1_reg = 0x40 ,
} ,
} ;
static const struct i2c_regval noon010_base_regs [ ] = {
{ WIN_COLL_REG , 0x06 } , { HBLANKL_REG , 0x7C } ,
/* Color corection and saturation */
{ ISP_CTL_REG ( 0 ) , 0x30 } , { ISP_CTL_REG ( 2 ) , 0x30 } ,
{ YOFS_REG , 0x80 } , { DARK_YOFS_REG , 0x04 } ,
{ SAT_CTL_REG , 0x1F } , { BSAT_REG , 0x90 } ,
{ CMC_CTL_REG , 0x0F } , { CMC_OFSGH_REG , 0x3C } ,
{ CMC_OFSGL_REG , 0x2C } , { CMC_SIGN_REG , 0x3F } ,
{ CMC_COEF_REG ( 0 ) , 0x79 } , { CMC_OFS_REG ( 0 ) , 0x00 } ,
{ CMC_COEF_REG ( 1 ) , 0x39 } , { CMC_OFS_REG ( 1 ) , 0x00 } ,
{ CMC_COEF_REG ( 2 ) , 0x00 } , { CMC_OFS_REG ( 2 ) , 0x00 } ,
{ CMC_COEF_REG ( 3 ) , 0x11 } , { CMC_OFS_REG ( 3 ) , 0x8B } ,
{ CMC_COEF_REG ( 4 ) , 0x65 } , { CMC_OFS_REG ( 4 ) , 0x07 } ,
{ CMC_COEF_REG ( 5 ) , 0x14 } , { CMC_OFS_REG ( 5 ) , 0x04 } ,
{ CMC_COEF_REG ( 6 ) , 0x01 } , { CMC_OFS_REG ( 6 ) , 0x9C } ,
{ CMC_COEF_REG ( 7 ) , 0x33 } , { CMC_OFS_REG ( 7 ) , 0x89 } ,
{ CMC_COEF_REG ( 8 ) , 0x74 } , { CMC_OFS_REG ( 8 ) , 0x25 } ,
/* Automatic white balance */
{ AWB_CTL_REG ( 0 ) , 0x78 } , { AWB_CTL_REG ( 1 ) , 0x2E } ,
{ AWB_CTL_REG ( 2 ) , 0x20 } , { AWB_CTL_REG ( 3 ) , 0x85 } ,
/* Auto exposure */
{ AE_CTL_REG ( 0 ) , 0xDC } , { AE_CTL_REG ( 1 ) , 0x81 } ,
{ AE_CTL_REG ( 2 ) , 0x30 } , { AE_CTL_REG ( 3 ) , 0xA5 } ,
{ AE_CTL_REG ( 4 ) , 0x40 } , { AE_CTL_REG ( 5 ) , 0x51 } ,
{ AE_CTL_REG ( 6 ) , 0x33 } , { AE_CTL_REG ( 7 ) , 0x7E } ,
{ AE_CTL9_REG , 0x00 } , { AE_CTL10_REG , 0x02 } ,
{ AE_YLVL_REG , 0x44 } , { AE_YTH_REG ( 0 ) , 0x34 } ,
{ AE_YTH_REG ( 1 ) , 0x30 } , { AE_WGT_REG , 0xD5 } ,
/* Lens shading compensation */
{ LENS_CTRL_REG , 0x01 } , { LENS_XCEN_REG , 0x80 } ,
{ LENS_YCEN_REG , 0x70 } , { LENS_RC_REG , 0x53 } ,
{ LENS_GC_REG , 0x40 } , { LENS_BC_REG , 0x3E } ,
{ REG_TERM , 0 } ,
} ;
static inline struct noon010_info * to_noon010 ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct noon010_info , sd ) ;
}
static inline struct v4l2_subdev * to_sd ( struct v4l2_ctrl * ctrl )
{
return & container_of ( ctrl - > handler , struct noon010_info , hdl ) - > sd ;
}
static inline int set_i2c_page ( struct noon010_info * info ,
struct i2c_client * client , unsigned int reg )
{
u32 page = reg > > 8 & 0xFF ;
int ret = 0 ;
if ( info - > i2c_reg_page ! = page & & ( reg & 0xFF ) ! = 0x03 ) {
ret = i2c_smbus_write_byte_data ( client , PAGEMODE_REG , page ) ;
if ( ! ret )
info - > i2c_reg_page = page ;
}
return ret ;
}
static int cam_i2c_read ( struct v4l2_subdev * sd , u32 reg_addr )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct noon010_info * info = to_noon010 ( sd ) ;
int ret = set_i2c_page ( info , client , reg_addr ) ;
if ( ret )
return ret ;
return i2c_smbus_read_byte_data ( client , reg_addr & 0xFF ) ;
}
static int cam_i2c_write ( struct v4l2_subdev * sd , u32 reg_addr , u32 val )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct noon010_info * info = to_noon010 ( sd ) ;
int ret = set_i2c_page ( info , client , reg_addr ) ;
if ( ret )
return ret ;
return i2c_smbus_write_byte_data ( client , reg_addr & 0xFF , val ) ;
}
static inline int noon010_bulk_write_reg ( struct v4l2_subdev * sd ,
const struct i2c_regval * msg )
{
while ( msg - > addr ! = REG_TERM ) {
int ret = cam_i2c_write ( sd , msg - > addr , msg - > val ) ;
if ( ret )
return ret ;
msg + + ;
}
return 0 ;
}
/* Device reset and sleep mode control */
static int noon010_power_ctrl ( struct v4l2_subdev * sd , bool reset , bool sleep )
{
struct noon010_info * info = to_noon010 ( sd ) ;
u8 reg = sleep ? 0xF1 : 0xF0 ;
int ret = 0 ;
2011-09-12 17:34:03 +04:00
if ( reset ) {
2011-01-03 14:07:30 +03:00
ret = cam_i2c_write ( sd , POWER_CTRL_REG , reg | 0x02 ) ;
2011-09-12 17:34:03 +04:00
udelay ( 20 ) ;
}
2011-01-03 14:07:30 +03:00
if ( ! ret ) {
ret = cam_i2c_write ( sd , POWER_CTRL_REG , reg ) ;
if ( reset & & ! ret )
info - > i2c_reg_page = - 1 ;
}
return ret ;
}
/* Automatic white balance control */
static int noon010_enable_autowhitebalance ( struct v4l2_subdev * sd , int on )
{
int ret ;
ret = cam_i2c_write ( sd , AWB_CTL_REG ( 1 ) , on ? 0x2E : 0x2F ) ;
if ( ! ret )
ret = cam_i2c_write ( sd , AWB_CTL_REG ( 0 ) , on ? 0xFB : 0x7B ) ;
return ret ;
}
2011-09-16 19:33:08 +04:00
/* Called with struct noon010_info.lock mutex held */
2011-01-03 14:07:30 +03:00
static int noon010_set_flip ( struct v4l2_subdev * sd , int hflip , int vflip )
{
struct noon010_info * info = to_noon010 ( sd ) ;
int reg , ret ;
reg = cam_i2c_read ( sd , VDO_CTL_REG ( 1 ) ) ;
if ( reg < 0 )
return reg ;
reg & = 0x7C ;
if ( hflip )
reg | = 0x01 ;
if ( vflip )
reg | = 0x02 ;
ret = cam_i2c_write ( sd , VDO_CTL_REG ( 1 ) , reg | 0x80 ) ;
if ( ! ret ) {
info - > hflip = hflip ;
info - > vflip = vflip ;
}
return ret ;
}
/* Configure resolution and color format */
static int noon010_set_params ( struct v4l2_subdev * sd )
{
struct noon010_info * info = to_noon010 ( sd ) ;
2011-09-16 19:33:08 +04:00
int ret = cam_i2c_write ( sd , VDO_CTL_REG ( 0 ) ,
info - > curr_win - > vid_ctl1 ) ;
if ( ret )
return ret ;
return cam_i2c_write ( sd , ISP_CTL_REG ( 0 ) ,
info - > curr_fmt - > ispctl1_reg ) ;
2011-01-03 14:07:30 +03:00
}
/* Find nearest matching image pixel size. */
2011-09-16 19:33:08 +04:00
static int noon010_try_frame_size ( struct v4l2_mbus_framefmt * mf ,
const struct noon010_frmsize * * size )
2011-01-03 14:07:30 +03:00
{
unsigned int min_err = ~ 0 ;
int i = ARRAY_SIZE ( noon010_sizes ) ;
const struct noon010_frmsize * fsize = & noon010_sizes [ 0 ] ,
* match = NULL ;
while ( i - - ) {
int err = abs ( fsize - > width - mf - > width )
+ abs ( fsize - > height - mf - > height ) ;
if ( err < min_err ) {
min_err = err ;
match = fsize ;
}
fsize + + ;
}
if ( match ) {
mf - > width = match - > width ;
mf - > height = match - > height ;
2011-09-16 19:33:08 +04:00
if ( size )
* size = match ;
2011-01-03 14:07:30 +03:00
return 0 ;
}
return - EINVAL ;
}
2011-09-16 19:33:08 +04:00
/* Called with info.lock mutex held */
2011-01-03 14:07:30 +03:00
static int power_enable ( struct noon010_info * info )
{
int ret ;
if ( info - > power ) {
v4l2_info ( & info - > sd , " %s: sensor is already on \n " , __func__ ) ;
return 0 ;
}
2022-02-24 03:11:29 +03:00
/* Assert standby: line should be flagged active low in descriptor */
if ( info - > stby )
gpiod_set_value ( info - > stby , 1 ) ;
2011-01-03 14:07:30 +03:00
2022-02-24 03:11:29 +03:00
/* Assert reset: line should be flagged active low in descriptor */
if ( info - > reset )
gpiod_set_value ( info - > reset , 1 ) ;
2011-01-03 14:07:30 +03:00
ret = regulator_bulk_enable ( NOON010_NUM_SUPPLIES , info - > supply ) ;
if ( ret )
return ret ;
2022-02-24 03:11:29 +03:00
/* De-assert reset and standby */
if ( info - > reset ) {
2011-01-03 14:07:30 +03:00
msleep ( 50 ) ;
2022-02-24 03:11:29 +03:00
gpiod_set_value ( info - > reset , 0 ) ;
2011-01-03 14:07:30 +03:00
}
2022-02-24 03:11:29 +03:00
if ( info - > stby ) {
2011-01-03 14:07:30 +03:00
udelay ( 1000 ) ;
2022-02-24 03:11:29 +03:00
gpiod_set_value ( info - > stby , 0 ) ;
2011-01-03 14:07:30 +03:00
}
2022-02-24 03:11:29 +03:00
/* Cycle reset: assert and deassert */
if ( info - > reset ) {
2011-01-03 14:07:30 +03:00
udelay ( 1000 ) ;
2022-02-24 03:11:29 +03:00
gpiod_set_value ( info - > reset , 1 ) ;
2011-01-03 14:07:30 +03:00
msleep ( 100 ) ;
2022-02-24 03:11:29 +03:00
gpiod_set_value ( info - > reset , 0 ) ;
2011-01-03 14:07:30 +03:00
msleep ( 20 ) ;
}
info - > power = 1 ;
v4l2_dbg ( 1 , debug , & info - > sd , " %s: sensor is on \n " , __func__ ) ;
return 0 ;
}
2011-09-16 19:33:08 +04:00
/* Called with info.lock mutex held */
2011-01-03 14:07:30 +03:00
static int power_disable ( struct noon010_info * info )
{
int ret ;
if ( ! info - > power ) {
v4l2_info ( & info - > sd , " %s: sensor is already off \n " , __func__ ) ;
return 0 ;
}
ret = regulator_bulk_disable ( NOON010_NUM_SUPPLIES , info - > supply ) ;
if ( ret )
return ret ;
2022-02-24 03:11:29 +03:00
/* Assert standby and reset */
if ( info - > stby )
gpiod_set_value ( info - > stby , 1 ) ;
2011-01-03 14:07:30 +03:00
2022-02-24 03:11:29 +03:00
if ( info - > reset )
gpiod_set_value ( info - > reset , 1 ) ;
2011-01-03 14:07:30 +03:00
info - > power = 0 ;
v4l2_dbg ( 1 , debug , & info - > sd , " %s: sensor is off \n " , __func__ ) ;
return 0 ;
}
static int noon010_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct v4l2_subdev * sd = to_sd ( ctrl ) ;
2011-09-16 19:33:08 +04:00
struct noon010_info * info = to_noon010 ( sd ) ;
int ret = 0 ;
2011-01-03 14:07:30 +03:00
v4l2_dbg ( 1 , debug , sd , " %s: ctrl_id: %d, value: %d \n " ,
__func__ , ctrl - > id , ctrl - > val ) ;
2011-09-16 19:33:08 +04:00
mutex_lock ( & info - > lock ) ;
/*
* If the device is not powered up by the host driver do
* not apply any controls to H / W at this time . Instead
* the controls will be restored right after power - up .
*/
if ( ! info - > power )
goto unlock ;
2011-01-03 14:07:30 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_AUTO_WHITE_BALANCE :
2011-09-16 19:33:08 +04:00
ret = noon010_enable_autowhitebalance ( sd , ctrl - > val ) ;
break ;
2011-01-03 14:07:30 +03:00
case V4L2_CID_BLUE_BALANCE :
2011-09-16 19:33:08 +04:00
ret = cam_i2c_write ( sd , MWB_BGAIN_REG , ctrl - > val ) ;
break ;
2011-01-03 14:07:30 +03:00
case V4L2_CID_RED_BALANCE :
2011-09-16 19:33:08 +04:00
ret = cam_i2c_write ( sd , MWB_RGAIN_REG , ctrl - > val ) ;
break ;
2011-01-03 14:07:30 +03:00
default :
2011-09-16 19:33:08 +04:00
ret = - EINVAL ;
2011-01-03 14:07:30 +03:00
}
2011-09-16 19:33:08 +04:00
unlock :
mutex_unlock ( & info - > lock ) ;
return ret ;
2011-01-03 14:07:30 +03:00
}
2011-09-16 19:33:08 +04:00
static int noon010_enum_mbus_code ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-09-16 19:33:08 +04:00
struct v4l2_subdev_mbus_code_enum * code )
2011-01-03 14:07:30 +03:00
{
2011-09-16 19:33:08 +04:00
if ( code - > index > = ARRAY_SIZE ( noon010_formats ) )
2011-01-03 14:07:30 +03:00
return - EINVAL ;
2011-09-16 19:33:08 +04:00
code - > code = noon010_formats [ code - > index ] . code ;
2011-01-03 14:07:30 +03:00
return 0 ;
}
2015-03-04 12:47:54 +03:00
static int noon010_get_fmt ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-09-16 19:33:08 +04:00
struct v4l2_subdev_format * fmt )
2011-01-03 14:07:30 +03:00
{
struct noon010_info * info = to_noon010 ( sd ) ;
2011-09-16 19:33:08 +04:00
struct v4l2_mbus_framefmt * mf ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
if ( fmt - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
if ( sd_state ) {
mf = v4l2_subdev_get_try_format ( sd , sd_state , 0 ) ;
2011-09-16 19:33:08 +04:00
fmt - > format = * mf ;
}
return 0 ;
2011-01-03 14:07:30 +03:00
}
2011-09-16 19:33:08 +04:00
mf = & fmt - > format ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
mutex_lock ( & info - > lock ) ;
mf - > width = info - > curr_win - > width ;
mf - > height = info - > curr_win - > height ;
mf - > code = info - > curr_fmt - > code ;
mf - > colorspace = info - > curr_fmt - > colorspace ;
mf - > field = V4L2_FIELD_NONE ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
mutex_unlock ( & info - > lock ) ;
2011-01-03 14:07:30 +03:00
return 0 ;
}
/* Return nearest media bus frame format. */
2011-09-16 19:33:08 +04:00
static const struct noon010_format * noon010_try_fmt ( struct v4l2_subdev * sd ,
2011-01-03 14:07:30 +03:00
struct v4l2_mbus_framefmt * mf )
{
int i = ARRAY_SIZE ( noon010_formats ) ;
2011-09-16 19:33:08 +04:00
while ( - - i )
2011-01-03 14:07:30 +03:00
if ( mf - > code = = noon010_formats [ i ] . code )
break ;
mf - > code = noon010_formats [ i ] . code ;
return & noon010_formats [ i ] ;
}
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
static int noon010_set_fmt ( struct v4l2_subdev * sd ,
struct v4l2_subdev_state * sd_state ,
2011-09-16 19:33:08 +04:00
struct v4l2_subdev_format * fmt )
2011-01-03 14:07:30 +03:00
{
struct noon010_info * info = to_noon010 ( sd ) ;
2011-09-16 19:33:08 +04:00
const struct noon010_frmsize * size = NULL ;
const struct noon010_format * nf ;
struct v4l2_mbus_framefmt * mf ;
int ret = 0 ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
nf = noon010_try_fmt ( sd , & fmt - > format ) ;
noon010_try_frame_size ( & fmt - > format , & size ) ;
fmt - > format . colorspace = V4L2_COLORSPACE_JPEG ;
2014-05-19 19:04:32 +04:00
fmt - > format . field = V4L2_FIELD_NONE ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
if ( fmt - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
if ( sd_state ) {
mf = v4l2_subdev_get_try_format ( sd , sd_state , 0 ) ;
2011-09-16 19:33:08 +04:00
* mf = fmt - > format ;
}
return 0 ;
}
mutex_lock ( & info - > lock ) ;
if ( ! info - > streaming ) {
info - > apply_new_cfg = 1 ;
info - > curr_fmt = nf ;
info - > curr_win = size ;
} else {
ret = - EBUSY ;
}
mutex_unlock ( & info - > lock ) ;
return ret ;
2011-01-03 14:07:30 +03:00
}
2011-09-12 17:34:03 +04:00
/* Called with struct noon010_info.lock mutex held */
2011-01-03 14:07:30 +03:00
static int noon010_base_config ( struct v4l2_subdev * sd )
{
2011-09-12 17:34:03 +04:00
int ret = noon010_bulk_write_reg ( sd , noon010_base_regs ) ;
if ( ! ret )
2011-01-03 14:07:30 +03:00
ret = noon010_set_params ( sd ) ;
if ( ! ret )
ret = noon010_set_flip ( sd , 1 , 0 ) ;
return ret ;
}
static int noon010_s_power ( struct v4l2_subdev * sd , int on )
{
struct noon010_info * info = to_noon010 ( sd ) ;
2011-09-12 17:34:03 +04:00
int ret ;
2011-01-03 14:07:30 +03:00
2011-09-12 17:34:03 +04:00
mutex_lock ( & info - > lock ) ;
2011-01-03 14:07:30 +03:00
if ( on ) {
ret = power_enable ( info ) ;
2011-09-12 17:34:03 +04:00
if ( ! ret )
ret = noon010_base_config ( sd ) ;
2011-01-03 14:07:30 +03:00
} else {
noon010_power_ctrl ( sd , false , true ) ;
ret = power_disable ( info ) ;
}
2011-09-12 17:34:03 +04:00
mutex_unlock ( & info - > lock ) ;
/* Restore the controls state */
if ( ! ret & & on )
ret = v4l2_ctrl_handler_setup ( & info - > hdl ) ;
2011-01-03 14:07:30 +03:00
return ret ;
}
2011-09-16 19:33:08 +04:00
static int noon010_s_stream ( struct v4l2_subdev * sd , int on )
{
struct noon010_info * info = to_noon010 ( sd ) ;
int ret = 0 ;
mutex_lock ( & info - > lock ) ;
if ( ! info - > streaming ! = ! on ) {
ret = noon010_power_ctrl ( sd , false , ! on ) ;
if ( ! ret )
info - > streaming = on ;
}
if ( ! ret & & on & & info - > apply_new_cfg ) {
ret = noon010_set_params ( sd ) ;
if ( ! ret )
info - > apply_new_cfg = 0 ;
}
mutex_unlock ( & info - > lock ) ;
return ret ;
}
2011-01-03 14:07:30 +03:00
static int noon010_log_status ( struct v4l2_subdev * sd )
{
struct noon010_info * info = to_noon010 ( sd ) ;
v4l2_ctrl_handler_log_status ( & info - > hdl , sd - > name ) ;
return 0 ;
}
2011-09-16 19:33:08 +04:00
static int noon010_open ( struct v4l2_subdev * sd , struct v4l2_subdev_fh * fh )
{
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_mbus_framefmt * mf = v4l2_subdev_get_try_format ( sd ,
fh - > state ,
0 ) ;
2011-09-16 19:33:08 +04:00
mf - > width = noon010_sizes [ 0 ] . width ;
mf - > height = noon010_sizes [ 0 ] . height ;
mf - > code = noon010_formats [ 0 ] . code ;
mf - > colorspace = V4L2_COLORSPACE_JPEG ;
mf - > field = V4L2_FIELD_NONE ;
return 0 ;
}
static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = {
. open = noon010_open ,
} ;
2011-01-03 14:07:30 +03:00
static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
. s_ctrl = noon010_s_ctrl ,
} ;
static const struct v4l2_subdev_core_ops noon010_core_ops = {
. s_power = noon010_s_power ,
. log_status = noon010_log_status ,
} ;
2016-12-12 10:45:32 +03:00
static const struct v4l2_subdev_pad_ops noon010_pad_ops = {
2011-09-16 19:33:08 +04:00
. enum_mbus_code = noon010_enum_mbus_code ,
. get_fmt = noon010_get_fmt ,
. set_fmt = noon010_set_fmt ,
} ;
2016-12-12 10:45:32 +03:00
static const struct v4l2_subdev_video_ops noon010_video_ops = {
2011-09-16 19:33:08 +04:00
. s_stream = noon010_s_stream ,
2011-01-03 14:07:30 +03:00
} ;
static const struct v4l2_subdev_ops noon010_ops = {
. core = & noon010_core_ops ,
2011-09-16 19:33:08 +04:00
. pad = & noon010_pad_ops ,
2011-01-03 14:07:30 +03:00
. video = & noon010_video_ops ,
} ;
/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */
static int noon010_detect ( struct i2c_client * client , struct noon010_info * info )
{
int ret ;
ret = power_enable ( info ) ;
if ( ret )
return ret ;
ret = i2c_smbus_read_byte_data ( client , DEVICE_ID_REG ) ;
if ( ret < 0 )
dev_err ( & client - > dev , " I2C read failed: 0x%X \n " , ret ) ;
power_disable ( info ) ;
return ret = = NOON010PC30_ID ? 0 : - ENODEV ;
}
static int noon010_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct noon010_info * info ;
struct v4l2_subdev * sd ;
const struct noon010pc30_platform_data * pdata
= client - > dev . platform_data ;
int ret ;
int i ;
if ( ! pdata ) {
dev_err ( & client - > dev , " No platform data! \n " ) ;
return - EIO ;
}
2013-05-02 15:29:43 +04:00
info = devm_kzalloc ( & client - > dev , sizeof ( * info ) , GFP_KERNEL ) ;
2011-01-03 14:07:30 +03:00
if ( ! info )
return - ENOMEM ;
2011-09-16 19:33:08 +04:00
mutex_init ( & info - > lock ) ;
2011-01-03 14:07:30 +03:00
sd = & info - > sd ;
v4l2_i2c_subdev_init ( sd , client , & noon010_ops ) ;
2018-09-24 17:24:43 +03:00
/* Static name; NEVER use in new drivers! */
2018-09-10 15:19:14 +03:00
strscpy ( sd - > name , MODULE_NAME , sizeof ( sd - > name ) ) ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
sd - > internal_ops = & noon010_subdev_internal_ops ;
sd - > flags | = V4L2_SUBDEV_FL_HAS_DEVNODE ;
2011-01-03 14:07:30 +03:00
v4l2_ctrl_handler_init ( & info - > hdl , 3 ) ;
v4l2_ctrl_new_std ( & info - > hdl , & noon010_ctrl_ops ,
V4L2_CID_AUTO_WHITE_BALANCE , 0 , 1 , 1 , 1 ) ;
v4l2_ctrl_new_std ( & info - > hdl , & noon010_ctrl_ops ,
V4L2_CID_RED_BALANCE , 0 , 127 , 1 , 64 ) ;
v4l2_ctrl_new_std ( & info - > hdl , & noon010_ctrl_ops ,
V4L2_CID_BLUE_BALANCE , 0 , 127 , 1 , 64 ) ;
sd - > ctrl_handler = & info - > hdl ;
ret = info - > hdl . error ;
if ( ret )
goto np_err ;
info - > i2c_reg_page = - 1 ;
2011-09-12 17:34:03 +04:00
info - > curr_fmt = & noon010_formats [ 0 ] ;
info - > curr_win = & noon010_sizes [ 0 ] ;
2011-01-03 14:07:30 +03:00
2022-02-24 03:11:29 +03:00
/* Request reset asserted so we get put into reset */
info - > reset = devm_gpiod_get ( & client - > dev , " reset " , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( info - > reset ) ) {
ret = PTR_ERR ( info - > reset ) ;
goto np_err ;
2011-01-03 14:07:30 +03:00
}
2022-02-24 03:11:29 +03:00
gpiod_set_consumer_name ( info - > reset , " NOON010PC30 NRST " ) ;
2011-01-03 14:07:30 +03:00
2022-02-24 03:11:29 +03:00
/* Request standby asserted so we get put into standby */
info - > stby = devm_gpiod_get ( & client - > dev , " standby " , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( info - > stby ) ) {
ret = PTR_ERR ( info - > stby ) ;
goto np_err ;
2011-01-03 14:07:30 +03:00
}
2022-02-24 03:11:29 +03:00
gpiod_set_consumer_name ( info - > reset , " NOON010PC30 STBY " ) ;
2011-01-03 14:07:30 +03:00
for ( i = 0 ; i < NOON010_NUM_SUPPLIES ; i + + )
info - > supply [ i ] . supply = noon010_supply_name [ i ] ;
2013-05-02 15:29:43 +04:00
ret = devm_regulator_bulk_get ( & client - > dev , NOON010_NUM_SUPPLIES ,
2011-01-03 14:07:30 +03:00
info - > supply ) ;
if ( ret )
2013-05-02 15:29:43 +04:00
goto np_err ;
2011-01-03 14:07:30 +03:00
2011-09-16 19:33:08 +04:00
info - > pad . flags = MEDIA_PAD_FL_SOURCE ;
2015-12-10 22:25:41 +03:00
sd - > entity . function = MEDIA_ENT_F_CAM_SENSOR ;
2015-12-11 12:44:40 +03:00
ret = media_entity_pads_init ( & sd - > entity , 1 , & info - > pad ) ;
2011-09-16 19:33:08 +04:00
if ( ret < 0 )
2013-05-02 15:29:43 +04:00
goto np_err ;
2011-09-16 19:33:08 +04:00
2011-01-03 14:07:30 +03:00
ret = noon010_detect ( client , info ) ;
if ( ! ret )
return 0 ;
np_err :
v4l2_ctrl_handler_free ( & info - > hdl ) ;
v4l2_device_unregister_subdev ( sd ) ;
return ret ;
}
static int noon010_remove ( struct i2c_client * client )
{
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
struct noon010_info * info = to_noon010 ( sd ) ;
v4l2_device_unregister_subdev ( sd ) ;
v4l2_ctrl_handler_free ( & info - > hdl ) ;
2011-09-16 19:33:08 +04:00
media_entity_cleanup ( & sd - > entity ) ;
2013-05-02 15:29:43 +04:00
2011-01-03 14:07:30 +03:00
return 0 ;
}
static const struct i2c_device_id noon010_id [ ] = {
{ MODULE_NAME , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , noon010_id ) ;
static struct i2c_driver noon010_i2c_driver = {
. driver = {
. name = MODULE_NAME
} ,
. probe = noon010_probe ,
. remove = noon010_remove ,
. id_table = noon010_id ,
} ;
2012-02-12 13:56:32 +04:00
module_i2c_driver ( noon010_i2c_driver ) ;
2011-01-03 14:07:30 +03:00
MODULE_DESCRIPTION ( " Siliconfile NOON010PC30 camera driver " ) ;
MODULE_AUTHOR ( " Sylwester Nawrocki <s.nawrocki@samsung.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;