V4L/DVB (10874): w9968cf/ovcamchip: convert to v4l2_subdev.
authorHans Verkuil <hverkuil@xs4all.nl>
Sun, 8 Mar 2009 13:19:44 +0000 (10:19 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 30 Mar 2009 15:43:11 +0000 (12:43 -0300)
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/ovcamchip/ovcamchip_priv.h
drivers/media/video/w9968cf.c
drivers/media/video/w9968cf.h

index c841f4e..21ec1dd 100644 (file)
@@ -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,
+};
index a05650f..4f07b78 100644 (file)
@@ -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;
index 3318be5..fd5c4c8 100644 (file)
@@ -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, &param_nv[0], 0444);
 module_param_array(packet_size, uint, &param_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);
 }
 
 
index c598835..fdfc6a4 100644 (file)
@@ -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                                                     *