2008-10-01 04:51:53 -03:00
/*
* Driver for the s5k4aa sensor
*
2008-10-16 16:43:16 -03:00
* Copyright ( C ) 2008 Erik Andrén
2008-10-01 04:51:53 -03:00
* Copyright ( C ) 2007 Ilyes Gouta . Based on the m5603x Linux Driver Project .
* Copyright ( C ) 2005 m5603x Linux Driver Project < m5602 @ x3ng . com . br >
*
* Portions of code to USB interface and ALi driver software ,
* Copyright ( c ) 2006 Willem Duinker
* v4l2 interface modeled after the V4L2 driver
* for SN9C10x PC Camera Controllers
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation , version 2.
*
*/
# include "m5602_s5k4aa.h"
2009-04-03 02:49:10 -03:00
static int s5k4aa_get_exposure ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int s5k4aa_set_exposure ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int s5k4aa_get_vflip ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int s5k4aa_set_vflip ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int s5k4aa_get_hflip ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int s5k4aa_set_hflip ( struct gspca_dev * gspca_dev , __s32 val ) ;
static int s5k4aa_get_gain ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int s5k4aa_set_gain ( struct gspca_dev * gspca_dev , __s32 val ) ;
2009-01-13 16:40:28 -03:00
static int s5k4aa_get_noise ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int s5k4aa_set_noise ( struct gspca_dev * gspca_dev , __s32 val ) ;
2009-01-14 03:37:03 -03:00
static int s5k4aa_get_brightness ( struct gspca_dev * gspca_dev , __s32 * val ) ;
static int s5k4aa_set_brightness ( struct gspca_dev * gspca_dev , __s32 val ) ;
2009-04-03 02:49:10 -03:00
2008-11-18 14:38:10 -03:00
static
const
struct dmi_system_id s5k4aa_vflip_dmi_table [ ] = {
{
. ident = " Fujitsu-Siemens Amilo Xa 2528 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " AMILO Xa 2528 " )
}
} , {
. ident = " Fujitsu-Siemens Amilo Xi 2550 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " FUJITSU SIEMENS " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " AMILO Xi 2550 " )
}
} , {
. ident = " MSI GX700 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Micro-Star International " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " GX700 " ) ,
DMI_MATCH ( DMI_BIOS_DATE , " 07/26/2007 " )
}
} , {
. ident = " MSI GX700/GX705/EX700 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Micro-Star International " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " GX700/GX705/EX700 " )
}
2009-02-12 16:36:05 -03:00
} , {
. ident = " MSI L735 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Micro-Star International " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " MS-1717X " )
}
2008-11-18 14:38:10 -03:00
} ,
{ }
} ;
2008-12-30 16:48:42 -03:00
static struct v4l2_pix_format s5k4aa_modes [ ] = {
{
640 ,
480 ,
V4L2_PIX_FMT_SBGGR8 ,
V4L2_FIELD_NONE ,
. sizeimage =
640 * 480 ,
. bytesperline = 640 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 0
2009-02-12 03:32:52 -03:00
} ,
{
1280 ,
1024 ,
V4L2_PIX_FMT_SBGGR8 ,
V4L2_FIELD_NONE ,
. sizeimage =
1280 * 1024 ,
. bytesperline = 1280 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 0
2008-12-30 16:48:42 -03:00
}
} ;
2009-04-26 09:30:18 -03:00
static const struct ctrl s5k4aa_ctrls [ ] = {
2009-01-06 11:37:03 -03:00
# define VFLIP_IDX 0
2008-12-30 17:06:55 -03:00
{
{
. id = V4L2_CID_VFLIP ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " vertical flip " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
. default_value = 0
} ,
. set = s5k4aa_set_vflip ,
. get = s5k4aa_get_vflip
2009-01-06 11:37:03 -03:00
} ,
# define HFLIP_IDX 1
{
2008-12-30 17:06:55 -03:00
{
. id = V4L2_CID_HFLIP ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " horizontal flip " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
. default_value = 0
} ,
. set = s5k4aa_set_hflip ,
. get = s5k4aa_get_hflip
2009-01-06 11:37:03 -03:00
} ,
# define GAIN_IDX 2
{
2008-12-30 17:06:55 -03:00
{
. id = V4L2_CID_GAIN ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Gain " ,
. minimum = 0 ,
. maximum = 127 ,
. step = 1 ,
2009-01-14 03:37:03 -03:00
. default_value = S5K4AA_DEFAULT_GAIN ,
2008-12-30 17:06:55 -03:00
. flags = V4L2_CTRL_FLAG_SLIDER
} ,
. set = s5k4aa_set_gain ,
. get = s5k4aa_get_gain
2009-01-06 11:37:03 -03:00
} ,
# define EXPOSURE_IDX 3
{
2008-12-30 17:06:55 -03:00
{
. id = V4L2_CID_EXPOSURE ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Exposure " ,
. minimum = 13 ,
. maximum = 0xfff ,
. step = 1 ,
. default_value = 0x100 ,
. flags = V4L2_CTRL_FLAG_SLIDER
} ,
. set = s5k4aa_set_exposure ,
. get = s5k4aa_get_exposure
2009-01-13 16:40:28 -03:00
} ,
# define NOISE_SUPP_IDX 4
{
{
. id = V4L2_CID_PRIVATE_BASE ,
. type = V4L2_CTRL_TYPE_BOOLEAN ,
. name = " Noise suppression (smoothing) " ,
. minimum = 0 ,
. maximum = 1 ,
. step = 1 ,
. default_value = 1 ,
} ,
. set = s5k4aa_set_noise ,
. get = s5k4aa_get_noise
} ,
2009-01-14 03:37:03 -03:00
# define BRIGHTNESS_IDX 5
{
{
. id = V4L2_CID_BRIGHTNESS ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Brightness " ,
. minimum = 0 ,
. maximum = 0x1f ,
. step = 1 ,
. default_value = S5K4AA_DEFAULT_BRIGHTNESS ,
} ,
. set = s5k4aa_set_brightness ,
. get = s5k4aa_get_brightness
} ,
2008-12-30 17:06:55 -03:00
} ;
2008-11-24 14:21:29 -03:00
static void s5k4aa_dump_registers ( struct sd * sd ) ;
2008-11-18 14:38:10 -03:00
2008-10-01 04:51:53 -03:00
int s5k4aa_probe ( struct sd * sd )
{
u8 prod_id [ 6 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
const u8 expected_prod_id [ 6 ] = { 0x00 , 0x10 , 0x00 , 0x4b , 0x33 , 0x75 } ;
int i , err = 0 ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings ;
2008-10-01 04:51:53 -03:00
if ( force_sensor ) {
if ( force_sensor = = S5K4AA_SENSOR ) {
info ( " Forcing a %s sensor " , s5k4aa . name ) ;
goto sensor_found ;
}
/* If we want to force another sensor, don't try to probe this
* one */
return - ENODEV ;
}
info ( " Probing for a s5k4aa sensor " ) ;
/* Preinit the sensor */
for ( i = 0 ; i < ARRAY_SIZE ( preinit_s5k4aa ) & & ! err ; i + + ) {
u8 data [ 2 ] = { 0x00 , 0x00 } ;
switch ( preinit_s5k4aa [ i ] [ 0 ] ) {
case BRIDGE :
err = m5602_write_bridge ( sd ,
preinit_s5k4aa [ i ] [ 1 ] ,
preinit_s5k4aa [ i ] [ 2 ] ) ;
break ;
case SENSOR :
data [ 0 ] = preinit_s5k4aa [ i ] [ 2 ] ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd ,
2008-10-01 04:51:53 -03:00
preinit_s5k4aa [ i ] [ 1 ] ,
data , 1 ) ;
break ;
case SENSOR_LONG :
data [ 0 ] = preinit_s5k4aa [ i ] [ 2 ] ;
data [ 1 ] = preinit_s5k4aa [ i ] [ 3 ] ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd ,
2008-10-01 04:51:53 -03:00
preinit_s5k4aa [ i ] [ 1 ] ,
data , 2 ) ;
break ;
default :
info ( " Invalid stream command, exiting init " ) ;
return - EINVAL ;
}
}
/* Test some registers, but we don't know their exact meaning yet */
2009-02-22 17:54:11 -03:00
if ( m5602_read_sensor ( sd , 0x00 , prod_id , 2 ) )
return - ENODEV ;
if ( m5602_read_sensor ( sd , 0x02 , prod_id + 2 , 2 ) )
return - ENODEV ;
if ( m5602_read_sensor ( sd , 0x04 , prod_id + 4 , 2 ) )
2008-10-01 04:51:53 -03:00
return - ENODEV ;
if ( memcmp ( prod_id , expected_prod_id , sizeof ( prod_id ) ) )
return - ENODEV ;
else
info ( " Detected a s5k4aa sensor " ) ;
2008-11-20 04:02:44 -03:00
2008-10-01 04:51:53 -03:00
sensor_found :
2009-01-06 11:37:03 -03:00
sensor_settings = kmalloc (
ARRAY_SIZE ( s5k4aa_ctrls ) * sizeof ( s32 ) , GFP_KERNEL ) ;
if ( ! sensor_settings )
return - ENOMEM ;
2008-12-30 16:48:42 -03:00
sd - > gspca_dev . cam . cam_mode = s5k4aa_modes ;
sd - > gspca_dev . cam . nmodes = ARRAY_SIZE ( s5k4aa_modes ) ;
2008-12-30 17:06:55 -03:00
sd - > desc - > ctrls = s5k4aa_ctrls ;
2008-12-30 15:27:17 -03:00
sd - > desc - > nctrls = ARRAY_SIZE ( s5k4aa_ctrls ) ;
2009-01-06 11:37:03 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( s5k4aa_ctrls ) ; i + + )
sensor_settings [ i ] = s5k4aa_ctrls [ i ] . qctrl . default_value ;
sd - > sensor_priv = sensor_settings ;
2009-01-09 03:30:54 -03:00
2008-10-01 04:51:53 -03:00
return 0 ;
}
2008-12-26 12:57:42 -03:00
int s5k4aa_start ( struct sd * sd )
{
int i , err = 0 ;
u8 data [ 2 ] ;
struct cam * cam = & sd - > gspca_dev . cam ;
2009-02-12 03:40:29 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-12-26 12:57:42 -03:00
2009-01-09 03:30:54 -03:00
switch ( cam - > cam_mode [ sd - > gspca_dev . curr_mode ] . width ) {
2009-01-29 13:34:41 -03:00
case 1280 :
PDEBUG ( D_V4L2 , " Configuring camera for SXGA mode " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( SXGA_s5k4aa ) ; i + + ) {
switch ( SXGA_s5k4aa [ i ] [ 0 ] ) {
case BRIDGE :
err = m5602_write_bridge ( sd ,
SXGA_s5k4aa [ i ] [ 1 ] ,
SXGA_s5k4aa [ i ] [ 2 ] ) ;
break ;
case SENSOR :
data [ 0 ] = SXGA_s5k4aa [ i ] [ 2 ] ;
err = m5602_write_sensor ( sd ,
SXGA_s5k4aa [ i ] [ 1 ] ,
data , 1 ) ;
break ;
case SENSOR_LONG :
data [ 0 ] = SXGA_s5k4aa [ i ] [ 2 ] ;
data [ 1 ] = SXGA_s5k4aa [ i ] [ 3 ] ;
err = m5602_write_sensor ( sd ,
SXGA_s5k4aa [ i ] [ 1 ] ,
data , 2 ) ;
break ;
default :
err ( " Invalid stream command, exiting init " ) ;
return - EINVAL ;
}
}
2009-02-12 03:32:52 -03:00
err = s5k4aa_set_noise ( & sd - > gspca_dev , 0 ) ;
if ( err < 0 )
return err ;
break ;
2009-01-29 13:34:41 -03:00
2008-12-26 12:57:42 -03:00
case 640 :
PDEBUG ( D_V4L2 , " Configuring camera for VGA mode " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( VGA_s5k4aa ) ; i + + ) {
switch ( VGA_s5k4aa [ i ] [ 0 ] ) {
case BRIDGE :
err = m5602_write_bridge ( sd ,
VGA_s5k4aa [ i ] [ 1 ] ,
VGA_s5k4aa [ i ] [ 2 ] ) ;
break ;
case SENSOR :
data [ 0 ] = VGA_s5k4aa [ i ] [ 2 ] ;
err = m5602_write_sensor ( sd ,
VGA_s5k4aa [ i ] [ 1 ] ,
data , 1 ) ;
break ;
case SENSOR_LONG :
data [ 0 ] = VGA_s5k4aa [ i ] [ 2 ] ;
data [ 1 ] = VGA_s5k4aa [ i ] [ 3 ] ;
err = m5602_write_sensor ( sd ,
VGA_s5k4aa [ i ] [ 1 ] ,
data , 2 ) ;
break ;
default :
err ( " Invalid stream command, exiting init " ) ;
return - EINVAL ;
}
}
2009-02-12 03:32:52 -03:00
err = s5k4aa_set_noise ( & sd - > gspca_dev , 1 ) ;
if ( err < 0 )
return err ;
break ;
2008-12-26 12:57:42 -03:00
}
2009-02-12 03:40:29 -03:00
if ( err < 0 )
return err ;
err = s5k4aa_set_exposure ( & sd - > gspca_dev ,
sensor_settings [ EXPOSURE_IDX ] ) ;
if ( err < 0 )
return err ;
err = s5k4aa_set_gain ( & sd - > gspca_dev , sensor_settings [ GAIN_IDX ] ) ;
if ( err < 0 )
return err ;
err = s5k4aa_set_brightness ( & sd - > gspca_dev ,
sensor_settings [ BRIGHTNESS_IDX ] ) ;
if ( err < 0 )
return err ;
err = s5k4aa_set_noise ( & sd - > gspca_dev , sensor_settings [ NOISE_SUPP_IDX ] ) ;
if ( err < 0 )
return err ;
err = s5k4aa_set_vflip ( & sd - > gspca_dev , sensor_settings [ VFLIP_IDX ] ) ;
if ( err < 0 )
return err ;
return s5k4aa_set_hflip ( & sd - > gspca_dev , sensor_settings [ HFLIP_IDX ] ) ;
2008-12-26 12:57:42 -03:00
}
2008-10-01 04:51:53 -03:00
int s5k4aa_init ( struct sd * sd )
{
int i , err = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( init_s5k4aa ) & & ! err ; i + + ) {
u8 data [ 2 ] = { 0x00 , 0x00 } ;
switch ( init_s5k4aa [ i ] [ 0 ] ) {
case BRIDGE :
err = m5602_write_bridge ( sd ,
init_s5k4aa [ i ] [ 1 ] ,
init_s5k4aa [ i ] [ 2 ] ) ;
break ;
case SENSOR :
data [ 0 ] = init_s5k4aa [ i ] [ 2 ] ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd ,
2008-10-01 04:51:53 -03:00
init_s5k4aa [ i ] [ 1 ] , data , 1 ) ;
break ;
case SENSOR_LONG :
data [ 0 ] = init_s5k4aa [ i ] [ 2 ] ;
data [ 1 ] = init_s5k4aa [ i ] [ 3 ] ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd ,
2008-10-01 04:51:53 -03:00
init_s5k4aa [ i ] [ 1 ] , data , 2 ) ;
break ;
default :
info ( " Invalid stream command, exiting init " ) ;
return - EINVAL ;
}
}
2009-01-09 13:35:00 -03:00
if ( dump_sensor )
s5k4aa_dump_registers ( sd ) ;
2009-02-12 03:40:29 -03:00
return err ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_get_exposure ( struct gspca_dev * gspca_dev , __s32 * val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
2009-01-06 11:37:03 -03:00
* val = sensor_settings [ EXPOSURE_IDX ] ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Read exposure %d " , * val ) ;
2008-12-27 12:28:00 -03:00
2009-01-06 11:37:03 -03:00
return 0 ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_set_exposure ( struct gspca_dev * gspca_dev , __s32 val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
u8 data = S5K4AA_PAGE_MAP_2 ;
int err ;
2009-01-06 11:37:03 -03:00
sensor_settings [ EXPOSURE_IDX ] = val ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Set exposure to %d " , val ) ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-10-01 04:51:53 -03:00
data = ( val > > 8 ) & 0xff ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_EXPOSURE_HI , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-10-01 04:51:53 -03:00
data = val & 0xff ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_EXPOSURE_LO , & data , 1 ) ;
2008-12-27 12:28:00 -03:00
2008-11-20 04:02:44 -03:00
return err ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_get_vflip ( struct gspca_dev * gspca_dev , __s32 * val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
2009-01-06 11:37:03 -03:00
* val = sensor_settings [ VFLIP_IDX ] ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Read vertical flip %d " , * val ) ;
2008-10-01 04:51:53 -03:00
2009-01-06 11:37:03 -03:00
return 0 ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_set_vflip ( struct gspca_dev * gspca_dev , __s32 val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
u8 data = S5K4AA_PAGE_MAP_2 ;
int err ;
2009-01-06 11:37:03 -03:00
sensor_settings [ VFLIP_IDX ] = val ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Set vertical flip to %d " , val ) ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_READ_MODE , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2009-01-06 11:37:03 -03:00
2009-01-13 15:44:03 -03:00
err = m5602_read_sensor ( sd , S5K4AA_READ_MODE , & data , 1 ) ;
if ( err < 0 )
return err ;
2009-02-12 03:40:29 -03:00
if ( dmi_check_system ( s5k4aa_vflip_dmi_table ) )
2009-01-06 11:37:03 -03:00
val = ! val ;
2009-02-12 03:40:29 -03:00
data = ( ( data & ~ S5K4AA_RM_V_FLIP ) | ( ( val & 0x01 ) < < 7 ) ) ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_READ_MODE , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-10-01 04:51:53 -03:00
2009-02-12 03:40:29 -03:00
err = m5602_read_sensor ( sd , S5K4AA_ROWSTART_LO , & data , 1 ) ;
if ( err < 0 )
return err ;
data = ( data & 0xfe ) | ! val ;
err = m5602_write_sensor ( sd , S5K4AA_ROWSTART_LO , & data , 1 ) ;
2008-11-20 04:02:44 -03:00
return err ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_get_hflip ( struct gspca_dev * gspca_dev , __s32 * val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
2009-01-06 11:37:03 -03:00
* val = sensor_settings [ HFLIP_IDX ] ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Read horizontal flip %d " , * val ) ;
2008-12-27 12:28:00 -03:00
2009-01-06 11:37:03 -03:00
return 0 ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_set_hflip ( struct gspca_dev * gspca_dev , __s32 val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
u8 data = S5K4AA_PAGE_MAP_2 ;
int err ;
2009-01-06 11:37:03 -03:00
sensor_settings [ HFLIP_IDX ] = val ;
PDEBUG ( D_V4L2 , " Set horizontal flip to %d " , val ) ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_READ_MODE , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-10-01 04:51:53 -03:00
2009-01-13 15:44:03 -03:00
err = m5602_read_sensor ( sd , S5K4AA_READ_MODE , & data , 1 ) ;
if ( err < 0 )
return err ;
2009-02-12 03:40:29 -03:00
if ( dmi_check_system ( s5k4aa_vflip_dmi_table ) )
2009-01-22 03:51:40 -03:00
val = ! val ;
2008-10-01 04:51:53 -03:00
data = ( ( data & ~ S5K4AA_RM_H_FLIP ) | ( ( val & 0x01 ) < < 6 ) ) ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_READ_MODE , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-10-01 04:51:53 -03:00
2009-02-12 03:40:29 -03:00
err = m5602_read_sensor ( sd , S5K4AA_COLSTART_LO , & data , 1 ) ;
if ( err < 0 )
return err ;
data = ( data & 0xfe ) | ! val ;
err = m5602_write_sensor ( sd , S5K4AA_COLSTART_LO , & data , 1 ) ;
2008-11-20 04:02:44 -03:00
return err ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_get_gain ( struct gspca_dev * gspca_dev , __s32 * val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
2009-01-06 11:37:03 -03:00
* val = sensor_settings [ GAIN_IDX ] ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Read gain %d " , * val ) ;
2009-01-06 11:37:03 -03:00
return 0 ;
2008-10-01 04:51:53 -03:00
}
2009-04-03 02:49:10 -03:00
static int s5k4aa_set_gain ( struct gspca_dev * gspca_dev , __s32 val )
2008-10-01 04:51:53 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2009-01-06 11:37:03 -03:00
s32 * sensor_settings = sd - > sensor_priv ;
2008-10-01 04:51:53 -03:00
u8 data = S5K4AA_PAGE_MAP_2 ;
int err ;
2009-01-06 11:37:03 -03:00
sensor_settings [ GAIN_IDX ] = val ;
2008-10-16 16:46:07 -03:00
PDEBUG ( D_V4L2 , " Set gain to %d " , val ) ;
2008-11-26 04:08:10 -03:00
err = m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( err < 0 )
2008-12-27 12:28:00 -03:00
return err ;
2008-10-01 04:51:53 -03:00
data = val & 0xff ;
2009-01-14 03:37:03 -03:00
err = m5602_write_sensor ( sd , S5K4AA_GAIN , & data , 1 ) ;
2008-10-01 04:51:53 -03:00
2008-11-20 04:02:44 -03:00
return err ;
2008-10-01 04:51:53 -03:00
}
2009-01-14 03:37:03 -03:00
static int s5k4aa_get_brightness ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
s32 * sensor_settings = sd - > sensor_priv ;
* val = sensor_settings [ BRIGHTNESS_IDX ] ;
PDEBUG ( D_V4L2 , " Read brightness %d " , * val ) ;
return 0 ;
}
static int s5k4aa_set_brightness ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
s32 * sensor_settings = sd - > sensor_priv ;
u8 data = S5K4AA_PAGE_MAP_2 ;
int err ;
sensor_settings [ BRIGHTNESS_IDX ] = val ;
PDEBUG ( D_V4L2 , " Set brightness to %d " , val ) ;
err = m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & data , 1 ) ;
if ( err < 0 )
return err ;
data = val & 0xff ;
return m5602_write_sensor ( sd , S5K4AA_BRIGHTNESS , & data , 1 ) ;
}
2009-01-13 16:40:28 -03:00
static int s5k4aa_get_noise ( struct gspca_dev * gspca_dev , __s32 * val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
s32 * sensor_settings = sd - > sensor_priv ;
* val = sensor_settings [ NOISE_SUPP_IDX ] ;
PDEBUG ( D_V4L2 , " Read noise %d " , * val ) ;
return 0 ;
}
static int s5k4aa_set_noise ( struct gspca_dev * gspca_dev , __s32 val )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
s32 * sensor_settings = sd - > sensor_priv ;
u8 data = S5K4AA_PAGE_MAP_2 ;
int err ;
sensor_settings [ NOISE_SUPP_IDX ] = val ;
PDEBUG ( D_V4L2 , " Set noise to %d " , val ) ;
err = m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & data , 1 ) ;
if ( err < 0 )
return err ;
data = val & 0x01 ;
return m5602_write_sensor ( sd , S5K4AA_NOISE_SUPP , & data , 1 ) ;
}
2009-01-06 11:37:03 -03:00
void s5k4aa_disconnect ( struct sd * sd )
{
sd - > sensor = NULL ;
kfree ( sd - > sensor_priv ) ;
}
2008-11-24 14:21:29 -03:00
static void s5k4aa_dump_registers ( struct sd * sd )
2008-10-01 04:51:53 -03:00
{
int address ;
u8 page , old_page ;
2008-11-27 13:51:11 -03:00
m5602_read_sensor ( sd , S5K4AA_PAGE_MAP , & old_page , 1 ) ;
2008-10-01 04:51:53 -03:00
for ( page = 0 ; page < 16 ; page + + ) {
2008-11-26 04:08:10 -03:00
m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & page , 1 ) ;
2008-10-01 04:51:53 -03:00
info ( " Dumping the s5k4aa register state for page 0x%x " , page ) ;
for ( address = 0 ; address < = 0xff ; address + + ) {
u8 value = 0 ;
2008-11-27 13:51:11 -03:00
m5602_read_sensor ( sd , address , & value , 1 ) ;
2008-10-01 04:51:53 -03:00
info ( " register 0x%x contains 0x%x " ,
address , value ) ;
}
}
info ( " s5k4aa register state dump complete " ) ;
for ( page = 0 ; page < 16 ; page + + ) {
2008-11-26 04:08:10 -03:00
m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & page , 1 ) ;
2008-10-01 04:51:53 -03:00
info ( " Probing for which registers that are "
" read/write for page 0x%x " , page ) ;
for ( address = 0 ; address < = 0xff ; address + + ) {
u8 old_value , ctrl_value , test_value = 0xff ;
2008-11-27 13:51:11 -03:00
m5602_read_sensor ( sd , address , & old_value , 1 ) ;
2008-11-26 04:08:10 -03:00
m5602_write_sensor ( sd , address , & test_value , 1 ) ;
2008-11-27 13:51:11 -03:00
m5602_read_sensor ( sd , address , & ctrl_value , 1 ) ;
2008-10-01 04:51:53 -03:00
if ( ctrl_value = = test_value )
info ( " register 0x%x is writeable " , address ) ;
else
info ( " register 0x%x is read only " , address ) ;
/* Restore original value */
2008-11-26 04:08:10 -03:00
m5602_write_sensor ( sd , address , & old_value , 1 ) ;
2008-10-01 04:51:53 -03:00
}
}
info ( " Read/write register probing complete " ) ;
2008-11-26 04:08:10 -03:00
m5602_write_sensor ( sd , S5K4AA_PAGE_MAP , & old_page , 1 ) ;
2008-10-01 04:51:53 -03:00
}