Fix unnecesary meminit
[powerpc.git] / drivers / media / video / cafe_ccic.c
index 682dc7c..96254db 100644 (file)
@@ -4,6 +4,7 @@
  * sensor.
  *
  * Copyright 2006 One Laptop Per Child Association, Inc.
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
  *
  * Written by Jonathan Corbet, corbet@lwn.net.
  *
@@ -22,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/list.h>
@@ -36,7 +38,7 @@
 
 #include "cafe_ccic-regs.h"
 
-#define CAFE_VERSION 0x000001
+#define CAFE_VERSION 0x000002
 
 
 /*
@@ -164,7 +166,7 @@ struct cafe_camera
        struct tasklet_struct s_tasklet;
 
        /* Current operating parameters */
-       enum v4l2_chip_ident sensor_type;               /* Currently ov7670 only */
+       u32 sensor_type;                /* Currently ov7670 only */
        struct v4l2_pix_format pix_format;
 
        /* Locks */
@@ -704,7 +706,13 @@ static void cafe_ctlr_init(struct cafe_camera *cam)
        cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
        cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
        cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+       /*
+        * Here we must wait a bit for the controller to come around.
+        */
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
        mdelay(5);      /* FIXME revisit this */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+
        cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
        cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
        /*
@@ -772,9 +780,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam)
         * Control 1 is power down, set to 0 to operate.
         */
        cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
-       mdelay(1); /* Marvell says 1ms will do it */
+//     mdelay(1); /* Marvell says 1ms will do it */
        cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-       mdelay(1); /* Enough? */
+//     mdelay(1); /* Enough? */
        spin_unlock_irqrestore(&cam->dev_lock, flags);
 }
 
@@ -818,6 +826,7 @@ static int __cafe_cam_reset(struct cafe_camera *cam)
  */
 static int cafe_cam_init(struct cafe_camera *cam)
 {
+       struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 };
        int ret;
 
        mutex_lock(&cam->s_mutex);
@@ -827,9 +836,11 @@ static int cafe_cam_init(struct cafe_camera *cam)
        ret = __cafe_cam_reset(cam);
        if (ret)
                goto out;
-       ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
+       chip.match_chip = cam->sensor->addr;
+       ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip);
        if (ret)
                goto out;
+       cam->sensor_type = chip.ident;
 //     if (cam->sensor->addr != OV7xx0_SID) {
        if (cam->sensor_type != V4L2_IDENT_OV7670) {
                cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
@@ -1022,7 +1033,7 @@ static ssize_t cafe_v4l_read(struct file *filp,
                char __user *buffer, size_t len, loff_t *pos)
 {
        struct cafe_camera *cam = filp->private_data;
-       int ret;
+       int ret = 0;
 
        /*
         * Perhaps we're in speculative read mode and already
@@ -1251,8 +1262,6 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
 
        if (cam->n_sbufs == 0)  /* no luck at all - ret already set */
                kfree(cam->sb_bufs);
-       else
-               ret = 0;
        req->count = cam->n_sbufs;  /* In case of partial success */
 
   out:
@@ -1794,18 +1803,19 @@ static void cafe_frame_tasklet(unsigned long data)
                if (list_empty(&cam->sb_avail))
                        break;  /* Leave it valid, hope for better later */
                clear_bit(bufno, &cam->flags);
-               /*
-                * We could perhaps drop the spinlock during this
-                * big copy.  Something to consider.
-                */
                sbuf = list_entry(cam->sb_avail.next,
                                struct cafe_sio_buffer, list);
+               /*
+                * Drop the lock during the big copy.  This *should* be safe...
+                */
+               spin_unlock_irqrestore(&cam->dev_lock, flags);
                memcpy(sbuf->buffer, cam->dma_bufs[bufno],
                                cam->pix_format.sizeimage);
                sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
                sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
                sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
                sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+               spin_lock_irqsave(&cam->dev_lock, flags);
                list_move_tail(&sbuf->list, &cam->sb_full);
        }
        if (! list_empty(&cam->sb_full))
@@ -2109,6 +2119,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        cam->v4ldev = cafe_v4l_template;
        cam->v4ldev.debug = 0;
 //     cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
+       cam->v4ldev.dev = &pdev->dev;
        ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
        if (ret)
                goto out_smbus;
@@ -2178,10 +2189,52 @@ static void cafe_pci_remove(struct pci_dev *pdev)
 }
 
 
+#ifdef CONFIG_PM
+/*
+ * Basic power management.
+ */
+static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+       int ret;
+
+       ret = pci_save_state(pdev);
+       if (ret)
+               return ret;
+       cafe_ctlr_stop_dma(cam);
+       cafe_ctlr_power_down(cam);
+       pci_disable_device(pdev);
+       return 0;
+}
+
+
+static int cafe_pci_resume(struct pci_dev *pdev)
+{
+       struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+       int ret = 0;
+
+       ret = pci_restore_state(pdev);
+       if (ret)
+               return ret;
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               cam_warn(cam, "Unable to re-enable device on resume!\n");
+               return ret;
+       }
+       cafe_ctlr_init(cam);
+       cafe_ctlr_power_up(cam);
+       set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       if (cam->state == S_SPECREAD)
+               cam->state = S_IDLE;  /* Don't bother restarting */
+       else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING)
+               ret = cafe_read_setup(cam, cam->state);
+       return ret;
+}
+
+#endif  /* CONFIG_PM */
 
 
 static struct pci_device_id cafe_ids[] = {
-       { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
        { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
        { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
        { 0, }
@@ -2194,6 +2247,10 @@ static struct pci_driver cafe_pci_driver = {
        .id_table = cafe_ids,
        .probe = cafe_pci_probe,
        .remove = cafe_pci_remove,
+#ifdef CONFIG_PM
+       .suspend = cafe_pci_suspend,
+       .resume = cafe_pci_resume,
+#endif
 };