Commit 3160fbc5 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (10874): w9968cf/ovcamchip: convert to v4l2_subdev.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4e06839f
......@@ -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) {
if (init_camchip(c) < 0)
return -ENODEV;
} else {
if (ov6xx0_detect(c) < 0) {
PERROR("Failed to init OV6xx0");
return -EIO;
}
}
} else {
/* 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;
}
/* ----------------------------------------------------------------------- */
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;
/* Test for 6xx0 */
PDEBUG(3, "Testing for 0V6xx0");
if (ov6xx0_detect(c) < 0) {
PERROR("Failed to init OV6xx0");
return -EIO;
}
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)
{
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)
/* ----------------------------------------------------------------------- */
static long ovcamchip_ioctl(struct v4l2_subdev *sd, 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;
ov = kzalloc(sizeof *ov, GFP_KERNEL);
if (!ov) {
rc = -ENOMEM;
goto no_ov;
}
sd = &ov->sd;
v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
PINFO(DRIVER_VERSION " : " DRIVER_DESC);
return i2c_add_driver(&driver);
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,
};
......@@ -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;
......
......@@ -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;
if (!c || !c->driver || !c->driver->command)
return -EINVAL;
int rc;
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);
}
......
......@@ -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 *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment