2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-05-20 02:27:28 -03:00
/*
* Driver for M - 5 MOLS 8 M Pixel camera sensor with ISP
*
* Copyright ( C ) 2011 Samsung Electronics Co . , Ltd .
2011-06-07 02:00:58 -03:00
* Author : HeungJun Kim < riverful . kim @ samsung . com >
2011-05-20 02:27:28 -03:00
*
* Copyright ( C ) 2009 Samsung Electronics Co . , Ltd .
2011-06-07 02:00:58 -03:00
* Author : Dongsoo Nathaniel Kim < dongsoo45 . kim @ samsung . com >
2011-05-20 02:27:28 -03:00
*/
# include <linux/i2c.h>
# include <linux/slab.h>
# include <linux/irq.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
2022-02-24 01:13:07 +01:00
# include <linux/gpio/consumer.h>
2011-05-20 02:27:28 -03:00
# include <linux/regulator/consumer.h>
# include <linux/videodev2.h>
2011-07-03 14:03:12 -04:00
# include <linux/module.h>
2011-05-20 02:27:28 -03:00
# include <media/v4l2-ctrls.h>
# include <media/v4l2-device.h>
# include <media/v4l2-subdev.h>
2015-11-10 12:01:44 -02:00
# include <media/i2c/m5mols.h>
2011-05-20 02:27:28 -03:00
# include "m5mols.h"
# include "m5mols_reg.h"
int m5mols_debug ;
module_param ( m5mols_debug , int , 0644 ) ;
# define MODULE_NAME "M5MOLS"
# define M5MOLS_I2C_CHECK_RETRY 500
/* The regulator consumer names for external voltage regulators */
static struct regulator_bulk_data supplies [ ] = {
{
. supply = " core " , /* ARM core power, 1.2V */
} , {
. supply = " dig_18 " , /* digital power 1, 1.8V */
} , {
. supply = " d_sensor " , /* sensor power 1, 1.8V */
} , {
. supply = " dig_28 " , /* digital power 2, 2.8V */
} , {
. supply = " a_sensor " , /* analog power */
} , {
. supply = " dig_12 " , /* digital power 3, 1.2V */
} ,
} ;
static struct v4l2_mbus_framefmt m5mols_default_ffmt [ M5MOLS_RESTYPE_MAX ] = {
[ M5MOLS_RESTYPE_MONITOR ] = {
. width = 1920 ,
. height = 1080 ,
2014-11-10 14:28:29 -03:00
. code = MEDIA_BUS_FMT_VYUY8_2X8 ,
2011-05-20 02:27:28 -03:00
. field = V4L2_FIELD_NONE ,
. colorspace = V4L2_COLORSPACE_JPEG ,
} ,
[ M5MOLS_RESTYPE_CAPTURE ] = {
. width = 1920 ,
. height = 1080 ,
2014-11-10 14:28:29 -03:00
. code = MEDIA_BUS_FMT_JPEG_1X8 ,
2011-05-20 02:27:28 -03:00
. field = V4L2_FIELD_NONE ,
. colorspace = V4L2_COLORSPACE_JPEG ,
} ,
} ;
# define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt)
static const struct m5mols_resolution m5mols_reg_res [ ] = {
{ 0x01 , M5MOLS_RESTYPE_MONITOR , 128 , 96 } , /* SUB-QCIF */
{ 0x03 , M5MOLS_RESTYPE_MONITOR , 160 , 120 } , /* QQVGA */
{ 0x05 , M5MOLS_RESTYPE_MONITOR , 176 , 144 } , /* QCIF */
{ 0x06 , M5MOLS_RESTYPE_MONITOR , 176 , 176 } ,
{ 0x08 , M5MOLS_RESTYPE_MONITOR , 240 , 320 } , /* QVGA */
{ 0x09 , M5MOLS_RESTYPE_MONITOR , 320 , 240 } , /* QVGA */
{ 0x0c , M5MOLS_RESTYPE_MONITOR , 240 , 400 } , /* WQVGA */
{ 0x0d , M5MOLS_RESTYPE_MONITOR , 400 , 240 } , /* WQVGA */
{ 0x0e , M5MOLS_RESTYPE_MONITOR , 352 , 288 } , /* CIF */
{ 0x13 , M5MOLS_RESTYPE_MONITOR , 480 , 360 } ,
{ 0x15 , M5MOLS_RESTYPE_MONITOR , 640 , 360 } , /* qHD */
{ 0x17 , M5MOLS_RESTYPE_MONITOR , 640 , 480 } , /* VGA */
{ 0x18 , M5MOLS_RESTYPE_MONITOR , 720 , 480 } ,
{ 0x1a , M5MOLS_RESTYPE_MONITOR , 800 , 480 } , /* WVGA */
{ 0x1f , M5MOLS_RESTYPE_MONITOR , 800 , 600 } , /* SVGA */
{ 0x21 , M5MOLS_RESTYPE_MONITOR , 1280 , 720 } , /* HD */
{ 0x25 , M5MOLS_RESTYPE_MONITOR , 1920 , 1080 } , /* 1080p */
{ 0x29 , M5MOLS_RESTYPE_MONITOR , 3264 , 2448 } , /* 2.63fps 8M */
{ 0x39 , M5MOLS_RESTYPE_MONITOR , 800 , 602 } , /* AHS_MON debug */
{ 0x02 , M5MOLS_RESTYPE_CAPTURE , 320 , 240 } , /* QVGA */
{ 0x04 , M5MOLS_RESTYPE_CAPTURE , 400 , 240 } , /* WQVGA */
{ 0x07 , M5MOLS_RESTYPE_CAPTURE , 480 , 360 } ,
{ 0x08 , M5MOLS_RESTYPE_CAPTURE , 640 , 360 } , /* qHD */
{ 0x09 , M5MOLS_RESTYPE_CAPTURE , 640 , 480 } , /* VGA */
{ 0x0a , M5MOLS_RESTYPE_CAPTURE , 800 , 480 } , /* WVGA */
{ 0x10 , M5MOLS_RESTYPE_CAPTURE , 1280 , 720 } , /* HD */
{ 0x14 , M5MOLS_RESTYPE_CAPTURE , 1280 , 960 } , /* 1M */
{ 0x17 , M5MOLS_RESTYPE_CAPTURE , 1600 , 1200 } , /* 2M */
{ 0x19 , M5MOLS_RESTYPE_CAPTURE , 1920 , 1080 } , /* Full-HD */
{ 0x1a , M5MOLS_RESTYPE_CAPTURE , 2048 , 1152 } , /* 3Mega */
{ 0x1b , M5MOLS_RESTYPE_CAPTURE , 2048 , 1536 } ,
{ 0x1c , M5MOLS_RESTYPE_CAPTURE , 2560 , 1440 } , /* 4Mega */
{ 0x1d , M5MOLS_RESTYPE_CAPTURE , 2560 , 1536 } ,
{ 0x1f , M5MOLS_RESTYPE_CAPTURE , 2560 , 1920 } , /* 5Mega */
{ 0x21 , M5MOLS_RESTYPE_CAPTURE , 3264 , 1836 } , /* 6Mega */
{ 0x22 , M5MOLS_RESTYPE_CAPTURE , 3264 , 1960 } ,
{ 0x25 , M5MOLS_RESTYPE_CAPTURE , 3264 , 2448 } , /* 8Mega */
} ;
/**
* m5mols_swap_byte - an byte array to integer conversion function
2017-11-29 04:08:14 -05:00
* @ data : byte array
* @ length : size in bytes of I2C packet defined in the M - 5 MOLS datasheet
2011-05-20 02:27:28 -03:00
*
* Convert I2C data byte array with performing any required byte
* reordering to assure proper values for each data type , regardless
* of the architecture endianness .
*/
static u32 m5mols_swap_byte ( u8 * data , u8 length )
{
if ( length = = 1 )
return * data ;
else if ( length = = 2 )
2014-12-13 08:52:57 -03:00
return be16_to_cpu ( * ( ( __be16 * ) data ) ) ;
2011-05-20 02:27:28 -03:00
else
2014-12-13 08:52:57 -03:00
return be32_to_cpu ( * ( ( __be32 * ) data ) ) ;
2011-05-20 02:27:28 -03:00
}
/**
* m5mols_read - I2C read function
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
2011-05-31 03:44:19 -03:00
* @ size : desired size of I2C packet
2017-11-29 04:08:14 -05:00
* @ reg : combination of size , category and command for the I2C packet
2011-05-20 02:27:28 -03:00
* @ val : read value
2011-12-03 11:47:40 -03:00
*
* Returns 0 on success , or else negative errno .
2011-05-20 02:27:28 -03:00
*/
2011-05-31 03:44:19 -03:00
static int m5mols_read ( struct v4l2_subdev * sd , u32 size , u32 reg , u32 * val )
2011-05-20 02:27:28 -03:00
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2011-12-03 11:47:40 -03:00
struct m5mols_info * info = to_m5mols ( sd ) ;
2011-05-20 02:27:28 -03:00
u8 rbuf [ M5MOLS_I2C_MAX_SIZE + 1 ] ;
u8 category = I2C_CATEGORY ( reg ) ;
u8 cmd = I2C_COMMAND ( reg ) ;
struct i2c_msg msg [ 2 ] ;
u8 wbuf [ 5 ] ;
int ret ;
if ( ! client - > adapter )
return - ENODEV ;
msg [ 0 ] . addr = client - > addr ;
msg [ 0 ] . flags = 0 ;
msg [ 0 ] . len = 5 ;
msg [ 0 ] . buf = wbuf ;
wbuf [ 0 ] = 5 ;
wbuf [ 1 ] = M5MOLS_BYTE_READ ;
wbuf [ 2 ] = category ;
wbuf [ 3 ] = cmd ;
wbuf [ 4 ] = size ;
msg [ 1 ] . addr = client - > addr ;
msg [ 1 ] . flags = I2C_M_RD ;
msg [ 1 ] . len = size + 1 ;
msg [ 1 ] . buf = rbuf ;
/* minimum stabilization time */
2016-12-13 03:34:53 -02:00
usleep_range ( 200 , 300 ) ;
2011-05-20 02:27:28 -03:00
ret = i2c_transfer ( client - > adapter , msg , 2 ) ;
2011-12-03 11:47:40 -03:00
if ( ret = = 2 ) {
* val = m5mols_swap_byte ( & rbuf [ 1 ] , size ) ;
return 0 ;
2011-05-20 02:27:28 -03:00
}
2011-12-03 11:47:40 -03:00
if ( info - > isp_ready )
v4l2_err ( sd , " read failed: size:%d cat:%02x cmd:%02x. %d \n " ,
size , category , cmd , ret ) ;
2011-05-20 02:27:28 -03:00
2011-12-03 11:47:40 -03:00
return ret < 0 ? ret : - EIO ;
2011-05-20 02:27:28 -03:00
}
2011-05-31 03:44:19 -03:00
int m5mols_read_u8 ( struct v4l2_subdev * sd , u32 reg , u8 * val )
{
u32 val_32 ;
int ret ;
if ( I2C_SIZE ( reg ) ! = 1 ) {
v4l2_err ( sd , " Wrong data size \n " ) ;
return - EINVAL ;
}
ret = m5mols_read ( sd , I2C_SIZE ( reg ) , reg , & val_32 ) ;
if ( ret )
return ret ;
* val = ( u8 ) val_32 ;
return ret ;
}
int m5mols_read_u16 ( struct v4l2_subdev * sd , u32 reg , u16 * val )
{
u32 val_32 ;
int ret ;
if ( I2C_SIZE ( reg ) ! = 2 ) {
v4l2_err ( sd , " Wrong data size \n " ) ;
return - EINVAL ;
}
ret = m5mols_read ( sd , I2C_SIZE ( reg ) , reg , & val_32 ) ;
if ( ret )
return ret ;
* val = ( u16 ) val_32 ;
return ret ;
}
int m5mols_read_u32 ( struct v4l2_subdev * sd , u32 reg , u32 * val )
{
if ( I2C_SIZE ( reg ) ! = 4 ) {
v4l2_err ( sd , " Wrong data size \n " ) ;
return - EINVAL ;
}
return m5mols_read ( sd , I2C_SIZE ( reg ) , reg , val ) ;
}
2011-05-20 02:27:28 -03:00
/**
* m5mols_write - I2C command write function
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
2011-05-20 02:27:28 -03:00
* @ reg : combination of size , category and command for the I2C packet
* @ val : value to write
2011-12-03 11:47:40 -03:00
*
* Returns 0 on success , or else negative errno .
2011-05-20 02:27:28 -03:00
*/
int m5mols_write ( struct v4l2_subdev * sd , u32 reg , u32 val )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2011-12-03 11:47:40 -03:00
struct m5mols_info * info = to_m5mols ( sd ) ;
2011-05-20 02:27:28 -03:00
u8 wbuf [ M5MOLS_I2C_MAX_SIZE + 4 ] ;
u8 category = I2C_CATEGORY ( reg ) ;
u8 cmd = I2C_COMMAND ( reg ) ;
u8 size = I2C_SIZE ( reg ) ;
u32 * buf = ( u32 * ) & wbuf [ 4 ] ;
struct i2c_msg msg [ 1 ] ;
int ret ;
if ( ! client - > adapter )
return - ENODEV ;
if ( size ! = 1 & & size ! = 2 & & size ! = 4 ) {
v4l2_err ( sd , " Wrong data size \n " ) ;
return - EINVAL ;
}
msg - > addr = client - > addr ;
msg - > flags = 0 ;
msg - > len = ( u16 ) size + 4 ;
msg - > buf = wbuf ;
wbuf [ 0 ] = size + 4 ;
wbuf [ 1 ] = M5MOLS_BYTE_WRITE ;
wbuf [ 2 ] = category ;
wbuf [ 3 ] = cmd ;
* buf = m5mols_swap_byte ( ( u8 * ) & val , size ) ;
2016-12-13 03:34:53 -02:00
/* minimum stabilization time */
usleep_range ( 200 , 300 ) ;
2011-05-20 02:27:28 -03:00
ret = i2c_transfer ( client - > adapter , msg , 1 ) ;
2011-12-03 11:47:40 -03:00
if ( ret = = 1 )
return 0 ;
2011-05-20 02:27:28 -03:00
2011-12-03 11:47:40 -03:00
if ( info - > isp_ready )
v4l2_err ( sd , " write failed: cat:%02x cmd:%02x ret:%d \n " ,
category , cmd , ret ) ;
return ret < 0 ? ret : - EIO ;
2011-05-20 02:27:28 -03:00
}
2011-12-12 08:04:03 -03:00
/**
* m5mols_busy_wait - Busy waiting with I2C register polling
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
2011-12-12 08:04:03 -03:00
* @ reg : the I2C_REG ( ) address of an 8 - bit status register to check
* @ value : expected status register value
* @ mask : bit mask for the read status register value
2019-02-18 14:28:58 -05:00
* @ timeout : timeout in milliseconds , or - 1 for default timeout
2011-12-12 08:04:03 -03:00
*
* The @ reg register value is ORed with @ mask before comparing with @ value .
*
* Return : 0 if the requested condition became true within less than
* @ timeout ms , or else negative errno .
*/
int m5mols_busy_wait ( struct v4l2_subdev * sd , u32 reg , u32 value , u32 mask ,
int timeout )
2011-05-20 02:27:28 -03:00
{
2011-12-12 08:04:03 -03:00
int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout ;
unsigned long end = jiffies + msecs_to_jiffies ( ms ) ;
u8 status ;
2011-05-20 02:27:28 -03:00
2011-12-12 08:04:03 -03:00
do {
int ret = m5mols_read_u8 ( sd , reg , & status ) ;
if ( ret < 0 & & ! ( mask & M5MOLS_I2C_RDY_WAIT_FL ) )
2011-05-20 02:27:28 -03:00
return ret ;
2011-12-12 08:04:03 -03:00
if ( ! ret & & ( status & mask & 0xff ) = = ( value & 0xff ) )
2011-05-20 02:27:28 -03:00
return 0 ;
2011-12-12 08:04:03 -03:00
usleep_range ( 100 , 250 ) ;
} while ( ms > 0 & & time_is_after_jiffies ( end ) ) ;
2011-05-20 02:27:28 -03:00
return - EBUSY ;
}
/**
* m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
* @ reg : combination of size , category and command for the I2C packet
2011-05-20 02:27:28 -03:00
*
* Before writing desired interrupt value the INT_FACTOR register should
* be read to clear pending interrupts .
*/
2011-05-31 03:44:19 -03:00
int m5mols_enable_interrupt ( struct v4l2_subdev * sd , u8 reg )
2011-05-20 02:27:28 -03:00
{
struct m5mols_info * info = to_m5mols ( sd ) ;
2011-05-31 03:44:19 -03:00
u8 mask = is_available_af ( info ) ? REG_INT_AF : 0 ;
u8 dummy ;
2011-05-20 02:27:28 -03:00
int ret ;
2011-05-31 03:44:19 -03:00
ret = m5mols_read_u8 ( sd , SYSTEM_INT_FACTOR , & dummy ) ;
2011-05-20 02:27:28 -03:00
if ( ! ret )
ret = m5mols_write ( sd , SYSTEM_INT_ENABLE , reg & ~ mask ) ;
return ret ;
}
2011-12-02 21:53:20 -03:00
int m5mols_wait_interrupt ( struct v4l2_subdev * sd , u8 irq_mask , u32 timeout )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
int ret = wait_event_interruptible_timeout ( info - > irq_waitq ,
atomic_add_unless ( & info - > irq_done , - 1 , 0 ) ,
msecs_to_jiffies ( timeout ) ) ;
if ( ret < = 0 )
return ret ? ret : - ETIMEDOUT ;
return m5mols_busy_wait ( sd , SYSTEM_INT_FACTOR , irq_mask ,
M5MOLS_I2C_RDY_WAIT_FL | irq_mask , - 1 ) ;
}
2011-05-20 02:27:28 -03:00
/**
* m5mols_reg_mode - Write the mode and check busy status
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
* @ mode : the required operation mode
2011-05-20 02:27:28 -03:00
*
* It always accompanies a little delay changing the M - 5 MOLS mode , so it is
* needed checking current busy status to guarantee right mode .
*/
2011-05-31 03:44:19 -03:00
static int m5mols_reg_mode ( struct v4l2_subdev * sd , u8 mode )
2011-05-20 02:27:28 -03:00
{
int ret = m5mols_write ( sd , SYSTEM_SYSMODE , mode ) ;
2011-12-12 08:04:03 -03:00
if ( ret < 0 )
return ret ;
return m5mols_busy_wait ( sd , SYSTEM_SYSMODE , mode , 0xff ,
M5MOLS_MODE_CHANGE_TIMEOUT ) ;
2011-05-20 02:27:28 -03:00
}
/**
2012-04-09 13:51:56 -03:00
* m5mols_set_mode - set the M - 5 MOLS controller mode
2017-11-29 04:08:14 -05:00
* @ info : M - 5 MOLS driver data structure
2011-05-20 02:27:28 -03:00
* @ mode : the required operation mode
*
* The commands of M - 5 MOLS are grouped into specific modes . Each functionality
2012-04-09 13:51:56 -03:00
* can be guaranteed only when the sensor is operating in mode which a command
* belongs to .
2011-05-20 02:27:28 -03:00
*/
2012-04-09 13:51:56 -03:00
int m5mols_set_mode ( struct m5mols_info * info , u8 mode )
2011-05-20 02:27:28 -03:00
{
struct v4l2_subdev * sd = & info - > sd ;
int ret = - EINVAL ;
2011-05-31 03:44:19 -03:00
u8 reg ;
2011-05-20 02:27:28 -03:00
2011-10-15 18:38:40 -03:00
if ( mode < REG_PARAMETER | | mode > REG_CAPTURE )
2011-05-20 02:27:28 -03:00
return ret ;
2011-05-31 03:44:19 -03:00
ret = m5mols_read_u8 ( sd , SYSTEM_SYSMODE , & reg ) ;
2011-12-02 21:55:04 -03:00
if ( ret | | reg = = mode )
2011-05-20 02:27:28 -03:00
return ret ;
switch ( reg ) {
case REG_PARAMETER :
ret = m5mols_reg_mode ( sd , REG_MONITOR ) ;
2011-12-02 21:55:04 -03:00
if ( mode = = REG_MONITOR )
2011-05-20 02:27:28 -03:00
break ;
if ( ! ret )
ret = m5mols_reg_mode ( sd , REG_CAPTURE ) ;
break ;
case REG_MONITOR :
if ( mode = = REG_PARAMETER ) {
ret = m5mols_reg_mode ( sd , REG_PARAMETER ) ;
break ;
}
ret = m5mols_reg_mode ( sd , REG_CAPTURE ) ;
break ;
case REG_CAPTURE :
ret = m5mols_reg_mode ( sd , REG_MONITOR ) ;
2011-12-02 21:55:04 -03:00
if ( mode = = REG_MONITOR )
2011-05-20 02:27:28 -03:00
break ;
if ( ! ret )
ret = m5mols_reg_mode ( sd , REG_PARAMETER ) ;
break ;
default :
v4l2_warn ( sd , " Wrong mode: %d \n " , mode ) ;
}
if ( ! ret )
info - > mode = mode ;
return ret ;
}
/**
* m5mols_get_version - retrieve full revisions information of M - 5 MOLS
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
2011-05-20 02:27:28 -03:00
*
* The version information includes revisions of hardware and firmware ,
* AutoFocus alghorithm version and the version string .
*/
static int m5mols_get_version ( struct v4l2_subdev * sd )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
2011-06-07 01:59:44 -03:00
struct m5mols_version * ver = & info - > ver ;
u8 * str = ver - > str ;
int i ;
2011-05-20 02:27:28 -03:00
int ret ;
2011-06-07 01:59:44 -03:00
ret = m5mols_read_u8 ( sd , SYSTEM_VER_CUSTOMER , & ver - > customer ) ;
if ( ! ret )
ret = m5mols_read_u8 ( sd , SYSTEM_VER_PROJECT , & ver - > project ) ;
if ( ! ret )
ret = m5mols_read_u16 ( sd , SYSTEM_VER_FIRMWARE , & ver - > fw ) ;
if ( ! ret )
ret = m5mols_read_u16 ( sd , SYSTEM_VER_HARDWARE , & ver - > hw ) ;
if ( ! ret )
ret = m5mols_read_u16 ( sd , SYSTEM_VER_PARAMETER , & ver - > param ) ;
if ( ! ret )
ret = m5mols_read_u16 ( sd , SYSTEM_VER_AWB , & ver - > awb ) ;
if ( ! ret )
ret = m5mols_read_u8 ( sd , AF_VERSION , & ver - > af ) ;
if ( ret )
return ret ;
2011-05-20 02:27:28 -03:00
2011-06-07 01:59:44 -03:00
for ( i = 0 ; i < VERSION_STRING_SIZE ; i + + ) {
ret = m5mols_read_u8 ( sd , SYSTEM_VER_STRING , & str [ i ] ) ;
2011-05-20 02:27:28 -03:00
if ( ret )
return ret ;
2011-06-07 01:59:44 -03:00
}
2011-05-20 02:27:28 -03:00
v4l2_info ( sd , " Manufacturer \t [%s] \n " ,
is_manufacturer ( info , REG_SAMSUNG_ELECTRO ) ?
2017-07-03 05:13:08 -04:00
" Samsung Electro-Mechanics " :
2011-05-20 02:27:28 -03:00
is_manufacturer ( info , REG_SAMSUNG_OPTICS ) ?
" Samsung Fiber-Optics " :
is_manufacturer ( info , REG_SAMSUNG_TECHWIN ) ?
" Samsung Techwin " : " None " ) ;
v4l2_info ( sd , " Customer/Project \t [0x%02x/0x%02x] \n " ,
info - > ver . customer , info - > ver . project ) ;
if ( ! is_available_af ( info ) )
v4l2_info ( sd , " No support Auto Focus on this firmware \n " ) ;
return ret ;
}
/**
* __find_restype - Lookup M - 5 MOLS resolution type according to pixel code
* @ code : pixel code
*/
2014-11-10 14:28:29 -03:00
static enum m5mols_restype __find_restype ( u32 code )
2011-05-20 02:27:28 -03:00
{
enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR ;
do {
if ( code = = m5mols_default_ffmt [ type ] . code )
return type ;
} while ( type + + ! = SIZE_DEFAULT_FFMT ) ;
return 0 ;
}
/**
* __find_resolution - Lookup preset and type of M - 5 MOLS ' s resolution
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
2011-05-20 02:27:28 -03:00
* @ mf : pixel format to find / negotiate the resolution preset for
* @ type : M - 5 MOLS resolution type
* @ resolution : M - 5 MOLS resolution preset register value
*
* Find nearest resolution matching resolution preset and adjust mf
* to supported values .
*/
static int __find_resolution ( struct v4l2_subdev * sd ,
struct v4l2_mbus_framefmt * mf ,
enum m5mols_restype * type ,
u32 * resolution )
{
const struct m5mols_resolution * fsize = & m5mols_reg_res [ 0 ] ;
const struct m5mols_resolution * match = NULL ;
enum m5mols_restype stype = __find_restype ( mf - > code ) ;
int i = ARRAY_SIZE ( m5mols_reg_res ) ;
unsigned int min_err = ~ 0 ;
while ( i - - ) {
int err ;
if ( stype = = fsize - > type ) {
err = abs ( fsize - > width - mf - > width )
+ abs ( fsize - > height - mf - > height ) ;
if ( err < min_err ) {
min_err = err ;
match = fsize ;
}
}
fsize + + ;
}
if ( match ) {
mf - > width = match - > width ;
mf - > height = match - > height ;
* resolution = match - > reg ;
* type = stype ;
return 0 ;
}
return - EINVAL ;
}
static struct v4l2_mbus_framefmt * __find_format ( struct m5mols_info * info ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-05-20 02:27:28 -03:00
enum v4l2_subdev_format_whence which ,
enum m5mols_restype type )
{
if ( which = = V4L2_SUBDEV_FORMAT_TRY )
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
return sd_state ? v4l2_subdev_get_try_format ( & info - > sd ,
sd_state , 0 ) : NULL ;
2011-05-20 02:27:28 -03:00
return & info - > ffmt [ type ] ;
}
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
static int m5mols_get_fmt ( struct v4l2_subdev * sd ,
struct v4l2_subdev_state * sd_state ,
2011-05-20 02:27:28 -03:00
struct v4l2_subdev_format * fmt )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
struct v4l2_mbus_framefmt * format ;
2012-09-20 08:16:45 -03:00
int ret = 0 ;
mutex_lock ( & info - > lock ) ;
2011-05-20 02:27:28 -03:00
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
format = __find_format ( info , sd_state , fmt - > which , info - > res_type ) ;
2012-12-05 12:49:12 -03:00
if ( format )
2012-09-20 08:16:45 -03:00
fmt - > format = * format ;
else
ret = - EINVAL ;
2011-05-20 02:27:28 -03:00
2012-09-20 08:16:45 -03:00
mutex_unlock ( & info - > lock ) ;
return ret ;
2011-05-20 02:27:28 -03:00
}
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
static int m5mols_set_fmt ( struct v4l2_subdev * sd ,
struct v4l2_subdev_state * sd_state ,
2011-05-20 02:27:28 -03:00
struct v4l2_subdev_format * fmt )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
struct v4l2_mbus_framefmt * format = & fmt - > format ;
struct v4l2_mbus_framefmt * sfmt ;
enum m5mols_restype type ;
u32 resolution = 0 ;
int ret ;
ret = __find_resolution ( sd , format , & type , & resolution ) ;
if ( ret < 0 )
return ret ;
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
sfmt = __find_format ( info , sd_state , fmt - > which , type ) ;
2011-05-20 02:27:28 -03:00
if ( ! sfmt )
return 0 ;
2012-09-20 08:16:45 -03:00
mutex_lock ( & info - > lock ) ;
2011-11-16 08:19:58 -03:00
format - > code = m5mols_default_ffmt [ type ] . code ;
format - > colorspace = V4L2_COLORSPACE_JPEG ;
format - > field = V4L2_FIELD_NONE ;
2011-05-20 02:27:28 -03:00
if ( fmt - > which = = V4L2_SUBDEV_FORMAT_ACTIVE ) {
2011-11-16 08:19:58 -03:00
* sfmt = * format ;
2011-05-20 02:27:28 -03:00
info - > resolution = resolution ;
info - > res_type = type ;
}
2012-09-20 08:16:45 -03:00
mutex_unlock ( & info - > lock ) ;
return ret ;
2011-05-20 02:27:28 -03:00
}
2012-09-18 06:18:43 -03:00
static int m5mols_get_frame_desc ( struct v4l2_subdev * sd , unsigned int pad ,
struct v4l2_mbus_frame_desc * fd )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
if ( pad ! = 0 | | fd = = NULL )
return - EINVAL ;
mutex_lock ( & info - > lock ) ;
/*
* . get_frame_desc is only used for compressed formats ,
* thus we always return the capture frame parameters here .
*/
fd - > entry [ 0 ] . length = info - > cap . buf_size ;
fd - > entry [ 0 ] . pixelcode = info - > ffmt [ M5MOLS_RESTYPE_CAPTURE ] . code ;
mutex_unlock ( & info - > lock ) ;
fd - > entry [ 0 ] . flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX ;
fd - > num_entries = 1 ;
return 0 ;
}
static int m5mols_set_frame_desc ( struct v4l2_subdev * sd , unsigned int pad ,
struct v4l2_mbus_frame_desc * fd )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
struct v4l2_mbus_framefmt * mf = & info - > ffmt [ M5MOLS_RESTYPE_CAPTURE ] ;
if ( pad ! = 0 | | fd = = NULL )
return - EINVAL ;
fd - > entry [ 0 ] . flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX ;
fd - > num_entries = 1 ;
fd - > entry [ 0 ] . length = clamp_t ( u32 , fd - > entry [ 0 ] . length ,
mf - > width * mf - > height ,
M5MOLS_MAIN_JPEG_SIZE_MAX ) ;
mutex_lock ( & info - > lock ) ;
info - > cap . buf_size = fd - > entry [ 0 ] . length ;
mutex_unlock ( & info - > lock ) ;
return 0 ;
}
2011-05-20 02:27:28 -03:00
static int m5mols_enum_mbus_code ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2011-05-20 02:27:28 -03:00
struct v4l2_subdev_mbus_code_enum * code )
{
if ( ! code | | code - > index > = SIZE_DEFAULT_FFMT )
return - EINVAL ;
code - > code = m5mols_default_ffmt [ code - > index ] . code ;
return 0 ;
}
2016-12-13 09:49:45 -02:00
static const struct v4l2_subdev_pad_ops m5mols_pad_ops = {
2011-05-20 02:27:28 -03:00
. enum_mbus_code = m5mols_enum_mbus_code ,
. get_fmt = m5mols_get_fmt ,
. set_fmt = m5mols_set_fmt ,
2012-09-18 06:18:43 -03:00
. get_frame_desc = m5mols_get_frame_desc ,
. set_frame_desc = m5mols_set_frame_desc ,
2011-05-20 02:27:28 -03:00
} ;
/**
2011-12-12 15:45:56 -03:00
* m5mols_restore_controls - Apply current control values to the registers
2017-11-29 04:08:14 -05:00
* @ info : M - 5 MOLS driver data structure
2011-05-20 02:27:28 -03:00
*
2011-12-12 15:45:56 -03:00
* m5mols_do_scenemode ( ) handles all parameters for which there is yet no
* individual control . It should be replaced at some point by setting each
* control individually , in required register set up order .
2011-05-20 02:27:28 -03:00
*/
2011-12-12 15:45:56 -03:00
int m5mols_restore_controls ( struct m5mols_info * info )
2011-05-20 02:27:28 -03:00
{
2011-12-12 15:45:56 -03:00
int ret ;
2011-05-20 02:27:28 -03:00
2011-12-12 15:45:56 -03:00
if ( info - > ctrl_sync )
return 0 ;
2011-05-20 02:27:28 -03:00
2011-12-12 15:45:56 -03:00
ret = m5mols_do_scenemode ( info , REG_SCENE_NORMAL ) ;
if ( ret )
return ret ;
ret = v4l2_ctrl_handler_setup ( & info - > handle ) ;
info - > ctrl_sync = ! ret ;
2011-05-20 02:27:28 -03:00
return ret ;
}
/**
* m5mols_start_monitor - Start the monitor mode
2017-11-29 04:08:14 -05:00
* @ info : M - 5 MOLS driver data structure
2011-05-20 02:27:28 -03:00
*
* Before applying the controls setup the resolution and frame rate
* in PARAMETER mode , and then switch over to MONITOR mode .
*/
static int m5mols_start_monitor ( struct m5mols_info * info )
{
struct v4l2_subdev * sd = & info - > sd ;
int ret ;
2012-04-09 13:51:56 -03:00
ret = m5mols_set_mode ( info , REG_PARAMETER ) ;
2011-05-20 02:27:28 -03:00
if ( ! ret )
ret = m5mols_write ( sd , PARM_MON_SIZE , info - > resolution ) ;
if ( ! ret )
ret = m5mols_write ( sd , PARM_MON_FPS , REG_FPS_30 ) ;
if ( ! ret )
2012-04-09 13:51:56 -03:00
ret = m5mols_set_mode ( info , REG_MONITOR ) ;
2011-05-20 02:27:28 -03:00
if ( ! ret )
2011-12-12 15:45:56 -03:00
ret = m5mols_restore_controls ( info ) ;
2011-05-20 02:27:28 -03:00
return ret ;
}
static int m5mols_s_stream ( struct v4l2_subdev * sd , int enable )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
2012-09-20 08:16:45 -03:00
u32 code ;
int ret ;
2011-05-20 02:27:28 -03:00
2012-09-20 08:16:45 -03:00
mutex_lock ( & info - > lock ) ;
code = info - > ffmt [ info - > res_type ] . code ;
2011-05-20 02:27:28 -03:00
2012-09-20 08:16:45 -03:00
if ( enable ) {
2011-11-16 08:19:58 -03:00
if ( is_code ( code , M5MOLS_RESTYPE_MONITOR ) )
2011-05-20 02:27:28 -03:00
ret = m5mols_start_monitor ( info ) ;
2013-02-27 08:21:07 -03:00
else if ( is_code ( code , M5MOLS_RESTYPE_CAPTURE ) )
2011-05-20 02:27:28 -03:00
ret = m5mols_start_capture ( info ) ;
2012-09-20 08:16:45 -03:00
else
ret = - EINVAL ;
} else {
ret = m5mols_set_mode ( info , REG_PARAMETER ) ;
2011-05-20 02:27:28 -03:00
}
2012-09-20 08:16:45 -03:00
mutex_unlock ( & info - > lock ) ;
return ret ;
2011-05-20 02:27:28 -03:00
}
static const struct v4l2_subdev_video_ops m5mols_video_ops = {
. s_stream = m5mols_s_stream ,
} ;
static int m5mols_sensor_power ( struct m5mols_info * info , bool enable )
{
struct v4l2_subdev * sd = & info - > sd ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
int ret ;
2011-12-03 11:47:40 -03:00
if ( info - > power = = enable )
return 0 ;
2011-05-20 02:27:28 -03:00
2011-12-03 11:47:40 -03:00
if ( enable ) {
2011-05-20 02:27:28 -03:00
if ( info - > set_power ) {
ret = info - > set_power ( & client - > dev , 1 ) ;
if ( ret )
return ret ;
}
ret = regulator_bulk_enable ( ARRAY_SIZE ( supplies ) , supplies ) ;
if ( ret ) {
2020-07-19 17:34:47 +02:00
if ( info - > set_power )
info - > set_power ( & client - > dev , 0 ) ;
2011-05-20 02:27:28 -03:00
return ret ;
}
2022-02-24 01:13:07 +01:00
gpiod_set_value ( info - > reset , 0 ) ;
2011-12-03 11:47:40 -03:00
info - > power = 1 ;
2011-05-20 02:27:28 -03:00
return ret ;
}
ret = regulator_bulk_disable ( ARRAY_SIZE ( supplies ) , supplies ) ;
if ( ret )
return ret ;
if ( info - > set_power )
info - > set_power ( & client - > dev , 0 ) ;
2022-02-24 01:13:07 +01:00
gpiod_set_value ( info - > reset , 1 ) ;
2011-12-03 11:47:40 -03:00
info - > isp_ready = 0 ;
info - > power = 0 ;
2011-05-20 02:27:28 -03:00
return ret ;
}
/* m5mols_update_fw - optional firmware update routine */
int __attribute__ ( ( weak ) ) m5mols_update_fw ( struct v4l2_subdev * sd ,
int ( * set_power ) ( struct m5mols_info * , bool ) )
{
return 0 ;
}
/**
2011-12-03 11:47:40 -03:00
* m5mols_fw_start - M - 5 MOLS internal ARM controller initialization
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
2011-05-20 02:27:28 -03:00
*
2011-12-03 11:47:40 -03:00
* Execute the M - 5 MOLS internal ARM controller initialization sequence .
* This function should be called after the supply voltage has been
* applied and before any requests to the device are made .
2011-05-20 02:27:28 -03:00
*/
2011-12-03 11:47:40 -03:00
static int m5mols_fw_start ( struct v4l2_subdev * sd )
2011-05-20 02:27:28 -03:00
{
2011-12-03 11:47:40 -03:00
struct m5mols_info * info = to_m5mols ( sd ) ;
2011-05-20 02:27:28 -03:00
int ret ;
2011-12-03 11:47:40 -03:00
atomic_set ( & info - > irq_done , 0 ) ;
/* Wait until I2C slave is initialized in Flash Writer mode */
ret = m5mols_busy_wait ( sd , FLASH_CAM_START , REG_IN_FLASH_MODE ,
M5MOLS_I2C_RDY_WAIT_FL | 0xff , - 1 ) ;
if ( ! ret )
ret = m5mols_write ( sd , FLASH_CAM_START , REG_START_ARM_BOOT ) ;
if ( ! ret )
ret = m5mols_wait_interrupt ( sd , REG_INT_MODE , 2000 ) ;
2011-05-20 02:27:28 -03:00
if ( ret < 0 )
return ret ;
2011-12-03 11:47:40 -03:00
info - > isp_ready = 1 ;
2011-05-20 02:27:28 -03:00
ret = m5mols_get_version ( sd ) ;
if ( ! ret )
ret = m5mols_update_fw ( sd , m5mols_sensor_power ) ;
if ( ret )
return ret ;
v4l2_dbg ( 1 , m5mols_debug , sd , " Success ARM Booting \n " ) ;
ret = m5mols_write ( sd , PARM_INTERFACE , REG_INTERFACE_MIPI ) ;
if ( ! ret )
2011-12-03 11:18:57 -03:00
ret = m5mols_enable_interrupt ( sd ,
REG_INT_AF | REG_INT_CAPTURE ) ;
2011-05-20 02:27:28 -03:00
return ret ;
}
2012-09-20 08:16:45 -03:00
/* Execute the lens soft-landing algorithm */
static int m5mols_auto_focus_stop ( struct m5mols_info * info )
{
int ret ;
ret = m5mols_write ( & info - > sd , AF_EXECUTE , REG_AF_STOP ) ;
if ( ! ret )
ret = m5mols_write ( & info - > sd , AF_MODE , REG_AF_POWEROFF ) ;
if ( ! ret )
ret = m5mols_busy_wait ( & info - > sd , SYSTEM_STATUS , REG_AF_IDLE ,
0xff , - 1 ) ;
return ret ;
}
2011-05-20 02:27:28 -03:00
/**
* m5mols_s_power - Main sensor power control function
2017-11-29 04:08:14 -05:00
* @ sd : sub - device , as pointed by struct v4l2_subdev
* @ on : if true , powers on the device ; powers off otherwise .
2011-05-20 02:27:28 -03:00
*
* To prevent breaking the lens when the sensor is powered off the Soft - Landing
* algorithm is called where available . The Soft - Landing algorithm availability
* dependends on the firmware provider .
*/
static int m5mols_s_power ( struct v4l2_subdev * sd , int on )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
int ret ;
2012-09-20 08:16:45 -03:00
mutex_lock ( & info - > lock ) ;
2011-05-20 02:27:28 -03:00
if ( on ) {
ret = m5mols_sensor_power ( info , true ) ;
if ( ! ret )
2011-12-03 11:47:40 -03:00
ret = m5mols_fw_start ( sd ) ;
2012-09-20 08:16:45 -03:00
} else {
if ( is_manufacturer ( info , REG_SAMSUNG_TECHWIN ) ) {
ret = m5mols_set_mode ( info , REG_MONITOR ) ;
if ( ! ret )
ret = m5mols_auto_focus_stop ( info ) ;
if ( ret < 0 )
v4l2_warn ( sd , " Soft landing lens failed \n " ) ;
}
ret = m5mols_sensor_power ( info , false ) ;
2011-05-20 02:27:28 -03:00
2012-09-20 08:16:45 -03:00
info - > ctrl_sync = 0 ;
2011-05-20 02:27:28 -03:00
}
2012-09-20 08:16:45 -03:00
mutex_unlock ( & info - > lock ) ;
2011-05-20 02:27:28 -03:00
return ret ;
}
static int m5mols_log_status ( struct v4l2_subdev * sd )
{
struct m5mols_info * info = to_m5mols ( sd ) ;
v4l2_ctrl_handler_log_status ( & info - > handle , sd - > name ) ;
return 0 ;
}
static const struct v4l2_subdev_core_ops m5mols_core_ops = {
. s_power = m5mols_s_power ,
. log_status = m5mols_log_status ,
} ;
2011-12-03 14:53:30 -03:00
/*
* V4L2 subdev internal operations
*/
static int m5mols_open ( struct v4l2_subdev * sd , struct v4l2_subdev_fh * fh )
{
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_mbus_framefmt * format = v4l2_subdev_get_try_format ( sd ,
fh - > state ,
0 ) ;
2011-12-03 14:53:30 -03:00
* format = m5mols_default_ffmt [ 0 ] ;
return 0 ;
}
static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = {
. open = m5mols_open ,
} ;
2011-05-20 02:27:28 -03:00
static const struct v4l2_subdev_ops m5mols_ops = {
. core = & m5mols_core_ops ,
. pad = & m5mols_pad_ops ,
. video = & m5mols_video_ops ,
} ;
static irqreturn_t m5mols_irq_handler ( int irq , void * data )
{
2011-12-02 21:53:20 -03:00
struct m5mols_info * info = to_m5mols ( data ) ;
2011-05-20 02:27:28 -03:00
2011-12-02 21:53:20 -03:00
atomic_set ( & info - > irq_done , 1 ) ;
wake_up_interruptible ( & info - > irq_waitq ) ;
2011-05-20 02:27:28 -03:00
return IRQ_HANDLED ;
}
2012-12-21 13:17:53 -08:00
static int m5mols_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2011-05-20 02:27:28 -03:00
{
const struct m5mols_platform_data * pdata = client - > dev . platform_data ;
struct m5mols_info * info ;
struct v4l2_subdev * sd ;
int ret ;
if ( pdata = = NULL ) {
dev_err ( & client - > dev , " No platform data \n " ) ;
return - EINVAL ;
}
2011-09-19 09:16:01 -03:00
if ( ! client - > irq ) {
2011-05-20 02:27:28 -03:00
dev_err ( & client - > dev , " Interrupt not assigned \n " ) ;
return - EINVAL ;
}
2013-05-02 08:29:43 -03:00
info = devm_kzalloc ( & client - > dev , sizeof ( * info ) , GFP_KERNEL ) ;
2011-05-20 02:27:28 -03:00
if ( ! info )
return - ENOMEM ;
2022-02-24 01:13:07 +01:00
/* This asserts reset, descriptor shall have polarity specified */
info - > reset = devm_gpiod_get ( & client - > dev , " reset " , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( info - > reset ) )
return PTR_ERR ( info - > reset ) ;
/* Notice: the "N" in M5MOLS_NRST implies active low */
gpiod_set_consumer_name ( info - > reset , " M5MOLS_NRST " ) ;
2011-05-20 02:27:28 -03:00
info - > pdata = pdata ;
info - > set_power = pdata - > set_power ;
2013-05-02 08:29:43 -03:00
ret = devm_regulator_bulk_get ( & client - > dev , ARRAY_SIZE ( supplies ) ,
supplies ) ;
2011-05-20 02:27:28 -03:00
if ( ret ) {
dev_err ( & client - > dev , " Failed to get regulators: %d \n " , ret ) ;
2013-05-02 08:29:43 -03:00
return ret ;
2011-05-20 02:27:28 -03:00
}
sd = & info - > sd ;
v4l2_i2c_subdev_init ( sd , client , & m5mols_ops ) ;
2018-09-24 10:24:43 -04:00
/* Static name; NEVER use in new drivers! */
2018-09-10 08:19:14 -04:00
strscpy ( sd - > name , MODULE_NAME , sizeof ( sd - > name ) ) ;
2011-07-01 08:38:13 -03:00
sd - > flags | = V4L2_SUBDEV_FL_HAS_DEVNODE ;
2011-05-20 02:27:28 -03:00
2011-12-03 14:53:30 -03:00
sd - > internal_ops = & m5mols_subdev_internal_ops ;
2011-05-20 02:27:28 -03:00
info - > pad . flags = MEDIA_PAD_FL_SOURCE ;
2015-12-11 07:44:40 -02:00
ret = media_entity_pads_init ( & sd - > entity , 1 , & info - > pad ) ;
2011-05-20 02:27:28 -03:00
if ( ret < 0 )
2013-05-02 08:29:43 -03:00
return ret ;
2015-12-10 17:25:41 -02:00
sd - > entity . function = MEDIA_ENT_F_CAM_SENSOR ;
2011-05-20 02:27:28 -03:00
init_waitqueue_head ( & info - > irq_waitq ) ;
2012-09-20 08:16:45 -03:00
mutex_init ( & info - > lock ) ;
2013-05-02 08:29:43 -03:00
ret = devm_request_irq ( & client - > dev , client - > irq , m5mols_irq_handler ,
IRQF_TRIGGER_RISING , MODULE_NAME , sd ) ;
2011-05-20 02:27:28 -03:00
if ( ret ) {
dev_err ( & client - > dev , " Interrupt request failed: %d \n " , ret ) ;
2013-05-02 08:29:43 -03:00
goto error ;
2011-05-20 02:27:28 -03:00
}
info - > res_type = M5MOLS_RESTYPE_MONITOR ;
2011-11-15 15:55:17 -03:00
info - > ffmt [ 0 ] = m5mols_default_ffmt [ 0 ] ;
info - > ffmt [ 1 ] = m5mols_default_ffmt [ 1 ] ;
2011-12-02 21:53:20 -03:00
2011-12-03 14:53:30 -03:00
ret = m5mols_sensor_power ( info , true ) ;
if ( ret )
2013-05-02 08:29:43 -03:00
goto error ;
2011-12-03 14:53:30 -03:00
ret = m5mols_fw_start ( sd ) ;
if ( ! ret )
2012-04-09 13:51:56 -03:00
ret = m5mols_init_controls ( sd ) ;
2011-12-03 14:53:30 -03:00
2012-08-18 17:25:59 -03:00
ret = m5mols_sensor_power ( info , false ) ;
2011-12-03 14:53:30 -03:00
if ( ! ret )
return 0 ;
2013-05-02 08:29:43 -03:00
error :
2011-05-20 02:27:28 -03:00
media_entity_cleanup ( & sd - > entity ) ;
return ret ;
}
2022-08-15 10:02:30 +02:00
static void m5mols_remove ( struct i2c_client * client )
2011-05-20 02:27:28 -03:00
{
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
v4l2_device_unregister_subdev ( sd ) ;
2011-12-03 14:53:30 -03:00
v4l2_ctrl_handler_free ( sd - > ctrl_handler ) ;
2011-05-20 02:27:28 -03:00
media_entity_cleanup ( & sd - > entity ) ;
}
static const struct i2c_device_id m5mols_id [ ] = {
{ MODULE_NAME , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , m5mols_id ) ;
static struct i2c_driver m5mols_i2c_driver = {
. driver = {
. name = MODULE_NAME ,
} ,
. probe = m5mols_probe ,
2012-12-21 13:17:53 -08:00
. remove = m5mols_remove ,
2011-05-20 02:27:28 -03:00
. id_table = m5mols_id ,
} ;
2012-02-12 06:56:32 -03:00
module_i2c_driver ( m5mols_i2c_driver ) ;
2011-05-20 02:27:28 -03:00
MODULE_AUTHOR ( " HeungJun Kim <riverful.kim@samsung.com> " ) ;
MODULE_AUTHOR ( " Dongsoo Kim <dongsoo45.kim@samsung.com> " ) ;
MODULE_DESCRIPTION ( " Fujitsu M-5MOLS 8M Pixel camera driver " ) ;
MODULE_LICENSE ( " GPL " ) ;