2008-04-22 14:42:04 -03:00
/*
* Driver for MT9V022 CMOS Image Sensor from Micron
*
* Copyright ( C ) 2008 , Guennadi Liakhovetski < kernel @ pengutronix . de >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/videodev2.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/delay.h>
# include <linux/log2.h>
2011-07-03 14:03:12 -04:00
# include <linux/module.h>
2008-04-22 14:42:04 -03:00
2012-09-27 19:05:27 -03:00
# include <media/mt9v022.h>
2011-07-27 05:53:33 -03:00
# include <media/soc_camera.h>
# include <media/soc_mediabus.h>
2009-08-25 11:43:33 -03:00
# include <media/v4l2-subdev.h>
2012-12-21 13:01:55 -03:00
# include <media/v4l2-clk.h>
2011-09-07 05:22:39 -03:00
# include <media/v4l2-ctrls.h>
2008-04-22 14:42:04 -03:00
2009-12-11 11:15:05 -03:00
/*
* mt9v022 i2c address 0x48 , 0x4c , 0x58 , 0x5c
2012-06-13 10:48:11 -03:00
* The platform has to define struct i2c_board_info objects and link to them
2012-12-21 08:11:48 -03:00
* from struct soc_camera_host_desc
2009-12-11 11:15:05 -03:00
*/
2008-04-22 14:42:04 -03:00
static char * sensor_type ;
module_param ( sensor_type , charp , S_IRUGO ) ;
2008-07-31 00:07:23 -07:00
MODULE_PARM_DESC ( sensor_type , " Sensor type: \" colour \" or \" monochrome \" " ) ;
2008-04-22 14:42:04 -03:00
/* mt9v022 selected register addresses */
# define MT9V022_CHIP_VERSION 0x00
# define MT9V022_COLUMN_START 0x01
# define MT9V022_ROW_START 0x02
# define MT9V022_WINDOW_HEIGHT 0x03
# define MT9V022_WINDOW_WIDTH 0x04
# define MT9V022_HORIZONTAL_BLANKING 0x05
# define MT9V022_VERTICAL_BLANKING 0x06
# define MT9V022_CHIP_CONTROL 0x07
# define MT9V022_SHUTTER_WIDTH1 0x08
# define MT9V022_SHUTTER_WIDTH2 0x09
# define MT9V022_SHUTTER_WIDTH_CTRL 0x0a
# define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b
# define MT9V022_RESET 0x0c
# define MT9V022_READ_MODE 0x0d
# define MT9V022_MONITOR_MODE 0x0e
# define MT9V022_PIXEL_OPERATION_MODE 0x0f
# define MT9V022_LED_OUT_CONTROL 0x1b
# define MT9V022_ADC_MODE_CONTROL 0x1c
2012-09-27 19:52:42 -03:00
# define MT9V022_REG32 0x20
2009-08-25 11:53:23 -03:00
# define MT9V022_ANALOG_GAIN 0x35
2008-04-22 14:42:04 -03:00
# define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
# define MT9V022_PIXCLK_FV_LV 0x74
# define MT9V022_DIGITAL_TEST_PATTERN 0x7f
# define MT9V022_AEC_AGC_ENABLE 0xAF
# define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD
2012-08-02 12:32:41 -03:00
/* mt9v024 partial list register addresses changes with respect to mt9v022 */
# define MT9V024_PIXCLK_FV_LV 0x72
# define MT9V024_MAX_TOTAL_SHUTTER_WIDTH 0xAD
2008-04-22 14:42:04 -03:00
/* Progressive scan, master, defaults */
# define MT9V022_CHIP_CONTROL_DEFAULT 0x188
2009-08-25 11:50:46 -03:00
# define MT9V022_MAX_WIDTH 752
# define MT9V022_MAX_HEIGHT 480
# define MT9V022_MIN_WIDTH 48
# define MT9V022_MIN_HEIGHT 32
# define MT9V022_COLUMN_SKIP 1
# define MT9V022_ROW_SKIP 4
2012-09-27 19:03:45 -03:00
# define MT9V022_HORIZONTAL_BLANKING_MIN 43
# define MT9V022_HORIZONTAL_BLANKING_MAX 1023
# define MT9V022_HORIZONTAL_BLANKING_DEF 94
# define MT9V022_VERTICAL_BLANKING_MIN 2
# define MT9V022_VERTICAL_BLANKING_MAX 3000
# define MT9V022_VERTICAL_BLANKING_DEF 45
2012-09-27 19:52:42 -03:00
# define is_mt9v022_rev3(id) (id == 0x1313)
# define is_mt9v024(id) (id == 0x1324)
2012-08-02 12:32:41 -03:00
2009-12-11 11:46:49 -03:00
/* MT9V022 has only one fixed colorspace per pixelcode */
struct mt9v022_datafmt {
enum v4l2_mbus_pixelcode code ;
enum v4l2_colorspace colorspace ;
} ;
/* Find a data format by a pixel code in an array */
static const struct mt9v022_datafmt * mt9v022_find_datafmt (
enum v4l2_mbus_pixelcode code , const struct mt9v022_datafmt * fmt ,
int n )
{
int i ;
for ( i = 0 ; i < n ; i + + )
if ( fmt [ i ] . code = = code )
return fmt + i ;
return NULL ;
}
static const struct mt9v022_datafmt mt9v022_colour_fmts [ ] = {
2009-12-11 11:15:05 -03:00
/*
* Order important : first natively supported ,
* second supported with a GPIO extender
*/
2009-12-11 11:46:49 -03:00
{ V4L2_MBUS_FMT_SBGGR10_1X10 , V4L2_COLORSPACE_SRGB } ,
{ V4L2_MBUS_FMT_SBGGR8_1X8 , V4L2_COLORSPACE_SRGB } ,
2008-04-22 14:45:13 -03:00
} ;
2009-12-11 11:46:49 -03:00
static const struct mt9v022_datafmt mt9v022_monochrome_fmts [ ] = {
2008-04-22 14:45:13 -03:00
/* Order important - see above */
2009-12-11 11:46:49 -03:00
{ V4L2_MBUS_FMT_Y10_1X10 , V4L2_COLORSPACE_JPEG } ,
2010-09-28 07:01:44 -03:00
{ V4L2_MBUS_FMT_Y8_1X8 , V4L2_COLORSPACE_JPEG } ,
2008-04-22 14:42:04 -03:00
} ;
2012-08-02 12:32:41 -03:00
/* only registers with different addresses on different mt9v02x sensors */
struct mt9v02x_register {
u8 max_total_shutter_width ;
u8 pixclk_fv_lv ;
} ;
static const struct mt9v02x_register mt9v022_register = {
. max_total_shutter_width = MT9V022_MAX_TOTAL_SHUTTER_WIDTH ,
. pixclk_fv_lv = MT9V022_PIXCLK_FV_LV ,
} ;
static const struct mt9v02x_register mt9v024_register = {
. max_total_shutter_width = MT9V024_MAX_TOTAL_SHUTTER_WIDTH ,
. pixclk_fv_lv = MT9V024_PIXCLK_FV_LV ,
} ;
2013-05-29 06:59:50 -03:00
enum mt9v022_model {
MT9V022IX7ATM ,
MT9V022IX7ATC ,
} ;
2008-04-22 14:42:04 -03:00
struct mt9v022 {
2009-08-25 11:43:33 -03:00
struct v4l2_subdev subdev ;
2011-09-07 05:22:39 -03:00
struct v4l2_ctrl_handler hdl ;
struct {
/* exposure/auto-exposure cluster */
struct v4l2_ctrl * autoexposure ;
struct v4l2_ctrl * exposure ;
} ;
struct {
/* gain/auto-gain cluster */
struct v4l2_ctrl * autogain ;
struct v4l2_ctrl * gain ;
} ;
2012-09-27 19:03:45 -03:00
struct v4l2_ctrl * hblank ;
struct v4l2_ctrl * vblank ;
2009-08-25 11:50:46 -03:00
struct v4l2_rect rect ; /* Sensor window */
2012-12-21 13:01:55 -03:00
struct v4l2_clk * clk ;
2009-12-11 11:46:49 -03:00
const struct mt9v022_datafmt * fmt ;
const struct mt9v022_datafmt * fmts ;
2012-08-02 12:32:41 -03:00
const struct mt9v02x_register * reg ;
2009-12-11 11:46:49 -03:00
int num_fmts ;
2013-05-29 06:59:50 -03:00
enum mt9v022_model model ;
2008-04-22 14:42:04 -03:00
u16 chip_control ;
2012-09-27 19:52:42 -03:00
u16 chip_version ;
2009-12-11 11:14:46 -03:00
unsigned short y_skip_top ; /* Lines to skip at the top */
2008-04-22 14:42:04 -03:00
} ;
2009-08-25 11:43:33 -03:00
static struct mt9v022 * to_mt9v022 ( const struct i2c_client * client )
{
return container_of ( i2c_get_clientdata ( client ) , struct mt9v022 , subdev ) ;
}
2009-04-24 12:57:01 -03:00
static int reg_read ( struct i2c_client * client , const u8 reg )
2008-04-22 14:42:04 -03:00
{
2011-10-21 09:30:25 -03:00
return i2c_smbus_read_word_swapped ( client , reg ) ;
2008-04-22 14:42:04 -03:00
}
2009-04-24 12:57:01 -03:00
static int reg_write ( struct i2c_client * client , const u8 reg ,
2008-04-22 14:42:04 -03:00
const u16 data )
{
2011-10-21 09:30:25 -03:00
return i2c_smbus_write_word_swapped ( client , reg , data ) ;
2008-04-22 14:42:04 -03:00
}
2009-04-24 12:57:01 -03:00
static int reg_set ( struct i2c_client * client , const u8 reg ,
2008-04-22 14:42:04 -03:00
const u16 data )
{
int ret ;
2009-04-24 12:57:01 -03:00
ret = reg_read ( client , reg ) ;
2008-04-22 14:42:04 -03:00
if ( ret < 0 )
return ret ;
2009-04-24 12:57:01 -03:00
return reg_write ( client , reg , ret | data ) ;
2008-04-22 14:42:04 -03:00
}
2009-04-24 12:57:01 -03:00
static int reg_clear ( struct i2c_client * client , const u8 reg ,
2008-04-22 14:42:04 -03:00
const u16 data )
{
int ret ;
2009-04-24 12:57:01 -03:00
ret = reg_read ( client , reg ) ;
2008-04-22 14:42:04 -03:00
if ( ret < 0 )
return ret ;
2009-04-24 12:57:01 -03:00
return reg_write ( client , reg , ret & ~ data ) ;
2008-04-22 14:42:04 -03:00
}
2009-08-25 11:53:23 -03:00
static int mt9v022_init ( struct i2c_client * client )
2008-04-22 14:42:04 -03:00
{
2009-08-25 11:43:33 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2008-04-22 14:42:04 -03:00
int ret ;
2009-12-11 11:15:05 -03:00
/*
* Almost the default mode : master , parallel , simultaneous , and an
2008-04-22 14:42:04 -03:00
* undocumented bit 0x200 , which is present in table 7 , but not in 8 ,
2009-12-11 11:15:05 -03:00
* plus snapshot mode to disable scan for now
*/
2008-04-22 14:42:04 -03:00
mt9v022 - > chip_control | = 0x10 ;
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_CHIP_CONTROL , mt9v022 - > chip_control ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_READ_MODE , 0x300 ) ;
2008-04-22 14:42:04 -03:00
/* All defaults */
2008-08-14 12:03:18 -03:00
if ( ! ret )
2008-04-22 14:42:04 -03:00
/* AEC, AGC on */
2009-04-24 12:57:01 -03:00
ret = reg_set ( client , MT9V022_AEC_AGC_ENABLE , 0x3 ) ;
2009-08-25 11:53:23 -03:00
if ( ! ret )
ret = reg_write ( client , MT9V022_ANALOG_GAIN , 16 ) ;
if ( ! ret )
ret = reg_write ( client , MT9V022_TOTAL_SHUTTER_WIDTH , 480 ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2012-08-02 12:32:41 -03:00
ret = reg_write ( client , mt9v022 - > reg - > max_total_shutter_width , 480 ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2008-04-22 14:42:04 -03:00
/* default - auto */
2009-04-24 12:57:01 -03:00
ret = reg_clear ( client , MT9V022_BLACK_LEVEL_CALIB_CTRL , 1 ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_DIGITAL_TEST_PATTERN , 0 ) ;
2011-09-07 05:22:39 -03:00
if ( ! ret )
return v4l2_ctrl_handler_setup ( & mt9v022 - > hdl ) ;
2008-04-22 14:42:04 -03:00
2008-08-14 12:03:18 -03:00
return ret ;
2008-04-22 14:42:04 -03:00
}
2009-08-25 11:43:33 -03:00
static int mt9v022_s_stream ( struct v4l2_subdev * sd , int enable )
2008-04-22 14:42:04 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-08-25 11:43:33 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2008-08-14 12:04:11 -03:00
2012-09-27 19:52:42 -03:00
if ( enable ) {
2009-08-25 11:43:33 -03:00
/* Switch to master "normal" mode */
mt9v022 - > chip_control & = ~ 0x10 ;
2012-09-27 19:52:42 -03:00
if ( is_mt9v022_rev3 ( mt9v022 - > chip_version ) | |
is_mt9v024 ( mt9v022 - > chip_version ) ) {
/*
* Unset snapshot mode specific settings : clear bit 9
* and bit 2 in reg . 0x20 when in normal mode .
*/
if ( reg_clear ( client , MT9V022_REG32 , 0x204 ) )
return - EIO ;
}
} else {
2009-08-25 11:43:33 -03:00
/* Switch to snapshot mode */
mt9v022 - > chip_control | = 0x10 ;
2012-09-27 19:52:42 -03:00
if ( is_mt9v022_rev3 ( mt9v022 - > chip_version ) | |
is_mt9v024 ( mt9v022 - > chip_version ) ) {
/*
* Required settings for snapshot mode : set bit 9
* ( RST enable ) and bit 2 ( CR enable ) in reg . 0x20
* See TechNote TN0960 or TN - 09 - 225.
*/
if ( reg_set ( client , MT9V022_REG32 , 0x204 ) )
return - EIO ;
}
}
2008-04-22 14:42:04 -03:00
2009-08-25 11:43:33 -03:00
if ( reg_write ( client , MT9V022_CHIP_CONTROL , mt9v022 - > chip_control ) < 0 )
2008-04-22 14:42:04 -03:00
return - EIO ;
return 0 ;
}
2012-09-05 05:10:48 -03:00
static int mt9v022_s_crop ( struct v4l2_subdev * sd , const struct v4l2_crop * a )
2008-03-07 21:57:18 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-08-25 11:50:46 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
struct v4l2_rect rect = a - > c ;
2013-02-06 11:29:18 -03:00
int min_row , min_blank ;
2008-03-07 21:57:18 -03:00
int ret ;
2009-08-25 11:50:46 -03:00
/* Bayer format - even size lengths */
2009-12-11 11:46:49 -03:00
if ( mt9v022 - > fmts = = mt9v022_colour_fmts ) {
2009-08-25 11:50:46 -03:00
rect . width = ALIGN ( rect . width , 2 ) ;
rect . height = ALIGN ( rect . height , 2 ) ;
/* Let the user play with the starting pixel */
}
soc_camera_limit_side ( & rect . left , & rect . width ,
MT9V022_COLUMN_SKIP , MT9V022_MIN_WIDTH , MT9V022_MAX_WIDTH ) ;
soc_camera_limit_side ( & rect . top , & rect . height ,
MT9V022_ROW_SKIP , MT9V022_MIN_HEIGHT , MT9V022_MAX_HEIGHT ) ;
2008-04-22 14:42:04 -03:00
/* Like in example app. Contradicts the datasheet though */
2009-04-24 12:57:01 -03:00
ret = reg_read ( client , MT9V022_AEC_AGC_ENABLE ) ;
2008-04-22 14:42:04 -03:00
if ( ret > = 0 ) {
if ( ret & 1 ) /* Autoexposure */
2012-08-02 12:32:41 -03:00
ret = reg_write ( client , mt9v022 - > reg - > max_total_shutter_width ,
2009-12-11 11:14:46 -03:00
rect . height + mt9v022 - > y_skip_top + 43 ) ;
2012-09-27 19:04:34 -03:00
/*
* If autoexposure is off , there is no need to set
* MT9V022_TOTAL_SHUTTER_WIDTH here . Autoexposure can be off
* only if the user has set exposure manually , using the
* V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL .
* In this case the register MT9V022_TOTAL_SHUTTER_WIDTH
* already contains the correct value .
*/
2008-04-22 14:42:04 -03:00
}
/* Setup frame format: defaults apart from width and height */
2008-08-14 12:03:18 -03:00
if ( ! ret )
2009-08-25 11:50:46 -03:00
ret = reg_write ( client , MT9V022_COLUMN_START , rect . left ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2009-08-25 11:50:46 -03:00
ret = reg_write ( client , MT9V022_ROW_START , rect . top ) ;
2013-02-06 11:29:18 -03:00
/*
* mt9v022 : min total row time is 660 columns , min blanking is 43
* mt9v024 : min total row time is 690 columns , min blanking is 61
*/
if ( is_mt9v024 ( mt9v022 - > chip_version ) ) {
min_row = 690 ;
min_blank = 61 ;
} else {
min_row = 660 ;
min_blank = 43 ;
}
2008-08-14 12:03:18 -03:00
if ( ! ret )
2012-09-27 19:03:45 -03:00
ret = v4l2_ctrl_s_ctrl ( mt9v022 - > hblank ,
2013-02-06 11:29:18 -03:00
rect . width > min_row - min_blank ?
min_blank : min_row - rect . width ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2012-09-27 19:03:45 -03:00
ret = v4l2_ctrl_s_ctrl ( mt9v022 - > vblank , 45 ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2009-08-25 11:50:46 -03:00
ret = reg_write ( client , MT9V022_WINDOW_WIDTH , rect . width ) ;
2008-08-14 12:03:18 -03:00
if ( ! ret )
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_WINDOW_HEIGHT ,
2009-12-11 11:14:46 -03:00
rect . height + mt9v022 - > y_skip_top ) ;
2008-04-22 14:42:04 -03:00
if ( ret < 0 )
return ret ;
2010-02-24 17:13:29 -03:00
dev_dbg ( & client - > dev , " Frame %dx%d pixel \n " , rect . width , rect . height ) ;
2009-08-25 11:50:46 -03:00
mt9v022 - > rect = rect ;
return 0 ;
}
static int mt9v022_g_crop ( struct v4l2_subdev * sd , struct v4l2_crop * a )
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-08-25 11:50:46 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
a - > c = mt9v022 - > rect ;
a - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
return 0 ;
}
static int mt9v022_cropcap ( struct v4l2_subdev * sd , struct v4l2_cropcap * a )
{
a - > bounds . left = MT9V022_COLUMN_SKIP ;
a - > bounds . top = MT9V022_ROW_SKIP ;
a - > bounds . width = MT9V022_MAX_WIDTH ;
a - > bounds . height = MT9V022_MAX_HEIGHT ;
a - > defrect = a - > bounds ;
a - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
a - > pixelaspect . numerator = 1 ;
a - > pixelaspect . denominator = 1 ;
return 0 ;
}
2009-12-11 11:46:49 -03:00
static int mt9v022_g_fmt ( struct v4l2_subdev * sd ,
struct v4l2_mbus_framefmt * mf )
2009-08-25 11:50:46 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-08-25 11:50:46 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2009-12-11 11:46:49 -03:00
mf - > width = mt9v022 - > rect . width ;
mf - > height = mt9v022 - > rect . height ;
mf - > code = mt9v022 - > fmt - > code ;
mf - > colorspace = mt9v022 - > fmt - > colorspace ;
mf - > field = V4L2_FIELD_NONE ;
2008-04-22 14:42:04 -03:00
return 0 ;
}
2009-12-11 11:46:49 -03:00
static int mt9v022_s_fmt ( struct v4l2_subdev * sd ,
struct v4l2_mbus_framefmt * mf )
2009-03-13 06:08:20 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-08-25 11:43:33 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2009-08-25 11:46:54 -03:00
struct v4l2_crop a = {
. c = {
2009-08-25 11:50:46 -03:00
. left = mt9v022 - > rect . left ,
. top = mt9v022 - > rect . top ,
2009-12-11 11:46:49 -03:00
. width = mf - > width ,
. height = mf - > height ,
2009-08-25 11:46:54 -03:00
} ,
2009-03-13 06:08:20 -03:00
} ;
2009-08-25 11:50:46 -03:00
int ret ;
2009-03-13 06:08:20 -03:00
2009-12-11 11:15:05 -03:00
/*
* The caller provides a supported format , as verified per call to
2011-09-21 15:16:30 -03:00
* . try_mbus_fmt ( ) , datawidth is from our supported format list
2009-12-11 11:15:05 -03:00
*/
2009-12-11 11:46:49 -03:00
switch ( mf - > code ) {
2010-09-28 07:01:44 -03:00
case V4L2_MBUS_FMT_Y8_1X8 :
2009-12-11 11:46:49 -03:00
case V4L2_MBUS_FMT_Y10_1X10 :
2013-05-29 06:59:50 -03:00
if ( mt9v022 - > model ! = MT9V022IX7ATM )
2009-03-13 06:08:20 -03:00
return - EINVAL ;
break ;
2009-12-11 11:46:49 -03:00
case V4L2_MBUS_FMT_SBGGR8_1X8 :
case V4L2_MBUS_FMT_SBGGR10_1X10 :
2013-05-29 06:59:50 -03:00
if ( mt9v022 - > model ! = MT9V022IX7ATC )
2009-03-13 06:08:20 -03:00
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
/* No support for scaling on this camera, just crop. */
2009-08-25 11:50:46 -03:00
ret = mt9v022_s_crop ( sd , & a ) ;
if ( ! ret ) {
2009-12-11 11:46:49 -03:00
mf - > width = mt9v022 - > rect . width ;
mf - > height = mt9v022 - > rect . height ;
mt9v022 - > fmt = mt9v022_find_datafmt ( mf - > code ,
mt9v022 - > fmts , mt9v022 - > num_fmts ) ;
mf - > colorspace = mt9v022 - > fmt - > colorspace ;
2009-08-25 11:50:46 -03:00
}
return ret ;
2009-03-13 06:08:20 -03:00
}
2009-12-11 11:46:49 -03:00
static int mt9v022_try_fmt ( struct v4l2_subdev * sd ,
struct v4l2_mbus_framefmt * mf )
2008-04-22 14:42:04 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-12-11 11:14:46 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2009-12-11 11:46:49 -03:00
const struct mt9v022_datafmt * fmt ;
int align = mf - > code = = V4L2_MBUS_FMT_SBGGR8_1X8 | |
mf - > code = = V4L2_MBUS_FMT_SBGGR10_1X10 ;
2008-12-18 11:51:55 -03:00
2009-12-11 11:46:49 -03:00
v4l_bound_align_image ( & mf - > width , MT9V022_MIN_WIDTH ,
2009-08-25 11:50:46 -03:00
MT9V022_MAX_WIDTH , align ,
2009-12-11 11:46:49 -03:00
& mf - > height , MT9V022_MIN_HEIGHT + mt9v022 - > y_skip_top ,
2009-12-11 11:14:46 -03:00
MT9V022_MAX_HEIGHT + mt9v022 - > y_skip_top , align , 0 ) ;
2008-04-22 14:42:04 -03:00
2009-12-11 11:46:49 -03:00
fmt = mt9v022_find_datafmt ( mf - > code , mt9v022 - > fmts ,
mt9v022 - > num_fmts ) ;
if ( ! fmt ) {
fmt = mt9v022 - > fmt ;
mf - > code = fmt - > code ;
}
mf - > colorspace = fmt - > colorspace ;
2008-04-22 14:42:04 -03:00
return 0 ;
}
# ifdef CONFIG_VIDEO_ADV_DEBUG
2009-08-25 11:43:33 -03:00
static int mt9v022_g_register ( struct v4l2_subdev * sd ,
struct v4l2_dbg_register * reg )
2008-04-22 14:42:04 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-04-22 14:42:04 -03:00
2013-05-29 06:59:50 -03:00
if ( reg - > reg > 0xff )
2008-04-22 14:42:04 -03:00
return - EINVAL ;
2008-12-30 07:14:19 -03:00
reg - > size = 2 ;
2009-04-24 12:57:01 -03:00
reg - > val = reg_read ( client , reg - > reg ) ;
2008-04-22 14:42:04 -03:00
if ( reg - > val > 0xffff )
return - EIO ;
return 0 ;
}
2009-08-25 11:43:33 -03:00
static int mt9v022_s_register ( struct v4l2_subdev * sd ,
2013-03-24 08:28:46 -03:00
const struct v4l2_dbg_register * reg )
2008-04-22 14:42:04 -03:00
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-04-22 14:42:04 -03:00
2013-05-29 06:59:50 -03:00
if ( reg - > reg > 0xff )
2008-04-22 14:42:04 -03:00
return - EINVAL ;
2009-04-24 12:57:01 -03:00
if ( reg_write ( client , reg - > reg , reg - > val ) < 0 )
2008-04-22 14:42:04 -03:00
return - EIO ;
return 0 ;
}
# endif
2012-07-20 10:19:50 -03:00
static int mt9v022_s_power ( struct v4l2_subdev * sd , int on )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2012-12-21 08:11:48 -03:00
struct soc_camera_subdev_desc * ssdd = soc_camera_i2c_to_desc ( client ) ;
2012-12-21 13:01:55 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2012-07-20 10:19:50 -03:00
2012-12-21 13:01:55 -03:00
return soc_camera_set_power ( & client - > dev , ssdd , mt9v022 - > clk , on ) ;
2012-07-20 10:19:50 -03:00
}
2011-09-07 05:22:39 -03:00
static int mt9v022_g_volatile_ctrl ( struct v4l2_ctrl * ctrl )
2008-04-22 14:42:04 -03:00
{
2011-09-07 05:22:39 -03:00
struct mt9v022 * mt9v022 = container_of ( ctrl - > handler ,
struct mt9v022 , hdl ) ;
struct v4l2_subdev * sd = & mt9v022 - > subdev ;
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2011-09-07 05:22:39 -03:00
struct v4l2_ctrl * gain = mt9v022 - > gain ;
struct v4l2_ctrl * exp = mt9v022 - > exposure ;
2009-08-25 11:53:23 -03:00
unsigned long range ;
2008-04-22 14:42:04 -03:00
int data ;
switch ( ctrl - > id ) {
case V4L2_CID_AUTOGAIN :
2009-08-25 11:53:23 -03:00
data = reg_read ( client , MT9V022_ANALOG_GAIN ) ;
if ( data < 0 )
return - EIO ;
2011-09-07 05:22:39 -03:00
range = gain - > maximum - gain - > minimum ;
gain - > val = ( ( data - 16 ) * range + 24 ) / 48 + gain - > minimum ;
return 0 ;
case V4L2_CID_EXPOSURE_AUTO :
2009-08-25 11:53:23 -03:00
data = reg_read ( client , MT9V022_TOTAL_SHUTTER_WIDTH ) ;
if ( data < 0 )
return - EIO ;
2011-09-07 05:22:39 -03:00
range = exp - > maximum - exp - > minimum ;
exp - > val = ( ( data - 1 ) * range + 239 ) / 479 + exp - > minimum ;
return 0 ;
2012-09-27 19:03:45 -03:00
case V4L2_CID_HBLANK :
data = reg_read ( client , MT9V022_HORIZONTAL_BLANKING ) ;
if ( data < 0 )
return - EIO ;
ctrl - > val = data ;
return 0 ;
case V4L2_CID_VBLANK :
data = reg_read ( client , MT9V022_VERTICAL_BLANKING ) ;
if ( data < 0 )
return - EIO ;
ctrl - > val = data ;
return 0 ;
2008-04-22 14:42:04 -03:00
}
2011-09-07 05:22:39 -03:00
return - EINVAL ;
2008-04-22 14:42:04 -03:00
}
2011-09-07 05:22:39 -03:00
static int mt9v022_s_ctrl ( struct v4l2_ctrl * ctrl )
2008-04-22 14:42:04 -03:00
{
2011-09-07 05:22:39 -03:00
struct mt9v022 * mt9v022 = container_of ( ctrl - > handler ,
struct mt9v022 , hdl ) ;
struct v4l2_subdev * sd = & mt9v022 - > subdev ;
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2011-09-07 05:22:39 -03:00
int data ;
2008-04-22 14:42:04 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_VFLIP :
2011-09-07 05:22:39 -03:00
if ( ctrl - > val )
2009-04-24 12:57:01 -03:00
data = reg_set ( client , MT9V022_READ_MODE , 0x10 ) ;
2008-04-22 14:42:04 -03:00
else
2009-04-24 12:57:01 -03:00
data = reg_clear ( client , MT9V022_READ_MODE , 0x10 ) ;
2008-04-22 14:42:04 -03:00
if ( data < 0 )
return - EIO ;
2011-09-07 05:22:39 -03:00
return 0 ;
2008-04-22 14:42:04 -03:00
case V4L2_CID_HFLIP :
2011-09-07 05:22:39 -03:00
if ( ctrl - > val )
2009-04-24 12:57:01 -03:00
data = reg_set ( client , MT9V022_READ_MODE , 0x20 ) ;
2008-04-22 14:42:04 -03:00
else
2009-04-24 12:57:01 -03:00
data = reg_clear ( client , MT9V022_READ_MODE , 0x20 ) ;
2008-04-22 14:42:04 -03:00
if ( data < 0 )
return - EIO ;
2011-09-07 05:22:39 -03:00
return 0 ;
case V4L2_CID_AUTOGAIN :
if ( ctrl - > val ) {
if ( reg_set ( client , MT9V022_AEC_AGC_ENABLE , 0x2 ) < 0 )
return - EIO ;
} else {
struct v4l2_ctrl * gain = mt9v022 - > gain ;
/* mt9v022 has minimum == default */
unsigned long range = gain - > maximum - gain - > minimum ;
2009-08-25 11:53:23 -03:00
/* Valid values 16 to 64, 32 to 64 must be even. */
2011-09-07 05:22:39 -03:00
unsigned long gain_val = ( ( gain - > val - gain - > minimum ) *
2009-08-25 11:53:23 -03:00
48 + range / 2 ) / range + 16 ;
2011-09-07 05:22:39 -03:00
if ( gain_val > = 32 )
gain_val & = ~ 1 ;
2009-12-11 11:15:05 -03:00
/*
* The user wants to set gain manually , hope , she
* knows , what she ' s doing . . . Switch AGC off .
*/
2009-04-24 12:57:01 -03:00
if ( reg_clear ( client , MT9V022_AEC_AGC_ENABLE , 0x2 ) < 0 )
2008-04-22 14:42:04 -03:00
return - EIO ;
2009-08-25 11:53:23 -03:00
dev_dbg ( & client - > dev , " Setting gain from %d to %lu \n " ,
2011-09-07 05:22:39 -03:00
reg_read ( client , MT9V022_ANALOG_GAIN ) , gain_val ) ;
if ( reg_write ( client , MT9V022_ANALOG_GAIN , gain_val ) < 0 )
2008-04-22 14:42:04 -03:00
return - EIO ;
}
2011-09-07 05:22:39 -03:00
return 0 ;
case V4L2_CID_EXPOSURE_AUTO :
if ( ctrl - > val = = V4L2_EXPOSURE_AUTO ) {
data = reg_set ( client , MT9V022_AEC_AGC_ENABLE , 0x1 ) ;
} else {
struct v4l2_ctrl * exp = mt9v022 - > exposure ;
unsigned long range = exp - > maximum - exp - > minimum ;
unsigned long shutter = ( ( exp - > val - exp - > minimum ) *
479 + range / 2 ) / range + 1 ;
2009-12-11 11:15:05 -03:00
/*
* The user wants to set shutter width manually , hope ,
* she knows , what she ' s doing . . . Switch AEC off .
*/
2011-09-07 05:22:39 -03:00
data = reg_clear ( client , MT9V022_AEC_AGC_ENABLE , 0x1 ) ;
if ( data < 0 )
2008-04-22 14:42:04 -03:00
return - EIO ;
2009-08-25 11:47:00 -03:00
dev_dbg ( & client - > dev , " Shutter width from %d to %lu \n " ,
2011-09-07 05:22:39 -03:00
reg_read ( client , MT9V022_TOTAL_SHUTTER_WIDTH ) ,
shutter ) ;
2009-04-24 12:57:01 -03:00
if ( reg_write ( client , MT9V022_TOTAL_SHUTTER_WIDTH ,
2011-09-07 05:22:39 -03:00
shutter ) < 0 )
2008-04-22 14:42:04 -03:00
return - EIO ;
}
2011-09-07 05:22:39 -03:00
return 0 ;
2012-09-27 19:03:45 -03:00
case V4L2_CID_HBLANK :
if ( reg_write ( client , MT9V022_HORIZONTAL_BLANKING ,
ctrl - > val ) < 0 )
return - EIO ;
return 0 ;
case V4L2_CID_VBLANK :
if ( reg_write ( client , MT9V022_VERTICAL_BLANKING ,
ctrl - > val ) < 0 )
return - EIO ;
return 0 ;
2008-04-22 14:42:04 -03:00
}
2011-09-07 05:22:39 -03:00
return - EINVAL ;
2008-04-22 14:42:04 -03:00
}
2009-12-11 11:15:05 -03: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
*/
2011-09-21 15:16:30 -03:00
static int mt9v022_video_probe ( struct i2c_client * client )
2008-04-22 14:42:04 -03:00
{
2009-08-25 11:43:33 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2012-12-21 08:11:48 -03:00
struct soc_camera_subdev_desc * ssdd = soc_camera_i2c_to_desc ( client ) ;
2008-04-22 14:42:04 -03:00
s32 data ;
int ret ;
2009-03-13 06:08:20 -03:00
unsigned long flags ;
2008-04-22 14:42:04 -03:00
2012-07-18 10:54:04 -03:00
ret = mt9v022_s_power ( & mt9v022 - > subdev , 1 ) ;
if ( ret < 0 )
return ret ;
2008-04-22 14:42:04 -03:00
/* Read out the chip version register */
2009-04-24 12:57:01 -03:00
data = reg_read ( client , MT9V022_CHIP_VERSION ) ;
2008-04-22 14:42:04 -03:00
2012-08-02 12:32:41 -03:00
/* must be 0x1311, 0x1313 or 0x1324 */
if ( data ! = 0x1311 & & data ! = 0x1313 & & data ! = 0x1324 ) {
2008-04-22 14:42:04 -03:00
ret = - ENODEV ;
2009-08-25 11:47:00 -03:00
dev_info ( & client - > dev , " No MT9V022 found, ID register 0x%x \n " ,
2008-04-22 14:42:04 -03:00
data ) ;
goto ei2c ;
}
2012-09-27 19:52:42 -03:00
mt9v022 - > chip_version = data ;
2012-08-02 12:32:41 -03:00
mt9v022 - > reg = is_mt9v024 ( data ) ? & mt9v024_register :
& mt9v022_register ;
2008-04-22 14:42:04 -03:00
/* Soft reset */
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_RESET , 1 ) ;
2008-04-22 14:42:04 -03:00
if ( ret < 0 )
goto ei2c ;
/* 15 clock cycles */
udelay ( 200 ) ;
2009-04-24 12:57:01 -03:00
if ( reg_read ( client , MT9V022_RESET ) ) {
2009-08-25 11:47:00 -03:00
dev_err ( & client - > dev , " Resetting MT9V022 failed! \n " ) ;
2009-08-25 11:28:22 -03:00
if ( ret > 0 )
ret = - EIO ;
2008-04-22 14:42:04 -03:00
goto ei2c ;
}
/* Set monochrome or colour sensor type */
if ( sensor_type & & ( ! strcmp ( " colour " , sensor_type ) | |
! strcmp ( " color " , sensor_type ) ) ) {
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_PIXEL_OPERATION_MODE , 4 | 0x11 ) ;
2013-05-29 06:59:50 -03:00
mt9v022 - > model = MT9V022IX7ATC ;
2009-12-11 11:46:49 -03:00
mt9v022 - > fmts = mt9v022_colour_fmts ;
2008-04-22 14:42:04 -03:00
} else {
2009-04-24 12:57:01 -03:00
ret = reg_write ( client , MT9V022_PIXEL_OPERATION_MODE , 0x11 ) ;
2013-05-29 06:59:50 -03:00
mt9v022 - > model = MT9V022IX7ATM ;
2009-12-11 11:46:49 -03:00
mt9v022 - > fmts = mt9v022_monochrome_fmts ;
2008-04-22 14:42:04 -03:00
}
2009-03-13 06:08:20 -03:00
if ( ret < 0 )
2009-08-25 11:28:22 -03:00
goto ei2c ;
2009-03-13 06:08:20 -03:00
2009-12-11 11:46:49 -03:00
mt9v022 - > num_fmts = 0 ;
2009-03-13 06:08:20 -03:00
/*
* This is a 10 bit sensor , so by default we only allow 10 bit .
* The platform may support different bus widths due to
* different routing of the data lines .
*/
2012-12-21 08:11:48 -03:00
if ( ssdd - > query_bus_param )
flags = ssdd - > query_bus_param ( ssdd ) ;
2009-03-13 06:08:20 -03:00
else
flags = SOCAM_DATAWIDTH_10 ;
if ( flags & SOCAM_DATAWIDTH_10 )
2009-12-11 11:46:49 -03:00
mt9v022 - > num_fmts + + ;
2009-03-13 06:08:20 -03:00
else
2009-12-11 11:46:49 -03:00
mt9v022 - > fmts + + ;
2009-03-13 06:08:20 -03:00
if ( flags & SOCAM_DATAWIDTH_8 )
2009-12-11 11:46:49 -03:00
mt9v022 - > num_fmts + + ;
2009-03-13 06:08:20 -03:00
2009-12-11 11:46:49 -03:00
mt9v022 - > fmt = & mt9v022 - > fmts [ 0 ] ;
2009-08-25 11:50:46 -03:00
2009-08-25 11:47:00 -03:00
dev_info ( & client - > dev , " Detected a MT9V022 chip ID %x, %s sensor \n " ,
2013-05-29 06:59:50 -03:00
data , mt9v022 - > model = = MT9V022IX7ATM ?
2008-04-22 14:42:04 -03:00
" monochrome " : " colour " ) ;
2009-08-25 11:53:23 -03:00
ret = mt9v022_init ( client ) ;
if ( ret < 0 )
dev_err ( & client - > dev , " Failed to initialise the camera \n " ) ;
2008-04-22 14:42:04 -03:00
ei2c :
2012-07-18 10:54:04 -03:00
mt9v022_s_power ( & mt9v022 - > subdev , 0 ) ;
2008-04-22 14:42:04 -03:00
return ret ;
}
2009-12-11 11:14:46 -03:00
static int mt9v022_g_skip_top_lines ( struct v4l2_subdev * sd , u32 * lines )
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-12-11 11:14:46 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
* lines = mt9v022 - > y_skip_top ;
return 0 ;
}
2011-09-07 05:22:39 -03:00
static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
. g_volatile_ctrl = mt9v022_g_volatile_ctrl ,
. s_ctrl = mt9v022_s_ctrl ,
} ;
2009-08-25 11:43:33 -03:00
static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
# ifdef CONFIG_VIDEO_ADV_DEBUG
. g_register = mt9v022_g_register ,
. s_register = mt9v022_s_register ,
# endif
2012-07-20 10:19:50 -03:00
. s_power = mt9v022_s_power ,
2009-08-25 11:43:33 -03:00
} ;
2010-05-08 17:55:00 -03:00
static int mt9v022_enum_fmt ( struct v4l2_subdev * sd , unsigned int index ,
2009-12-11 11:46:49 -03:00
enum v4l2_mbus_pixelcode * code )
{
2010-07-30 17:24:54 -03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2009-12-11 11:46:49 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2010-05-08 17:55:00 -03:00
if ( index > = mt9v022 - > num_fmts )
2009-12-11 11:46:49 -03:00
return - EINVAL ;
* code = mt9v022 - > fmts [ index ] . code ;
return 0 ;
}
2011-07-27 05:53:33 -03:00
static int mt9v022_g_mbus_config ( struct v4l2_subdev * sd ,
struct v4l2_mbus_config * cfg )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2012-12-21 08:11:48 -03:00
struct soc_camera_subdev_desc * ssdd = soc_camera_i2c_to_desc ( client ) ;
2011-07-27 05:53:33 -03:00
cfg - > flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_DATA_ACTIVE_HIGH ;
cfg - > type = V4L2_MBUS_PARALLEL ;
2012-12-21 08:11:48 -03:00
cfg - > flags = soc_camera_apply_board_flags ( ssdd , cfg ) ;
2011-07-27 05:53:33 -03:00
return 0 ;
}
static int mt9v022_s_mbus_config ( struct v4l2_subdev * sd ,
const struct v4l2_mbus_config * cfg )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2012-12-21 08:11:48 -03:00
struct soc_camera_subdev_desc * ssdd = soc_camera_i2c_to_desc ( client ) ;
2011-07-27 05:53:33 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2012-12-21 08:11:48 -03:00
unsigned long flags = soc_camera_apply_board_flags ( ssdd , cfg ) ;
2011-09-09 07:06:50 -03:00
unsigned int bps = soc_mbus_get_fmtdesc ( mt9v022 - > fmt - > code ) - > bits_per_sample ;
2011-07-27 05:53:33 -03:00
int ret ;
u16 pixclk = 0 ;
2012-12-21 08:11:48 -03:00
if ( ssdd - > set_bus_param ) {
ret = ssdd - > set_bus_param ( ssdd , 1 < < ( bps - 1 ) ) ;
2011-07-27 05:53:33 -03:00
if ( ret )
return ret ;
} else if ( bps ! = 10 ) {
/*
* Without board specific bus width settings we only support the
* sensors native bus width
*/
return - EINVAL ;
}
if ( flags & V4L2_MBUS_PCLK_SAMPLE_FALLING )
pixclk | = 0x10 ;
if ( ! ( flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ) )
pixclk | = 0x1 ;
if ( ! ( flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ) )
pixclk | = 0x2 ;
2012-08-02 12:32:41 -03:00
ret = reg_write ( client , mt9v022 - > reg - > pixclk_fv_lv , pixclk ) ;
2011-07-27 05:53:33 -03:00
if ( ret < 0 )
return ret ;
if ( ! ( flags & V4L2_MBUS_MASTER ) )
mt9v022 - > chip_control & = ~ 0x8 ;
ret = reg_write ( client , MT9V022_CHIP_CONTROL , mt9v022 - > chip_control ) ;
if ( ret < 0 )
return ret ;
dev_dbg ( & client - > dev , " Calculated pixclk 0x%x, chip control 0x%x \n " ,
pixclk , mt9v022 - > chip_control ) ;
return 0 ;
}
2009-08-25 11:43:33 -03:00
static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
. s_stream = mt9v022_s_stream ,
2009-12-11 11:46:49 -03:00
. s_mbus_fmt = mt9v022_s_fmt ,
. g_mbus_fmt = mt9v022_g_fmt ,
. try_mbus_fmt = mt9v022_try_fmt ,
2009-08-25 11:46:54 -03:00
. s_crop = mt9v022_s_crop ,
2009-08-25 11:50:46 -03:00
. g_crop = mt9v022_g_crop ,
. cropcap = mt9v022_cropcap ,
2009-12-11 11:46:49 -03:00
. enum_mbus_fmt = mt9v022_enum_fmt ,
2011-07-27 05:53:33 -03:00
. g_mbus_config = mt9v022_g_mbus_config ,
. s_mbus_config = mt9v022_s_mbus_config ,
2009-08-25 11:43:33 -03:00
} ;
2009-12-11 11:14:46 -03:00
static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
. g_skip_top_lines = mt9v022_g_skip_top_lines ,
} ;
2009-08-25 11:43:33 -03:00
static struct v4l2_subdev_ops mt9v022_subdev_ops = {
. core = & mt9v022_subdev_core_ops ,
. video = & mt9v022_subdev_video_ops ,
2009-12-11 11:14:46 -03:00
. sensor = & mt9v022_subdev_sensor_ops ,
2009-08-25 11:43:33 -03:00
} ;
2008-04-29 23:11:39 +02:00
static int mt9v022_probe ( struct i2c_client * client ,
const struct i2c_device_id * did )
2008-04-22 14:42:04 -03:00
{
struct mt9v022 * mt9v022 ;
2012-12-21 08:11:48 -03:00
struct soc_camera_subdev_desc * ssdd = soc_camera_i2c_to_desc ( client ) ;
2008-04-22 14:42:04 -03:00
struct i2c_adapter * adapter = to_i2c_adapter ( client - > dev . parent ) ;
2012-11-28 23:56:15 -03:00
struct mt9v022_platform_data * pdata ;
2008-04-22 14:42:04 -03:00
int ret ;
2012-12-21 08:11:48 -03:00
if ( ! ssdd ) {
2008-04-22 14:42:04 -03:00
dev_err ( & client - > dev , " MT9V022 driver needs platform data \n " ) ;
return - EINVAL ;
}
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 10:28:43 -03:00
mt9v022 = devm_kzalloc ( & client - > dev , sizeof ( struct mt9v022 ) , GFP_KERNEL ) ;
2008-04-22 14:42:04 -03:00
if ( ! mt9v022 )
return - ENOMEM ;
2012-12-21 08:11:48 -03:00
pdata = ssdd - > drv_priv ;
2009-08-25 11:43:33 -03:00
v4l2_i2c_subdev_init ( & mt9v022 - > subdev , client , & mt9v022_subdev_ops ) ;
2011-09-07 05:22:39 -03:00
v4l2_ctrl_handler_init ( & mt9v022 - > hdl , 6 ) ;
v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_VFLIP , 0 , 1 , 1 , 0 ) ;
v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_HFLIP , 0 , 1 , 1 , 0 ) ;
mt9v022 - > autogain = v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_AUTOGAIN , 0 , 1 , 1 , 1 ) ;
mt9v022 - > gain = v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_GAIN , 0 , 127 , 1 , 64 ) ;
/*
* Simulated autoexposure . If enabled , we calculate shutter width
* ourselves in the driver based on vertical blanking and frame width
*/
mt9v022 - > autoexposure = v4l2_ctrl_new_std_menu ( & mt9v022 - > hdl ,
& mt9v022_ctrl_ops , V4L2_CID_EXPOSURE_AUTO , 1 , 0 ,
V4L2_EXPOSURE_AUTO ) ;
mt9v022 - > exposure = v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_EXPOSURE , 1 , 255 , 1 , 255 ) ;
2012-09-27 19:03:45 -03:00
mt9v022 - > hblank = v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_HBLANK , MT9V022_HORIZONTAL_BLANKING_MIN ,
MT9V022_HORIZONTAL_BLANKING_MAX , 1 ,
MT9V022_HORIZONTAL_BLANKING_DEF ) ;
mt9v022 - > vblank = v4l2_ctrl_new_std ( & mt9v022 - > hdl , & mt9v022_ctrl_ops ,
V4L2_CID_VBLANK , MT9V022_VERTICAL_BLANKING_MIN ,
MT9V022_VERTICAL_BLANKING_MAX , 1 ,
MT9V022_VERTICAL_BLANKING_DEF ) ;
2011-09-07 05:22:39 -03:00
mt9v022 - > subdev . ctrl_handler = & mt9v022 - > hdl ;
if ( mt9v022 - > hdl . error ) {
int err = mt9v022 - > hdl . error ;
2012-09-27 19:03:45 -03:00
dev_err ( & client - > dev , " control initialisation err %d \n " , err ) ;
2011-09-07 05:22:39 -03:00
return err ;
}
v4l2_ctrl_auto_cluster ( 2 , & mt9v022 - > autoexposure ,
V4L2_EXPOSURE_MANUAL , true ) ;
v4l2_ctrl_auto_cluster ( 2 , & mt9v022 - > autogain , 0 , true ) ;
2009-08-25 11:43:33 -03:00
2008-04-22 14:42:04 -03:00
mt9v022 - > chip_control = MT9V022_CHIP_CONTROL_DEFAULT ;
2009-08-25 11:53:23 -03:00
/*
2012-09-27 19:05:27 -03:00
* On some platforms the first read out line is corrupted .
* Workaround it by skipping if indicated by platform data .
2009-08-25 11:53:23 -03:00
*/
2012-09-27 19:05:27 -03:00
mt9v022 - > y_skip_top = pdata ? pdata - > y_skip_top : 0 ;
2009-08-25 11:50:46 -03:00
mt9v022 - > rect . left = MT9V022_COLUMN_SKIP ;
mt9v022 - > rect . top = MT9V022_ROW_SKIP ;
mt9v022 - > rect . width = MT9V022_MAX_WIDTH ;
mt9v022 - > rect . height = MT9V022_MAX_HEIGHT ;
2012-12-21 13:01:55 -03:00
mt9v022 - > clk = v4l2_clk_get ( & client - > dev , " mclk " ) ;
if ( IS_ERR ( mt9v022 - > clk ) ) {
ret = PTR_ERR ( mt9v022 - > clk ) ;
goto eclkget ;
}
2011-09-21 15:16:30 -03:00
ret = mt9v022_video_probe ( client ) ;
2012-12-21 13:01:55 -03:00
if ( ret ) {
v4l2_clk_put ( mt9v022 - > clk ) ;
eclkget :
2011-09-07 05:22:39 -03:00
v4l2_ctrl_handler_free ( & mt9v022 - > hdl ) ;
2012-12-21 13:01:55 -03:00
}
2008-04-22 14:42:04 -03:00
return ret ;
}
static int mt9v022_remove ( struct i2c_client * client )
{
2009-08-25 11:43:33 -03:00
struct mt9v022 * mt9v022 = to_mt9v022 ( client ) ;
2012-12-21 08:11:48 -03:00
struct soc_camera_subdev_desc * ssdd = soc_camera_i2c_to_desc ( client ) ;
2008-04-22 14:42:04 -03:00
2012-12-21 13:01:55 -03:00
v4l2_clk_put ( mt9v022 - > clk ) ;
2011-09-07 05:22:39 -03:00
v4l2_device_unregister_subdev ( & mt9v022 - > subdev ) ;
2012-12-21 08:11:48 -03:00
if ( ssdd - > free_bus )
ssdd - > free_bus ( ssdd ) ;
2011-09-07 05:22:39 -03:00
v4l2_ctrl_handler_free ( & mt9v022 - > hdl ) ;
2008-04-22 14:42:04 -03:00
return 0 ;
}
2008-04-29 23:11:40 +02:00
static const struct i2c_device_id mt9v022_id [ ] = {
{ " mt9v022 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , mt9v022_id ) ;
2008-04-22 14:42:04 -03:00
static struct i2c_driver mt9v022_i2c_driver = {
. driver = {
. name = " mt9v022 " ,
} ,
. probe = mt9v022_probe ,
. remove = mt9v022_remove ,
2008-04-29 23:11:40 +02:00
. id_table = mt9v022_id ,
2008-04-22 14:42:04 -03:00
} ;
2012-02-12 06:56:32 -03:00
module_i2c_driver ( mt9v022_i2c_driver ) ;
2008-04-22 14:42:04 -03:00
MODULE_DESCRIPTION ( " Micron MT9V022 Camera driver " ) ;
MODULE_AUTHOR ( " Guennadi Liakhovetski <kernel@pengutronix.de> " ) ;
MODULE_LICENSE ( " GPL " ) ;