18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SQ930x subdriver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr> 68c2ecf20Sopenharmony_ci * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl> 78c2ecf20Sopenharmony_ci * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define MODULE_NAME "sq930x" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "gspca.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n" 178c2ecf20Sopenharmony_ci "Gerard Klaver <gerard at gkall dot hobby dot nl\n" 188c2ecf20Sopenharmony_ci "Sam Revitch <samr7@cs.washington.edu>"); 198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); 208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Structure to hold all of our device specific stuff */ 238c2ecf20Sopenharmony_cistruct sd { 248c2ecf20Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci struct { /* exposure/gain control cluster */ 278c2ecf20Sopenharmony_ci struct v4l2_ctrl *exposure; 288c2ecf20Sopenharmony_ci struct v4l2_ctrl *gain; 298c2ecf20Sopenharmony_ci }; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci u8 do_ctrl; 328c2ecf20Sopenharmony_ci u8 gpio[2]; 338c2ecf20Sopenharmony_ci u8 sensor; 348c2ecf20Sopenharmony_ci u8 type; 358c2ecf20Sopenharmony_ci#define Generic 0 368c2ecf20Sopenharmony_ci#define Creative_live_motion 1 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_cienum sensors { 398c2ecf20Sopenharmony_ci SENSOR_ICX098BQ, 408c2ecf20Sopenharmony_ci SENSOR_LZ24BP, 418c2ecf20Sopenharmony_ci SENSOR_MI0360, 428c2ecf20Sopenharmony_ci SENSOR_MT9V111, /* = MI360SOC */ 438c2ecf20Sopenharmony_ci SENSOR_OV7660, 448c2ecf20Sopenharmony_ci SENSOR_OV9630, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct v4l2_pix_format vga_mode[] = { 488c2ecf20Sopenharmony_ci {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, 498c2ecf20Sopenharmony_ci .bytesperline = 320, 508c2ecf20Sopenharmony_ci .sizeimage = 320 * 240, 518c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 528c2ecf20Sopenharmony_ci .priv = 0}, 538c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, 548c2ecf20Sopenharmony_ci .bytesperline = 640, 558c2ecf20Sopenharmony_ci .sizeimage = 640 * 480, 568c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 578c2ecf20Sopenharmony_ci .priv = 1}, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* sq930x registers */ 618c2ecf20Sopenharmony_ci#define SQ930_CTRL_UCBUS_IO 0x0001 628c2ecf20Sopenharmony_ci#define SQ930_CTRL_I2C_IO 0x0002 638c2ecf20Sopenharmony_ci#define SQ930_CTRL_GPIO 0x0005 648c2ecf20Sopenharmony_ci#define SQ930_CTRL_CAP_START 0x0010 658c2ecf20Sopenharmony_ci#define SQ930_CTRL_CAP_STOP 0x0011 668c2ecf20Sopenharmony_ci#define SQ930_CTRL_SET_EXPOSURE 0x001d 678c2ecf20Sopenharmony_ci#define SQ930_CTRL_RESET 0x001e 688c2ecf20Sopenharmony_ci#define SQ930_CTRL_GET_DEV_INFO 0x001f 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* gpio 1 (8..15) */ 718c2ecf20Sopenharmony_ci#define SQ930_GPIO_DFL_I2C_SDA 0x0001 728c2ecf20Sopenharmony_ci#define SQ930_GPIO_DFL_I2C_SCL 0x0002 738c2ecf20Sopenharmony_ci#define SQ930_GPIO_RSTBAR 0x0004 748c2ecf20Sopenharmony_ci#define SQ930_GPIO_EXTRA1 0x0040 758c2ecf20Sopenharmony_ci#define SQ930_GPIO_EXTRA2 0x0080 768c2ecf20Sopenharmony_ci/* gpio 3 (24..31) */ 778c2ecf20Sopenharmony_ci#define SQ930_GPIO_POWER 0x0200 788c2ecf20Sopenharmony_ci#define SQ930_GPIO_DFL_LED 0x1000 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct ucbus_write_cmd { 818c2ecf20Sopenharmony_ci u16 bw_addr; 828c2ecf20Sopenharmony_ci u8 bw_data; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_cistruct i2c_write_cmd { 858c2ecf20Sopenharmony_ci u8 reg; 868c2ecf20Sopenharmony_ci u16 val; 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd icx098bq_start_0[] = { 908c2ecf20Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, 918c2ecf20Sopenharmony_ci {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, 928c2ecf20Sopenharmony_ci {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, 938c2ecf20Sopenharmony_ci {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, 948c2ecf20Sopenharmony_ci {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, 958c2ecf20Sopenharmony_ci {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, 968c2ecf20Sopenharmony_ci {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, 978c2ecf20Sopenharmony_ci {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, 988c2ecf20Sopenharmony_ci {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, 998c2ecf20Sopenharmony_ci {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, 1008c2ecf20Sopenharmony_ci {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, 1018c2ecf20Sopenharmony_ci {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, 1028c2ecf20Sopenharmony_ci {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, 1038c2ecf20Sopenharmony_ci {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, 1048c2ecf20Sopenharmony_ci {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, 1058c2ecf20Sopenharmony_ci {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, 1068c2ecf20Sopenharmony_ci {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, 1078c2ecf20Sopenharmony_ci {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, 1088c2ecf20Sopenharmony_ci {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, 1098c2ecf20Sopenharmony_ci {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, 1108c2ecf20Sopenharmony_ci {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, 1118c2ecf20Sopenharmony_ci {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, 1128c2ecf20Sopenharmony_ci {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, 1138c2ecf20Sopenharmony_ci {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, 1148c2ecf20Sopenharmony_ci {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, 1158c2ecf20Sopenharmony_ci {0xf800, 0x03} 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd icx098bq_start_1[] = { 1188c2ecf20Sopenharmony_ci {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 1198c2ecf20Sopenharmony_ci {0xf5f4, 0xc0}, 1208c2ecf20Sopenharmony_ci {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 1218c2ecf20Sopenharmony_ci {0xf5f4, 0xc0}, 1228c2ecf20Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 1238c2ecf20Sopenharmony_ci {0xf5f9, 0x00} 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd icx098bq_start_2[] = { 1278c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, 1288c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 1298c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, 1308c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 1318c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, 1328c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 1338c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, 1348c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03} 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_0[] = { 1388c2ecf20Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, 1398c2ecf20Sopenharmony_ci {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, 1408c2ecf20Sopenharmony_ci {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, 1418c2ecf20Sopenharmony_ci {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, 1428c2ecf20Sopenharmony_ci {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, 1438c2ecf20Sopenharmony_ci {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, 1448c2ecf20Sopenharmony_ci {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, 1458c2ecf20Sopenharmony_ci {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, 1468c2ecf20Sopenharmony_ci {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, 1478c2ecf20Sopenharmony_ci {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, 1488c2ecf20Sopenharmony_ci {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, 1498c2ecf20Sopenharmony_ci {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, 1508c2ecf20Sopenharmony_ci {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, 1518c2ecf20Sopenharmony_ci {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, 1528c2ecf20Sopenharmony_ci {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, 1538c2ecf20Sopenharmony_ci {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, 1548c2ecf20Sopenharmony_ci {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, 1558c2ecf20Sopenharmony_ci {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, 1568c2ecf20Sopenharmony_ci {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, 1578c2ecf20Sopenharmony_ci {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, 1588c2ecf20Sopenharmony_ci {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, 1598c2ecf20Sopenharmony_ci {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, 1608c2ecf20Sopenharmony_ci {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, 1618c2ecf20Sopenharmony_ci {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, 1628c2ecf20Sopenharmony_ci {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, 1638c2ecf20Sopenharmony_ci {0xf800, 0x03} 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_1_gen[] = { 1668c2ecf20Sopenharmony_ci {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 1678c2ecf20Sopenharmony_ci {0xf5f4, 0xb3}, 1688c2ecf20Sopenharmony_ci {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 1698c2ecf20Sopenharmony_ci {0xf5f4, 0xb3}, 1708c2ecf20Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 1718c2ecf20Sopenharmony_ci {0xf5f9, 0x00} 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_1_clm[] = { 1758c2ecf20Sopenharmony_ci {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, 1768c2ecf20Sopenharmony_ci {0xf5f4, 0xc0}, 1778c2ecf20Sopenharmony_ci {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, 1788c2ecf20Sopenharmony_ci {0xf5f4, 0xc0}, 1798c2ecf20Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 1808c2ecf20Sopenharmony_ci {0xf5f9, 0x00} 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd lz24bp_start_2[] = { 1848c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, 1858c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 1868c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, 1878c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 1888c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, 1898c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03}, 1908c2ecf20Sopenharmony_ci {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, 1918c2ecf20Sopenharmony_ci {0xf807, 0x7f}, {0xf800, 0x03} 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd mi0360_start_0[] = { 1958c2ecf20Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, 1968c2ecf20Sopenharmony_ci {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mi0360_init_23[] = { 1998c2ecf20Sopenharmony_ci {0x30, 0x0040}, /* reserved - def 0x0005 */ 2008c2ecf20Sopenharmony_ci {0x31, 0x0000}, /* reserved - def 0x002a */ 2018c2ecf20Sopenharmony_ci {0x34, 0x0100}, /* reserved - def 0x0100 */ 2028c2ecf20Sopenharmony_ci {0x3d, 0x068f}, /* reserved - def 0x068f */ 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mi0360_init_24[] = { 2058c2ecf20Sopenharmony_ci {0x03, 0x01e5}, /* window height */ 2068c2ecf20Sopenharmony_ci {0x04, 0x0285}, /* window width */ 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mi0360_init_25[] = { 2098c2ecf20Sopenharmony_ci {0x35, 0x0020}, /* global gain */ 2108c2ecf20Sopenharmony_ci {0x2b, 0x0020}, /* green1 gain */ 2118c2ecf20Sopenharmony_ci {0x2c, 0x002a}, /* blue gain */ 2128c2ecf20Sopenharmony_ci {0x2d, 0x0028}, /* red gain */ 2138c2ecf20Sopenharmony_ci {0x2e, 0x0020}, /* green2 gain */ 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd mi0360_start_1[] = { 2168c2ecf20Sopenharmony_ci {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 2178c2ecf20Sopenharmony_ci {0xf5f4, 0xa6}, 2188c2ecf20Sopenharmony_ci {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 2198c2ecf20Sopenharmony_ci {0xf5f4, 0xa6}, 2208c2ecf20Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, 2218c2ecf20Sopenharmony_ci {0xf5f9, 0x00} 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mi0360_start_2[] = { 2248c2ecf20Sopenharmony_ci {0x62, 0x041d}, /* reserved - def 0x0418 */ 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mi0360_start_3[] = { 2278c2ecf20Sopenharmony_ci {0x05, 0x007b}, /* horiz blanking */ 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mi0360_start_4[] = { 2308c2ecf20Sopenharmony_ci {0x05, 0x03f5}, /* horiz blanking */ 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_0[] = { 2348c2ecf20Sopenharmony_ci {0x01, 0x0001}, /* select IFP/SOC registers */ 2358c2ecf20Sopenharmony_ci {0x06, 0x300c}, /* operating mode control */ 2368c2ecf20Sopenharmony_ci {0x08, 0xcc00}, /* output format control (RGB) */ 2378c2ecf20Sopenharmony_ci {0x01, 0x0004}, /* select sensor core registers */ 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_1[] = { 2408c2ecf20Sopenharmony_ci {0x03, 0x01e5}, /* window height */ 2418c2ecf20Sopenharmony_ci {0x04, 0x0285}, /* window width */ 2428c2ecf20Sopenharmony_ci}; 2438c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_2[] = { 2448c2ecf20Sopenharmony_ci {0x30, 0x7800}, 2458c2ecf20Sopenharmony_ci {0x31, 0x0000}, 2468c2ecf20Sopenharmony_ci {0x07, 0x3002}, /* output control */ 2478c2ecf20Sopenharmony_ci {0x35, 0x0020}, /* global gain */ 2488c2ecf20Sopenharmony_ci {0x2b, 0x0020}, /* green1 gain */ 2498c2ecf20Sopenharmony_ci {0x2c, 0x0020}, /* blue gain */ 2508c2ecf20Sopenharmony_ci {0x2d, 0x0020}, /* red gain */ 2518c2ecf20Sopenharmony_ci {0x2e, 0x0020}, /* green2 gain */ 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd mt9v111_start_1[] = { 2548c2ecf20Sopenharmony_ci {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 2558c2ecf20Sopenharmony_ci {0xf5f4, 0xaa}, 2568c2ecf20Sopenharmony_ci {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, 2578c2ecf20Sopenharmony_ci {0xf5f4, 0xaa}, 2588c2ecf20Sopenharmony_ci {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a}, 2598c2ecf20Sopenharmony_ci {0xf5f9, 0x0a} 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_3[] = { 2628c2ecf20Sopenharmony_ci {0x62, 0x0405}, 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_cistatic const struct i2c_write_cmd mt9v111_init_4[] = { 2658c2ecf20Sopenharmony_ci/* {0x05, 0x00ce}, */ 2668c2ecf20Sopenharmony_ci {0x05, 0x005d}, /* horizontal blanking */ 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd ov7660_start_0[] = { 2708c2ecf20Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0}, 2718c2ecf20Sopenharmony_ci {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03} 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic const struct ucbus_write_cmd ov9630_start_0[] = { 2758c2ecf20Sopenharmony_ci {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00}, 2768c2ecf20Sopenharmony_ci {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03} 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* start parameters indexed by [sensor][mode] */ 2808c2ecf20Sopenharmony_cistatic const struct cap_s { 2818c2ecf20Sopenharmony_ci u8 cc_sizeid; 2828c2ecf20Sopenharmony_ci u8 cc_bytes[32]; 2838c2ecf20Sopenharmony_ci} capconfig[4][2] = { 2848c2ecf20Sopenharmony_ci [SENSOR_ICX098BQ] = { 2858c2ecf20Sopenharmony_ci {2, /* Bayer 320x240 */ 2868c2ecf20Sopenharmony_ci {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, 2878c2ecf20Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 2888c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 2898c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 2908c2ecf20Sopenharmony_ci {4, /* Bayer 640x480 */ 2918c2ecf20Sopenharmony_ci {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, 2928c2ecf20Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 2938c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2948c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 2958c2ecf20Sopenharmony_ci }, 2968c2ecf20Sopenharmony_ci [SENSOR_LZ24BP] = { 2978c2ecf20Sopenharmony_ci {2, /* Bayer 320x240 */ 2988c2ecf20Sopenharmony_ci {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, 2998c2ecf20Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 3008c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3018c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 3028c2ecf20Sopenharmony_ci {4, /* Bayer 640x480 */ 3038c2ecf20Sopenharmony_ci {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, 3048c2ecf20Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 3058c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3068c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 3078c2ecf20Sopenharmony_ci }, 3088c2ecf20Sopenharmony_ci [SENSOR_MI0360] = { 3098c2ecf20Sopenharmony_ci {2, /* Bayer 320x240 */ 3108c2ecf20Sopenharmony_ci {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 3118c2ecf20Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 3128c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3138c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 3148c2ecf20Sopenharmony_ci {4, /* Bayer 640x480 */ 3158c2ecf20Sopenharmony_ci {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 3168c2ecf20Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 3178c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3188c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 3198c2ecf20Sopenharmony_ci }, 3208c2ecf20Sopenharmony_ci [SENSOR_MT9V111] = { 3218c2ecf20Sopenharmony_ci {2, /* Bayer 320x240 */ 3228c2ecf20Sopenharmony_ci {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 3238c2ecf20Sopenharmony_ci 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 3248c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3258c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 3268c2ecf20Sopenharmony_ci {4, /* Bayer 640x480 */ 3278c2ecf20Sopenharmony_ci {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, 3288c2ecf20Sopenharmony_ci 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, 3298c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3308c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, 3318c2ecf20Sopenharmony_ci }, 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistruct sensor_s { 3358c2ecf20Sopenharmony_ci const char *name; 3368c2ecf20Sopenharmony_ci u8 i2c_addr; 3378c2ecf20Sopenharmony_ci u8 i2c_dum; 3388c2ecf20Sopenharmony_ci u8 gpio[5]; 3398c2ecf20Sopenharmony_ci u8 cmd_len; 3408c2ecf20Sopenharmony_ci const struct ucbus_write_cmd *cmd; 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic const struct sensor_s sensor_tb[] = { 3448c2ecf20Sopenharmony_ci [SENSOR_ICX098BQ] = { 3458c2ecf20Sopenharmony_ci "icx098bp", 3468c2ecf20Sopenharmony_ci 0x00, 0x00, 3478c2ecf20Sopenharmony_ci {0, 3488c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 3498c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 3508c2ecf20Sopenharmony_ci 0, 3518c2ecf20Sopenharmony_ci SQ930_GPIO_RSTBAR 3528c2ecf20Sopenharmony_ci }, 3538c2ecf20Sopenharmony_ci 8, icx098bq_start_0 3548c2ecf20Sopenharmony_ci }, 3558c2ecf20Sopenharmony_ci [SENSOR_LZ24BP] = { 3568c2ecf20Sopenharmony_ci "lz24bp", 3578c2ecf20Sopenharmony_ci 0x00, 0x00, 3588c2ecf20Sopenharmony_ci {0, 3598c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 3608c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 3618c2ecf20Sopenharmony_ci 0, 3628c2ecf20Sopenharmony_ci SQ930_GPIO_RSTBAR 3638c2ecf20Sopenharmony_ci }, 3648c2ecf20Sopenharmony_ci 8, lz24bp_start_0 3658c2ecf20Sopenharmony_ci }, 3668c2ecf20Sopenharmony_ci [SENSOR_MI0360] = { 3678c2ecf20Sopenharmony_ci "mi0360", 3688c2ecf20Sopenharmony_ci 0x5d, 0x80, 3698c2ecf20Sopenharmony_ci {SQ930_GPIO_RSTBAR, 3708c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 3718c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 3728c2ecf20Sopenharmony_ci 0, 3738c2ecf20Sopenharmony_ci 0 3748c2ecf20Sopenharmony_ci }, 3758c2ecf20Sopenharmony_ci 7, mi0360_start_0 3768c2ecf20Sopenharmony_ci }, 3778c2ecf20Sopenharmony_ci [SENSOR_MT9V111] = { 3788c2ecf20Sopenharmony_ci "mt9v111", 3798c2ecf20Sopenharmony_ci 0x5c, 0x7f, 3808c2ecf20Sopenharmony_ci {SQ930_GPIO_RSTBAR, 3818c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 3828c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 3838c2ecf20Sopenharmony_ci 0, 3848c2ecf20Sopenharmony_ci 0 3858c2ecf20Sopenharmony_ci }, 3868c2ecf20Sopenharmony_ci 7, mi0360_start_0 3878c2ecf20Sopenharmony_ci }, 3888c2ecf20Sopenharmony_ci [SENSOR_OV7660] = { 3898c2ecf20Sopenharmony_ci "ov7660", 3908c2ecf20Sopenharmony_ci 0x21, 0x00, 3918c2ecf20Sopenharmony_ci {0, 3928c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 3938c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 3948c2ecf20Sopenharmony_ci 0, 3958c2ecf20Sopenharmony_ci SQ930_GPIO_RSTBAR 3968c2ecf20Sopenharmony_ci }, 3978c2ecf20Sopenharmony_ci 7, ov7660_start_0 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci [SENSOR_OV9630] = { 4008c2ecf20Sopenharmony_ci "ov9630", 4018c2ecf20Sopenharmony_ci 0x30, 0x00, 4028c2ecf20Sopenharmony_ci {0, 4038c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, 4048c2ecf20Sopenharmony_ci SQ930_GPIO_DFL_I2C_SDA, 4058c2ecf20Sopenharmony_ci 0, 4068c2ecf20Sopenharmony_ci SQ930_GPIO_RSTBAR 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci 7, ov9630_start_0 4098c2ecf20Sopenharmony_ci }, 4108c2ecf20Sopenharmony_ci}; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic void reg_r(struct gspca_dev *gspca_dev, 4138c2ecf20Sopenharmony_ci u16 value, int len) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci int ret; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 4188c2ecf20Sopenharmony_ci return; 4198c2ecf20Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 4208c2ecf20Sopenharmony_ci usb_rcvctrlpipe(gspca_dev->dev, 0), 4218c2ecf20Sopenharmony_ci 0x0c, 4228c2ecf20Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 4238c2ecf20Sopenharmony_ci value, 0, gspca_dev->usb_buf, len, 4248c2ecf20Sopenharmony_ci 500); 4258c2ecf20Sopenharmony_ci if (ret < 0) { 4268c2ecf20Sopenharmony_ci pr_err("reg_r %04x failed %d\n", value, ret); 4278c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * Make sure the buffer is zeroed to avoid uninitialized 4308c2ecf20Sopenharmony_ci * values. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci int ret; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 4418c2ecf20Sopenharmony_ci return; 4428c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "reg_w v: %04x i: %04x\n", value, index); 4438c2ecf20Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 4448c2ecf20Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 4458c2ecf20Sopenharmony_ci 0x0c, /* request */ 4468c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 4478c2ecf20Sopenharmony_ci value, index, NULL, 0, 4488c2ecf20Sopenharmony_ci 500); 4498c2ecf20Sopenharmony_ci msleep(30); 4508c2ecf20Sopenharmony_ci if (ret < 0) { 4518c2ecf20Sopenharmony_ci pr_err("reg_w %04x %04x failed %d\n", value, index, ret); 4528c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, 4578c2ecf20Sopenharmony_ci const u8 *data, int len) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci int ret; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 4628c2ecf20Sopenharmony_ci return; 4638c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "reg_wb v: %04x i: %04x %02x...%02x\n", 4648c2ecf20Sopenharmony_ci value, index, *data, data[len - 1]); 4658c2ecf20Sopenharmony_ci memcpy(gspca_dev->usb_buf, data, len); 4668c2ecf20Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 4678c2ecf20Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 4688c2ecf20Sopenharmony_ci 0x0c, /* request */ 4698c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 4708c2ecf20Sopenharmony_ci value, index, gspca_dev->usb_buf, len, 4718c2ecf20Sopenharmony_ci 1000); 4728c2ecf20Sopenharmony_ci msleep(30); 4738c2ecf20Sopenharmony_ci if (ret < 0) { 4748c2ecf20Sopenharmony_ci pr_err("reg_wb %04x %04x failed %d\n", value, index, ret); 4758c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void i2c_write(struct sd *sd, 4808c2ecf20Sopenharmony_ci const struct i2c_write_cmd *cmd, 4818c2ecf20Sopenharmony_ci int ncmds) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 4848c2ecf20Sopenharmony_ci const struct sensor_s *sensor; 4858c2ecf20Sopenharmony_ci u16 val, idx; 4868c2ecf20Sopenharmony_ci u8 *buf; 4878c2ecf20Sopenharmony_ci int ret; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 4908c2ecf20Sopenharmony_ci return; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci sensor = &sensor_tb[sd->sensor]; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO; 4958c2ecf20Sopenharmony_ci idx = (cmd->val & 0xff00) | cmd->reg; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci buf = gspca_dev->usb_buf; 4988c2ecf20Sopenharmony_ci *buf++ = sensor->i2c_dum; 4998c2ecf20Sopenharmony_ci *buf++ = cmd->val; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci while (--ncmds > 0) { 5028c2ecf20Sopenharmony_ci cmd++; 5038c2ecf20Sopenharmony_ci *buf++ = cmd->reg; 5048c2ecf20Sopenharmony_ci *buf++ = cmd->val >> 8; 5058c2ecf20Sopenharmony_ci *buf++ = sensor->i2c_dum; 5068c2ecf20Sopenharmony_ci *buf++ = cmd->val; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "i2c_w v: %04x i: %04x %02x...%02x\n", 5108c2ecf20Sopenharmony_ci val, idx, gspca_dev->usb_buf[0], buf[-1]); 5118c2ecf20Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 5128c2ecf20Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 5138c2ecf20Sopenharmony_ci 0x0c, /* request */ 5148c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 5158c2ecf20Sopenharmony_ci val, idx, 5168c2ecf20Sopenharmony_ci gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 5178c2ecf20Sopenharmony_ci 500); 5188c2ecf20Sopenharmony_ci if (ret < 0) { 5198c2ecf20Sopenharmony_ci pr_err("i2c_write failed %d\n", ret); 5208c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void ucbus_write(struct gspca_dev *gspca_dev, 5258c2ecf20Sopenharmony_ci const struct ucbus_write_cmd *cmd, 5268c2ecf20Sopenharmony_ci int ncmds, 5278c2ecf20Sopenharmony_ci int batchsize) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci u8 *buf; 5308c2ecf20Sopenharmony_ci u16 val, idx; 5318c2ecf20Sopenharmony_ci int len, ret; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 5348c2ecf20Sopenharmony_ci return; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if ((batchsize - 1) * 3 > USB_BUF_SZ) { 5378c2ecf20Sopenharmony_ci gspca_err(gspca_dev, "Bug: usb_buf overflow\n"); 5388c2ecf20Sopenharmony_ci gspca_dev->usb_err = -ENOMEM; 5398c2ecf20Sopenharmony_ci return; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci for (;;) { 5438c2ecf20Sopenharmony_ci len = ncmds; 5448c2ecf20Sopenharmony_ci if (len > batchsize) 5458c2ecf20Sopenharmony_ci len = batchsize; 5468c2ecf20Sopenharmony_ci ncmds -= len; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; 5498c2ecf20Sopenharmony_ci idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci buf = gspca_dev->usb_buf; 5528c2ecf20Sopenharmony_ci while (--len > 0) { 5538c2ecf20Sopenharmony_ci cmd++; 5548c2ecf20Sopenharmony_ci *buf++ = cmd->bw_addr; 5558c2ecf20Sopenharmony_ci *buf++ = cmd->bw_addr >> 8; 5568c2ecf20Sopenharmony_ci *buf++ = cmd->bw_data; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci if (buf != gspca_dev->usb_buf) 5598c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "ucbus v: %04x i: %04x %02x...%02x\n", 5608c2ecf20Sopenharmony_ci val, idx, 5618c2ecf20Sopenharmony_ci gspca_dev->usb_buf[0], buf[-1]); 5628c2ecf20Sopenharmony_ci else 5638c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "ucbus v: %04x i: %04x\n", 5648c2ecf20Sopenharmony_ci val, idx); 5658c2ecf20Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 5668c2ecf20Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 5678c2ecf20Sopenharmony_ci 0x0c, /* request */ 5688c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 5698c2ecf20Sopenharmony_ci val, idx, 5708c2ecf20Sopenharmony_ci gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 5718c2ecf20Sopenharmony_ci 500); 5728c2ecf20Sopenharmony_ci if (ret < 0) { 5738c2ecf20Sopenharmony_ci pr_err("ucbus_write failed %d\n", ret); 5748c2ecf20Sopenharmony_ci gspca_dev->usb_err = ret; 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci msleep(30); 5788c2ecf20Sopenharmony_ci if (ncmds <= 0) 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci cmd++; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic void gpio_set(struct sd *sd, u16 val, u16 mask) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = &sd->gspca_dev; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (mask & 0x00ff) { 5898c2ecf20Sopenharmony_ci sd->gpio[0] &= ~mask; 5908c2ecf20Sopenharmony_ci sd->gpio[0] |= val; 5918c2ecf20Sopenharmony_ci reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, 5928c2ecf20Sopenharmony_ci ~sd->gpio[0] << 8); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci mask >>= 8; 5958c2ecf20Sopenharmony_ci val >>= 8; 5968c2ecf20Sopenharmony_ci if (mask) { 5978c2ecf20Sopenharmony_ci sd->gpio[1] &= ~mask; 5988c2ecf20Sopenharmony_ci sd->gpio[1] |= val; 5998c2ecf20Sopenharmony_ci reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, 6008c2ecf20Sopenharmony_ci ~sd->gpio[1] << 8); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic void gpio_init(struct sd *sd, 6058c2ecf20Sopenharmony_ci const u8 *gpio) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 6088c2ecf20Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 6098c2ecf20Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 6108c2ecf20Sopenharmony_ci gpio_set(sd, *gpio++, 0x000f); 6118c2ecf20Sopenharmony_ci gpio_set(sd, *gpio, 0x000f); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic void bridge_init(struct sd *sd) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci static const struct ucbus_write_cmd clkfreq_cmd = { 6178c2ecf20Sopenharmony_ci 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ 6188c2ecf20Sopenharmony_ci }; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci gpio_set(sd, SQ930_GPIO_POWER, 0xff00); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic void cmos_probe(struct gspca_dev *gspca_dev) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 6288c2ecf20Sopenharmony_ci int i; 6298c2ecf20Sopenharmony_ci const struct sensor_s *sensor; 6308c2ecf20Sopenharmony_ci static const u8 probe_order[] = { 6318c2ecf20Sopenharmony_ci/* SENSOR_LZ24BP, (tested as ccd) */ 6328c2ecf20Sopenharmony_ci SENSOR_OV9630, 6338c2ecf20Sopenharmony_ci SENSOR_MI0360, 6348c2ecf20Sopenharmony_ci SENSOR_OV7660, 6358c2ecf20Sopenharmony_ci SENSOR_MT9V111, 6368c2ecf20Sopenharmony_ci }; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(probe_order); i++) { 6398c2ecf20Sopenharmony_ci sensor = &sensor_tb[probe_order[i]]; 6408c2ecf20Sopenharmony_ci ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8); 6418c2ecf20Sopenharmony_ci gpio_init(sd, sensor->gpio); 6428c2ecf20Sopenharmony_ci msleep(100); 6438c2ecf20Sopenharmony_ci reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1); 6448c2ecf20Sopenharmony_ci msleep(100); 6458c2ecf20Sopenharmony_ci if (gspca_dev->usb_buf[0] != 0) 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(probe_order)) { 6498c2ecf20Sopenharmony_ci pr_err("Unknown sensor\n"); 6508c2ecf20Sopenharmony_ci gspca_dev->usb_err = -EINVAL; 6518c2ecf20Sopenharmony_ci return; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci sd->sensor = probe_order[i]; 6548c2ecf20Sopenharmony_ci switch (sd->sensor) { 6558c2ecf20Sopenharmony_ci case SENSOR_OV7660: 6568c2ecf20Sopenharmony_ci case SENSOR_OV9630: 6578c2ecf20Sopenharmony_ci pr_err("Sensor %s not yet treated\n", 6588c2ecf20Sopenharmony_ci sensor_tb[sd->sensor].name); 6598c2ecf20Sopenharmony_ci gspca_dev->usb_err = -EINVAL; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void mt9v111_init(struct gspca_dev *gspca_dev) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci int i, nwait; 6678c2ecf20Sopenharmony_ci static const u8 cmd_001b[] = { 6688c2ecf20Sopenharmony_ci 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00, 6698c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00 6708c2ecf20Sopenharmony_ci }; 6718c2ecf20Sopenharmony_ci static const u8 cmd_011b[][7] = { 6728c2ecf20Sopenharmony_ci {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00}, 6738c2ecf20Sopenharmony_ci {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00}, 6748c2ecf20Sopenharmony_ci {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00}, 6758c2ecf20Sopenharmony_ci {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00}, 6768c2ecf20Sopenharmony_ci }; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b); 6798c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) { 6808c2ecf20Sopenharmony_ci reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i], 6818c2ecf20Sopenharmony_ci ARRAY_SIZE(cmd_011b[0])); 6828c2ecf20Sopenharmony_ci msleep(400); 6838c2ecf20Sopenharmony_ci nwait = 20; 6848c2ecf20Sopenharmony_ci for (;;) { 6858c2ecf20Sopenharmony_ci reg_r(gspca_dev, 0x031b, 1); 6868c2ecf20Sopenharmony_ci if (gspca_dev->usb_buf[0] == 0 6878c2ecf20Sopenharmony_ci || gspca_dev->usb_err != 0) 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci if (--nwait < 0) { 6908c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "mt9v111_init timeout\n"); 6918c2ecf20Sopenharmony_ci gspca_dev->usb_err = -ETIME; 6928c2ecf20Sopenharmony_ci return; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci msleep(50); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void global_init(struct sd *sd, int first_time) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci switch (sd->sensor) { 7028c2ecf20Sopenharmony_ci case SENSOR_ICX098BQ: 7038c2ecf20Sopenharmony_ci if (first_time) 7048c2ecf20Sopenharmony_ci ucbus_write(&sd->gspca_dev, 7058c2ecf20Sopenharmony_ci icx098bq_start_0, 7068c2ecf20Sopenharmony_ci 8, 8); 7078c2ecf20Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci case SENSOR_LZ24BP: 7108c2ecf20Sopenharmony_ci if (sd->type != Creative_live_motion) 7118c2ecf20Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci gpio_set(sd, 0, 0x00ff); 7148c2ecf20Sopenharmony_ci msleep(50); 7158c2ecf20Sopenharmony_ci if (first_time) 7168c2ecf20Sopenharmony_ci ucbus_write(&sd->gspca_dev, 7178c2ecf20Sopenharmony_ci lz24bp_start_0, 7188c2ecf20Sopenharmony_ci 8, 8); 7198c2ecf20Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci case SENSOR_MI0360: 7228c2ecf20Sopenharmony_ci if (first_time) 7238c2ecf20Sopenharmony_ci ucbus_write(&sd->gspca_dev, 7248c2ecf20Sopenharmony_ci mi0360_start_0, 7258c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_start_0), 7268c2ecf20Sopenharmony_ci 8); 7278c2ecf20Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 7288c2ecf20Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci default: 7318c2ecf20Sopenharmony_ci/* case SENSOR_MT9V111: */ 7328c2ecf20Sopenharmony_ci if (first_time) 7338c2ecf20Sopenharmony_ci mt9v111_init(&sd->gspca_dev); 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci gpio_init(sd, sensor_tb[sd->sensor].gpio); 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic void lz24bp_ppl(struct sd *sd, u16 ppl) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct ucbus_write_cmd cmds[2] = { 7438c2ecf20Sopenharmony_ci {0xf810, ppl >> 8}, 7448c2ecf20Sopenharmony_ci {0xf811, ppl} 7458c2ecf20Sopenharmony_ci }; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 7538c2ecf20Sopenharmony_ci int i, integclks, intstartclk, frameclks, min_frclk; 7548c2ecf20Sopenharmony_ci const struct sensor_s *sensor; 7558c2ecf20Sopenharmony_ci u16 cmd; 7568c2ecf20Sopenharmony_ci u8 buf[15]; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci integclks = expo; 7598c2ecf20Sopenharmony_ci i = 0; 7608c2ecf20Sopenharmony_ci cmd = SQ930_CTRL_SET_EXPOSURE; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci switch (sd->sensor) { 7638c2ecf20Sopenharmony_ci case SENSOR_ICX098BQ: /* ccd */ 7648c2ecf20Sopenharmony_ci case SENSOR_LZ24BP: 7658c2ecf20Sopenharmony_ci min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; 7668c2ecf20Sopenharmony_ci if (integclks >= min_frclk) { 7678c2ecf20Sopenharmony_ci intstartclk = 0; 7688c2ecf20Sopenharmony_ci frameclks = integclks; 7698c2ecf20Sopenharmony_ci } else { 7708c2ecf20Sopenharmony_ci intstartclk = min_frclk - integclks; 7718c2ecf20Sopenharmony_ci frameclks = min_frclk; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci buf[i++] = intstartclk >> 8; 7748c2ecf20Sopenharmony_ci buf[i++] = intstartclk; 7758c2ecf20Sopenharmony_ci buf[i++] = frameclks >> 8; 7768c2ecf20Sopenharmony_ci buf[i++] = frameclks; 7778c2ecf20Sopenharmony_ci buf[i++] = gain; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci default: /* cmos */ 7808c2ecf20Sopenharmony_ci/* case SENSOR_MI0360: */ 7818c2ecf20Sopenharmony_ci/* case SENSOR_MT9V111: */ 7828c2ecf20Sopenharmony_ci cmd |= 0x0100; 7838c2ecf20Sopenharmony_ci sensor = &sensor_tb[sd->sensor]; 7848c2ecf20Sopenharmony_ci buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */ 7858c2ecf20Sopenharmony_ci buf[i++] = 0x08; /* 2 * ni2c */ 7868c2ecf20Sopenharmony_ci buf[i++] = 0x09; /* reg = shutter width */ 7878c2ecf20Sopenharmony_ci buf[i++] = integclks >> 8; /* val H */ 7888c2ecf20Sopenharmony_ci buf[i++] = sensor->i2c_dum; 7898c2ecf20Sopenharmony_ci buf[i++] = integclks; /* val L */ 7908c2ecf20Sopenharmony_ci buf[i++] = 0x35; /* reg = global gain */ 7918c2ecf20Sopenharmony_ci buf[i++] = 0x00; /* val H */ 7928c2ecf20Sopenharmony_ci buf[i++] = sensor->i2c_dum; 7938c2ecf20Sopenharmony_ci buf[i++] = 0x80 + gain / 2; /* val L */ 7948c2ecf20Sopenharmony_ci buf[i++] = 0x00; 7958c2ecf20Sopenharmony_ci buf[i++] = 0x00; 7968c2ecf20Sopenharmony_ci buf[i++] = 0x00; 7978c2ecf20Sopenharmony_ci buf[i++] = 0x00; 7988c2ecf20Sopenharmony_ci buf[i++] = 0x83; 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci reg_wb(gspca_dev, cmd, 0, buf, i); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/* This function is called at probe time just before sd_init */ 8058c2ecf20Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 8068c2ecf20Sopenharmony_ci const struct usb_device_id *id) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 8098c2ecf20Sopenharmony_ci struct cam *cam = &gspca_dev->cam; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci sd->sensor = id->driver_info >> 8; 8128c2ecf20Sopenharmony_ci sd->type = id->driver_info; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci cam->cam_mode = vga_mode; 8158c2ecf20Sopenharmony_ci cam->nmodes = ARRAY_SIZE(vga_mode); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci cam->bulk = 1; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */ 8238c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/*fixme: is this needed for icx098bp and mi0360? 8308c2ecf20Sopenharmony_ci if (sd->sensor != SENSOR_LZ24BP) 8318c2ecf20Sopenharmony_ci reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); 8358c2ecf20Sopenharmony_ci if (gspca_dev->usb_err < 0) 8368c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/* it returns: 8398c2ecf20Sopenharmony_ci * 03 00 12 93 0b f6 c9 00 live! ultra 8408c2ecf20Sopenharmony_ci * 03 00 07 93 0b f6 ca 00 live! ultra for notebook 8418c2ecf20Sopenharmony_ci * 03 00 12 93 0b fe c8 00 Trust WB-3500T 8428c2ecf20Sopenharmony_ci * 02 00 06 93 0b fe c8 00 Joy-IT 318S 8438c2ecf20Sopenharmony_ci * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq 8448c2ecf20Sopenharmony_ci * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam 8458c2ecf20Sopenharmony_ci * 8468c2ecf20Sopenharmony_ci * byte 8478c2ecf20Sopenharmony_ci * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) 8488c2ecf20Sopenharmony_ci * 1: 00 8498c2ecf20Sopenharmony_ci * 2: 06 / 07 / 12 = mode webcam? firmware?? 8508c2ecf20Sopenharmony_ci * 3: 93 chip = 930b (930b or 930c) 8518c2ecf20Sopenharmony_ci * 4: 0b 8528c2ecf20Sopenharmony_ci * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors) 8538c2ecf20Sopenharmony_ci * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? 8548c2ecf20Sopenharmony_ci * 7: 00 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "info: %*ph\n", 8, gspca_dev->usb_buf); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci bridge_init(sd); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_MI0360) { 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* no sensor probe for icam tracer */ 8638c2ecf20Sopenharmony_ci if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */ 8648c2ecf20Sopenharmony_ci sd->sensor = SENSOR_ICX098BQ; 8658c2ecf20Sopenharmony_ci else 8668c2ecf20Sopenharmony_ci cmos_probe(gspca_dev); 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci if (gspca_dev->usb_err >= 0) { 8698c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Sensor %s\n", 8708c2ecf20Sopenharmony_ci sensor_tb[sd->sensor].name); 8718c2ecf20Sopenharmony_ci global_init(sd, 1); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci/* send the start/stop commands to the webcam */ 8778c2ecf20Sopenharmony_cistatic void send_start(struct gspca_dev *gspca_dev) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 8808c2ecf20Sopenharmony_ci const struct cap_s *cap; 8818c2ecf20Sopenharmony_ci int mode; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 8848c2ecf20Sopenharmony_ci cap = &capconfig[sd->sensor][mode]; 8858c2ecf20Sopenharmony_ci reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START, 8868c2ecf20Sopenharmony_ci 0x0a00 | cap->cc_sizeid, 8878c2ecf20Sopenharmony_ci cap->cc_bytes, 32); 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic void send_stop(struct gspca_dev *gspca_dev) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci/* function called at start time before URB creation */ 8968c2ecf20Sopenharmony_cistatic int sd_isoc_init(struct gspca_dev *gspca_dev) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ 9018c2ecf20Sopenharmony_ci sd->do_ctrl = 0; 9028c2ecf20Sopenharmony_ci gspca_dev->cam.bulk_size = gspca_dev->pixfmt.width * 9038c2ecf20Sopenharmony_ci gspca_dev->pixfmt.height + 8; 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/* start the capture */ 9088c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 9118c2ecf20Sopenharmony_ci int mode; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci bridge_init(sd); 9148c2ecf20Sopenharmony_ci global_init(sd, 0); 9158c2ecf20Sopenharmony_ci msleep(100); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci switch (sd->sensor) { 9188c2ecf20Sopenharmony_ci case SENSOR_ICX098BQ: 9198c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, icx098bq_start_0, 9208c2ecf20Sopenharmony_ci ARRAY_SIZE(icx098bq_start_0), 9218c2ecf20Sopenharmony_ci 8); 9228c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, icx098bq_start_1, 9238c2ecf20Sopenharmony_ci ARRAY_SIZE(icx098bq_start_1), 9248c2ecf20Sopenharmony_ci 5); 9258c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, icx098bq_start_2, 9268c2ecf20Sopenharmony_ci ARRAY_SIZE(icx098bq_start_2), 9278c2ecf20Sopenharmony_ci 6); 9288c2ecf20Sopenharmony_ci msleep(50); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* 1st start */ 9318c2ecf20Sopenharmony_ci send_start(gspca_dev); 9328c2ecf20Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); 9338c2ecf20Sopenharmony_ci msleep(70); 9348c2ecf20Sopenharmony_ci reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); 9358c2ecf20Sopenharmony_ci gpio_set(sd, 0x7f, 0x00ff); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* 2nd start */ 9388c2ecf20Sopenharmony_ci send_start(gspca_dev); 9398c2ecf20Sopenharmony_ci gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); 9408c2ecf20Sopenharmony_ci goto out; 9418c2ecf20Sopenharmony_ci case SENSOR_LZ24BP: 9428c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_0, 9438c2ecf20Sopenharmony_ci ARRAY_SIZE(lz24bp_start_0), 9448c2ecf20Sopenharmony_ci 8); 9458c2ecf20Sopenharmony_ci if (sd->type != Creative_live_motion) 9468c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_1_gen, 9478c2ecf20Sopenharmony_ci ARRAY_SIZE(lz24bp_start_1_gen), 9488c2ecf20Sopenharmony_ci 5); 9498c2ecf20Sopenharmony_ci else 9508c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_1_clm, 9518c2ecf20Sopenharmony_ci ARRAY_SIZE(lz24bp_start_1_clm), 9528c2ecf20Sopenharmony_ci 5); 9538c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, lz24bp_start_2, 9548c2ecf20Sopenharmony_ci ARRAY_SIZE(lz24bp_start_2), 9558c2ecf20Sopenharmony_ci 6); 9568c2ecf20Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 9578c2ecf20Sopenharmony_ci lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310); 9588c2ecf20Sopenharmony_ci msleep(10); 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci case SENSOR_MI0360: 9618c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, mi0360_start_0, 9628c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_start_0), 9638c2ecf20Sopenharmony_ci 8); 9648c2ecf20Sopenharmony_ci i2c_write(sd, mi0360_init_23, 9658c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_init_23)); 9668c2ecf20Sopenharmony_ci i2c_write(sd, mi0360_init_24, 9678c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_init_24)); 9688c2ecf20Sopenharmony_ci i2c_write(sd, mi0360_init_25, 9698c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_init_25)); 9708c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, mi0360_start_1, 9718c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_start_1), 9728c2ecf20Sopenharmony_ci 5); 9738c2ecf20Sopenharmony_ci i2c_write(sd, mi0360_start_2, 9748c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_start_2)); 9758c2ecf20Sopenharmony_ci i2c_write(sd, mi0360_start_3, 9768c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_start_3)); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* 1st start */ 9798c2ecf20Sopenharmony_ci send_start(gspca_dev); 9808c2ecf20Sopenharmony_ci msleep(60); 9818c2ecf20Sopenharmony_ci send_stop(gspca_dev); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci i2c_write(sd, 9848c2ecf20Sopenharmony_ci mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci default: 9878c2ecf20Sopenharmony_ci/* case SENSOR_MT9V111: */ 9888c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, mi0360_start_0, 9898c2ecf20Sopenharmony_ci ARRAY_SIZE(mi0360_start_0), 9908c2ecf20Sopenharmony_ci 8); 9918c2ecf20Sopenharmony_ci i2c_write(sd, mt9v111_init_0, 9928c2ecf20Sopenharmony_ci ARRAY_SIZE(mt9v111_init_0)); 9938c2ecf20Sopenharmony_ci i2c_write(sd, mt9v111_init_1, 9948c2ecf20Sopenharmony_ci ARRAY_SIZE(mt9v111_init_1)); 9958c2ecf20Sopenharmony_ci i2c_write(sd, mt9v111_init_2, 9968c2ecf20Sopenharmony_ci ARRAY_SIZE(mt9v111_init_2)); 9978c2ecf20Sopenharmony_ci ucbus_write(gspca_dev, mt9v111_start_1, 9988c2ecf20Sopenharmony_ci ARRAY_SIZE(mt9v111_start_1), 9998c2ecf20Sopenharmony_ci 5); 10008c2ecf20Sopenharmony_ci i2c_write(sd, mt9v111_init_3, 10018c2ecf20Sopenharmony_ci ARRAY_SIZE(mt9v111_init_3)); 10028c2ecf20Sopenharmony_ci i2c_write(sd, mt9v111_init_4, 10038c2ecf20Sopenharmony_ci ARRAY_SIZE(mt9v111_init_4)); 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci send_start(gspca_dev); 10088c2ecf20Sopenharmony_ciout: 10098c2ecf20Sopenharmony_ci msleep(1000); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_MT9V111) 10128c2ecf20Sopenharmony_ci gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci sd->do_ctrl = 1; /* set the exposure */ 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (sd->sensor == SENSOR_MT9V111) 10248c2ecf20Sopenharmony_ci gpio_set(sd, 0, SQ930_GPIO_DFL_LED); 10258c2ecf20Sopenharmony_ci send_stop(gspca_dev); 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci/* function called when the application gets a new frame */ 10298c2ecf20Sopenharmony_ci/* It sets the exposure if required and restart the bulk transfer. */ 10308c2ecf20Sopenharmony_cistatic void sd_dq_callback(struct gspca_dev *gspca_dev) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10338c2ecf20Sopenharmony_ci int ret; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) 10368c2ecf20Sopenharmony_ci return; 10378c2ecf20Sopenharmony_ci sd->do_ctrl = 0; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure), 10408c2ecf20Sopenharmony_ci v4l2_ctrl_g_ctrl(sd->gain)); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 1; 10438c2ecf20Sopenharmony_ci ret = usb_submit_urb(gspca_dev->urb[0], GFP_KERNEL); 10448c2ecf20Sopenharmony_ci if (ret < 0) 10458c2ecf20Sopenharmony_ci pr_err("sd_dq_callback() err %d\n", ret); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* wait a little time, otherwise the webcam crashes */ 10488c2ecf20Sopenharmony_ci msleep(100); 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, 10528c2ecf20Sopenharmony_ci u8 *data, /* isoc packet */ 10538c2ecf20Sopenharmony_ci int len) /* iso packet length */ 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (sd->do_ctrl) 10588c2ecf20Sopenharmony_ci gspca_dev->cam.bulk_nurbs = 0; 10598c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); 10608c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8); 10618c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct gspca_dev *gspca_dev = 10678c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 10688c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci gspca_dev->usb_err = 0; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (!gspca_dev->streaming) 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci switch (ctrl->id) { 10768c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE: 10778c2ecf20Sopenharmony_ci setexposure(gspca_dev, ctrl->val, sd->gain->val); 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci return gspca_dev->usb_err; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = { 10848c2ecf20Sopenharmony_ci .s_ctrl = sd_s_ctrl, 10858c2ecf20Sopenharmony_ci}; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 10908c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci gspca_dev->vdev.ctrl_handler = hdl; 10938c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 2); 10948c2ecf20Sopenharmony_ci sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 10958c2ecf20Sopenharmony_ci V4L2_CID_EXPOSURE, 1, 0xfff, 1, 0x356); 10968c2ecf20Sopenharmony_ci sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 10978c2ecf20Sopenharmony_ci V4L2_CID_GAIN, 1, 255, 1, 0x8d); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (hdl->error) { 11008c2ecf20Sopenharmony_ci pr_err("Could not initialize controls\n"); 11018c2ecf20Sopenharmony_ci return hdl->error; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(2, &sd->exposure); 11048c2ecf20Sopenharmony_ci return 0; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci/* sub-driver description */ 11088c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc = { 11098c2ecf20Sopenharmony_ci .name = MODULE_NAME, 11108c2ecf20Sopenharmony_ci .config = sd_config, 11118c2ecf20Sopenharmony_ci .init = sd_init, 11128c2ecf20Sopenharmony_ci .init_controls = sd_init_controls, 11138c2ecf20Sopenharmony_ci .isoc_init = sd_isoc_init, 11148c2ecf20Sopenharmony_ci .start = sd_start, 11158c2ecf20Sopenharmony_ci .stopN = sd_stopN, 11168c2ecf20Sopenharmony_ci .pkt_scan = sd_pkt_scan, 11178c2ecf20Sopenharmony_ci .dq_callback = sd_dq_callback, 11188c2ecf20Sopenharmony_ci}; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci/* Table of supported USB devices */ 11218c2ecf20Sopenharmony_ci#define ST(sensor, type) \ 11228c2ecf20Sopenharmony_ci .driver_info = (SENSOR_ ## sensor << 8) \ 11238c2ecf20Sopenharmony_ci | (type) 11248c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = { 11258c2ecf20Sopenharmony_ci {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, 11268c2ecf20Sopenharmony_ci {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, 11278c2ecf20Sopenharmony_ci {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, 11288c2ecf20Sopenharmony_ci {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, 11298c2ecf20Sopenharmony_ci {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, 11308c2ecf20Sopenharmony_ci {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, 11318c2ecf20Sopenharmony_ci {} 11328c2ecf20Sopenharmony_ci}; 11338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci/* -- device connect -- */ 11378c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, 11388c2ecf20Sopenharmony_ci const struct usb_device_id *id) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 11418c2ecf20Sopenharmony_ci THIS_MODULE); 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = { 11458c2ecf20Sopenharmony_ci .name = MODULE_NAME, 11468c2ecf20Sopenharmony_ci .id_table = device_table, 11478c2ecf20Sopenharmony_ci .probe = sd_probe, 11488c2ecf20Sopenharmony_ci .disconnect = gspca_disconnect, 11498c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 11508c2ecf20Sopenharmony_ci .suspend = gspca_suspend, 11518c2ecf20Sopenharmony_ci .resume = gspca_resume, 11528c2ecf20Sopenharmony_ci .reset_resume = gspca_resume, 11538c2ecf20Sopenharmony_ci#endif 11548c2ecf20Sopenharmony_ci}; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver); 1157