2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-08-14 19:02:51 +04:00
/*
2010-08-03 14:57:39 +04:00
* Driver for MT9M111 / MT9M112 / MT9M131 CMOS Image Sensor from Micron / Aptina
2008-08-14 19:02:51 +04:00
*
* Copyright ( C ) 2008 , Robert Jarzmik < robert . jarzmik @ free . fr >
*/
2021-01-12 22:49:17 +03:00
# include <linux/clk.h>
2008-08-14 19:02:51 +04:00
# include <linux/videodev2.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/log2.h>
# include <linux/gpio.h>
# include <linux/delay.h>
2019-05-29 22:25:18 +03:00
# include <linux/regulator/consumer.h>
2011-09-09 20:56:04 +04:00
# include <linux/v4l2-mediabus.h>
2011-07-03 22:03:12 +04:00
# include <linux/module.h>
2018-11-27 13:02:53 +03:00
# include <linux/property.h>
2008-08-14 19:02:51 +04:00
2016-09-06 12:04:11 +03:00
# include <media/v4l2-async.h>
2008-08-14 19:02:51 +04:00
# include <media/v4l2-common.h>
2011-09-07 13:56:57 +04:00
# include <media/v4l2-ctrls.h>
2016-09-06 12:04:11 +03:00
# include <media/v4l2-device.h>
2018-11-12 19:00:48 +03:00
# include <media/v4l2-event.h>
2018-11-27 13:02:53 +03:00
# include <media/v4l2-fwnode.h>
2008-08-14 19:02:51 +04:00
/*
2010-08-03 14:57:39 +04:00
* MT9M111 , MT9M112 and MT9M131 :
* i2c address is 0x48 or 0x5d ( depending on SADDR pin )
2012-12-21 15:11:48 +04:00
* The platform has to define struct i2c_board_info objects and link to them
* from struct soc_camera_host_desc
2008-08-14 19:02:51 +04:00
*/
2010-08-03 14:57:39 +04:00
/*
* Sensor core register addresses ( 0x000 . .0 x0ff )
*/
2008-08-14 19:02:51 +04:00
# define MT9M111_CHIP_VERSION 0x000
# define MT9M111_ROW_START 0x001
# define MT9M111_COLUMN_START 0x002
# define MT9M111_WINDOW_HEIGHT 0x003
# define MT9M111_WINDOW_WIDTH 0x004
# define MT9M111_HORIZONTAL_BLANKING_B 0x005
# define MT9M111_VERTICAL_BLANKING_B 0x006
# define MT9M111_HORIZONTAL_BLANKING_A 0x007
# define MT9M111_VERTICAL_BLANKING_A 0x008
# define MT9M111_SHUTTER_WIDTH 0x009
# define MT9M111_ROW_SPEED 0x00a
# define MT9M111_EXTRA_DELAY 0x00b
# define MT9M111_SHUTTER_DELAY 0x00c
# define MT9M111_RESET 0x00d
# define MT9M111_READ_MODE_B 0x020
# define MT9M111_READ_MODE_A 0x021
# define MT9M111_FLASH_CONTROL 0x023
# define MT9M111_GREEN1_GAIN 0x02b
# define MT9M111_BLUE_GAIN 0x02c
# define MT9M111_RED_GAIN 0x02d
# define MT9M111_GREEN2_GAIN 0x02e
# define MT9M111_GLOBAL_GAIN 0x02f
# define MT9M111_CONTEXT_CONTROL 0x0c8
# define MT9M111_PAGE_MAP 0x0f0
# define MT9M111_BYTE_WISE_ADDR 0x0f1
# define MT9M111_RESET_SYNC_CHANGES (1 << 15)
# define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9)
# define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8)
# define MT9M111_RESET_RESET_SOC (1 << 5)
# define MT9M111_RESET_OUTPUT_DISABLE (1 << 4)
# define MT9M111_RESET_CHIP_ENABLE (1 << 3)
# define MT9M111_RESET_ANALOG_STANDBY (1 << 2)
# define MT9M111_RESET_RESTART_FRAME (1 << 1)
# define MT9M111_RESET_RESET_MODE (1 << 0)
2011-07-12 19:39:05 +04:00
# define MT9M111_RM_FULL_POWER_RD (0 << 10)
# define MT9M111_RM_LOW_POWER_RD (1 << 10)
# define MT9M111_RM_COL_SKIP_4X (1 << 5)
# define MT9M111_RM_ROW_SKIP_4X (1 << 4)
# define MT9M111_RM_COL_SKIP_2X (1 << 3)
# define MT9M111_RM_ROW_SKIP_2X (1 << 2)
2008-08-14 19:02:51 +04:00
# define MT9M111_RMB_MIRROR_COLS (1 << 1)
# define MT9M111_RMB_MIRROR_ROWS (1 << 0)
# define MT9M111_CTXT_CTRL_RESTART (1 << 15)
# define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12)
# define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10)
# define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9)
# define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8)
# define MT9M111_CTXT_CTRL_XENON_EN (1 << 7)
# define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3)
# define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
# define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
# define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
2010-08-03 14:57:39 +04:00
2008-08-14 19:02:51 +04:00
/*
2010-08-03 14:57:39 +04:00
* Colorpipe register addresses ( 0x100 . .0 x1ff )
2008-08-14 19:02:51 +04:00
*/
# define MT9M111_OPER_MODE_CTRL 0x106
# define MT9M111_OUTPUT_FORMAT_CTRL 0x108
2018-01-03 21:22:47 +03:00
# define MT9M111_TPG_CTRL 0x148
2008-08-14 19:02:51 +04:00
# define MT9M111_REDUCER_XZOOM_B 0x1a0
# define MT9M111_REDUCER_XSIZE_B 0x1a1
# define MT9M111_REDUCER_YZOOM_B 0x1a3
# define MT9M111_REDUCER_YSIZE_B 0x1a4
# define MT9M111_REDUCER_XZOOM_A 0x1a6
# define MT9M111_REDUCER_XSIZE_A 0x1a7
# define MT9M111_REDUCER_YZOOM_A 0x1a9
# define MT9M111_REDUCER_YSIZE_A 0x1aa
2018-11-12 19:00:49 +03:00
# define MT9M111_EFFECTS_MODE 0x1e2
2008-08-14 19:02:51 +04:00
# define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a
# define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
# define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14)
2008-12-18 17:29:05 +03:00
# define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
2011-07-12 19:39:05 +04:00
# define MT9M111_OUTFMT_FLIP_BAYER_COL (1 << 9)
# define MT9M111_OUTFMT_FLIP_BAYER_ROW (1 << 8)
2008-08-14 19:02:51 +04:00
# define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
# define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
# define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9)
# define MT9M111_OUTFMT_RGB (1 << 8)
2010-08-03 14:57:41 +04:00
# define MT9M111_OUTFMT_RGB565 (0 << 6)
# define MT9M111_OUTFMT_RGB555 (1 << 6)
# define MT9M111_OUTFMT_RGB444x (2 << 6)
# define MT9M111_OUTFMT_RGBx444 (3 << 6)
# define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4)
# define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4)
# define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4)
# define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4)
2008-08-14 19:02:51 +04:00
# define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3)
# define MT9M111_OUTFMT_AVG_CHROMA (1 << 2)
2011-07-12 19:39:05 +04:00
# define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
# define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0)
2018-01-03 21:22:47 +03:00
# define MT9M111_TPG_SEL_MASK GENMASK(2, 0)
2018-11-12 19:00:49 +03:00
# define MT9M111_EFFECTS_MODE_MASK GENMASK(2, 0)
2018-11-27 13:02:50 +03:00
# define MT9M111_RM_PWR_MASK BIT(10)
# define MT9M111_RM_SKIP2_MASK GENMASK(3, 2)
2010-08-03 14:57:39 +04:00
2008-08-14 19:02:51 +04:00
/*
2010-08-03 14:57:39 +04:00
* Camera control register addresses ( 0x200 . .0 x2ff not implemented )
2008-08-14 19:02:51 +04:00
*/
2009-04-24 19:57:01 +04:00
# define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
# define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
# define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
# define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
2011-07-12 19:39:05 +04:00
# define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
( val ) , ( mask ) )
2008-08-14 19:02:51 +04:00
# define MT9M111_MIN_DARK_ROWS 8
2010-08-03 14:57:43 +04:00
# define MT9M111_MIN_DARK_COLS 26
2008-08-14 19:02:51 +04:00
# define MT9M111_MAX_HEIGHT 1024
# define MT9M111_MAX_WIDTH 1280
2011-11-03 15:14:56 +04:00
struct mt9m111_context {
u16 read_mode ;
u16 blanking_h ;
u16 blanking_v ;
u16 reducer_xzoom ;
u16 reducer_yzoom ;
u16 reducer_xsize ;
u16 reducer_ysize ;
u16 output_fmt_ctrl2 ;
u16 control ;
} ;
static struct mt9m111_context context_a = {
. read_mode = MT9M111_READ_MODE_A ,
. blanking_h = MT9M111_HORIZONTAL_BLANKING_A ,
. blanking_v = MT9M111_VERTICAL_BLANKING_A ,
. reducer_xzoom = MT9M111_REDUCER_XZOOM_A ,
. reducer_yzoom = MT9M111_REDUCER_YZOOM_A ,
. reducer_xsize = MT9M111_REDUCER_XSIZE_A ,
. reducer_ysize = MT9M111_REDUCER_YSIZE_A ,
. output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_A ,
. control = MT9M111_CTXT_CTRL_RESTART ,
} ;
static struct mt9m111_context context_b = {
. read_mode = MT9M111_READ_MODE_B ,
. blanking_h = MT9M111_HORIZONTAL_BLANKING_B ,
. blanking_v = MT9M111_VERTICAL_BLANKING_B ,
. reducer_xzoom = MT9M111_REDUCER_XZOOM_B ,
. reducer_yzoom = MT9M111_REDUCER_YZOOM_B ,
. reducer_xsize = MT9M111_REDUCER_XSIZE_B ,
. reducer_ysize = MT9M111_REDUCER_YSIZE_B ,
. output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_B ,
. control = MT9M111_CTXT_CTRL_RESTART |
MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
MT9M111_CTXT_CTRL_HBLANK_SEL_B ,
} ;
2009-12-11 17:46:49 +03:00
/* MT9M111 has only one fixed colorspace per pixelcode */
struct mt9m111_datafmt {
2014-11-10 20:28:29 +03:00
u32 code ;
2009-12-11 17:46:49 +03:00
enum v4l2_colorspace colorspace ;
} ;
static const struct mt9m111_datafmt mt9m111_colour_fmts [ ] = {
2016-09-06 12:04:12 +03:00
{ MEDIA_BUS_FMT_YUYV8_2X8 , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_YVYU8_2X8 , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_UYVY8_2X8 , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_VYUY8_2X8 , V4L2_COLORSPACE_SRGB } ,
2014-11-10 20:28:29 +03:00
{ MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_RGB565_2X8_LE , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_RGB565_2X8_BE , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_BGR565_2X8_LE , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_BGR565_2X8_BE , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_SBGGR8_1X8 , V4L2_COLORSPACE_SRGB } ,
{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE , V4L2_COLORSPACE_SRGB } ,
2008-08-14 19:02:51 +04:00
} ;
2018-11-27 13:02:50 +03:00
enum mt9m111_mode_id {
MT9M111_MODE_SXGA_8FPS ,
MT9M111_MODE_SXGA_15FPS ,
MT9M111_MODE_QSXGA_30FPS ,
MT9M111_NUM_MODES ,
} ;
struct mt9m111_mode_info {
unsigned int sensor_w ;
unsigned int sensor_h ;
unsigned int max_image_w ;
unsigned int max_image_h ;
unsigned int max_fps ;
unsigned int reg_val ;
unsigned int reg_mask ;
} ;
2008-08-14 19:02:51 +04:00
struct mt9m111 {
2009-08-25 18:43:33 +04:00
struct v4l2_subdev subdev ;
2011-09-07 13:56:57 +04:00
struct v4l2_ctrl_handler hdl ;
struct v4l2_ctrl * gain ;
2011-11-03 15:14:56 +04:00
struct mt9m111_context * ctx ;
2011-11-04 22:13:18 +04:00
struct v4l2_rect rect ; /* cropping rectangle */
2021-01-12 22:49:17 +03:00
struct clk * clk ;
2013-11-26 12:31:42 +04:00
unsigned int width ; /* output */
unsigned int height ; /* sizes */
2018-11-27 13:02:50 +03:00
struct v4l2_fract frame_interval ;
const struct mt9m111_mode_info * current_mode ;
2011-06-05 15:27:39 +04:00
struct mutex power_lock ; /* lock to protect power_count */
int power_count ;
2009-12-11 17:46:49 +03:00
const struct mt9m111_datafmt * fmt ;
2011-07-19 16:26:35 +04:00
int lastpage ; /* PageMap cache value */
2019-05-29 22:25:18 +03:00
struct regulator * regulator ;
2018-11-27 13:02:48 +03:00
bool is_streaming ;
2018-11-27 13:02:53 +03:00
/* user point of view - 0: falling 1: rising edge */
unsigned int pclk_sample : 1 ;
2018-01-03 21:22:45 +03:00
# ifdef CONFIG_MEDIA_CONTROLLER
struct media_pad pad ;
# endif
2008-08-14 19:02:51 +04:00
} ;
2018-11-27 13:02:50 +03:00
static const struct mt9m111_mode_info mt9m111_mode_data [ MT9M111_NUM_MODES ] = {
[ MT9M111_MODE_SXGA_8FPS ] = {
. sensor_w = 1280 ,
. sensor_h = 1024 ,
. max_image_w = 1280 ,
. max_image_h = 1024 ,
. max_fps = 8 ,
. reg_val = MT9M111_RM_LOW_POWER_RD ,
. reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK ,
} ,
[ MT9M111_MODE_SXGA_15FPS ] = {
. sensor_w = 1280 ,
. sensor_h = 1024 ,
. max_image_w = 1280 ,
. max_image_h = 1024 ,
. max_fps = 15 ,
. reg_val = MT9M111_RM_FULL_POWER_RD ,
. reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK ,
} ,
[ MT9M111_MODE_QSXGA_30FPS ] = {
. sensor_w = 1280 ,
. sensor_h = 1024 ,
. max_image_w = 640 ,
. max_image_h = 512 ,
. max_fps = 30 ,
. reg_val = MT9M111_RM_LOW_POWER_RD | MT9M111_RM_COL_SKIP_2X |
MT9M111_RM_ROW_SKIP_2X ,
. reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK ,
} ,
} ;
2011-11-04 22:13:18 +04:00
/* Find a data format by a pixel code */
static const struct mt9m111_datafmt * mt9m111_find_datafmt ( struct mt9m111 * mt9m111 ,
2014-11-10 20:28:29 +03:00
u32 code )
2011-11-04 22:13:18 +04:00
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( mt9m111_colour_fmts ) ; i + + )
if ( mt9m111_colour_fmts [ i ] . code = = code )
return mt9m111_colour_fmts + i ;
return mt9m111 - > fmt ;
}
2009-08-25 18:43:33 +04:00
static struct mt9m111 * to_mt9m111 ( const struct i2c_client * client )
{
return container_of ( i2c_get_clientdata ( client ) , struct mt9m111 , subdev ) ;
}
2008-08-14 19:02:51 +04:00
static int reg_page_map_set ( struct i2c_client * client , const u16 reg )
{
int ret ;
u16 page ;
2011-07-19 16:26:35 +04:00
struct mt9m111 * mt9m111 = to_mt9m111 ( client ) ;
2008-08-14 19:02:51 +04:00
page = ( reg > > 8 ) ;
2011-07-19 16:26:35 +04:00
if ( page = = mt9m111 - > lastpage )
2008-08-14 19:02:51 +04:00
return 0 ;
if ( page > 2 )
return - EINVAL ;
2011-10-21 16:30:25 +04:00
ret = i2c_smbus_write_word_swapped ( client , MT9M111_PAGE_MAP , page ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2011-07-19 16:26:35 +04:00
mt9m111 - > lastpage = page ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2009-04-24 19:57:01 +04:00
static int mt9m111_reg_read ( struct i2c_client * client , const u16 reg )
2008-08-14 19:02:51 +04:00
{
int ret ;
ret = reg_page_map_set ( client , reg ) ;
if ( ! ret )
2011-10-21 16:30:25 +04:00
ret = i2c_smbus_read_word_swapped ( client , reg & 0xff ) ;
2008-08-14 19:02:51 +04:00
2009-04-24 19:57:01 +04:00
dev_dbg ( & client - > dev , " read reg.%03x -> %04x \n " , reg , ret ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2009-04-24 19:57:01 +04:00
static int mt9m111_reg_write ( struct i2c_client * client , const u16 reg ,
2008-08-14 19:02:51 +04:00
const u16 data )
{
int ret ;
ret = reg_page_map_set ( client , reg ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2011-10-21 16:30:25 +04:00
ret = i2c_smbus_write_word_swapped ( client , reg & 0xff , data ) ;
2009-04-24 19:57:01 +04:00
dev_dbg ( & client - > dev , " write reg.%03x = %04x -> %d \n " , reg , data , ret ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2009-04-24 19:57:01 +04:00
static int mt9m111_reg_set ( struct i2c_client * client , const u16 reg ,
2008-08-14 19:02:51 +04:00
const u16 data )
{
int ret ;
2009-04-24 19:57:01 +04:00
ret = mt9m111_reg_read ( client , reg ) ;
2008-08-14 19:02:51 +04:00
if ( ret > = 0 )
2009-04-24 19:57:01 +04:00
ret = mt9m111_reg_write ( client , reg , ret | data ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2009-04-24 19:57:01 +04:00
static int mt9m111_reg_clear ( struct i2c_client * client , const u16 reg ,
2008-08-14 19:02:51 +04:00
const u16 data )
{
int ret ;
2009-04-24 19:57:01 +04:00
ret = mt9m111_reg_read ( client , reg ) ;
2011-07-12 19:39:03 +04:00
if ( ret > = 0 )
ret = mt9m111_reg_write ( client , reg , ret & ~ data ) ;
return ret ;
2008-08-14 19:02:51 +04:00
}
2011-07-12 19:39:05 +04:00
static int mt9m111_reg_mask ( struct i2c_client * client , const u16 reg ,
const u16 data , const u16 mask )
{
int ret ;
ret = mt9m111_reg_read ( client , reg ) ;
if ( ret > = 0 )
ret = mt9m111_reg_write ( client , reg , ( ret & ~ mask ) | data ) ;
return ret ;
}
2011-06-07 13:47:30 +04:00
static int mt9m111_set_context ( struct mt9m111 * mt9m111 ,
2011-11-03 15:14:56 +04:00
struct mt9m111_context * ctx )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2011-11-03 15:14:56 +04:00
return reg_write ( CONTEXT_CONTROL , ctx - > control ) ;
}
static int mt9m111_setup_rect_ctx ( struct mt9m111 * mt9m111 ,
2011-11-04 22:13:18 +04:00
struct mt9m111_context * ctx , struct v4l2_rect * rect ,
unsigned int width , unsigned int height )
2011-11-03 15:14:56 +04:00
{
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2011-11-04 22:13:18 +04:00
int ret = mt9m111_reg_write ( client , ctx - > reducer_xzoom , rect - > width ) ;
2011-11-03 15:14:56 +04:00
if ( ! ret )
2011-11-04 22:13:18 +04:00
ret = mt9m111_reg_write ( client , ctx - > reducer_yzoom , rect - > height ) ;
2011-11-03 15:14:56 +04:00
if ( ! ret )
2011-11-04 22:13:18 +04:00
ret = mt9m111_reg_write ( client , ctx - > reducer_xsize , width ) ;
2011-11-03 15:14:56 +04:00
if ( ! ret )
2011-11-04 22:13:18 +04:00
ret = mt9m111_reg_write ( client , ctx - > reducer_ysize , height ) ;
2011-11-03 15:14:56 +04:00
return ret ;
2008-08-14 19:02:51 +04:00
}
2011-11-04 22:13:18 +04:00
static int mt9m111_setup_geometry ( struct mt9m111 * mt9m111 , struct v4l2_rect * rect ,
2014-11-10 20:28:29 +03:00
int width , int height , u32 code )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2011-11-03 15:14:56 +04:00
int ret ;
2008-08-14 19:02:51 +04:00
2009-03-13 12:08:20 +03:00
ret = reg_write ( COLUMN_START , rect - > left ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2009-03-13 12:08:20 +03:00
ret = reg_write ( ROW_START , rect - > top ) ;
2008-08-14 19:02:51 +04:00
2011-11-04 22:13:18 +04:00
if ( ! ret )
ret = reg_write ( WINDOW_WIDTH , rect - > width ) ;
if ( ! ret )
ret = reg_write ( WINDOW_HEIGHT , rect - > height ) ;
2014-11-10 20:28:29 +03:00
if ( code ! = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ) {
2011-11-04 22:13:18 +04:00
/* IFP in use, down-scaling possible */
2008-08-14 19:03:49 +04:00
if ( ! ret )
2011-11-04 22:13:18 +04:00
ret = mt9m111_setup_rect_ctx ( mt9m111 , & context_b ,
rect , width , height ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2011-11-04 22:13:18 +04:00
ret = mt9m111_setup_rect_ctx ( mt9m111 , & context_a ,
rect , width , height ) ;
2008-08-14 19:02:51 +04:00
}
2011-11-04 22:13:18 +04:00
dev_dbg ( & client - > dev , " %s(%x): %ux%u@%u:%u -> %ux%u = %d \n " ,
__func__ , code , rect - > width , rect - > height , rect - > left , rect - > top ,
width , height , ret ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2011-06-07 13:47:30 +04:00
static int mt9m111_enable ( struct mt9m111 * mt9m111 )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2011-11-03 15:19:18 +04:00
return reg_write ( RESET , MT9M111_RESET_CHIP_ENABLE ) ;
2008-08-14 19:02:51 +04:00
}
2011-06-07 13:47:30 +04:00
static int mt9m111_reset ( struct mt9m111 * mt9m111 )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-08-14 19:02:51 +04:00
int ret ;
ret = reg_set ( RESET , MT9M111_RESET_RESET_MODE ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2008-08-14 19:02:51 +04:00
ret = reg_set ( RESET , MT9M111_RESET_RESET_SOC ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2008-08-14 19:02:51 +04:00
ret = reg_clear ( RESET , MT9M111_RESET_RESET_MODE
| MT9M111_RESET_RESET_SOC ) ;
2009-02-23 18:13:24 +03:00
2008-08-14 19:02:51 +04:00
return ret ;
}
2015-12-14 13:25:32 +03:00
static int mt9m111_set_selection ( 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 ,
2015-12-14 13:25:32 +03:00
struct v4l2_subdev_selection * sel )
2009-08-25 18:50:46 +04:00
{
2015-12-14 13:25:32 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct mt9m111 * mt9m111 = to_mt9m111 ( client ) ;
struct v4l2_rect rect = sel - > r ;
2011-11-04 22:13:18 +04:00
int width , height ;
2016-09-06 12:04:11 +03:00
int ret , align = 0 ;
2011-11-04 22:13:18 +04:00
2015-12-14 13:25:32 +03:00
if ( sel - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE | |
sel - > target ! = V4L2_SEL_TGT_CROP )
2011-11-04 22:13:18 +04:00
return - EINVAL ;
2014-11-10 20:28:29 +03:00
if ( mt9m111 - > fmt - > code = = MEDIA_BUS_FMT_SBGGR8_1X8 | |
mt9m111 - > fmt - > code = = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ) {
2009-08-25 18:50:46 +04:00
/* Bayer format - even size lengths */
2016-09-06 12:04:11 +03:00
align = 1 ;
2009-08-25 18:50:46 +04:00
/* Let the user play with the starting pixel */
}
/* FIXME: the datasheet doesn't specify minimum sizes */
2016-09-06 12:04:11 +03:00
v4l_bound_align_image ( & rect . width , 2 , MT9M111_MAX_WIDTH , align ,
& rect . height , 2 , MT9M111_MAX_HEIGHT , align , 0 ) ;
rect . left = clamp ( rect . left , MT9M111_MIN_DARK_COLS ,
MT9M111_MIN_DARK_COLS + MT9M111_MAX_WIDTH -
( __s32 ) rect . width ) ;
rect . top = clamp ( rect . top , MT9M111_MIN_DARK_ROWS ,
MT9M111_MIN_DARK_ROWS + MT9M111_MAX_HEIGHT -
( __s32 ) rect . height ) ;
2009-08-25 18:50:46 +04:00
2011-11-04 22:13:18 +04:00
width = min ( mt9m111 - > width , rect . width ) ;
height = min ( mt9m111 - > height , rect . height ) ;
2009-03-13 12:08:20 +03:00
2011-11-04 22:13:18 +04:00
ret = mt9m111_setup_geometry ( mt9m111 , & rect , width , height , mt9m111 - > fmt - > code ) ;
if ( ! ret ) {
2009-08-25 18:50:46 +04:00
mt9m111 - > rect = rect ;
2011-11-04 22:13:18 +04:00
mt9m111 - > width = width ;
mt9m111 - > height = height ;
}
2009-03-13 12:08:20 +03:00
return ret ;
}
2015-12-14 13:25:32 +03:00
static int mt9m111_get_selection ( 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 ,
2015-12-14 13:25:32 +03:00
struct v4l2_subdev_selection * sel )
2009-08-25 18:50:46 +04:00
{
2015-12-14 13:25:32 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct mt9m111 * mt9m111 = to_mt9m111 ( client ) ;
2009-08-25 18:50:46 +04:00
2015-12-14 13:25:32 +03:00
if ( sel - > which ! = V4L2_SUBDEV_FORMAT_ACTIVE )
2010-08-03 14:57:44 +04:00
return - EINVAL ;
2015-12-14 13:25:32 +03:00
switch ( sel - > target ) {
case V4L2_SEL_TGT_CROP_BOUNDS :
sel - > r . left = MT9M111_MIN_DARK_COLS ;
sel - > r . top = MT9M111_MIN_DARK_ROWS ;
sel - > r . width = MT9M111_MAX_WIDTH ;
sel - > r . height = MT9M111_MAX_HEIGHT ;
return 0 ;
case V4L2_SEL_TGT_CROP :
sel - > r = mt9m111 - > rect ;
return 0 ;
default :
return - EINVAL ;
}
2009-08-25 18:50:46 +04:00
}
2015-04-09 10:02:34 +03:00
static int mt9m111_get_fmt ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2015-04-09 10:02:34 +03:00
struct v4l2_subdev_format * format )
2009-08-25 18:50:46 +04:00
{
2015-04-09 10:02:34 +03:00
struct v4l2_mbus_framefmt * mf = & format - > format ;
2011-06-07 13:47:30 +04:00
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
2009-08-25 18:50:46 +04:00
2015-04-09 10:02:34 +03:00
if ( format - > pad )
return - EINVAL ;
2019-01-15 17:05:39 +03:00
if ( format - > which = = V4L2_SUBDEV_FORMAT_TRY ) {
# ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
mf = v4l2_subdev_get_try_format ( sd , sd_state , format - > pad ) ;
2019-01-15 17:05:39 +03:00
format - > format = * mf ;
return 0 ;
# else
2019-07-17 12:24:13 +03:00
return - EINVAL ;
2019-01-15 17:05:39 +03:00
# endif
}
2011-11-04 22:13:18 +04:00
mf - > width = mt9m111 - > width ;
mf - > height = mt9m111 - > height ;
2009-12-11 17:46:49 +03:00
mf - > code = mt9m111 - > fmt - > code ;
2010-08-03 14:57:45 +04:00
mf - > colorspace = mt9m111 - > fmt - > colorspace ;
2009-12-11 17:46:49 +03:00
mf - > field = V4L2_FIELD_NONE ;
2019-01-15 17:05:40 +03:00
mf - > ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT ;
mf - > quantization = V4L2_QUANTIZATION_DEFAULT ;
mf - > xfer_func = V4L2_XFER_FUNC_DEFAULT ;
2009-08-25 18:50:46 +04:00
return 0 ;
}
2011-06-07 13:47:30 +04:00
static int mt9m111_set_pixfmt ( struct mt9m111 * mt9m111 ,
2014-11-10 20:28:29 +03:00
u32 code )
2008-08-14 19:02:51 +04:00
{
2011-07-12 19:39:05 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
u16 data_outfmt2 , mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B ;
2008-08-14 19:03:49 +04:00
int ret ;
2008-08-14 19:02:51 +04:00
2009-12-11 17:46:49 +03:00
switch ( code ) {
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_SBGGR8_1X8 :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
MT9M111_OUTFMT_RGB ;
2008-08-14 19:02:51 +04:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB ;
2008-08-14 19:02:51 +04:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN ;
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 ;
2008-08-14 19:02:51 +04:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_RGB565_2X8_LE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN ;
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_RGB565_2X8_BE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 ;
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_BGR565_2X8_BE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B ;
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_BGR565_2X8_LE :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B ;
2008-08-14 19:02:51 +04:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_UYVY8_2X8 :
2011-07-12 19:39:05 +04:00
data_outfmt2 = 0 ;
2008-12-17 20:05:31 +03:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_VYUY8_2X8 :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B ;
2008-12-17 20:05:31 +03:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_YUYV8_2X8 :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN ;
2008-12-17 20:05:31 +03:00
break ;
2014-11-10 20:28:29 +03:00
case MEDIA_BUS_FMT_YVYU8_2X8 :
2011-07-12 19:39:05 +04:00
data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B ;
2008-08-14 19:02:51 +04:00
break ;
default :
2011-07-12 19:39:05 +04:00
dev_err ( & client - > dev , " Pixel format not handled: %x \n " , code ) ;
return - EINVAL ;
2008-08-14 19:02:51 +04:00
}
2018-11-27 13:02:53 +03:00
/* receiver samples on falling edge, chip-hw default is rising */
if ( mt9m111 - > pclk_sample = = 0 )
mask_outfmt2 | = MT9M111_OUTFMT_INV_PIX_CLOCK ;
2011-11-03 15:14:56 +04:00
ret = mt9m111_reg_mask ( client , context_a . output_fmt_ctrl2 ,
data_outfmt2 , mask_outfmt2 ) ;
2011-07-12 19:39:05 +04:00
if ( ! ret )
2011-11-03 15:14:56 +04:00
ret = mt9m111_reg_mask ( client , context_b . output_fmt_ctrl2 ,
data_outfmt2 , mask_outfmt2 ) ;
2011-07-12 19:39:05 +04:00
2008-08-14 19:02:51 +04:00
return ret ;
}
2015-04-09 12:24:36 +03:00
static int mt9m111_set_fmt ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state ,
2015-04-09 12:24:36 +03:00
struct v4l2_subdev_format * format )
2008-08-14 19:02:51 +04:00
{
2015-04-09 12:24:36 +03:00
struct v4l2_mbus_framefmt * mf = & format - > format ;
2011-11-04 22:13:18 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2011-06-07 13:47:30 +04:00
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
2009-12-11 17:46:49 +03:00
const struct mt9m111_datafmt * fmt ;
2011-11-04 22:13:18 +04:00
struct v4l2_rect * rect = & mt9m111 - > rect ;
bool bayer ;
2015-04-09 12:24:36 +03:00
int ret ;
2018-11-27 13:02:49 +03:00
if ( mt9m111 - > is_streaming )
return - EBUSY ;
2015-04-09 12:24:36 +03:00
if ( format - > pad )
return - EINVAL ;
2011-11-04 22:13:18 +04:00
fmt = mt9m111_find_datafmt ( mt9m111 , mf - > code ) ;
2014-11-10 20:28:29 +03:00
bayer = fmt - > code = = MEDIA_BUS_FMT_SBGGR8_1X8 | |
fmt - > code = = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ;
2009-08-25 18:50:46 +04:00
/*
* With Bayer format enforce even side lengths , but let the user play
* with the starting pixel
*/
2011-11-04 22:13:18 +04:00
if ( bayer ) {
rect - > width = ALIGN ( rect - > width , 2 ) ;
rect - > height = ALIGN ( rect - > height , 2 ) ;
}
2008-12-18 17:51:55 +03:00
2014-11-10 20:28:29 +03:00
if ( fmt - > code = = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ) {
2011-11-04 22:13:18 +04:00
/* IFP bypass mode, no scaling */
mf - > width = rect - > width ;
mf - > height = rect - > height ;
} else {
/* No upscaling */
if ( mf - > width > rect - > width )
mf - > width = rect - > width ;
if ( mf - > height > rect - > height )
mf - > height = rect - > height ;
}
2009-08-25 18:50:46 +04:00
2011-11-04 22:13:18 +04:00
dev_dbg ( & client - > dev , " %s(): %ux%u, code=%x \n " , __func__ ,
mf - > width , mf - > height , fmt - > code ) ;
2009-12-11 17:46:49 +03:00
2011-11-04 22:13:18 +04:00
mf - > code = fmt - > code ;
2009-12-11 17:46:49 +03:00
mf - > colorspace = fmt - > colorspace ;
2019-01-15 17:05:40 +03:00
mf - > field = V4L2_FIELD_NONE ;
mf - > ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT ;
mf - > quantization = V4L2_QUANTIZATION_DEFAULT ;
mf - > xfer_func = V4L2_XFER_FUNC_DEFAULT ;
2008-08-14 19:02:51 +04:00
2015-04-09 12:24:36 +03:00
if ( format - > 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
sd_state - > pads - > try_fmt = * mf ;
2015-04-09 12:24:36 +03:00
return 0 ;
}
2011-11-04 22:13:18 +04:00
ret = mt9m111_setup_geometry ( mt9m111 , rect , mf - > width , mf - > height , mf - > code ) ;
if ( ! ret )
ret = mt9m111_set_pixfmt ( mt9m111 , mf - > code ) ;
if ( ! ret ) {
mt9m111 - > width = mf - > width ;
mt9m111 - > height = mf - > height ;
mt9m111 - > fmt = fmt ;
}
return ret ;
}
2018-11-27 13:02:50 +03:00
static const struct mt9m111_mode_info *
mt9m111_find_mode ( struct mt9m111 * mt9m111 , unsigned int req_fps ,
unsigned int width , unsigned int height )
{
const struct mt9m111_mode_info * mode ;
struct v4l2_rect * sensor_rect = & mt9m111 - > rect ;
unsigned int gap , gap_best = ( unsigned int ) - 1 ;
int i , best_gap_idx = MT9M111_MODE_SXGA_15FPS ;
bool skip_30fps = false ;
/*
* The fps selection is based on the row , column skipping mechanism .
* So ensure that the sensor window is set to default else the fps
* aren ' t calculated correctly within the sensor hw .
*/
if ( sensor_rect - > width ! = MT9M111_MAX_WIDTH | |
sensor_rect - > height ! = MT9M111_MAX_HEIGHT ) {
dev_info ( mt9m111 - > subdev . dev ,
" Framerate selection is not supported for cropped "
" images \n " ) ;
return NULL ;
}
/* 30fps only supported for images not exceeding 640x512 */
if ( width > MT9M111_MAX_WIDTH / 2 | | height > MT9M111_MAX_HEIGHT / 2 ) {
dev_dbg ( mt9m111 - > subdev . dev ,
" Framerates > 15fps are supported only for images "
" not exceeding 640x512 \n " ) ;
skip_30fps = true ;
}
/* find best matched fps */
for ( i = 0 ; i < MT9M111_NUM_MODES ; i + + ) {
unsigned int fps = mt9m111_mode_data [ i ] . max_fps ;
if ( fps = = 30 & & skip_30fps )
continue ;
gap = abs ( fps - req_fps ) ;
if ( gap < gap_best ) {
best_gap_idx = i ;
gap_best = gap ;
}
}
/*
* Use context a / b default timing values instead of calculate blanking
* timing values .
*/
mode = & mt9m111_mode_data [ best_gap_idx ] ;
mt9m111 - > ctx = ( best_gap_idx = = MT9M111_MODE_QSXGA_30FPS ) ? & context_a :
& context_b ;
return mode ;
}
2008-08-14 19:02:51 +04:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2009-08-25 18:43:33 +04:00
static int mt9m111_g_register ( struct v4l2_subdev * sd ,
struct v4l2_dbg_register * reg )
2008-08-14 19:02:51 +04:00
{
2010-07-31 00:24:54 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-08-14 19:02:51 +04:00
int val ;
2013-05-29 13:59:50 +04:00
if ( reg - > reg > 0x2ff )
2008-08-14 19:02:51 +04:00
return - EINVAL ;
2009-04-24 19:57:01 +04:00
val = mt9m111_reg_read ( client , reg - > reg ) ;
2008-12-30 13:14:19 +03:00
reg - > size = 2 ;
2008-08-14 19:02:51 +04:00
reg - > val = ( u64 ) val ;
if ( reg - > val > 0xffff )
return - EIO ;
return 0 ;
}
2009-08-25 18:43:33 +04:00
static int mt9m111_s_register ( struct v4l2_subdev * sd ,
2013-03-24 15:28:46 +04:00
const struct v4l2_dbg_register * reg )
2008-08-14 19:02:51 +04:00
{
2010-07-31 00:24:54 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-08-14 19:02:51 +04:00
2013-05-29 13:59:50 +04:00
if ( reg - > reg > 0x2ff )
2008-08-14 19:02:51 +04:00
return - EINVAL ;
2009-04-24 19:57:01 +04:00
if ( mt9m111_reg_write ( client , reg - > reg , reg - > val ) < 0 )
2008-08-14 19:02:51 +04:00
return - EIO ;
return 0 ;
}
# endif
2011-06-07 13:47:30 +04:00
static int mt9m111_set_flip ( struct mt9m111 * mt9m111 , int flip , int mask )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-08-14 19:02:51 +04:00
int ret ;
2011-11-03 15:14:56 +04:00
if ( flip )
ret = mt9m111_reg_set ( client , mt9m111 - > ctx - > read_mode , mask ) ;
else
ret = mt9m111_reg_clear ( client , mt9m111 - > ctx - > read_mode , mask ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2011-06-07 13:47:30 +04:00
static int mt9m111_get_global_gain ( struct mt9m111 * mt9m111 )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-12-17 20:01:07 +03:00
int data ;
2008-08-14 19:02:51 +04:00
data = reg_read ( GLOBAL_GAIN ) ;
if ( data > = 0 )
2008-12-17 20:01:07 +03:00
return ( data & 0x2f ) * ( 1 < < ( ( data > > 10 ) & 1 ) ) *
( 1 < < ( ( data > > 9 ) & 1 ) ) ;
return data ;
2008-08-14 19:02:51 +04:00
}
2008-12-17 20:01:07 +03:00
2011-06-07 13:47:30 +04:00
static int mt9m111_set_global_gain ( struct mt9m111 * mt9m111 , int gain )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-08-14 19:02:51 +04:00
u16 val ;
if ( gain > 63 * 2 * 2 )
return - EINVAL ;
if ( ( gain > = 64 * 2 ) & & ( gain < 63 * 2 * 2 ) )
val = ( 1 < < 10 ) | ( 1 < < 9 ) | ( gain / 4 ) ;
else if ( ( gain > = 64 ) & & ( gain < 64 * 2 ) )
2008-08-14 19:03:49 +04:00
val = ( 1 < < 9 ) | ( gain / 2 ) ;
2008-08-14 19:02:51 +04:00
else
val = gain ;
return reg_write ( GLOBAL_GAIN , val ) ;
}
2013-02-26 22:32:49 +04:00
static int mt9m111_set_autoexposure ( struct mt9m111 * mt9m111 , int val )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-08-14 19:02:51 +04:00
2013-02-26 22:32:49 +04:00
if ( val = = V4L2_EXPOSURE_AUTO )
2011-09-07 13:56:57 +04:00
return reg_set ( OPER_MODE_CTRL , MT9M111_OPMODE_AUTOEXPO_EN ) ;
return reg_clear ( OPER_MODE_CTRL , MT9M111_OPMODE_AUTOEXPO_EN ) ;
2008-08-14 19:02:51 +04:00
}
2008-12-18 17:29:05 +03:00
2011-06-07 13:47:30 +04:00
static int mt9m111_set_autowhitebalance ( struct mt9m111 * mt9m111 , int on )
2008-12-18 17:29:05 +03:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-12-18 17:29:05 +03:00
if ( on )
2011-09-07 13:56:57 +04:00
return reg_set ( OPER_MODE_CTRL , MT9M111_OPMODE_AUTOWHITEBAL_EN ) ;
return reg_clear ( OPER_MODE_CTRL , MT9M111_OPMODE_AUTOWHITEBAL_EN ) ;
2008-12-18 17:29:05 +03:00
}
2018-01-03 21:22:47 +03:00
static const char * const mt9m111_test_pattern_menu [ ] = {
" Disabled " ,
" Vertical monochrome gradient " ,
" Flat color type 1 " ,
" Flat color type 2 " ,
" Flat color type 3 " ,
" Flat color type 4 " ,
" Flat color type 5 " ,
" Color bar " ,
} ;
static int mt9m111_set_test_pattern ( struct mt9m111 * mt9m111 , int val )
{
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
return mt9m111_reg_mask ( client , MT9M111_TPG_CTRL , val ,
MT9M111_TPG_SEL_MASK ) ;
}
2018-11-12 19:00:49 +03:00
static int mt9m111_set_colorfx ( struct mt9m111 * mt9m111 , int val )
{
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
static const struct v4l2_control colorfx [ ] = {
{ V4L2_COLORFX_NONE , 0 } ,
{ V4L2_COLORFX_BW , 1 } ,
{ V4L2_COLORFX_SEPIA , 2 } ,
{ V4L2_COLORFX_NEGATIVE , 3 } ,
{ V4L2_COLORFX_SOLARIZATION , 4 } ,
} ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( colorfx ) ; i + + ) {
if ( colorfx [ i ] . id = = val ) {
return mt9m111_reg_mask ( client , MT9M111_EFFECTS_MODE ,
colorfx [ i ] . value ,
MT9M111_EFFECTS_MODE_MASK ) ;
}
}
return - EINVAL ;
}
2011-09-07 13:56:57 +04:00
static int mt9m111_s_ctrl ( struct v4l2_ctrl * ctrl )
2008-08-14 19:02:51 +04:00
{
2011-09-07 13:56:57 +04:00
struct mt9m111 * mt9m111 = container_of ( ctrl - > handler ,
struct mt9m111 , hdl ) ;
2008-08-14 19:02:51 +04:00
switch ( ctrl - > id ) {
case V4L2_CID_VFLIP :
2011-09-07 13:56:57 +04:00
return mt9m111_set_flip ( mt9m111 , ctrl - > val ,
2008-08-14 19:02:51 +04:00
MT9M111_RMB_MIRROR_ROWS ) ;
case V4L2_CID_HFLIP :
2011-09-07 13:56:57 +04:00
return mt9m111_set_flip ( mt9m111 , ctrl - > val ,
2008-08-14 19:02:51 +04:00
MT9M111_RMB_MIRROR_COLS ) ;
case V4L2_CID_GAIN :
2011-09-07 13:56:57 +04:00
return mt9m111_set_global_gain ( mt9m111 , ctrl - > val ) ;
2008-08-14 19:02:51 +04:00
case V4L2_CID_EXPOSURE_AUTO :
2011-09-07 13:56:57 +04:00
return mt9m111_set_autoexposure ( mt9m111 , ctrl - > val ) ;
2008-12-18 17:29:05 +03:00
case V4L2_CID_AUTO_WHITE_BALANCE :
2011-09-07 13:56:57 +04:00
return mt9m111_set_autowhitebalance ( mt9m111 , ctrl - > val ) ;
2018-01-03 21:22:47 +03:00
case V4L2_CID_TEST_PATTERN :
return mt9m111_set_test_pattern ( mt9m111 , ctrl - > val ) ;
2018-11-12 19:00:49 +03:00
case V4L2_CID_COLORFX :
return mt9m111_set_colorfx ( mt9m111 , ctrl - > val ) ;
2008-08-14 19:02:51 +04:00
}
2011-09-07 13:56:57 +04:00
return - EINVAL ;
2008-08-14 19:02:51 +04:00
}
2011-06-05 15:27:39 +04:00
static int mt9m111_suspend ( struct mt9m111 * mt9m111 )
2009-08-25 18:53:23 +04:00
{
2011-11-03 15:19:18 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
int ret ;
2011-09-07 13:56:57 +04:00
v4l2_ctrl_s_ctrl ( mt9m111 - > gain , mt9m111_get_global_gain ( mt9m111 ) ) ;
2009-08-25 18:53:23 +04:00
2011-11-03 15:19:18 +04:00
ret = reg_set ( RESET , MT9M111_RESET_RESET_MODE ) ;
if ( ! ret )
ret = reg_set ( RESET , MT9M111_RESET_RESET_SOC |
MT9M111_RESET_OUTPUT_DISABLE |
MT9M111_RESET_ANALOG_STANDBY ) ;
if ( ! ret )
ret = reg_clear ( RESET , MT9M111_RESET_CHIP_ENABLE ) ;
return ret ;
2009-08-25 18:53:23 +04:00
}
2011-06-07 13:47:30 +04:00
static void mt9m111_restore_state ( struct mt9m111 * mt9m111 )
2008-08-14 19:02:51 +04:00
{
2018-11-27 13:02:50 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2011-11-03 15:14:56 +04:00
mt9m111_set_context ( mt9m111 , mt9m111 - > ctx ) ;
2011-06-07 13:47:30 +04:00
mt9m111_set_pixfmt ( mt9m111 , mt9m111 - > fmt - > code ) ;
2011-11-04 22:13:18 +04:00
mt9m111_setup_geometry ( mt9m111 , & mt9m111 - > rect ,
mt9m111 - > width , mt9m111 - > height , mt9m111 - > fmt - > code ) ;
2011-09-07 13:56:57 +04:00
v4l2_ctrl_handler_setup ( & mt9m111 - > hdl ) ;
2018-11-27 13:02:50 +03:00
mt9m111_reg_mask ( client , mt9m111 - > ctx - > read_mode ,
mt9m111 - > current_mode - > reg_val ,
mt9m111 - > current_mode - > reg_mask ) ;
2008-08-14 19:02:51 +04:00
}
2011-06-05 15:27:39 +04:00
static int mt9m111_resume ( struct mt9m111 * mt9m111 )
2008-08-14 19:02:51 +04:00
{
2011-11-03 15:19:18 +04:00
int ret = mt9m111_enable ( mt9m111 ) ;
if ( ! ret )
ret = mt9m111_reset ( mt9m111 ) ;
if ( ! ret )
mt9m111_restore_state ( mt9m111 ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
2011-06-07 13:47:30 +04:00
static int mt9m111_init ( struct mt9m111 * mt9m111 )
2008-08-14 19:02:51 +04:00
{
2011-06-07 13:47:30 +04:00
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
2008-08-14 19:02:51 +04:00
int ret ;
2011-06-07 13:47:30 +04:00
ret = mt9m111_enable ( mt9m111 ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2011-06-07 13:47:30 +04:00
ret = mt9m111_reset ( mt9m111 ) ;
2008-08-14 19:03:49 +04:00
if ( ! ret )
2011-11-03 15:14:56 +04:00
ret = mt9m111_set_context ( mt9m111 , mt9m111 - > ctx ) ;
2008-08-14 19:03:49 +04:00
if ( ret )
2010-08-03 14:57:39 +04:00
dev_err ( & client - > dev , " mt9m111 init failed: %d \n " , ret ) ;
2008-08-14 19:03:49 +04:00
return ret ;
2008-08-14 19:02:51 +04:00
}
2012-07-20 17:19:50 +04:00
static int mt9m111_power_on ( struct mt9m111 * mt9m111 )
{
struct i2c_client * client = v4l2_get_subdevdata ( & mt9m111 - > subdev ) ;
int ret ;
2021-01-12 22:49:17 +03:00
ret = clk_prepare_enable ( mt9m111 - > clk ) ;
2012-07-20 17:19:50 +04:00
if ( ret < 0 )
return ret ;
2019-05-31 23:11:35 +03:00
ret = regulator_enable ( mt9m111 - > regulator ) ;
if ( ret < 0 )
2019-05-31 23:12:49 +03:00
goto out_clk_disable ;
2019-05-29 22:25:18 +03:00
2012-07-20 17:19:50 +04:00
ret = mt9m111_resume ( mt9m111 ) ;
2019-05-31 23:12:49 +03:00
if ( ret < 0 )
goto out_regulator_disable ;
return 0 ;
out_regulator_disable :
regulator_disable ( mt9m111 - > regulator ) ;
out_clk_disable :
2021-01-12 22:49:17 +03:00
clk_disable_unprepare ( mt9m111 - > clk ) ;
2019-05-31 23:12:49 +03:00
dev_err ( & client - > dev , " Failed to resume the sensor: %d \n " , ret ) ;
2012-07-20 17:19:50 +04:00
return ret ;
}
static void mt9m111_power_off ( struct mt9m111 * mt9m111 )
{
mt9m111_suspend ( mt9m111 ) ;
2019-05-31 23:11:35 +03:00
regulator_disable ( mt9m111 - > regulator ) ;
2021-01-12 22:49:17 +03:00
clk_disable_unprepare ( mt9m111 - > clk ) ;
2012-07-20 17:19:50 +04:00
}
2011-06-05 15:27:39 +04:00
static int mt9m111_s_power ( struct v4l2_subdev * sd , int on )
{
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
int ret = 0 ;
mutex_lock ( & mt9m111 - > power_lock ) ;
/*
* If the power count is modified from 0 to ! = 0 or from ! = 0 to 0 ,
* update the power state .
*/
if ( mt9m111 - > power_count = = ! on ) {
2012-07-20 17:19:50 +04:00
if ( on )
ret = mt9m111_power_on ( mt9m111 ) ;
else
mt9m111_power_off ( mt9m111 ) ;
2011-06-05 15:27:39 +04:00
}
2012-07-20 17:19:50 +04:00
if ( ! ret ) {
/* Update the power count. */
mt9m111 - > power_count + = on ? 1 : - 1 ;
WARN_ON ( mt9m111 - > power_count < 0 ) ;
}
2011-06-05 15:27:39 +04:00
mutex_unlock ( & mt9m111 - > power_lock ) ;
return ret ;
}
2011-09-07 13:56:57 +04:00
static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
. s_ctrl = mt9m111_s_ctrl ,
} ;
2017-08-08 13:58:30 +03:00
static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
2011-06-05 15:27:39 +04:00
. s_power = mt9m111_s_power ,
2018-11-12 19:00:48 +03:00
. log_status = v4l2_ctrl_subdev_log_status ,
. subscribe_event = v4l2_ctrl_subdev_subscribe_event ,
. unsubscribe_event = v4l2_event_subdev_unsubscribe ,
2009-08-25 18:43:33 +04:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
. g_register = mt9m111_g_register ,
. s_register = mt9m111_s_register ,
# endif
} ;
2018-11-27 13:02:50 +03:00
static int mt9m111_g_frame_interval ( struct v4l2_subdev * sd ,
struct v4l2_subdev_frame_interval * fi )
{
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
fi - > interval = mt9m111 - > frame_interval ;
return 0 ;
}
static int mt9m111_s_frame_interval ( struct v4l2_subdev * sd ,
struct v4l2_subdev_frame_interval * fi )
{
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
const struct mt9m111_mode_info * mode ;
struct v4l2_fract * fract = & fi - > interval ;
int fps ;
if ( mt9m111 - > is_streaming )
return - EBUSY ;
if ( fi - > pad ! = 0 )
return - EINVAL ;
if ( fract - > numerator = = 0 ) {
fract - > denominator = 30 ;
fract - > numerator = 1 ;
}
fps = DIV_ROUND_CLOSEST ( fract - > denominator , fract - > numerator ) ;
/* Find best fitting mode. Do not update the mode if no one was found. */
mode = mt9m111_find_mode ( mt9m111 , fps , mt9m111 - > width , mt9m111 - > height ) ;
if ( ! mode )
return 0 ;
if ( mode - > max_fps ! = fps ) {
fract - > denominator = mode - > max_fps ;
fract - > numerator = 1 ;
}
mt9m111 - > current_mode = mode ;
mt9m111 - > frame_interval = fi - > interval ;
return 0 ;
}
2015-04-09 10:01:33 +03:00
static int mt9m111_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 ,
2015-04-09 10:01:33 +03:00
struct v4l2_subdev_mbus_code_enum * code )
2009-12-11 17:46:49 +03:00
{
2015-04-09 10:01:33 +03:00
if ( code - > pad | | code - > index > = ARRAY_SIZE ( mt9m111_colour_fmts ) )
2009-12-11 17:46:49 +03:00
return - EINVAL ;
2015-04-09 10:01:33 +03:00
code - > code = mt9m111_colour_fmts [ code - > index ] . code ;
2009-12-11 17:46:49 +03:00
return 0 ;
}
2018-11-27 13:02:48 +03:00
static int mt9m111_s_stream ( struct v4l2_subdev * sd , int enable )
{
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
mt9m111 - > is_streaming = ! ! enable ;
return 0 ;
}
2019-01-15 17:05:39 +03:00
static int mt9m111_init_cfg ( struct v4l2_subdev * sd ,
media: v4l2-subdev: add subdev-wide state struct
We have 'struct v4l2_subdev_pad_config' which contains configuration for
a single pad used for the TRY functionality, and an array of those
structs is passed to various v4l2_subdev_pad_ops.
I was working on subdev internal routing between pads, and realized that
there's no way to add TRY functionality for routes, which is not pad
specific configuration. Adding a separate struct for try-route config
wouldn't work either, as e.g. set-fmt needs to know the try-route
configuration to propagate the settings.
This patch adds a new struct, 'struct v4l2_subdev_state' (which at the
moment only contains the v4l2_subdev_pad_config array) and the new
struct is used in most of the places where v4l2_subdev_pad_config was
used. All v4l2_subdev_pad_ops functions taking v4l2_subdev_pad_config
are changed to instead take v4l2_subdev_state.
The changes to drivers/media/v4l2-core/v4l2-subdev.c and
include/media/v4l2-subdev.h were written by hand, and all the driver
changes were done with the semantic patch below. The spatch needs to be
applied to a select list of directories. I used the following shell
commands to apply the spatch:
dirs="drivers/media/i2c drivers/media/platform drivers/media/usb drivers/media/test-drivers/vimc drivers/media/pci drivers/staging/media"
for dir in $dirs; do spatch -j8 --dir --include-headers --no-show-diff --in-place --sp-file v4l2-subdev-state.cocci $dir; done
Note that Coccinelle chokes on a few drivers (gcc extensions?). With
minor changes we can make Coccinelle run fine, and these changes can be
reverted after spatch. The diff for these changes is:
For drivers/media/i2c/s5k5baf.c:
@@ -1481,7 +1481,7 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
&s5k5baf_cis_rect,
v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT),
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
For drivers/media/platform/s3c-camif/camif-capture.c:
@@ -1230,7 +1230,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
*mf = camif->mbus_fmt;
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* crop rectangle at camera interface input */
mf->width = camif->camif_crop.width;
mf->height = camif->camif_crop.height;
@@ -1332,7 +1332,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
break;
- case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P:
+ case CAMIF_SD_PAD_SOURCE_C:
/* Pixel format can be only changed on the sink pad. */
mf->code = camif->mbus_fmt.code;
mf->width = crop->width;
The semantic patch is:
// <smpl>
// Change function parameter
@@
identifier func;
identifier cfg;
@@
func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...)
{
<...
- cfg
+ sd_state
...>
}
// Change function declaration parameter
@@
identifier func;
identifier cfg;
type T;
@@
T func(...,
- struct v4l2_subdev_pad_config *cfg
+ struct v4l2_subdev_state *sd_state
, ...);
// Change function return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...)
{
...
}
// Change function declaration return value
@@
identifier func;
@@
- struct v4l2_subdev_pad_config
+ struct v4l2_subdev_state
*func(...);
// Some drivers pass a local pad_cfg for a single pad to a called function. Wrap it
// inside a pad_state.
@@
identifier func;
identifier pad_cfg;
@@
func(...)
{
...
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = { .pads = &pad_cfg };
<+...
(
v4l2_subdev_call
|
sensor_call
|
isi_try_fse
|
isc_try_fse
|
saa_call_all
)
(...,
- &pad_cfg
+ &pad_state
,...)
...+>
}
// If the function uses fields from pad_config, access via state->pads
@@
identifier func;
identifier state;
@@
func(...,
struct v4l2_subdev_state *state
, ...)
{
<...
(
- state->try_fmt
+ state->pads->try_fmt
|
- state->try_crop
+ state->pads->try_crop
|
- state->try_compose
+ state->pads->try_compose
)
...>
}
// If the function accesses the filehandle, use fh->state instead
@@
struct v4l2_subdev_fh *fh;
@@
- fh->pad
+ fh->state
@@
struct v4l2_subdev_fh fh;
@@
- fh.pad
+ fh.state
// Start of vsp1 specific
@@
@@
struct vsp1_entity {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
};
@@
symbol entity;
@@
vsp1_entity_init(...)
{
...
entity->config =
- v4l2_subdev_alloc_pad_config
+ v4l2_subdev_alloc_state
(&entity->subdev);
...
}
@@
symbol entity;
@@
vsp1_entity_destroy(...)
{
...
- v4l2_subdev_free_pad_config
+ v4l2_subdev_free_state
(entity->config);
...
}
@exists@
identifier func =~ "(^vsp1.*)|(hsit_set_format)|(sru_enum_frame_size)|(sru_set_format)|(uif_get_selection)|(uif_set_selection)|(uds_enum_frame_size)|(uds_set_format)|(brx_set_format)|(brx_get_selection)|(histo_get_selection)|(histo_set_selection)|(brx_set_selection)";
symbol config;
@@
func(...) {
...
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
...
}
// End of vsp1 specific
// Start of rcar specific
@@
identifier sd;
identifier pad_cfg;
@@
rvin_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
// End of rcar specific
// Start of rockchip specific
@@
identifier func =~ "(rkisp1_rsz_get_pad_fmt)|(rkisp1_rsz_get_pad_crop)|(rkisp1_rsz_register)";
symbol rsz;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = rsz->pad_cfg };
...
- rsz->pad_cfg
+ &state
...
}
@@
identifier func =~ "(rkisp1_isp_get_pad_fmt)|(rkisp1_isp_get_pad_crop)";
symbol isp;
symbol pad_cfg;
@@
func(...)
{
+ struct v4l2_subdev_state state = { .pads = isp->pad_cfg };
...
- isp->pad_cfg
+ &state
...
}
@@
symbol rkisp1;
symbol isp;
symbol pad_cfg;
@@
rkisp1_isp_register(...)
{
+ struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg };
...
- rkisp1->isp.pad_cfg
+ &state
...
}
// End of rockchip specific
// Start of tegra-video specific
@@
identifier sd;
identifier pad_cfg;
@@
__tegra_channel_try_format(...)
{
...
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
...
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
+ sd_state = v4l2_subdev_alloc_state(sd);
<...
- pad_cfg
+ sd_state
...>
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
...
}
@@
identifier sd_state;
@@
__tegra_channel_try_format(...)
{
...
struct v4l2_subdev_state *sd_state;
<...
- sd_state->try_crop
+ sd_state->pads->try_crop
...>
}
// End of tegra-video specific
// </smpl>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2021-06-10 17:55:58 +03:00
struct v4l2_subdev_state * sd_state )
2019-01-15 17:05:39 +03:00
{
# ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
struct v4l2_mbus_framefmt * format =
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
v4l2_subdev_get_try_format ( sd , sd_state , 0 ) ;
2019-01-15 17:05:39 +03:00
format - > width = MT9M111_MAX_WIDTH ;
format - > height = MT9M111_MAX_HEIGHT ;
format - > code = mt9m111_colour_fmts [ 0 ] . code ;
format - > colorspace = mt9m111_colour_fmts [ 0 ] . colorspace ;
format - > field = V4L2_FIELD_NONE ;
format - > ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT ;
format - > quantization = V4L2_QUANTIZATION_DEFAULT ;
format - > xfer_func = V4L2_XFER_FUNC_DEFAULT ;
# endif
return 0 ;
}
2020-07-17 17:53:16 +03:00
static int mt9m111_get_mbus_config ( struct v4l2_subdev * sd ,
unsigned int pad ,
struct v4l2_mbus_config * cfg )
2011-07-26 18:48:29 +04:00
{
2018-11-27 13:02:53 +03:00
struct mt9m111 * mt9m111 = container_of ( sd , struct mt9m111 , subdev ) ;
cfg - > flags = V4L2_MBUS_MASTER |
2011-07-26 18:48:29 +04:00
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH ;
2018-11-27 13:02:53 +03:00
cfg - > flags | = mt9m111 - > pclk_sample ? V4L2_MBUS_PCLK_SAMPLE_RISING :
V4L2_MBUS_PCLK_SAMPLE_FALLING ;
2011-07-26 18:48:29 +04:00
cfg - > type = V4L2_MBUS_PARALLEL ;
return 0 ;
}
2017-08-08 13:58:30 +03:00
static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
2018-11-27 13:02:48 +03:00
. s_stream = mt9m111_s_stream ,
2018-11-27 13:02:50 +03:00
. g_frame_interval = mt9m111_g_frame_interval ,
. s_frame_interval = mt9m111_s_frame_interval ,
2009-08-25 18:43:33 +04:00
} ;
2015-04-09 10:01:33 +03:00
static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
2019-01-15 17:05:39 +03:00
. init_cfg = mt9m111_init_cfg ,
2015-04-09 10:01:33 +03:00
. enum_mbus_code = mt9m111_enum_mbus_code ,
2015-12-14 13:25:32 +03:00
. get_selection = mt9m111_get_selection ,
. set_selection = mt9m111_set_selection ,
2015-04-09 10:02:34 +03:00
. get_fmt = mt9m111_get_fmt ,
2015-04-09 12:24:36 +03:00
. set_fmt = mt9m111_set_fmt ,
2020-07-17 17:53:16 +03:00
. get_mbus_config = mt9m111_get_mbus_config ,
2015-04-09 10:01:33 +03:00
} ;
2017-08-08 13:58:30 +03:00
static const struct v4l2_subdev_ops mt9m111_subdev_ops = {
2009-08-25 18:43:33 +04:00
. core = & mt9m111_subdev_core_ops ,
. video = & mt9m111_subdev_video_ops ,
2015-04-09 10:01:33 +03:00
. pad = & mt9m111_subdev_pad_ops ,
2009-08-25 18:43:33 +04:00
} ;
2012-07-18 17:54:04 +04:00
/*
* Interface active , can use i2c . If it fails , it can indeed mean , that
* this wasn ' t our capture interface , so , we wait for the right one
*/
static int mt9m111_video_probe ( struct i2c_client * client )
{
struct mt9m111 * mt9m111 = to_mt9m111 ( client ) ;
s32 data ;
int ret ;
ret = mt9m111_s_power ( & mt9m111 - > subdev , 1 ) ;
if ( ret < 0 )
return ret ;
data = reg_read ( CHIP_VERSION ) ;
switch ( data ) {
case 0x143a : /* MT9M111 or MT9M131 */
dev_info ( & client - > dev ,
" Detected a MT9M111/MT9M131 chip ID %x \n " , data ) ;
break ;
case 0x148c : /* MT9M112 */
dev_info ( & client - > dev , " Detected a MT9M112 chip ID %x \n " , data ) ;
break ;
default :
dev_err ( & client - > dev ,
" No MT9M111/MT9M112/MT9M131 chip detected register read %x \n " ,
data ) ;
ret = - ENODEV ;
goto done ;
}
ret = mt9m111_init ( mt9m111 ) ;
if ( ret )
goto done ;
ret = v4l2_ctrl_handler_setup ( & mt9m111 - > hdl ) ;
done :
mt9m111_s_power ( & mt9m111 - > subdev , 0 ) ;
return ret ;
}
2018-11-27 13:02:53 +03:00
static int mt9m111_probe_fw ( struct i2c_client * client , struct mt9m111 * mt9m111 )
{
struct v4l2_fwnode_endpoint bus_cfg = {
. bus_type = V4L2_MBUS_PARALLEL
} ;
struct fwnode_handle * np ;
int ret ;
np = fwnode_graph_get_next_endpoint ( dev_fwnode ( & client - > dev ) , NULL ) ;
if ( ! np )
return - EINVAL ;
ret = v4l2_fwnode_endpoint_parse ( np , & bus_cfg ) ;
if ( ret )
goto out_put_fw ;
mt9m111 - > pclk_sample = ! ! ( bus_cfg . bus . parallel . flags &
V4L2_MBUS_PCLK_SAMPLE_RISING ) ;
out_put_fw :
fwnode_handle_put ( np ) ;
return ret ;
}
2019-07-11 00:51:49 +03:00
static int mt9m111_probe ( struct i2c_client * client )
2008-08-14 19:02:51 +04:00
{
struct mt9m111 * mt9m111 ;
2019-06-08 13:55:47 +03:00
struct i2c_adapter * adapter = client - > adapter ;
2008-08-14 19:02:51 +04:00
int ret ;
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_WORD_DATA ) ) {
dev_warn ( & adapter - > dev ,
" I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD \n " ) ;
return - EIO ;
}
2012-12-21 17:28:43 +04:00
mt9m111 = devm_kzalloc ( & client - > dev , sizeof ( struct mt9m111 ) , GFP_KERNEL ) ;
2008-08-14 19:02:51 +04:00
if ( ! mt9m111 )
return - ENOMEM ;
2019-06-03 23:01:55 +03:00
if ( dev_fwnode ( & client - > dev ) ) {
ret = mt9m111_probe_fw ( client , mt9m111 ) ;
if ( ret )
return ret ;
}
2018-11-27 13:02:53 +03:00
2021-01-12 22:49:17 +03:00
mt9m111 - > clk = devm_clk_get ( & client - > dev , " mclk " ) ;
2013-07-30 11:35:18 +04:00
if ( IS_ERR ( mt9m111 - > clk ) )
2017-08-27 19:30:36 +03:00
return PTR_ERR ( mt9m111 - > clk ) ;
2013-07-30 11:35:18 +04:00
2019-05-29 22:25:18 +03:00
mt9m111 - > regulator = devm_regulator_get ( & client - > dev , " vdd " ) ;
if ( IS_ERR ( mt9m111 - > regulator ) ) {
dev_err ( & client - > dev , " regulator not found: %ld \n " ,
PTR_ERR ( mt9m111 - > regulator ) ) ;
return PTR_ERR ( mt9m111 - > regulator ) ;
}
2013-03-12 15:40:37 +04:00
/* Default HIGHPOWER context */
mt9m111 - > ctx = & context_b ;
2009-08-25 18:43:33 +04:00
v4l2_i2c_subdev_init ( & mt9m111 - > subdev , client , & mt9m111_subdev_ops ) ;
2018-11-12 19:00:48 +03:00
mt9m111 - > subdev . flags | = V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS ;
2018-01-03 21:22:44 +03:00
2018-11-12 19:00:49 +03:00
v4l2_ctrl_handler_init ( & mt9m111 - > hdl , 7 ) ;
2011-09-07 13:56:57 +04:00
v4l2_ctrl_new_std ( & mt9m111 - > hdl , & mt9m111_ctrl_ops ,
V4L2_CID_VFLIP , 0 , 1 , 1 , 0 ) ;
v4l2_ctrl_new_std ( & mt9m111 - > hdl , & mt9m111_ctrl_ops ,
V4L2_CID_HFLIP , 0 , 1 , 1 , 0 ) ;
v4l2_ctrl_new_std ( & mt9m111 - > hdl , & mt9m111_ctrl_ops ,
V4L2_CID_AUTO_WHITE_BALANCE , 0 , 1 , 1 , 1 ) ;
mt9m111 - > gain = v4l2_ctrl_new_std ( & mt9m111 - > hdl , & mt9m111_ctrl_ops ,
V4L2_CID_GAIN , 0 , 63 * 2 * 2 , 1 , 32 ) ;
v4l2_ctrl_new_std_menu ( & mt9m111 - > hdl ,
& mt9m111_ctrl_ops , V4L2_CID_EXPOSURE_AUTO , 1 , 0 ,
V4L2_EXPOSURE_AUTO ) ;
2018-01-03 21:22:47 +03:00
v4l2_ctrl_new_std_menu_items ( & mt9m111 - > hdl ,
& mt9m111_ctrl_ops , V4L2_CID_TEST_PATTERN ,
ARRAY_SIZE ( mt9m111_test_pattern_menu ) - 1 , 0 , 0 ,
mt9m111_test_pattern_menu ) ;
2018-11-12 19:00:49 +03:00
v4l2_ctrl_new_std_menu ( & mt9m111 - > hdl , & mt9m111_ctrl_ops ,
V4L2_CID_COLORFX , V4L2_COLORFX_SOLARIZATION ,
~ ( BIT ( V4L2_COLORFX_NONE ) |
BIT ( V4L2_COLORFX_BW ) |
BIT ( V4L2_COLORFX_SEPIA ) |
BIT ( V4L2_COLORFX_NEGATIVE ) |
BIT ( V4L2_COLORFX_SOLARIZATION ) ) ,
V4L2_COLORFX_NONE ) ;
2011-09-07 13:56:57 +04:00
mt9m111 - > subdev . ctrl_handler = & mt9m111 - > hdl ;
2013-07-30 11:35:18 +04:00
if ( mt9m111 - > hdl . error ) {
ret = mt9m111 - > hdl . error ;
2021-01-12 22:49:17 +03:00
return ret ;
2013-07-30 11:35:18 +04:00
}
2008-08-14 19:02:51 +04:00
2018-01-03 21:22:45 +03:00
# ifdef CONFIG_MEDIA_CONTROLLER
mt9m111 - > pad . flags = MEDIA_PAD_FL_SOURCE ;
mt9m111 - > subdev . entity . function = MEDIA_ENT_F_CAM_SENSOR ;
ret = media_entity_pads_init ( & mt9m111 - > subdev . entity , 1 , & mt9m111 - > pad ) ;
if ( ret < 0 )
goto out_hdlfree ;
# endif
2018-11-27 13:02:50 +03:00
mt9m111 - > current_mode = & mt9m111_mode_data [ MT9M111_MODE_SXGA_15FPS ] ;
mt9m111 - > frame_interval . numerator = 1 ;
mt9m111 - > frame_interval . denominator = mt9m111 - > current_mode - > max_fps ;
2011-09-07 13:56:57 +04:00
/* Second stage probe - when a capture adapter is there */
2009-08-25 18:50:46 +04:00
mt9m111 - > rect . left = MT9M111_MIN_DARK_COLS ;
mt9m111 - > rect . top = MT9M111_MIN_DARK_ROWS ;
mt9m111 - > rect . width = MT9M111_MAX_WIDTH ;
mt9m111 - > rect . height = MT9M111_MAX_HEIGHT ;
2019-01-15 17:05:41 +03:00
mt9m111 - > width = mt9m111 - > rect . width ;
mt9m111 - > height = mt9m111 - > rect . height ;
2009-12-11 17:46:49 +03:00
mt9m111 - > fmt = & mt9m111_colour_fmts [ 0 ] ;
2011-09-21 22:16:30 +04:00
mt9m111 - > lastpage = - 1 ;
2011-11-03 15:12:00 +04:00
mutex_init ( & mt9m111 - > power_lock ) ;
2009-08-25 18:50:46 +04:00
2011-09-21 22:16:30 +04:00
ret = mt9m111_video_probe ( client ) ;
2013-07-30 11:35:18 +04:00
if ( ret < 0 )
2018-01-03 21:22:45 +03:00
goto out_entityclean ;
2013-07-30 11:35:18 +04:00
mt9m111 - > subdev . dev = & client - > dev ;
ret = v4l2_async_register_subdev ( & mt9m111 - > subdev ) ;
if ( ret < 0 )
2018-01-03 21:22:45 +03:00
goto out_entityclean ;
2013-07-30 11:35:18 +04:00
return 0 ;
2018-01-03 21:22:45 +03:00
out_entityclean :
# ifdef CONFIG_MEDIA_CONTROLLER
media_entity_cleanup ( & mt9m111 - > subdev . entity ) ;
2013-07-30 11:35:18 +04:00
out_hdlfree :
2018-01-03 21:22:45 +03:00
# endif
2013-07-30 11:35:18 +04:00
v4l2_ctrl_handler_free ( & mt9m111 - > hdl ) ;
2008-08-14 19:02:51 +04:00
return ret ;
}
static int mt9m111_remove ( struct i2c_client * client )
{
2009-08-25 18:43:33 +04:00
struct mt9m111 * mt9m111 = to_mt9m111 ( client ) ;
2009-08-25 18:28:22 +04:00
2013-07-30 11:35:18 +04:00
v4l2_async_unregister_subdev ( & mt9m111 - > subdev ) ;
2018-01-03 21:22:45 +03:00
media_entity_cleanup ( & mt9m111 - > subdev . entity ) ;
2011-09-07 13:56:57 +04:00
v4l2_ctrl_handler_free ( & mt9m111 - > hdl ) ;
2008-08-14 19:02:51 +04:00
return 0 ;
}
2014-06-22 02:19:54 +04:00
static const struct of_device_id mt9m111_of_match [ ] = {
{ . compatible = " micron,mt9m111 " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , mt9m111_of_match ) ;
2008-08-14 19:02:51 +04:00
static const struct i2c_device_id mt9m111_id [ ] = {
{ " mt9m111 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , mt9m111_id ) ;
static struct i2c_driver mt9m111_i2c_driver = {
. driver = {
. name = " mt9m111 " ,
2014-06-22 02:19:54 +04:00
. of_match_table = of_match_ptr ( mt9m111_of_match ) ,
2008-08-14 19:02:51 +04:00
} ,
2019-07-11 00:51:49 +03:00
. probe_new = mt9m111_probe ,
2008-08-14 19:02:51 +04:00
. remove = mt9m111_remove ,
. id_table = mt9m111_id ,
} ;
2012-02-12 13:56:32 +04:00
module_i2c_driver ( mt9m111_i2c_driver ) ;
2008-08-14 19:02:51 +04:00
2010-08-03 14:57:39 +04:00
MODULE_DESCRIPTION ( " Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver " ) ;
2008-08-14 19:02:51 +04:00
MODULE_AUTHOR ( " Robert Jarzmik " ) ;
MODULE_LICENSE ( " GPL " ) ;