int flexio_capture_hw_disable(struct imx_flexio_capture_dev *fcam)
{
disable_irq(fcam->hw.irq);
flexio_capture_enable_rx_dma(fcam, 0);
dmaengine_terminate_sync(fcam->hw.dma);
fcam->hw.ctrl.flexen = false;
flexio_setup_ctrl(fcam->hw.base, &fcam->hw.ctrl, CTRL);
flexio_writel(fcam->hw.base, 1UL << FLEXIO_TIMER_IDX, TIMSTAT);
flexio_capture_clear_status_flag(fcam);
return 0;
}
static irqreturn_t flexio_capture_vsync_irq(int irq, void *dev)
{
struct imx_flexio_capture_dev *fcam = dev;
struct flexio_capture_buffer *buf, *prev;
unsigned long flags;
/* Why is it needed?
* Because sensor might start not in sync with flexio (ov7670 case)
* and in this case we have to align them manually.
* Hopefully, in normal case all data already captured, so
* it seems safe anyway.
*/
dmaengine_terminate_all(fcam->hw.dma);
flexio_capture_clear_status_flag(fcam);
spin_lock_irqsave(&fcam->pipe.buf_lock, flags);
prev = fcam->pipe.active;
buf = list_first_entry_or_null(&fcam->pipe.pending,
struct flexio_capture_buffer, list);
fcam->pipe.active = buf;
if (buf)
list_del_init(&buf->list);
spin_unlock_irqrestore(&fcam->pipe.buf_lock, flags);
if (prev)
vb2_buffer_done(&prev->v4l2_buf.vb2_buf, VB2_BUF_STATE_DONE);
flexio_capture_dma_submit(fcam);
return IRQ_HANDLED;
}
int flexio_capture_hw_probe(struct imx_flexio_capture_dev *fcam)
{
struct flexio_ddata *ddata = dev_get_drvdata(fcam->dev->parent);
struct device_node *of_node = fcam->dev->of_node;
long irqflags = IRQF_ONESHOT;
int err, irq;
if (IS_ERR_OR_NULL(ddata))
return -EINVAL;
fcam->hw.base = ddata->base;
fcam->hw.src_addr = ddata->phy_addr;
if (IS_ERR(fcam->hw.base))
return PTR_ERR(fcam->hw.base);
fcam->hw.clk = ddata->ipg_clk;
if (IS_ERR(fcam->hw.clk)) {
dev_err(fcam->dev, "missing imx flexio camera clock\n");
return PTR_ERR(fcam->hw.clk);
}
err = of_property_read_u32(of_node, "pclk", &fcam->hw.pclk_pin);
if (err < 0) {
dev_err(fcam->dev, "no pclk property found\n");
return err;
}
err = of_property_read_u32(of_node, "href", &fcam->hw.href_pin);
if (err < 0) {
dev_err(fcam->dev, "no href property found\n");
return err;
}
irq = platform_get_irq(to_platform_device(fcam->dev), 0);
if (irq < 0)
return irq;
fcam->hw.irq = irq;
if (fcam->pipe.buscfg.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
irqflags |= IRQF_TRIGGER_RISING;
else
irqflags |= IRQF_TRIGGER_FALLING;
err = devm_request_irq(fcam->dev, irq, flexio_capture_vsync_irq,
irqflags, dev_name(fcam->dev), fcam);
if (err < 0) {
dev_err(fcam->dev, "failed to request IRQ (%d)\n", err);
return err;
}
disable_irq(irq);
fcam->hw.dma = dma_request_chan(fcam->dev->parent, "flexio_dma");
if (IS_ERR(fcam->hw.dma)) {
err = PTR_ERR(fcam->hw.dma);
dev_err(fcam->dev, "can't get the RX FlexIO DMA channel, error %d\n", err);
fcam->hw.dma = NULL;
return err;
}
clk_set_rate(fcam->hw.clk, FLEXIO_CLK_RATE);
clk_prepare_enable(fcam->hw.clk);
return 0;
};
void flexio_capture_hw_remove(struct imx_flexio_capture_dev *fcam)
{
dma_release_channel(fcam->hw.dma);
clk_disable_unprepare(fcam->hw.clk);
}