2018-07-03 10:08:03 -04:00
// SPDX-License-Identifier: GPL-2.0
/*
* Omnivision OV2680 CMOS Image Sensor driver
*
* Copyright ( C ) 2018 Linaro Ltd
*
* Based on OV5640 Sensor Driver
* Copyright ( C ) 2011 - 2013 Freescale Semiconductor , Inc . All Rights Reserved .
* Copyright ( C ) 2014 - 2017 Mentor Graphics Inc .
*
*/
# include <asm/unaligned.h>
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/gpio/consumer.h>
# include <linux/regulator/consumer.h>
# include <media/v4l2-common.h>
# include <media/v4l2-ctrls.h>
# include <media/v4l2-subdev.h>
# define OV2680_XVCLK_VALUE 24000000
# define OV2680_CHIP_ID 0x2680
# define OV2680_REG_STREAM_CTRL 0x0100
# define OV2680_REG_SOFT_RESET 0x0103
# define OV2680_REG_CHIP_ID_HIGH 0x300a
# define OV2680_REG_CHIP_ID_LOW 0x300b
# define OV2680_REG_R_MANUAL 0x3503
# define OV2680_REG_GAIN_PK 0x350a
# define OV2680_REG_EXPOSURE_PK_HIGH 0x3500
# define OV2680_REG_TIMING_HTS 0x380c
# define OV2680_REG_TIMING_VTS 0x380e
# define OV2680_REG_FORMAT1 0x3820
# define OV2680_REG_FORMAT2 0x3821
# define OV2680_REG_ISP_CTRL00 0x5080
# define OV2680_FRAME_RATE 30
# define OV2680_REG_VALUE_8BIT 1
# define OV2680_REG_VALUE_16BIT 2
# define OV2680_REG_VALUE_24BIT 3
# define OV2680_WIDTH_MAX 1600
# define OV2680_HEIGHT_MAX 1200
enum ov2680_mode_id {
OV2680_MODE_QUXGA_800_600 ,
OV2680_MODE_720P_1280_720 ,
OV2680_MODE_UXGA_1600_1200 ,
OV2680_MODE_MAX ,
} ;
struct reg_value {
u16 reg_addr ;
u8 val ;
} ;
static const char * const ov2680_supply_name [ ] = {
" DOVDD " ,
" DVDD " ,
" AVDD " ,
} ;
# define OV2680_NUM_SUPPLIES ARRAY_SIZE(ov2680_supply_name)
struct ov2680_mode_info {
const char * name ;
enum ov2680_mode_id id ;
u32 width ;
u32 height ;
const struct reg_value * reg_data ;
u32 reg_data_size ;
} ;
struct ov2680_ctrls {
struct v4l2_ctrl_handler handler ;
struct {
struct v4l2_ctrl * auto_exp ;
struct v4l2_ctrl * exposure ;
} ;
struct {
struct v4l2_ctrl * auto_gain ;
struct v4l2_ctrl * gain ;
} ;
struct v4l2_ctrl * hflip ;
struct v4l2_ctrl * vflip ;
struct v4l2_ctrl * test_pattern ;
} ;
struct ov2680_dev {
struct i2c_client * i2c_client ;
struct v4l2_subdev sd ;
struct media_pad pad ;
struct clk * xvclk ;
u32 xvclk_freq ;
struct regulator_bulk_data supplies [ OV2680_NUM_SUPPLIES ] ;
struct gpio_desc * reset_gpio ;
struct mutex lock ; /* protect members */
bool mode_pending_changes ;
bool is_enabled ;
bool is_streaming ;
struct ov2680_ctrls ctrls ;
struct v4l2_mbus_framefmt fmt ;
struct v4l2_fract frame_interval ;
const struct ov2680_mode_info * current_mode ;
} ;
static const char * const test_pattern_menu [ ] = {
" Disabled " ,
" Color Bars " ,
" Random Data " ,
" Square " ,
" Black Image " ,
} ;
static const int ov2680_hv_flip_bayer_order [ ] = {
MEDIA_BUS_FMT_SBGGR10_1X10 ,
MEDIA_BUS_FMT_SGRBG10_1X10 ,
MEDIA_BUS_FMT_SGBRG10_1X10 ,
MEDIA_BUS_FMT_SRGGB10_1X10 ,
} ;
static const struct reg_value ov2680_setting_30fps_QUXGA_800_600 [ ] = {
{ 0x3086 , 0x01 } , { 0x370a , 0x23 } , { 0x3808 , 0x03 } , { 0x3809 , 0x20 } ,
{ 0x380a , 0x02 } , { 0x380b , 0x58 } , { 0x380c , 0x06 } , { 0x380d , 0xac } ,
{ 0x380e , 0x02 } , { 0x380f , 0x84 } , { 0x3811 , 0x04 } , { 0x3813 , 0x04 } ,
{ 0x3814 , 0x31 } , { 0x3815 , 0x31 } , { 0x3820 , 0xc0 } , { 0x4008 , 0x00 } ,
{ 0x4009 , 0x03 } , { 0x4837 , 0x1e } , { 0x3501 , 0x4e } , { 0x3502 , 0xe0 } ,
} ;
static const struct reg_value ov2680_setting_30fps_720P_1280_720 [ ] = {
{ 0x3086 , 0x00 } , { 0x3808 , 0x05 } , { 0x3809 , 0x00 } , { 0x380a , 0x02 } ,
{ 0x380b , 0xd0 } , { 0x380c , 0x06 } , { 0x380d , 0xa8 } , { 0x380e , 0x05 } ,
{ 0x380f , 0x0e } , { 0x3811 , 0x08 } , { 0x3813 , 0x06 } , { 0x3814 , 0x11 } ,
{ 0x3815 , 0x11 } , { 0x3820 , 0xc0 } , { 0x4008 , 0x00 } ,
} ;
static const struct reg_value ov2680_setting_30fps_UXGA_1600_1200 [ ] = {
{ 0x3086 , 0x00 } , { 0x3501 , 0x4e } , { 0x3502 , 0xe0 } , { 0x3808 , 0x06 } ,
{ 0x3809 , 0x40 } , { 0x380a , 0x04 } , { 0x380b , 0xb0 } , { 0x380c , 0x06 } ,
{ 0x380d , 0xa8 } , { 0x380e , 0x05 } , { 0x380f , 0x0e } , { 0x3811 , 0x00 } ,
{ 0x3813 , 0x00 } , { 0x3814 , 0x11 } , { 0x3815 , 0x11 } , { 0x3820 , 0xc0 } ,
{ 0x4008 , 0x00 } , { 0x4837 , 0x18 }
} ;
static const struct ov2680_mode_info ov2680_mode_init_data = {
" mode_quxga_800_600 " , OV2680_MODE_QUXGA_800_600 , 800 , 600 ,
ov2680_setting_30fps_QUXGA_800_600 ,
ARRAY_SIZE ( ov2680_setting_30fps_QUXGA_800_600 ) ,
} ;
static const struct ov2680_mode_info ov2680_mode_data [ OV2680_MODE_MAX ] = {
{ " mode_quxga_800_600 " , OV2680_MODE_QUXGA_800_600 ,
800 , 600 , ov2680_setting_30fps_QUXGA_800_600 ,
ARRAY_SIZE ( ov2680_setting_30fps_QUXGA_800_600 ) } ,
{ " mode_720p_1280_720 " , OV2680_MODE_720P_1280_720 ,
1280 , 720 , ov2680_setting_30fps_720P_1280_720 ,
ARRAY_SIZE ( ov2680_setting_30fps_720P_1280_720 ) } ,
{ " mode_uxga_1600_1200 " , OV2680_MODE_UXGA_1600_1200 ,
1600 , 1200 , ov2680_setting_30fps_UXGA_1600_1200 ,
ARRAY_SIZE ( ov2680_setting_30fps_UXGA_1600_1200 ) } ,
} ;
static struct ov2680_dev * to_ov2680_dev ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct ov2680_dev , sd ) ;
}
static struct device * ov2680_to_dev ( struct ov2680_dev * sensor )
{
return & sensor - > i2c_client - > dev ;
}
static inline struct v4l2_subdev * ctrl_to_sd ( struct v4l2_ctrl * ctrl )
{
return & container_of ( ctrl - > handler , struct ov2680_dev ,
ctrls . handler ) - > sd ;
}
static int __ov2680_write_reg ( struct ov2680_dev * sensor , u16 reg ,
unsigned int len , u32 val )
{
struct i2c_client * client = sensor - > i2c_client ;
u8 buf [ 6 ] ;
int ret ;
if ( len > 4 )
return - EINVAL ;
put_unaligned_be16 ( reg , buf ) ;
put_unaligned_be32 ( val < < ( 8 * ( 4 - len ) ) , buf + 2 ) ;
ret = i2c_master_send ( client , buf , len + 2 ) ;
if ( ret ! = len + 2 ) {
dev_err ( & client - > dev , " write error: reg=0x%4x: %d \n " , reg , ret ) ;
return - EIO ;
}
return 0 ;
}
# define ov2680_write_reg(s, r, v) \
__ov2680_write_reg ( s , r , OV2680_REG_VALUE_8BIT , v )
# define ov2680_write_reg16(s, r, v) \
__ov2680_write_reg ( s , r , OV2680_REG_VALUE_16BIT , v )
# define ov2680_write_reg24(s, r, v) \
__ov2680_write_reg ( s , r , OV2680_REG_VALUE_24BIT , v )
static int __ov2680_read_reg ( struct ov2680_dev * sensor , u16 reg ,
unsigned int len , u32 * val )
{
struct i2c_client * client = sensor - > i2c_client ;
struct i2c_msg msgs [ 2 ] ;
u8 addr_buf [ 2 ] = { reg > > 8 , reg & 0xff } ;
u8 data_buf [ 4 ] = { 0 , } ;
int ret ;
if ( len > 4 )
return - EINVAL ;
msgs [ 0 ] . addr = client - > addr ;
msgs [ 0 ] . flags = 0 ;
msgs [ 0 ] . len = ARRAY_SIZE ( addr_buf ) ;
msgs [ 0 ] . buf = addr_buf ;
msgs [ 1 ] . addr = client - > addr ;
msgs [ 1 ] . flags = I2C_M_RD ;
msgs [ 1 ] . len = len ;
msgs [ 1 ] . buf = & data_buf [ 4 - len ] ;
ret = i2c_transfer ( client - > adapter , msgs , ARRAY_SIZE ( msgs ) ) ;
if ( ret ! = ARRAY_SIZE ( msgs ) ) {
dev_err ( & client - > dev , " read error: reg=0x%4x: %d \n " , reg , ret ) ;
return - EIO ;
}
* val = get_unaligned_be32 ( data_buf ) ;
return 0 ;
}
# define ov2680_read_reg(s, r, v) \
__ov2680_read_reg ( s , r , OV2680_REG_VALUE_8BIT , v )
# define ov2680_read_reg16(s, r, v) \
__ov2680_read_reg ( s , r , OV2680_REG_VALUE_16BIT , v )
# define ov2680_read_reg24(s, r, v) \
__ov2680_read_reg ( s , r , OV2680_REG_VALUE_24BIT , v )
static int ov2680_mod_reg ( struct ov2680_dev * sensor , u16 reg , u8 mask , u8 val )
{
u32 readval ;
int ret ;
ret = ov2680_read_reg ( sensor , reg , & readval ) ;
if ( ret < 0 )
return ret ;
readval & = ~ mask ;
val & = mask ;
val | = readval ;
return ov2680_write_reg ( sensor , reg , val ) ;
}
static int ov2680_load_regs ( struct ov2680_dev * sensor ,
const struct ov2680_mode_info * mode )
{
const struct reg_value * regs = mode - > reg_data ;
unsigned int i ;
int ret = 0 ;
u16 reg_addr ;
u8 val ;
for ( i = 0 ; i < mode - > reg_data_size ; + + i , + + regs ) {
reg_addr = regs - > reg_addr ;
val = regs - > val ;
ret = ov2680_write_reg ( sensor , reg_addr , val ) ;
if ( ret )
break ;
}
return ret ;
}
static void ov2680_power_up ( struct ov2680_dev * sensor )
{
if ( ! sensor - > reset_gpio )
return ;
gpiod_set_value ( sensor - > reset_gpio , 0 ) ;
usleep_range ( 5000 , 10000 ) ;
}
static void ov2680_power_down ( struct ov2680_dev * sensor )
{
if ( ! sensor - > reset_gpio )
return ;
gpiod_set_value ( sensor - > reset_gpio , 1 ) ;
usleep_range ( 5000 , 10000 ) ;
}
static int ov2680_bayer_order ( struct ov2680_dev * sensor )
{
u32 format1 ;
u32 format2 ;
u32 hv_flip ;
int ret ;
ret = ov2680_read_reg ( sensor , OV2680_REG_FORMAT1 , & format1 ) ;
if ( ret < 0 )
return ret ;
ret = ov2680_read_reg ( sensor , OV2680_REG_FORMAT2 , & format2 ) ;
if ( ret < 0 )
return ret ;
hv_flip = ( format2 & BIT ( 2 ) < < 1 ) | ( format1 & BIT ( 2 ) ) ;
sensor - > fmt . code = ov2680_hv_flip_bayer_order [ hv_flip ] ;
return 0 ;
}
static int ov2680_vflip_enable ( struct ov2680_dev * sensor )
{
int ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_FORMAT1 , BIT ( 2 ) , BIT ( 2 ) ) ;
if ( ret < 0 )
return ret ;
return ov2680_bayer_order ( sensor ) ;
}
static int ov2680_vflip_disable ( struct ov2680_dev * sensor )
{
int ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_FORMAT1 , BIT ( 2 ) , BIT ( 0 ) ) ;
if ( ret < 0 )
return ret ;
return ov2680_bayer_order ( sensor ) ;
}
static int ov2680_hflip_enable ( struct ov2680_dev * sensor )
{
int ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_FORMAT2 , BIT ( 2 ) , BIT ( 2 ) ) ;
if ( ret < 0 )
return ret ;
return ov2680_bayer_order ( sensor ) ;
}
static int ov2680_hflip_disable ( struct ov2680_dev * sensor )
{
int ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_FORMAT2 , BIT ( 2 ) , BIT ( 0 ) ) ;
if ( ret < 0 )
return ret ;
return ov2680_bayer_order ( sensor ) ;
}
static int ov2680_test_pattern_set ( struct ov2680_dev * sensor , int value )
{
int ret ;
if ( ! value )
return ov2680_mod_reg ( sensor , OV2680_REG_ISP_CTRL00 , BIT ( 7 ) , 0 ) ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_ISP_CTRL00 , 0x03 , value - 1 ) ;
if ( ret < 0 )
return ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_ISP_CTRL00 , BIT ( 7 ) , BIT ( 7 ) ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
static int ov2680_gain_set ( struct ov2680_dev * sensor , bool auto_gain )
{
struct ov2680_ctrls * ctrls = & sensor - > ctrls ;
u32 gain ;
int ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_R_MANUAL , BIT ( 1 ) ,
auto_gain ? 0 : BIT ( 1 ) ) ;
if ( ret < 0 )
return ret ;
if ( auto_gain | | ! ctrls - > gain - > is_new )
return 0 ;
gain = ctrls - > gain - > val ;
ret = ov2680_write_reg16 ( sensor , OV2680_REG_GAIN_PK , gain ) ;
return 0 ;
}
static int ov2680_gain_get ( struct ov2680_dev * sensor )
{
u32 gain ;
int ret ;
ret = ov2680_read_reg16 ( sensor , OV2680_REG_GAIN_PK , & gain ) ;
if ( ret )
return ret ;
return gain ;
}
static int ov2680_exposure_set ( struct ov2680_dev * sensor , bool auto_exp )
{
struct ov2680_ctrls * ctrls = & sensor - > ctrls ;
u32 exp ;
int ret ;
ret = ov2680_mod_reg ( sensor , OV2680_REG_R_MANUAL , BIT ( 0 ) ,
auto_exp ? 0 : BIT ( 0 ) ) ;
if ( ret < 0 )
return ret ;
if ( auto_exp | | ! ctrls - > exposure - > is_new )
return 0 ;
exp = ( u32 ) ctrls - > exposure - > val ;
exp < < = 4 ;
return ov2680_write_reg24 ( sensor , OV2680_REG_EXPOSURE_PK_HIGH , exp ) ;
}
static int ov2680_exposure_get ( struct ov2680_dev * sensor )
{
int ret ;
u32 exp ;
ret = ov2680_read_reg24 ( sensor , OV2680_REG_EXPOSURE_PK_HIGH , & exp ) ;
if ( ret )
return ret ;
return exp > > 4 ;
}
static int ov2680_stream_enable ( struct ov2680_dev * sensor )
{
return ov2680_write_reg ( sensor , OV2680_REG_STREAM_CTRL , 1 ) ;
}
static int ov2680_stream_disable ( struct ov2680_dev * sensor )
{
return ov2680_write_reg ( sensor , OV2680_REG_STREAM_CTRL , 0 ) ;
}
static int ov2680_mode_set ( struct ov2680_dev * sensor )
{
struct ov2680_ctrls * ctrls = & sensor - > ctrls ;
int ret ;
ret = ov2680_gain_set ( sensor , false ) ;
if ( ret < 0 )
return ret ;
ret = ov2680_exposure_set ( sensor , false ) ;
if ( ret < 0 )
return ret ;
ret = ov2680_load_regs ( sensor , sensor - > current_mode ) ;
if ( ret < 0 )
return ret ;
if ( ctrls - > auto_gain - > val ) {
ret = ov2680_gain_set ( sensor , true ) ;
if ( ret < 0 )
return ret ;
}
if ( ctrls - > auto_exp - > val = = V4L2_EXPOSURE_AUTO ) {
ret = ov2680_exposure_set ( sensor , true ) ;
if ( ret < 0 )
return ret ;
}
sensor - > mode_pending_changes = false ;
return 0 ;
}
static int ov2680_mode_restore ( struct ov2680_dev * sensor )
{
int ret ;
ret = ov2680_load_regs ( sensor , & ov2680_mode_init_data ) ;
if ( ret < 0 )
return ret ;
return ov2680_mode_set ( sensor ) ;
}
static int ov2680_power_off ( struct ov2680_dev * sensor )
{
if ( ! sensor - > is_enabled )
return 0 ;
clk_disable_unprepare ( sensor - > xvclk ) ;
ov2680_power_down ( sensor ) ;
regulator_bulk_disable ( OV2680_NUM_SUPPLIES , sensor - > supplies ) ;
sensor - > is_enabled = false ;
return 0 ;
}
static int ov2680_power_on ( struct ov2680_dev * sensor )
{
struct device * dev = ov2680_to_dev ( sensor ) ;
int ret ;
if ( sensor - > is_enabled )
return 0 ;
ret = regulator_bulk_enable ( OV2680_NUM_SUPPLIES , sensor - > supplies ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to enable regulators: %d \n " , ret ) ;
return ret ;
}
if ( ! sensor - > reset_gpio ) {
ret = ov2680_write_reg ( sensor , OV2680_REG_SOFT_RESET , 0x01 ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " sensor soft reset failed \n " ) ;
return ret ;
}
usleep_range ( 1000 , 2000 ) ;
} else {
ov2680_power_down ( sensor ) ;
ov2680_power_up ( sensor ) ;
}
ret = clk_prepare_enable ( sensor - > xvclk ) ;
if ( ret < 0 )
return ret ;
sensor - > is_enabled = true ;
/* Set clock lane into LP-11 state */
ov2680_stream_enable ( sensor ) ;
usleep_range ( 1000 , 2000 ) ;
ov2680_stream_disable ( sensor ) ;
return 0 ;
}
static int ov2680_s_power ( struct v4l2_subdev * sd , int on )
{
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
int ret = 0 ;
mutex_lock ( & sensor - > lock ) ;
if ( on )
ret = ov2680_power_on ( sensor ) ;
else
ret = ov2680_power_off ( sensor ) ;
mutex_unlock ( & sensor - > lock ) ;
if ( on & & ret = = 0 ) {
ret = v4l2_ctrl_handler_setup ( & sensor - > ctrls . handler ) ;
if ( ret < 0 )
return ret ;
2018-11-21 05:59:55 -05:00
ret = ov2680_mode_restore ( sensor ) ;
2018-07-03 10:08:03 -04:00
}
return ret ;
}
static int ov2680_s_g_frame_interval ( struct v4l2_subdev * sd ,
struct v4l2_subdev_frame_interval * fi )
{
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
mutex_lock ( & sensor - > lock ) ;
fi - > interval = sensor - > frame_interval ;
mutex_unlock ( & sensor - > lock ) ;
return 0 ;
}
static int ov2680_s_stream ( struct v4l2_subdev * sd , int enable )
{
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
int ret = 0 ;
mutex_lock ( & sensor - > lock ) ;
if ( sensor - > is_streaming = = ! ! enable )
goto unlock ;
if ( enable & & sensor - > mode_pending_changes ) {
ret = ov2680_mode_set ( sensor ) ;
if ( ret < 0 )
goto unlock ;
}
if ( enable )
ret = ov2680_stream_enable ( sensor ) ;
else
ret = ov2680_stream_disable ( sensor ) ;
sensor - > is_streaming = ! ! enable ;
unlock :
mutex_unlock ( & sensor - > lock ) ;
return ret ;
}
static int ov2680_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 ,
2018-07-03 10:08:03 -04:00
struct v4l2_subdev_mbus_code_enum * code )
{
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
if ( code - > pad ! = 0 | | code - > index ! = 0 )
return - EINVAL ;
code - > code = sensor - > fmt . code ;
return 0 ;
}
static int ov2680_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 ,
2018-07-03 10:08:03 -04:00
struct v4l2_subdev_format * format )
{
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
struct v4l2_mbus_framefmt * fmt = NULL ;
int ret = 0 ;
if ( format - > pad ! = 0 )
return - EINVAL ;
mutex_lock ( & sensor - > lock ) ;
if ( format - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
# ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
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
fmt = v4l2_subdev_get_try_format ( & sensor - > sd , sd_state ,
format - > pad ) ;
2018-07-03 10:08:03 -04:00
# else
2019-07-17 05:24:13 -04:00
ret = - EINVAL ;
2018-07-03 10:08:03 -04:00
# endif
} else {
fmt = & sensor - > fmt ;
}
if ( fmt )
format - > format = * fmt ;
mutex_unlock ( & sensor - > lock ) ;
return ret ;
}
static int ov2680_set_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 ,
2018-07-03 10:08:03 -04:00
struct v4l2_subdev_format * format )
{
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
struct v4l2_mbus_framefmt * fmt = & format - > format ;
# ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
struct v4l2_mbus_framefmt * try_fmt ;
# endif
const struct ov2680_mode_info * mode ;
int ret = 0 ;
if ( format - > pad ! = 0 )
return - EINVAL ;
mutex_lock ( & sensor - > lock ) ;
if ( sensor - > is_streaming ) {
ret = - EBUSY ;
goto unlock ;
}
mode = v4l2_find_nearest_size ( ov2680_mode_data ,
ARRAY_SIZE ( ov2680_mode_data ) , width ,
height , fmt - > width , fmt - > height ) ;
if ( ! mode ) {
ret = - EINVAL ;
goto unlock ;
}
if ( format - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
# ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
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
try_fmt = v4l2_subdev_get_try_format ( sd , sd_state , 0 ) ;
2018-07-03 10:08:03 -04:00
format - > format = * try_fmt ;
# endif
goto unlock ;
}
fmt - > width = mode - > width ;
fmt - > height = mode - > height ;
fmt - > code = sensor - > fmt . code ;
fmt - > colorspace = sensor - > fmt . colorspace ;
sensor - > current_mode = mode ;
sensor - > fmt = format - > format ;
sensor - > mode_pending_changes = true ;
unlock :
mutex_unlock ( & sensor - > lock ) ;
return ret ;
}
static int ov2680_init_cfg ( 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 )
2018-07-03 10:08:03 -04:00
{
struct v4l2_subdev_format fmt = {
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
. which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
: V4L2_SUBDEV_FORMAT_ACTIVE ,
2018-07-03 10:08:03 -04:00
. format = {
. width = 800 ,
. height = 600 ,
}
} ;
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
return ov2680_set_fmt ( sd , sd_state , & fmt ) ;
2018-07-03 10:08:03 -04:00
}
static int ov2680_enum_frame_size ( 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 ,
2018-07-03 10:08:03 -04:00
struct v4l2_subdev_frame_size_enum * fse )
{
int index = fse - > index ;
if ( index > = OV2680_MODE_MAX | | index < 0 )
return - EINVAL ;
fse - > min_width = ov2680_mode_data [ index ] . width ;
fse - > min_height = ov2680_mode_data [ index ] . height ;
fse - > max_width = ov2680_mode_data [ index ] . width ;
fse - > max_height = ov2680_mode_data [ index ] . height ;
return 0 ;
}
static int ov2680_enum_frame_interval ( 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 ,
2018-07-03 10:08:03 -04:00
struct v4l2_subdev_frame_interval_enum * fie )
{
struct v4l2_fract tpf ;
if ( fie - > index > = OV2680_MODE_MAX | | fie - > width > OV2680_WIDTH_MAX | |
fie - > height > OV2680_HEIGHT_MAX | |
fie - > which > V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
tpf . denominator = OV2680_FRAME_RATE ;
tpf . numerator = 1 ;
fie - > interval = tpf ;
return 0 ;
}
static int ov2680_g_volatile_ctrl ( struct v4l2_ctrl * ctrl )
{
struct v4l2_subdev * sd = ctrl_to_sd ( ctrl ) ;
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
struct ov2680_ctrls * ctrls = & sensor - > ctrls ;
int val ;
if ( ! sensor - > is_enabled )
return 0 ;
switch ( ctrl - > id ) {
case V4L2_CID_GAIN :
val = ov2680_gain_get ( sensor ) ;
if ( val < 0 )
return val ;
ctrls - > gain - > val = val ;
break ;
case V4L2_CID_EXPOSURE :
val = ov2680_exposure_get ( sensor ) ;
if ( val < 0 )
return val ;
ctrls - > exposure - > val = val ;
break ;
}
return 0 ;
}
static int ov2680_s_ctrl ( struct v4l2_ctrl * ctrl )
{
struct v4l2_subdev * sd = ctrl_to_sd ( ctrl ) ;
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
struct ov2680_ctrls * ctrls = & sensor - > ctrls ;
if ( ! sensor - > is_enabled )
return 0 ;
switch ( ctrl - > id ) {
case V4L2_CID_AUTOGAIN :
return ov2680_gain_set ( sensor , ! ! ctrl - > val ) ;
case V4L2_CID_GAIN :
return ov2680_gain_set ( sensor , ! ! ctrls - > auto_gain - > val ) ;
case V4L2_CID_EXPOSURE_AUTO :
return ov2680_exposure_set ( sensor , ! ! ctrl - > val ) ;
case V4L2_CID_EXPOSURE :
return ov2680_exposure_set ( sensor , ! ! ctrls - > auto_exp - > val ) ;
case V4L2_CID_VFLIP :
if ( sensor - > is_streaming )
return - EBUSY ;
if ( ctrl - > val )
return ov2680_vflip_enable ( sensor ) ;
else
return ov2680_vflip_disable ( sensor ) ;
case V4L2_CID_HFLIP :
if ( sensor - > is_streaming )
return - EBUSY ;
if ( ctrl - > val )
return ov2680_hflip_enable ( sensor ) ;
else
return ov2680_hflip_disable ( sensor ) ;
case V4L2_CID_TEST_PATTERN :
return ov2680_test_pattern_set ( sensor , ctrl - > val ) ;
default :
break ;
}
return - EINVAL ;
}
static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
. g_volatile_ctrl = ov2680_g_volatile_ctrl ,
. s_ctrl = ov2680_s_ctrl ,
} ;
static const struct v4l2_subdev_core_ops ov2680_core_ops = {
. s_power = ov2680_s_power ,
} ;
static const struct v4l2_subdev_video_ops ov2680_video_ops = {
. g_frame_interval = ov2680_s_g_frame_interval ,
. s_frame_interval = ov2680_s_g_frame_interval ,
. s_stream = ov2680_s_stream ,
} ;
static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
. init_cfg = ov2680_init_cfg ,
. enum_mbus_code = ov2680_enum_mbus_code ,
. get_fmt = ov2680_get_fmt ,
. set_fmt = ov2680_set_fmt ,
. enum_frame_size = ov2680_enum_frame_size ,
. enum_frame_interval = ov2680_enum_frame_interval ,
} ;
static const struct v4l2_subdev_ops ov2680_subdev_ops = {
. core = & ov2680_core_ops ,
. video = & ov2680_video_ops ,
. pad = & ov2680_pad_ops ,
} ;
static int ov2680_mode_init ( struct ov2680_dev * sensor )
{
const struct ov2680_mode_info * init_mode ;
/* set initial mode */
sensor - > fmt . code = MEDIA_BUS_FMT_SBGGR10_1X10 ;
sensor - > fmt . width = 800 ;
sensor - > fmt . height = 600 ;
sensor - > fmt . field = V4L2_FIELD_NONE ;
sensor - > fmt . colorspace = V4L2_COLORSPACE_SRGB ;
sensor - > frame_interval . denominator = OV2680_FRAME_RATE ;
sensor - > frame_interval . numerator = 1 ;
init_mode = & ov2680_mode_init_data ;
sensor - > current_mode = init_mode ;
sensor - > mode_pending_changes = true ;
return 0 ;
}
2018-09-01 08:46:30 -04:00
static int ov2680_v4l2_register ( struct ov2680_dev * sensor )
2018-07-03 10:08:03 -04:00
{
const struct v4l2_ctrl_ops * ops = & ov2680_ctrl_ops ;
struct ov2680_ctrls * ctrls = & sensor - > ctrls ;
struct v4l2_ctrl_handler * hdl = & ctrls - > handler ;
int ret = 0 ;
v4l2_i2c_subdev_init ( & sensor - > sd , sensor - > i2c_client ,
& ov2680_subdev_ops ) ;
# ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sensor - > sd . flags = V4L2_SUBDEV_FL_HAS_DEVNODE ;
# endif
sensor - > pad . flags = MEDIA_PAD_FL_SOURCE ;
sensor - > sd . entity . function = MEDIA_ENT_F_CAM_SENSOR ;
ret = media_entity_pads_init ( & sensor - > sd . entity , 1 , & sensor - > pad ) ;
if ( ret < 0 )
return ret ;
v4l2_ctrl_handler_init ( hdl , 7 ) ;
hdl - > lock = & sensor - > lock ;
ctrls - > vflip = v4l2_ctrl_new_std ( hdl , ops , V4L2_CID_VFLIP , 0 , 1 , 1 , 0 ) ;
ctrls - > hflip = v4l2_ctrl_new_std ( hdl , ops , V4L2_CID_HFLIP , 0 , 1 , 1 , 0 ) ;
ctrls - > test_pattern = v4l2_ctrl_new_std_menu_items ( hdl ,
& ov2680_ctrl_ops , V4L2_CID_TEST_PATTERN ,
ARRAY_SIZE ( test_pattern_menu ) - 1 ,
0 , 0 , test_pattern_menu ) ;
ctrls - > auto_exp = v4l2_ctrl_new_std_menu ( hdl , ops ,
V4L2_CID_EXPOSURE_AUTO ,
V4L2_EXPOSURE_MANUAL , 0 ,
V4L2_EXPOSURE_AUTO ) ;
ctrls - > exposure = v4l2_ctrl_new_std ( hdl , ops , V4L2_CID_EXPOSURE ,
0 , 32767 , 1 , 0 ) ;
ctrls - > auto_gain = v4l2_ctrl_new_std ( hdl , ops , V4L2_CID_AUTOGAIN ,
0 , 1 , 1 , 1 ) ;
ctrls - > gain = v4l2_ctrl_new_std ( hdl , ops , V4L2_CID_GAIN , 0 , 2047 , 1 , 0 ) ;
if ( hdl - > error ) {
ret = hdl - > error ;
goto cleanup_entity ;
}
ctrls - > gain - > flags | = V4L2_CTRL_FLAG_VOLATILE ;
ctrls - > exposure - > flags | = V4L2_CTRL_FLAG_VOLATILE ;
2022-12-05 15:21:45 +00:00
ctrls - > vflip - > flags | = V4L2_CTRL_FLAG_MODIFY_LAYOUT ;
ctrls - > hflip - > flags | = V4L2_CTRL_FLAG_MODIFY_LAYOUT ;
2018-07-03 10:08:03 -04:00
v4l2_ctrl_auto_cluster ( 2 , & ctrls - > auto_gain , 0 , true ) ;
v4l2_ctrl_auto_cluster ( 2 , & ctrls - > auto_exp , 1 , true ) ;
sensor - > sd . ctrl_handler = hdl ;
ret = v4l2_async_register_subdev ( & sensor - > sd ) ;
if ( ret < 0 )
goto cleanup_entity ;
return 0 ;
cleanup_entity :
media_entity_cleanup ( & sensor - > sd . entity ) ;
v4l2_ctrl_handler_free ( hdl ) ;
return ret ;
}
static int ov2680_get_regulators ( struct ov2680_dev * sensor )
{
int i ;
for ( i = 0 ; i < OV2680_NUM_SUPPLIES ; i + + )
sensor - > supplies [ i ] . supply = ov2680_supply_name [ i ] ;
return devm_regulator_bulk_get ( & sensor - > i2c_client - > dev ,
OV2680_NUM_SUPPLIES ,
sensor - > supplies ) ;
}
static int ov2680_check_id ( struct ov2680_dev * sensor )
{
struct device * dev = ov2680_to_dev ( sensor ) ;
u32 chip_id ;
int ret ;
ov2680_power_on ( sensor ) ;
ret = ov2680_read_reg16 ( sensor , OV2680_REG_CHIP_ID_HIGH , & chip_id ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to read chip id high \n " ) ;
return - ENODEV ;
}
if ( chip_id ! = OV2680_CHIP_ID ) {
dev_err ( dev , " chip id: 0x%04x does not match expected 0x%04x \n " ,
chip_id , OV2680_CHIP_ID ) ;
return - ENODEV ;
}
return 0 ;
}
2019-07-21 15:04:23 -04:00
static int ov2680_parse_dt ( struct ov2680_dev * sensor )
2018-07-03 10:08:03 -04:00
{
struct device * dev = ov2680_to_dev ( sensor ) ;
int ret ;
sensor - > reset_gpio = devm_gpiod_get_optional ( dev , " reset " ,
GPIOD_OUT_HIGH ) ;
ret = PTR_ERR_OR_ZERO ( sensor - > reset_gpio ) ;
if ( ret < 0 ) {
dev_dbg ( dev , " error while getting reset gpio: %d \n " , ret ) ;
return ret ;
}
sensor - > xvclk = devm_clk_get ( dev , " xvclk " ) ;
if ( IS_ERR ( sensor - > xvclk ) ) {
dev_err ( dev , " xvclk clock missing or invalid \n " ) ;
return PTR_ERR ( sensor - > xvclk ) ;
}
sensor - > xvclk_freq = clk_get_rate ( sensor - > xvclk ) ;
if ( sensor - > xvclk_freq ! = OV2680_XVCLK_VALUE ) {
dev_err ( dev , " wrong xvclk frequency %d HZ, expected: %d Hz \n " ,
sensor - > xvclk_freq , OV2680_XVCLK_VALUE ) ;
return - EINVAL ;
}
return 0 ;
}
static int ov2680_probe ( struct i2c_client * client )
{
struct device * dev = & client - > dev ;
struct ov2680_dev * sensor ;
int ret ;
sensor = devm_kzalloc ( dev , sizeof ( * sensor ) , GFP_KERNEL ) ;
if ( ! sensor )
return - ENOMEM ;
sensor - > i2c_client = client ;
2019-07-21 15:04:23 -04:00
ret = ov2680_parse_dt ( sensor ) ;
2018-07-03 10:08:03 -04:00
if ( ret < 0 )
return - EINVAL ;
ret = ov2680_mode_init ( sensor ) ;
if ( ret < 0 )
return ret ;
ret = ov2680_get_regulators ( sensor ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to get regulators \n " ) ;
return ret ;
}
mutex_init ( & sensor - > lock ) ;
2018-09-01 08:46:29 -04:00
ret = ov2680_check_id ( sensor ) ;
2018-07-03 10:08:03 -04:00
if ( ret < 0 )
goto lock_destroy ;
2018-09-01 08:46:30 -04:00
ret = ov2680_v4l2_register ( sensor ) ;
2018-07-03 10:08:03 -04:00
if ( ret < 0 )
2018-09-01 08:46:29 -04:00
goto lock_destroy ;
2018-07-03 10:08:03 -04:00
dev_info ( dev , " ov2680 init correctly \n " ) ;
return 0 ;
lock_destroy :
2018-09-01 08:46:29 -04:00
dev_err ( dev , " ov2680 init fail: %d \n " , ret ) ;
2018-07-03 10:08:03 -04:00
mutex_destroy ( & sensor - > lock ) ;
return ret ;
}
2022-08-15 10:02:30 +02:00
static void ov2680_remove ( struct i2c_client * client )
2018-07-03 10:08:03 -04:00
{
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
v4l2_async_unregister_subdev ( & sensor - > sd ) ;
mutex_destroy ( & sensor - > lock ) ;
media_entity_cleanup ( & sensor - > sd . entity ) ;
v4l2_ctrl_handler_free ( & sensor - > ctrls . handler ) ;
}
static int __maybe_unused ov2680_suspend ( struct device * dev )
{
2020-09-21 18:23:33 +02:00
struct v4l2_subdev * sd = dev_get_drvdata ( dev ) ;
2018-07-03 10:08:03 -04:00
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
if ( sensor - > is_streaming )
ov2680_stream_disable ( sensor ) ;
return 0 ;
}
static int __maybe_unused ov2680_resume ( struct device * dev )
{
2020-09-21 18:23:33 +02:00
struct v4l2_subdev * sd = dev_get_drvdata ( dev ) ;
2018-07-03 10:08:03 -04:00
struct ov2680_dev * sensor = to_ov2680_dev ( sd ) ;
int ret ;
if ( sensor - > is_streaming ) {
ret = ov2680_stream_enable ( sensor ) ;
if ( ret < 0 )
goto stream_disable ;
}
return 0 ;
stream_disable :
ov2680_stream_disable ( sensor ) ;
sensor - > is_streaming = false ;
return ret ;
}
static const struct dev_pm_ops ov2680_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( ov2680_suspend , ov2680_resume )
} ;
static const struct of_device_id ov2680_dt_ids [ ] = {
{ . compatible = " ovti,ov2680 " } ,
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , ov2680_dt_ids ) ;
static struct i2c_driver ov2680_i2c_driver = {
. driver = {
. name = " ov2680 " ,
. pm = & ov2680_pm_ops ,
2023-03-12 14:13:14 +01:00
. of_match_table = ov2680_dt_ids ,
2018-07-03 10:08:03 -04:00
} ,
2023-05-14 14:04:07 +02:00
. probe = ov2680_probe ,
2018-07-03 10:08:03 -04:00
. remove = ov2680_remove ,
} ;
module_i2c_driver ( ov2680_i2c_driver ) ;
MODULE_AUTHOR ( " Rui Miguel Silva <rui.silva@linaro.org> " ) ;
MODULE_DESCRIPTION ( " OV2680 CMOS Image Sensor driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;