162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org> 662306a36Sopenharmony_ci// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "em28xx.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/i2c.h> 1162306a36Sopenharmony_ci#include <linux/usb.h> 1262306a36Sopenharmony_ci#include <media/i2c/mt9v011.h> 1362306a36Sopenharmony_ci#include <media/v4l2-common.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Possible i2c addresses of Micron sensors */ 1662306a36Sopenharmony_cistatic unsigned short micron_sensor_addrs[] = { 1762306a36Sopenharmony_ci 0xb8 >> 1, /* MT9V111, MT9V403 */ 1862306a36Sopenharmony_ci 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */ 1962306a36Sopenharmony_ci 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */ 2062306a36Sopenharmony_ci I2C_CLIENT_END 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Possible i2c addresses of Omnivision sensors */ 2462306a36Sopenharmony_cistatic unsigned short omnivision_sensor_addrs[] = { 2562306a36Sopenharmony_ci 0x42 >> 1, /* OV7725, OV7670/60/48 */ 2662306a36Sopenharmony_ci 0x60 >> 1, /* OV2640, OV9650/53/55 */ 2762306a36Sopenharmony_ci I2C_CLIENT_END 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* FIXME: Should be replaced by a proper mt9m111 driver */ 3162306a36Sopenharmony_cistatic int em28xx_initialize_mt9m111(struct em28xx *dev) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int i; 3462306a36Sopenharmony_ci unsigned char regs[][3] = { 3562306a36Sopenharmony_ci { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ 3662306a36Sopenharmony_ci { 0x0d, 0x00, 0x00, }, 3762306a36Sopenharmony_ci { 0x0a, 0x00, 0x21, }, 3862306a36Sopenharmony_ci { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */ 3962306a36Sopenharmony_ci }; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regs); i++) 4262306a36Sopenharmony_ci i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], 4362306a36Sopenharmony_ci ®s[i][0], 3); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* FIXME: This won't be creating a sensor at the media graph */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* FIXME: Should be replaced by a proper mt9m001 driver */ 5162306a36Sopenharmony_cistatic int em28xx_initialize_mt9m001(struct em28xx *dev) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int i; 5462306a36Sopenharmony_ci unsigned char regs[][3] = { 5562306a36Sopenharmony_ci { 0x0d, 0x00, 0x01, }, 5662306a36Sopenharmony_ci { 0x0d, 0x00, 0x00, }, 5762306a36Sopenharmony_ci { 0x04, 0x05, 0x00, }, /* hres = 1280 */ 5862306a36Sopenharmony_ci { 0x03, 0x04, 0x00, }, /* vres = 1024 */ 5962306a36Sopenharmony_ci { 0x20, 0x11, 0x00, }, 6062306a36Sopenharmony_ci { 0x06, 0x00, 0x10, }, 6162306a36Sopenharmony_ci { 0x2b, 0x00, 0x24, }, 6262306a36Sopenharmony_ci { 0x2e, 0x00, 0x24, }, 6362306a36Sopenharmony_ci { 0x35, 0x00, 0x24, }, 6462306a36Sopenharmony_ci { 0x2d, 0x00, 0x20, }, 6562306a36Sopenharmony_ci { 0x2c, 0x00, 0x20, }, 6662306a36Sopenharmony_ci { 0x09, 0x0a, 0xd4, }, 6762306a36Sopenharmony_ci { 0x35, 0x00, 0x57, }, 6862306a36Sopenharmony_ci }; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regs); i++) 7162306a36Sopenharmony_ci i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], 7262306a36Sopenharmony_ci ®s[i][0], 3); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* FIXME: This won't be creating a sensor at the media graph */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * Probes Micron sensors with 8 bit address and 16 bit register width 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic int em28xx_probe_sensor_micron(struct em28xx *dev) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci int ret, i; 8562306a36Sopenharmony_ci char *name; 8662306a36Sopenharmony_ci u16 id; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci dev->em28xx_sensor = EM28XX_NOSENSOR; 9162306a36Sopenharmony_ci for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { 9262306a36Sopenharmony_ci client->addr = micron_sensor_addrs[i]; 9362306a36Sopenharmony_ci /* Read chip ID from register 0x00 */ 9462306a36Sopenharmony_ci ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */ 9562306a36Sopenharmony_ci if (ret < 0) { 9662306a36Sopenharmony_ci if (ret != -ENXIO) 9762306a36Sopenharmony_ci dev_err(&dev->intf->dev, 9862306a36Sopenharmony_ci "couldn't read from i2c device 0x%02x: error %i\n", 9962306a36Sopenharmony_ci client->addr << 1, ret); 10062306a36Sopenharmony_ci continue; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci id = swab16(ret); /* LE -> BE */ 10362306a36Sopenharmony_ci /* Read chip ID from register 0xff */ 10462306a36Sopenharmony_ci ret = i2c_smbus_read_word_data(client, 0xff); 10562306a36Sopenharmony_ci if (ret < 0) { 10662306a36Sopenharmony_ci dev_err(&dev->intf->dev, 10762306a36Sopenharmony_ci "couldn't read from i2c device 0x%02x: error %i\n", 10862306a36Sopenharmony_ci client->addr << 1, ret); 10962306a36Sopenharmony_ci continue; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci /* Validate chip ID to be sure we have a Micron device */ 11262306a36Sopenharmony_ci if (id != swab16(ret)) 11362306a36Sopenharmony_ci continue; 11462306a36Sopenharmony_ci /* Check chip ID */ 11562306a36Sopenharmony_ci switch (id) { 11662306a36Sopenharmony_ci case 0x1222: 11762306a36Sopenharmony_ci name = "MT9V012"; /* MI370 */ /* 640x480 */ 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case 0x1229: 12062306a36Sopenharmony_ci name = "MT9V112"; /* 640x480 */ 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci case 0x1433: 12362306a36Sopenharmony_ci name = "MT9M011"; /* 1280x1024 */ 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case 0x143a: /* found in the ECS G200 */ 12662306a36Sopenharmony_ci name = "MT9M111"; /* MI1310 */ /* 1280x1024 */ 12762306a36Sopenharmony_ci dev->em28xx_sensor = EM28XX_MT9M111; 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci case 0x148c: 13062306a36Sopenharmony_ci name = "MT9M112"; /* MI1320 */ /* 1280x1024 */ 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case 0x1511: 13362306a36Sopenharmony_ci name = "MT9D011"; /* MI2010 */ /* 1600x1200 */ 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci case 0x8232: 13662306a36Sopenharmony_ci case 0x8243: /* rev B */ 13762306a36Sopenharmony_ci name = "MT9V011"; /* MI360 */ /* 640x480 */ 13862306a36Sopenharmony_ci dev->em28xx_sensor = EM28XX_MT9V011; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case 0x8431: 14162306a36Sopenharmony_ci name = "MT9M001"; /* 1280x1024 */ 14262306a36Sopenharmony_ci dev->em28xx_sensor = EM28XX_MT9M001; 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci default: 14562306a36Sopenharmony_ci dev_info(&dev->intf->dev, 14662306a36Sopenharmony_ci "unknown Micron sensor detected: 0x%04x\n", 14762306a36Sopenharmony_ci id); 14862306a36Sopenharmony_ci return 0; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (dev->em28xx_sensor == EM28XX_NOSENSOR) 15262306a36Sopenharmony_ci dev_info(&dev->intf->dev, 15362306a36Sopenharmony_ci "unsupported sensor detected: %s\n", name); 15462306a36Sopenharmony_ci else 15562306a36Sopenharmony_ci dev_info(&dev->intf->dev, 15662306a36Sopenharmony_ci "sensor %s detected\n", name); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return -ENODEV; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * Probes Omnivision sensors with 8 bit address and register width 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_cistatic int em28xx_probe_sensor_omnivision(struct em28xx *dev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int ret, i; 17062306a36Sopenharmony_ci char *name; 17162306a36Sopenharmony_ci u8 reg; 17262306a36Sopenharmony_ci u16 id; 17362306a36Sopenharmony_ci struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci dev->em28xx_sensor = EM28XX_NOSENSOR; 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * NOTE: these devices have the register auto incrementation disabled 17862306a36Sopenharmony_ci * by default, so we have to use single byte reads ! 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { 18162306a36Sopenharmony_ci client->addr = omnivision_sensor_addrs[i]; 18262306a36Sopenharmony_ci /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ 18362306a36Sopenharmony_ci reg = 0x1c; 18462306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(client, reg); 18562306a36Sopenharmony_ci if (ret < 0) { 18662306a36Sopenharmony_ci if (ret != -ENXIO) 18762306a36Sopenharmony_ci dev_err(&dev->intf->dev, 18862306a36Sopenharmony_ci "couldn't read from i2c device 0x%02x: error %i\n", 18962306a36Sopenharmony_ci client->addr << 1, ret); 19062306a36Sopenharmony_ci continue; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci id = ret << 8; 19362306a36Sopenharmony_ci reg = 0x1d; 19462306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(client, reg); 19562306a36Sopenharmony_ci if (ret < 0) { 19662306a36Sopenharmony_ci dev_err(&dev->intf->dev, 19762306a36Sopenharmony_ci "couldn't read from i2c device 0x%02x: error %i\n", 19862306a36Sopenharmony_ci client->addr << 1, ret); 19962306a36Sopenharmony_ci continue; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci id += ret; 20262306a36Sopenharmony_ci /* Check manufacturer ID */ 20362306a36Sopenharmony_ci if (id != 0x7fa2) 20462306a36Sopenharmony_ci continue; 20562306a36Sopenharmony_ci /* Read product ID from registers 0x0a-0x0b (BE) */ 20662306a36Sopenharmony_ci reg = 0x0a; 20762306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(client, reg); 20862306a36Sopenharmony_ci if (ret < 0) { 20962306a36Sopenharmony_ci dev_err(&dev->intf->dev, 21062306a36Sopenharmony_ci "couldn't read from i2c device 0x%02x: error %i\n", 21162306a36Sopenharmony_ci client->addr << 1, ret); 21262306a36Sopenharmony_ci continue; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci id = ret << 8; 21562306a36Sopenharmony_ci reg = 0x0b; 21662306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(client, reg); 21762306a36Sopenharmony_ci if (ret < 0) { 21862306a36Sopenharmony_ci dev_err(&dev->intf->dev, 21962306a36Sopenharmony_ci "couldn't read from i2c device 0x%02x: error %i\n", 22062306a36Sopenharmony_ci client->addr << 1, ret); 22162306a36Sopenharmony_ci continue; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci id += ret; 22462306a36Sopenharmony_ci /* Check product ID */ 22562306a36Sopenharmony_ci switch (id) { 22662306a36Sopenharmony_ci case 0x2642: 22762306a36Sopenharmony_ci name = "OV2640"; 22862306a36Sopenharmony_ci dev->em28xx_sensor = EM28XX_OV2640; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci case 0x7648: 23162306a36Sopenharmony_ci name = "OV7648"; 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci case 0x7660: 23462306a36Sopenharmony_ci name = "OV7660"; 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci case 0x7673: 23762306a36Sopenharmony_ci name = "OV7670"; 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci case 0x7720: 24062306a36Sopenharmony_ci name = "OV7720"; 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci case 0x7721: 24362306a36Sopenharmony_ci name = "OV7725"; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci case 0x9648: /* Rev 2 */ 24662306a36Sopenharmony_ci case 0x9649: /* Rev 3 */ 24762306a36Sopenharmony_ci name = "OV9640"; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case 0x9650: 25062306a36Sopenharmony_ci case 0x9652: /* OV9653 */ 25162306a36Sopenharmony_ci name = "OV9650"; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case 0x9656: /* Rev 4 */ 25462306a36Sopenharmony_ci case 0x9657: /* Rev 5 */ 25562306a36Sopenharmony_ci name = "OV9655"; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci dev_info(&dev->intf->dev, 25962306a36Sopenharmony_ci "unknown OmniVision sensor detected: 0x%04x\n", 26062306a36Sopenharmony_ci id); 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (dev->em28xx_sensor == EM28XX_NOSENSOR) 26562306a36Sopenharmony_ci dev_info(&dev->intf->dev, 26662306a36Sopenharmony_ci "unsupported sensor detected: %s\n", name); 26762306a36Sopenharmony_ci else 26862306a36Sopenharmony_ci dev_info(&dev->intf->dev, 26962306a36Sopenharmony_ci "sensor %s detected\n", name); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return -ENODEV; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ciint em28xx_detect_sensor(struct em28xx *dev) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = em28xx_probe_sensor_micron(dev); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) 28462306a36Sopenharmony_ci ret = em28xx_probe_sensor_omnivision(dev); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* 28762306a36Sopenharmony_ci * NOTE: the Windows driver also probes i2c addresses 28862306a36Sopenharmony_ci * 0x22 (Samsung ?) and 0x66 (Kodak ?) 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { 29262306a36Sopenharmony_ci dev_info(&dev->intf->dev, 29362306a36Sopenharmony_ci "No sensor detected\n"); 29462306a36Sopenharmony_ci return -ENODEV; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciint em28xx_init_camera(struct em28xx *dev) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; 30362306a36Sopenharmony_ci struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; 30462306a36Sopenharmony_ci struct em28xx_v4l2 *v4l2 = dev->v4l2; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci switch (dev->em28xx_sensor) { 30762306a36Sopenharmony_ci case EM28XX_MT9V011: 30862306a36Sopenharmony_ci { 30962306a36Sopenharmony_ci struct mt9v011_platform_data pdata; 31062306a36Sopenharmony_ci struct i2c_board_info mt9v011_info = { 31162306a36Sopenharmony_ci .type = "mt9v011", 31262306a36Sopenharmony_ci .addr = client->addr, 31362306a36Sopenharmony_ci .platform_data = &pdata, 31462306a36Sopenharmony_ci }; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci v4l2->sensor_xres = 640; 31762306a36Sopenharmony_ci v4l2->sensor_yres = 480; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * FIXME: mt9v011 uses I2S speed as xtal clk - at least with 32162306a36Sopenharmony_ci * the Silvercrest cam I have here for testing - for higher 32262306a36Sopenharmony_ci * resolutions, a high clock cause horizontal artifacts, so we 32362306a36Sopenharmony_ci * need to use a lower xclk frequency. 32462306a36Sopenharmony_ci * Yet, it would be possible to adjust xclk depending on the 32562306a36Sopenharmony_ci * desired resolution, since this affects directly the 32662306a36Sopenharmony_ci * frame rate. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; 32962306a36Sopenharmony_ci em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); 33062306a36Sopenharmony_ci v4l2->sensor_xtal = 4300000; 33162306a36Sopenharmony_ci pdata.xtal = v4l2->sensor_xtal; 33262306a36Sopenharmony_ci if (NULL == 33362306a36Sopenharmony_ci v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, 33462306a36Sopenharmony_ci &mt9v011_info, NULL)) 33562306a36Sopenharmony_ci return -ENODEV; 33662306a36Sopenharmony_ci v4l2->vinmode = EM28XX_VINMODE_RGB8_GRBG; 33762306a36Sopenharmony_ci v4l2->vinctl = 0x00; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci case EM28XX_MT9M001: 34262306a36Sopenharmony_ci v4l2->sensor_xres = 1280; 34362306a36Sopenharmony_ci v4l2->sensor_yres = 1024; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci em28xx_initialize_mt9m001(dev); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci v4l2->vinmode = EM28XX_VINMODE_RGB8_BGGR; 34862306a36Sopenharmony_ci v4l2->vinctl = 0x00; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case EM28XX_MT9M111: 35262306a36Sopenharmony_ci v4l2->sensor_xres = 640; 35362306a36Sopenharmony_ci v4l2->sensor_yres = 512; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; 35662306a36Sopenharmony_ci em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); 35762306a36Sopenharmony_ci em28xx_initialize_mt9m111(dev); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci v4l2->vinmode = EM28XX_VINMODE_YUV422_UYVY; 36062306a36Sopenharmony_ci v4l2->vinctl = 0x00; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci case EM28XX_OV2640: 36462306a36Sopenharmony_ci { 36562306a36Sopenharmony_ci struct v4l2_subdev *subdev; 36662306a36Sopenharmony_ci struct i2c_board_info ov2640_info = { 36762306a36Sopenharmony_ci .type = "ov2640", 36862306a36Sopenharmony_ci .flags = I2C_CLIENT_SCCB, 36962306a36Sopenharmony_ci .addr = client->addr, 37062306a36Sopenharmony_ci }; 37162306a36Sopenharmony_ci struct v4l2_subdev_format format = { 37262306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 37362306a36Sopenharmony_ci }; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * FIXME: sensor supports resolutions up to 1600x1200, but 37762306a36Sopenharmony_ci * resolution setting/switching needs to be modified to 37862306a36Sopenharmony_ci * - switch sensor output resolution (including further 37962306a36Sopenharmony_ci * configuration changes) 38062306a36Sopenharmony_ci * - adjust bridge xclk 38162306a36Sopenharmony_ci * - disable 16 bit (12 bit) output formats on high resolutions 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci v4l2->sensor_xres = 640; 38462306a36Sopenharmony_ci v4l2->sensor_yres = 480; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci subdev = 38762306a36Sopenharmony_ci v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, 38862306a36Sopenharmony_ci &ov2640_info, NULL); 38962306a36Sopenharmony_ci if (!subdev) 39062306a36Sopenharmony_ci return -ENODEV; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; 39362306a36Sopenharmony_ci format.format.width = 640; 39462306a36Sopenharmony_ci format.format.height = 480; 39562306a36Sopenharmony_ci v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* NOTE: for UXGA=1600x1200 switch to 12MHz */ 39862306a36Sopenharmony_ci dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; 39962306a36Sopenharmony_ci em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); 40062306a36Sopenharmony_ci v4l2->vinmode = EM28XX_VINMODE_YUV422_YUYV; 40162306a36Sopenharmony_ci v4l2->vinctl = 0x00; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci case EM28XX_NOSENSOR: 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci return -EINVAL; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(em28xx_init_camera); 413