diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-03-08 10:19:44 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 12:43:11 -0300 |
commit | 3160fbc556aa2e60404fa4da35b3e13dd741a5a2 (patch) | |
tree | 51ea0abb1bfbda94749b7b088950942e52a085e5 | |
parent | 4e06839fc7221872d7868855c05659f08d1c9f3d (diff) | |
download | linux-3.10-3160fbc556aa2e60404fa4da35b3e13dd741a5a2.tar.gz linux-3.10-3160fbc556aa2e60404fa4da35b3e13dd741a5a2.tar.bz2 linux-3.10-3160fbc556aa2e60404fa4da35b3e13dd741a5a2.zip |
V4L/DVB (10874): w9968cf/ovcamchip: convert to v4l2_subdev.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/ovcamchip/ovcamchip_core.c | 203 | ||||
-rw-r--r-- | drivers/media/video/ovcamchip/ovcamchip_priv.h | 7 | ||||
-rw-r--r-- | drivers/media/video/w9968cf.c | 114 | ||||
-rw-r--r-- | drivers/media/video/w9968cf.h | 8 |
4 files changed, 126 insertions, 206 deletions
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c index c841f4e4fbe..21ec1dd2e1e 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -15,6 +15,9 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <media/v4l2-device.h> +#include <media/v4l2-i2c-drv.h> #include "ovcamchip_priv.h" #define DRIVER_VERSION "v2.27 for Linux 2.6" @@ -44,6 +47,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); + /* Registers common to all chips, that are needed for detection */ #define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */ #define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */ @@ -61,10 +65,6 @@ static char *chip_names[NUM_CC_TYPES] = { [CC_OV6630AF] = "OV6630AF", }; -/* Forward declarations */ -static struct i2c_driver driver; -static struct i2c_client client_template; - /* ----------------------------------------------------------------------- */ int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals) @@ -253,112 +253,36 @@ static int ovcamchip_detect(struct i2c_client *c) /* Test for 7xx0 */ PDEBUG(3, "Testing for 0V7xx0"); - c->addr = OV7xx0_SID; - if (init_camchip(c) < 0) { - /* Test for 6xx0 */ - PDEBUG(3, "Testing for 0V6xx0"); - c->addr = OV6xx0_SID; - if (init_camchip(c) < 0) { - return -ENODEV; - } else { - if (ov6xx0_detect(c) < 0) { - PERROR("Failed to init OV6xx0"); - return -EIO; - } - } - } else { + if (init_camchip(c) < 0) + return -ENODEV; + /* 7-bit addresses with bit 0 set are for the OV7xx0 */ + if (c->addr & 1) { if (ov7xx0_detect(c) < 0) { PERROR("Failed to init OV7xx0"); return -EIO; } + return 0; + } + /* Test for 6xx0 */ + PDEBUG(3, "Testing for 0V6xx0"); + if (ov6xx0_detect(c) < 0) { + PERROR("Failed to init OV6xx0"); + return -EIO; } - return 0; } /* ----------------------------------------------------------------------- */ -static int ovcamchip_attach(struct i2c_adapter *adap) -{ - int rc = 0; - struct ovcamchip *ov; - struct i2c_client *c; - - /* I2C is not a PnP bus, so we can never be certain that we're talking - * to the right chip. To prevent damage to EEPROMS and such, only - * attach to adapters that are known to contain OV camera chips. */ - - switch (adap->id) { - case I2C_HW_SMBUS_OV511: - case I2C_HW_SMBUS_OV518: - case I2C_HW_SMBUS_W9968CF: - PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id); - break; - default: - PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id); - return -ENODEV; - } - - c = kmalloc(sizeof *c, GFP_KERNEL); - if (!c) { - rc = -ENOMEM; - goto no_client; - } - memcpy(c, &client_template, sizeof *c); - c->adapter = adap; - strcpy(c->name, "OV????"); - - ov = kzalloc(sizeof *ov, GFP_KERNEL); - if (!ov) { - rc = -ENOMEM; - goto no_ov; - } - i2c_set_clientdata(c, ov); - - rc = ovcamchip_detect(c); - if (rc < 0) - goto error; - - strcpy(c->name, chip_names[ov->subtype]); - - PDEBUG(1, "Camera chip detection complete"); - - i2c_attach_client(c); - - return rc; -error: - kfree(ov); -no_ov: - kfree(c); -no_client: - PDEBUG(1, "returning %d", rc); - return rc; -} - -static int ovcamchip_detach(struct i2c_client *c) +static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { - struct ovcamchip *ov = i2c_get_clientdata(c); - int rc; - - rc = ov->sops->free(c); - if (rc < 0) - return rc; - - i2c_detach_client(c); - - kfree(ov); - kfree(c); - return 0; -} - -static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg) -{ - struct ovcamchip *ov = i2c_get_clientdata(c); + struct ovcamchip *ov = to_ovcamchip(sd); + struct i2c_client *c = v4l2_get_subdevdata(sd); if (!ov->initialized && cmd != OVCAMCHIP_CMD_Q_SUBTYPE && cmd != OVCAMCHIP_CMD_INITIALIZE) { - dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n"); + v4l2_err(sd, "Camera chip not initialized yet!\n"); return -EPERM; } @@ -379,10 +303,10 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg) if (ov->mono) { if (ov->subtype != CC_OV7620) - dev_warn(&c->dev, "Warning: Monochrome not " + v4l2_warn(sd, "Monochrome not " "implemented for this chip\n"); else - dev_info(&c->dev, "Initializing chip as " + v4l2_info(sd, "Initializing chip as " "monochrome\n"); } @@ -398,37 +322,80 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg) } } +static int ovcamchip_command(struct i2c_client *client, unsigned cmd, void *arg) +{ + return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); +} + /* ----------------------------------------------------------------------- */ -static struct i2c_driver driver = { - .driver = { - .name = "ovcamchip", - }, - .id = I2C_DRIVERID_OVCAMCHIP, - .attach_adapter = ovcamchip_attach, - .detach_client = ovcamchip_detach, - .command = ovcamchip_command, +static const struct v4l2_subdev_core_ops ovcamchip_core_ops = { + .ioctl = ovcamchip_ioctl, }; -static struct i2c_client client_template = { - .name = "(unset)", - .driver = &driver, +static const struct v4l2_subdev_ops ovcamchip_ops = { + .core = &ovcamchip_core_ops, }; -static int __init ovcamchip_init(void) +static int ovcamchip_probe(struct i2c_client *client, + const struct i2c_device_id *id) { -#ifdef DEBUG - ovcamchip_debug = debug; -#endif + struct ovcamchip *ov; + struct v4l2_subdev *sd; + int rc = 0; - PINFO(DRIVER_VERSION " : " DRIVER_DESC); - return i2c_add_driver(&driver); + ov = kzalloc(sizeof *ov, GFP_KERNEL); + if (!ov) { + rc = -ENOMEM; + goto no_ov; + } + sd = &ov->sd; + v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops); + + rc = ovcamchip_detect(client); + if (rc < 0) + goto error; + + v4l_info(client, "%s found @ 0x%02x (%s)\n", + chip_names[ov->subtype], client->addr << 1, client->adapter->name); + + PDEBUG(1, "Camera chip detection complete"); + + return rc; +error: + kfree(ov); +no_ov: + PDEBUG(1, "returning %d", rc); + return rc; } -static void __exit ovcamchip_exit(void) +static int ovcamchip_remove(struct i2c_client *client) { - i2c_del_driver(&driver); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ovcamchip *ov = to_ovcamchip(sd); + int rc; + + v4l2_device_unregister_subdev(sd); + rc = ov->sops->free(client); + if (rc < 0) + return rc; + + kfree(ov); + return 0; } -module_init(ovcamchip_init); -module_exit(ovcamchip_exit); +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id ovcamchip_id[] = { + { "ovcamchip", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ovcamchip_id); + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "ovcamchip", + .command = ovcamchip_command, + .probe = ovcamchip_probe, + .remove = ovcamchip_remove, + .id_table = ovcamchip_id, +}; diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h index a05650faedd..4f07b78c88b 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_priv.h +++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h @@ -16,6 +16,7 @@ #define __LINUX_OVCAMCHIP_PRIV_H #include <linux/i2c.h> +#include <media/v4l2-subdev.h> #include <media/ovcamchip.h> #ifdef DEBUG @@ -46,6 +47,7 @@ struct ovcamchip_ops { }; struct ovcamchip { + struct v4l2_subdev sd; struct ovcamchip_ops *sops; void *spriv; /* Private data for OV7x10.c etc... */ int subtype; /* = SEN_OV7610 etc... */ @@ -53,6 +55,11 @@ struct ovcamchip { int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */ }; +static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ovcamchip, sd); +} + extern struct ovcamchip_ops ov6x20_ops; extern struct ovcamchip_ops ov6x30_ops; extern struct ovcamchip_ops ov7x10_ops; diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 3318be5688c..fd5c4c87a73 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -68,7 +68,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION); MODULE_LICENSE(W9968CF_MODULE_LICENSE); MODULE_SUPPORTED_DEVICE("Video"); -static int ovmod_load = W9968CF_OVMOD_LOAD; static unsigned short simcams = W9968CF_SIMCAMS; static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = @@ -111,9 +110,6 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG; static unsigned int param_nv[24]; /* number of values per parameter */ -#ifdef CONFIG_MODULES -module_param(ovmod_load, bool, 0644); -#endif module_param(simcams, ushort, 0644); module_param_array(video_nr, short, ¶m_nv[0], 0444); module_param_array(packet_size, uint, ¶m_nv[1], 0444); @@ -144,18 +140,6 @@ module_param(debug, ushort, 0644); module_param(specific_debug, bool, 0644); #endif -#ifdef CONFIG_MODULES -MODULE_PARM_DESC(ovmod_load, - "\n<0|1> Automatic 'ovcamchip' module loading." - "\n0 disabled, 1 enabled." - "\nIf enabled,'insmod' searches for the required 'ovcamchip'" - "\nmodule in the system, according to its configuration, and" - "\nattempts to load that module automatically. This action is" - "\nperformed once as soon as the 'w9968cf' module is loaded" - "\ninto memory." - "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"." - "\n"); -#endif MODULE_PARM_DESC(simcams, "\n<n> Number of cameras allowed to stream simultaneously." "\nn may vary from 0 to " @@ -443,8 +427,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data*); static u32 w9968cf_i2c_func(struct i2c_adapter*); -static int w9968cf_i2c_attach_inform(struct i2c_client*); -static int w9968cf_i2c_detach_inform(struct i2c_client*); /* Memory management */ static void* rvmalloc(unsigned long size); @@ -1443,19 +1425,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { - struct w9968cf_device* cam = i2c_get_adapdata(adapter); + struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); + struct w9968cf_device *cam = to_cam(v4l2_dev); u8 i; int err = 0; - switch (addr) { - case OV6xx0_SID: - case OV7xx0_SID: - break; - default: - DBG(4, "Rejected slave ID 0x%04X", addr) - return -EINVAL; - } - if (size == I2C_SMBUS_BYTE) { /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ addr <<= 1; @@ -1463,8 +1437,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, if (read_write == I2C_SMBUS_WRITE) err = w9968cf_i2c_adap_write_byte(cam, addr, command); else if (read_write == I2C_SMBUS_READ) - err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); - + for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { + err = w9968cf_i2c_adap_read_byte(cam, addr, + &data->byte); + if (err) { + if (w9968cf_smbus_refresh_bus(cam)) { + err = -EIO; + break; + } + } else + break; + } } else if (size == I2C_SMBUS_BYTE_DATA) { addr <<= 1; @@ -1491,7 +1474,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, DBG(4, "Unsupported I2C transfer mode (%d)", size) return -EINVAL; } - return err; } @@ -1504,44 +1486,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap) } -static int w9968cf_i2c_attach_inform(struct i2c_client* client) -{ - struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); - int id = client->driver->id, err = 0; - - if (id == I2C_DRIVERID_OVCAMCHIP) { - cam->sensor_client = client; - err = w9968cf_sensor_init(cam); - if (err) { - cam->sensor_client = NULL; - return err; - } - } else { - DBG(4, "Rejected client [%s] with driver [%s]", - client->name, client->driver->driver.name) - return -EINVAL; - } - - DBG(5, "I2C attach client [%s] with driver [%s]", - client->name, client->driver->driver.name) - - return 0; -} - - -static int w9968cf_i2c_detach_inform(struct i2c_client* client) -{ - struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); - - if (cam->sensor_client == client) - cam->sensor_client = NULL; - - DBG(5, "I2C detach client [%s]", client->name) - - return 0; -} - - static int w9968cf_i2c_init(struct w9968cf_device* cam) { int err = 0; @@ -1554,15 +1498,13 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam) static struct i2c_adapter adap = { .id = I2C_HW_SMBUS_W9968CF, .owner = THIS_MODULE, - .client_register = w9968cf_i2c_attach_inform, - .client_unregister = w9968cf_i2c_detach_inform, .algo = &algo, }; memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); strcpy(cam->i2c_adapter.name, "w9968cf"); cam->i2c_adapter.dev.parent = &cam->usbdev->dev; - i2c_set_adapdata(&cam->i2c_adapter, cam); + i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev); DBG(6, "Registering I2C adapter with kernel...") @@ -2165,13 +2107,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) static int w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) { - struct i2c_client* c = cam->sensor_client; - int rc = 0; + int rc; - if (!c || !c->driver || !c->driver->command) - return -EINVAL; - - rc = c->driver->command(c, cmd, arg); + rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg); /* The I2C driver returns -EPERM on non-supported controls */ return (rc < 0 && rc != -EPERM) ? rc : 0; } @@ -2346,7 +2284,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam) goto error; /* NOTE: Make sure width and height are a multiple of 16 */ - switch (cam->sensor_client->addr) { + switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) { case OV6xx0_SID: cam->maxwidth = 352; cam->maxheight = 288; @@ -2651,6 +2589,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) w9968cf_deallocate_memory(cam); kfree(cam->control_buffer); kfree(cam->data_buffer); + v4l2_device_unregister(&cam->v4l2_dev); mutex_unlock(&w9968cf_devlist_mutex); } @@ -3480,6 +3419,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) struct list_head* ptr; u8 sc = 0; /* number of simultaneous cameras */ static unsigned short dev_nr; /* 0 - we are handling device number n */ + static unsigned short addrs[] = { + OV7xx0_SID, + OV6xx0_SID, + I2C_CLIENT_END + }; if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) @@ -3578,12 +3522,13 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) w9968cf_turn_on_led(cam); w9968cf_i2c_init(cam); + cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter, + "ovcamchip", "ovcamchip", addrs); usb_set_intfdata(intf, cam); mutex_unlock(&cam->dev_mutex); - if (ovmod_load) - request_module("ovcamchip"); + err = w9968cf_sensor_init(cam); return 0; fail: /* Free unused memory */ @@ -3604,9 +3549,8 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) struct w9968cf_device* cam = (struct w9968cf_device*)usb_get_intfdata(intf); - down_write(&w9968cf_disconnect); - if (cam) { + down_write(&w9968cf_disconnect); /* Prevent concurrent accesses to data */ mutex_lock(&cam->dev_mutex); @@ -3628,14 +3572,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) w9968cf_release_resources(cam); mutex_unlock(&cam->dev_mutex); + up_write(&w9968cf_disconnect); if (!cam->users) { - v4l2_device_unregister(&cam->v4l2_dev); kfree(cam); } } - - up_write(&w9968cf_disconnect); } diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h index c5988355254..fdfc6a4e1c8 100644 --- a/drivers/media/video/w9968cf.h +++ b/drivers/media/video/w9968cf.h @@ -43,7 +43,6 @@ * Default values * ****************************************************************************/ -#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */ #define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */ /* Comment/uncomment the following line to enable/disable debugging messages */ @@ -265,7 +264,7 @@ struct w9968cf_device { /* I2C interface to kernel */ struct i2c_adapter i2c_adapter; - struct i2c_client* sensor_client; + struct v4l2_subdev *sensor_sd; /* Locks */ struct mutex dev_mutex, /* for probe, disconnect,open and close */ @@ -277,6 +276,11 @@ struct w9968cf_device { char command[16]; /* name of the program holding the device */ }; +static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev); +} + /**************************************************************************** * Macros for debugging * |