diff options
Diffstat (limited to 'drivers/media/usb/em28xx/em28xx-camera.c')
| -rw-r--r-- | drivers/media/usb/em28xx/em28xx-camera.c | 226 |
1 files changed, 102 insertions, 124 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 73cc50afa5e1..b5f58dc6dd0f 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -1,32 +1,17 @@ -/* - em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices - - Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org> - Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +// SPDX-License-Identifier: GPL-2.0+ +// +// em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices +// +// Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org> +// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +#include "em28xx.h" #include <linux/i2c.h> -#include <media/soc_camera.h> -#include <media/mt9v011.h> +#include <linux/usb.h> +#include <media/i2c/mt9v011.h> #include <media/v4l2-common.h> -#include "em28xx.h" - - /* Possible i2c addresses of Micron sensors */ static unsigned short micron_sensor_addrs[] = { 0xb8 >> 1, /* MT9V111, MT9V403 */ @@ -42,14 +27,6 @@ static unsigned short omnivision_sensor_addrs[] = { I2C_CLIENT_END }; - -static struct soc_camera_link camlink = { - .bus_id = 0, - .flags = 0, - .module_name = "em28xx", -}; - - /* FIXME: Should be replaced by a proper mt9m111 driver */ static int em28xx_initialize_mt9m111(struct em28xx *dev) { @@ -58,17 +35,18 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev) { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ { 0x0d, 0x00, 0x00, }, { 0x0a, 0x00, 0x21, }, - { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ + { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */ }; for (i = 0; i < ARRAY_SIZE(regs); i++) i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®s[i][0], 3); + /* FIXME: This won't be creating a sensor at the media graph */ + return 0; } - /* FIXME: Should be replaced by a proper mt9m001 driver */ static int em28xx_initialize_mt9m001(struct em28xx *dev) { @@ -93,10 +71,11 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev) i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®s[i][0], 3); + /* FIXME: This won't be creating a sensor at the media graph */ + return 0; } - /* * Probes Micron sensors with 8 bit address and 16 bit register width */ @@ -104,51 +83,35 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) { int ret, i; char *name; - u8 reg; - __be16 id_be; u16 id; - struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; + struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; dev->em28xx_sensor = EM28XX_NOSENSOR; for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { - client.addr = micron_sensor_addrs[i]; - /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */ + client->addr = micron_sensor_addrs[i]; /* Read chip ID from register 0x00 */ - reg = 0x00; - ret = i2c_master_send(&client, ®, 1); + ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */ if (ret < 0) { - if (ret != -ENODEV) - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + if (ret != -ENXIO) + dev_err(&dev->intf->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client->addr << 1, ret); continue; } - ret = i2c_master_recv(&client, (u8 *)&id_be, 2); - if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); - continue; - } - id = be16_to_cpu(id_be); + id = swab16(ret); /* LE -> BE */ /* Read chip ID from register 0xff */ - reg = 0xff; - ret = i2c_master_send(&client, ®, 1); - if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); - continue; - } - ret = i2c_master_recv(&client, (u8 *)&id_be, 2); + ret = i2c_smbus_read_word_data(client, 0xff); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->intf->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client->addr << 1, ret); continue; } /* Validate chip ID to be sure we have a Micron device */ - if (id != be16_to_cpu(id_be)) + if (id != swab16(ret)) continue; /* Check chip ID */ - id = be16_to_cpu(id_be); switch (id) { case 0x1222: name = "MT9V012"; /* MI370 */ /* 640x480 */ @@ -179,17 +142,19 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) dev->em28xx_sensor = EM28XX_MT9M001; break; default: - em28xx_info("unknown Micron sensor detected: 0x%04x\n", - id); + dev_info(&dev->intf->dev, + "unknown Micron sensor detected: 0x%04x\n", + id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - em28xx_info("unsupported sensor detected: %s\n", name); + dev_info(&dev->intf->dev, + "unsupported sensor detected: %s\n", name); else - em28xx_info("sensor %s detected\n", name); + dev_info(&dev->intf->dev, + "sensor %s detected\n", name); - dev->i2c_client[dev->def_i2c_bus].addr = client.addr; return 0; } @@ -205,28 +170,32 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) char *name; u8 reg; u16 id; - struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; + struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; dev->em28xx_sensor = EM28XX_NOSENSOR; - /* NOTE: these devices have the register auto incrementation disabled - * by default, so we have to use single byte reads ! */ + /* + * NOTE: these devices have the register auto incrementation disabled + * by default, so we have to use single byte reads ! + */ for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { - client.addr = omnivision_sensor_addrs[i]; + client->addr = omnivision_sensor_addrs[i]; /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ reg = 0x1c; - ret = i2c_smbus_read_byte_data(&client, reg); + ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) { - if (ret != -ENODEV) - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + if (ret != -ENXIO) + dev_err(&dev->intf->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client->addr << 1, ret); continue; } id = ret << 8; reg = 0x1d; - ret = i2c_smbus_read_byte_data(&client, reg); + ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->intf->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client->addr << 1, ret); continue; } id += ret; @@ -235,18 +204,20 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) continue; /* Read product ID from registers 0x0a-0x0b (BE) */ reg = 0x0a; - ret = i2c_smbus_read_byte_data(&client, reg); + ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->intf->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client->addr << 1, ret); continue; } id = ret << 8; reg = 0x0b; - ret = i2c_smbus_read_byte_data(&client, reg); + ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->intf->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client->addr << 1, ret); continue; } id += ret; @@ -284,17 +255,19 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) name = "OV9655"; break; default: - em28xx_info("unknown OmniVision sensor detected: 0x%04x\n", - id); + dev_info(&dev->intf->dev, + "unknown OmniVision sensor detected: 0x%04x\n", + id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - em28xx_info("unsupported sensor detected: %s\n", name); + dev_info(&dev->intf->dev, + "unsupported sensor detected: %s\n", name); else - em28xx_info("sensor %s detected\n", name); + dev_info(&dev->intf->dev, + "sensor %s detected\n", name); - dev->i2c_client[dev->def_i2c_bus].addr = client.addr; return 0; } @@ -316,7 +289,8 @@ int em28xx_detect_sensor(struct em28xx *dev) */ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { - em28xx_info("No sensor detected\n"); + dev_info(&dev->intf->dev, + "No sensor detected\n"); return -ENODEV; } @@ -325,18 +299,22 @@ int em28xx_detect_sensor(struct em28xx *dev) int em28xx_init_camera(struct em28xx *dev) { + struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; + struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; + struct em28xx_v4l2 *v4l2 = dev->v4l2; + switch (dev->em28xx_sensor) { case EM28XX_MT9V011: { struct mt9v011_platform_data pdata; struct i2c_board_info mt9v011_info = { .type = "mt9v011", - .addr = dev->i2c_client[dev->def_i2c_bus].addr, + .addr = client->addr, .platform_data = &pdata, }; - dev->sensor_xres = 640; - dev->sensor_yres = 480; + v4l2->sensor_xres = 640; + v4l2->sensor_yres = 480; /* * FIXME: mt9v011 uses I2S speed as xtal clk - at least with @@ -349,40 +327,37 @@ int em28xx_init_camera(struct em28xx *dev) */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); - dev->sensor_xtal = 4300000; - pdata.xtal = dev->sensor_xtal; + v4l2->sensor_xtal = 4300000; + pdata.xtal = v4l2->sensor_xtal; if (NULL == - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], + v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &mt9v011_info, NULL)) return -ENODEV; - /* probably means GRGB 16 bit bayer */ - dev->vinmode = 0x0d; - dev->vinctl = 0x00; + v4l2->vinmode = EM28XX_VINMODE_RGB8_GRBG; + v4l2->vinctl = 0x00; break; } case EM28XX_MT9M001: - dev->sensor_xres = 1280; - dev->sensor_yres = 1024; + v4l2->sensor_xres = 1280; + v4l2->sensor_yres = 1024; em28xx_initialize_mt9m001(dev); - /* probably means BGGR 16 bit bayer */ - dev->vinmode = 0x0c; - dev->vinctl = 0x00; + v4l2->vinmode = EM28XX_VINMODE_RGB8_BGGR; + v4l2->vinctl = 0x00; break; case EM28XX_MT9M111: - dev->sensor_xres = 640; - dev->sensor_yres = 512; + v4l2->sensor_xres = 640; + v4l2->sensor_yres = 512; dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); em28xx_initialize_mt9m111(dev); - dev->vinmode = 0x0a; - dev->vinctl = 0x00; + v4l2->vinmode = EM28XX_VINMODE_YUV422_UYVY; + v4l2->vinctl = 0x00; break; case EM28XX_OV2640: @@ -391,10 +366,11 @@ int em28xx_init_camera(struct em28xx *dev) struct i2c_board_info ov2640_info = { .type = "ov2640", .flags = I2C_CLIENT_SCCB, - .addr = dev->i2c_client[dev->def_i2c_bus].addr, - .platform_data = &camlink, + .addr = client->addr, + }; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - struct v4l2_mbus_framefmt fmt; /* * FIXME: sensor supports resolutions up to 1600x1200, but @@ -404,24 +380,25 @@ int em28xx_init_camera(struct em28xx *dev) * - adjust bridge xclk * - disable 16 bit (12 bit) output formats on high resolutions */ - dev->sensor_xres = 640; - dev->sensor_yres = 480; + v4l2->sensor_xres = 640; + v4l2->sensor_yres = 480; subdev = - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], + v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &ov2640_info, NULL); + if (!subdev) + return -ENODEV; - fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; - fmt.width = 640; - fmt.height = 480; - v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt); + format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; + format.format.width = 640; + format.format.height = 480; + v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); /* NOTE: for UXGA=1600x1200 switch to 12MHz */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); - dev->vinmode = 0x08; - dev->vinctl = 0x00; + v4l2->vinmode = EM28XX_VINMODE_YUV422_YUYV; + v4l2->vinctl = 0x00; break; } @@ -432,3 +409,4 @@ int em28xx_init_camera(struct em28xx *dev) return 0; } +EXPORT_SYMBOL_GPL(em28xx_init_camera); |
