aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKuninori Morimoto <morimoto.kuninori@renesas.com>2009-10-05 11:48:59 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:40:28 -0500
commit5cf93f1dcaff4960bdfea22196963556778b22b3 (patch)
treef11f97df0b960b9dfab245aba82917895fc7e99a /drivers
parentb1de7aeba1d7592b97507c21ea986ec6243a4165 (diff)
V4L/DVB (13128): sh_mobile_ceu_camera: add VBP error support
If CEU driver can not receive data from camera, CETCR has VBP error state. Then, CEU is stopped and cure operation is needed. This patch add VBP error cure operation. Signed-off-by: Kuninori Morimoto <morimoto.kuninori@renesas.com> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c41
1 files changed, 33 insertions, 8 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index edb6ec3d2bcd..a4f3472d4db8 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -236,26 +236,45 @@ static void free_buffer(struct videobuf_queue *vq,
236#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */ 236#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
237#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */ 237#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
238#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */ 238#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
239#define CEU_CEIER_VBP (1 << 20) /* vbp error */
239#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */ 240#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */
241#define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP)
240 242
241 243
242static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) 244/*
245 * return value doesn't reflex the success/failure to queue the new buffer,
246 * but rather the status of the previous buffer.
247 */
248static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
243{ 249{
244 struct soc_camera_device *icd = pcdev->icd; 250 struct soc_camera_device *icd = pcdev->icd;
245 dma_addr_t phys_addr_top, phys_addr_bottom; 251 dma_addr_t phys_addr_top, phys_addr_bottom;
252 u32 status;
253 int ret = 0;
246 254
247 /* The hardware is _very_ picky about this sequence. Especially 255 /* The hardware is _very_ picky about this sequence. Especially
248 * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge 256 * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
249 * several not-so-well documented interrupt sources in CETCR. 257 * several not-so-well documented interrupt sources in CETCR.
250 */ 258 */
251 ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_CPEIE); 259 ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
252 ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & CEU_CETCR_MAGIC); 260 status = ceu_read(pcdev, CETCR);
253 ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_CPEIE); 261 ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
262 ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
254 ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); 263 ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
255 ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); 264 ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
256 265
266 /*
267 * When a VBP interrupt occurs, a capture end interrupt does not occur
268 * and the image of that frame is not captured correctly. So, soft reset
269 * is needed here.
270 */
271 if (status & CEU_CEIER_VBP) {
272 sh_mobile_ceu_soft_reset(pcdev);
273 ret = -EIO;
274 }
275
257 if (!pcdev->active) 276 if (!pcdev->active)
258 return; 277 return ret;
259 278
260 phys_addr_top = videobuf_to_dma_contig(pcdev->active); 279 phys_addr_top = videobuf_to_dma_contig(pcdev->active);
261 ceu_write(pcdev, CDAYR, phys_addr_top); 280 ceu_write(pcdev, CDAYR, phys_addr_top);
@@ -281,6 +300,8 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
281 300
282 pcdev->active->state = VIDEOBUF_ACTIVE; 301 pcdev->active->state = VIDEOBUF_ACTIVE;
283 ceu_write(pcdev, CAPSR, 0x1); /* start capture */ 302 ceu_write(pcdev, CAPSR, 0x1); /* start capture */
303
304 return ret;
284} 305}
285 306
286static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, 307static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
@@ -353,6 +374,11 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
353 list_add_tail(&vb->queue, &pcdev->capture); 374 list_add_tail(&vb->queue, &pcdev->capture);
354 375
355 if (!pcdev->active) { 376 if (!pcdev->active) {
377 /*
378 * Because there were no active buffer at this moment,
379 * we are not interested in the return value of
380 * sh_mobile_ceu_capture here.
381 */
356 pcdev->active = vb; 382 pcdev->active = vb;
357 sh_mobile_ceu_capture(pcdev); 383 sh_mobile_ceu_capture(pcdev);
358 } 384 }
@@ -413,9 +439,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
413 else 439 else
414 pcdev->active = NULL; 440 pcdev->active = NULL;
415 441
416 sh_mobile_ceu_capture(pcdev); 442 vb->state = (sh_mobile_ceu_capture(pcdev) < 0) ?
417 443 VIDEOBUF_ERROR : VIDEOBUF_DONE;
418 vb->state = VIDEOBUF_DONE;
419 do_gettimeofday(&vb->ts); 444 do_gettimeofday(&vb->ts);
420 vb->field_count++; 445 vb->field_count++;
421 wake_up(&vb->done); 446 wake_up(&vb->done);