diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-03-18 12:16:44 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:30 -0400 |
commit | 8bcfd7af902eaa7c0029082247fe0682ce0c1a5b (patch) | |
tree | 8f3fdd9eaf3fb4608dbf97b6c83dd259ec99db7d /drivers/media/video | |
parent | 21508b902b314e0cd9c081a9141b138e96c9f441 (diff) |
V4L/DVB (11115): cafe_ccic: use v4l2_subdev to talk to the ov7670 sensor.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Acked-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/cafe_ccic.c | 106 |
1 files changed, 32 insertions, 74 deletions
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 600dde379efe..3363e501d6d7 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c | |||
@@ -148,7 +148,8 @@ struct cafe_camera | |||
148 | struct pci_dev *pdev; | 148 | struct pci_dev *pdev; |
149 | struct video_device vdev; | 149 | struct video_device vdev; |
150 | struct i2c_adapter i2c_adapter; | 150 | struct i2c_adapter i2c_adapter; |
151 | struct i2c_client *sensor; | 151 | struct v4l2_subdev *sensor; |
152 | unsigned short sensor_addr; | ||
152 | 153 | ||
153 | unsigned char __iomem *regs; | 154 | unsigned char __iomem *regs; |
154 | struct list_head dev_list; /* link to other devices */ | 155 | struct list_head dev_list; /* link to other devices */ |
@@ -196,6 +197,8 @@ struct cafe_camera | |||
196 | #define CF_DMA_ACTIVE 3 /* A frame is incoming */ | 197 | #define CF_DMA_ACTIVE 3 /* A frame is incoming */ |
197 | #define CF_CONFIG_NEEDED 4 /* Must configure hardware */ | 198 | #define CF_CONFIG_NEEDED 4 /* Must configure hardware */ |
198 | 199 | ||
200 | #define sensor_call(cam, o, f, args...) \ | ||
201 | v4l2_subdev_call(cam->sensor, o, f, ##args) | ||
199 | 202 | ||
200 | static inline struct cafe_camera *to_cam(struct v4l2_device *dev) | 203 | static inline struct cafe_camera *to_cam(struct v4l2_device *dev) |
201 | { | 204 | { |
@@ -440,14 +443,6 @@ static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | |||
440 | int ret = -EINVAL; | 443 | int ret = -EINVAL; |
441 | 444 | ||
442 | /* | 445 | /* |
443 | * Refuse to talk to anything but OV cam chips. We should | ||
444 | * never even see an attempt to do so, but one never knows. | ||
445 | */ | ||
446 | if (cam->sensor && addr != cam->sensor->addr) { | ||
447 | cam_err(cam, "funky smbus addr %d\n", addr); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | /* | ||
451 | * This interface would appear to only do byte data ops. OK | 446 | * This interface would appear to only do byte data ops. OK |
452 | * it can do word too, but the cam chip has no use for that. | 447 | * it can do word too, but the cam chip has no use for that. |
453 | */ | 448 | */ |
@@ -485,40 +480,9 @@ static struct i2c_algorithm cafe_smbus_algo = { | |||
485 | }; | 480 | }; |
486 | 481 | ||
487 | /* Somebody is on the bus */ | 482 | /* Somebody is on the bus */ |
488 | static int cafe_cam_init(struct cafe_camera *cam); | ||
489 | static void cafe_ctlr_stop_dma(struct cafe_camera *cam); | 483 | static void cafe_ctlr_stop_dma(struct cafe_camera *cam); |
490 | static void cafe_ctlr_power_down(struct cafe_camera *cam); | 484 | static void cafe_ctlr_power_down(struct cafe_camera *cam); |
491 | 485 | ||
492 | static int cafe_smbus_attach(struct i2c_client *client) | ||
493 | { | ||
494 | struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter); | ||
495 | struct cafe_camera *cam = to_cam(v4l2_dev); | ||
496 | |||
497 | /* | ||
498 | * Don't talk to chips we don't recognize. | ||
499 | */ | ||
500 | if (client->driver->id == I2C_DRIVERID_OV7670) { | ||
501 | cam->sensor = client; | ||
502 | return cafe_cam_init(cam); | ||
503 | } | ||
504 | return -EINVAL; | ||
505 | } | ||
506 | |||
507 | static int cafe_smbus_detach(struct i2c_client *client) | ||
508 | { | ||
509 | struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter); | ||
510 | struct cafe_camera *cam = to_cam(v4l2_dev); | ||
511 | |||
512 | if (cam->sensor == client) { | ||
513 | cafe_ctlr_stop_dma(cam); | ||
514 | cafe_ctlr_power_down(cam); | ||
515 | cam_err(cam, "lost the sensor!\n"); | ||
516 | cam->sensor = NULL; /* Bummer, no camera */ | ||
517 | cam->state = S_NOTREADY; | ||
518 | } | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static int cafe_smbus_setup(struct cafe_camera *cam) | 486 | static int cafe_smbus_setup(struct cafe_camera *cam) |
523 | { | 487 | { |
524 | struct i2c_adapter *adap = &cam->i2c_adapter; | 488 | struct i2c_adapter *adap = &cam->i2c_adapter; |
@@ -527,8 +491,6 @@ static int cafe_smbus_setup(struct cafe_camera *cam) | |||
527 | cafe_smbus_enable_irq(cam); | 491 | cafe_smbus_enable_irq(cam); |
528 | adap->id = I2C_HW_SMBUS_CAFE; | 492 | adap->id = I2C_HW_SMBUS_CAFE; |
529 | adap->owner = THIS_MODULE; | 493 | adap->owner = THIS_MODULE; |
530 | adap->client_register = cafe_smbus_attach; | ||
531 | adap->client_unregister = cafe_smbus_detach; | ||
532 | adap->algo = &cafe_smbus_algo; | 494 | adap->algo = &cafe_smbus_algo; |
533 | strcpy(adap->name, "cafe_ccic"); | 495 | strcpy(adap->name, "cafe_ccic"); |
534 | adap->dev.parent = &cam->pdev->dev; | 496 | adap->dev.parent = &cam->pdev->dev; |
@@ -790,23 +752,9 @@ static void cafe_ctlr_power_down(struct cafe_camera *cam) | |||
790 | * Communications with the sensor. | 752 | * Communications with the sensor. |
791 | */ | 753 | */ |
792 | 754 | ||
793 | static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg) | ||
794 | { | ||
795 | struct i2c_client *sc = cam->sensor; | ||
796 | int ret; | ||
797 | |||
798 | if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL) | ||
799 | return -EINVAL; | ||
800 | ret = sc->driver->command(sc, cmd, arg); | ||
801 | if (ret == -EPERM) /* Unsupported command */ | ||
802 | return 0; | ||
803 | return ret; | ||
804 | } | ||
805 | |||
806 | static int __cafe_cam_reset(struct cafe_camera *cam) | 755 | static int __cafe_cam_reset(struct cafe_camera *cam) |
807 | { | 756 | { |
808 | int zero = 0; | 757 | return sensor_call(cam, core, reset, 0); |
809 | return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero); | ||
810 | } | 758 | } |
811 | 759 | ||
812 | /* | 760 | /* |
@@ -826,14 +774,13 @@ static int cafe_cam_init(struct cafe_camera *cam) | |||
826 | if (ret) | 774 | if (ret) |
827 | goto out; | 775 | goto out; |
828 | chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; | 776 | chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; |
829 | chip.match.addr = cam->sensor->addr; | 777 | chip.match.addr = cam->sensor_addr; |
830 | ret = __cafe_cam_cmd(cam, VIDIOC_DBG_G_CHIP_IDENT, &chip); | 778 | ret = sensor_call(cam, core, g_chip_ident, &chip); |
831 | if (ret) | 779 | if (ret) |
832 | goto out; | 780 | goto out; |
833 | cam->sensor_type = chip.ident; | 781 | cam->sensor_type = chip.ident; |
834 | /* if (cam->sensor->addr != OV7xx0_SID) { */ | ||
835 | if (cam->sensor_type != V4L2_IDENT_OV7670) { | 782 | if (cam->sensor_type != V4L2_IDENT_OV7670) { |
836 | cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); | 783 | cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); |
837 | ret = -EINVAL; | 784 | ret = -EINVAL; |
838 | goto out; | 785 | goto out; |
839 | } | 786 | } |
@@ -857,21 +804,21 @@ static int cafe_cam_set_flip(struct cafe_camera *cam) | |||
857 | memset(&ctrl, 0, sizeof(ctrl)); | 804 | memset(&ctrl, 0, sizeof(ctrl)); |
858 | ctrl.id = V4L2_CID_VFLIP; | 805 | ctrl.id = V4L2_CID_VFLIP; |
859 | ctrl.value = flip; | 806 | ctrl.value = flip; |
860 | return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl); | 807 | return sensor_call(cam, core, s_ctrl, &ctrl); |
861 | } | 808 | } |
862 | 809 | ||
863 | 810 | ||
864 | static int cafe_cam_configure(struct cafe_camera *cam) | 811 | static int cafe_cam_configure(struct cafe_camera *cam) |
865 | { | 812 | { |
866 | struct v4l2_format fmt; | 813 | struct v4l2_format fmt; |
867 | int ret, zero = 0; | 814 | int ret; |
868 | 815 | ||
869 | if (cam->state != S_IDLE) | 816 | if (cam->state != S_IDLE) |
870 | return -EINVAL; | 817 | return -EINVAL; |
871 | fmt.fmt.pix = cam->pix_format; | 818 | fmt.fmt.pix = cam->pix_format; |
872 | ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero); | 819 | ret = sensor_call(cam, core, init, 0); |
873 | if (ret == 0) | 820 | if (ret == 0) |
874 | ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt); | 821 | ret = sensor_call(cam, video, s_fmt, &fmt); |
875 | /* | 822 | /* |
876 | * OV7670 does weird things if flip is set *before* format... | 823 | * OV7670 does weird things if flip is set *before* format... |
877 | */ | 824 | */ |
@@ -1490,7 +1437,7 @@ static int cafe_vidioc_queryctrl(struct file *filp, void *priv, | |||
1490 | int ret; | 1437 | int ret; |
1491 | 1438 | ||
1492 | mutex_lock(&cam->s_mutex); | 1439 | mutex_lock(&cam->s_mutex); |
1493 | ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc); | 1440 | ret = sensor_call(cam, core, queryctrl, qc); |
1494 | mutex_unlock(&cam->s_mutex); | 1441 | mutex_unlock(&cam->s_mutex); |
1495 | return ret; | 1442 | return ret; |
1496 | } | 1443 | } |
@@ -1503,7 +1450,7 @@ static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, | |||
1503 | int ret; | 1450 | int ret; |
1504 | 1451 | ||
1505 | mutex_lock(&cam->s_mutex); | 1452 | mutex_lock(&cam->s_mutex); |
1506 | ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl); | 1453 | ret = sensor_call(cam, core, g_ctrl, ctrl); |
1507 | mutex_unlock(&cam->s_mutex); | 1454 | mutex_unlock(&cam->s_mutex); |
1508 | return ret; | 1455 | return ret; |
1509 | } | 1456 | } |
@@ -1516,7 +1463,7 @@ static int cafe_vidioc_s_ctrl(struct file *filp, void *priv, | |||
1516 | int ret; | 1463 | int ret; |
1517 | 1464 | ||
1518 | mutex_lock(&cam->s_mutex); | 1465 | mutex_lock(&cam->s_mutex); |
1519 | ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl); | 1466 | ret = sensor_call(cam, core, s_ctrl, ctrl); |
1520 | mutex_unlock(&cam->s_mutex); | 1467 | mutex_unlock(&cam->s_mutex); |
1521 | return ret; | 1468 | return ret; |
1522 | } | 1469 | } |
@@ -1558,7 +1505,7 @@ static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp, | |||
1558 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1505 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1559 | return -EINVAL; | 1506 | return -EINVAL; |
1560 | mutex_lock(&cam->s_mutex); | 1507 | mutex_lock(&cam->s_mutex); |
1561 | ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt); | 1508 | ret = sensor_call(cam, video, enum_fmt, fmt); |
1562 | mutex_unlock(&cam->s_mutex); | 1509 | mutex_unlock(&cam->s_mutex); |
1563 | return ret; | 1510 | return ret; |
1564 | } | 1511 | } |
@@ -1571,7 +1518,7 @@ static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, | |||
1571 | int ret; | 1518 | int ret; |
1572 | 1519 | ||
1573 | mutex_lock(&cam->s_mutex); | 1520 | mutex_lock(&cam->s_mutex); |
1574 | ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt); | 1521 | ret = sensor_call(cam, video, try_fmt, fmt); |
1575 | mutex_unlock(&cam->s_mutex); | 1522 | mutex_unlock(&cam->s_mutex); |
1576 | return ret; | 1523 | return ret; |
1577 | } | 1524 | } |
@@ -1680,7 +1627,7 @@ static int cafe_vidioc_g_parm(struct file *filp, void *priv, | |||
1680 | int ret; | 1627 | int ret; |
1681 | 1628 | ||
1682 | mutex_lock(&cam->s_mutex); | 1629 | mutex_lock(&cam->s_mutex); |
1683 | ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms); | 1630 | ret = sensor_call(cam, video, g_parm, parms); |
1684 | mutex_unlock(&cam->s_mutex); | 1631 | mutex_unlock(&cam->s_mutex); |
1685 | parms->parm.capture.readbuffers = n_dma_bufs; | 1632 | parms->parm.capture.readbuffers = n_dma_bufs; |
1686 | return ret; | 1633 | return ret; |
@@ -1693,7 +1640,7 @@ static int cafe_vidioc_s_parm(struct file *filp, void *priv, | |||
1693 | int ret; | 1640 | int ret; |
1694 | 1641 | ||
1695 | mutex_lock(&cam->s_mutex); | 1642 | mutex_lock(&cam->s_mutex); |
1696 | ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms); | 1643 | ret = sensor_call(cam, video, s_parm, parms); |
1697 | mutex_unlock(&cam->s_mutex); | 1644 | mutex_unlock(&cam->s_mutex); |
1698 | parms->parm.capture.readbuffers = n_dma_bufs; | 1645 | parms->parm.capture.readbuffers = n_dma_bufs; |
1699 | return ret; | 1646 | return ret; |
@@ -1973,7 +1920,7 @@ static ssize_t cafe_dfs_read_cam(struct file *file, | |||
1973 | { | 1920 | { |
1974 | u8 v; | 1921 | u8 v; |
1975 | 1922 | ||
1976 | cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v); | 1923 | cafe_smbus_read_data(cam, cam->sensor_addr, offset, &v); |
1977 | s += sprintf(s, "%02x: %02x\n", offset, v); | 1924 | s += sprintf(s, "%02x: %02x\n", offset, v); |
1978 | } | 1925 | } |
1979 | return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, | 1926 | return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, |
@@ -2089,6 +2036,18 @@ static int cafe_pci_probe(struct pci_dev *pdev, | |||
2089 | ret = cafe_smbus_setup(cam); | 2036 | ret = cafe_smbus_setup(cam); |
2090 | if (ret) | 2037 | if (ret) |
2091 | goto out_freeirq; | 2038 | goto out_freeirq; |
2039 | |||
2040 | cam->sensor_addr = 0x42; | ||
2041 | cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter, | ||
2042 | "ov7670", "ov7670", cam->sensor_addr); | ||
2043 | if (cam->sensor == NULL) { | ||
2044 | ret = -ENODEV; | ||
2045 | goto out_smbus; | ||
2046 | } | ||
2047 | ret = cafe_cam_init(cam); | ||
2048 | if (ret) | ||
2049 | goto out_smbus; | ||
2050 | |||
2092 | /* | 2051 | /* |
2093 | * Get the v4l2 setup done. | 2052 | * Get the v4l2 setup done. |
2094 | */ | 2053 | */ |
@@ -2263,7 +2222,6 @@ static int __init cafe_init(void) | |||
2263 | printk(KERN_ERR "Unable to register cafe_ccic driver\n"); | 2222 | printk(KERN_ERR "Unable to register cafe_ccic driver\n"); |
2264 | goto out; | 2223 | goto out; |
2265 | } | 2224 | } |
2266 | request_module("ov7670"); /* FIXME want something more general */ | ||
2267 | ret = 0; | 2225 | ret = 0; |
2268 | 2226 | ||
2269 | out: | 2227 | out: |