2019-06-04 10:11:19 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2008-12-05 10:19:36 -03:00
/*
2012-08-14 16:23:43 -03:00
* drivers / media / i2c / tvp514x . c
2008-12-05 10:19:36 -03:00
*
* TI TVP5146 / 47 decoder driver
*
* Copyright ( C ) 2008 Texas Instruments Inc
* Author : Vaibhav Hiremath < hvaibhav @ ti . com >
*
* Contributors :
* Sivaraj R < sivaraj @ ti . com >
* Brijesh R Jadav < brijesh . j @ ti . com >
* Hardik Shah < hardik . shah @ ti . com >
* Manjunath Hadli < mrh @ ti . com >
* Karicheri Muralidharan < m - karicheri2 @ ti . com >
2013-03-08 04:13:35 -03:00
* Prabhakar Lad < prabhakar . lad @ ti . com >
2008-12-05 10:19:36 -03:00
*/
# include <linux/delay.h>
2023-09-23 17:36:41 +01:00
# include <linux/i2c.h>
2023-09-23 17:36:40 +01:00
# include <linux/mod_devicetable.h>
2011-07-03 14:03:12 -04:00
# include <linux/module.h>
2013-10-18 00:07:13 -03:00
# include <linux/of.h>
2014-02-10 22:01:48 +01:00
# include <linux/of_graph.h>
2023-09-23 17:36:41 +01:00
# include <linux/slab.h>
# include <linux/v4l2-mediabus.h>
# include <linux/videodev2.h>
2009-06-19 07:13:44 -03:00
2023-09-23 17:36:41 +01:00
# include <media/i2c/tvp514x.h>
# include <media/media-entity.h>
2013-06-24 11:51:39 -03:00
# include <media/v4l2-async.h>
2009-06-19 07:13:44 -03:00
# include <media/v4l2-common.h>
2010-12-12 08:45:22 -03:00
# include <media/v4l2-ctrls.h>
2023-09-23 17:36:41 +01:00
# include <media/v4l2-device.h>
# include <media/v4l2-fwnode.h>
# include <media/v4l2-mediabus.h>
2008-12-05 10:19:36 -03:00
# include "tvp514x_regs.h"
/* Private macros for TVP */
# define I2C_RETRY_COUNT (5)
# define LOCK_RETRY_COUNT (5)
# define LOCK_RETRY_DELAY (200)
/* Debug functions */
2012-01-13 09:32:20 +10:30
static bool debug ;
2008-12-05 10:19:36 -03:00
module_param ( debug , bool , 0644 ) ;
MODULE_PARM_DESC ( debug , " Debug level (0-1) " ) ;
2009-06-19 07:13:44 -03:00
MODULE_AUTHOR ( " Texas Instruments " ) ;
MODULE_DESCRIPTION ( " TVP514X linux decoder driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-12-05 10:19:36 -03:00
2009-07-01 04:20:43 -03:00
/* enum tvp514x_std - enum for supported standards */
2008-12-05 10:19:36 -03:00
enum tvp514x_std {
STD_NTSC_MJ = 0 ,
STD_PAL_BDGHIN ,
STD_INVALID
} ;
2009-07-01 04:20:43 -03:00
/**
2019-02-18 14:28:58 -05:00
* struct tvp514x_std_info - Structure to store standard information
2008-12-05 10:19:36 -03:00
* @ width : Line width in pixels
* @ height : Number of active lines
* @ video_std : Value to write in REG_VIDEO_STD register
* @ standard : v4l2 standard structure information
*/
struct tvp514x_std_info {
unsigned long width ;
unsigned long height ;
u8 video_std ;
struct v4l2_standard standard ;
} ;
2009-01-12 06:17:43 -03:00
static struct tvp514x_reg tvp514x_reg_list_default [ 0x40 ] ;
2010-03-27 09:37:54 -03:00
static int tvp514x_s_stream ( struct v4l2_subdev * sd , int enable ) ;
2009-07-01 04:20:43 -03:00
/**
2009-01-12 06:17:43 -03:00
* struct tvp514x_decoder - TVP5146 / 47 decoder object
2009-06-19 07:13:44 -03:00
* @ sd : Subdevice Slave handle
2017-11-29 09:26:20 -05:00
* @ hdl : embedded & struct v4l2_ctrl_handler
2009-01-12 06:17:43 -03:00
* @ tvp514x_regs : copy of hw ' s regs with preset values .
2008-12-05 10:19:36 -03:00
* @ pdata : Board specific
* @ ver : Chip version
2009-06-19 07:13:44 -03:00
* @ streaming : TVP5146 / 47 decoder streaming - enabled or disabled .
2013-03-08 04:13:35 -03:00
* @ pix : Current pixel format
* @ num_fmts : Number of formats
* @ fmt_list : Format list
2008-12-05 10:19:36 -03:00
* @ current_std : Current standard
* @ num_stds : Number of standards
* @ std_list : Standards list
2009-06-19 07:13:44 -03:00
* @ input : Input routing at chip level
* @ output : Output routing at chip level
2017-11-29 09:26:20 -05:00
* @ pad : subdev media pad associated with the decoder
* @ format : media bus frame format
* @ int_seq : driver ' s register init sequence
2008-12-05 10:19:36 -03:00
*/
struct tvp514x_decoder {
2009-06-19 07:13:44 -03:00
struct v4l2_subdev sd ;
2010-12-12 08:45:22 -03:00
struct v4l2_ctrl_handler hdl ;
2009-01-12 06:17:43 -03:00
struct tvp514x_reg tvp514x_regs [ ARRAY_SIZE ( tvp514x_reg_list_default ) ] ;
2008-12-05 10:19:36 -03:00
const struct tvp514x_platform_data * pdata ;
int ver ;
2009-06-19 07:13:44 -03:00
int streaming ;
2008-12-05 10:19:36 -03:00
2013-03-08 04:13:35 -03:00
struct v4l2_pix_format pix ;
int num_fmts ;
const struct v4l2_fmtdesc * fmt_list ;
2008-12-05 10:19:36 -03:00
enum tvp514x_std current_std ;
int num_stds ;
2010-05-09 06:32:47 -03:00
const struct tvp514x_std_info * std_list ;
2009-07-01 04:20:43 -03:00
/* Input and Output Routing parameters */
2009-06-19 07:13:44 -03:00
u32 input ;
u32 output ;
2013-03-08 04:13:35 -03:00
/* mc related members */
struct media_pad pad ;
struct v4l2_mbus_framefmt format ;
2013-06-23 10:01:35 -03:00
2023-09-23 17:36:39 +01:00
const struct tvp514x_reg * int_seq ;
2008-12-05 10:19:36 -03:00
} ;
/* TVP514x default register values */
2009-01-12 06:17:43 -03:00
static struct tvp514x_reg tvp514x_reg_list_default [ ] = {
2009-07-01 04:20:43 -03:00
/* Composite selected */
{ TOK_WRITE , REG_INPUT_SEL , 0x05 } ,
2008-12-05 10:19:36 -03:00
{ TOK_WRITE , REG_AFE_GAIN_CTRL , 0x0F } ,
2009-07-01 04:20:43 -03:00
/* Auto mode */
{ TOK_WRITE , REG_VIDEO_STD , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_WRITE , REG_OPERATION_MODE , 0x00 } ,
{ TOK_SKIP , REG_AUTOSWITCH_MASK , 0x3F } ,
{ TOK_WRITE , REG_COLOR_KILLER , 0x10 } ,
{ TOK_WRITE , REG_LUMA_CONTROL1 , 0x00 } ,
{ TOK_WRITE , REG_LUMA_CONTROL2 , 0x00 } ,
{ TOK_WRITE , REG_LUMA_CONTROL3 , 0x02 } ,
{ TOK_WRITE , REG_BRIGHTNESS , 0x80 } ,
{ TOK_WRITE , REG_CONTRAST , 0x80 } ,
{ TOK_WRITE , REG_SATURATION , 0x80 } ,
{ TOK_WRITE , REG_HUE , 0x00 } ,
{ TOK_WRITE , REG_CHROMA_CONTROL1 , 0x00 } ,
{ TOK_WRITE , REG_CHROMA_CONTROL2 , 0x0E } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x0F , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_WRITE , REG_COMP_PR_SATURATION , 0x80 } ,
{ TOK_WRITE , REG_COMP_Y_CONTRAST , 0x80 } ,
{ TOK_WRITE , REG_COMP_PB_SATURATION , 0x80 } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x13 , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_WRITE , REG_COMP_Y_BRIGHTNESS , 0x80 } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x15 , 0x00 } ,
/* NTSC timing */
{ TOK_SKIP , REG_AVID_START_PIXEL_LSB , 0x55 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_AVID_START_PIXEL_MSB , 0x00 } ,
{ TOK_SKIP , REG_AVID_STOP_PIXEL_LSB , 0x25 } ,
{ TOK_SKIP , REG_AVID_STOP_PIXEL_MSB , 0x03 } ,
2009-07-01 04:20:43 -03:00
/* NTSC timing */
{ TOK_SKIP , REG_HSYNC_START_PIXEL_LSB , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_HSYNC_START_PIXEL_MSB , 0x00 } ,
{ TOK_SKIP , REG_HSYNC_STOP_PIXEL_LSB , 0x40 } ,
{ TOK_SKIP , REG_HSYNC_STOP_PIXEL_MSB , 0x00 } ,
2009-07-01 04:20:43 -03:00
/* NTSC timing */
{ TOK_SKIP , REG_VSYNC_START_LINE_LSB , 0x04 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_VSYNC_START_LINE_MSB , 0x00 } ,
{ TOK_SKIP , REG_VSYNC_STOP_LINE_LSB , 0x07 } ,
{ TOK_SKIP , REG_VSYNC_STOP_LINE_MSB , 0x00 } ,
2009-07-01 04:20:43 -03:00
/* NTSC timing */
{ TOK_SKIP , REG_VBLK_START_LINE_LSB , 0x01 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_VBLK_START_LINE_MSB , 0x00 } ,
{ TOK_SKIP , REG_VBLK_STOP_LINE_LSB , 0x15 } ,
{ TOK_SKIP , REG_VBLK_STOP_LINE_MSB , 0x00 } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x26 , 0x00 } ,
/* Reserved */
{ TOK_SKIP , 0x27 , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_FAST_SWTICH_CONTROL , 0xCC } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x29 , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_FAST_SWTICH_SCART_DELAY , 0x00 } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x2B , 0x00 } ,
2008-12-05 10:19:36 -03:00
{ TOK_SKIP , REG_SCART_DELAY , 0x00 } ,
{ TOK_SKIP , REG_CTI_DELAY , 0x00 } ,
{ TOK_SKIP , REG_CTI_CONTROL , 0x00 } ,
2009-07-01 04:20:43 -03:00
/* Reserved */
{ TOK_SKIP , 0x2F , 0x00 } ,
/* Reserved */
{ TOK_SKIP , 0x30 , 0x00 } ,
/* Reserved */
{ TOK_SKIP , 0x31 , 0x00 } ,
/* HS, VS active high */
{ TOK_WRITE , REG_SYNC_CONTROL , 0x00 } ,
/* 10-bit BT.656 */
{ TOK_WRITE , REG_OUTPUT_FORMATTER1 , 0x00 } ,
/* Enable clk & data */
{ TOK_WRITE , REG_OUTPUT_FORMATTER2 , 0x11 } ,
/* Enable AVID & FLD */
{ TOK_WRITE , REG_OUTPUT_FORMATTER3 , 0xEE } ,
/* Enable VS & HS */
{ TOK_WRITE , REG_OUTPUT_FORMATTER4 , 0xAF } ,
2008-12-05 10:19:36 -03:00
{ TOK_WRITE , REG_OUTPUT_FORMATTER5 , 0xFF } ,
{ TOK_WRITE , REG_OUTPUT_FORMATTER6 , 0xFF } ,
2009-07-01 04:20:43 -03:00
/* Clear status */
{ TOK_WRITE , REG_CLEAR_LOST_LOCK , 0x01 } ,
2008-12-05 10:19:36 -03:00
{ TOK_TERM , 0 , 0 } ,
} ;
2017-11-29 09:26:20 -05:00
/*
2013-03-08 04:13:35 -03:00
* List of image formats supported by TVP5146 / 47 decoder
* Currently we are using 8 bit mode only , but can be
* extended to 10 / 20 bit mode .
*/
static const struct v4l2_fmtdesc tvp514x_fmt_list [ ] = {
{
. index = 0 ,
. type = V4L2_BUF_TYPE_VIDEO_CAPTURE ,
. flags = 0 ,
. description = " 8-bit UYVY 4:2:2 Format " ,
. pixelformat = V4L2_PIX_FMT_UYVY ,
} ,
} ;
2017-11-29 09:26:20 -05:00
/*
2008-12-05 10:19:36 -03:00
* Supported standards -
*
* Currently supports two standards only , need to add support for rest of the
* modes , like SECAM , etc . . .
*/
2010-05-09 06:32:47 -03:00
static const struct tvp514x_std_info tvp514x_std_list [ ] = {
2008-12-05 10:19:36 -03:00
/* Standard: STD_NTSC_MJ */
[ STD_NTSC_MJ ] = {
. width = NTSC_NUM_ACTIVE_PIXELS ,
. height = NTSC_NUM_ACTIVE_LINES ,
. video_std = VIDEO_STD_NTSC_MJ_BIT ,
. standard = {
. index = 0 ,
. id = V4L2_STD_NTSC ,
. name = " NTSC " ,
. frameperiod = { 1001 , 30000 } ,
. framelines = 525
} ,
/* Standard: STD_PAL_BDGHIN */
} ,
[ STD_PAL_BDGHIN ] = {
. width = PAL_NUM_ACTIVE_PIXELS ,
. height = PAL_NUM_ACTIVE_LINES ,
. video_std = VIDEO_STD_PAL_BDGHIN_BIT ,
. standard = {
. index = 1 ,
. id = V4L2_STD_PAL ,
. name = " PAL " ,
. frameperiod = { 1 , 25 } ,
. framelines = 625
} ,
} ,
/* Standard: need to add for additional standard */
} ;
2009-06-19 07:13:44 -03:00
static inline struct tvp514x_decoder * to_decoder ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct tvp514x_decoder , sd ) ;
}
2010-12-12 08:45:22 -03:00
static inline struct v4l2_subdev * to_sd ( struct v4l2_ctrl * ctrl )
{
return & container_of ( ctrl - > handler , struct tvp514x_decoder , hdl ) - > sd ;
}
2008-12-05 10:19:36 -03:00
2009-07-01 04:20:43 -03:00
/**
* tvp514x_read_reg ( ) - Read a value from a register in an TVP5146 / 47.
* @ sd : ptr to v4l2_subdev struct
* @ reg : TVP5146 / 47 register address
*
2008-12-05 10:19:36 -03:00
* Returns value read if successful , or non - zero ( - 1 ) otherwise .
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_read_reg ( struct v4l2_subdev * sd , u8 reg )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
int err , retry = 0 ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-12-05 10:19:36 -03:00
read_again :
err = i2c_smbus_read_byte_data ( client , reg ) ;
2009-11-04 15:35:09 -03:00
if ( err < 0 ) {
2008-12-05 10:19:36 -03:00
if ( retry < = I2C_RETRY_COUNT ) {
2009-06-19 07:13:44 -03:00
v4l2_warn ( sd , " Read: retry ... %d \n " , retry ) ;
2008-12-05 10:19:36 -03:00
retry + + ;
msleep_interruptible ( 10 ) ;
goto read_again ;
}
}
return err ;
}
2009-07-01 04:20:43 -03:00
/**
* dump_reg ( ) - dump the register content of TVP5146 / 47.
* @ sd : ptr to v4l2_subdev struct
* @ reg : TVP5146 / 47 register address
*/
2009-06-19 07:13:44 -03:00
static void dump_reg ( struct v4l2_subdev * sd , u8 reg )
{
u32 val ;
val = tvp514x_read_reg ( sd , reg ) ;
v4l2_info ( sd , " Reg(0x%.2X): 0x%.2X \n " , reg , val ) ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_write_reg ( ) - Write a value to a register in TVP5146 / 47
* @ sd : ptr to v4l2_subdev struct
* @ reg : TVP5146 / 47 register address
* @ val : value to be written to the register
*
2008-12-05 10:19:36 -03:00
* Write a value to a register in an TVP5146 / 47 decoder device .
* Returns zero if successful , or non - zero otherwise .
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_write_reg ( struct v4l2_subdev * sd , u8 reg , u8 val )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
int err , retry = 0 ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-12-05 10:19:36 -03:00
write_again :
err = i2c_smbus_write_byte_data ( client , reg , val ) ;
if ( err ) {
if ( retry < = I2C_RETRY_COUNT ) {
2009-06-19 07:13:44 -03:00
v4l2_warn ( sd , " Write: retry ... %d \n " , retry ) ;
2008-12-05 10:19:36 -03:00
retry + + ;
msleep_interruptible ( 10 ) ;
goto write_again ;
}
}
return err ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_write_regs ( ) : Initializes a list of TVP5146 / 47 registers
* @ sd : ptr to v4l2_subdev struct
* @ reglist : list of TVP5146 / 47 registers and values
*
* Initializes a list of TVP5146 / 47 registers : -
2008-12-05 10:19:36 -03:00
* if token is TOK_TERM , then entire write operation terminates
* if token is TOK_DELAY , then a delay of ' val ' msec is introduced
* if token is TOK_SKIP , then the register write is skipped
* if token is TOK_WRITE , then the register write is performed
* Returns zero if successful , or non - zero otherwise .
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_write_regs ( struct v4l2_subdev * sd ,
2008-12-05 10:19:36 -03:00
const struct tvp514x_reg reglist [ ] )
{
int err ;
const struct tvp514x_reg * next = reglist ;
for ( ; next - > token ! = TOK_TERM ; next + + ) {
if ( next - > token = = TOK_DELAY ) {
msleep ( next - > val ) ;
continue ;
}
if ( next - > token = = TOK_SKIP )
continue ;
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , next - > reg , ( u8 ) next - > val ) ;
2008-12-05 10:19:36 -03:00
if ( err ) {
2009-06-19 07:13:44 -03:00
v4l2_err ( sd , " Write failed. Err[%d] \n " , err ) ;
2008-12-05 10:19:36 -03:00
return err ;
}
}
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
2010-05-09 06:30:15 -03:00
* tvp514x_query_current_std ( ) : Query the current standard detected by TVP5146 / 47
2009-07-01 04:20:43 -03:00
* @ sd : ptr to v4l2_subdev struct
*
2010-05-09 06:30:15 -03:00
* Returns the current standard detected by TVP5146 / 47 , STD_INVALID if there is no
2009-07-01 04:20:43 -03:00
* standard detected .
2008-12-05 10:19:36 -03:00
*/
2010-05-09 06:30:15 -03:00
static enum tvp514x_std tvp514x_query_current_std ( struct v4l2_subdev * sd )
2008-12-05 10:19:36 -03:00
{
u8 std , std_status ;
2009-06-19 07:13:44 -03:00
std = tvp514x_read_reg ( sd , REG_VIDEO_STD ) ;
if ( ( std & VIDEO_STD_MASK ) = = VIDEO_STD_AUTO_SWITCH_BIT )
2008-12-05 10:19:36 -03:00
/* use the standard status register */
2009-06-19 07:13:44 -03:00
std_status = tvp514x_read_reg ( sd , REG_VIDEO_STD_STATUS ) ;
else
2009-07-01 04:20:43 -03:00
/* use the standard register itself */
std_status = std ;
2008-12-05 10:19:36 -03:00
switch ( std_status & VIDEO_STD_MASK ) {
case VIDEO_STD_NTSC_MJ_BIT :
return STD_NTSC_MJ ;
case VIDEO_STD_PAL_BDGHIN_BIT :
return STD_PAL_BDGHIN ;
default :
return STD_INVALID ;
}
return STD_INVALID ;
}
2009-07-01 04:20:43 -03:00
/* TVP5146/47 register dump function */
2009-06-19 07:13:44 -03:00
static void tvp514x_reg_dump ( struct v4l2_subdev * sd )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
dump_reg ( sd , REG_INPUT_SEL ) ;
dump_reg ( sd , REG_AFE_GAIN_CTRL ) ;
dump_reg ( sd , REG_VIDEO_STD ) ;
dump_reg ( sd , REG_OPERATION_MODE ) ;
dump_reg ( sd , REG_COLOR_KILLER ) ;
dump_reg ( sd , REG_LUMA_CONTROL1 ) ;
dump_reg ( sd , REG_LUMA_CONTROL2 ) ;
dump_reg ( sd , REG_LUMA_CONTROL3 ) ;
dump_reg ( sd , REG_BRIGHTNESS ) ;
dump_reg ( sd , REG_CONTRAST ) ;
dump_reg ( sd , REG_SATURATION ) ;
dump_reg ( sd , REG_HUE ) ;
dump_reg ( sd , REG_CHROMA_CONTROL1 ) ;
dump_reg ( sd , REG_CHROMA_CONTROL2 ) ;
dump_reg ( sd , REG_COMP_PR_SATURATION ) ;
dump_reg ( sd , REG_COMP_Y_CONTRAST ) ;
dump_reg ( sd , REG_COMP_PB_SATURATION ) ;
dump_reg ( sd , REG_COMP_Y_BRIGHTNESS ) ;
dump_reg ( sd , REG_AVID_START_PIXEL_LSB ) ;
dump_reg ( sd , REG_AVID_START_PIXEL_MSB ) ;
dump_reg ( sd , REG_AVID_STOP_PIXEL_LSB ) ;
dump_reg ( sd , REG_AVID_STOP_PIXEL_MSB ) ;
dump_reg ( sd , REG_HSYNC_START_PIXEL_LSB ) ;
dump_reg ( sd , REG_HSYNC_START_PIXEL_MSB ) ;
dump_reg ( sd , REG_HSYNC_STOP_PIXEL_LSB ) ;
dump_reg ( sd , REG_HSYNC_STOP_PIXEL_MSB ) ;
dump_reg ( sd , REG_VSYNC_START_LINE_LSB ) ;
dump_reg ( sd , REG_VSYNC_START_LINE_MSB ) ;
dump_reg ( sd , REG_VSYNC_STOP_LINE_LSB ) ;
dump_reg ( sd , REG_VSYNC_STOP_LINE_MSB ) ;
dump_reg ( sd , REG_VBLK_START_LINE_LSB ) ;
dump_reg ( sd , REG_VBLK_START_LINE_MSB ) ;
dump_reg ( sd , REG_VBLK_STOP_LINE_LSB ) ;
dump_reg ( sd , REG_VBLK_STOP_LINE_MSB ) ;
dump_reg ( sd , REG_SYNC_CONTROL ) ;
dump_reg ( sd , REG_OUTPUT_FORMATTER1 ) ;
dump_reg ( sd , REG_OUTPUT_FORMATTER2 ) ;
dump_reg ( sd , REG_OUTPUT_FORMATTER3 ) ;
dump_reg ( sd , REG_OUTPUT_FORMATTER4 ) ;
dump_reg ( sd , REG_OUTPUT_FORMATTER5 ) ;
dump_reg ( sd , REG_OUTPUT_FORMATTER6 ) ;
dump_reg ( sd , REG_CLEAR_LOST_LOCK ) ;
2008-12-05 10:19:36 -03:00
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_configure ( ) - Configure the TVP5146 / 47 registers
* @ sd : ptr to v4l2_subdev struct
* @ decoder : ptr to tvp514x_decoder structure
*
2008-12-05 10:19:36 -03:00
* Returns zero if successful , or non - zero otherwise .
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_configure ( struct v4l2_subdev * sd ,
struct tvp514x_decoder * decoder )
2008-12-05 10:19:36 -03:00
{
int err ;
/* common register initialization */
err =
2009-06-19 07:13:44 -03:00
tvp514x_write_regs ( sd , decoder - > tvp514x_regs ) ;
2008-12-05 10:19:36 -03:00
if ( err )
return err ;
if ( debug )
2009-06-19 07:13:44 -03:00
tvp514x_reg_dump ( sd ) ;
2008-12-05 10:19:36 -03:00
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_detect ( ) - Detect if an tvp514x is present , and if so which revision .
* @ sd : pointer to standard V4L2 sub - device structure
* @ decoder : pointer to tvp514x_decoder structure
*
2008-12-05 10:19:36 -03:00
* A device is considered to be detected if the chip ID ( LSB and MSB )
* registers match the expected values .
* Any value of the rom version register is accepted .
* Returns ENODEV error number if no device is detected , or zero
* if a device is detected .
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_detect ( struct v4l2_subdev * sd ,
struct tvp514x_decoder * decoder )
2008-12-05 10:19:36 -03:00
{
u8 chip_id_msb , chip_id_lsb , rom_ver ;
2009-06-19 07:13:44 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
chip_id_msb = tvp514x_read_reg ( sd , REG_CHIP_ID_MSB ) ;
chip_id_lsb = tvp514x_read_reg ( sd , REG_CHIP_ID_LSB ) ;
rom_ver = tvp514x_read_reg ( sd , REG_ROM_VERSION ) ;
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
v4l2_dbg ( 1 , debug , sd ,
2008-12-05 10:19:36 -03:00
" chip id detected msb:0x%x lsb:0x%x rom version:0x%x \n " ,
chip_id_msb , chip_id_lsb , rom_ver ) ;
if ( ( chip_id_msb ! = TVP514X_CHIP_ID_MSB )
| | ( ( chip_id_lsb ! = TVP5146_CHIP_ID_LSB )
& & ( chip_id_lsb ! = TVP5147_CHIP_ID_LSB ) ) ) {
/* We didn't read the values we expected, so this must not be
* an TVP5146 / 47.
*/
2009-06-19 07:13:44 -03:00
v4l2_err ( sd , " chip id mismatch msb:0x%x lsb:0x%x \n " ,
chip_id_msb , chip_id_lsb ) ;
2008-12-05 10:19:36 -03:00
return - ENODEV ;
}
decoder - > ver = rom_ver ;
2009-06-19 07:13:44 -03:00
v4l2_info ( sd , " %s (Version - 0x%.2x) found at 0x%x (%s) \n " ,
client - > name , decoder - > ver ,
client - > addr < < 1 , client - > adapter - > name ) ;
2008-12-05 10:19:36 -03:00
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_querystd ( ) - V4L2 decoder interface handler for querystd
2009-06-19 07:13:44 -03:00
* @ sd : pointer to standard V4L2 sub - device structure
2008-12-05 10:19:36 -03:00
* @ std_id : standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146 / 47. If no active input is
2010-05-09 06:30:15 -03:00
* detected then * std_id is set to 0 and the function returns 0.
2008-12-05 10:19:36 -03:00
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_querystd ( struct v4l2_subdev * sd , v4l2_std_id * std_id )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
enum tvp514x_std current_std ;
enum tvp514x_input input_sel ;
u8 sync_lock_status , lock_mask ;
if ( std_id = = NULL )
return - EINVAL ;
2012-09-20 09:06:33 -03:00
/* To query the standard the TVP514x must power on the ADCs. */
if ( ! decoder - > streaming ) {
tvp514x_s_stream ( sd , 1 ) ;
msleep ( LOCK_RETRY_DELAY ) ;
}
2010-05-09 06:30:15 -03:00
/* query the current standard */
current_std = tvp514x_query_current_std ( sd ) ;
2013-05-29 10:19:00 -03:00
if ( current_std = = STD_INVALID ) {
* std_id = V4L2_STD_UNKNOWN ;
2010-05-09 06:30:15 -03:00
return 0 ;
2013-05-29 10:19:00 -03:00
}
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
input_sel = decoder - > input ;
2008-12-05 10:19:36 -03:00
switch ( input_sel ) {
case INPUT_CVBS_VI1A :
case INPUT_CVBS_VI1B :
case INPUT_CVBS_VI1C :
case INPUT_CVBS_VI2A :
case INPUT_CVBS_VI2B :
case INPUT_CVBS_VI2C :
case INPUT_CVBS_VI3A :
case INPUT_CVBS_VI3B :
case INPUT_CVBS_VI3C :
case INPUT_CVBS_VI4A :
lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT ;
break ;
case INPUT_SVIDEO_VI2A_VI1A :
case INPUT_SVIDEO_VI2B_VI1B :
case INPUT_SVIDEO_VI2C_VI1C :
case INPUT_SVIDEO_VI2A_VI3A :
case INPUT_SVIDEO_VI2B_VI3B :
case INPUT_SVIDEO_VI2C_VI3C :
case INPUT_SVIDEO_VI4A_VI1A :
case INPUT_SVIDEO_VI4A_VI1B :
case INPUT_SVIDEO_VI4A_VI1C :
case INPUT_SVIDEO_VI4A_VI3A :
case INPUT_SVIDEO_VI4A_VI3B :
case INPUT_SVIDEO_VI4A_VI3C :
lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
STATUS_VIRT_SYNC_LOCK_BIT ;
break ;
/*Need to add other interfaces*/
default :
return - EINVAL ;
}
/* check whether signal is locked */
2009-06-19 07:13:44 -03:00
sync_lock_status = tvp514x_read_reg ( sd , REG_STATUS1 ) ;
2013-05-29 10:19:00 -03:00
if ( lock_mask ! = ( sync_lock_status & lock_mask ) ) {
* std_id = V4L2_STD_UNKNOWN ;
2010-05-09 06:30:15 -03:00
return 0 ; /* No input detected */
2013-05-29 10:19:00 -03:00
}
2008-12-05 10:19:36 -03:00
2013-05-29 10:19:00 -03:00
* std_id & = decoder - > std_list [ current_std ] . standard . id ;
2008-12-05 10:19:36 -03:00
2010-05-09 06:30:15 -03:00
v4l2_dbg ( 1 , debug , sd , " Current STD: %s \n " ,
2008-12-05 10:19:36 -03:00
decoder - > std_list [ current_std ] . standard . name ) ;
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_s_std ( ) - V4L2 decoder interface handler for s_std
2009-06-19 07:13:44 -03:00
* @ sd : pointer to standard V4L2 sub - device structure
2008-12-05 10:19:36 -03:00
* @ std_id : standard V4L2 v4l2_std_id ioctl enum
*
* If std_id is supported , sets the requested standard . Otherwise , returns
* - EINVAL
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_s_std ( struct v4l2_subdev * sd , v4l2_std_id std_id )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
int err , i ;
for ( i = 0 ; i < decoder - > num_stds ; i + + )
2009-06-19 07:13:44 -03:00
if ( std_id & decoder - > std_list [ i ] . standard . id )
2008-12-05 10:19:36 -03:00
break ;
if ( ( i = = decoder - > num_stds ) | | ( i = = STD_INVALID ) )
return - EINVAL ;
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , REG_VIDEO_STD ,
2008-12-05 10:19:36 -03:00
decoder - > std_list [ i ] . video_std ) ;
if ( err )
return err ;
decoder - > current_std = i ;
2009-01-12 06:17:43 -03:00
decoder - > tvp514x_regs [ REG_VIDEO_STD ] . val =
decoder - > std_list [ i ] . video_std ;
2008-12-05 10:19:36 -03:00
2010-05-09 06:39:44 -03:00
v4l2_dbg ( 1 , debug , sd , " Standard set to: %s \n " ,
2008-12-05 10:19:36 -03:00
decoder - > std_list [ i ] . standard . name ) ;
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_s_routing ( ) - V4L2 decoder interface handler for s_routing
2009-06-19 07:13:44 -03:00
* @ sd : pointer to standard V4L2 sub - device structure
2009-07-01 04:20:43 -03:00
* @ input : input selector for routing the signal
* @ output : output selector for routing the signal
* @ config : config value . Not used
2008-12-05 10:19:36 -03:00
*
* If index is valid , selects the requested input . Otherwise , returns - EINVAL if
* the input is not supported or there is no active signal present in the
* selected input .
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_s_routing ( struct v4l2_subdev * sd ,
u32 input , u32 output , u32 config )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
int err ;
enum tvp514x_input input_sel ;
enum tvp514x_output output_sel ;
2009-06-19 07:13:44 -03:00
if ( ( input > = INPUT_INVALID ) | |
( output > = OUTPUT_INVALID ) )
2009-07-01 04:20:43 -03:00
/* Index out of bound */
return - EINVAL ;
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
input_sel = input ;
output_sel = output ;
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , REG_INPUT_SEL , input_sel ) ;
2008-12-05 10:19:36 -03:00
if ( err )
return err ;
2009-06-19 07:13:44 -03:00
output_sel | = tvp514x_read_reg ( sd ,
2008-12-05 10:19:36 -03:00
REG_OUTPUT_FORMATTER1 ) & 0x7 ;
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , REG_OUTPUT_FORMATTER1 ,
2008-12-05 10:19:36 -03:00
output_sel ) ;
if ( err )
return err ;
2009-01-12 06:17:43 -03:00
decoder - > tvp514x_regs [ REG_INPUT_SEL ] . val = input_sel ;
decoder - > tvp514x_regs [ REG_OUTPUT_FORMATTER1 ] . val = output_sel ;
2009-06-19 07:13:44 -03:00
decoder - > input = input ;
decoder - > output = output ;
2008-12-05 10:19:36 -03:00
2010-05-09 06:30:15 -03:00
v4l2_dbg ( 1 , debug , sd , " Input set to: %d \n " , input_sel ) ;
2008-12-05 10:19:36 -03:00
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_s_ctrl ( ) - V4L2 decoder interface handler for s_ctrl
2010-12-12 08:45:22 -03:00
* @ ctrl : pointer to v4l2_ctrl structure
2008-12-05 10:19:36 -03:00
*
* If the requested control is supported , sets the control ' s current
* value in HW . Otherwise , returns - EINVAL if the control is not supported .
*/
2010-12-12 08:45:22 -03:00
static int tvp514x_s_ctrl ( struct v4l2_ctrl * ctrl )
2008-12-05 10:19:36 -03:00
{
2010-12-12 08:45:22 -03:00
struct v4l2_subdev * sd = to_sd ( ctrl ) ;
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
int err = - EINVAL , value ;
2010-12-12 08:45:22 -03:00
value = ctrl - > val ;
2008-12-05 10:19:36 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
2010-12-12 08:45:22 -03:00
err = tvp514x_write_reg ( sd , REG_BRIGHTNESS , value ) ;
if ( ! err )
decoder - > tvp514x_regs [ REG_BRIGHTNESS ] . val = value ;
2008-12-05 10:19:36 -03:00
break ;
case V4L2_CID_CONTRAST :
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , REG_CONTRAST , value ) ;
2010-12-12 08:45:22 -03:00
if ( ! err )
decoder - > tvp514x_regs [ REG_CONTRAST ] . val = value ;
2008-12-05 10:19:36 -03:00
break ;
case V4L2_CID_SATURATION :
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , REG_SATURATION , value ) ;
2010-12-12 08:45:22 -03:00
if ( ! err )
decoder - > tvp514x_regs [ REG_SATURATION ] . val = value ;
2008-12-05 10:19:36 -03:00
break ;
case V4L2_CID_HUE :
if ( value = = 180 )
value = 0x7F ;
else if ( value = = - 180 )
value = 0x80 ;
2009-06-19 07:13:44 -03:00
err = tvp514x_write_reg ( sd , REG_HUE , value ) ;
2010-12-12 08:45:22 -03:00
if ( ! err )
decoder - > tvp514x_regs [ REG_HUE ] . val = value ;
2008-12-05 10:19:36 -03:00
break ;
case V4L2_CID_AUTOGAIN :
2010-12-12 08:45:22 -03:00
err = tvp514x_write_reg ( sd , REG_AFE_GAIN_CTRL , value ? 0x0f : 0x0c ) ;
if ( ! err )
decoder - > tvp514x_regs [ REG_AFE_GAIN_CTRL ] . val = value ;
2008-12-05 10:19:36 -03:00
break ;
}
2010-05-09 06:39:44 -03:00
v4l2_dbg ( 1 , debug , sd , " Set Control: ID - %d - %d \n " ,
2010-12-12 08:45:22 -03:00
ctrl - > id , ctrl - > val ) ;
2008-12-05 10:19:36 -03:00
return err ;
}
static int
2023-12-13 17:00:04 +02:00
tvp514x_get_frame_interval ( struct v4l2_subdev * sd ,
struct v4l2_subdev_state * sd_state ,
struct v4l2_subdev_frame_interval * ival )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
enum tvp514x_std current_std ;
2023-12-13 17:00:05 +02:00
/*
* FIXME : Implement support for V4L2_SUBDEV_FORMAT_TRY , using the V4L2
* subdev active state API .
*/
if ( ival - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
2008-12-05 10:19:36 -03:00
/* get the current standard */
2010-05-09 06:30:15 -03:00
current_std = decoder - > current_std ;
2008-12-05 10:19:36 -03:00
2018-01-22 04:00:45 -05:00
ival - > interval =
2008-12-05 10:19:36 -03:00
decoder - > std_list [ current_std ] . standard . frameperiod ;
return 0 ;
}
static int
2023-12-13 17:00:04 +02:00
tvp514x_set_frame_interval ( struct v4l2_subdev * sd ,
struct v4l2_subdev_state * sd_state ,
struct v4l2_subdev_frame_interval * ival )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
struct v4l2_fract * timeperframe ;
enum tvp514x_std current_std ;
2023-12-13 17:00:05 +02:00
/*
* FIXME : Implement support for V4L2_SUBDEV_FORMAT_TRY , using the V4L2
* subdev active state API .
*/
if ( ival - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
return - EINVAL ;
2008-12-05 10:19:36 -03:00
2018-01-22 04:00:45 -05:00
timeperframe = & ival - > interval ;
2008-12-05 10:19:36 -03:00
/* get the current standard */
2010-05-09 06:30:15 -03:00
current_std = decoder - > current_std ;
2008-12-05 10:19:36 -03:00
* timeperframe =
decoder - > std_list [ current_std ] . standard . frameperiod ;
return 0 ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_s_stream ( ) - V4L2 decoder i / f handler for s_stream
2009-06-19 07:13:44 -03:00
* @ sd : pointer to standard V4L2 sub - device structure
* @ enable : streaming enable or disable
2008-12-05 10:19:36 -03:00
*
2009-06-19 07:13:44 -03:00
* Sets streaming to enable or disable , if possible .
2008-12-05 10:19:36 -03:00
*/
2009-06-19 07:13:44 -03:00
static int tvp514x_s_stream ( struct v4l2_subdev * sd , int enable )
2008-12-05 10:19:36 -03:00
{
int err = 0 ;
2009-06-19 07:13:44 -03:00
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
if ( decoder - > streaming = = enable )
return 0 ;
2008-12-05 10:19:36 -03:00
2009-06-19 07:13:44 -03:00
switch ( enable ) {
case 0 :
{
/* Power Down Sequence */
err = tvp514x_write_reg ( sd , REG_OPERATION_MODE , 0x01 ) ;
if ( err ) {
v4l2_err ( sd , " Unable to turn off decoder \n " ) ;
return err ;
}
decoder - > streaming = enable ;
2008-12-05 10:19:36 -03:00
break ;
2009-06-19 07:13:44 -03:00
}
case 1 :
{
/* Power Up Sequence */
2013-06-23 10:01:35 -03:00
err = tvp514x_write_regs ( sd , decoder - > int_seq ) ;
2009-06-19 07:13:44 -03:00
if ( err ) {
v4l2_err ( sd , " Unable to turn on decoder \n " ) ;
return err ;
}
/* Detect if not already detected */
err = tvp514x_detect ( sd , decoder ) ;
if ( err ) {
v4l2_err ( sd , " Unable to detect decoder \n " ) ;
return err ;
2008-12-05 10:19:36 -03:00
}
2009-06-19 07:13:44 -03:00
err = tvp514x_configure ( sd , decoder ) ;
if ( err ) {
v4l2_err ( sd , " Unable to configure decoder \n " ) ;
return err ;
}
decoder - > streaming = enable ;
2008-12-05 10:19:36 -03:00
break ;
2009-06-19 07:13:44 -03:00
}
2008-12-05 10:19:36 -03:00
default :
err = - ENODEV ;
break ;
}
return err ;
}
2010-12-12 08:45:22 -03:00
static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
2009-06-19 07:13:44 -03:00
. s_ctrl = tvp514x_s_ctrl ,
2010-12-12 08:45:22 -03:00
} ;
2013-03-08 04:13:35 -03:00
/**
* tvp514x_enum_mbus_code ( ) - V4L2 decoder interface handler for enum_mbus_code
* @ sd : pointer to standard V4L2 sub - device structure
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
* @ sd_state : subdev state
2013-03-08 04:13:35 -03:00
* @ code : pointer to v4l2_subdev_mbus_code_enum structure
*
* Enumertaes mbus codes supported
*/
static int tvp514x_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 ,
2013-03-08 04:13:35 -03:00
struct v4l2_subdev_mbus_code_enum * code )
{
u32 pad = code - > pad ;
u32 index = code - > index ;
memset ( code , 0 , sizeof ( * code ) ) ;
code - > index = index ;
code - > pad = pad ;
if ( index ! = 0 )
return - EINVAL ;
2016-09-14 17:03:13 -03:00
code - > code = MEDIA_BUS_FMT_UYVY8_2X8 ;
2013-03-08 04:13:35 -03:00
return 0 ;
}
/**
* tvp514x_get_pad_format ( ) - V4L2 decoder interface handler for get pad format
* @ sd : pointer to standard V4L2 sub - device structure
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
* @ sd_state : subdev state
2013-03-08 04:13:35 -03:00
* @ format : pointer to v4l2_subdev_format structure
*
* Retrieves pad format which is active or tried based on requirement
*/
static int tvp514x_get_pad_format ( 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 ,
2013-03-08 04:13:35 -03:00
struct v4l2_subdev_format * format )
{
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
__u32 which = format - > which ;
2015-04-09 04:02:34 -03:00
if ( format - > pad )
return - EINVAL ;
2013-03-08 04:13:35 -03:00
if ( which = = V4L2_SUBDEV_FORMAT_ACTIVE ) {
format - > format = decoder - > format ;
return 0 ;
}
2016-09-14 17:03:13 -03:00
format - > format . code = MEDIA_BUS_FMT_UYVY8_2X8 ;
2013-03-08 04:13:35 -03:00
format - > format . width = tvp514x_std_list [ decoder - > current_std ] . width ;
format - > format . height = tvp514x_std_list [ decoder - > current_std ] . height ;
format - > format . colorspace = V4L2_COLORSPACE_SMPTE170M ;
format - > format . field = V4L2_FIELD_INTERLACED ;
return 0 ;
}
/**
* tvp514x_set_pad_format ( ) - V4L2 decoder interface handler for set pad format
* @ sd : pointer to standard V4L2 sub - device structure
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
* @ sd_state : subdev state
2017-11-29 09:26:20 -05:00
* @ fmt : pointer to v4l2_subdev_format structure
2013-03-08 04:13:35 -03:00
*
* Set pad format for the output pad
*/
static int tvp514x_set_pad_format ( 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 ,
2013-03-08 04:13:35 -03:00
struct v4l2_subdev_format * fmt )
{
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
if ( fmt - > format . field ! = V4L2_FIELD_INTERLACED | |
2016-09-14 17:03:13 -03:00
fmt - > format . code ! = MEDIA_BUS_FMT_UYVY8_2X8 | |
2013-03-08 04:13:35 -03:00
fmt - > format . colorspace ! = V4L2_COLORSPACE_SMPTE170M | |
fmt - > format . width ! = tvp514x_std_list [ decoder - > current_std ] . width | |
fmt - > format . height ! = tvp514x_std_list [ decoder - > current_std ] . height )
return - EINVAL ;
decoder - > format = fmt - > format ;
return 0 ;
}
2009-06-19 07:13:44 -03:00
static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
2014-04-28 16:53:01 -03:00
. s_std = tvp514x_s_std ,
2009-06-19 07:13:44 -03:00
. s_routing = tvp514x_s_routing ,
. querystd = tvp514x_querystd ,
. s_stream = tvp514x_s_stream ,
} ;
2008-12-05 10:19:36 -03:00
2013-03-08 04:13:35 -03:00
static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = {
. enum_mbus_code = tvp514x_enum_mbus_code ,
. get_fmt = tvp514x_get_pad_format ,
. set_fmt = tvp514x_set_pad_format ,
2023-12-13 17:00:04 +02:00
. get_frame_interval = tvp514x_get_frame_interval ,
. set_frame_interval = tvp514x_set_frame_interval ,
2013-03-08 04:13:35 -03:00
} ;
2009-06-19 07:13:44 -03:00
static const struct v4l2_subdev_ops tvp514x_ops = {
. video = & tvp514x_video_ops ,
2013-03-08 04:13:35 -03:00
. pad = & tvp514x_pad_ops ,
2008-12-05 10:19:36 -03:00
} ;
2016-09-11 10:05:55 -03:00
static const struct tvp514x_decoder tvp514x_dev = {
2009-06-19 07:13:44 -03:00
. streaming = 0 ,
2013-03-08 04:13:35 -03:00
. fmt_list = tvp514x_fmt_list ,
. num_fmts = ARRAY_SIZE ( tvp514x_fmt_list ) ,
. pix = {
/* Default to NTSC 8-bit YUV 422 */
. width = NTSC_NUM_ACTIVE_PIXELS ,
. height = NTSC_NUM_ACTIVE_LINES ,
. pixelformat = V4L2_PIX_FMT_UYVY ,
. field = V4L2_FIELD_INTERLACED ,
. bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2 ,
. sizeimage = NTSC_NUM_ACTIVE_PIXELS * 2 *
NTSC_NUM_ACTIVE_LINES ,
. colorspace = V4L2_COLORSPACE_SMPTE170M ,
} ,
2008-12-05 10:19:36 -03:00
. current_std = STD_NTSC_MJ ,
. std_list = tvp514x_std_list ,
. num_stds = ARRAY_SIZE ( tvp514x_std_list ) ,
2009-06-19 07:13:44 -03:00
2008-12-05 10:19:36 -03:00
} ;
2013-06-04 12:26:23 -03:00
static struct tvp514x_platform_data *
tvp514x_get_pdata ( struct i2c_client * client )
{
2016-01-11 14:47:13 -02:00
struct tvp514x_platform_data * pdata = NULL ;
2018-07-31 05:15:50 -04:00
struct v4l2_fwnode_endpoint bus_cfg = { . bus_type = 0 } ;
2013-06-04 12:26:23 -03:00
struct device_node * endpoint ;
unsigned int flags ;
if ( ! IS_ENABLED ( CONFIG_OF ) | | ! client - > dev . of_node )
return client - > dev . platform_data ;
2014-02-10 22:01:48 +01:00
endpoint = of_graph_get_next_endpoint ( client - > dev . of_node , NULL ) ;
2013-06-04 12:26:23 -03:00
if ( ! endpoint )
return NULL ;
2016-08-26 20:17:25 -03:00
if ( v4l2_fwnode_endpoint_parse ( of_fwnode_handle ( endpoint ) , & bus_cfg ) )
2016-01-11 14:47:13 -02:00
goto done ;
2013-06-04 12:26:23 -03:00
pdata = devm_kzalloc ( & client - > dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
goto done ;
flags = bus_cfg . bus . parallel . flags ;
if ( flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH )
pdata - > hs_polarity = 1 ;
if ( flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH )
pdata - > vs_polarity = 1 ;
if ( flags & V4L2_MBUS_PCLK_SAMPLE_RISING )
pdata - > clk_polarity = 1 ;
done :
of_node_put ( endpoint ) ;
return pdata ;
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_probe ( ) - decoder driver i2c probe handler
2008-12-05 10:19:36 -03:00
* @ client : i2c driver client device structure
*
* Register decoder as an i2c client device and V4L2
* device .
*/
static int
2022-11-18 23:41:56 +01:00
tvp514x_probe ( struct i2c_client * client )
2008-12-05 10:19:36 -03:00
{
2013-06-04 12:26:23 -03:00
struct tvp514x_platform_data * pdata = tvp514x_get_pdata ( client ) ;
2009-01-12 06:17:43 -03:00
struct tvp514x_decoder * decoder ;
2009-06-19 07:13:44 -03:00
struct v4l2_subdev * sd ;
2013-03-08 04:13:35 -03:00
int ret ;
2008-12-05 10:19:36 -03:00
2013-06-04 12:26:23 -03:00
if ( pdata = = NULL ) {
dev_err ( & client - > dev , " No platform data \n " ) ;
return - EINVAL ;
}
2008-12-05 10:19:36 -03:00
/* Check if the adapter supports the needed features */
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - EIO ;
2013-01-03 10:04:57 -03:00
decoder = devm_kzalloc ( & client - > dev , sizeof ( * decoder ) , GFP_KERNEL ) ;
2009-01-12 06:17:43 -03:00
if ( ! decoder )
return - ENOMEM ;
2009-07-01 04:20:43 -03:00
/* Initialize the tvp514x_decoder with default configuration */
2009-01-12 06:17:43 -03:00
* decoder = tvp514x_dev ;
2009-06-19 07:13:44 -03:00
/* Copy default register configuration */
2009-01-12 06:17:43 -03:00
memcpy ( decoder - > tvp514x_regs , tvp514x_reg_list_default ,
sizeof ( tvp514x_reg_list_default ) ) ;
2009-06-19 07:13:44 -03:00
2023-09-23 17:36:39 +01:00
decoder - > int_seq = i2c_get_match_data ( client ) ;
2013-06-23 10:01:35 -03:00
2009-07-01 04:20:43 -03:00
/* Copy board specific information here */
2013-06-04 12:26:23 -03:00
decoder - > pdata = pdata ;
2009-06-19 07:13:44 -03:00
2009-07-01 04:20:43 -03:00
/**
2008-12-05 10:19:36 -03:00
* Fetch platform specific data , and configure the
* tvp514x_reg_list [ ] accordingly . Since this is one
* time configuration , no need to preserve .
*/
2009-01-12 06:17:43 -03:00
decoder - > tvp514x_regs [ REG_OUTPUT_FORMATTER2 ] . val | =
2009-06-19 07:13:44 -03:00
( decoder - > pdata - > clk_polarity < < 1 ) ;
2009-01-12 06:17:43 -03:00
decoder - > tvp514x_regs [ REG_SYNC_CONTROL ] . val | =
2009-06-19 07:13:44 -03:00
( ( decoder - > pdata - > hs_polarity < < 2 ) |
( decoder - > pdata - > vs_polarity < < 3 ) ) ;
/* Set default standard to auto */
decoder - > tvp514x_regs [ REG_VIDEO_STD ] . val =
VIDEO_STD_AUTO_SWITCH_BIT ;
2008-12-05 10:19:36 -03:00
/* Register with V4L2 layer as slave device */
2009-06-19 07:13:44 -03:00
sd = & decoder - > sd ;
v4l2_i2c_subdev_init ( sd , client , & tvp514x_ops ) ;
2013-03-08 04:13:35 -03:00
# if defined(CONFIG_MEDIA_CONTROLLER)
decoder - > pad . flags = MEDIA_PAD_FL_SOURCE ;
decoder - > sd . flags | = V4L2_SUBDEV_FL_HAS_DEVNODE ;
2018-06-18 05:09:45 -04:00
decoder - > sd . entity . function = MEDIA_ENT_F_ATV_DECODER ;
2013-03-08 04:13:35 -03:00
2015-12-11 07:44:40 -02:00
ret = media_entity_pads_init ( & decoder - > sd . entity , 1 , & decoder - > pad ) ;
2013-03-08 04:13:35 -03:00
if ( ret < 0 ) {
v4l2_err ( sd , " %s decoder driver failed to register !! \n " ,
sd - > name ) ;
return ret ;
}
# endif
2010-12-12 08:45:22 -03:00
v4l2_ctrl_handler_init ( & decoder - > hdl , 5 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & tvp514x_ctrl_ops ,
V4L2_CID_BRIGHTNESS , 0 , 255 , 1 , 128 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & tvp514x_ctrl_ops ,
V4L2_CID_CONTRAST , 0 , 255 , 1 , 128 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & tvp514x_ctrl_ops ,
V4L2_CID_SATURATION , 0 , 255 , 1 , 128 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & tvp514x_ctrl_ops ,
V4L2_CID_HUE , - 180 , 180 , 180 , 0 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & tvp514x_ctrl_ops ,
V4L2_CID_AUTOGAIN , 0 , 1 , 1 , 1 ) ;
sd - > ctrl_handler = & decoder - > hdl ;
if ( decoder - > hdl . error ) {
2013-03-08 04:13:35 -03:00
ret = decoder - > hdl . error ;
2013-06-24 11:51:39 -03:00
goto done ;
2010-12-12 08:45:22 -03:00
}
v4l2_ctrl_handler_setup ( & decoder - > hdl ) ;
2013-06-24 11:51:39 -03:00
ret = v4l2_async_register_subdev ( & decoder - > sd ) ;
if ( ! ret )
v4l2_info ( sd , " %s decoder driver registered !! \n " , sd - > name ) ;
2009-01-12 06:17:43 -03:00
2013-06-24 11:51:39 -03:00
done :
if ( ret < 0 ) {
v4l2_ctrl_handler_free ( & decoder - > hdl ) ;
media_entity_cleanup ( & decoder - > sd . entity ) ;
}
return ret ;
2008-12-05 10:19:36 -03:00
}
2009-07-01 04:20:43 -03:00
/**
* tvp514x_remove ( ) - decoder driver i2c remove handler
2008-12-05 10:19:36 -03:00
* @ client : i2c driver client device structure
*
* Unregister decoder as an i2c client device and V4L2
* device . Complement of tvp514x_probe ( ) .
*/
2022-08-15 10:02:30 +02:00
static void tvp514x_remove ( struct i2c_client * client )
2008-12-05 10:19:36 -03:00
{
2009-06-19 07:13:44 -03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
struct tvp514x_decoder * decoder = to_decoder ( sd ) ;
2008-12-05 10:19:36 -03:00
2013-06-24 11:51:39 -03:00
v4l2_async_unregister_subdev ( & decoder - > sd ) ;
2013-03-08 04:13:35 -03:00
media_entity_cleanup ( & decoder - > sd . entity ) ;
2010-12-12 08:45:22 -03:00
v4l2_ctrl_handler_free ( & decoder - > hdl ) ;
2008-12-05 10:19:36 -03:00
}
2009-07-01 04:20:43 -03:00
/* TVP5146 Init/Power on Sequence */
2008-12-05 10:19:36 -03:00
static const struct tvp514x_reg tvp5146_init_reg_seq [ ] = {
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS1 , 0x02 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS2 , 0x00 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS3 , 0x80 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x01 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS1 , 0x60 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS2 , 0x00 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS3 , 0xB0 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x01 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x00 } ,
{ TOK_WRITE , REG_OPERATION_MODE , 0x01 } ,
{ TOK_WRITE , REG_OPERATION_MODE , 0x00 } ,
2009-06-19 07:13:44 -03:00
{ TOK_TERM , 0 , 0 } ,
2008-12-05 10:19:36 -03:00
} ;
2009-06-19 07:13:44 -03:00
2009-07-01 04:20:43 -03:00
/* TVP5147 Init/Power on Sequence */
2008-12-05 10:19:36 -03:00
static const struct tvp514x_reg tvp5147_init_reg_seq [ ] = {
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS1 , 0x02 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS2 , 0x00 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS3 , 0x80 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x01 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS1 , 0x60 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS2 , 0x00 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS3 , 0xB0 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x01 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS1 , 0x16 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS2 , 0x00 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS3 , 0xA0 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x16 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS1 , 0x60 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS2 , 0x00 } ,
{ TOK_WRITE , REG_VBUS_ADDRESS_ACCESS3 , 0xB0 } ,
{ TOK_WRITE , REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR , 0x00 } ,
{ TOK_WRITE , REG_OPERATION_MODE , 0x01 } ,
{ TOK_WRITE , REG_OPERATION_MODE , 0x00 } ,
2009-06-19 07:13:44 -03:00
{ TOK_TERM , 0 , 0 } ,
2008-12-05 10:19:36 -03:00
} ;
2009-06-19 07:13:44 -03:00
2009-07-01 04:20:43 -03:00
/* TVP5146M2/TVP5147M1 Init/Power on Sequence */
2008-12-05 10:19:36 -03:00
static const struct tvp514x_reg tvp514xm_init_reg_seq [ ] = {
{ TOK_WRITE , REG_OPERATION_MODE , 0x01 } ,
{ TOK_WRITE , REG_OPERATION_MODE , 0x00 } ,
2009-06-19 07:13:44 -03:00
{ TOK_TERM , 0 , 0 } ,
2008-12-05 10:19:36 -03:00
} ;
2009-06-19 07:13:44 -03:00
2017-11-29 09:26:20 -05:00
/*
2008-12-05 10:19:36 -03:00
* I2C Device Table -
*
* name - Name of the actual device / chip .
* driver_data - Driver data
*/
static const struct i2c_device_id tvp514x_id [ ] = {
2023-09-23 17:36:39 +01:00
{ " tvp5146 " , ( kernel_ulong_t ) tvp5146_init_reg_seq } ,
{ " tvp5146m2 " , ( kernel_ulong_t ) tvp514xm_init_reg_seq } ,
{ " tvp5147 " , ( kernel_ulong_t ) tvp5147_init_reg_seq } ,
{ " tvp5147m1 " , ( kernel_ulong_t ) tvp514xm_init_reg_seq } ,
{ /* sentinel */ }
2008-12-05 10:19:36 -03:00
} ;
MODULE_DEVICE_TABLE ( i2c , tvp514x_id ) ;
2013-06-04 12:26:23 -03:00
static const struct of_device_id tvp514x_of_match [ ] = {
2023-09-23 17:36:39 +01:00
{ . compatible = " ti,tvp5146 " , . data = tvp5146_init_reg_seq } ,
{ . compatible = " ti,tvp5146m2 " , . data = tvp514xm_init_reg_seq } ,
{ . compatible = " ti,tvp5147 " , . data = tvp5147_init_reg_seq } ,
{ . compatible = " ti,tvp5147m1 " , . data = tvp514xm_init_reg_seq } ,
{ /* sentinel */ }
2013-06-04 12:26:23 -03:00
} ;
MODULE_DEVICE_TABLE ( of , tvp514x_of_match ) ;
2009-06-19 07:13:44 -03:00
static struct i2c_driver tvp514x_driver = {
2008-12-05 10:19:36 -03:00
. driver = {
2023-09-23 17:36:40 +01:00
. of_match_table = tvp514x_of_match ,
2009-06-19 07:13:44 -03:00
. name = TVP514X_MODULE_NAME ,
} ,
2023-05-14 14:04:07 +02:00
. probe = tvp514x_probe ,
2009-06-19 07:13:44 -03:00
. remove = tvp514x_remove ,
2008-12-05 10:19:36 -03:00
. id_table = tvp514x_id ,
} ;
2012-02-12 06:56:32 -03:00
module_i2c_driver ( tvp514x_driver ) ;