X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fcafe_ccic.c;h=7ae499c9c54c8785e497e9ddabdcde740c017f01;hb=4adeaaf51ebcc3f629f5512b96aebb5089388bca;hp=c08f650df42337df25a517eb7538e7a29c9a8a8d;hpb=8269cc4e2b0ddcdcb9e7f2034c464ef8613737a1;p=linux-2.6 diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index c08f650df4..7ae499c9c5 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -3,6 +3,9 @@ * multifunction chip. Currently works with the Omnivision OV7670 * sensor. * + * The data sheet for this device can be found at: + * http://www.marvell.com/products/pcconn/88ALP01.jsp + * * Copyright 2006 One Laptop Per Child Association, Inc. * Copyright 2006-7 Jonathan Corbet * @@ -14,7 +17,6 @@ #include #include -#include #include #include #include @@ -63,13 +65,13 @@ MODULE_SUPPORTED_DEVICE("Video"); */ #define MAX_DMA_BUFS 3 -static int alloc_bufs_at_load = 0; -module_param(alloc_bufs_at_load, bool, 0444); -MODULE_PARM_DESC(alloc_bufs_at_load, - "Non-zero value causes DMA buffers to be allocated at module " - "load time. This increases the chances of successfully getting " - "those buffers, but at the cost of nailing down the memory from " - "the outset."); +static int alloc_bufs_at_read = 0; +module_param(alloc_bufs_at_read, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_read, + "Non-zero value causes DMA buffers to be allocated when the " + "video capture device is read, rather than at module load " + "time. This saves memory, but decreases the chances of " + "successfully getting those buffers."); static int n_dma_bufs = 3; module_param(n_dma_bufs, uint, 0644); @@ -356,6 +358,7 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, { unsigned int rval; unsigned long flags; + DEFINE_WAIT(the_wait); spin_lock_irqsave(&cam->dev_lock, flags); rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); @@ -369,10 +372,29 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); cafe_reg_write(cam, REG_TWSIC1, rval); spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(2); /* Required or things flake */ + /* + * Time to wait for the write to complete. THIS IS A RACY + * WAY TO DO IT, but the sad fact is that reading the TWSIC1 + * register too quickly after starting the operation sends + * the device into a place that may be kinder and better, but + * which is absolutely useless for controlling the sensor. In + * practice we have plenty of time to get into our sleep state + * before the interrupt hits, and the worst case is that we + * time out and then see that things completed, so this seems + * the best way for now. + */ + do { + prepare_to_wait(&cam->smbus_wait, &the_wait, + TASK_UNINTERRUPTIBLE); + schedule_timeout(1); /* even 1 jiffy is too long */ + finish_wait(&cam->smbus_wait, &the_wait); + } while (!cafe_smbus_write_done(cam)); + +#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), CAFE_SMBUS_TIMEOUT); +#endif spin_lock_irqsave(&cam->dev_lock, flags); rval = cafe_reg_read(cam, REG_TWSIC1); spin_unlock_irqrestore(&cam->dev_lock, flags); @@ -710,7 +732,7 @@ static void cafe_ctlr_init(struct cafe_camera *cam) * Here we must wait a bit for the controller to come around. */ spin_unlock_irqrestore(&cam->dev_lock, flags); - mdelay(5); /* FIXME revisit this */ + msleep(5); spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); @@ -1178,7 +1200,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index) buf->v4lbuf.field = V4L2_FIELD_NONE; buf->v4lbuf.memory = V4L2_MEMORY_MMAP; /* - * Offset: must be 32-bit even on a 64-bit system. video-buf + * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg * just uses the length times the index, but the spec warns * against doing just that - vma merging problems. So we * leave a gap between each pair of buffers. @@ -1483,7 +1505,7 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp) } if (cam->users == 0) { cafe_ctlr_power_down(cam); - if (! alloc_bufs_at_load) + if (alloc_bufs_at_read) cafe_free_dma_bufs(cam); } mutex_unlock(&cam->s_mutex); @@ -2142,7 +2164,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, /* * If so requested, try to get our DMA buffers now. */ - if (alloc_bufs_at_load) { + if (!alloc_bufs_at_read) { if (cafe_alloc_dma_bufs(cam, 1)) cam_warn(cam, "Unable to alloc DMA buffers at load" " will try again later."); @@ -2213,13 +2235,16 @@ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct cafe_camera *cam = cafe_find_by_pdev(pdev); int ret; + enum cafe_state cstate; ret = pci_save_state(pdev); if (ret) return ret; + cstate = cam->state; /* HACK - stop_dma sets to idle */ cafe_ctlr_stop_dma(cam); cafe_ctlr_power_down(cam); pci_disable_device(pdev); + cam->state = cstate; return 0; } @@ -2233,12 +2258,21 @@ static int cafe_pci_resume(struct pci_dev *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); + cafe_ctlr_power_down(cam); + + mutex_lock(&cam->s_mutex); + if (cam->users > 0) { + cafe_ctlr_power_up(cam); + __cafe_cam_reset(cam); + } + mutex_unlock(&cam->s_mutex); + set_bit(CF_CONFIG_NEEDED, &cam->flags); if (cam->state == S_SPECREAD) cam->state = S_IDLE; /* Don't bother restarting */