1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org>
6*4882a593Smuzhiyun // Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
7*4882a593Smuzhiyun //
8*4882a593Smuzhiyun // This program is free software; you can redistribute it and/or modify
9*4882a593Smuzhiyun // it under the terms of the GNU General Public License as published by
10*4882a593Smuzhiyun // the Free Software Foundation; either version 2 of the License, or
11*4882a593Smuzhiyun // (at your option) any later version.
12*4882a593Smuzhiyun //
13*4882a593Smuzhiyun // This program is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun // but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun // GNU General Public License for more details.
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "em28xx.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/i2c.h>
21*4882a593Smuzhiyun #include <linux/usb.h>
22*4882a593Smuzhiyun #include <media/i2c/mt9v011.h>
23*4882a593Smuzhiyun #include <media/v4l2-common.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* Possible i2c addresses of Micron sensors */
26*4882a593Smuzhiyun static unsigned short micron_sensor_addrs[] = {
27*4882a593Smuzhiyun 0xb8 >> 1, /* MT9V111, MT9V403 */
28*4882a593Smuzhiyun 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */
29*4882a593Smuzhiyun 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */
30*4882a593Smuzhiyun I2C_CLIENT_END
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /* Possible i2c addresses of Omnivision sensors */
34*4882a593Smuzhiyun static unsigned short omnivision_sensor_addrs[] = {
35*4882a593Smuzhiyun 0x42 >> 1, /* OV7725, OV7670/60/48 */
36*4882a593Smuzhiyun 0x60 >> 1, /* OV2640, OV9650/53/55 */
37*4882a593Smuzhiyun I2C_CLIENT_END
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* FIXME: Should be replaced by a proper mt9m111 driver */
em28xx_initialize_mt9m111(struct em28xx * dev)41*4882a593Smuzhiyun static int em28xx_initialize_mt9m111(struct em28xx *dev)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun int i;
44*4882a593Smuzhiyun unsigned char regs[][3] = {
45*4882a593Smuzhiyun { 0x0d, 0x00, 0x01, }, /* reset and use defaults */
46*4882a593Smuzhiyun { 0x0d, 0x00, 0x00, },
47*4882a593Smuzhiyun { 0x0a, 0x00, 0x21, },
48*4882a593Smuzhiyun { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(regs); i++)
52*4882a593Smuzhiyun i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
53*4882a593Smuzhiyun ®s[i][0], 3);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* FIXME: This won't be creating a sensor at the media graph */
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun return 0;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* FIXME: Should be replaced by a proper mt9m001 driver */
em28xx_initialize_mt9m001(struct em28xx * dev)61*4882a593Smuzhiyun static int em28xx_initialize_mt9m001(struct em28xx *dev)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun int i;
64*4882a593Smuzhiyun unsigned char regs[][3] = {
65*4882a593Smuzhiyun { 0x0d, 0x00, 0x01, },
66*4882a593Smuzhiyun { 0x0d, 0x00, 0x00, },
67*4882a593Smuzhiyun { 0x04, 0x05, 0x00, }, /* hres = 1280 */
68*4882a593Smuzhiyun { 0x03, 0x04, 0x00, }, /* vres = 1024 */
69*4882a593Smuzhiyun { 0x20, 0x11, 0x00, },
70*4882a593Smuzhiyun { 0x06, 0x00, 0x10, },
71*4882a593Smuzhiyun { 0x2b, 0x00, 0x24, },
72*4882a593Smuzhiyun { 0x2e, 0x00, 0x24, },
73*4882a593Smuzhiyun { 0x35, 0x00, 0x24, },
74*4882a593Smuzhiyun { 0x2d, 0x00, 0x20, },
75*4882a593Smuzhiyun { 0x2c, 0x00, 0x20, },
76*4882a593Smuzhiyun { 0x09, 0x0a, 0xd4, },
77*4882a593Smuzhiyun { 0x35, 0x00, 0x57, },
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(regs); i++)
81*4882a593Smuzhiyun i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
82*4882a593Smuzhiyun ®s[i][0], 3);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /* FIXME: This won't be creating a sensor at the media graph */
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun return 0;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /*
90*4882a593Smuzhiyun * Probes Micron sensors with 8 bit address and 16 bit register width
91*4882a593Smuzhiyun */
em28xx_probe_sensor_micron(struct em28xx * dev)92*4882a593Smuzhiyun static int em28xx_probe_sensor_micron(struct em28xx *dev)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun int ret, i;
95*4882a593Smuzhiyun char *name;
96*4882a593Smuzhiyun u16 id;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun dev->em28xx_sensor = EM28XX_NOSENSOR;
101*4882a593Smuzhiyun for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
102*4882a593Smuzhiyun client->addr = micron_sensor_addrs[i];
103*4882a593Smuzhiyun /* Read chip ID from register 0x00 */
104*4882a593Smuzhiyun ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */
105*4882a593Smuzhiyun if (ret < 0) {
106*4882a593Smuzhiyun if (ret != -ENXIO)
107*4882a593Smuzhiyun dev_err(&dev->intf->dev,
108*4882a593Smuzhiyun "couldn't read from i2c device 0x%02x: error %i\n",
109*4882a593Smuzhiyun client->addr << 1, ret);
110*4882a593Smuzhiyun continue;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun id = swab16(ret); /* LE -> BE */
113*4882a593Smuzhiyun /* Read chip ID from register 0xff */
114*4882a593Smuzhiyun ret = i2c_smbus_read_word_data(client, 0xff);
115*4882a593Smuzhiyun if (ret < 0) {
116*4882a593Smuzhiyun dev_err(&dev->intf->dev,
117*4882a593Smuzhiyun "couldn't read from i2c device 0x%02x: error %i\n",
118*4882a593Smuzhiyun client->addr << 1, ret);
119*4882a593Smuzhiyun continue;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun /* Validate chip ID to be sure we have a Micron device */
122*4882a593Smuzhiyun if (id != swab16(ret))
123*4882a593Smuzhiyun continue;
124*4882a593Smuzhiyun /* Check chip ID */
125*4882a593Smuzhiyun switch (id) {
126*4882a593Smuzhiyun case 0x1222:
127*4882a593Smuzhiyun name = "MT9V012"; /* MI370 */ /* 640x480 */
128*4882a593Smuzhiyun break;
129*4882a593Smuzhiyun case 0x1229:
130*4882a593Smuzhiyun name = "MT9V112"; /* 640x480 */
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun case 0x1433:
133*4882a593Smuzhiyun name = "MT9M011"; /* 1280x1024 */
134*4882a593Smuzhiyun break;
135*4882a593Smuzhiyun case 0x143a: /* found in the ECS G200 */
136*4882a593Smuzhiyun name = "MT9M111"; /* MI1310 */ /* 1280x1024 */
137*4882a593Smuzhiyun dev->em28xx_sensor = EM28XX_MT9M111;
138*4882a593Smuzhiyun break;
139*4882a593Smuzhiyun case 0x148c:
140*4882a593Smuzhiyun name = "MT9M112"; /* MI1320 */ /* 1280x1024 */
141*4882a593Smuzhiyun break;
142*4882a593Smuzhiyun case 0x1511:
143*4882a593Smuzhiyun name = "MT9D011"; /* MI2010 */ /* 1600x1200 */
144*4882a593Smuzhiyun break;
145*4882a593Smuzhiyun case 0x8232:
146*4882a593Smuzhiyun case 0x8243: /* rev B */
147*4882a593Smuzhiyun name = "MT9V011"; /* MI360 */ /* 640x480 */
148*4882a593Smuzhiyun dev->em28xx_sensor = EM28XX_MT9V011;
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun case 0x8431:
151*4882a593Smuzhiyun name = "MT9M001"; /* 1280x1024 */
152*4882a593Smuzhiyun dev->em28xx_sensor = EM28XX_MT9M001;
153*4882a593Smuzhiyun break;
154*4882a593Smuzhiyun default:
155*4882a593Smuzhiyun dev_info(&dev->intf->dev,
156*4882a593Smuzhiyun "unknown Micron sensor detected: 0x%04x\n",
157*4882a593Smuzhiyun id);
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (dev->em28xx_sensor == EM28XX_NOSENSOR)
162*4882a593Smuzhiyun dev_info(&dev->intf->dev,
163*4882a593Smuzhiyun "unsupported sensor detected: %s\n", name);
164*4882a593Smuzhiyun else
165*4882a593Smuzhiyun dev_info(&dev->intf->dev,
166*4882a593Smuzhiyun "sensor %s detected\n", name);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return -ENODEV;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /*
175*4882a593Smuzhiyun * Probes Omnivision sensors with 8 bit address and register width
176*4882a593Smuzhiyun */
em28xx_probe_sensor_omnivision(struct em28xx * dev)177*4882a593Smuzhiyun static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun int ret, i;
180*4882a593Smuzhiyun char *name;
181*4882a593Smuzhiyun u8 reg;
182*4882a593Smuzhiyun u16 id;
183*4882a593Smuzhiyun struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun dev->em28xx_sensor = EM28XX_NOSENSOR;
186*4882a593Smuzhiyun /*
187*4882a593Smuzhiyun * NOTE: these devices have the register auto incrementation disabled
188*4882a593Smuzhiyun * by default, so we have to use single byte reads !
189*4882a593Smuzhiyun */
190*4882a593Smuzhiyun for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
191*4882a593Smuzhiyun client->addr = omnivision_sensor_addrs[i];
192*4882a593Smuzhiyun /* Read manufacturer ID from registers 0x1c-0x1d (BE) */
193*4882a593Smuzhiyun reg = 0x1c;
194*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(client, reg);
195*4882a593Smuzhiyun if (ret < 0) {
196*4882a593Smuzhiyun if (ret != -ENXIO)
197*4882a593Smuzhiyun dev_err(&dev->intf->dev,
198*4882a593Smuzhiyun "couldn't read from i2c device 0x%02x: error %i\n",
199*4882a593Smuzhiyun client->addr << 1, ret);
200*4882a593Smuzhiyun continue;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun id = ret << 8;
203*4882a593Smuzhiyun reg = 0x1d;
204*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(client, reg);
205*4882a593Smuzhiyun if (ret < 0) {
206*4882a593Smuzhiyun dev_err(&dev->intf->dev,
207*4882a593Smuzhiyun "couldn't read from i2c device 0x%02x: error %i\n",
208*4882a593Smuzhiyun client->addr << 1, ret);
209*4882a593Smuzhiyun continue;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun id += ret;
212*4882a593Smuzhiyun /* Check manufacturer ID */
213*4882a593Smuzhiyun if (id != 0x7fa2)
214*4882a593Smuzhiyun continue;
215*4882a593Smuzhiyun /* Read product ID from registers 0x0a-0x0b (BE) */
216*4882a593Smuzhiyun reg = 0x0a;
217*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(client, reg);
218*4882a593Smuzhiyun if (ret < 0) {
219*4882a593Smuzhiyun dev_err(&dev->intf->dev,
220*4882a593Smuzhiyun "couldn't read from i2c device 0x%02x: error %i\n",
221*4882a593Smuzhiyun client->addr << 1, ret);
222*4882a593Smuzhiyun continue;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun id = ret << 8;
225*4882a593Smuzhiyun reg = 0x0b;
226*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(client, reg);
227*4882a593Smuzhiyun if (ret < 0) {
228*4882a593Smuzhiyun dev_err(&dev->intf->dev,
229*4882a593Smuzhiyun "couldn't read from i2c device 0x%02x: error %i\n",
230*4882a593Smuzhiyun client->addr << 1, ret);
231*4882a593Smuzhiyun continue;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun id += ret;
234*4882a593Smuzhiyun /* Check product ID */
235*4882a593Smuzhiyun switch (id) {
236*4882a593Smuzhiyun case 0x2642:
237*4882a593Smuzhiyun name = "OV2640";
238*4882a593Smuzhiyun dev->em28xx_sensor = EM28XX_OV2640;
239*4882a593Smuzhiyun break;
240*4882a593Smuzhiyun case 0x7648:
241*4882a593Smuzhiyun name = "OV7648";
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun case 0x7660:
244*4882a593Smuzhiyun name = "OV7660";
245*4882a593Smuzhiyun break;
246*4882a593Smuzhiyun case 0x7673:
247*4882a593Smuzhiyun name = "OV7670";
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun case 0x7720:
250*4882a593Smuzhiyun name = "OV7720";
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun case 0x7721:
253*4882a593Smuzhiyun name = "OV7725";
254*4882a593Smuzhiyun break;
255*4882a593Smuzhiyun case 0x9648: /* Rev 2 */
256*4882a593Smuzhiyun case 0x9649: /* Rev 3 */
257*4882a593Smuzhiyun name = "OV9640";
258*4882a593Smuzhiyun break;
259*4882a593Smuzhiyun case 0x9650:
260*4882a593Smuzhiyun case 0x9652: /* OV9653 */
261*4882a593Smuzhiyun name = "OV9650";
262*4882a593Smuzhiyun break;
263*4882a593Smuzhiyun case 0x9656: /* Rev 4 */
264*4882a593Smuzhiyun case 0x9657: /* Rev 5 */
265*4882a593Smuzhiyun name = "OV9655";
266*4882a593Smuzhiyun break;
267*4882a593Smuzhiyun default:
268*4882a593Smuzhiyun dev_info(&dev->intf->dev,
269*4882a593Smuzhiyun "unknown OmniVision sensor detected: 0x%04x\n",
270*4882a593Smuzhiyun id);
271*4882a593Smuzhiyun return 0;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun if (dev->em28xx_sensor == EM28XX_NOSENSOR)
275*4882a593Smuzhiyun dev_info(&dev->intf->dev,
276*4882a593Smuzhiyun "unsupported sensor detected: %s\n", name);
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun dev_info(&dev->intf->dev,
279*4882a593Smuzhiyun "sensor %s detected\n", name);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return -ENODEV;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
em28xx_detect_sensor(struct em28xx * dev)287*4882a593Smuzhiyun int em28xx_detect_sensor(struct em28xx *dev)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun int ret;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun ret = em28xx_probe_sensor_micron(dev);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0)
294*4882a593Smuzhiyun ret = em28xx_probe_sensor_omnivision(dev);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /*
297*4882a593Smuzhiyun * NOTE: the Windows driver also probes i2c addresses
298*4882a593Smuzhiyun * 0x22 (Samsung ?) and 0x66 (Kodak ?)
299*4882a593Smuzhiyun */
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) {
302*4882a593Smuzhiyun dev_info(&dev->intf->dev,
303*4882a593Smuzhiyun "No sensor detected\n");
304*4882a593Smuzhiyun return -ENODEV;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return 0;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
em28xx_init_camera(struct em28xx * dev)310*4882a593Smuzhiyun int em28xx_init_camera(struct em28xx *dev)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
313*4882a593Smuzhiyun struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
314*4882a593Smuzhiyun struct em28xx_v4l2 *v4l2 = dev->v4l2;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun switch (dev->em28xx_sensor) {
317*4882a593Smuzhiyun case EM28XX_MT9V011:
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun struct mt9v011_platform_data pdata;
320*4882a593Smuzhiyun struct i2c_board_info mt9v011_info = {
321*4882a593Smuzhiyun .type = "mt9v011",
322*4882a593Smuzhiyun .addr = client->addr,
323*4882a593Smuzhiyun .platform_data = &pdata,
324*4882a593Smuzhiyun };
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun v4l2->sensor_xres = 640;
327*4882a593Smuzhiyun v4l2->sensor_yres = 480;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /*
330*4882a593Smuzhiyun * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
331*4882a593Smuzhiyun * the Silvercrest cam I have here for testing - for higher
332*4882a593Smuzhiyun * resolutions, a high clock cause horizontal artifacts, so we
333*4882a593Smuzhiyun * need to use a lower xclk frequency.
334*4882a593Smuzhiyun * Yet, it would be possible to adjust xclk depending on the
335*4882a593Smuzhiyun * desired resolution, since this affects directly the
336*4882a593Smuzhiyun * frame rate.
337*4882a593Smuzhiyun */
338*4882a593Smuzhiyun dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
339*4882a593Smuzhiyun em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
340*4882a593Smuzhiyun v4l2->sensor_xtal = 4300000;
341*4882a593Smuzhiyun pdata.xtal = v4l2->sensor_xtal;
342*4882a593Smuzhiyun if (NULL ==
343*4882a593Smuzhiyun v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
344*4882a593Smuzhiyun &mt9v011_info, NULL))
345*4882a593Smuzhiyun return -ENODEV;
346*4882a593Smuzhiyun v4l2->vinmode = EM28XX_VINMODE_RGB8_GRBG;
347*4882a593Smuzhiyun v4l2->vinctl = 0x00;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun case EM28XX_MT9M001:
352*4882a593Smuzhiyun v4l2->sensor_xres = 1280;
353*4882a593Smuzhiyun v4l2->sensor_yres = 1024;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun em28xx_initialize_mt9m001(dev);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun v4l2->vinmode = EM28XX_VINMODE_RGB8_BGGR;
358*4882a593Smuzhiyun v4l2->vinctl = 0x00;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun break;
361*4882a593Smuzhiyun case EM28XX_MT9M111:
362*4882a593Smuzhiyun v4l2->sensor_xres = 640;
363*4882a593Smuzhiyun v4l2->sensor_yres = 512;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
366*4882a593Smuzhiyun em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
367*4882a593Smuzhiyun em28xx_initialize_mt9m111(dev);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun v4l2->vinmode = EM28XX_VINMODE_YUV422_UYVY;
370*4882a593Smuzhiyun v4l2->vinctl = 0x00;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun break;
373*4882a593Smuzhiyun case EM28XX_OV2640:
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun struct v4l2_subdev *subdev;
376*4882a593Smuzhiyun struct i2c_board_info ov2640_info = {
377*4882a593Smuzhiyun .type = "ov2640",
378*4882a593Smuzhiyun .flags = I2C_CLIENT_SCCB,
379*4882a593Smuzhiyun .addr = client->addr,
380*4882a593Smuzhiyun };
381*4882a593Smuzhiyun struct v4l2_subdev_format format = {
382*4882a593Smuzhiyun .which = V4L2_SUBDEV_FORMAT_ACTIVE,
383*4882a593Smuzhiyun };
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun /*
386*4882a593Smuzhiyun * FIXME: sensor supports resolutions up to 1600x1200, but
387*4882a593Smuzhiyun * resolution setting/switching needs to be modified to
388*4882a593Smuzhiyun * - switch sensor output resolution (including further
389*4882a593Smuzhiyun * configuration changes)
390*4882a593Smuzhiyun * - adjust bridge xclk
391*4882a593Smuzhiyun * - disable 16 bit (12 bit) output formats on high resolutions
392*4882a593Smuzhiyun */
393*4882a593Smuzhiyun v4l2->sensor_xres = 640;
394*4882a593Smuzhiyun v4l2->sensor_yres = 480;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun subdev =
397*4882a593Smuzhiyun v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
398*4882a593Smuzhiyun &ov2640_info, NULL);
399*4882a593Smuzhiyun if (!subdev)
400*4882a593Smuzhiyun return -ENODEV;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
403*4882a593Smuzhiyun format.format.width = 640;
404*4882a593Smuzhiyun format.format.height = 480;
405*4882a593Smuzhiyun v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* NOTE: for UXGA=1600x1200 switch to 12MHz */
408*4882a593Smuzhiyun dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
409*4882a593Smuzhiyun em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
410*4882a593Smuzhiyun v4l2->vinmode = EM28XX_VINMODE_YUV422_YUYV;
411*4882a593Smuzhiyun v4l2->vinctl = 0x00;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun case EM28XX_NOSENSOR:
416*4882a593Smuzhiyun default:
417*4882a593Smuzhiyun return -EINVAL;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(em28xx_init_camera);
423