162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SQ930x subdriver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr> 662306a36Sopenharmony_ci * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl> 762306a36Sopenharmony_ci * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define MODULE_NAME "sq930x" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "gspca.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciMODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n" 1762306a36Sopenharmony_ci "Gerard Klaver <gerard at gkall dot hobby dot nl\n" 1862306a36Sopenharmony_ci "Sam Revitch <samr7@cs.washington.edu>"); 1962306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); 2062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Structure to hold all of our device specific stuff */ 2362306a36Sopenharmony_cistruct sd { 2462306a36Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci struct { /* exposure/gain control cluster */ 2762306a36Sopenharmony_ci struct v4l2_ctrl *exposure; 2862306a36Sopenharmony_ci struct v4l2_ctrl *gain; 2962306a36Sopenharmony_ci }; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci u8 do_ctrl; 3262306a36Sopenharmony_ci u8 gpio[2]; 3362306a36Sopenharmony_ci u8 sensor; 3462306a36Sopenharmony_ci u8 type; 3562306a36Sopenharmony_ci#define Generic 0 3662306a36Sopenharmony_ci#define Creative_live_motion 1 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_cienum sensors { 3962306a36Sopenharmony_ci SENSOR_ICX098BQ, 4062306a36Sopenharmony_ci SENSOR_LZ24BP, 4162306a36Sopenharmony_ci SENSOR_MI0360, 4262306a36Sopenharmony_ci SENSOR_MT9V111, /* = MI360SOC */ 4362306a36Sopenharmony_ci SENSOR_OV7660, 4462306a36Sopenharmony_ci SENSOR_OV9630, 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct v4l2_pix_format vga_mode[] = { 4862306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, 4962306a36Sopenharmony_ci .bytesperline = 320, 5062306a36Sopenharmony_ci .sizeimage = 320 * 240, 5162306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 5262306a36Sopenharmony_ci .priv = 0}, 5362306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, 5462306a36Sopenharmony_ci .bytesperline = 640, 5562306a36Sopenharmony_ci .sizeimage = 640 * 480, 5662306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 5762306a36Sopenharmony_ci .priv = 1}, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* sq930x registers */ 6162306a36Sopenharmony_ci#define SQ930_CTRL_UCBUS_IO 0x0001 6262306a36Sopenharmony_ci#define SQ930_CTRL_I2C_IO 0x0002 6362306a36Sopenharmony_ci#define SQ930_CTRL_GPIO 0x0005 6462306a36Sopenharmony_ci#define SQ930_CTRL_CAP_START 0x0010 6562306a36Sopenharmony_ci#define SQ930_CTRL_CAP_STOP 0x0011 6662306a36Sopenharmony_ci#define SQ930_CTRL_SET_EXPOSURE 0x001d 6762306a36Sopenharmony_ci#define SQ930_CTRL_RESET 0x001e 6862306a36Sopenharmony_ci#define SQ930_CTRL_GET_DEV_INFO 0x001f 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* gpio 1 (8..15) */ 7162306a36Sopenharmony_ci#define SQ930_GPIO_DFL_I2C_SDA 0x0001 7262306a36Sopenharmony_ci#define SQ930_GPIO_DFL_I2C_SCL 0x0002 7362306a36Sopenharmony_ci#define SQ930_GPIO_RSTBAR 0x0004 7462306a36Sopenharmony_ci#define SQ930_GPIO_EXTRA1 0x0040 7562306a36Sopenharmony_ci#define SQ930_GPIO_EXTRA2 0x0080 7662306a36Sopenharmony_ci/* gpio 3 (24..31) */ 7762306a36Sopenharmony_ci#define SQ930_GPIO_POWER 0x0200 7862306a36Sopenharmony_ci#define SQ930_GPIO_DFL_LED 0x1000 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct ucbus_write_cmd { 8162306a36Sopenharmony_ci u16 bw_addr; 8262306a36Sopenharmony_ci u8 bw_data; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_cistruct i2c_write_cmd { 8562306a36Sopenharmony_ci u8 reg; 8662306a36Sopenharmony_ci u16 val; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct ucbus_write_cmd icx098bq_start_0[] = { 9062306a36Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, 9162306a36Sopenharmony_ci {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, 9262306a36Sopenharmony_ci {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, 9362306a36Sopenharmony_ci {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, 9462306a36Sopenharmony_ci {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, 9562306a36Sopenharmony_ci {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, 9662306a36Sopenharmony_ci {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, 9762306a36Sopenharmony_ci {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, 9862306a36Sopenharmony_ci {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, 9962306a36Sopenharmony_ci {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, 10062306a36Sopenharmony_ci {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, 10162306a36Sopenharmony_ci {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, 10262306a36Sopenharmony_ci {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, 10362306a36Sopenharmony_ci {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, 10462306a36Sopenharmony_ci {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, 10562306a36Sopenharmony_ci {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, 10662306a36Sopenharmony_ci {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, 10762306a36Sopenharmony_ci {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, 10862306a36Sopenharmony_ci {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, 10962306a36Sopenharmony_ci {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, 11062306a36Sopenharmony_ci {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, 11162306a36Sopenharmony_ci {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, 11262306a36Sopenharmony_ci {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, 11362306a36Sopenharmony_ci {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, 11462306a36Sopenharmony_ci {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, 11562306a36Sopenharmony_ci {0xf800, 0x03} 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_cistatic const struct ucbus_write_cmd icx098bq_start_1[] = { 11862306a36Sopenharmony_ci {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 11962306a36Sopenharmony_ci {0xf5f4, 0xc0}, 12062306a36Sopenharmony_ci {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 12162306a36Sopenharmony_ci {0xf5f4, 0xc0}, 12262306a36Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 12362306a36Sopenharmony_ci {0xf5f9, 0x00} 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic const struct ucbus_write_cmd icx098bq_start_2[] = { 12762306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, 12862306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 12962306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, 13062306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 13162306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, 13262306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 13362306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, 13462306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03} 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_0[] = { 13862306a36Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, 13962306a36Sopenharmony_ci {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, 14062306a36Sopenharmony_ci {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, 14162306a36Sopenharmony_ci {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, 14262306a36Sopenharmony_ci {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, 14362306a36Sopenharmony_ci {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, 14462306a36Sopenharmony_ci {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, 14562306a36Sopenharmony_ci {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, 14662306a36Sopenharmony_ci {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, 14762306a36Sopenharmony_ci {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, 14862306a36Sopenharmony_ci {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, 14962306a36Sopenharmony_ci {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, 15062306a36Sopenharmony_ci {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, 15162306a36Sopenharmony_ci {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, 15262306a36Sopenharmony_ci {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, 15362306a36Sopenharmony_ci {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, 15462306a36Sopenharmony_ci {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, 15562306a36Sopenharmony_ci {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, 15662306a36Sopenharmony_ci {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, 15762306a36Sopenharmony_ci {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, 15862306a36Sopenharmony_ci {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, 15962306a36Sopenharmony_ci {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, 16062306a36Sopenharmony_ci {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, 16162306a36Sopenharmony_ci {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, 16262306a36Sopenharmony_ci {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, 16362306a36Sopenharmony_ci {0xf800, 0x03} 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_1_gen[] = { 16662306a36Sopenharmony_ci {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 16762306a36Sopenharmony_ci {0xf5f4, 0xb3}, 16862306a36Sopenharmony_ci {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 16962306a36Sopenharmony_ci {0xf5f4, 0xb3}, 17062306a36Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 17162306a36Sopenharmony_ci {0xf5f9, 0x00} 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_1_clm[] = { 17562306a36Sopenharmony_ci {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, 17662306a36Sopenharmony_ci {0xf5f4, 0xc0}, 17762306a36Sopenharmony_ci {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, 17862306a36Sopenharmony_ci {0xf5f4, 0xc0}, 17962306a36Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 18062306a36Sopenharmony_ci {0xf5f9, 0x00} 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_2[] = { 18462306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, 18562306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 18662306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, 18762306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 18862306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, 18962306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 19062306a36Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, 19162306a36Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03} 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic const struct ucbus_write_cmd mi0360_start_0[] = { 19562306a36Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, 19662306a36Sopenharmony_ci {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_cistatic const struct i2c_write_cmd mi0360_init_23[] = { 19962306a36Sopenharmony_ci {0x30, 0x0040}, /* reserved - def 0x0005 */ 20062306a36Sopenharmony_ci {0x31, 0x0000}, /* reserved - def 0x002a */ 20162306a36Sopenharmony_ci {0x34, 0x0100}, /* reserved - def 0x0100 */ 20262306a36Sopenharmony_ci {0x3d, 0x068f}, /* reserved - def 0x068f */ 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_cistatic const struct i2c_write_cmd mi0360_init_24[] = { 20562306a36Sopenharmony_ci {0x03, 0x01e5}, /* window height */ 20662306a36Sopenharmony_ci {0x04, 0x0285}, /* window width */ 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_cistatic const struct i2c_write_cmd mi0360_init_25[] = { 20962306a36Sopenharmony_ci {0x35, 0x0020}, /* global gain */ 21062306a36Sopenharmony_ci {0x2b, 0x0020}, /* green1 gain */ 21162306a36Sopenharmony_ci {0x2c, 0x002a}, /* blue gain */ 21262306a36Sopenharmony_ci {0x2d, 0x0028}, /* red gain */ 21362306a36Sopenharmony_ci {0x2e, 0x0020}, /* green2 gain */ 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_cistatic const struct ucbus_write_cmd mi0360_start_1[] = { 21662306a36Sopenharmony_ci {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 21762306a36Sopenharmony_ci {0xf5f4, 0xa6}, 21862306a36Sopenharmony_ci {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 21962306a36Sopenharmony_ci {0xf5f4, 0xa6}, 22062306a36Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 22162306a36Sopenharmony_ci {0xf5f9, 0x00} 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_cistatic const struct i2c_write_cmd mi0360_start_2[] = { 22462306a36Sopenharmony_ci {0x62, 0x041d}, /* reserved - def 0x0418 */ 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_cistatic const struct i2c_write_cmd mi0360_start_3[] = { 22762306a36Sopenharmony_ci {0x05, 0x007b}, /* horiz blanking */ 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_cistatic const struct i2c_write_cmd mi0360_start_4[] = { 23062306a36Sopenharmony_ci {0x05, 0x03f5}, /* horiz blanking */ 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_0[] = { 23462306a36Sopenharmony_ci {0x01, 0x0001}, /* select IFP/SOC registers */ 23562306a36Sopenharmony_ci {0x06, 0x300c}, /* operating mode control */ 23662306a36Sopenharmony_ci {0x08, 0xcc00}, /* output format control (RGB) */ 23762306a36Sopenharmony_ci {0x01, 0x0004}, /* select sensor core registers */ 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_1[] = { 24062306a36Sopenharmony_ci {0x03, 0x01e5}, /* window height */ 24162306a36Sopenharmony_ci {0x04, 0x0285}, /* window width */ 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_2[] = { 24462306a36Sopenharmony_ci {0x30, 0x7800}, 24562306a36Sopenharmony_ci {0x31, 0x0000}, 24662306a36Sopenharmony_ci {0x07, 0x3002}, /* output control */ 24762306a36Sopenharmony_ci {0x35, 0x0020}, /* global gain */ 24862306a36Sopenharmony_ci {0x2b, 0x0020}, /* green1 gain */ 24962306a36Sopenharmony_ci {0x2c, 0x0020}, /* blue gain */ 25062306a36Sopenharmony_ci {0x2d, 0x0020}, /* red gain */ 25162306a36Sopenharmony_ci {0x2e, 0x0020}, /* green2 gain */ 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_cistatic const struct ucbus_write_cmd mt9v111_start_1[] = { 25462306a36Sopenharmony_ci {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 25562306a36Sopenharmony_ci {0xf5f4, 0xaa}, 25662306a36Sopenharmony_ci {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 25762306a36Sopenharmony_ci {0xf5f4, 0xaa}, 25862306a36Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a}, 25962306a36Sopenharmony_ci {0xf5f9, 0x0a} 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_3[] = { 26262306a36Sopenharmony_ci {0x62, 0x0405}, 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_4[] = { 26562306a36Sopenharmony_ci/* {0x05, 0x00ce}, */ 26662306a36Sopenharmony_ci {0x05, 0x005d}, /* horizontal blanking */ 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic const struct ucbus_write_cmd ov7660_start_0[] = { 27062306a36Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0}, 27162306a36Sopenharmony_ci {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03} 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic const struct ucbus_write_cmd ov9630_start_0[] = { 27562306a36Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00}, 27662306a36Sopenharmony_ci {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03} 27762306a36Sopenharmony_ci}; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci/* start parameters indexed by [sensor][mode] */ 28062306a36Sopenharmony_cistatic const struct cap_s { 28162306a36Sopenharmony_ci u8 cc_sizeid; 28262306a36Sopenharmony_ci u8 cc_bytes[32]; 28362306a36Sopenharmony_ci} capconfig[4][2] = { 28462306a36Sopenharmony_ci [SENSOR_ICX098BQ] = { 28562306a36Sopenharmony_ci {2, /* Bayer 320x240 */ 28662306a36Sopenharmony_ci {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, 28762306a36Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 28862306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 28962306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 29062306a36Sopenharmony_ci {4, /* Bayer 640x480 */ 29162306a36Sopenharmony_ci {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, 29262306a36Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 29362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29462306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 29562306a36Sopenharmony_ci }, 29662306a36Sopenharmony_ci [SENSOR_LZ24BP] = { 29762306a36Sopenharmony_ci {2, /* Bayer 320x240 */ 29862306a36Sopenharmony_ci {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, 29962306a36Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 30062306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30162306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 30262306a36Sopenharmony_ci {4, /* Bayer 640x480 */ 30362306a36Sopenharmony_ci {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, 30462306a36Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 30562306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 30762306a36Sopenharmony_ci }, 30862306a36Sopenharmony_ci [SENSOR_MI0360] = { 30962306a36Sopenharmony_ci {2, /* Bayer 320x240 */ 31062306a36Sopenharmony_ci {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 31162306a36Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 31262306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 31462306a36Sopenharmony_ci {4, /* Bayer 640x480 */ 31562306a36Sopenharmony_ci {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 31662306a36Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 31762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31862306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 31962306a36Sopenharmony_ci }, 32062306a36Sopenharmony_ci [SENSOR_MT9V111] = { 32162306a36Sopenharmony_ci {2, /* Bayer 320x240 */ 32262306a36Sopenharmony_ci {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 32362306a36Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 32462306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32562306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 32662306a36Sopenharmony_ci {4, /* Bayer 640x480 */ 32762306a36Sopenharmony_ci {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 32862306a36Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 32962306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33062306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 33162306a36Sopenharmony_ci }, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistruct sensor_s { 33562306a36Sopenharmony_ci const char *name; 33662306a36Sopenharmony_ci u8 i2c_addr; 33762306a36Sopenharmony_ci u8 i2c_dum; 33862306a36Sopenharmony_ci u8 gpio[5]; 33962306a36Sopenharmony_ci u8 cmd_len; 34062306a36Sopenharmony_ci const struct ucbus_write_cmd *cmd; 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic const struct sensor_s sensor_tb[] = { 34462306a36Sopenharmony_ci [SENSOR_ICX098BQ] = { 34562306a36Sopenharmony_ci "icx098bp", 34662306a36Sopenharmony_ci 0x00, 0x00, 34762306a36Sopenharmony_ci {0, 34862306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 34962306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 35062306a36Sopenharmony_ci 0, 35162306a36Sopenharmony_ci SQ930_GPIO_RSTBAR 35262306a36Sopenharmony_ci }, 35362306a36Sopenharmony_ci 8, icx098bq_start_0 35462306a36Sopenharmony_ci }, 35562306a36Sopenharmony_ci [SENSOR_LZ24BP] = { 35662306a36Sopenharmony_ci "lz24bp", 35762306a36Sopenharmony_ci 0x00, 0x00, 35862306a36Sopenharmony_ci {0, 35962306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 36062306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 36162306a36Sopenharmony_ci 0, 36262306a36Sopenharmony_ci SQ930_GPIO_RSTBAR 36362306a36Sopenharmony_ci }, 36462306a36Sopenharmony_ci 8, lz24bp_start_0 36562306a36Sopenharmony_ci }, 36662306a36Sopenharmony_ci [SENSOR_MI0360] = { 36762306a36Sopenharmony_ci "mi0360", 36862306a36Sopenharmony_ci 0x5d, 0x80, 36962306a36Sopenharmony_ci {SQ930_GPIO_RSTBAR, 37062306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 37162306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 37262306a36Sopenharmony_ci 0, 37362306a36Sopenharmony_ci 0 37462306a36Sopenharmony_ci }, 37562306a36Sopenharmony_ci 7, mi0360_start_0 37662306a36Sopenharmony_ci }, 37762306a36Sopenharmony_ci [SENSOR_MT9V111] = { 37862306a36Sopenharmony_ci "mt9v111", 37962306a36Sopenharmony_ci 0x5c, 0x7f, 38062306a36Sopenharmony_ci {SQ930_GPIO_RSTBAR, 38162306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 38262306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 38362306a36Sopenharmony_ci 0, 38462306a36Sopenharmony_ci 0 38562306a36Sopenharmony_ci }, 38662306a36Sopenharmony_ci 7, mi0360_start_0 38762306a36Sopenharmony_ci }, 38862306a36Sopenharmony_ci [SENSOR_OV7660] = { 38962306a36Sopenharmony_ci "ov7660", 39062306a36Sopenharmony_ci 0x21, 0x00, 39162306a36Sopenharmony_ci {0, 39262306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 39362306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 39462306a36Sopenharmony_ci 0, 39562306a36Sopenharmony_ci SQ930_GPIO_RSTBAR 39662306a36Sopenharmony_ci }, 39762306a36Sopenharmony_ci 7, ov7660_start_0 39862306a36Sopenharmony_ci }, 39962306a36Sopenharmony_ci [SENSOR_OV9630] = { 40062306a36Sopenharmony_ci "ov9630", 40162306a36Sopenharmony_ci 0x30, 0x00, 40262306a36Sopenharmony_ci {0, 40362306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 40462306a36Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 40562306a36Sopenharmony_ci 0, 40662306a36Sopenharmony_ci SQ930_GPIO_RSTBAR 40762306a36Sopenharmony_ci }, 40862306a36Sopenharmony_ci 7, ov9630_start_0 40962306a36Sopenharmony_ci }, 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void reg_r(struct gspca_dev *gspca_dev, 41362306a36Sopenharmony_ci u16 value, int len) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci int ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 41862306a36Sopenharmony_ci return; 41962306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 42062306a36Sopenharmony_ci usb_rcvctrlpipe(gspca_dev->dev, 0), 42162306a36Sopenharmony_ci 0x0c, 42262306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 42362306a36Sopenharmony_ci value, 0, gspca_dev->usb_buf, len, 42462306a36Sopenharmony_ci 500); 42562306a36Sopenharmony_ci if (ret < 0) { 42662306a36Sopenharmony_ci pr_err("reg_r %04x failed %d\n", value, ret); 42762306a36Sopenharmony_ci gspca_dev->usb_err = ret; 42862306a36Sopenharmony_ci /* 42962306a36Sopenharmony_ci * Make sure the buffer is zeroed to avoid uninitialized 43062306a36Sopenharmony_ci * values. 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci int ret; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 44162306a36Sopenharmony_ci return; 44262306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "reg_w v: %04x i: %04x\n", value, index); 44362306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 44462306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 44562306a36Sopenharmony_ci 0x0c, /* request */ 44662306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 44762306a36Sopenharmony_ci value, index, NULL, 0, 44862306a36Sopenharmony_ci 500); 44962306a36Sopenharmony_ci msleep(30); 45062306a36Sopenharmony_ci if (ret < 0) { 45162306a36Sopenharmony_ci pr_err("reg_w %04x %04x failed %d\n", value, index, ret); 45262306a36Sopenharmony_ci gspca_dev->usb_err = ret; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, 45762306a36Sopenharmony_ci const u8 *data, int len) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci int ret; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 46262306a36Sopenharmony_ci return; 46362306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "reg_wb v: %04x i: %04x %02x...%02x\n", 46462306a36Sopenharmony_ci value, index, *data, data[len - 1]); 46562306a36Sopenharmony_ci memcpy(gspca_dev->usb_buf, data, len); 46662306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 46762306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 46862306a36Sopenharmony_ci 0x0c, /* request */ 46962306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 47062306a36Sopenharmony_ci value, index, gspca_dev->usb_buf, len, 47162306a36Sopenharmony_ci 1000); 47262306a36Sopenharmony_ci msleep(30); 47362306a36Sopenharmony_ci if (ret < 0) { 47462306a36Sopenharmony_ci pr_err("reg_wb %04x %04x failed %d\n", value, index, ret); 47562306a36Sopenharmony_ci gspca_dev->usb_err = ret; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic void i2c_write(struct sd *sd, 48062306a36Sopenharmony_ci const struct i2c_write_cmd *cmd, 48162306a36Sopenharmony_ci int ncmds) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 48462306a36Sopenharmony_ci const struct sensor_s *sensor; 48562306a36Sopenharmony_ci u16 val, idx; 48662306a36Sopenharmony_ci u8 *buf; 48762306a36Sopenharmony_ci int ret; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 49062306a36Sopenharmony_ci return; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci sensor = &sensor_tb[sd->sensor]; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO; 49562306a36Sopenharmony_ci idx = (cmd->val & 0xff00) | cmd->reg; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci buf = gspca_dev->usb_buf; 49862306a36Sopenharmony_ci *buf++ = sensor->i2c_dum; 49962306a36Sopenharmony_ci *buf++ = cmd->val; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci while (--ncmds > 0) { 50262306a36Sopenharmony_ci cmd++; 50362306a36Sopenharmony_ci *buf++ = cmd->reg; 50462306a36Sopenharmony_ci *buf++ = cmd->val >> 8; 50562306a36Sopenharmony_ci *buf++ = sensor->i2c_dum; 50662306a36Sopenharmony_ci *buf++ = cmd->val; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "i2c_w v: %04x i: %04x %02x...%02x\n", 51062306a36Sopenharmony_ci val, idx, gspca_dev->usb_buf[0], buf[-1]); 51162306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 51262306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 51362306a36Sopenharmony_ci 0x0c, /* request */ 51462306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 51562306a36Sopenharmony_ci val, idx, 51662306a36Sopenharmony_ci gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 51762306a36Sopenharmony_ci 500); 51862306a36Sopenharmony_ci if (ret < 0) { 51962306a36Sopenharmony_ci pr_err("i2c_write failed %d\n", ret); 52062306a36Sopenharmony_ci gspca_dev->usb_err = ret; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic void ucbus_write(struct gspca_dev *gspca_dev, 52562306a36Sopenharmony_ci const struct ucbus_write_cmd *cmd, 52662306a36Sopenharmony_ci int ncmds, 52762306a36Sopenharmony_ci int batchsize) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci u8 *buf; 53062306a36Sopenharmony_ci u16 val, idx; 53162306a36Sopenharmony_ci int len, ret; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 53462306a36Sopenharmony_ci return; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if ((batchsize - 1) * 3 > USB_BUF_SZ) { 53762306a36Sopenharmony_ci gspca_err(gspca_dev, "Bug: usb_buf overflow\n"); 53862306a36Sopenharmony_ci gspca_dev->usb_err = -ENOMEM; 53962306a36Sopenharmony_ci return; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci for (;;) { 54362306a36Sopenharmony_ci len = ncmds; 54462306a36Sopenharmony_ci if (len > batchsize) 54562306a36Sopenharmony_ci len = batchsize; 54662306a36Sopenharmony_ci ncmds -= len; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; 54962306a36Sopenharmony_ci idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci buf = gspca_dev->usb_buf; 55262306a36Sopenharmony_ci while (--len > 0) { 55362306a36Sopenharmony_ci cmd++; 55462306a36Sopenharmony_ci *buf++ = cmd->bw_addr; 55562306a36Sopenharmony_ci *buf++ = cmd->bw_addr >> 8; 55662306a36Sopenharmony_ci *buf++ = cmd->bw_data; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci if (buf != gspca_dev->usb_buf) 55962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "ucbus v: %04x i: %04x %02x...%02x\n", 56062306a36Sopenharmony_ci val, idx, 56162306a36Sopenharmony_ci gspca_dev->usb_buf[0], buf[-1]); 56262306a36Sopenharmony_ci else 56362306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "ucbus v: %04x i: %04x\n", 56462306a36Sopenharmony_ci val, idx); 56562306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 56662306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 56762306a36Sopenharmony_ci 0x0c, /* request */ 56862306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 56962306a36Sopenharmony_ci val, idx, 57062306a36Sopenharmony_ci gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 57162306a36Sopenharmony_ci 500); 57262306a36Sopenharmony_ci if (ret < 0) { 57362306a36Sopenharmony_ci pr_err("ucbus_write failed %d\n", ret); 57462306a36Sopenharmony_ci gspca_dev->usb_err = ret; 57562306a36Sopenharmony_ci return; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci msleep(30); 57862306a36Sopenharmony_ci if (ncmds <= 0) 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci cmd++; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic void gpio_set(struct sd *sd, u16 val, u16 mask) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (mask & 0x00ff) { 58962306a36Sopenharmony_ci sd->gpio[0] &= ~mask; 59062306a36Sopenharmony_ci sd->gpio[0] |= val; 59162306a36Sopenharmony_ci reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, 59262306a36Sopenharmony_ci ~sd->gpio[0] << 8); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci mask >>= 8; 59562306a36Sopenharmony_ci val >>= 8; 59662306a36Sopenharmony_ci if (mask) { 59762306a36Sopenharmony_ci sd->gpio[1] &= ~mask; 59862306a36Sopenharmony_ci sd->gpio[1] |= val; 59962306a36Sopenharmony_ci reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, 60062306a36Sopenharmony_ci ~sd->gpio[1] << 8); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void gpio_init(struct sd *sd, 60562306a36Sopenharmony_ci const u8 *gpio) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 60862306a36Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 60962306a36Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 61062306a36Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 61162306a36Sopenharmony_ci gpio_set(sd, *gpio, 0x000f); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic void bridge_init(struct sd *sd) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci static const struct ucbus_write_cmd clkfreq_cmd = { 61762306a36Sopenharmony_ci 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ 61862306a36Sopenharmony_ci }; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci gpio_set(sd, SQ930_GPIO_POWER, 0xff00); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void cmos_probe(struct gspca_dev *gspca_dev) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 62862306a36Sopenharmony_ci int i; 62962306a36Sopenharmony_ci const struct sensor_s *sensor; 63062306a36Sopenharmony_ci static const u8 probe_order[] = { 63162306a36Sopenharmony_ci/* SENSOR_LZ24BP, (tested as ccd) */ 63262306a36Sopenharmony_ci SENSOR_OV9630, 63362306a36Sopenharmony_ci SENSOR_MI0360, 63462306a36Sopenharmony_ci SENSOR_OV7660, 63562306a36Sopenharmony_ci SENSOR_MT9V111, 63662306a36Sopenharmony_ci }; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(probe_order); i++) { 63962306a36Sopenharmony_ci sensor = &sensor_tb[probe_order[i]]; 64062306a36Sopenharmony_ci ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8); 64162306a36Sopenharmony_ci gpio_init(sd, sensor->gpio); 64262306a36Sopenharmony_ci msleep(100); 64362306a36Sopenharmony_ci reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1); 64462306a36Sopenharmony_ci msleep(100); 64562306a36Sopenharmony_ci if (gspca_dev->usb_buf[0] != 0) 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci if (i >= ARRAY_SIZE(probe_order)) { 64962306a36Sopenharmony_ci pr_err("Unknown sensor\n"); 65062306a36Sopenharmony_ci gspca_dev->usb_err = -EINVAL; 65162306a36Sopenharmony_ci return; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci sd->sensor = probe_order[i]; 65462306a36Sopenharmony_ci switch (sd->sensor) { 65562306a36Sopenharmony_ci case SENSOR_OV7660: 65662306a36Sopenharmony_ci case SENSOR_OV9630: 65762306a36Sopenharmony_ci pr_err("Sensor %s not yet treated\n", 65862306a36Sopenharmony_ci sensor_tb[sd->sensor].name); 65962306a36Sopenharmony_ci gspca_dev->usb_err = -EINVAL; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic void mt9v111_init(struct gspca_dev *gspca_dev) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci int i, nwait; 66762306a36Sopenharmony_ci static const u8 cmd_001b[] = { 66862306a36Sopenharmony_ci 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00, 66962306a36Sopenharmony_ci 0x00, 0x00, 0x00 67062306a36Sopenharmony_ci }; 67162306a36Sopenharmony_ci static const u8 cmd_011b[][7] = { 67262306a36Sopenharmony_ci {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00}, 67362306a36Sopenharmony_ci {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00}, 67462306a36Sopenharmony_ci {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00}, 67562306a36Sopenharmony_ci {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00}, 67662306a36Sopenharmony_ci }; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b); 67962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) { 68062306a36Sopenharmony_ci reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i], 68162306a36Sopenharmony_ci ARRAY_SIZE(cmd_011b[0])); 68262306a36Sopenharmony_ci msleep(400); 68362306a36Sopenharmony_ci nwait = 20; 68462306a36Sopenharmony_ci for (;;) { 68562306a36Sopenharmony_ci reg_r(gspca_dev, 0x031b, 1); 68662306a36Sopenharmony_ci if (gspca_dev->usb_buf[0] == 0 68762306a36Sopenharmony_ci || gspca_dev->usb_err != 0) 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci if (--nwait < 0) { 69062306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "mt9v111_init timeout\n"); 69162306a36Sopenharmony_ci gspca_dev->usb_err = -ETIME; 69262306a36Sopenharmony_ci return; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci msleep(50); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void global_init(struct sd *sd, int first_time) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci switch (sd->sensor) { 70262306a36Sopenharmony_ci case SENSOR_ICX098BQ: 70362306a36Sopenharmony_ci if (first_time) 70462306a36Sopenharmony_ci ucbus_write(&sd->gspca_dev, 70562306a36Sopenharmony_ci icx098bq_start_0, 70662306a36Sopenharmony_ci 8, 8); 70762306a36Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 70862306a36Sopenharmony_ci break; 70962306a36Sopenharmony_ci case SENSOR_LZ24BP: 71062306a36Sopenharmony_ci if (sd->type != Creative_live_motion) 71162306a36Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); 71262306a36Sopenharmony_ci else 71362306a36Sopenharmony_ci gpio_set(sd, 0, 0x00ff); 71462306a36Sopenharmony_ci msleep(50); 71562306a36Sopenharmony_ci if (first_time) 71662306a36Sopenharmony_ci ucbus_write(&sd->gspca_dev, 71762306a36Sopenharmony_ci lz24bp_start_0, 71862306a36Sopenharmony_ci 8, 8); 71962306a36Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 72062306a36Sopenharmony_ci break; 72162306a36Sopenharmony_ci case SENSOR_MI0360: 72262306a36Sopenharmony_ci if (first_time) 72362306a36Sopenharmony_ci ucbus_write(&sd->gspca_dev, 72462306a36Sopenharmony_ci mi0360_start_0, 72562306a36Sopenharmony_ci ARRAY_SIZE(mi0360_start_0), 72662306a36Sopenharmony_ci 8); 72762306a36Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 72862306a36Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci default: 73162306a36Sopenharmony_ci/* case SENSOR_MT9V111: */ 73262306a36Sopenharmony_ci if (first_time) 73362306a36Sopenharmony_ci mt9v111_init(&sd->gspca_dev); 73462306a36Sopenharmony_ci else 73562306a36Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic void lz24bp_ppl(struct sd *sd, u16 ppl) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct ucbus_write_cmd cmds[2] = { 74362306a36Sopenharmony_ci {0xf810, ppl >> 8}, 74462306a36Sopenharmony_ci {0xf811, ppl} 74562306a36Sopenharmony_ci }; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 75362306a36Sopenharmony_ci int i, integclks, intstartclk, frameclks, min_frclk; 75462306a36Sopenharmony_ci const struct sensor_s *sensor; 75562306a36Sopenharmony_ci u16 cmd; 75662306a36Sopenharmony_ci u8 buf[15]; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci integclks = expo; 75962306a36Sopenharmony_ci i = 0; 76062306a36Sopenharmony_ci cmd = SQ930_CTRL_SET_EXPOSURE; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci switch (sd->sensor) { 76362306a36Sopenharmony_ci case SENSOR_ICX098BQ: /* ccd */ 76462306a36Sopenharmony_ci case SENSOR_LZ24BP: 76562306a36Sopenharmony_ci min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; 76662306a36Sopenharmony_ci if (integclks >= min_frclk) { 76762306a36Sopenharmony_ci intstartclk = 0; 76862306a36Sopenharmony_ci frameclks = integclks; 76962306a36Sopenharmony_ci } else { 77062306a36Sopenharmony_ci intstartclk = min_frclk - integclks; 77162306a36Sopenharmony_ci frameclks = min_frclk; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci buf[i++] = intstartclk >> 8; 77462306a36Sopenharmony_ci buf[i++] = intstartclk; 77562306a36Sopenharmony_ci buf[i++] = frameclks >> 8; 77662306a36Sopenharmony_ci buf[i++] = frameclks; 77762306a36Sopenharmony_ci buf[i++] = gain; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci default: /* cmos */ 78062306a36Sopenharmony_ci/* case SENSOR_MI0360: */ 78162306a36Sopenharmony_ci/* case SENSOR_MT9V111: */ 78262306a36Sopenharmony_ci cmd |= 0x0100; 78362306a36Sopenharmony_ci sensor = &sensor_tb[sd->sensor]; 78462306a36Sopenharmony_ci buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */ 78562306a36Sopenharmony_ci buf[i++] = 0x08; /* 2 * ni2c */ 78662306a36Sopenharmony_ci buf[i++] = 0x09; /* reg = shutter width */ 78762306a36Sopenharmony_ci buf[i++] = integclks >> 8; /* val H */ 78862306a36Sopenharmony_ci buf[i++] = sensor->i2c_dum; 78962306a36Sopenharmony_ci buf[i++] = integclks; /* val L */ 79062306a36Sopenharmony_ci buf[i++] = 0x35; /* reg = global gain */ 79162306a36Sopenharmony_ci buf[i++] = 0x00; /* val H */ 79262306a36Sopenharmony_ci buf[i++] = sensor->i2c_dum; 79362306a36Sopenharmony_ci buf[i++] = 0x80 + gain / 2; /* val L */ 79462306a36Sopenharmony_ci buf[i++] = 0x00; 79562306a36Sopenharmony_ci buf[i++] = 0x00; 79662306a36Sopenharmony_ci buf[i++] = 0x00; 79762306a36Sopenharmony_ci buf[i++] = 0x00; 79862306a36Sopenharmony_ci buf[i++] = 0x83; 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci reg_wb(gspca_dev, cmd, 0, buf, i); 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/* This function is called at probe time just before sd_init */ 80562306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 80662306a36Sopenharmony_ci const struct usb_device_id *id) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 80962306a36Sopenharmony_ci struct cam *cam = &gspca_dev->cam; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci sd->sensor = id->driver_info >> 8; 81262306a36Sopenharmony_ci sd->type = id->driver_info; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci cam->cam_mode = vga_mode; 81562306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(vga_mode); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci cam->bulk = 1; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/* this function is called at probe and resume time */ 82362306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci/*fixme: is this needed for icx098bp and mi0360? 83062306a36Sopenharmony_ci if (sd->sensor != SENSOR_LZ24BP) 83162306a36Sopenharmony_ci reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); 83562306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 83662306a36Sopenharmony_ci return gspca_dev->usb_err; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/* it returns: 83962306a36Sopenharmony_ci * 03 00 12 93 0b f6 c9 00 live! ultra 84062306a36Sopenharmony_ci * 03 00 07 93 0b f6 ca 00 live! ultra for notebook 84162306a36Sopenharmony_ci * 03 00 12 93 0b fe c8 00 Trust WB-3500T 84262306a36Sopenharmony_ci * 02 00 06 93 0b fe c8 00 Joy-IT 318S 84362306a36Sopenharmony_ci * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq 84462306a36Sopenharmony_ci * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam 84562306a36Sopenharmony_ci * 84662306a36Sopenharmony_ci * byte 84762306a36Sopenharmony_ci * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) 84862306a36Sopenharmony_ci * 1: 00 84962306a36Sopenharmony_ci * 2: 06 / 07 / 12 = mode webcam? firmware?? 85062306a36Sopenharmony_ci * 3: 93 chip = 930b (930b or 930c) 85162306a36Sopenharmony_ci * 4: 0b 85262306a36Sopenharmony_ci * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors) 85362306a36Sopenharmony_ci * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? 85462306a36Sopenharmony_ci * 7: 00 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "info: %*ph\n", 8, gspca_dev->usb_buf); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci bridge_init(sd); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (sd->sensor == SENSOR_MI0360) { 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* no sensor probe for icam tracer */ 86362306a36Sopenharmony_ci if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */ 86462306a36Sopenharmony_ci sd->sensor = SENSOR_ICX098BQ; 86562306a36Sopenharmony_ci else 86662306a36Sopenharmony_ci cmos_probe(gspca_dev); 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci if (gspca_dev->usb_err >= 0) { 86962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Sensor %s\n", 87062306a36Sopenharmony_ci sensor_tb[sd->sensor].name); 87162306a36Sopenharmony_ci global_init(sd, 1); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci return gspca_dev->usb_err; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/* send the start/stop commands to the webcam */ 87762306a36Sopenharmony_cistatic void send_start(struct gspca_dev *gspca_dev) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 88062306a36Sopenharmony_ci const struct cap_s *cap; 88162306a36Sopenharmony_ci int mode; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 88462306a36Sopenharmony_ci cap = &capconfig[sd->sensor][mode]; 88562306a36Sopenharmony_ci reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START, 88662306a36Sopenharmony_ci 0x0a00 | cap->cc_sizeid, 88762306a36Sopenharmony_ci cap->cc_bytes, 32); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic void send_stop(struct gspca_dev *gspca_dev) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci/* function called at start time before URB creation */ 89662306a36Sopenharmony_cistatic int sd_isoc_init(struct gspca_dev *gspca_dev) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ 90162306a36Sopenharmony_ci sd->do_ctrl = 0; 90262306a36Sopenharmony_ci gspca_dev->cam.bulk_size = gspca_dev->pixfmt.width * 90362306a36Sopenharmony_ci gspca_dev->pixfmt.height + 8; 90462306a36Sopenharmony_ci return 0; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci/* start the capture */ 90862306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 91162306a36Sopenharmony_ci int mode; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci bridge_init(sd); 91462306a36Sopenharmony_ci global_init(sd, 0); 91562306a36Sopenharmony_ci msleep(100); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci switch (sd->sensor) { 91862306a36Sopenharmony_ci case SENSOR_ICX098BQ: 91962306a36Sopenharmony_ci ucbus_write(gspca_dev, icx098bq_start_0, 92062306a36Sopenharmony_ci ARRAY_SIZE(icx098bq_start_0), 92162306a36Sopenharmony_ci 8); 92262306a36Sopenharmony_ci ucbus_write(gspca_dev, icx098bq_start_1, 92362306a36Sopenharmony_ci ARRAY_SIZE(icx098bq_start_1), 92462306a36Sopenharmony_ci 5); 92562306a36Sopenharmony_ci ucbus_write(gspca_dev, icx098bq_start_2, 92662306a36Sopenharmony_ci ARRAY_SIZE(icx098bq_start_2), 92762306a36Sopenharmony_ci 6); 92862306a36Sopenharmony_ci msleep(50); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* 1st start */ 93162306a36Sopenharmony_ci send_start(gspca_dev); 93262306a36Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); 93362306a36Sopenharmony_ci msleep(70); 93462306a36Sopenharmony_ci reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); 93562306a36Sopenharmony_ci gpio_set(sd, 0x7f, 0x00ff); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* 2nd start */ 93862306a36Sopenharmony_ci send_start(gspca_dev); 93962306a36Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); 94062306a36Sopenharmony_ci goto out; 94162306a36Sopenharmony_ci case SENSOR_LZ24BP: 94262306a36Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_0, 94362306a36Sopenharmony_ci ARRAY_SIZE(lz24bp_start_0), 94462306a36Sopenharmony_ci 8); 94562306a36Sopenharmony_ci if (sd->type != Creative_live_motion) 94662306a36Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_1_gen, 94762306a36Sopenharmony_ci ARRAY_SIZE(lz24bp_start_1_gen), 94862306a36Sopenharmony_ci 5); 94962306a36Sopenharmony_ci else 95062306a36Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_1_clm, 95162306a36Sopenharmony_ci ARRAY_SIZE(lz24bp_start_1_clm), 95262306a36Sopenharmony_ci 5); 95362306a36Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_2, 95462306a36Sopenharmony_ci ARRAY_SIZE(lz24bp_start_2), 95562306a36Sopenharmony_ci 6); 95662306a36Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 95762306a36Sopenharmony_ci lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310); 95862306a36Sopenharmony_ci msleep(10); 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci case SENSOR_MI0360: 96162306a36Sopenharmony_ci ucbus_write(gspca_dev, mi0360_start_0, 96262306a36Sopenharmony_ci ARRAY_SIZE(mi0360_start_0), 96362306a36Sopenharmony_ci 8); 96462306a36Sopenharmony_ci i2c_write(sd, mi0360_init_23, 96562306a36Sopenharmony_ci ARRAY_SIZE(mi0360_init_23)); 96662306a36Sopenharmony_ci i2c_write(sd, mi0360_init_24, 96762306a36Sopenharmony_ci ARRAY_SIZE(mi0360_init_24)); 96862306a36Sopenharmony_ci i2c_write(sd, mi0360_init_25, 96962306a36Sopenharmony_ci ARRAY_SIZE(mi0360_init_25)); 97062306a36Sopenharmony_ci ucbus_write(gspca_dev, mi0360_start_1, 97162306a36Sopenharmony_ci ARRAY_SIZE(mi0360_start_1), 97262306a36Sopenharmony_ci 5); 97362306a36Sopenharmony_ci i2c_write(sd, mi0360_start_2, 97462306a36Sopenharmony_ci ARRAY_SIZE(mi0360_start_2)); 97562306a36Sopenharmony_ci i2c_write(sd, mi0360_start_3, 97662306a36Sopenharmony_ci ARRAY_SIZE(mi0360_start_3)); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* 1st start */ 97962306a36Sopenharmony_ci send_start(gspca_dev); 98062306a36Sopenharmony_ci msleep(60); 98162306a36Sopenharmony_ci send_stop(gspca_dev); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci i2c_write(sd, 98462306a36Sopenharmony_ci mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci default: 98762306a36Sopenharmony_ci/* case SENSOR_MT9V111: */ 98862306a36Sopenharmony_ci ucbus_write(gspca_dev, mi0360_start_0, 98962306a36Sopenharmony_ci ARRAY_SIZE(mi0360_start_0), 99062306a36Sopenharmony_ci 8); 99162306a36Sopenharmony_ci i2c_write(sd, mt9v111_init_0, 99262306a36Sopenharmony_ci ARRAY_SIZE(mt9v111_init_0)); 99362306a36Sopenharmony_ci i2c_write(sd, mt9v111_init_1, 99462306a36Sopenharmony_ci ARRAY_SIZE(mt9v111_init_1)); 99562306a36Sopenharmony_ci i2c_write(sd, mt9v111_init_2, 99662306a36Sopenharmony_ci ARRAY_SIZE(mt9v111_init_2)); 99762306a36Sopenharmony_ci ucbus_write(gspca_dev, mt9v111_start_1, 99862306a36Sopenharmony_ci ARRAY_SIZE(mt9v111_start_1), 99962306a36Sopenharmony_ci 5); 100062306a36Sopenharmony_ci i2c_write(sd, mt9v111_init_3, 100162306a36Sopenharmony_ci ARRAY_SIZE(mt9v111_init_3)); 100262306a36Sopenharmony_ci i2c_write(sd, mt9v111_init_4, 100362306a36Sopenharmony_ci ARRAY_SIZE(mt9v111_init_4)); 100462306a36Sopenharmony_ci break; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci send_start(gspca_dev); 100862306a36Sopenharmony_ciout: 100962306a36Sopenharmony_ci msleep(1000); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (sd->sensor == SENSOR_MT9V111) 101262306a36Sopenharmony_ci gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci sd->do_ctrl = 1; /* set the exposure */ 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci return gspca_dev->usb_err; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (sd->sensor == SENSOR_MT9V111) 102462306a36Sopenharmony_ci gpio_set(sd, 0, SQ930_GPIO_DFL_LED); 102562306a36Sopenharmony_ci send_stop(gspca_dev); 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci/* function called when the application gets a new frame */ 102962306a36Sopenharmony_ci/* It sets the exposure if required and restart the bulk transfer. */ 103062306a36Sopenharmony_cistatic void sd_dq_callback(struct gspca_dev *gspca_dev) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 103362306a36Sopenharmony_ci int ret; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) 103662306a36Sopenharmony_ci return; 103762306a36Sopenharmony_ci sd->do_ctrl = 0; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure), 104062306a36Sopenharmony_ci v4l2_ctrl_g_ctrl(sd->gain)); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 1; 104362306a36Sopenharmony_ci ret = usb_submit_urb(gspca_dev->urb[0], GFP_KERNEL); 104462306a36Sopenharmony_ci if (ret < 0) 104562306a36Sopenharmony_ci pr_err("sd_dq_callback() err %d\n", ret); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* wait a little time, otherwise the webcam crashes */ 104862306a36Sopenharmony_ci msleep(100); 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, 105262306a36Sopenharmony_ci u8 *data, /* isoc packet */ 105362306a36Sopenharmony_ci int len) /* iso packet length */ 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (sd->do_ctrl) 105862306a36Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 0; 105962306a36Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); 106062306a36Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8); 106162306a36Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci struct gspca_dev *gspca_dev = 106762306a36Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 106862306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci gspca_dev->usb_err = 0; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (!gspca_dev->streaming) 107362306a36Sopenharmony_ci return 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci switch (ctrl->id) { 107662306a36Sopenharmony_ci case V4L2_CID_EXPOSURE: 107762306a36Sopenharmony_ci setexposure(gspca_dev, ctrl->val, sd->gain->val); 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci return gspca_dev->usb_err; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = { 108462306a36Sopenharmony_ci .s_ctrl = sd_s_ctrl, 108562306a36Sopenharmony_ci}; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 109062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci gspca_dev->vdev.ctrl_handler = hdl; 109362306a36Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 2); 109462306a36Sopenharmony_ci sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 109562306a36Sopenharmony_ci V4L2_CID_EXPOSURE, 1, 0xfff, 1, 0x356); 109662306a36Sopenharmony_ci sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 109762306a36Sopenharmony_ci V4L2_CID_GAIN, 1, 255, 1, 0x8d); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (hdl->error) { 110062306a36Sopenharmony_ci pr_err("Could not initialize controls\n"); 110162306a36Sopenharmony_ci return hdl->error; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci v4l2_ctrl_cluster(2, &sd->exposure); 110462306a36Sopenharmony_ci return 0; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci/* sub-driver description */ 110862306a36Sopenharmony_cistatic const struct sd_desc sd_desc = { 110962306a36Sopenharmony_ci .name = MODULE_NAME, 111062306a36Sopenharmony_ci .config = sd_config, 111162306a36Sopenharmony_ci .init = sd_init, 111262306a36Sopenharmony_ci .init_controls = sd_init_controls, 111362306a36Sopenharmony_ci .isoc_init = sd_isoc_init, 111462306a36Sopenharmony_ci .start = sd_start, 111562306a36Sopenharmony_ci .stopN = sd_stopN, 111662306a36Sopenharmony_ci .pkt_scan = sd_pkt_scan, 111762306a36Sopenharmony_ci .dq_callback = sd_dq_callback, 111862306a36Sopenharmony_ci}; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci/* Table of supported USB devices */ 112162306a36Sopenharmony_ci#define ST(sensor, type) \ 112262306a36Sopenharmony_ci .driver_info = (SENSOR_ ## sensor << 8) \ 112362306a36Sopenharmony_ci | (type) 112462306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = { 112562306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, 112662306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, 112762306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, 112862306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, 112962306a36Sopenharmony_ci {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, 113062306a36Sopenharmony_ci {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, 113162306a36Sopenharmony_ci {} 113262306a36Sopenharmony_ci}; 113362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci/* -- device connect -- */ 113762306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, 113862306a36Sopenharmony_ci const struct usb_device_id *id) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 114162306a36Sopenharmony_ci THIS_MODULE); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic struct usb_driver sd_driver = { 114562306a36Sopenharmony_ci .name = MODULE_NAME, 114662306a36Sopenharmony_ci .id_table = device_table, 114762306a36Sopenharmony_ci .probe = sd_probe, 114862306a36Sopenharmony_ci .disconnect = gspca_disconnect, 114962306a36Sopenharmony_ci#ifdef CONFIG_PM 115062306a36Sopenharmony_ci .suspend = gspca_suspend, 115162306a36Sopenharmony_ci .resume = gspca_resume, 115262306a36Sopenharmony_ci .reset_resume = gspca_resume, 115362306a36Sopenharmony_ci#endif 115462306a36Sopenharmony_ci}; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cimodule_usb_driver(sd_driver); 1157