2019-05-19 15:51:54 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-06-05 07:45:04 -03:00
/*
* SQ930x subdriver
*
* Copyright ( C ) 2010 Jean - François Moine < http : //moinejf.free.fr>
* Copyright ( C ) 2006 - 2008 Gerard Klaver < gerard at gkall dot hobby dot nl >
* Copyright ( C ) 2007 Sam Revitch < samr7 @ cs . washington . edu >
*/
2011-08-21 19:56:57 -03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2010-06-05 07:45:04 -03:00
# define MODULE_NAME "sq930x"
# include "gspca.h"
MODULE_AUTHOR ( " Jean-Francois Moine <http://moinejf.free.fr> \n "
" Gerard Klaver <gerard at gkall dot hobby dot nl \n "
" Sam Revitch <samr7@cs.washington.edu> " ) ;
MODULE_DESCRIPTION ( " GSPCA/SQ930x USB Camera Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
/* Structure to hold all of our device specific stuff */
struct sd {
struct gspca_dev gspca_dev ; /* !! must be the first item */
2012-05-16 08:29:16 -03:00
struct { /* exposure/gain control cluster */
struct v4l2_ctrl * exposure ;
struct v4l2_ctrl * gain ;
} ;
2010-06-05 07:45:04 -03:00
u8 do_ctrl ;
2010-07-26 07:23:00 -03:00
u8 gpio [ 2 ] ;
2010-06-05 07:45:04 -03:00
u8 sensor ;
2010-07-26 06:39:40 -03:00
u8 type ;
# define Generic 0
# define Creative_live_motion 1
} ;
enum sensors {
2010-06-05 07:45:04 -03:00
SENSOR_ICX098BQ ,
SENSOR_LZ24BP ,
2010-06-24 05:02:57 -03:00
SENSOR_MI0360 ,
2010-07-26 07:27:13 -03:00
SENSOR_MT9V111 , /* = MI360SOC */
2010-06-24 05:02:57 -03:00
SENSOR_OV7660 ,
SENSOR_OV9630 ,
2010-06-05 07:45:04 -03:00
} ;
static struct v4l2_pix_format vga_mode [ ] = {
2010-07-26 07:23:00 -03:00
{ 320 , 240 , V4L2_PIX_FMT_SRGGB8 , V4L2_FIELD_NONE ,
2010-06-05 07:45:04 -03:00
. bytesperline = 320 ,
2010-07-26 07:23:00 -03:00
. sizeimage = 320 * 240 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 0 } ,
{ 640 , 480 , V4L2_PIX_FMT_SRGGB8 , V4L2_FIELD_NONE ,
2010-06-05 07:45:04 -03:00
. bytesperline = 640 ,
2010-07-26 07:23:00 -03:00
. sizeimage = 640 * 480 ,
. colorspace = V4L2_COLORSPACE_SRGB ,
. priv = 1 } ,
2010-06-05 07:45:04 -03:00
} ;
/* sq930x registers */
# define SQ930_CTRL_UCBUS_IO 0x0001
# define SQ930_CTRL_I2C_IO 0x0002
# define SQ930_CTRL_GPIO 0x0005
# define SQ930_CTRL_CAP_START 0x0010
# define SQ930_CTRL_CAP_STOP 0x0011
# define SQ930_CTRL_SET_EXPOSURE 0x001d
# define SQ930_CTRL_RESET 0x001e
# define SQ930_CTRL_GET_DEV_INFO 0x001f
/* gpio 1 (8..15) */
# define SQ930_GPIO_DFL_I2C_SDA 0x0001
# define SQ930_GPIO_DFL_I2C_SCL 0x0002
# define SQ930_GPIO_RSTBAR 0x0004
# define SQ930_GPIO_EXTRA1 0x0040
# define SQ930_GPIO_EXTRA2 0x0080
/* gpio 3 (24..31) */
# define SQ930_GPIO_POWER 0x0200
# define SQ930_GPIO_DFL_LED 0x1000
struct ucbus_write_cmd {
u16 bw_addr ;
u8 bw_data ;
} ;
struct i2c_write_cmd {
u8 reg ;
u16 val ;
} ;
static const struct ucbus_write_cmd icx098bq_start_0 [ ] = {
{ 0x0354 , 0x00 } , { 0x03fa , 0x00 } , { 0xf800 , 0x02 } , { 0xf801 , 0xce } ,
{ 0xf802 , 0xc1 } , { 0xf804 , 0x00 } , { 0xf808 , 0x00 } , { 0xf809 , 0x0e } ,
{ 0xf80a , 0x01 } , { 0xf80b , 0xee } , { 0xf807 , 0x60 } , { 0xf80c , 0x02 } ,
{ 0xf80d , 0xf0 } , { 0xf80e , 0x03 } , { 0xf80f , 0x0a } , { 0xf81c , 0x02 } ,
{ 0xf81d , 0xf0 } , { 0xf81e , 0x03 } , { 0xf81f , 0x0a } , { 0xf83a , 0x00 } ,
{ 0xf83b , 0x10 } , { 0xf83c , 0x00 } , { 0xf83d , 0x4e } , { 0xf810 , 0x04 } ,
{ 0xf811 , 0x00 } , { 0xf812 , 0x02 } , { 0xf813 , 0x10 } , { 0xf803 , 0x00 } ,
{ 0xf814 , 0x01 } , { 0xf815 , 0x18 } , { 0xf816 , 0x00 } , { 0xf817 , 0x48 } ,
{ 0xf818 , 0x00 } , { 0xf819 , 0x25 } , { 0xf81a , 0x00 } , { 0xf81b , 0x3c } ,
{ 0xf82f , 0x03 } , { 0xf820 , 0xff } , { 0xf821 , 0x0d } , { 0xf822 , 0xff } ,
{ 0xf823 , 0x07 } , { 0xf824 , 0xff } , { 0xf825 , 0x03 } , { 0xf826 , 0xff } ,
{ 0xf827 , 0x06 } , { 0xf828 , 0xff } , { 0xf829 , 0x03 } , { 0xf82a , 0xff } ,
{ 0xf82b , 0x0c } , { 0xf82c , 0xfd } , { 0xf82d , 0x01 } , { 0xf82e , 0x00 } ,
{ 0xf830 , 0x00 } , { 0xf831 , 0x47 } , { 0xf832 , 0x00 } , { 0xf833 , 0x00 } ,
{ 0xf850 , 0x00 } , { 0xf851 , 0x00 } , { 0xf852 , 0x00 } , { 0xf853 , 0x24 } ,
{ 0xf854 , 0x00 } , { 0xf855 , 0x18 } , { 0xf856 , 0x00 } , { 0xf857 , 0x3c } ,
{ 0xf858 , 0x00 } , { 0xf859 , 0x0c } , { 0xf85a , 0x00 } , { 0xf85b , 0x30 } ,
{ 0xf85c , 0x00 } , { 0xf85d , 0x0c } , { 0xf85e , 0x00 } , { 0xf85f , 0x30 } ,
{ 0xf860 , 0x00 } , { 0xf861 , 0x48 } , { 0xf862 , 0x01 } , { 0xf863 , 0xdc } ,
{ 0xf864 , 0xff } , { 0xf865 , 0x98 } , { 0xf866 , 0xff } , { 0xf867 , 0xc0 } ,
{ 0xf868 , 0xff } , { 0xf869 , 0x70 } , { 0xf86c , 0xff } , { 0xf86d , 0x00 } ,
{ 0xf86a , 0xff } , { 0xf86b , 0x48 } , { 0xf86e , 0xff } , { 0xf86f , 0x00 } ,
{ 0xf870 , 0x01 } , { 0xf871 , 0xdb } , { 0xf872 , 0x01 } , { 0xf873 , 0xfa } ,
{ 0xf874 , 0x01 } , { 0xf875 , 0xdb } , { 0xf876 , 0x01 } , { 0xf877 , 0xfa } ,
{ 0xf878 , 0x0f } , { 0xf879 , 0x0f } , { 0xf87a , 0xff } , { 0xf87b , 0xff } ,
{ 0xf800 , 0x03 }
} ;
static const struct ucbus_write_cmd icx098bq_start_1 [ ] = {
{ 0xf5f0 , 0x00 } , { 0xf5f1 , 0xcd } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xc0 } ,
{ 0xf5f0 , 0x49 } , { 0xf5f1 , 0xcd } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xc0 } ,
{ 0xf5fa , 0x00 } , { 0xf5f6 , 0x00 } , { 0xf5f7 , 0x00 } , { 0xf5f8 , 0x00 } ,
{ 0xf5f9 , 0x00 }
} ;
static const struct ucbus_write_cmd icx098bq_start_2 [ ] = {
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0x82 } , { 0xf806 , 0x00 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 } ,
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0x40 } , { 0xf806 , 0x00 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 } ,
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0xcf } , { 0xf806 , 0xd0 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 } ,
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0x00 } , { 0xf806 , 0x00 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 }
} ;
static const struct ucbus_write_cmd lz24bp_start_0 [ ] = {
{ 0x0354 , 0x00 } , { 0x03fa , 0x00 } , { 0xf800 , 0x02 } , { 0xf801 , 0xbe } ,
{ 0xf802 , 0xc6 } , { 0xf804 , 0x00 } , { 0xf808 , 0x00 } , { 0xf809 , 0x06 } ,
{ 0xf80a , 0x01 } , { 0xf80b , 0xfe } , { 0xf807 , 0x84 } , { 0xf80c , 0x02 } ,
{ 0xf80d , 0xf7 } , { 0xf80e , 0x03 } , { 0xf80f , 0x0b } , { 0xf81c , 0x00 } ,
{ 0xf81d , 0x49 } , { 0xf81e , 0x03 } , { 0xf81f , 0x0b } , { 0xf83a , 0x00 } ,
{ 0xf83b , 0x01 } , { 0xf83c , 0x00 } , { 0xf83d , 0x6b } , { 0xf810 , 0x03 } ,
{ 0xf811 , 0x10 } , { 0xf812 , 0x02 } , { 0xf813 , 0x6f } , { 0xf803 , 0x00 } ,
{ 0xf814 , 0x00 } , { 0xf815 , 0x44 } , { 0xf816 , 0x00 } , { 0xf817 , 0x48 } ,
{ 0xf818 , 0x00 } , { 0xf819 , 0x25 } , { 0xf81a , 0x00 } , { 0xf81b , 0x3c } ,
{ 0xf82f , 0x03 } , { 0xf820 , 0xff } , { 0xf821 , 0x0d } , { 0xf822 , 0xff } ,
{ 0xf823 , 0x07 } , { 0xf824 , 0xfd } , { 0xf825 , 0x07 } , { 0xf826 , 0xf0 } ,
{ 0xf827 , 0x0c } , { 0xf828 , 0xff } , { 0xf829 , 0x03 } , { 0xf82a , 0xff } ,
{ 0xf82b , 0x0c } , { 0xf82c , 0xfc } , { 0xf82d , 0x01 } , { 0xf82e , 0x00 } ,
{ 0xf830 , 0x00 } , { 0xf831 , 0x47 } , { 0xf832 , 0x00 } , { 0xf833 , 0x00 } ,
{ 0xf850 , 0x00 } , { 0xf851 , 0x00 } , { 0xf852 , 0x00 } , { 0xf853 , 0x24 } ,
{ 0xf854 , 0x00 } , { 0xf855 , 0x0c } , { 0xf856 , 0x00 } , { 0xf857 , 0x30 } ,
{ 0xf858 , 0x00 } , { 0xf859 , 0x18 } , { 0xf85a , 0x00 } , { 0xf85b , 0x3c } ,
{ 0xf85c , 0x00 } , { 0xf85d , 0x18 } , { 0xf85e , 0x00 } , { 0xf85f , 0x3c } ,
{ 0xf860 , 0xff } , { 0xf861 , 0x37 } , { 0xf862 , 0xff } , { 0xf863 , 0x1d } ,
{ 0xf864 , 0xff } , { 0xf865 , 0x98 } , { 0xf866 , 0xff } , { 0xf867 , 0xc0 } ,
{ 0xf868 , 0x00 } , { 0xf869 , 0x37 } , { 0xf86c , 0x02 } , { 0xf86d , 0x1d } ,
{ 0xf86a , 0x00 } , { 0xf86b , 0x37 } , { 0xf86e , 0x02 } , { 0xf86f , 0x1d } ,
{ 0xf870 , 0x01 } , { 0xf871 , 0xc6 } , { 0xf872 , 0x02 } , { 0xf873 , 0x04 } ,
{ 0xf874 , 0x01 } , { 0xf875 , 0xc6 } , { 0xf876 , 0x02 } , { 0xf877 , 0x04 } ,
{ 0xf878 , 0x0f } , { 0xf879 , 0x0f } , { 0xf87a , 0xff } , { 0xf87b , 0xff } ,
{ 0xf800 , 0x03 }
} ;
static const struct ucbus_write_cmd lz24bp_start_1_gen [ ] = {
{ 0xf5f0 , 0x00 } , { 0xf5f1 , 0xff } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xb3 } ,
{ 0xf5f0 , 0x40 } , { 0xf5f1 , 0xff } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xb3 } ,
{ 0xf5fa , 0x00 } , { 0xf5f6 , 0x00 } , { 0xf5f7 , 0x00 } , { 0xf5f8 , 0x00 } ,
{ 0xf5f9 , 0x00 }
} ;
static const struct ucbus_write_cmd lz24bp_start_1_clm [ ] = {
{ 0xf5f0 , 0x00 } , { 0xf5f1 , 0xff } , { 0xf5f2 , 0x88 } , { 0xf5f3 , 0x88 } ,
{ 0xf5f4 , 0xc0 } ,
{ 0xf5f0 , 0x40 } , { 0xf5f1 , 0xff } , { 0xf5f2 , 0x88 } , { 0xf5f3 , 0x88 } ,
{ 0xf5f4 , 0xc0 } ,
{ 0xf5fa , 0x00 } , { 0xf5f6 , 0x00 } , { 0xf5f7 , 0x00 } , { 0xf5f8 , 0x00 } ,
{ 0xf5f9 , 0x00 }
} ;
static const struct ucbus_write_cmd lz24bp_start_2 [ ] = {
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0x80 } , { 0xf806 , 0x00 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 } ,
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0x4e } , { 0xf806 , 0x00 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 } ,
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0xc0 } , { 0xf806 , 0x48 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 } ,
{ 0xf800 , 0x02 } , { 0xf807 , 0xff } , { 0xf805 , 0x00 } , { 0xf806 , 0x00 } ,
{ 0xf807 , 0x7f } , { 0xf800 , 0x03 }
} ;
static const struct ucbus_write_cmd mi0360_start_0 [ ] = {
{ 0x0354 , 0x00 } , { 0x03fa , 0x00 } , { 0xf332 , 0xcc } , { 0xf333 , 0xcc } ,
{ 0xf334 , 0xcc } , { 0xf335 , 0xcc } , { 0xf33f , 0x00 }
} ;
static const struct i2c_write_cmd mi0360_init_23 [ ] = {
{ 0x30 , 0x0040 } , /* reserved - def 0x0005 */
{ 0x31 , 0x0000 } , /* reserved - def 0x002a */
{ 0x34 , 0x0100 } , /* reserved - def 0x0100 */
{ 0x3d , 0x068f } , /* reserved - def 0x068f */
} ;
static const struct i2c_write_cmd mi0360_init_24 [ ] = {
{ 0x03 , 0x01e5 } , /* window height */
{ 0x04 , 0x0285 } , /* window width */
} ;
static const struct i2c_write_cmd mi0360_init_25 [ ] = {
{ 0x35 , 0x0020 } , /* global gain */
{ 0x2b , 0x0020 } , /* green1 gain */
{ 0x2c , 0x002a } , /* blue gain */
{ 0x2d , 0x0028 } , /* red gain */
{ 0x2e , 0x0020 } , /* green2 gain */
} ;
static const struct ucbus_write_cmd mi0360_start_1 [ ] = {
{ 0xf5f0 , 0x11 } , { 0xf5f1 , 0x99 } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xa6 } ,
{ 0xf5f0 , 0x51 } , { 0xf5f1 , 0x99 } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xa6 } ,
{ 0xf5fa , 0x00 } , { 0xf5f6 , 0x00 } , { 0xf5f7 , 0x00 } , { 0xf5f8 , 0x00 } ,
{ 0xf5f9 , 0x00 }
} ;
static const struct i2c_write_cmd mi0360_start_2 [ ] = {
{ 0x62 , 0x041d } , /* reserved - def 0x0418 */
} ;
static const struct i2c_write_cmd mi0360_start_3 [ ] = {
{ 0x05 , 0x007b } , /* horiz blanking */
} ;
static const struct i2c_write_cmd mi0360_start_4 [ ] = {
{ 0x05 , 0x03f5 } , /* horiz blanking */
} ;
2010-06-24 05:02:57 -03:00
static const struct i2c_write_cmd mt9v111_init_0 [ ] = {
2010-07-06 05:14:57 -03:00
{ 0x01 , 0x0001 } , /* select IFP/SOC registers */
{ 0x06 , 0x300c } , /* operating mode control */
{ 0x08 , 0xcc00 } , /* output format control (RGB) */
2010-07-26 07:27:13 -03:00
{ 0x01 , 0x0004 } , /* select sensor core registers */
2010-06-24 05:02:57 -03:00
} ;
static const struct i2c_write_cmd mt9v111_init_1 [ ] = {
2010-07-06 05:14:57 -03:00
{ 0x03 , 0x01e5 } , /* window height */
{ 0x04 , 0x0285 } , /* window width */
2010-06-24 05:02:57 -03:00
} ;
static const struct i2c_write_cmd mt9v111_init_2 [ ] = {
{ 0x30 , 0x7800 } ,
{ 0x31 , 0x0000 } ,
2010-07-06 05:14:57 -03:00
{ 0x07 , 0x3002 } , /* output control */
{ 0x35 , 0x0020 } , /* global gain */
{ 0x2b , 0x0020 } , /* green1 gain */
{ 0x2c , 0x0020 } , /* blue gain */
{ 0x2d , 0x0020 } , /* red gain */
{ 0x2e , 0x0020 } , /* green2 gain */
2010-06-24 05:02:57 -03:00
} ;
static const struct ucbus_write_cmd mt9v111_start_1 [ ] = {
{ 0xf5f0 , 0x11 } , { 0xf5f1 , 0x96 } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xaa } ,
{ 0xf5f0 , 0x51 } , { 0xf5f1 , 0x96 } , { 0xf5f2 , 0x80 } , { 0xf5f3 , 0x80 } ,
{ 0xf5f4 , 0xaa } ,
{ 0xf5fa , 0x00 } , { 0xf5f6 , 0x0a } , { 0xf5f7 , 0x0a } , { 0xf5f8 , 0x0a } ,
{ 0xf5f9 , 0x0a }
} ;
static const struct i2c_write_cmd mt9v111_init_3 [ ] = {
{ 0x62 , 0x0405 } ,
} ;
static const struct i2c_write_cmd mt9v111_init_4 [ ] = {
2010-07-26 07:25:44 -03:00
/* {0x05, 0x00ce}, */
{ 0x05 , 0x005d } , /* horizontal blanking */
2010-06-24 05:02:57 -03:00
} ;
static const struct ucbus_write_cmd ov7660_start_0 [ ] = {
{ 0x0354 , 0x00 } , { 0x03fa , 0x00 } , { 0xf332 , 0x00 } , { 0xf333 , 0xc0 } ,
{ 0xf334 , 0x39 } , { 0xf335 , 0xe7 } , { 0xf33f , 0x03 }
} ;
static const struct ucbus_write_cmd ov9630_start_0 [ ] = {
{ 0x0354 , 0x00 } , { 0x03fa , 0x00 } , { 0xf332 , 0x00 } , { 0xf333 , 0x00 } ,
{ 0xf334 , 0x3e } , { 0xf335 , 0xf8 } , { 0xf33f , 0x03 }
} ;
2010-07-26 07:27:13 -03:00
/* start parameters indexed by [sensor][mode] */
2010-06-05 07:45:04 -03:00
static const struct cap_s {
u8 cc_sizeid ;
u8 cc_bytes [ 32 ] ;
2010-07-26 07:23:00 -03:00
} capconfig [ 4 ] [ 2 ] = {
2010-06-05 07:45:04 -03:00
[ SENSOR_ICX098BQ ] = {
2010-07-26 07:23:00 -03:00
{ 2 , /* Bayer 320x240 */
{ 0x05 , 0x1f , 0x20 , 0x0e , 0x00 , 0x9f , 0x02 , 0xee ,
0x01 , 0x01 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ 4 , /* Bayer 640x480 */
2010-06-05 07:45:04 -03:00
{ 0x01 , 0x1f , 0x20 , 0x0e , 0x00 , 0x9f , 0x02 , 0xee ,
0x01 , 0x02 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
2010-07-26 07:23:00 -03:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2010-06-05 07:45:04 -03:00
} ,
[ SENSOR_LZ24BP ] = {
2010-07-26 07:23:00 -03:00
{ 2 , /* Bayer 320x240 */
{ 0x05 , 0x22 , 0x20 , 0x0e , 0x00 , 0xa2 , 0x02 , 0xee ,
0x01 , 0x01 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ 4 , /* Bayer 640x480 */
2010-06-05 07:45:04 -03:00
{ 0x01 , 0x22 , 0x20 , 0x0e , 0x00 , 0xa2 , 0x02 , 0xee ,
0x01 , 0x02 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
2010-07-26 07:23:00 -03:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2010-06-05 07:45:04 -03:00
} ,
[ SENSOR_MI0360 ] = {
2010-07-26 07:23:00 -03:00
{ 2 , /* Bayer 320x240 */
{ 0x05 , 0x02 , 0x20 , 0x01 , 0x20 , 0x82 , 0x02 , 0xe1 ,
0x01 , 0x01 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ 4 , /* Bayer 640x480 */
2010-06-05 07:45:04 -03:00
{ 0x01 , 0x02 , 0x20 , 0x01 , 0x20 , 0x82 , 0x02 , 0xe1 ,
0x01 , 0x02 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
2010-07-26 07:23:00 -03:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2010-06-05 07:45:04 -03:00
} ,
2010-06-24 05:02:57 -03:00
[ SENSOR_MT9V111 ] = {
2010-07-26 07:23:00 -03:00
{ 2 , /* Bayer 320x240 */
{ 0x05 , 0x02 , 0x20 , 0x01 , 0x20 , 0x82 , 0x02 , 0xe1 ,
0x01 , 0x01 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
{ 4 , /* Bayer 640x480 */
{ 0x01 , 0x02 , 0x20 , 0x01 , 0x20 , 0x82 , 0x02 , 0xe1 ,
2010-06-24 05:02:57 -03:00
0x01 , 0x02 , 0x00 , 0x08 , 0x18 , 0x12 , 0x78 , 0xc8 ,
2010-07-26 07:23:00 -03:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } } ,
2010-06-24 05:02:57 -03:00
} ,
} ;
struct sensor_s {
const char * name ;
u8 i2c_addr ;
u8 i2c_dum ;
u8 gpio [ 5 ] ;
u8 cmd_len ;
const struct ucbus_write_cmd * cmd ;
} ;
static const struct sensor_s sensor_tb [ ] = {
[ SENSOR_ICX098BQ ] = {
" icx098bp " ,
0x00 , 0x00 ,
{ 0 ,
SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL ,
SQ930_GPIO_DFL_I2C_SDA ,
0 ,
SQ930_GPIO_RSTBAR
} ,
8 , icx098bq_start_0
} ,
[ SENSOR_LZ24BP ] = {
" lz24bp " ,
0x00 , 0x00 ,
{ 0 ,
SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL ,
SQ930_GPIO_DFL_I2C_SDA ,
0 ,
SQ930_GPIO_RSTBAR
} ,
8 , lz24bp_start_0
} ,
[ SENSOR_MI0360 ] = {
" mi0360 " ,
0x5d , 0x80 ,
{ SQ930_GPIO_RSTBAR ,
SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL ,
SQ930_GPIO_DFL_I2C_SDA ,
0 ,
0
} ,
7 , mi0360_start_0
} ,
[ SENSOR_MT9V111 ] = {
" mt9v111 " ,
0x5c , 0x7f ,
{ SQ930_GPIO_RSTBAR ,
SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL ,
SQ930_GPIO_DFL_I2C_SDA ,
0 ,
0
} ,
7 , mi0360_start_0
} ,
[ SENSOR_OV7660 ] = {
" ov7660 " ,
0x21 , 0x00 ,
{ 0 ,
SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL ,
SQ930_GPIO_DFL_I2C_SDA ,
0 ,
SQ930_GPIO_RSTBAR
} ,
7 , ov7660_start_0
} ,
[ SENSOR_OV9630 ] = {
" ov9630 " ,
0x30 , 0x00 ,
{ 0 ,
SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL ,
SQ930_GPIO_DFL_I2C_SDA ,
0 ,
SQ930_GPIO_RSTBAR
} ,
7 , ov9630_start_0
} ,
2010-06-05 07:45:04 -03:00
} ;
static void reg_r ( struct gspca_dev * gspca_dev ,
u16 value , int len )
{
2010-06-24 04:57:12 -03:00
int ret ;
if ( gspca_dev - > usb_err < 0 )
return ;
ret = usb_control_msg ( gspca_dev - > dev ,
2010-06-05 07:45:04 -03:00
usb_rcvctrlpipe ( gspca_dev - > dev , 0 ) ,
0x0c ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
value , 0 , gspca_dev - > usb_buf , len ,
500 ) ;
2010-06-24 04:57:12 -03:00
if ( ret < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " reg_r %04x failed %d \n " , value , ret ) ;
2010-06-24 04:57:12 -03:00
gspca_dev - > usb_err = ret ;
2019-08-16 03:38:13 -03:00
/*
* Make sure the buffer is zeroed to avoid uninitialized
* values .
*/
memset ( gspca_dev - > usb_buf , 0 , USB_BUF_SZ ) ;
2010-06-24 04:57:12 -03:00
}
2010-06-05 07:45:04 -03:00
}
static void reg_w ( struct gspca_dev * gspca_dev , u16 value , u16 index )
{
int ret ;
if ( gspca_dev - > usb_err < 0 )
return ;
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_USBO , " reg_w v: %04x i: %04x \n " , value , index ) ;
2010-06-05 07:45:04 -03:00
ret = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) ,
0x0c , /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
value , index , NULL , 0 ,
500 ) ;
msleep ( 30 ) ;
if ( ret < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " reg_w %04x %04x failed %d \n " , value , index , ret ) ;
2010-06-05 07:45:04 -03:00
gspca_dev - > usb_err = ret ;
}
}
static void reg_wb ( struct gspca_dev * gspca_dev , u16 value , u16 index ,
const u8 * data , int len )
{
int ret ;
if ( gspca_dev - > usb_err < 0 )
return ;
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_USBO , " reg_wb v: %04x i: %04x %02x...%02x \n " ,
value , index , * data , data [ len - 1 ] ) ;
2010-06-05 07:45:04 -03:00
memcpy ( gspca_dev - > usb_buf , data , len ) ;
ret = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) ,
0x0c , /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
value , index , gspca_dev - > usb_buf , len ,
1000 ) ;
msleep ( 30 ) ;
if ( ret < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " reg_wb %04x %04x failed %d \n " , value , index , ret ) ;
2010-06-05 07:45:04 -03:00
gspca_dev - > usb_err = ret ;
}
}
2010-06-24 05:02:57 -03:00
static void i2c_write ( struct sd * sd ,
2010-06-05 07:45:04 -03:00
const struct i2c_write_cmd * cmd ,
int ncmds )
{
2010-06-24 05:02:57 -03:00
struct gspca_dev * gspca_dev = & sd - > gspca_dev ;
const struct sensor_s * sensor ;
2010-06-05 07:45:04 -03:00
u16 val , idx ;
u8 * buf ;
int ret ;
if ( gspca_dev - > usb_err < 0 )
return ;
2010-06-24 05:02:57 -03:00
sensor = & sensor_tb [ sd - > sensor ] ;
val = ( sensor - > i2c_addr < < 8 ) | SQ930_CTRL_I2C_IO ;
2010-06-05 07:45:04 -03:00
idx = ( cmd - > val & 0xff00 ) | cmd - > reg ;
buf = gspca_dev - > usb_buf ;
2010-06-24 05:02:57 -03:00
* buf + + = sensor - > i2c_dum ;
2010-06-05 07:45:04 -03:00
* buf + + = cmd - > val ;
while ( - - ncmds > 0 ) {
cmd + + ;
* buf + + = cmd - > reg ;
* buf + + = cmd - > val > > 8 ;
2010-06-24 05:02:57 -03:00
* buf + + = sensor - > i2c_dum ;
2010-06-05 07:45:04 -03:00
* buf + + = cmd - > val ;
}
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_USBO , " i2c_w v: %04x i: %04x %02x...%02x \n " ,
val , idx , gspca_dev - > usb_buf [ 0 ] , buf [ - 1 ] ) ;
2010-06-05 07:45:04 -03:00
ret = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) ,
0x0c , /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
val , idx ,
gspca_dev - > usb_buf , buf - gspca_dev - > usb_buf ,
500 ) ;
if ( ret < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " i2c_write failed %d \n " , ret ) ;
2010-06-05 07:45:04 -03:00
gspca_dev - > usb_err = ret ;
}
}
static void ucbus_write ( struct gspca_dev * gspca_dev ,
const struct ucbus_write_cmd * cmd ,
int ncmds ,
int batchsize )
{
u8 * buf ;
u16 val , idx ;
int len , ret ;
if ( gspca_dev - > usb_err < 0 )
return ;
if ( ( batchsize - 1 ) * 3 > USB_BUF_SZ ) {
2017-09-22 14:33:35 -04:00
gspca_err ( gspca_dev , " Bug: usb_buf overflow \n " ) ;
2010-06-05 07:45:04 -03:00
gspca_dev - > usb_err = - ENOMEM ;
return ;
}
for ( ; ; ) {
len = ncmds ;
if ( len > batchsize )
len = batchsize ;
ncmds - = len ;
val = ( cmd - > bw_addr < < 8 ) | SQ930_CTRL_UCBUS_IO ;
idx = ( cmd - > bw_data < < 8 ) | ( cmd - > bw_addr > > 8 ) ;
buf = gspca_dev - > usb_buf ;
while ( - - len > 0 ) {
cmd + + ;
* buf + + = cmd - > bw_addr ;
* buf + + = cmd - > bw_addr > > 8 ;
* buf + + = cmd - > bw_data ;
}
if ( buf ! = gspca_dev - > usb_buf )
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_USBO , " ucbus v: %04x i: %04x %02x...%02x \n " ,
val , idx ,
gspca_dev - > usb_buf [ 0 ] , buf [ - 1 ] ) ;
2010-06-05 07:45:04 -03:00
else
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_USBO , " ucbus v: %04x i: %04x \n " ,
val , idx ) ;
2010-06-05 07:45:04 -03:00
ret = usb_control_msg ( gspca_dev - > dev ,
usb_sndctrlpipe ( gspca_dev - > dev , 0 ) ,
0x0c , /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
val , idx ,
gspca_dev - > usb_buf , buf - gspca_dev - > usb_buf ,
500 ) ;
if ( ret < 0 ) {
2011-08-21 19:56:57 -03:00
pr_err ( " ucbus_write failed %d \n " , ret ) ;
2010-06-05 07:45:04 -03:00
gspca_dev - > usb_err = ret ;
return ;
}
msleep ( 30 ) ;
if ( ncmds < = 0 )
break ;
cmd + + ;
}
}
static void gpio_set ( struct sd * sd , u16 val , u16 mask )
{
struct gspca_dev * gspca_dev = & sd - > gspca_dev ;
if ( mask & 0x00ff ) {
sd - > gpio [ 0 ] & = ~ mask ;
sd - > gpio [ 0 ] | = val ;
reg_w ( gspca_dev , 0x0100 | SQ930_CTRL_GPIO ,
~ sd - > gpio [ 0 ] < < 8 ) ;
}
mask > > = 8 ;
val > > = 8 ;
if ( mask ) {
sd - > gpio [ 1 ] & = ~ mask ;
sd - > gpio [ 1 ] | = val ;
reg_w ( gspca_dev , 0x0300 | SQ930_CTRL_GPIO ,
~ sd - > gpio [ 1 ] < < 8 ) ;
}
}
2010-06-24 05:02:57 -03:00
static void gpio_init ( struct sd * sd ,
const u8 * gpio )
{
gpio_set ( sd , * gpio + + , 0x000f ) ;
gpio_set ( sd , * gpio + + , 0x000f ) ;
gpio_set ( sd , * gpio + + , 0x000f ) ;
gpio_set ( sd , * gpio + + , 0x000f ) ;
gpio_set ( sd , * gpio , 0x000f ) ;
}
static void bridge_init ( struct sd * sd )
2010-06-05 07:45:04 -03:00
{
static const struct ucbus_write_cmd clkfreq_cmd = {
0xf031 , 0 /* SQ930_CLKFREQ_60MHZ */
} ;
ucbus_write ( & sd - > gspca_dev , & clkfreq_cmd , 1 , 1 ) ;
gpio_set ( sd , SQ930_GPIO_POWER , 0xff00 ) ;
2010-06-24 05:02:57 -03:00
}
static void cmos_probe ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int i ;
const struct sensor_s * sensor ;
static const u8 probe_order [ ] = {
/* SENSOR_LZ24BP, (tested as ccd) */
SENSOR_OV9630 ,
SENSOR_MI0360 ,
SENSOR_OV7660 ,
SENSOR_MT9V111 ,
} ;
for ( i = 0 ; i < ARRAY_SIZE ( probe_order ) ; i + + ) {
sensor = & sensor_tb [ probe_order [ i ] ] ;
ucbus_write ( & sd - > gspca_dev , sensor - > cmd , sensor - > cmd_len , 8 ) ;
gpio_init ( sd , sensor - > gpio ) ;
msleep ( 100 ) ;
reg_r ( gspca_dev , ( sensor - > i2c_addr < < 8 ) | 0x001c , 1 ) ;
msleep ( 100 ) ;
if ( gspca_dev - > usb_buf [ 0 ] ! = 0 )
break ;
}
2010-12-25 13:07:57 -03:00
if ( i > = ARRAY_SIZE ( probe_order ) ) {
2011-08-21 19:56:57 -03:00
pr_err ( " Unknown sensor \n " ) ;
2010-12-25 13:07:57 -03:00
gspca_dev - > usb_err = - EINVAL ;
return ;
}
sd - > sensor = probe_order [ i ] ;
2010-12-25 13:11:54 -03:00
switch ( sd - > sensor ) {
case SENSOR_OV7660 :
case SENSOR_OV9630 :
2011-08-21 19:56:57 -03:00
pr_err ( " Sensor %s not yet treated \n " ,
sensor_tb [ sd - > sensor ] . name ) ;
2010-12-25 13:11:54 -03:00
gspca_dev - > usb_err = - EINVAL ;
break ;
}
2010-06-24 05:02:57 -03:00
}
static void mt9v111_init ( struct gspca_dev * gspca_dev )
{
int i , nwait ;
static const u8 cmd_001b [ ] = {
0x00 , 0x3b , 0xf6 , 0x01 , 0x03 , 0x02 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00
} ;
static const u8 cmd_011b [ ] [ 7 ] = {
{ 0x10 , 0x01 , 0x66 , 0x08 , 0x00 , 0x00 , 0x00 } ,
{ 0x01 , 0x00 , 0x1a , 0x04 , 0x00 , 0x00 , 0x00 } ,
{ 0x20 , 0x00 , 0x10 , 0x04 , 0x00 , 0x00 , 0x00 } ,
{ 0x02 , 0x01 , 0xae , 0x01 , 0x00 , 0x00 , 0x00 } ,
} ;
reg_wb ( gspca_dev , 0x001b , 0x0000 , cmd_001b , sizeof cmd_001b ) ;
for ( i = 0 ; i < ARRAY_SIZE ( cmd_011b ) ; i + + ) {
reg_wb ( gspca_dev , 0x001b , 0x0000 , cmd_011b [ i ] ,
ARRAY_SIZE ( cmd_011b [ 0 ] ) ) ;
msleep ( 400 ) ;
nwait = 20 ;
for ( ; ; ) {
reg_r ( gspca_dev , 0x031b , 1 ) ;
if ( gspca_dev - > usb_buf [ 0 ] = = 0
| | gspca_dev - > usb_err ! = 0 )
break ;
if ( - - nwait < 0 ) {
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " mt9v111_init timeout \n " ) ;
2010-06-24 05:02:57 -03:00
gspca_dev - > usb_err = - ETIME ;
return ;
}
msleep ( 50 ) ;
}
}
}
static void global_init ( struct sd * sd , int first_time )
{
2010-06-05 07:45:04 -03:00
switch ( sd - > sensor ) {
case SENSOR_ICX098BQ :
if ( first_time )
ucbus_write ( & sd - > gspca_dev ,
icx098bq_start_0 ,
8 , 8 ) ;
2010-06-24 05:02:57 -03:00
gpio_init ( sd , sensor_tb [ sd - > sensor ] . gpio ) ;
2010-06-05 07:45:04 -03:00
break ;
case SENSOR_LZ24BP :
if ( sd - > type ! = Creative_live_motion )
gpio_set ( sd , SQ930_GPIO_EXTRA1 , 0x00ff ) ;
else
gpio_set ( sd , 0 , 0x00ff ) ;
msleep ( 50 ) ;
if ( first_time )
ucbus_write ( & sd - > gspca_dev ,
lz24bp_start_0 ,
8 , 8 ) ;
2010-06-24 05:02:57 -03:00
gpio_init ( sd , sensor_tb [ sd - > sensor ] . gpio ) ;
2010-06-05 07:45:04 -03:00
break ;
2010-06-24 05:02:57 -03:00
case SENSOR_MI0360 :
if ( first_time )
2010-06-05 07:45:04 -03:00
ucbus_write ( & sd - > gspca_dev ,
mi0360_start_0 ,
ARRAY_SIZE ( mi0360_start_0 ) ,
8 ) ;
2010-06-24 05:02:57 -03:00
gpio_init ( sd , sensor_tb [ sd - > sensor ] . gpio ) ;
2010-06-05 07:45:04 -03:00
gpio_set ( sd , SQ930_GPIO_EXTRA2 , SQ930_GPIO_EXTRA2 ) ;
break ;
2010-06-24 05:02:57 -03:00
default :
/* case SENSOR_MT9V111: */
if ( first_time )
mt9v111_init ( & sd - > gspca_dev ) ;
else
gpio_init ( sd , sensor_tb [ sd - > sensor ] . gpio ) ;
break ;
2010-06-05 07:45:04 -03:00
}
}
static void lz24bp_ppl ( struct sd * sd , u16 ppl )
{
struct ucbus_write_cmd cmds [ 2 ] = {
{ 0xf810 , ppl > > 8 } ,
{ 0xf811 , ppl }
} ;
ucbus_write ( & sd - > gspca_dev , cmds , ARRAY_SIZE ( cmds ) , 2 ) ;
}
2012-05-16 08:29:16 -03:00
static void setexposure ( struct gspca_dev * gspca_dev , s32 expo , s32 gain )
2010-06-05 07:45:04 -03:00
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int i , integclks , intstartclk , frameclks , min_frclk ;
2010-06-24 05:02:57 -03:00
const struct sensor_s * sensor ;
2010-06-05 07:45:04 -03:00
u16 cmd ;
u8 buf [ 15 ] ;
2012-05-16 08:29:16 -03:00
integclks = expo ;
2010-06-05 07:45:04 -03:00
i = 0 ;
cmd = SQ930_CTRL_SET_EXPOSURE ;
2010-06-24 05:02:57 -03:00
switch ( sd - > sensor ) {
case SENSOR_ICX098BQ : /* ccd */
case SENSOR_LZ24BP :
2010-06-05 07:45:04 -03:00
min_frclk = sd - > sensor = = SENSOR_ICX098BQ ? 0x210 : 0x26f ;
if ( integclks > = min_frclk ) {
intstartclk = 0 ;
frameclks = integclks ;
} else {
intstartclk = min_frclk - integclks ;
frameclks = min_frclk ;
}
buf [ i + + ] = intstartclk > > 8 ;
buf [ i + + ] = intstartclk ;
buf [ i + + ] = frameclks > > 8 ;
buf [ i + + ] = frameclks ;
2012-05-16 08:29:16 -03:00
buf [ i + + ] = gain ;
2010-06-24 05:02:57 -03:00
break ;
default : /* cmos */
/* case SENSOR_MI0360: */
/* case SENSOR_MT9V111: */
cmd | = 0x0100 ;
sensor = & sensor_tb [ sd - > sensor ] ;
buf [ i + + ] = sensor - > i2c_addr ; /* i2c_slave_addr */
buf [ i + + ] = 0x08 ; /* 2 * ni2c */
buf [ i + + ] = 0x09 ; /* reg = shutter width */
buf [ i + + ] = integclks > > 8 ; /* val H */
buf [ i + + ] = sensor - > i2c_dum ;
buf [ i + + ] = integclks ; /* val L */
buf [ i + + ] = 0x35 ; /* reg = global gain */
buf [ i + + ] = 0x00 ; /* val H */
buf [ i + + ] = sensor - > i2c_dum ;
2012-05-16 08:29:16 -03:00
buf [ i + + ] = 0x80 + gain / 2 ; /* val L */
2010-06-24 05:02:57 -03:00
buf [ i + + ] = 0x00 ;
buf [ i + + ] = 0x00 ;
buf [ i + + ] = 0x00 ;
buf [ i + + ] = 0x00 ;
buf [ i + + ] = 0x83 ;
break ;
2010-06-05 07:45:04 -03:00
}
reg_wb ( gspca_dev , cmd , 0 , buf , i ) ;
}
/* This function is called at probe time just before sd_init */
static int sd_config ( struct gspca_dev * gspca_dev ,
const struct usb_device_id * id )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
struct cam * cam = & gspca_dev - > cam ;
sd - > sensor = id - > driver_info > > 8 ;
sd - > type = id - > driver_info ;
cam - > cam_mode = vga_mode ;
cam - > nmodes = ARRAY_SIZE ( vga_mode ) ;
cam - > bulk = 1 ;
return 0 ;
}
/* this function is called at probe and resume time */
static int sd_init ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
sd - > gpio [ 0 ] = sd - > gpio [ 1 ] = 0xff ; /* force gpio rewrite */
2010-06-24 05:02:57 -03:00
/*fixme: is this needed for icx098bp and mi0360?
2010-06-05 07:45:04 -03:00
if ( sd - > sensor ! = SENSOR_LZ24BP )
reg_w ( gspca_dev , SQ930_CTRL_RESET , 0x0000 ) ;
2010-06-24 05:02:57 -03:00
*/
2010-06-05 07:45:04 -03:00
reg_r ( gspca_dev , SQ930_CTRL_GET_DEV_INFO , 8 ) ;
2010-12-25 13:07:57 -03:00
if ( gspca_dev - > usb_err < 0 )
return gspca_dev - > usb_err ;
2010-06-05 07:45:04 -03:00
/* it returns:
* 03 00 12 93 0 b f6 c9 00 live ! ultra
* 03 00 07 93 0 b f6 ca 00 live ! ultra for notebook
* 03 00 12 93 0 b fe c8 00 Trust WB - 3500 T
* 02 00 06 93 0 b fe c8 00 Joy - IT 318 S
* 03 00 12 93 0 b f6 cf 00 icam tracer - sensor icx098bq
* 02 00 12 93 0 b fe cf 00 ProQ Motion Webcam
*
* byte
* 0 : 02 = usb 1.0 ( 12 Mbit ) / 03 = usb2 .0 ( 480 Mbit )
* 1 : 00
* 2 : 06 / 07 / 12 = mode webcam ? firmware ? ?
* 3 : 93 chip = 930 b ( 930 b or 930 c )
* 4 : 0 b
2010-06-24 05:02:57 -03:00
* 5 : f6 = cdd ( icx098bq , lz24bp ) / fe or de = cmos ( i2c ) ( other sensors )
2010-06-05 07:45:04 -03:00
* 6 : c8 / c9 / ca / cf = mode webcam ? , sensor ? webcam ?
* 7 : 00
*/
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " info: %*ph \n " , 8 , gspca_dev - > usb_buf ) ;
2010-06-05 07:45:04 -03:00
2010-06-24 05:02:57 -03:00
bridge_init ( sd ) ;
if ( sd - > sensor = = SENSOR_MI0360 ) {
/* no sensor probe for icam tracer */
2010-12-25 13:19:59 -03:00
if ( gspca_dev - > usb_buf [ 5 ] = = 0xf6 ) /* if ccd */
2010-06-24 05:02:57 -03:00
sd - > sensor = SENSOR_ICX098BQ ;
2010-07-26 07:23:00 -03:00
else
2010-06-24 05:02:57 -03:00
cmos_probe ( gspca_dev ) ;
2010-06-05 07:45:04 -03:00
}
2010-12-25 13:07:57 -03:00
if ( gspca_dev - > usb_err > = 0 ) {
2017-09-22 15:20:33 -04:00
gspca_dbg ( gspca_dev , D_PROBE , " Sensor %s \n " ,
sensor_tb [ sd - > sensor ] . name ) ;
2010-12-25 13:07:57 -03:00
global_init ( sd , 1 ) ;
}
2010-06-05 07:45:04 -03:00
return gspca_dev - > usb_err ;
}
/* send the start/stop commands to the webcam */
static void send_start ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
const struct cap_s * cap ;
2010-07-26 07:23:00 -03:00
int mode ;
2010-06-05 07:45:04 -03:00
mode = gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . priv ;
cap = & capconfig [ sd - > sensor ] [ mode ] ;
2010-07-26 07:23:00 -03:00
reg_wb ( gspca_dev , 0x0900 | SQ930_CTRL_CAP_START ,
0x0a00 | cap - > cc_sizeid ,
2010-06-05 07:45:04 -03:00
cap - > cc_bytes , 32 ) ;
2010-07-26 07:27:13 -03:00
}
2010-06-05 07:45:04 -03:00
static void send_stop ( struct gspca_dev * gspca_dev )
{
reg_w ( gspca_dev , SQ930_CTRL_CAP_STOP , 0 ) ;
2010-07-26 07:27:13 -03:00
}
2010-06-05 07:45:04 -03:00
/* function called at start time before URB creation */
static int sd_isoc_init ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
gspca_dev - > cam . bulk_nurbs = 1 ; /* there must be one URB only */
sd - > do_ctrl = 0 ;
2013-08-30 17:54:23 -03:00
gspca_dev - > cam . bulk_size = gspca_dev - > pixfmt . width *
gspca_dev - > pixfmt . height + 8 ;
2010-06-05 07:45:04 -03:00
return 0 ;
}
/* start the capture */
static int sd_start ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int mode ;
2010-06-24 05:02:57 -03:00
bridge_init ( sd ) ;
2010-06-05 07:45:04 -03:00
global_init ( sd , 0 ) ;
msleep ( 100 ) ;
switch ( sd - > sensor ) {
case SENSOR_ICX098BQ :
ucbus_write ( gspca_dev , icx098bq_start_0 ,
ARRAY_SIZE ( icx098bq_start_0 ) ,
8 ) ;
ucbus_write ( gspca_dev , icx098bq_start_1 ,
ARRAY_SIZE ( icx098bq_start_1 ) ,
5 ) ;
ucbus_write ( gspca_dev , icx098bq_start_2 ,
ARRAY_SIZE ( icx098bq_start_2 ) ,
6 ) ;
msleep ( 50 ) ;
/* 1st start */
send_start ( gspca_dev ) ;
gpio_set ( sd , SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR , 0x00ff ) ;
msleep ( 70 ) ;
reg_w ( gspca_dev , SQ930_CTRL_CAP_STOP , 0x0000 ) ;
gpio_set ( sd , 0x7f , 0x00ff ) ;
/* 2nd start */
send_start ( gspca_dev ) ;
gpio_set ( sd , SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR , 0x00ff ) ;
goto out ;
case SENSOR_LZ24BP :
ucbus_write ( gspca_dev , lz24bp_start_0 ,
ARRAY_SIZE ( lz24bp_start_0 ) ,
8 ) ;
if ( sd - > type ! = Creative_live_motion )
ucbus_write ( gspca_dev , lz24bp_start_1_gen ,
ARRAY_SIZE ( lz24bp_start_1_gen ) ,
5 ) ;
else
ucbus_write ( gspca_dev , lz24bp_start_1_clm ,
ARRAY_SIZE ( lz24bp_start_1_clm ) ,
5 ) ;
ucbus_write ( gspca_dev , lz24bp_start_2 ,
ARRAY_SIZE ( lz24bp_start_2 ) ,
6 ) ;
mode = gspca_dev - > cam . cam_mode [ gspca_dev - > curr_mode ] . priv ;
2010-07-26 07:23:00 -03:00
lz24bp_ppl ( sd , mode = = 1 ? 0x0564 : 0x0310 ) ;
2010-06-05 07:45:04 -03:00
msleep ( 10 ) ;
break ;
2010-06-24 05:02:57 -03:00
case SENSOR_MI0360 :
2010-06-05 07:45:04 -03:00
ucbus_write ( gspca_dev , mi0360_start_0 ,
ARRAY_SIZE ( mi0360_start_0 ) ,
8 ) ;
2010-06-24 05:02:57 -03:00
i2c_write ( sd , mi0360_init_23 ,
2010-06-05 07:45:04 -03:00
ARRAY_SIZE ( mi0360_init_23 ) ) ;
2010-06-24 05:02:57 -03:00
i2c_write ( sd , mi0360_init_24 ,
2010-06-05 07:45:04 -03:00
ARRAY_SIZE ( mi0360_init_24 ) ) ;
2010-06-24 05:02:57 -03:00
i2c_write ( sd , mi0360_init_25 ,
2010-06-05 07:45:04 -03:00
ARRAY_SIZE ( mi0360_init_25 ) ) ;
ucbus_write ( gspca_dev , mi0360_start_1 ,
ARRAY_SIZE ( mi0360_start_1 ) ,
5 ) ;
2010-06-24 05:02:57 -03:00
i2c_write ( sd , mi0360_start_2 ,
2010-06-05 07:45:04 -03:00
ARRAY_SIZE ( mi0360_start_2 ) ) ;
2010-06-24 05:02:57 -03:00
i2c_write ( sd , mi0360_start_3 ,
2010-06-05 07:45:04 -03:00
ARRAY_SIZE ( mi0360_start_3 ) ) ;
/* 1st start */
send_start ( gspca_dev ) ;
msleep ( 60 ) ;
2010-07-26 07:27:13 -03:00
send_stop ( gspca_dev ) ;
2010-06-05 07:45:04 -03:00
2010-06-24 05:02:57 -03:00
i2c_write ( sd ,
2010-06-05 07:45:04 -03:00
mi0360_start_4 , ARRAY_SIZE ( mi0360_start_4 ) ) ;
break ;
2010-06-24 05:02:57 -03:00
default :
/* case SENSOR_MT9V111: */
ucbus_write ( gspca_dev , mi0360_start_0 ,
ARRAY_SIZE ( mi0360_start_0 ) ,
8 ) ;
i2c_write ( sd , mt9v111_init_0 ,
ARRAY_SIZE ( mt9v111_init_0 ) ) ;
i2c_write ( sd , mt9v111_init_1 ,
ARRAY_SIZE ( mt9v111_init_1 ) ) ;
i2c_write ( sd , mt9v111_init_2 ,
ARRAY_SIZE ( mt9v111_init_2 ) ) ;
ucbus_write ( gspca_dev , mt9v111_start_1 ,
ARRAY_SIZE ( mt9v111_start_1 ) ,
2010-07-26 06:50:31 -03:00
5 ) ;
2010-06-24 05:02:57 -03:00
i2c_write ( sd , mt9v111_init_3 ,
ARRAY_SIZE ( mt9v111_init_3 ) ) ;
i2c_write ( sd , mt9v111_init_4 ,
ARRAY_SIZE ( mt9v111_init_4 ) ) ;
break ;
2010-06-05 07:45:04 -03:00
}
send_start ( gspca_dev ) ;
out :
msleep ( 1000 ) ;
2010-06-24 05:02:57 -03:00
if ( sd - > sensor = = SENSOR_MT9V111 )
gpio_set ( sd , SQ930_GPIO_DFL_LED , SQ930_GPIO_DFL_LED ) ;
2010-06-05 07:45:04 -03:00
sd - > do_ctrl = 1 ; /* set the exposure */
return gspca_dev - > usb_err ;
}
static void sd_stopN ( struct gspca_dev * gspca_dev )
{
2010-06-24 05:02:57 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
if ( sd - > sensor = = SENSOR_MT9V111 )
gpio_set ( sd , 0 , SQ930_GPIO_DFL_LED ) ;
2010-06-05 07:45:04 -03:00
send_stop ( gspca_dev ) ;
}
/* function called when the application gets a new frame */
/* It sets the exposure if required and restart the bulk transfer. */
static void sd_dq_callback ( struct gspca_dev * gspca_dev )
{
struct sd * sd = ( struct sd * ) gspca_dev ;
int ret ;
if ( ! sd - > do_ctrl | | gspca_dev - > cam . bulk_nurbs ! = 0 )
return ;
sd - > do_ctrl = 0 ;
2012-05-16 08:29:16 -03:00
setexposure ( gspca_dev , v4l2_ctrl_g_ctrl ( sd - > exposure ) ,
v4l2_ctrl_g_ctrl ( sd - > gain ) ) ;
2010-06-05 07:45:04 -03:00
gspca_dev - > cam . bulk_nurbs = 1 ;
2018-06-20 07:00:52 -04:00
ret = usb_submit_urb ( gspca_dev - > urb [ 0 ] , GFP_KERNEL ) ;
2010-06-05 07:45:04 -03:00
if ( ret < 0 )
2011-08-21 19:56:57 -03:00
pr_err ( " sd_dq_callback() err %d \n " , ret ) ;
2010-06-05 07:45:04 -03:00
/* wait a little time, otherwise the webcam crashes */
msleep ( 100 ) ;
}
static void sd_pkt_scan ( struct gspca_dev * gspca_dev ,
u8 * data , /* isoc packet */
int len ) /* iso packet length */
{
struct sd * sd = ( struct sd * ) gspca_dev ;
2010-07-26 07:23:00 -03:00
if ( sd - > do_ctrl )
gspca_dev - > cam . bulk_nurbs = 0 ;
gspca_frame_add ( gspca_dev , FIRST_PACKET , NULL , 0 ) ;
gspca_frame_add ( gspca_dev , INTER_PACKET , data , len - 8 ) ;
gspca_frame_add ( gspca_dev , LAST_PACKET , NULL , 0 ) ;
2010-06-05 07:45:04 -03:00
}
2012-05-16 08:29:16 -03:00
static int sd_s_ctrl ( struct v4l2_ctrl * ctrl )
2010-06-05 07:45:04 -03:00
{
2012-05-16 08:29:16 -03:00
struct gspca_dev * gspca_dev =
container_of ( ctrl - > handler , struct gspca_dev , ctrl_handler ) ;
2010-06-05 07:45:04 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2012-05-16 08:29:16 -03:00
gspca_dev - > usb_err = 0 ;
2010-06-05 07:45:04 -03:00
2012-05-16 08:29:16 -03:00
if ( ! gspca_dev - > streaming )
return 0 ;
2010-06-05 07:45:04 -03:00
2012-05-16 08:29:16 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_EXPOSURE :
setexposure ( gspca_dev , ctrl - > val , sd - > gain - > val ) ;
break ;
}
return gspca_dev - > usb_err ;
2010-06-05 07:45:04 -03:00
}
2012-05-16 08:29:16 -03:00
static const struct v4l2_ctrl_ops sd_ctrl_ops = {
. s_ctrl = sd_s_ctrl ,
} ;
2010-06-05 07:45:04 -03:00
2012-05-16 08:29:16 -03:00
static int sd_init_controls ( struct gspca_dev * gspca_dev )
2010-06-05 07:45:04 -03:00
{
2012-05-16 08:29:16 -03:00
struct v4l2_ctrl_handler * hdl = & gspca_dev - > ctrl_handler ;
2010-06-05 07:45:04 -03:00
struct sd * sd = ( struct sd * ) gspca_dev ;
2012-05-16 08:29:16 -03:00
gspca_dev - > vdev . ctrl_handler = hdl ;
v4l2_ctrl_handler_init ( hdl , 2 ) ;
sd - > exposure = v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_EXPOSURE , 1 , 0xfff , 1 , 0x356 ) ;
sd - > gain = v4l2_ctrl_new_std ( hdl , & sd_ctrl_ops ,
V4L2_CID_GAIN , 1 , 255 , 1 , 0x8d ) ;
if ( hdl - > error ) {
pr_err ( " Could not initialize controls \n " ) ;
return hdl - > error ;
}
v4l2_ctrl_cluster ( 2 , & sd - > exposure ) ;
2010-06-05 07:45:04 -03:00
return 0 ;
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
. name = MODULE_NAME ,
. config = sd_config ,
. init = sd_init ,
2012-05-16 08:29:16 -03:00
. init_controls = sd_init_controls ,
2010-06-05 07:45:04 -03:00
. isoc_init = sd_isoc_init ,
. start = sd_start ,
. stopN = sd_stopN ,
. pkt_scan = sd_pkt_scan ,
. dq_callback = sd_dq_callback ,
} ;
/* Table of supported USB devices */
# define ST(sensor, type) \
. driver_info = ( SENSOR_ # # sensor < < 8 ) \
| ( type )
2011-01-13 05:20:29 -03:00
static const struct usb_device_id device_table [ ] = {
2010-06-05 07:45:04 -03:00
{ USB_DEVICE ( 0x041e , 0x4038 ) , ST ( MI0360 , 0 ) } ,
{ USB_DEVICE ( 0x041e , 0x403c ) , ST ( LZ24BP , 0 ) } ,
{ USB_DEVICE ( 0x041e , 0x403d ) , ST ( LZ24BP , 0 ) } ,
{ USB_DEVICE ( 0x041e , 0x4041 ) , ST ( LZ24BP , Creative_live_motion ) } ,
2010-06-24 05:02:57 -03:00
{ USB_DEVICE ( 0x2770 , 0x930b ) , ST ( MI0360 , 0 ) } ,
2010-06-05 07:45:04 -03:00
{ USB_DEVICE ( 0x2770 , 0x930c ) , ST ( MI0360 , 0 ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( usb , device_table ) ;
/* -- device connect -- */
static int sd_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
return gspca_dev_probe ( intf , id , & sd_desc , sizeof ( struct sd ) ,
THIS_MODULE ) ;
}
static struct usb_driver sd_driver = {
. name = MODULE_NAME ,
. id_table = device_table ,
. probe = sd_probe ,
. disconnect = gspca_disconnect ,
# ifdef CONFIG_PM
. suspend = gspca_suspend ,
. resume = gspca_resume ,
2012-06-30 06:44:47 -03:00
. reset_resume = gspca_resume ,
2010-06-05 07:45:04 -03:00
# endif
} ;
2011-11-18 09:46:12 -08:00
module_usb_driver ( sd_driver ) ;