static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); unsigned long flags; int ret; /* * Find sensor subdev linked to FIMC-LITE directly or through * MIPI-CSIS. This is required for configuration where FIMC-LITE * is used as a subdev only and feeds data internally to FIMC-IS. * The pipeline links are protected through entity.stream_count * so there is no need to take the media graph mutex here. */ fimc->sensor = fimc_find_remote_sensor(&sd->entity); if (atomic_read(&fimc->out_path) != FIMC_IO_ISP) return -ENOIOCTLCMD; mutex_lock(&fimc->lock); if (on) { flite_hw_reset(fimc); ret = fimc_lite_hw_init(fimc, true); if (!ret) { spin_lock_irqsave(&fimc->slock, flags); flite_hw_capture_start(fimc); spin_unlock_irqrestore(&fimc->slock, flags); } } else { set_bit(ST_FLITE_OFF, &fimc->state); spin_lock_irqsave(&fimc->slock, flags); flite_hw_capture_stop(fimc); spin_unlock_irqrestore(&fimc->slock, flags); ret = wait_event_timeout(fimc->irq_queue, !test_bit(ST_FLITE_OFF, &fimc->state), msecs_to_jiffies(200)); if (ret == 0) v4l2_err(sd, "s_stream(0) timeout\n"); clear_bit(ST_FLITE_RUN, &fimc->state); } mutex_unlock(&fimc->lock); return ret; }
static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend) { unsigned long flags; if (!fimc_lite_active(fimc)) return 0; spin_lock_irqsave(&fimc->slock, flags); set_bit(ST_FLITE_OFF, &fimc->state); flite_hw_capture_stop(fimc); spin_unlock_irqrestore(&fimc->slock, flags); wait_event_timeout(fimc->irq_queue, !test_bit(ST_FLITE_OFF, &fimc->state), (2*HZ/10)); /* 200 ms */ return fimc_lite_reinit(fimc, suspend); }
static irqreturn_t flite_irq_handler(int irq, void *priv) { struct fimc_lite *fimc = priv; struct flite_buffer *vbuf; unsigned long flags; struct timeval *tv; struct timespec ts; u32 intsrc; spin_lock_irqsave(&fimc->slock, flags); intsrc = flite_hw_get_interrupt_source(fimc); flite_hw_clear_pending_irq(fimc); if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) { wake_up(&fimc->irq_queue); goto done; } if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) { clear_bit(ST_FLITE_RUN, &fimc->state); fimc->events.data_overflow++; } if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) { flite_hw_clear_last_capture_end(fimc); clear_bit(ST_FLITE_STREAM, &fimc->state); wake_up(&fimc->irq_queue); } if (fimc->out_path != FIMC_IO_DMA) goto done; if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && test_bit(ST_FLITE_RUN, &fimc->state) && !list_empty(&fimc->active_buf_q) && !list_empty(&fimc->pending_buf_q)) { vbuf = fimc_lite_active_queue_pop(fimc); ktime_get_ts(&ts); tv = &vbuf->vb.v4l2_buf.timestamp; tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; vbuf->vb.v4l2_buf.sequence = fimc->frame_count++; vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); vbuf = fimc_lite_pending_queue_pop(fimc); flite_hw_set_output_addr(fimc, vbuf->paddr); fimc_lite_active_queue_add(fimc, vbuf); } if (test_bit(ST_FLITE_CONFIG, &fimc->state)) fimc_lite_config_update(fimc); if (list_empty(&fimc->pending_buf_q)) { flite_hw_capture_stop(fimc); clear_bit(ST_FLITE_STREAM, &fimc->state); } done: set_bit(ST_FLITE_RUN, &fimc->state); spin_unlock_irqrestore(&fimc->slock, flags); return IRQ_HANDLED; }