1f22e9e71SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+
2f22e9e71SMauro Carvalho Chehab //
3f22e9e71SMauro Carvalho Chehab // em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
4f22e9e71SMauro Carvalho Chehab //
5*32590819SMauro Carvalho Chehab // Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org>
6f22e9e71SMauro Carvalho Chehab // Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
7855ff38eSFrank Schaefer
88314d402SMauro Carvalho Chehab #include "em28xx.h"
98314d402SMauro Carvalho Chehab
10855ff38eSFrank Schaefer #include <linux/i2c.h>
11ce8591ffSMauro Carvalho Chehab #include <linux/usb.h>
12b5dcee22SMauro Carvalho Chehab #include <media/i2c/mt9v011.h>
13855ff38eSFrank Schaefer #include <media/v4l2-common.h>
14855ff38eSFrank Schaefer
15176013b1SFrank Schaefer /* Possible i2c addresses of Micron sensors */
16176013b1SFrank Schaefer static unsigned short micron_sensor_addrs[] = {
17176013b1SFrank Schaefer 0xb8 >> 1, /* MT9V111, MT9V403 */
18176013b1SFrank Schaefer 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */
19176013b1SFrank Schaefer 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */
20176013b1SFrank Schaefer I2C_CLIENT_END
21176013b1SFrank Schaefer };
22176013b1SFrank Schaefer
23bde03684SFrank Schaefer /* Possible i2c addresses of Omnivision sensors */
24bde03684SFrank Schaefer static unsigned short omnivision_sensor_addrs[] = {
25bde03684SFrank Schaefer 0x42 >> 1, /* OV7725, OV7670/60/48 */
26bde03684SFrank Schaefer 0x60 >> 1, /* OV2640, OV9650/53/55 */
27bde03684SFrank Schaefer I2C_CLIENT_END
28bde03684SFrank Schaefer };
29bde03684SFrank Schaefer
30855ff38eSFrank Schaefer /* FIXME: Should be replaced by a proper mt9m111 driver */
em28xx_initialize_mt9m111(struct em28xx * dev)31855ff38eSFrank Schaefer static int em28xx_initialize_mt9m111(struct em28xx *dev)
32855ff38eSFrank Schaefer {
33855ff38eSFrank Schaefer int i;
34855ff38eSFrank Schaefer unsigned char regs[][3] = {
35855ff38eSFrank Schaefer { 0x0d, 0x00, 0x01, }, /* reset and use defaults */
36855ff38eSFrank Schaefer { 0x0d, 0x00, 0x00, },
37855ff38eSFrank Schaefer { 0x0a, 0x00, 0x21, },
3804964eb0SMauro Carvalho Chehab { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */
39855ff38eSFrank Schaefer };
40855ff38eSFrank Schaefer
41855ff38eSFrank Schaefer for (i = 0; i < ARRAY_SIZE(regs); i++)
42855ff38eSFrank Schaefer i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
43855ff38eSFrank Schaefer ®s[i][0], 3);
44855ff38eSFrank Schaefer
4537ecc7b1SMauro Carvalho Chehab /* FIXME: This won't be creating a sensor at the media graph */
4637ecc7b1SMauro Carvalho Chehab
47855ff38eSFrank Schaefer return 0;
48855ff38eSFrank Schaefer }
49855ff38eSFrank Schaefer
50855ff38eSFrank Schaefer /* FIXME: Should be replaced by a proper mt9m001 driver */
em28xx_initialize_mt9m001(struct em28xx * dev)51855ff38eSFrank Schaefer static int em28xx_initialize_mt9m001(struct em28xx *dev)
52855ff38eSFrank Schaefer {
53855ff38eSFrank Schaefer int i;
54855ff38eSFrank Schaefer unsigned char regs[][3] = {
55855ff38eSFrank Schaefer { 0x0d, 0x00, 0x01, },
56855ff38eSFrank Schaefer { 0x0d, 0x00, 0x00, },
57855ff38eSFrank Schaefer { 0x04, 0x05, 0x00, }, /* hres = 1280 */
58855ff38eSFrank Schaefer { 0x03, 0x04, 0x00, }, /* vres = 1024 */
59855ff38eSFrank Schaefer { 0x20, 0x11, 0x00, },
60855ff38eSFrank Schaefer { 0x06, 0x00, 0x10, },
61855ff38eSFrank Schaefer { 0x2b, 0x00, 0x24, },
62855ff38eSFrank Schaefer { 0x2e, 0x00, 0x24, },
63855ff38eSFrank Schaefer { 0x35, 0x00, 0x24, },
64855ff38eSFrank Schaefer { 0x2d, 0x00, 0x20, },
65855ff38eSFrank Schaefer { 0x2c, 0x00, 0x20, },
66855ff38eSFrank Schaefer { 0x09, 0x0a, 0xd4, },
67855ff38eSFrank Schaefer { 0x35, 0x00, 0x57, },
68855ff38eSFrank Schaefer };
69855ff38eSFrank Schaefer
70855ff38eSFrank Schaefer for (i = 0; i < ARRAY_SIZE(regs); i++)
71855ff38eSFrank Schaefer i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
72855ff38eSFrank Schaefer ®s[i][0], 3);
73855ff38eSFrank Schaefer
7437ecc7b1SMauro Carvalho Chehab /* FIXME: This won't be creating a sensor at the media graph */
7537ecc7b1SMauro Carvalho Chehab
76855ff38eSFrank Schaefer return 0;
77855ff38eSFrank Schaefer }
78855ff38eSFrank Schaefer
79855ff38eSFrank Schaefer /*
800af0b25aSFrank Schaefer * Probes Micron sensors with 8 bit address and 16 bit register width
81855ff38eSFrank Schaefer */
em28xx_probe_sensor_micron(struct em28xx * dev)820af0b25aSFrank Schaefer static int em28xx_probe_sensor_micron(struct em28xx *dev)
83855ff38eSFrank Schaefer {
84176013b1SFrank Schaefer int ret, i;
85855ff38eSFrank Schaefer char *name;
86855ff38eSFrank Schaefer u16 id;
87855ff38eSFrank Schaefer
889e006953SFrank Schaefer struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
89855ff38eSFrank Schaefer
90176013b1SFrank Schaefer dev->em28xx_sensor = EM28XX_NOSENSOR;
91176013b1SFrank Schaefer for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
929e006953SFrank Schaefer client->addr = micron_sensor_addrs[i];
93176013b1SFrank Schaefer /* Read chip ID from register 0x00 */
944d584436SFrank Schaefer ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */
95176013b1SFrank Schaefer if (ret < 0) {
96cb497c75SFrank Schaefer if (ret != -ENXIO)
9729b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
98ce8591ffSMauro Carvalho Chehab "couldn't read from i2c device 0x%02x: error %i\n",
999e006953SFrank Schaefer client->addr << 1, ret);
100176013b1SFrank Schaefer continue;
101176013b1SFrank Schaefer }
1024d584436SFrank Schaefer id = swab16(ret); /* LE -> BE */
103176013b1SFrank Schaefer /* Read chip ID from register 0xff */
1044d584436SFrank Schaefer ret = i2c_smbus_read_word_data(client, 0xff);
105176013b1SFrank Schaefer if (ret < 0) {
10629b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
107ce8591ffSMauro Carvalho Chehab "couldn't read from i2c device 0x%02x: error %i\n",
1089e006953SFrank Schaefer client->addr << 1, ret);
109176013b1SFrank Schaefer continue;
110176013b1SFrank Schaefer }
111176013b1SFrank Schaefer /* Validate chip ID to be sure we have a Micron device */
1124d584436SFrank Schaefer if (id != swab16(ret))
113176013b1SFrank Schaefer continue;
114176013b1SFrank Schaefer /* Check chip ID */
115855ff38eSFrank Schaefer switch (id) {
116176013b1SFrank Schaefer case 0x1222:
117176013b1SFrank Schaefer name = "MT9V012"; /* MI370 */ /* 640x480 */
118855ff38eSFrank Schaefer break;
119176013b1SFrank Schaefer case 0x1229:
120176013b1SFrank Schaefer name = "MT9V112"; /* 640x480 */
121176013b1SFrank Schaefer break;
122176013b1SFrank Schaefer case 0x1433:
123176013b1SFrank Schaefer name = "MT9M011"; /* 1280x1024 */
124176013b1SFrank Schaefer break;
125176013b1SFrank Schaefer case 0x143a: /* found in the ECS G200 */
126176013b1SFrank Schaefer name = "MT9M111"; /* MI1310 */ /* 1280x1024 */
127855ff38eSFrank Schaefer dev->em28xx_sensor = EM28XX_MT9M111;
128855ff38eSFrank Schaefer break;
129176013b1SFrank Schaefer case 0x148c:
130176013b1SFrank Schaefer name = "MT9M112"; /* MI1320 */ /* 1280x1024 */
131176013b1SFrank Schaefer break;
132176013b1SFrank Schaefer case 0x1511:
133176013b1SFrank Schaefer name = "MT9D011"; /* MI2010 */ /* 1600x1200 */
134176013b1SFrank Schaefer break;
135176013b1SFrank Schaefer case 0x8232:
136176013b1SFrank Schaefer case 0x8243: /* rev B */
137176013b1SFrank Schaefer name = "MT9V011"; /* MI360 */ /* 640x480 */
138176013b1SFrank Schaefer dev->em28xx_sensor = EM28XX_MT9V011;
139176013b1SFrank Schaefer break;
140855ff38eSFrank Schaefer case 0x8431:
141176013b1SFrank Schaefer name = "MT9M001"; /* 1280x1024 */
142855ff38eSFrank Schaefer dev->em28xx_sensor = EM28XX_MT9M001;
143855ff38eSFrank Schaefer break;
144855ff38eSFrank Schaefer default:
14529b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
14604964eb0SMauro Carvalho Chehab "unknown Micron sensor detected: 0x%04x\n",
14704964eb0SMauro Carvalho Chehab id);
1480af0b25aSFrank Schaefer return 0;
149855ff38eSFrank Schaefer }
150855ff38eSFrank Schaefer
151176013b1SFrank Schaefer if (dev->em28xx_sensor == EM28XX_NOSENSOR)
15229b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
153ce8591ffSMauro Carvalho Chehab "unsupported sensor detected: %s\n", name);
154176013b1SFrank Schaefer else
15529b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
156ce8591ffSMauro Carvalho Chehab "sensor %s detected\n", name);
157855ff38eSFrank Schaefer
158855ff38eSFrank Schaefer return 0;
159855ff38eSFrank Schaefer }
160855ff38eSFrank Schaefer
161176013b1SFrank Schaefer return -ENODEV;
162176013b1SFrank Schaefer }
163176013b1SFrank Schaefer
1640af0b25aSFrank Schaefer /*
165bde03684SFrank Schaefer * Probes Omnivision sensors with 8 bit address and register width
1660af0b25aSFrank Schaefer */
em28xx_probe_sensor_omnivision(struct em28xx * dev)167bde03684SFrank Schaefer static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
168bde03684SFrank Schaefer {
169bde03684SFrank Schaefer int ret, i;
170bde03684SFrank Schaefer char *name;
171bde03684SFrank Schaefer u8 reg;
172bde03684SFrank Schaefer u16 id;
1739e006953SFrank Schaefer struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
174bde03684SFrank Schaefer
175bde03684SFrank Schaefer dev->em28xx_sensor = EM28XX_NOSENSOR;
17604964eb0SMauro Carvalho Chehab /*
17704964eb0SMauro Carvalho Chehab * NOTE: these devices have the register auto incrementation disabled
17804964eb0SMauro Carvalho Chehab * by default, so we have to use single byte reads !
17904964eb0SMauro Carvalho Chehab */
180bde03684SFrank Schaefer for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
1819e006953SFrank Schaefer client->addr = omnivision_sensor_addrs[i];
182bde03684SFrank Schaefer /* Read manufacturer ID from registers 0x1c-0x1d (BE) */
183bde03684SFrank Schaefer reg = 0x1c;
1849e006953SFrank Schaefer ret = i2c_smbus_read_byte_data(client, reg);
185bde03684SFrank Schaefer if (ret < 0) {
186cb497c75SFrank Schaefer if (ret != -ENXIO)
18729b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
188ce8591ffSMauro Carvalho Chehab "couldn't read from i2c device 0x%02x: error %i\n",
1899e006953SFrank Schaefer client->addr << 1, ret);
190bde03684SFrank Schaefer continue;
191bde03684SFrank Schaefer }
192bde03684SFrank Schaefer id = ret << 8;
193bde03684SFrank Schaefer reg = 0x1d;
1949e006953SFrank Schaefer ret = i2c_smbus_read_byte_data(client, reg);
195bde03684SFrank Schaefer if (ret < 0) {
19629b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
197ce8591ffSMauro Carvalho Chehab "couldn't read from i2c device 0x%02x: error %i\n",
1989e006953SFrank Schaefer client->addr << 1, ret);
199bde03684SFrank Schaefer continue;
200bde03684SFrank Schaefer }
201bde03684SFrank Schaefer id += ret;
202bde03684SFrank Schaefer /* Check manufacturer ID */
203bde03684SFrank Schaefer if (id != 0x7fa2)
204bde03684SFrank Schaefer continue;
205bde03684SFrank Schaefer /* Read product ID from registers 0x0a-0x0b (BE) */
206bde03684SFrank Schaefer reg = 0x0a;
2079e006953SFrank Schaefer ret = i2c_smbus_read_byte_data(client, reg);
208bde03684SFrank Schaefer if (ret < 0) {
20929b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
210ce8591ffSMauro Carvalho Chehab "couldn't read from i2c device 0x%02x: error %i\n",
2119e006953SFrank Schaefer client->addr << 1, ret);
212bde03684SFrank Schaefer continue;
213bde03684SFrank Schaefer }
214bde03684SFrank Schaefer id = ret << 8;
215bde03684SFrank Schaefer reg = 0x0b;
2169e006953SFrank Schaefer ret = i2c_smbus_read_byte_data(client, reg);
217bde03684SFrank Schaefer if (ret < 0) {
21829b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
219ce8591ffSMauro Carvalho Chehab "couldn't read from i2c device 0x%02x: error %i\n",
2209e006953SFrank Schaefer client->addr << 1, ret);
221bde03684SFrank Schaefer continue;
222bde03684SFrank Schaefer }
223bde03684SFrank Schaefer id += ret;
224bde03684SFrank Schaefer /* Check product ID */
225bde03684SFrank Schaefer switch (id) {
226bde03684SFrank Schaefer case 0x2642:
227bde03684SFrank Schaefer name = "OV2640";
228e4b7131dSFrank Schaefer dev->em28xx_sensor = EM28XX_OV2640;
229bde03684SFrank Schaefer break;
230bde03684SFrank Schaefer case 0x7648:
231bde03684SFrank Schaefer name = "OV7648";
232bde03684SFrank Schaefer break;
233bde03684SFrank Schaefer case 0x7660:
234bde03684SFrank Schaefer name = "OV7660";
235bde03684SFrank Schaefer break;
236bde03684SFrank Schaefer case 0x7673:
237bde03684SFrank Schaefer name = "OV7670";
238bde03684SFrank Schaefer break;
239bde03684SFrank Schaefer case 0x7720:
240bde03684SFrank Schaefer name = "OV7720";
241bde03684SFrank Schaefer break;
242bde03684SFrank Schaefer case 0x7721:
243bde03684SFrank Schaefer name = "OV7725";
244bde03684SFrank Schaefer break;
245bde03684SFrank Schaefer case 0x9648: /* Rev 2 */
246bde03684SFrank Schaefer case 0x9649: /* Rev 3 */
247bde03684SFrank Schaefer name = "OV9640";
248bde03684SFrank Schaefer break;
249bde03684SFrank Schaefer case 0x9650:
250bde03684SFrank Schaefer case 0x9652: /* OV9653 */
251bde03684SFrank Schaefer name = "OV9650";
252bde03684SFrank Schaefer break;
253bde03684SFrank Schaefer case 0x9656: /* Rev 4 */
254bde03684SFrank Schaefer case 0x9657: /* Rev 5 */
255bde03684SFrank Schaefer name = "OV9655";
256bde03684SFrank Schaefer break;
257bde03684SFrank Schaefer default:
25829b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
259ce8591ffSMauro Carvalho Chehab "unknown OmniVision sensor detected: 0x%04x\n",
260bde03684SFrank Schaefer id);
261bde03684SFrank Schaefer return 0;
262bde03684SFrank Schaefer }
263bde03684SFrank Schaefer
264bde03684SFrank Schaefer if (dev->em28xx_sensor == EM28XX_NOSENSOR)
26529b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
266ce8591ffSMauro Carvalho Chehab "unsupported sensor detected: %s\n", name);
267bde03684SFrank Schaefer else
26829b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
269ce8591ffSMauro Carvalho Chehab "sensor %s detected\n", name);
270bde03684SFrank Schaefer
271bde03684SFrank Schaefer return 0;
272bde03684SFrank Schaefer }
273bde03684SFrank Schaefer
274bde03684SFrank Schaefer return -ENODEV;
275bde03684SFrank Schaefer }
276bde03684SFrank Schaefer
em28xx_detect_sensor(struct em28xx * dev)2770af0b25aSFrank Schaefer int em28xx_detect_sensor(struct em28xx *dev)
2780af0b25aSFrank Schaefer {
2790af0b25aSFrank Schaefer int ret;
2800af0b25aSFrank Schaefer
2810af0b25aSFrank Schaefer ret = em28xx_probe_sensor_micron(dev);
282bde03684SFrank Schaefer
283bde03684SFrank Schaefer if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0)
284bde03684SFrank Schaefer ret = em28xx_probe_sensor_omnivision(dev);
285bde03684SFrank Schaefer
28652f1f230SFrank Schaefer /*
28752f1f230SFrank Schaefer * NOTE: the Windows driver also probes i2c addresses
28852f1f230SFrank Schaefer * 0x22 (Samsung ?) and 0x66 (Kodak ?)
28952f1f230SFrank Schaefer */
29052f1f230SFrank Schaefer
2910af0b25aSFrank Schaefer if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) {
29229b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
293ce8591ffSMauro Carvalho Chehab "No sensor detected\n");
2940af0b25aSFrank Schaefer return -ENODEV;
2950af0b25aSFrank Schaefer }
2960af0b25aSFrank Schaefer
2970af0b25aSFrank Schaefer return 0;
2980af0b25aSFrank Schaefer }
2990af0b25aSFrank Schaefer
em28xx_init_camera(struct em28xx * dev)300855ff38eSFrank Schaefer int em28xx_init_camera(struct em28xx *dev)
301855ff38eSFrank Schaefer {
302fc5d0f8aSGuennadi Liakhovetski struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
303fc5d0f8aSGuennadi Liakhovetski struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
3042c52a2fcSFrank Schaefer struct em28xx_v4l2 *v4l2 = dev->v4l2;
305fc5d0f8aSGuennadi Liakhovetski
306855ff38eSFrank Schaefer switch (dev->em28xx_sensor) {
307855ff38eSFrank Schaefer case EM28XX_MT9V011:
308855ff38eSFrank Schaefer {
309855ff38eSFrank Schaefer struct mt9v011_platform_data pdata;
310855ff38eSFrank Schaefer struct i2c_board_info mt9v011_info = {
311855ff38eSFrank Schaefer .type = "mt9v011",
312fc5d0f8aSGuennadi Liakhovetski .addr = client->addr,
313855ff38eSFrank Schaefer .platform_data = &pdata,
314855ff38eSFrank Schaefer };
315855ff38eSFrank Schaefer
316d7dc18daSFrank Schaefer v4l2->sensor_xres = 640;
317d7dc18daSFrank Schaefer v4l2->sensor_yres = 480;
318855ff38eSFrank Schaefer
319855ff38eSFrank Schaefer /*
320855ff38eSFrank Schaefer * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
321855ff38eSFrank Schaefer * the Silvercrest cam I have here for testing - for higher
322855ff38eSFrank Schaefer * resolutions, a high clock cause horizontal artifacts, so we
323855ff38eSFrank Schaefer * need to use a lower xclk frequency.
324855ff38eSFrank Schaefer * Yet, it would be possible to adjust xclk depending on the
325855ff38eSFrank Schaefer * desired resolution, since this affects directly the
326855ff38eSFrank Schaefer * frame rate.
327855ff38eSFrank Schaefer */
328855ff38eSFrank Schaefer dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
329855ff38eSFrank Schaefer em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
330d7dc18daSFrank Schaefer v4l2->sensor_xtal = 4300000;
331d7dc18daSFrank Schaefer pdata.xtal = v4l2->sensor_xtal;
332855ff38eSFrank Schaefer if (NULL ==
3335015389fSFrank Schaefer v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
3342437aeb4SFrank Schaefer &mt9v011_info, NULL))
3352437aeb4SFrank Schaefer return -ENODEV;
336a7b8e9a5SFrank Schaefer v4l2->vinmode = EM28XX_VINMODE_RGB8_GRBG;
3379297285eSFrank Schaefer v4l2->vinctl = 0x00;
338855ff38eSFrank Schaefer
339855ff38eSFrank Schaefer break;
340855ff38eSFrank Schaefer }
341855ff38eSFrank Schaefer case EM28XX_MT9M001:
342d7dc18daSFrank Schaefer v4l2->sensor_xres = 1280;
343d7dc18daSFrank Schaefer v4l2->sensor_yres = 1024;
344855ff38eSFrank Schaefer
345855ff38eSFrank Schaefer em28xx_initialize_mt9m001(dev);
346855ff38eSFrank Schaefer
347a7b8e9a5SFrank Schaefer v4l2->vinmode = EM28XX_VINMODE_RGB8_BGGR;
3489297285eSFrank Schaefer v4l2->vinctl = 0x00;
349855ff38eSFrank Schaefer
350855ff38eSFrank Schaefer break;
351855ff38eSFrank Schaefer case EM28XX_MT9M111:
352d7dc18daSFrank Schaefer v4l2->sensor_xres = 640;
353d7dc18daSFrank Schaefer v4l2->sensor_yres = 512;
354855ff38eSFrank Schaefer
355855ff38eSFrank Schaefer dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
356855ff38eSFrank Schaefer em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
357855ff38eSFrank Schaefer em28xx_initialize_mt9m111(dev);
358855ff38eSFrank Schaefer
359a7b8e9a5SFrank Schaefer v4l2->vinmode = EM28XX_VINMODE_YUV422_UYVY;
3609297285eSFrank Schaefer v4l2->vinctl = 0x00;
361855ff38eSFrank Schaefer
362855ff38eSFrank Schaefer break;
363e4b7131dSFrank Schaefer case EM28XX_OV2640:
364e4b7131dSFrank Schaefer {
365e4b7131dSFrank Schaefer struct v4l2_subdev *subdev;
366e4b7131dSFrank Schaefer struct i2c_board_info ov2640_info = {
367e4b7131dSFrank Schaefer .type = "ov2640",
368e4b7131dSFrank Schaefer .flags = I2C_CLIENT_SCCB,
369fc5d0f8aSGuennadi Liakhovetski .addr = client->addr,
370e4b7131dSFrank Schaefer };
371ebf984bbSHans Verkuil struct v4l2_subdev_format format = {
372ebf984bbSHans Verkuil .which = V4L2_SUBDEV_FORMAT_ACTIVE,
373ebf984bbSHans Verkuil };
374e4b7131dSFrank Schaefer
375e4b7131dSFrank Schaefer /*
376e4b7131dSFrank Schaefer * FIXME: sensor supports resolutions up to 1600x1200, but
377e4b7131dSFrank Schaefer * resolution setting/switching needs to be modified to
378e4b7131dSFrank Schaefer * - switch sensor output resolution (including further
379e4b7131dSFrank Schaefer * configuration changes)
380e4b7131dSFrank Schaefer * - adjust bridge xclk
381e4b7131dSFrank Schaefer * - disable 16 bit (12 bit) output formats on high resolutions
382e4b7131dSFrank Schaefer */
383d7dc18daSFrank Schaefer v4l2->sensor_xres = 640;
384d7dc18daSFrank Schaefer v4l2->sensor_yres = 480;
385e4b7131dSFrank Schaefer
386e4b7131dSFrank Schaefer subdev =
3875015389fSFrank Schaefer v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
388e4b7131dSFrank Schaefer &ov2640_info, NULL);
38904964eb0SMauro Carvalho Chehab if (!subdev)
3902437aeb4SFrank Schaefer return -ENODEV;
391e4b7131dSFrank Schaefer
392ebf984bbSHans Verkuil format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
393ebf984bbSHans Verkuil format.format.width = 640;
394ebf984bbSHans Verkuil format.format.height = 480;
395ebf984bbSHans Verkuil v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format);
396e4b7131dSFrank Schaefer
397e4b7131dSFrank Schaefer /* NOTE: for UXGA=1600x1200 switch to 12MHz */
398e4b7131dSFrank Schaefer dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
399e4b7131dSFrank Schaefer em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
400a7b8e9a5SFrank Schaefer v4l2->vinmode = EM28XX_VINMODE_YUV422_YUYV;
4019297285eSFrank Schaefer v4l2->vinctl = 0x00;
402e4b7131dSFrank Schaefer
403e4b7131dSFrank Schaefer break;
404e4b7131dSFrank Schaefer }
405855ff38eSFrank Schaefer case EM28XX_NOSENSOR:
406855ff38eSFrank Schaefer default:
4072437aeb4SFrank Schaefer return -EINVAL;
408855ff38eSFrank Schaefer }
409855ff38eSFrank Schaefer
4102437aeb4SFrank Schaefer return 0;
411855ff38eSFrank Schaefer }
41201c28193SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(em28xx_init_camera);
413