162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for STM32 Digital Camera Memory Interface
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2017
662306a36Sopenharmony_ci * Authors: Yannick Fertre <yannick.fertre@st.com>
762306a36Sopenharmony_ci *          Hugues Fruchet <hugues.fruchet@st.com>
862306a36Sopenharmony_ci *          for STMicroelectronics.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This driver is based on atmel_isi.c
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/completion.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/dmaengine.h>
1862306a36Sopenharmony_ci#include <linux/init.h>
1962306a36Sopenharmony_ci#include <linux/interrupt.h>
2062306a36Sopenharmony_ci#include <linux/kernel.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/of.h>
2362306a36Sopenharmony_ci#include <linux/of_device.h>
2462306a36Sopenharmony_ci#include <linux/of_graph.h>
2562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2662306a36Sopenharmony_ci#include <linux/platform_device.h>
2762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2862306a36Sopenharmony_ci#include <linux/reset.h>
2962306a36Sopenharmony_ci#include <linux/videodev2.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
3262306a36Sopenharmony_ci#include <media/v4l2-dev.h>
3362306a36Sopenharmony_ci#include <media/v4l2-device.h>
3462306a36Sopenharmony_ci#include <media/v4l2-event.h>
3562306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
3662306a36Sopenharmony_ci#include <media/v4l2-image-sizes.h>
3762306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
3862306a36Sopenharmony_ci#include <media/v4l2-rect.h>
3962306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define DRV_NAME "stm32-dcmi"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Registers offset for DCMI */
4462306a36Sopenharmony_ci#define DCMI_CR		0x00 /* Control Register */
4562306a36Sopenharmony_ci#define DCMI_SR		0x04 /* Status Register */
4662306a36Sopenharmony_ci#define DCMI_RIS	0x08 /* Raw Interrupt Status register */
4762306a36Sopenharmony_ci#define DCMI_IER	0x0C /* Interrupt Enable Register */
4862306a36Sopenharmony_ci#define DCMI_MIS	0x10 /* Masked Interrupt Status register */
4962306a36Sopenharmony_ci#define DCMI_ICR	0x14 /* Interrupt Clear Register */
5062306a36Sopenharmony_ci#define DCMI_ESCR	0x18 /* Embedded Synchronization Code Register */
5162306a36Sopenharmony_ci#define DCMI_ESUR	0x1C /* Embedded Synchronization Unmask Register */
5262306a36Sopenharmony_ci#define DCMI_CWSTRT	0x20 /* Crop Window STaRT */
5362306a36Sopenharmony_ci#define DCMI_CWSIZE	0x24 /* Crop Window SIZE */
5462306a36Sopenharmony_ci#define DCMI_DR		0x28 /* Data Register */
5562306a36Sopenharmony_ci#define DCMI_IDR	0x2C /* IDentifier Register */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Bits definition for control register (DCMI_CR) */
5862306a36Sopenharmony_ci#define CR_CAPTURE	BIT(0)
5962306a36Sopenharmony_ci#define CR_CM		BIT(1)
6062306a36Sopenharmony_ci#define CR_CROP		BIT(2)
6162306a36Sopenharmony_ci#define CR_JPEG		BIT(3)
6262306a36Sopenharmony_ci#define CR_ESS		BIT(4)
6362306a36Sopenharmony_ci#define CR_PCKPOL	BIT(5)
6462306a36Sopenharmony_ci#define CR_HSPOL	BIT(6)
6562306a36Sopenharmony_ci#define CR_VSPOL	BIT(7)
6662306a36Sopenharmony_ci#define CR_FCRC_0	BIT(8)
6762306a36Sopenharmony_ci#define CR_FCRC_1	BIT(9)
6862306a36Sopenharmony_ci#define CR_EDM_0	BIT(10)
6962306a36Sopenharmony_ci#define CR_EDM_1	BIT(11)
7062306a36Sopenharmony_ci#define CR_ENABLE	BIT(14)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Bits definition for status register (DCMI_SR) */
7362306a36Sopenharmony_ci#define SR_HSYNC	BIT(0)
7462306a36Sopenharmony_ci#define SR_VSYNC	BIT(1)
7562306a36Sopenharmony_ci#define SR_FNE		BIT(2)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * Bits definition for interrupt registers
7962306a36Sopenharmony_ci * (DCMI_RIS, DCMI_IER, DCMI_MIS, DCMI_ICR)
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci#define IT_FRAME	BIT(0)
8262306a36Sopenharmony_ci#define IT_OVR		BIT(1)
8362306a36Sopenharmony_ci#define IT_ERR		BIT(2)
8462306a36Sopenharmony_ci#define IT_VSYNC	BIT(3)
8562306a36Sopenharmony_ci#define IT_LINE		BIT(4)
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cienum state {
8862306a36Sopenharmony_ci	STOPPED = 0,
8962306a36Sopenharmony_ci	WAIT_FOR_BUFFER,
9062306a36Sopenharmony_ci	RUNNING,
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define MIN_WIDTH	16U
9462306a36Sopenharmony_ci#define MAX_WIDTH	2592U
9562306a36Sopenharmony_ci#define MIN_HEIGHT	16U
9662306a36Sopenharmony_ci#define MAX_HEIGHT	2592U
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define TIMEOUT_MS	1000
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define OVERRUN_ERROR_THRESHOLD	3
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct dcmi_format {
10362306a36Sopenharmony_ci	u32	fourcc;
10462306a36Sopenharmony_ci	u32	mbus_code;
10562306a36Sopenharmony_ci	u8	bpp;
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistruct dcmi_framesize {
10962306a36Sopenharmony_ci	u32	width;
11062306a36Sopenharmony_ci	u32	height;
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistruct dcmi_buf {
11462306a36Sopenharmony_ci	struct vb2_v4l2_buffer	vb;
11562306a36Sopenharmony_ci	bool			prepared;
11662306a36Sopenharmony_ci	struct sg_table		sgt;
11762306a36Sopenharmony_ci	size_t			size;
11862306a36Sopenharmony_ci	struct list_head	list;
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistruct stm32_dcmi {
12262306a36Sopenharmony_ci	/* Protects the access of variables shared within the interrupt */
12362306a36Sopenharmony_ci	spinlock_t			irqlock;
12462306a36Sopenharmony_ci	struct device			*dev;
12562306a36Sopenharmony_ci	void __iomem			*regs;
12662306a36Sopenharmony_ci	struct resource			*res;
12762306a36Sopenharmony_ci	struct reset_control		*rstc;
12862306a36Sopenharmony_ci	int				sequence;
12962306a36Sopenharmony_ci	struct list_head		buffers;
13062306a36Sopenharmony_ci	struct dcmi_buf			*active;
13162306a36Sopenharmony_ci	int			irq;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	struct v4l2_device		v4l2_dev;
13462306a36Sopenharmony_ci	struct video_device		*vdev;
13562306a36Sopenharmony_ci	struct v4l2_async_notifier	notifier;
13662306a36Sopenharmony_ci	struct v4l2_subdev		*source;
13762306a36Sopenharmony_ci	struct v4l2_subdev		*s_subdev;
13862306a36Sopenharmony_ci	struct v4l2_format		fmt;
13962306a36Sopenharmony_ci	struct v4l2_rect		crop;
14062306a36Sopenharmony_ci	bool				do_crop;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	const struct dcmi_format	**sd_formats;
14362306a36Sopenharmony_ci	unsigned int			num_of_sd_formats;
14462306a36Sopenharmony_ci	const struct dcmi_format	*sd_format;
14562306a36Sopenharmony_ci	struct dcmi_framesize		*sd_framesizes;
14662306a36Sopenharmony_ci	unsigned int			num_of_sd_framesizes;
14762306a36Sopenharmony_ci	struct dcmi_framesize		sd_framesize;
14862306a36Sopenharmony_ci	struct v4l2_rect		sd_bounds;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Protect this data structure */
15162306a36Sopenharmony_ci	struct mutex			lock;
15262306a36Sopenharmony_ci	struct vb2_queue		queue;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	struct v4l2_mbus_config_parallel	bus;
15562306a36Sopenharmony_ci	enum v4l2_mbus_type		bus_type;
15662306a36Sopenharmony_ci	struct completion		complete;
15762306a36Sopenharmony_ci	struct clk			*mclk;
15862306a36Sopenharmony_ci	enum state			state;
15962306a36Sopenharmony_ci	struct dma_chan			*dma_chan;
16062306a36Sopenharmony_ci	dma_cookie_t			dma_cookie;
16162306a36Sopenharmony_ci	u32				dma_max_burst;
16262306a36Sopenharmony_ci	u32				misr;
16362306a36Sopenharmony_ci	int				errors_count;
16462306a36Sopenharmony_ci	int				overrun_count;
16562306a36Sopenharmony_ci	int				buffers_count;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Ensure DMA operations atomicity */
16862306a36Sopenharmony_ci	struct mutex			dma_lock;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	struct media_device		mdev;
17162306a36Sopenharmony_ci	struct media_pad		vid_cap_pad;
17262306a36Sopenharmony_ci	struct media_pipeline		pipeline;
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	return container_of(n, struct stm32_dcmi, notifier);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic inline u32 reg_read(void __iomem *base, u32 reg)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return readl_relaxed(base + reg);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic inline void reg_write(void __iomem *base, u32 reg, u32 val)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	writel_relaxed(val, base + reg);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline void reg_set(void __iomem *base, u32 reg, u32 mask)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	reg_write(base, reg, reg_read(base, reg) | mask);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic inline void reg_clear(void __iomem *base, u32 reg, u32 mask)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	reg_write(base, reg, reg_read(base, reg) & ~mask);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic int dcmi_start_capture(struct stm32_dcmi *dcmi, struct dcmi_buf *buf);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void dcmi_buffer_done(struct stm32_dcmi *dcmi,
20362306a36Sopenharmony_ci			     struct dcmi_buf *buf,
20462306a36Sopenharmony_ci			     size_t bytesused,
20562306a36Sopenharmony_ci			     int err)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (!buf)
21062306a36Sopenharmony_ci		return;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	list_del_init(&buf->list);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	vbuf = &buf->vb;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	vbuf->sequence = dcmi->sequence++;
21762306a36Sopenharmony_ci	vbuf->field = V4L2_FIELD_NONE;
21862306a36Sopenharmony_ci	vbuf->vb2_buf.timestamp = ktime_get_ns();
21962306a36Sopenharmony_ci	vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused);
22062306a36Sopenharmony_ci	vb2_buffer_done(&vbuf->vb2_buf,
22162306a36Sopenharmony_ci			err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
22262306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "buffer[%d] done seq=%d, bytesused=%zu\n",
22362306a36Sopenharmony_ci		vbuf->vb2_buf.index, vbuf->sequence, bytesused);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	dcmi->buffers_count++;
22662306a36Sopenharmony_ci	dcmi->active = NULL;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic int dcmi_restart_capture(struct stm32_dcmi *dcmi)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct dcmi_buf *buf;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (dcmi->state != RUNNING) {
23662306a36Sopenharmony_ci		spin_unlock_irq(&dcmi->irqlock);
23762306a36Sopenharmony_ci		return -EINVAL;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* Restart a new DMA transfer with next buffer */
24162306a36Sopenharmony_ci	if (list_empty(&dcmi->buffers)) {
24262306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "Capture restart is deferred to next buffer queueing\n");
24362306a36Sopenharmony_ci		dcmi->state = WAIT_FOR_BUFFER;
24462306a36Sopenharmony_ci		spin_unlock_irq(&dcmi->irqlock);
24562306a36Sopenharmony_ci		return 0;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci	buf = list_entry(dcmi->buffers.next, struct dcmi_buf, list);
24862306a36Sopenharmony_ci	dcmi->active = buf;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return dcmi_start_capture(dcmi, buf);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic void dcmi_dma_callback(void *param)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param;
25862306a36Sopenharmony_ci	struct dma_tx_state state;
25962306a36Sopenharmony_ci	enum dma_status status;
26062306a36Sopenharmony_ci	struct dcmi_buf *buf = dcmi->active;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/* Check DMA status */
26562306a36Sopenharmony_ci	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	switch (status) {
26862306a36Sopenharmony_ci	case DMA_IN_PROGRESS:
26962306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "%s: Received DMA_IN_PROGRESS\n", __func__);
27062306a36Sopenharmony_ci		break;
27162306a36Sopenharmony_ci	case DMA_PAUSED:
27262306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Received DMA_PAUSED\n", __func__);
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	case DMA_ERROR:
27562306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Received DMA_ERROR\n", __func__);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci		/* Return buffer to V4L2 in error state */
27862306a36Sopenharmony_ci		dcmi_buffer_done(dcmi, buf, 0, -EIO);
27962306a36Sopenharmony_ci		break;
28062306a36Sopenharmony_ci	case DMA_COMPLETE:
28162306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		/* Return buffer to V4L2 */
28462306a36Sopenharmony_ci		dcmi_buffer_done(dcmi, buf, buf->size, 0);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		spin_unlock_irq(&dcmi->irqlock);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		/* Restart capture */
28962306a36Sopenharmony_ci		if (dcmi_restart_capture(dcmi))
29062306a36Sopenharmony_ci			dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n",
29162306a36Sopenharmony_ci				__func__);
29262306a36Sopenharmony_ci		return;
29362306a36Sopenharmony_ci	default:
29462306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Received unknown status\n", __func__);
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int dcmi_start_dma(struct stm32_dcmi *dcmi,
30262306a36Sopenharmony_ci			  struct dcmi_buf *buf)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct dma_async_tx_descriptor *desc = NULL;
30562306a36Sopenharmony_ci	struct dma_slave_config config;
30662306a36Sopenharmony_ci	int ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	memset(&config, 0, sizeof(config));
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
31162306a36Sopenharmony_ci	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
31262306a36Sopenharmony_ci	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
31362306a36Sopenharmony_ci	config.dst_maxburst = 4;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Configure DMA channel */
31662306a36Sopenharmony_ci	ret = dmaengine_slave_config(dcmi->dma_chan, &config);
31762306a36Sopenharmony_ci	if (ret < 0) {
31862306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: DMA channel config failed (%d)\n",
31962306a36Sopenharmony_ci			__func__, ret);
32062306a36Sopenharmony_ci		return ret;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/*
32462306a36Sopenharmony_ci	 * Avoid call of dmaengine_terminate_sync() between
32562306a36Sopenharmony_ci	 * dmaengine_prep_slave_single() and dmaengine_submit()
32662306a36Sopenharmony_ci	 * by locking the whole DMA submission sequence
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	mutex_lock(&dcmi->dma_lock);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Prepare a DMA transaction */
33162306a36Sopenharmony_ci	desc = dmaengine_prep_slave_sg(dcmi->dma_chan, buf->sgt.sgl, buf->sgt.nents,
33262306a36Sopenharmony_ci				       DMA_DEV_TO_MEM,
33362306a36Sopenharmony_ci				       DMA_PREP_INTERRUPT);
33462306a36Sopenharmony_ci	if (!desc) {
33562306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
33662306a36Sopenharmony_ci		mutex_unlock(&dcmi->dma_lock);
33762306a36Sopenharmony_ci		return -EINVAL;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Set completion callback routine for notification */
34162306a36Sopenharmony_ci	desc->callback = dcmi_dma_callback;
34262306a36Sopenharmony_ci	desc->callback_param = dcmi;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* Push current DMA transaction in the pending queue */
34562306a36Sopenharmony_ci	dcmi->dma_cookie = dmaengine_submit(desc);
34662306a36Sopenharmony_ci	if (dma_submit_error(dcmi->dma_cookie)) {
34762306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
34862306a36Sopenharmony_ci		mutex_unlock(&dcmi->dma_lock);
34962306a36Sopenharmony_ci		return -ENXIO;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	mutex_unlock(&dcmi->dma_lock);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	dma_async_issue_pending(dcmi->dma_chan);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int dcmi_start_capture(struct stm32_dcmi *dcmi, struct dcmi_buf *buf)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	int ret;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (!buf)
36462306a36Sopenharmony_ci		return -EINVAL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	ret = dcmi_start_dma(dcmi, buf);
36762306a36Sopenharmony_ci	if (ret) {
36862306a36Sopenharmony_ci		dcmi->errors_count++;
36962306a36Sopenharmony_ci		return ret;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Enable capture */
37362306a36Sopenharmony_ci	reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return 0;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic void dcmi_set_crop(struct stm32_dcmi *dcmi)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	u32 size, start;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* Crop resolution */
38362306a36Sopenharmony_ci	size = ((dcmi->crop.height - 1) << 16) |
38462306a36Sopenharmony_ci		((dcmi->crop.width << 1) - 1);
38562306a36Sopenharmony_ci	reg_write(dcmi->regs, DCMI_CWSIZE, size);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* Crop start point */
38862306a36Sopenharmony_ci	start = ((dcmi->crop.top) << 16) |
38962306a36Sopenharmony_ci		 ((dcmi->crop.left << 1));
39062306a36Sopenharmony_ci	reg_write(dcmi->regs, DCMI_CWSTRT, start);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Cropping to %ux%u@%u:%u\n",
39362306a36Sopenharmony_ci		dcmi->crop.width, dcmi->crop.height,
39462306a36Sopenharmony_ci		dcmi->crop.left, dcmi->crop.top);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Enable crop */
39762306a36Sopenharmony_ci	reg_set(dcmi->regs, DCMI_CR, CR_CROP);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct dma_tx_state state;
40362306a36Sopenharmony_ci	enum dma_status status;
40462306a36Sopenharmony_ci	struct dcmi_buf *buf = dcmi->active;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (!buf)
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Because of variable JPEG buffer size sent by sensor,
41162306a36Sopenharmony_ci	 * DMA transfer never completes due to transfer size never reached.
41262306a36Sopenharmony_ci	 * In order to ensure that all the JPEG data are transferred
41362306a36Sopenharmony_ci	 * in active buffer memory, DMA is drained.
41462306a36Sopenharmony_ci	 * Then DMA tx status gives the amount of data transferred
41562306a36Sopenharmony_ci	 * to memory, which is then returned to V4L2 through the active
41662306a36Sopenharmony_ci	 * buffer payload.
41762306a36Sopenharmony_ci	 */
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* Drain DMA */
42062306a36Sopenharmony_ci	dmaengine_synchronize(dcmi->dma_chan);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Get DMA residue to get JPEG size */
42362306a36Sopenharmony_ci	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
42462306a36Sopenharmony_ci	if (status != DMA_ERROR && state.residue < buf->size) {
42562306a36Sopenharmony_ci		/* Return JPEG buffer to V4L2 with received JPEG buffer size */
42662306a36Sopenharmony_ci		dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0);
42762306a36Sopenharmony_ci	} else {
42862306a36Sopenharmony_ci		dcmi->errors_count++;
42962306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n",
43062306a36Sopenharmony_ci			__func__);
43162306a36Sopenharmony_ci		/* Return JPEG buffer to V4L2 in ERROR state */
43262306a36Sopenharmony_ci		dcmi_buffer_done(dcmi, buf, 0, -EIO);
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* Abort DMA operation */
43662306a36Sopenharmony_ci	dmaengine_terminate_sync(dcmi->dma_chan);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* Restart capture */
43962306a36Sopenharmony_ci	if (dcmi_restart_capture(dcmi))
44062306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n",
44162306a36Sopenharmony_ci			__func__);
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic irqreturn_t dcmi_irq_thread(int irq, void *arg)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = arg;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (dcmi->misr & IT_OVR) {
45162306a36Sopenharmony_ci		dcmi->overrun_count++;
45262306a36Sopenharmony_ci		if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD)
45362306a36Sopenharmony_ci			dcmi->errors_count++;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci	if (dcmi->misr & IT_ERR)
45662306a36Sopenharmony_ci		dcmi->errors_count++;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
45962306a36Sopenharmony_ci	    dcmi->misr & IT_FRAME) {
46062306a36Sopenharmony_ci		/* JPEG received */
46162306a36Sopenharmony_ci		spin_unlock_irq(&dcmi->irqlock);
46262306a36Sopenharmony_ci		dcmi_process_jpeg(dcmi);
46362306a36Sopenharmony_ci		return IRQ_HANDLED;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
46762306a36Sopenharmony_ci	return IRQ_HANDLED;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic irqreturn_t dcmi_irq_callback(int irq, void *arg)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = arg;
47362306a36Sopenharmony_ci	unsigned long flags;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	spin_lock_irqsave(&dcmi->irqlock, flags);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	dcmi->misr = reg_read(dcmi->regs, DCMI_MIS);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Clear interrupt */
48062306a36Sopenharmony_ci	reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	spin_unlock_irqrestore(&dcmi->irqlock, flags);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int dcmi_queue_setup(struct vb2_queue *vq,
48862306a36Sopenharmony_ci			    unsigned int *nbuffers,
48962306a36Sopenharmony_ci			    unsigned int *nplanes,
49062306a36Sopenharmony_ci			    unsigned int sizes[],
49162306a36Sopenharmony_ci			    struct device *alloc_devs[])
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
49462306a36Sopenharmony_ci	unsigned int size;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	size = dcmi->fmt.fmt.pix.sizeimage;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* Make sure the image size is large enough */
49962306a36Sopenharmony_ci	if (*nplanes)
50062306a36Sopenharmony_ci		return sizes[0] < size ? -EINVAL : 0;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	*nplanes = 1;
50362306a36Sopenharmony_ci	sizes[0] = size;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Setup queue, count=%d, size=%d\n",
50662306a36Sopenharmony_ci		*nbuffers, size);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic int dcmi_buf_init(struct vb2_buffer *vb)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
51462306a36Sopenharmony_ci	struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	INIT_LIST_HEAD(&buf->list);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	return 0;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int dcmi_buf_prepare(struct vb2_buffer *vb)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct stm32_dcmi *dcmi =  vb2_get_drv_priv(vb->vb2_queue);
52462306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
52562306a36Sopenharmony_ci	struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
52662306a36Sopenharmony_ci	unsigned long size;
52762306a36Sopenharmony_ci	unsigned int num_sgs = 1;
52862306a36Sopenharmony_ci	dma_addr_t dma_buf;
52962306a36Sopenharmony_ci	struct scatterlist *sg;
53062306a36Sopenharmony_ci	int i, ret;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	size = dcmi->fmt.fmt.pix.sizeimage;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (vb2_plane_size(vb, 0) < size) {
53562306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s data will not fit into plane (%lu < %lu)\n",
53662306a36Sopenharmony_ci			__func__, vb2_plane_size(vb, 0), size);
53762306a36Sopenharmony_ci		return -EINVAL;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	vb2_set_plane_payload(vb, 0, size);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (!buf->prepared) {
54362306a36Sopenharmony_ci		/* Get memory addresses */
54462306a36Sopenharmony_ci		buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0);
54562306a36Sopenharmony_ci		if (buf->size > dcmi->dma_max_burst)
54662306a36Sopenharmony_ci			num_sgs = DIV_ROUND_UP(buf->size, dcmi->dma_max_burst);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		ret = sg_alloc_table(&buf->sgt, num_sgs, GFP_ATOMIC);
54962306a36Sopenharmony_ci		if (ret) {
55062306a36Sopenharmony_ci			dev_err(dcmi->dev, "sg table alloc failed\n");
55162306a36Sopenharmony_ci			return ret;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		dma_buf = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n",
55762306a36Sopenharmony_ci			vb->index, &dma_buf, buf->size);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		for_each_sg(buf->sgt.sgl, sg, num_sgs, i) {
56062306a36Sopenharmony_ci			size_t bytes = min_t(size_t, size, dcmi->dma_max_burst);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci			sg_dma_address(sg) = dma_buf;
56362306a36Sopenharmony_ci			sg_dma_len(sg) = bytes;
56462306a36Sopenharmony_ci			dma_buf += bytes;
56562306a36Sopenharmony_ci			size -= bytes;
56662306a36Sopenharmony_ci		}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		buf->prepared = true;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return 0;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic void dcmi_buf_queue(struct vb2_buffer *vb)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct stm32_dcmi *dcmi =  vb2_get_drv_priv(vb->vb2_queue);
57962306a36Sopenharmony_ci	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
58062306a36Sopenharmony_ci	struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* Enqueue to video buffers list */
58562306a36Sopenharmony_ci	list_add_tail(&buf->list, &dcmi->buffers);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (dcmi->state == WAIT_FOR_BUFFER) {
58862306a36Sopenharmony_ci		dcmi->state = RUNNING;
58962306a36Sopenharmony_ci		dcmi->active = buf;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n",
59262306a36Sopenharmony_ci			buf->vb.vb2_buf.index);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		spin_unlock_irq(&dcmi->irqlock);
59562306a36Sopenharmony_ci		if (dcmi_start_capture(dcmi, buf))
59662306a36Sopenharmony_ci			dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
59762306a36Sopenharmony_ci				__func__);
59862306a36Sopenharmony_ci		return;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct media_entity *entity = &dcmi->vdev->entity;
60762306a36Sopenharmony_ci	struct media_pad *pad;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Walk searching for entity having no sink */
61062306a36Sopenharmony_ci	while (1) {
61162306a36Sopenharmony_ci		pad = &entity->pads[0];
61262306a36Sopenharmony_ci		if (!(pad->flags & MEDIA_PAD_FL_SINK))
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		pad = media_pad_remote_pad_first(pad);
61662306a36Sopenharmony_ci		if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
61762306a36Sopenharmony_ci			break;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		entity = pad->entity;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return entity;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
62662306a36Sopenharmony_ci			       struct v4l2_subdev_format *format)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct media_entity *entity = &dcmi->source->entity;
62962306a36Sopenharmony_ci	struct v4l2_subdev *subdev;
63062306a36Sopenharmony_ci	struct media_pad *sink_pad = NULL;
63162306a36Sopenharmony_ci	struct media_pad *src_pad = NULL;
63262306a36Sopenharmony_ci	struct media_pad *pad = NULL;
63362306a36Sopenharmony_ci	struct v4l2_subdev_format fmt = *format;
63462306a36Sopenharmony_ci	bool found = false;
63562306a36Sopenharmony_ci	int ret;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/*
63862306a36Sopenharmony_ci	 * Starting from sensor subdevice, walk within
63962306a36Sopenharmony_ci	 * pipeline and set format on each subdevice
64062306a36Sopenharmony_ci	 */
64162306a36Sopenharmony_ci	while (1) {
64262306a36Sopenharmony_ci		unsigned int i;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci		/* Search if current entity has a source pad */
64562306a36Sopenharmony_ci		for (i = 0; i < entity->num_pads; i++) {
64662306a36Sopenharmony_ci			pad = &entity->pads[i];
64762306a36Sopenharmony_ci			if (pad->flags & MEDIA_PAD_FL_SOURCE) {
64862306a36Sopenharmony_ci				src_pad = pad;
64962306a36Sopenharmony_ci				found = true;
65062306a36Sopenharmony_ci				break;
65162306a36Sopenharmony_ci			}
65262306a36Sopenharmony_ci		}
65362306a36Sopenharmony_ci		if (!found)
65462306a36Sopenharmony_ci			break;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci		subdev = media_entity_to_v4l2_subdev(entity);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		/* Propagate format on sink pad if any, otherwise source pad */
65962306a36Sopenharmony_ci		if (sink_pad)
66062306a36Sopenharmony_ci			pad = sink_pad;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "\"%s\":%d pad format set to 0x%x %ux%u\n",
66362306a36Sopenharmony_ci			subdev->name, pad->index, format->format.code,
66462306a36Sopenharmony_ci			format->format.width, format->format.height);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		fmt.pad = pad->index;
66762306a36Sopenharmony_ci		ret = v4l2_subdev_call(subdev, pad, set_fmt, NULL, &fmt);
66862306a36Sopenharmony_ci		if (ret < 0) {
66962306a36Sopenharmony_ci			dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n",
67062306a36Sopenharmony_ci				__func__, format->format.code,
67162306a36Sopenharmony_ci				format->format.width, format->format.height,
67262306a36Sopenharmony_ci				subdev->name, pad->index, ret);
67362306a36Sopenharmony_ci			return ret;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		if (fmt.format.code != format->format.code ||
67762306a36Sopenharmony_ci		    fmt.format.width != format->format.width ||
67862306a36Sopenharmony_ci		    fmt.format.height != format->format.height) {
67962306a36Sopenharmony_ci			dev_dbg(dcmi->dev, "\"%s\":%d pad format has been changed to 0x%x %ux%u\n",
68062306a36Sopenharmony_ci				subdev->name, pad->index, fmt.format.code,
68162306a36Sopenharmony_ci				fmt.format.width, fmt.format.height);
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		/* Walk to next entity */
68562306a36Sopenharmony_ci		sink_pad = media_pad_remote_pad_first(src_pad);
68662306a36Sopenharmony_ci		if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity))
68762306a36Sopenharmony_ci			break;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		entity = sink_pad->entity;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci	*format = fmt;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
69962306a36Sopenharmony_ci	struct dcmi_buf *buf, *node;
70062306a36Sopenharmony_ci	u32 val = 0;
70162306a36Sopenharmony_ci	int ret;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dcmi->dev);
70462306a36Sopenharmony_ci	if (ret < 0) {
70562306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
70662306a36Sopenharmony_ci			__func__, ret);
70762306a36Sopenharmony_ci		goto err_unlocked;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	ret = video_device_pipeline_start(dcmi->vdev, &dcmi->pipeline);
71162306a36Sopenharmony_ci	if (ret < 0) {
71262306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n",
71362306a36Sopenharmony_ci			__func__, ret);
71462306a36Sopenharmony_ci		goto err_pm_put;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	ret = v4l2_subdev_call(dcmi->s_subdev, video, s_stream, 1);
71862306a36Sopenharmony_ci	if (ret < 0) {
71962306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Failed to start source subdev, error (%d)\n",
72062306a36Sopenharmony_ci			__func__, ret);
72162306a36Sopenharmony_ci		goto err_media_pipeline_stop;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/* Set bus width */
72762306a36Sopenharmony_ci	switch (dcmi->bus.bus_width) {
72862306a36Sopenharmony_ci	case 14:
72962306a36Sopenharmony_ci		val |= CR_EDM_0 | CR_EDM_1;
73062306a36Sopenharmony_ci		break;
73162306a36Sopenharmony_ci	case 12:
73262306a36Sopenharmony_ci		val |= CR_EDM_1;
73362306a36Sopenharmony_ci		break;
73462306a36Sopenharmony_ci	case 10:
73562306a36Sopenharmony_ci		val |= CR_EDM_0;
73662306a36Sopenharmony_ci		break;
73762306a36Sopenharmony_ci	default:
73862306a36Sopenharmony_ci		/* Set bus width to 8 bits by default */
73962306a36Sopenharmony_ci		break;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Set vertical synchronization polarity */
74362306a36Sopenharmony_ci	if (dcmi->bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
74462306a36Sopenharmony_ci		val |= CR_VSPOL;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* Set horizontal synchronization polarity */
74762306a36Sopenharmony_ci	if (dcmi->bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
74862306a36Sopenharmony_ci		val |= CR_HSPOL;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Set pixel clock polarity */
75162306a36Sopenharmony_ci	if (dcmi->bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
75262306a36Sopenharmony_ci		val |= CR_PCKPOL;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	/*
75562306a36Sopenharmony_ci	 * BT656 embedded synchronisation bus mode.
75662306a36Sopenharmony_ci	 *
75762306a36Sopenharmony_ci	 * Default SAV/EAV mode is supported here with default codes
75862306a36Sopenharmony_ci	 * SAV=0xff000080 & EAV=0xff00009d.
75962306a36Sopenharmony_ci	 * With DCMI this means LSC=SAV=0x80 & LEC=EAV=0x9d.
76062306a36Sopenharmony_ci	 */
76162306a36Sopenharmony_ci	if (dcmi->bus_type == V4L2_MBUS_BT656) {
76262306a36Sopenharmony_ci		val |= CR_ESS;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		/* Unmask all codes */
76562306a36Sopenharmony_ci		reg_write(dcmi->regs, DCMI_ESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		/* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */
76862306a36Sopenharmony_ci		reg_write(dcmi->regs, DCMI_ESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	reg_write(dcmi->regs, DCMI_CR, val);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/* Set crop */
77462306a36Sopenharmony_ci	if (dcmi->do_crop)
77562306a36Sopenharmony_ci		dcmi_set_crop(dcmi);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/* Enable jpeg capture */
77862306a36Sopenharmony_ci	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
77962306a36Sopenharmony_ci		reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* Enable dcmi */
78262306a36Sopenharmony_ci	reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	dcmi->sequence = 0;
78562306a36Sopenharmony_ci	dcmi->errors_count = 0;
78662306a36Sopenharmony_ci	dcmi->overrun_count = 0;
78762306a36Sopenharmony_ci	dcmi->buffers_count = 0;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/*
79062306a36Sopenharmony_ci	 * Start transfer if at least one buffer has been queued,
79162306a36Sopenharmony_ci	 * otherwise transfer is deferred at buffer queueing
79262306a36Sopenharmony_ci	 */
79362306a36Sopenharmony_ci	if (list_empty(&dcmi->buffers)) {
79462306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "Start streaming is deferred to next buffer queueing\n");
79562306a36Sopenharmony_ci		dcmi->state = WAIT_FOR_BUFFER;
79662306a36Sopenharmony_ci		spin_unlock_irq(&dcmi->irqlock);
79762306a36Sopenharmony_ci		return 0;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	buf = list_entry(dcmi->buffers.next, struct dcmi_buf, list);
80162306a36Sopenharmony_ci	dcmi->active = buf;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	dcmi->state = RUNNING;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Start streaming, starting capture\n");
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
80862306a36Sopenharmony_ci	ret = dcmi_start_capture(dcmi, buf);
80962306a36Sopenharmony_ci	if (ret) {
81062306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n",
81162306a36Sopenharmony_ci			__func__);
81262306a36Sopenharmony_ci		goto err_pipeline_stop;
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* Enable interruptions */
81662306a36Sopenharmony_ci	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
81762306a36Sopenharmony_ci		reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
81862306a36Sopenharmony_ci	else
81962306a36Sopenharmony_ci		reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	return 0;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cierr_pipeline_stop:
82462306a36Sopenharmony_ci	v4l2_subdev_call(dcmi->s_subdev, video, s_stream, 0);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cierr_media_pipeline_stop:
82762306a36Sopenharmony_ci	video_device_pipeline_stop(dcmi->vdev);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cierr_pm_put:
83062306a36Sopenharmony_ci	pm_runtime_put(dcmi->dev);
83162306a36Sopenharmony_cierr_unlocked:
83262306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
83362306a36Sopenharmony_ci	/*
83462306a36Sopenharmony_ci	 * Return all buffers to vb2 in QUEUED state.
83562306a36Sopenharmony_ci	 * This will give ownership back to userspace
83662306a36Sopenharmony_ci	 */
83762306a36Sopenharmony_ci	list_for_each_entry_safe(buf, node, &dcmi->buffers, list) {
83862306a36Sopenharmony_ci		list_del_init(&buf->list);
83962306a36Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	dcmi->active = NULL;
84262306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	return ret;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic void dcmi_stop_streaming(struct vb2_queue *vq)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
85062306a36Sopenharmony_ci	struct dcmi_buf *buf, *node;
85162306a36Sopenharmony_ci	int ret;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	ret = v4l2_subdev_call(dcmi->s_subdev, video, s_stream, 0);
85462306a36Sopenharmony_ci	if (ret < 0)
85562306a36Sopenharmony_ci		dev_err(dcmi->dev, "%s: Failed to stop source subdev, error (%d)\n",
85662306a36Sopenharmony_ci			__func__, ret);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	video_device_pipeline_stop(dcmi->vdev);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	spin_lock_irq(&dcmi->irqlock);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	/* Disable interruptions */
86362306a36Sopenharmony_ci	reg_clear(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* Disable DCMI */
86662306a36Sopenharmony_ci	reg_clear(dcmi->regs, DCMI_CR, CR_ENABLE);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* Return all queued buffers to vb2 in ERROR state */
86962306a36Sopenharmony_ci	list_for_each_entry_safe(buf, node, &dcmi->buffers, list) {
87062306a36Sopenharmony_ci		list_del_init(&buf->list);
87162306a36Sopenharmony_ci		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	dcmi->active = NULL;
87562306a36Sopenharmony_ci	dcmi->state = STOPPED;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	spin_unlock_irq(&dcmi->irqlock);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* Stop all pending DMA operations */
88062306a36Sopenharmony_ci	mutex_lock(&dcmi->dma_lock);
88162306a36Sopenharmony_ci	dmaengine_terminate_sync(dcmi->dma_chan);
88262306a36Sopenharmony_ci	mutex_unlock(&dcmi->dma_lock);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	pm_runtime_put(dcmi->dev);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	if (dcmi->errors_count)
88762306a36Sopenharmony_ci		dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n",
88862306a36Sopenharmony_ci			 dcmi->errors_count, dcmi->overrun_count,
88962306a36Sopenharmony_ci			 dcmi->buffers_count);
89062306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Stop streaming, errors=%d (overrun=%d), buffers=%d\n",
89162306a36Sopenharmony_ci		dcmi->errors_count, dcmi->overrun_count,
89262306a36Sopenharmony_ci		dcmi->buffers_count);
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic const struct vb2_ops dcmi_video_qops = {
89662306a36Sopenharmony_ci	.queue_setup		= dcmi_queue_setup,
89762306a36Sopenharmony_ci	.buf_init		= dcmi_buf_init,
89862306a36Sopenharmony_ci	.buf_prepare		= dcmi_buf_prepare,
89962306a36Sopenharmony_ci	.buf_queue		= dcmi_buf_queue,
90062306a36Sopenharmony_ci	.start_streaming	= dcmi_start_streaming,
90162306a36Sopenharmony_ci	.stop_streaming		= dcmi_stop_streaming,
90262306a36Sopenharmony_ci	.wait_prepare		= vb2_ops_wait_prepare,
90362306a36Sopenharmony_ci	.wait_finish		= vb2_ops_wait_finish,
90462306a36Sopenharmony_ci};
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic int dcmi_g_fmt_vid_cap(struct file *file, void *priv,
90762306a36Sopenharmony_ci			      struct v4l2_format *fmt)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	*fmt = dcmi->fmt;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	return 0;
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic const struct dcmi_format *find_format_by_fourcc(struct stm32_dcmi *dcmi,
91762306a36Sopenharmony_ci						       unsigned int fourcc)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	unsigned int num_formats = dcmi->num_of_sd_formats;
92062306a36Sopenharmony_ci	const struct dcmi_format *fmt;
92162306a36Sopenharmony_ci	unsigned int i;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	for (i = 0; i < num_formats; i++) {
92462306a36Sopenharmony_ci		fmt = dcmi->sd_formats[i];
92562306a36Sopenharmony_ci		if (fmt->fourcc == fourcc)
92662306a36Sopenharmony_ci			return fmt;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return NULL;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic void __find_outer_frame_size(struct stm32_dcmi *dcmi,
93362306a36Sopenharmony_ci				    struct v4l2_pix_format *pix,
93462306a36Sopenharmony_ci				    struct dcmi_framesize *framesize)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct dcmi_framesize *match = NULL;
93762306a36Sopenharmony_ci	unsigned int i;
93862306a36Sopenharmony_ci	unsigned int min_err = UINT_MAX;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	for (i = 0; i < dcmi->num_of_sd_framesizes; i++) {
94162306a36Sopenharmony_ci		struct dcmi_framesize *fsize = &dcmi->sd_framesizes[i];
94262306a36Sopenharmony_ci		int w_err = (fsize->width - pix->width);
94362306a36Sopenharmony_ci		int h_err = (fsize->height - pix->height);
94462306a36Sopenharmony_ci		int err = w_err + h_err;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		if (w_err >= 0 && h_err >= 0 && err < min_err) {
94762306a36Sopenharmony_ci			min_err = err;
94862306a36Sopenharmony_ci			match = fsize;
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci	if (!match)
95262306a36Sopenharmony_ci		match = &dcmi->sd_framesizes[0];
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	*framesize = *match;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
95862306a36Sopenharmony_ci			const struct dcmi_format **sd_format,
95962306a36Sopenharmony_ci			struct dcmi_framesize *sd_framesize)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	const struct dcmi_format *sd_fmt;
96262306a36Sopenharmony_ci	struct dcmi_framesize sd_fsize;
96362306a36Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
96462306a36Sopenharmony_ci	struct v4l2_subdev_format format = {
96562306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_TRY,
96662306a36Sopenharmony_ci	};
96762306a36Sopenharmony_ci	bool do_crop;
96862306a36Sopenharmony_ci	int ret;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
97162306a36Sopenharmony_ci	if (!sd_fmt) {
97262306a36Sopenharmony_ci		if (!dcmi->num_of_sd_formats)
97362306a36Sopenharmony_ci			return -ENODATA;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1];
97662306a36Sopenharmony_ci		pix->pixelformat = sd_fmt->fourcc;
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/* Limit to hardware capabilities */
98062306a36Sopenharmony_ci	pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
98162306a36Sopenharmony_ci	pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* No crop if JPEG is requested */
98462306a36Sopenharmony_ci	do_crop = dcmi->do_crop && (pix->pixelformat != V4L2_PIX_FMT_JPEG);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (do_crop && dcmi->num_of_sd_framesizes) {
98762306a36Sopenharmony_ci		struct dcmi_framesize outer_sd_fsize;
98862306a36Sopenharmony_ci		/*
98962306a36Sopenharmony_ci		 * If crop is requested and sensor have discrete frame sizes,
99062306a36Sopenharmony_ci		 * select the frame size that is just larger than request
99162306a36Sopenharmony_ci		 */
99262306a36Sopenharmony_ci		__find_outer_frame_size(dcmi, pix, &outer_sd_fsize);
99362306a36Sopenharmony_ci		pix->width = outer_sd_fsize.width;
99462306a36Sopenharmony_ci		pix->height = outer_sd_fsize.height;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
99862306a36Sopenharmony_ci	ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format);
99962306a36Sopenharmony_ci	if (ret < 0)
100062306a36Sopenharmony_ci		return ret;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* Update pix regarding to what sensor can do */
100362306a36Sopenharmony_ci	v4l2_fill_pix_format(pix, &format.format);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* Save resolution that sensor can actually do */
100662306a36Sopenharmony_ci	sd_fsize.width = pix->width;
100762306a36Sopenharmony_ci	sd_fsize.height = pix->height;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (do_crop) {
101062306a36Sopenharmony_ci		struct v4l2_rect c = dcmi->crop;
101162306a36Sopenharmony_ci		struct v4l2_rect max_rect;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		/*
101462306a36Sopenharmony_ci		 * Adjust crop by making the intersection between
101562306a36Sopenharmony_ci		 * format resolution request and crop request
101662306a36Sopenharmony_ci		 */
101762306a36Sopenharmony_ci		max_rect.top = 0;
101862306a36Sopenharmony_ci		max_rect.left = 0;
101962306a36Sopenharmony_ci		max_rect.width = pix->width;
102062306a36Sopenharmony_ci		max_rect.height = pix->height;
102162306a36Sopenharmony_ci		v4l2_rect_map_inside(&c, &max_rect);
102262306a36Sopenharmony_ci		c.top  = clamp_t(s32, c.top, 0, pix->height - c.height);
102362306a36Sopenharmony_ci		c.left = clamp_t(s32, c.left, 0, pix->width - c.width);
102462306a36Sopenharmony_ci		dcmi->crop = c;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		/* Adjust format resolution request to crop */
102762306a36Sopenharmony_ci		pix->width = dcmi->crop.width;
102862306a36Sopenharmony_ci		pix->height = dcmi->crop.height;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	pix->field = V4L2_FIELD_NONE;
103262306a36Sopenharmony_ci	pix->bytesperline = pix->width * sd_fmt->bpp;
103362306a36Sopenharmony_ci	pix->sizeimage = pix->bytesperline * pix->height;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (sd_format)
103662306a36Sopenharmony_ci		*sd_format = sd_fmt;
103762306a36Sopenharmony_ci	if (sd_framesize)
103862306a36Sopenharmony_ci		*sd_framesize = sd_fsize;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	return 0;
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cistatic int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	struct v4l2_subdev_format format = {
104662306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
104762306a36Sopenharmony_ci	};
104862306a36Sopenharmony_ci	const struct dcmi_format *sd_format;
104962306a36Sopenharmony_ci	struct dcmi_framesize sd_framesize;
105062306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *mf = &format.format;
105162306a36Sopenharmony_ci	struct v4l2_pix_format *pix = &f->fmt.pix;
105262306a36Sopenharmony_ci	int ret;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/*
105562306a36Sopenharmony_ci	 * Try format, fmt.width/height could have been changed
105662306a36Sopenharmony_ci	 * to match sensor capability or crop request
105762306a36Sopenharmony_ci	 * sd_format & sd_framesize will contain what subdev
105862306a36Sopenharmony_ci	 * can do for this request.
105962306a36Sopenharmony_ci	 */
106062306a36Sopenharmony_ci	ret = dcmi_try_fmt(dcmi, f, &sd_format, &sd_framesize);
106162306a36Sopenharmony_ci	if (ret)
106262306a36Sopenharmony_ci		return ret;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	/* Disable crop if JPEG is requested or BT656 bus is selected */
106562306a36Sopenharmony_ci	if (pix->pixelformat == V4L2_PIX_FMT_JPEG &&
106662306a36Sopenharmony_ci	    dcmi->bus_type != V4L2_MBUS_BT656)
106762306a36Sopenharmony_ci		dcmi->do_crop = false;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	/* pix to mbus format */
107062306a36Sopenharmony_ci	v4l2_fill_mbus_format(mf, pix,
107162306a36Sopenharmony_ci			      sd_format->mbus_code);
107262306a36Sopenharmony_ci	mf->width = sd_framesize.width;
107362306a36Sopenharmony_ci	mf->height = sd_framesize.height;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	ret = dcmi_pipeline_s_fmt(dcmi, &format);
107662306a36Sopenharmony_ci	if (ret < 0)
107762306a36Sopenharmony_ci		return ret;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Sensor format set to 0x%x %ux%u\n",
108062306a36Sopenharmony_ci		mf->code, mf->width, mf->height);
108162306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Buffer format set to %4.4s %ux%u\n",
108262306a36Sopenharmony_ci		(char *)&pix->pixelformat,
108362306a36Sopenharmony_ci		pix->width, pix->height);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	dcmi->fmt = *f;
108662306a36Sopenharmony_ci	dcmi->sd_format = sd_format;
108762306a36Sopenharmony_ci	dcmi->sd_framesize = sd_framesize;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return 0;
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic int dcmi_s_fmt_vid_cap(struct file *file, void *priv,
109362306a36Sopenharmony_ci			      struct v4l2_format *f)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (vb2_is_streaming(&dcmi->queue))
109862306a36Sopenharmony_ci		return -EBUSY;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	return dcmi_set_fmt(dcmi, f);
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic int dcmi_try_fmt_vid_cap(struct file *file, void *priv,
110462306a36Sopenharmony_ci				struct v4l2_format *f)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	return dcmi_try_fmt(dcmi, f, NULL, NULL);
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic int dcmi_enum_fmt_vid_cap(struct file *file, void  *priv,
111262306a36Sopenharmony_ci				 struct v4l2_fmtdesc *f)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (f->index >= dcmi->num_of_sd_formats)
111762306a36Sopenharmony_ci		return -EINVAL;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	f->pixelformat = dcmi->sd_formats[f->index]->fourcc;
112062306a36Sopenharmony_ci	return 0;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic int dcmi_get_sensor_format(struct stm32_dcmi *dcmi,
112462306a36Sopenharmony_ci				  struct v4l2_pix_format *pix)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	struct v4l2_subdev_format fmt = {
112762306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
112862306a36Sopenharmony_ci	};
112962306a36Sopenharmony_ci	int ret;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	ret = v4l2_subdev_call(dcmi->source, pad, get_fmt, NULL, &fmt);
113262306a36Sopenharmony_ci	if (ret)
113362306a36Sopenharmony_ci		return ret;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	v4l2_fill_pix_format(pix, &fmt.format);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	return 0;
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
114162306a36Sopenharmony_ci				  struct v4l2_pix_format *pix)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	const struct dcmi_format *sd_fmt;
114462306a36Sopenharmony_ci	struct v4l2_subdev_format format = {
114562306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_TRY,
114662306a36Sopenharmony_ci	};
114762306a36Sopenharmony_ci	int ret;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
115062306a36Sopenharmony_ci	if (!sd_fmt) {
115162306a36Sopenharmony_ci		if (!dcmi->num_of_sd_formats)
115262306a36Sopenharmony_ci			return -ENODATA;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci		sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1];
115562306a36Sopenharmony_ci		pix->pixelformat = sd_fmt->fourcc;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
115962306a36Sopenharmony_ci	ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format);
116062306a36Sopenharmony_ci	if (ret < 0)
116162306a36Sopenharmony_ci		return ret;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	return 0;
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic int dcmi_get_sensor_bounds(struct stm32_dcmi *dcmi,
116762306a36Sopenharmony_ci				  struct v4l2_rect *r)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	struct v4l2_subdev_selection bounds = {
117062306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
117162306a36Sopenharmony_ci		.target = V4L2_SEL_TGT_CROP_BOUNDS,
117262306a36Sopenharmony_ci	};
117362306a36Sopenharmony_ci	unsigned int max_width, max_height, max_pixsize;
117462306a36Sopenharmony_ci	struct v4l2_pix_format pix;
117562306a36Sopenharmony_ci	unsigned int i;
117662306a36Sopenharmony_ci	int ret;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	/*
117962306a36Sopenharmony_ci	 * Get sensor bounds first
118062306a36Sopenharmony_ci	 */
118162306a36Sopenharmony_ci	ret = v4l2_subdev_call(dcmi->source, pad, get_selection,
118262306a36Sopenharmony_ci			       NULL, &bounds);
118362306a36Sopenharmony_ci	if (!ret)
118462306a36Sopenharmony_ci		*r = bounds.r;
118562306a36Sopenharmony_ci	if (ret != -ENOIOCTLCMD)
118662306a36Sopenharmony_ci		return ret;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/*
118962306a36Sopenharmony_ci	 * If selection is not implemented,
119062306a36Sopenharmony_ci	 * fallback by enumerating sensor frame sizes
119162306a36Sopenharmony_ci	 * and take the largest one
119262306a36Sopenharmony_ci	 */
119362306a36Sopenharmony_ci	max_width = 0;
119462306a36Sopenharmony_ci	max_height = 0;
119562306a36Sopenharmony_ci	max_pixsize = 0;
119662306a36Sopenharmony_ci	for (i = 0; i < dcmi->num_of_sd_framesizes; i++) {
119762306a36Sopenharmony_ci		struct dcmi_framesize *fsize = &dcmi->sd_framesizes[i];
119862306a36Sopenharmony_ci		unsigned int pixsize = fsize->width * fsize->height;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci		if (pixsize > max_pixsize) {
120162306a36Sopenharmony_ci			max_pixsize = pixsize;
120262306a36Sopenharmony_ci			max_width = fsize->width;
120362306a36Sopenharmony_ci			max_height = fsize->height;
120462306a36Sopenharmony_ci		}
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	if (max_pixsize > 0) {
120762306a36Sopenharmony_ci		r->top = 0;
120862306a36Sopenharmony_ci		r->left = 0;
120962306a36Sopenharmony_ci		r->width = max_width;
121062306a36Sopenharmony_ci		r->height = max_height;
121162306a36Sopenharmony_ci		return 0;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/*
121562306a36Sopenharmony_ci	 * If frame sizes enumeration is not implemented,
121662306a36Sopenharmony_ci	 * fallback by getting current sensor frame size
121762306a36Sopenharmony_ci	 */
121862306a36Sopenharmony_ci	ret = dcmi_get_sensor_format(dcmi, &pix);
121962306a36Sopenharmony_ci	if (ret)
122062306a36Sopenharmony_ci		return ret;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	r->top = 0;
122362306a36Sopenharmony_ci	r->left = 0;
122462306a36Sopenharmony_ci	r->width = pix.width;
122562306a36Sopenharmony_ci	r->height = pix.height;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	return 0;
122862306a36Sopenharmony_ci}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_cistatic int dcmi_g_selection(struct file *file, void *fh,
123162306a36Sopenharmony_ci			    struct v4l2_selection *s)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
123662306a36Sopenharmony_ci		return -EINVAL;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	switch (s->target) {
123962306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_DEFAULT:
124062306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP_BOUNDS:
124162306a36Sopenharmony_ci		s->r = dcmi->sd_bounds;
124262306a36Sopenharmony_ci		return 0;
124362306a36Sopenharmony_ci	case V4L2_SEL_TGT_CROP:
124462306a36Sopenharmony_ci		if (dcmi->do_crop) {
124562306a36Sopenharmony_ci			s->r = dcmi->crop;
124662306a36Sopenharmony_ci		} else {
124762306a36Sopenharmony_ci			s->r.top = 0;
124862306a36Sopenharmony_ci			s->r.left = 0;
124962306a36Sopenharmony_ci			s->r.width = dcmi->fmt.fmt.pix.width;
125062306a36Sopenharmony_ci			s->r.height = dcmi->fmt.fmt.pix.height;
125162306a36Sopenharmony_ci		}
125262306a36Sopenharmony_ci		break;
125362306a36Sopenharmony_ci	default:
125462306a36Sopenharmony_ci		return -EINVAL;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	return 0;
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic int dcmi_s_selection(struct file *file, void *priv,
126162306a36Sopenharmony_ci			    struct v4l2_selection *s)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
126462306a36Sopenharmony_ci	struct v4l2_rect r = s->r;
126562306a36Sopenharmony_ci	struct v4l2_rect max_rect;
126662306a36Sopenharmony_ci	struct v4l2_pix_format pix;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
126962306a36Sopenharmony_ci	    s->target != V4L2_SEL_TGT_CROP)
127062306a36Sopenharmony_ci		return -EINVAL;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/* Reset sensor resolution to max resolution */
127362306a36Sopenharmony_ci	pix.pixelformat = dcmi->fmt.fmt.pix.pixelformat;
127462306a36Sopenharmony_ci	pix.width = dcmi->sd_bounds.width;
127562306a36Sopenharmony_ci	pix.height = dcmi->sd_bounds.height;
127662306a36Sopenharmony_ci	dcmi_set_sensor_format(dcmi, &pix);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	/*
127962306a36Sopenharmony_ci	 * Make the intersection between
128062306a36Sopenharmony_ci	 * sensor resolution
128162306a36Sopenharmony_ci	 * and crop request
128262306a36Sopenharmony_ci	 */
128362306a36Sopenharmony_ci	max_rect.top = 0;
128462306a36Sopenharmony_ci	max_rect.left = 0;
128562306a36Sopenharmony_ci	max_rect.width = pix.width;
128662306a36Sopenharmony_ci	max_rect.height = pix.height;
128762306a36Sopenharmony_ci	v4l2_rect_map_inside(&r, &max_rect);
128862306a36Sopenharmony_ci	r.top  = clamp_t(s32, r.top, 0, pix.height - r.height);
128962306a36Sopenharmony_ci	r.left = clamp_t(s32, r.left, 0, pix.width - r.width);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	if (!(r.top == dcmi->sd_bounds.top &&
129262306a36Sopenharmony_ci	      r.left == dcmi->sd_bounds.left &&
129362306a36Sopenharmony_ci	      r.width == dcmi->sd_bounds.width &&
129462306a36Sopenharmony_ci	      r.height == dcmi->sd_bounds.height)) {
129562306a36Sopenharmony_ci		/* Crop if request is different than sensor resolution */
129662306a36Sopenharmony_ci		dcmi->do_crop = true;
129762306a36Sopenharmony_ci		dcmi->crop = r;
129862306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "s_selection: crop %ux%u@(%u,%u) from %ux%u\n",
129962306a36Sopenharmony_ci			r.width, r.height, r.left, r.top,
130062306a36Sopenharmony_ci			pix.width, pix.height);
130162306a36Sopenharmony_ci	} else {
130262306a36Sopenharmony_ci		/* Disable crop */
130362306a36Sopenharmony_ci		dcmi->do_crop = false;
130462306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "s_selection: crop is disabled\n");
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	s->r = r;
130862306a36Sopenharmony_ci	return 0;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int dcmi_querycap(struct file *file, void *priv,
131262306a36Sopenharmony_ci			 struct v4l2_capability *cap)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	strscpy(cap->driver, DRV_NAME, sizeof(cap->driver));
131562306a36Sopenharmony_ci	strscpy(cap->card, "STM32 Camera Memory Interface",
131662306a36Sopenharmony_ci		sizeof(cap->card));
131762306a36Sopenharmony_ci	strscpy(cap->bus_info, "platform:dcmi", sizeof(cap->bus_info));
131862306a36Sopenharmony_ci	return 0;
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic int dcmi_enum_input(struct file *file, void *priv,
132262306a36Sopenharmony_ci			   struct v4l2_input *i)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	if (i->index != 0)
132562306a36Sopenharmony_ci		return -EINVAL;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	i->type = V4L2_INPUT_TYPE_CAMERA;
132862306a36Sopenharmony_ci	strscpy(i->name, "Camera", sizeof(i->name));
132962306a36Sopenharmony_ci	return 0;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic int dcmi_g_input(struct file *file, void *priv, unsigned int *i)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	*i = 0;
133562306a36Sopenharmony_ci	return 0;
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_cistatic int dcmi_s_input(struct file *file, void *priv, unsigned int i)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	if (i > 0)
134162306a36Sopenharmony_ci		return -EINVAL;
134262306a36Sopenharmony_ci	return 0;
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic int dcmi_enum_framesizes(struct file *file, void *fh,
134662306a36Sopenharmony_ci				struct v4l2_frmsizeenum *fsize)
134762306a36Sopenharmony_ci{
134862306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
134962306a36Sopenharmony_ci	const struct dcmi_format *sd_fmt;
135062306a36Sopenharmony_ci	struct v4l2_subdev_frame_size_enum fse = {
135162306a36Sopenharmony_ci		.index = fsize->index,
135262306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
135362306a36Sopenharmony_ci	};
135462306a36Sopenharmony_ci	int ret;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	sd_fmt = find_format_by_fourcc(dcmi, fsize->pixel_format);
135762306a36Sopenharmony_ci	if (!sd_fmt)
135862306a36Sopenharmony_ci		return -EINVAL;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	fse.code = sd_fmt->mbus_code;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	ret = v4l2_subdev_call(dcmi->source, pad, enum_frame_size,
136362306a36Sopenharmony_ci			       NULL, &fse);
136462306a36Sopenharmony_ci	if (ret)
136562306a36Sopenharmony_ci		return ret;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
136862306a36Sopenharmony_ci	fsize->discrete.width = fse.max_width;
136962306a36Sopenharmony_ci	fsize->discrete.height = fse.max_height;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	return 0;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_cistatic int dcmi_g_parm(struct file *file, void *priv,
137562306a36Sopenharmony_ci		       struct v4l2_streamparm *p)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	return v4l2_g_parm_cap(video_devdata(file), dcmi->source, p);
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic int dcmi_s_parm(struct file *file, void *priv,
138362306a36Sopenharmony_ci		       struct v4l2_streamparm *p)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return v4l2_s_parm_cap(video_devdata(file), dcmi->source, p);
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int dcmi_enum_frameintervals(struct file *file, void *fh,
139162306a36Sopenharmony_ci				    struct v4l2_frmivalenum *fival)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
139462306a36Sopenharmony_ci	const struct dcmi_format *sd_fmt;
139562306a36Sopenharmony_ci	struct v4l2_subdev_frame_interval_enum fie = {
139662306a36Sopenharmony_ci		.index = fival->index,
139762306a36Sopenharmony_ci		.width = fival->width,
139862306a36Sopenharmony_ci		.height = fival->height,
139962306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
140062306a36Sopenharmony_ci	};
140162306a36Sopenharmony_ci	int ret;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	sd_fmt = find_format_by_fourcc(dcmi, fival->pixel_format);
140462306a36Sopenharmony_ci	if (!sd_fmt)
140562306a36Sopenharmony_ci		return -EINVAL;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	fie.code = sd_fmt->mbus_code;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	ret = v4l2_subdev_call(dcmi->source, pad,
141062306a36Sopenharmony_ci			       enum_frame_interval, NULL, &fie);
141162306a36Sopenharmony_ci	if (ret)
141262306a36Sopenharmony_ci		return ret;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
141562306a36Sopenharmony_ci	fival->discrete = fie.interval;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	return 0;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_cistatic const struct of_device_id stm32_dcmi_of_match[] = {
142162306a36Sopenharmony_ci	{ .compatible = "st,stm32-dcmi"},
142262306a36Sopenharmony_ci	{ /* end node */ },
142362306a36Sopenharmony_ci};
142462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_dcmi_of_match);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_cistatic int dcmi_open(struct file *file)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
142962306a36Sopenharmony_ci	struct v4l2_subdev *sd = dcmi->source;
143062306a36Sopenharmony_ci	int ret;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	if (mutex_lock_interruptible(&dcmi->lock))
143362306a36Sopenharmony_ci		return -ERESTARTSYS;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	ret = v4l2_fh_open(file);
143662306a36Sopenharmony_ci	if (ret < 0)
143762306a36Sopenharmony_ci		goto unlock;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (!v4l2_fh_is_singular_file(file))
144062306a36Sopenharmony_ci		goto fh_rel;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	ret = v4l2_subdev_call(sd, core, s_power, 1);
144362306a36Sopenharmony_ci	if (ret < 0 && ret != -ENOIOCTLCMD)
144462306a36Sopenharmony_ci		goto fh_rel;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	ret = dcmi_set_fmt(dcmi, &dcmi->fmt);
144762306a36Sopenharmony_ci	if (ret)
144862306a36Sopenharmony_ci		v4l2_subdev_call(sd, core, s_power, 0);
144962306a36Sopenharmony_cifh_rel:
145062306a36Sopenharmony_ci	if (ret)
145162306a36Sopenharmony_ci		v4l2_fh_release(file);
145262306a36Sopenharmony_ciunlock:
145362306a36Sopenharmony_ci	mutex_unlock(&dcmi->lock);
145462306a36Sopenharmony_ci	return ret;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic int dcmi_release(struct file *file)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = video_drvdata(file);
146062306a36Sopenharmony_ci	struct v4l2_subdev *sd = dcmi->source;
146162306a36Sopenharmony_ci	bool fh_singular;
146262306a36Sopenharmony_ci	int ret;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	mutex_lock(&dcmi->lock);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	fh_singular = v4l2_fh_is_singular_file(file);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	ret = _vb2_fop_release(file, NULL);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	if (fh_singular)
147162306a36Sopenharmony_ci		v4l2_subdev_call(sd, core, s_power, 0);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	mutex_unlock(&dcmi->lock);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	return ret;
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops dcmi_ioctl_ops = {
147962306a36Sopenharmony_ci	.vidioc_querycap		= dcmi_querycap,
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	.vidioc_try_fmt_vid_cap		= dcmi_try_fmt_vid_cap,
148262306a36Sopenharmony_ci	.vidioc_g_fmt_vid_cap		= dcmi_g_fmt_vid_cap,
148362306a36Sopenharmony_ci	.vidioc_s_fmt_vid_cap		= dcmi_s_fmt_vid_cap,
148462306a36Sopenharmony_ci	.vidioc_enum_fmt_vid_cap	= dcmi_enum_fmt_vid_cap,
148562306a36Sopenharmony_ci	.vidioc_g_selection		= dcmi_g_selection,
148662306a36Sopenharmony_ci	.vidioc_s_selection		= dcmi_s_selection,
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	.vidioc_enum_input		= dcmi_enum_input,
148962306a36Sopenharmony_ci	.vidioc_g_input			= dcmi_g_input,
149062306a36Sopenharmony_ci	.vidioc_s_input			= dcmi_s_input,
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	.vidioc_g_parm			= dcmi_g_parm,
149362306a36Sopenharmony_ci	.vidioc_s_parm			= dcmi_s_parm,
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	.vidioc_enum_framesizes		= dcmi_enum_framesizes,
149662306a36Sopenharmony_ci	.vidioc_enum_frameintervals	= dcmi_enum_frameintervals,
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
149962306a36Sopenharmony_ci	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
150062306a36Sopenharmony_ci	.vidioc_querybuf		= vb2_ioctl_querybuf,
150162306a36Sopenharmony_ci	.vidioc_qbuf			= vb2_ioctl_qbuf,
150262306a36Sopenharmony_ci	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
150362306a36Sopenharmony_ci	.vidioc_expbuf			= vb2_ioctl_expbuf,
150462306a36Sopenharmony_ci	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
150562306a36Sopenharmony_ci	.vidioc_streamon		= vb2_ioctl_streamon,
150662306a36Sopenharmony_ci	.vidioc_streamoff		= vb2_ioctl_streamoff,
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	.vidioc_log_status		= v4l2_ctrl_log_status,
150962306a36Sopenharmony_ci	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
151062306a36Sopenharmony_ci	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
151162306a36Sopenharmony_ci};
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic const struct v4l2_file_operations dcmi_fops = {
151462306a36Sopenharmony_ci	.owner		= THIS_MODULE,
151562306a36Sopenharmony_ci	.unlocked_ioctl	= video_ioctl2,
151662306a36Sopenharmony_ci	.open		= dcmi_open,
151762306a36Sopenharmony_ci	.release	= dcmi_release,
151862306a36Sopenharmony_ci	.poll		= vb2_fop_poll,
151962306a36Sopenharmony_ci	.mmap		= vb2_fop_mmap,
152062306a36Sopenharmony_ci#ifndef CONFIG_MMU
152162306a36Sopenharmony_ci	.get_unmapped_area = vb2_fop_get_unmapped_area,
152262306a36Sopenharmony_ci#endif
152362306a36Sopenharmony_ci	.read		= vb2_fop_read,
152462306a36Sopenharmony_ci};
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic int dcmi_set_default_fmt(struct stm32_dcmi *dcmi)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	struct v4l2_format f = {
152962306a36Sopenharmony_ci		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
153062306a36Sopenharmony_ci		.fmt.pix = {
153162306a36Sopenharmony_ci			.width		= CIF_WIDTH,
153262306a36Sopenharmony_ci			.height		= CIF_HEIGHT,
153362306a36Sopenharmony_ci			.field		= V4L2_FIELD_NONE,
153462306a36Sopenharmony_ci			.pixelformat	= dcmi->sd_formats[0]->fourcc,
153562306a36Sopenharmony_ci		},
153662306a36Sopenharmony_ci	};
153762306a36Sopenharmony_ci	int ret;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	ret = dcmi_try_fmt(dcmi, &f, NULL, NULL);
154062306a36Sopenharmony_ci	if (ret)
154162306a36Sopenharmony_ci		return ret;
154262306a36Sopenharmony_ci	dcmi->sd_format = dcmi->sd_formats[0];
154362306a36Sopenharmony_ci	dcmi->fmt = f;
154462306a36Sopenharmony_ci	return 0;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_cistatic const struct dcmi_format dcmi_formats[] = {
154862306a36Sopenharmony_ci	{
154962306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_RGB565,
155062306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
155162306a36Sopenharmony_ci		.bpp = 2,
155262306a36Sopenharmony_ci	}, {
155362306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_RGB565,
155462306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_RGB565_1X16,
155562306a36Sopenharmony_ci		.bpp = 2,
155662306a36Sopenharmony_ci	}, {
155762306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_YUYV,
155862306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
155962306a36Sopenharmony_ci		.bpp = 2,
156062306a36Sopenharmony_ci	}, {
156162306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_YUYV,
156262306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
156362306a36Sopenharmony_ci		.bpp = 2,
156462306a36Sopenharmony_ci	}, {
156562306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_UYVY,
156662306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
156762306a36Sopenharmony_ci		.bpp = 2,
156862306a36Sopenharmony_ci	}, {
156962306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_UYVY,
157062306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
157162306a36Sopenharmony_ci		.bpp = 2,
157262306a36Sopenharmony_ci	}, {
157362306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_JPEG,
157462306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
157562306a36Sopenharmony_ci		.bpp = 1,
157662306a36Sopenharmony_ci	}, {
157762306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SBGGR8,
157862306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
157962306a36Sopenharmony_ci		.bpp = 1,
158062306a36Sopenharmony_ci	}, {
158162306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGBRG8,
158262306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
158362306a36Sopenharmony_ci		.bpp = 1,
158462306a36Sopenharmony_ci	}, {
158562306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGRBG8,
158662306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
158762306a36Sopenharmony_ci		.bpp = 1,
158862306a36Sopenharmony_ci	}, {
158962306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SRGGB8,
159062306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
159162306a36Sopenharmony_ci		.bpp = 1,
159262306a36Sopenharmony_ci	}, {
159362306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SBGGR10,
159462306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
159562306a36Sopenharmony_ci		.bpp = 2,
159662306a36Sopenharmony_ci	}, {
159762306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGBRG10,
159862306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
159962306a36Sopenharmony_ci		.bpp = 2,
160062306a36Sopenharmony_ci	}, {
160162306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGRBG10,
160262306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
160362306a36Sopenharmony_ci		.bpp = 2,
160462306a36Sopenharmony_ci	}, {
160562306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SRGGB10,
160662306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
160762306a36Sopenharmony_ci		.bpp = 2,
160862306a36Sopenharmony_ci	}, {
160962306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SBGGR12,
161062306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
161162306a36Sopenharmony_ci		.bpp = 2,
161262306a36Sopenharmony_ci	}, {
161362306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGBRG12,
161462306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
161562306a36Sopenharmony_ci		.bpp = 2,
161662306a36Sopenharmony_ci	}, {
161762306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGRBG12,
161862306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
161962306a36Sopenharmony_ci		.bpp = 2,
162062306a36Sopenharmony_ci	}, {
162162306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SRGGB12,
162262306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
162362306a36Sopenharmony_ci		.bpp = 2,
162462306a36Sopenharmony_ci	}, {
162562306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SBGGR14,
162662306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14,
162762306a36Sopenharmony_ci		.bpp = 2,
162862306a36Sopenharmony_ci	}, {
162962306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGBRG14,
163062306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14,
163162306a36Sopenharmony_ci		.bpp = 2,
163262306a36Sopenharmony_ci	}, {
163362306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SGRBG14,
163462306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14,
163562306a36Sopenharmony_ci		.bpp = 2,
163662306a36Sopenharmony_ci	}, {
163762306a36Sopenharmony_ci		.fourcc = V4L2_PIX_FMT_SRGGB14,
163862306a36Sopenharmony_ci		.mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14,
163962306a36Sopenharmony_ci		.bpp = 2,
164062306a36Sopenharmony_ci	},
164162306a36Sopenharmony_ci};
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_cistatic int dcmi_formats_init(struct stm32_dcmi *dcmi)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)];
164662306a36Sopenharmony_ci	unsigned int num_fmts = 0, i, j;
164762306a36Sopenharmony_ci	struct v4l2_subdev *subdev = dcmi->source;
164862306a36Sopenharmony_ci	struct v4l2_subdev_mbus_code_enum mbus_code = {
164962306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
165062306a36Sopenharmony_ci	};
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	while (!v4l2_subdev_call(subdev, pad, enum_mbus_code,
165362306a36Sopenharmony_ci				 NULL, &mbus_code)) {
165462306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(dcmi_formats); i++) {
165562306a36Sopenharmony_ci			if (dcmi_formats[i].mbus_code != mbus_code.code)
165662306a36Sopenharmony_ci				continue;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci			/* Exclude JPEG if BT656 bus is selected */
165962306a36Sopenharmony_ci			if (dcmi_formats[i].fourcc == V4L2_PIX_FMT_JPEG &&
166062306a36Sopenharmony_ci			    dcmi->bus_type == V4L2_MBUS_BT656)
166162306a36Sopenharmony_ci				continue;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci			/* Code supported, have we got this fourcc yet? */
166462306a36Sopenharmony_ci			for (j = 0; j < num_fmts; j++)
166562306a36Sopenharmony_ci				if (sd_fmts[j]->fourcc ==
166662306a36Sopenharmony_ci						dcmi_formats[i].fourcc) {
166762306a36Sopenharmony_ci					/* Already available */
166862306a36Sopenharmony_ci					dev_dbg(dcmi->dev, "Skipping fourcc/code: %4.4s/0x%x\n",
166962306a36Sopenharmony_ci						(char *)&sd_fmts[j]->fourcc,
167062306a36Sopenharmony_ci						mbus_code.code);
167162306a36Sopenharmony_ci					break;
167262306a36Sopenharmony_ci				}
167362306a36Sopenharmony_ci			if (j == num_fmts) {
167462306a36Sopenharmony_ci				/* New */
167562306a36Sopenharmony_ci				sd_fmts[num_fmts++] = dcmi_formats + i;
167662306a36Sopenharmony_ci				dev_dbg(dcmi->dev, "Supported fourcc/code: %4.4s/0x%x\n",
167762306a36Sopenharmony_ci					(char *)&sd_fmts[num_fmts - 1]->fourcc,
167862306a36Sopenharmony_ci					sd_fmts[num_fmts - 1]->mbus_code);
167962306a36Sopenharmony_ci			}
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci		mbus_code.index++;
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	if (!num_fmts)
168562306a36Sopenharmony_ci		return -ENXIO;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	dcmi->num_of_sd_formats = num_fmts;
168862306a36Sopenharmony_ci	dcmi->sd_formats = devm_kcalloc(dcmi->dev,
168962306a36Sopenharmony_ci					num_fmts, sizeof(struct dcmi_format *),
169062306a36Sopenharmony_ci					GFP_KERNEL);
169162306a36Sopenharmony_ci	if (!dcmi->sd_formats) {
169262306a36Sopenharmony_ci		dev_err(dcmi->dev, "Could not allocate memory\n");
169362306a36Sopenharmony_ci		return -ENOMEM;
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	memcpy(dcmi->sd_formats, sd_fmts,
169762306a36Sopenharmony_ci	       num_fmts * sizeof(struct dcmi_format *));
169862306a36Sopenharmony_ci	dcmi->sd_format = dcmi->sd_formats[0];
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	return 0;
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic int dcmi_framesizes_init(struct stm32_dcmi *dcmi)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	unsigned int num_fsize = 0;
170662306a36Sopenharmony_ci	struct v4l2_subdev *subdev = dcmi->source;
170762306a36Sopenharmony_ci	struct v4l2_subdev_frame_size_enum fse = {
170862306a36Sopenharmony_ci		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
170962306a36Sopenharmony_ci		.code = dcmi->sd_format->mbus_code,
171062306a36Sopenharmony_ci	};
171162306a36Sopenharmony_ci	unsigned int ret;
171262306a36Sopenharmony_ci	unsigned int i;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	/* Allocate discrete framesizes array */
171562306a36Sopenharmony_ci	while (!v4l2_subdev_call(subdev, pad, enum_frame_size,
171662306a36Sopenharmony_ci				 NULL, &fse))
171762306a36Sopenharmony_ci		fse.index++;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	num_fsize = fse.index;
172062306a36Sopenharmony_ci	if (!num_fsize)
172162306a36Sopenharmony_ci		return 0;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	dcmi->num_of_sd_framesizes = num_fsize;
172462306a36Sopenharmony_ci	dcmi->sd_framesizes = devm_kcalloc(dcmi->dev, num_fsize,
172562306a36Sopenharmony_ci					   sizeof(struct dcmi_framesize),
172662306a36Sopenharmony_ci					   GFP_KERNEL);
172762306a36Sopenharmony_ci	if (!dcmi->sd_framesizes) {
172862306a36Sopenharmony_ci		dev_err(dcmi->dev, "Could not allocate memory\n");
172962306a36Sopenharmony_ci		return -ENOMEM;
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/* Fill array with sensor supported framesizes */
173362306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Sensor supports %u frame sizes:\n", num_fsize);
173462306a36Sopenharmony_ci	for (i = 0; i < dcmi->num_of_sd_framesizes; i++) {
173562306a36Sopenharmony_ci		fse.index = i;
173662306a36Sopenharmony_ci		ret = v4l2_subdev_call(subdev, pad, enum_frame_size,
173762306a36Sopenharmony_ci				       NULL, &fse);
173862306a36Sopenharmony_ci		if (ret)
173962306a36Sopenharmony_ci			return ret;
174062306a36Sopenharmony_ci		dcmi->sd_framesizes[fse.index].width = fse.max_width;
174162306a36Sopenharmony_ci		dcmi->sd_framesizes[fse.index].height = fse.max_height;
174262306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "%ux%u\n", fse.max_width, fse.max_height);
174362306a36Sopenharmony_ci	}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	return 0;
174662306a36Sopenharmony_ci}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_cistatic int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
174962306a36Sopenharmony_ci{
175062306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
175162306a36Sopenharmony_ci	int ret;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	/*
175462306a36Sopenharmony_ci	 * Now that the graph is complete,
175562306a36Sopenharmony_ci	 * we search for the source subdevice
175662306a36Sopenharmony_ci	 * in order to expose it through V4L2 interface
175762306a36Sopenharmony_ci	 */
175862306a36Sopenharmony_ci	dcmi->source = media_entity_to_v4l2_subdev(dcmi_find_source(dcmi));
175962306a36Sopenharmony_ci	if (!dcmi->source) {
176062306a36Sopenharmony_ci		dev_err(dcmi->dev, "Source subdevice not found\n");
176162306a36Sopenharmony_ci		return -ENODEV;
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	dcmi->vdev->ctrl_handler = dcmi->source->ctrl_handler;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	ret = dcmi_formats_init(dcmi);
176762306a36Sopenharmony_ci	if (ret) {
176862306a36Sopenharmony_ci		dev_err(dcmi->dev, "No supported mediabus format found\n");
176962306a36Sopenharmony_ci		return ret;
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	ret = dcmi_framesizes_init(dcmi);
177362306a36Sopenharmony_ci	if (ret) {
177462306a36Sopenharmony_ci		dev_err(dcmi->dev, "Could not initialize framesizes\n");
177562306a36Sopenharmony_ci		return ret;
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	ret = dcmi_get_sensor_bounds(dcmi, &dcmi->sd_bounds);
177962306a36Sopenharmony_ci	if (ret) {
178062306a36Sopenharmony_ci		dev_err(dcmi->dev, "Could not get sensor bounds\n");
178162306a36Sopenharmony_ci		return ret;
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	ret = dcmi_set_default_fmt(dcmi);
178562306a36Sopenharmony_ci	if (ret) {
178662306a36Sopenharmony_ci		dev_err(dcmi->dev, "Could not set default format\n");
178762306a36Sopenharmony_ci		return ret;
178862306a36Sopenharmony_ci	}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	ret = devm_request_threaded_irq(dcmi->dev, dcmi->irq, dcmi_irq_callback,
179162306a36Sopenharmony_ci					dcmi_irq_thread, IRQF_ONESHOT,
179262306a36Sopenharmony_ci					dev_name(dcmi->dev), dcmi);
179362306a36Sopenharmony_ci	if (ret) {
179462306a36Sopenharmony_ci		dev_err(dcmi->dev, "Unable to request irq %d\n", dcmi->irq);
179562306a36Sopenharmony_ci		return ret;
179662306a36Sopenharmony_ci	}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	return 0;
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_cistatic void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
180262306a36Sopenharmony_ci				     struct v4l2_subdev *sd,
180362306a36Sopenharmony_ci				     struct v4l2_async_connection *asd)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Removing %s\n", video_device_node_name(dcmi->vdev));
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	/* Checks internally if vdev has been init or not */
181062306a36Sopenharmony_ci	video_unregister_device(dcmi->vdev);
181162306a36Sopenharmony_ci}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_cistatic int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
181462306a36Sopenharmony_ci				   struct v4l2_subdev *subdev,
181562306a36Sopenharmony_ci				   struct v4l2_async_connection *asd)
181662306a36Sopenharmony_ci{
181762306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
181862306a36Sopenharmony_ci	unsigned int ret;
181962306a36Sopenharmony_ci	int src_pad;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/*
182462306a36Sopenharmony_ci	 * Link this sub-device to DCMI, it could be
182562306a36Sopenharmony_ci	 * a parallel camera sensor or a bridge
182662306a36Sopenharmony_ci	 */
182762306a36Sopenharmony_ci	src_pad = media_entity_get_fwnode_pad(&subdev->entity,
182862306a36Sopenharmony_ci					      subdev->fwnode,
182962306a36Sopenharmony_ci					      MEDIA_PAD_FL_SOURCE);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	ret = media_create_pad_link(&subdev->entity, src_pad,
183262306a36Sopenharmony_ci				    &dcmi->vdev->entity, 0,
183362306a36Sopenharmony_ci				    MEDIA_LNK_FL_IMMUTABLE |
183462306a36Sopenharmony_ci				    MEDIA_LNK_FL_ENABLED);
183562306a36Sopenharmony_ci	if (ret)
183662306a36Sopenharmony_ci		dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n",
183762306a36Sopenharmony_ci			subdev->name);
183862306a36Sopenharmony_ci	else
183962306a36Sopenharmony_ci		dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n",
184062306a36Sopenharmony_ci			subdev->name);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	dcmi->s_subdev = subdev;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	return ret;
184562306a36Sopenharmony_ci}
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = {
184862306a36Sopenharmony_ci	.bound = dcmi_graph_notify_bound,
184962306a36Sopenharmony_ci	.unbind = dcmi_graph_notify_unbind,
185062306a36Sopenharmony_ci	.complete = dcmi_graph_notify_complete,
185162306a36Sopenharmony_ci};
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_cistatic int dcmi_graph_init(struct stm32_dcmi *dcmi)
185462306a36Sopenharmony_ci{
185562306a36Sopenharmony_ci	struct v4l2_async_connection *asd;
185662306a36Sopenharmony_ci	struct device_node *ep;
185762306a36Sopenharmony_ci	int ret;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	ep = of_graph_get_next_endpoint(dcmi->dev->of_node, NULL);
186062306a36Sopenharmony_ci	if (!ep) {
186162306a36Sopenharmony_ci		dev_err(dcmi->dev, "Failed to get next endpoint\n");
186262306a36Sopenharmony_ci		return -EINVAL;
186362306a36Sopenharmony_ci	}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	v4l2_async_nf_init(&dcmi->notifier, &dcmi->v4l2_dev);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	asd = v4l2_async_nf_add_fwnode_remote(&dcmi->notifier,
186862306a36Sopenharmony_ci					      of_fwnode_handle(ep),
186962306a36Sopenharmony_ci					      struct v4l2_async_connection);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	of_node_put(ep);
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	if (IS_ERR(asd)) {
187462306a36Sopenharmony_ci		dev_err(dcmi->dev, "Failed to add subdev notifier\n");
187562306a36Sopenharmony_ci		return PTR_ERR(asd);
187662306a36Sopenharmony_ci	}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	dcmi->notifier.ops = &dcmi_graph_notify_ops;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	ret = v4l2_async_nf_register(&dcmi->notifier);
188162306a36Sopenharmony_ci	if (ret < 0) {
188262306a36Sopenharmony_ci		dev_err(dcmi->dev, "Failed to register notifier\n");
188362306a36Sopenharmony_ci		v4l2_async_nf_cleanup(&dcmi->notifier);
188462306a36Sopenharmony_ci		return ret;
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	return 0;
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_cistatic int dcmi_probe(struct platform_device *pdev)
189162306a36Sopenharmony_ci{
189262306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
189362306a36Sopenharmony_ci	const struct of_device_id *match = NULL;
189462306a36Sopenharmony_ci	struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
189562306a36Sopenharmony_ci	struct stm32_dcmi *dcmi;
189662306a36Sopenharmony_ci	struct vb2_queue *q;
189762306a36Sopenharmony_ci	struct dma_chan *chan;
189862306a36Sopenharmony_ci	struct dma_slave_caps caps;
189962306a36Sopenharmony_ci	struct clk *mclk;
190062306a36Sopenharmony_ci	int ret = 0;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	match = of_match_device(of_match_ptr(stm32_dcmi_of_match), &pdev->dev);
190362306a36Sopenharmony_ci	if (!match) {
190462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not find a match in devicetree\n");
190562306a36Sopenharmony_ci		return -ENODEV;
190662306a36Sopenharmony_ci	}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	dcmi = devm_kzalloc(&pdev->dev, sizeof(struct stm32_dcmi), GFP_KERNEL);
190962306a36Sopenharmony_ci	if (!dcmi)
191062306a36Sopenharmony_ci		return -ENOMEM;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
191362306a36Sopenharmony_ci	if (IS_ERR(dcmi->rstc))
191462306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(dcmi->rstc),
191562306a36Sopenharmony_ci				     "Could not get reset control\n");
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	/* Get bus characteristics from devicetree */
191862306a36Sopenharmony_ci	np = of_graph_get_next_endpoint(np, NULL);
191962306a36Sopenharmony_ci	if (!np) {
192062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not find the endpoint\n");
192162306a36Sopenharmony_ci		return -ENODEV;
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &ep);
192562306a36Sopenharmony_ci	of_node_put(np);
192662306a36Sopenharmony_ci	if (ret) {
192762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not parse the endpoint\n");
192862306a36Sopenharmony_ci		return ret;
192962306a36Sopenharmony_ci	}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	if (ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
193262306a36Sopenharmony_ci		dev_err(&pdev->dev, "CSI bus not supported\n");
193362306a36Sopenharmony_ci		return -ENODEV;
193462306a36Sopenharmony_ci	}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	if (ep.bus_type == V4L2_MBUS_BT656 &&
193762306a36Sopenharmony_ci	    ep.bus.parallel.bus_width != 8) {
193862306a36Sopenharmony_ci		dev_err(&pdev->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n",
193962306a36Sopenharmony_ci			ep.bus.parallel.bus_width);
194062306a36Sopenharmony_ci		return -ENODEV;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	dcmi->bus.flags = ep.bus.parallel.flags;
194462306a36Sopenharmony_ci	dcmi->bus.bus_width = ep.bus.parallel.bus_width;
194562306a36Sopenharmony_ci	dcmi->bus.data_shift = ep.bus.parallel.data_shift;
194662306a36Sopenharmony_ci	dcmi->bus_type = ep.bus_type;
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	dcmi->irq = platform_get_irq(pdev, 0);
194962306a36Sopenharmony_ci	if (dcmi->irq < 0)
195062306a36Sopenharmony_ci		return dcmi->irq;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	dcmi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &dcmi->res);
195362306a36Sopenharmony_ci	if (IS_ERR(dcmi->regs))
195462306a36Sopenharmony_ci		return PTR_ERR(dcmi->regs);
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	mclk = devm_clk_get(&pdev->dev, "mclk");
195762306a36Sopenharmony_ci	if (IS_ERR(mclk))
195862306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(mclk),
195962306a36Sopenharmony_ci				     "Unable to get mclk\n");
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	chan = dma_request_chan(&pdev->dev, "tx");
196262306a36Sopenharmony_ci	if (IS_ERR(chan))
196362306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(chan),
196462306a36Sopenharmony_ci				     "Failed to request DMA channel\n");
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	dcmi->dma_max_burst = UINT_MAX;
196762306a36Sopenharmony_ci	ret = dma_get_slave_caps(chan, &caps);
196862306a36Sopenharmony_ci	if (!ret && caps.max_sg_burst)
196962306a36Sopenharmony_ci		dcmi->dma_max_burst = caps.max_sg_burst	* DMA_SLAVE_BUSWIDTH_4_BYTES;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	spin_lock_init(&dcmi->irqlock);
197262306a36Sopenharmony_ci	mutex_init(&dcmi->lock);
197362306a36Sopenharmony_ci	mutex_init(&dcmi->dma_lock);
197462306a36Sopenharmony_ci	init_completion(&dcmi->complete);
197562306a36Sopenharmony_ci	INIT_LIST_HEAD(&dcmi->buffers);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	dcmi->dev = &pdev->dev;
197862306a36Sopenharmony_ci	dcmi->mclk = mclk;
197962306a36Sopenharmony_ci	dcmi->state = STOPPED;
198062306a36Sopenharmony_ci	dcmi->dma_chan = chan;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	q = &dcmi->queue;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	dcmi->v4l2_dev.mdev = &dcmi->mdev;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	/* Initialize media device */
198762306a36Sopenharmony_ci	strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model));
198862306a36Sopenharmony_ci	dcmi->mdev.dev = &pdev->dev;
198962306a36Sopenharmony_ci	media_device_init(&dcmi->mdev);
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	/* Initialize the top-level structure */
199262306a36Sopenharmony_ci	ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev);
199362306a36Sopenharmony_ci	if (ret)
199462306a36Sopenharmony_ci		goto err_media_device_cleanup;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	dcmi->vdev = video_device_alloc();
199762306a36Sopenharmony_ci	if (!dcmi->vdev) {
199862306a36Sopenharmony_ci		ret = -ENOMEM;
199962306a36Sopenharmony_ci		goto err_device_unregister;
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	/* Video node */
200362306a36Sopenharmony_ci	dcmi->vdev->fops = &dcmi_fops;
200462306a36Sopenharmony_ci	dcmi->vdev->v4l2_dev = &dcmi->v4l2_dev;
200562306a36Sopenharmony_ci	dcmi->vdev->queue = &dcmi->queue;
200662306a36Sopenharmony_ci	strscpy(dcmi->vdev->name, KBUILD_MODNAME, sizeof(dcmi->vdev->name));
200762306a36Sopenharmony_ci	dcmi->vdev->release = video_device_release;
200862306a36Sopenharmony_ci	dcmi->vdev->ioctl_ops = &dcmi_ioctl_ops;
200962306a36Sopenharmony_ci	dcmi->vdev->lock = &dcmi->lock;
201062306a36Sopenharmony_ci	dcmi->vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
201162306a36Sopenharmony_ci				  V4L2_CAP_READWRITE;
201262306a36Sopenharmony_ci	video_set_drvdata(dcmi->vdev, dcmi);
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	/* Media entity pads */
201562306a36Sopenharmony_ci	dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK;
201662306a36Sopenharmony_ci	ret = media_entity_pads_init(&dcmi->vdev->entity,
201762306a36Sopenharmony_ci				     1, &dcmi->vid_cap_pad);
201862306a36Sopenharmony_ci	if (ret) {
201962306a36Sopenharmony_ci		dev_err(dcmi->dev, "Failed to init media entity pad\n");
202062306a36Sopenharmony_ci		goto err_device_release;
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci	dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1);
202562306a36Sopenharmony_ci	if (ret) {
202662306a36Sopenharmony_ci		dev_err(dcmi->dev, "Failed to register video device\n");
202762306a36Sopenharmony_ci		goto err_media_entity_cleanup;
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	dev_dbg(dcmi->dev, "Device registered as %s\n",
203162306a36Sopenharmony_ci		video_device_node_name(dcmi->vdev));
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	/* Buffer queue */
203462306a36Sopenharmony_ci	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
203562306a36Sopenharmony_ci	q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
203662306a36Sopenharmony_ci	q->lock = &dcmi->lock;
203762306a36Sopenharmony_ci	q->drv_priv = dcmi;
203862306a36Sopenharmony_ci	q->buf_struct_size = sizeof(struct dcmi_buf);
203962306a36Sopenharmony_ci	q->ops = &dcmi_video_qops;
204062306a36Sopenharmony_ci	q->mem_ops = &vb2_dma_contig_memops;
204162306a36Sopenharmony_ci	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
204262306a36Sopenharmony_ci	q->min_buffers_needed = 2;
204362306a36Sopenharmony_ci	q->allow_cache_hints = 1;
204462306a36Sopenharmony_ci	q->dev = &pdev->dev;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	ret = vb2_queue_init(q);
204762306a36Sopenharmony_ci	if (ret < 0) {
204862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to initialize vb2 queue\n");
204962306a36Sopenharmony_ci		goto err_media_entity_cleanup;
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	ret = dcmi_graph_init(dcmi);
205362306a36Sopenharmony_ci	if (ret < 0)
205462306a36Sopenharmony_ci		goto err_media_entity_cleanup;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/* Reset device */
205762306a36Sopenharmony_ci	ret = reset_control_assert(dcmi->rstc);
205862306a36Sopenharmony_ci	if (ret) {
205962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to assert the reset line\n");
206062306a36Sopenharmony_ci		goto err_cleanup;
206162306a36Sopenharmony_ci	}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	usleep_range(3000, 5000);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	ret = reset_control_deassert(dcmi->rstc);
206662306a36Sopenharmony_ci	if (ret) {
206762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to deassert the reset line\n");
206862306a36Sopenharmony_ci		goto err_cleanup;
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	dev_info(&pdev->dev, "Probe done\n");
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	platform_set_drvdata(pdev, dcmi);
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	return 0;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_cierr_cleanup:
208062306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&dcmi->notifier);
208162306a36Sopenharmony_cierr_media_entity_cleanup:
208262306a36Sopenharmony_ci	media_entity_cleanup(&dcmi->vdev->entity);
208362306a36Sopenharmony_cierr_device_release:
208462306a36Sopenharmony_ci	video_device_release(dcmi->vdev);
208562306a36Sopenharmony_cierr_device_unregister:
208662306a36Sopenharmony_ci	v4l2_device_unregister(&dcmi->v4l2_dev);
208762306a36Sopenharmony_cierr_media_device_cleanup:
208862306a36Sopenharmony_ci	media_device_cleanup(&dcmi->mdev);
208962306a36Sopenharmony_ci	dma_release_channel(dcmi->dma_chan);
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	return ret;
209262306a36Sopenharmony_ci}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_cistatic void dcmi_remove(struct platform_device *pdev)
209562306a36Sopenharmony_ci{
209662306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = platform_get_drvdata(pdev);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	v4l2_async_nf_unregister(&dcmi->notifier);
210162306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&dcmi->notifier);
210262306a36Sopenharmony_ci	media_entity_cleanup(&dcmi->vdev->entity);
210362306a36Sopenharmony_ci	v4l2_device_unregister(&dcmi->v4l2_dev);
210462306a36Sopenharmony_ci	media_device_cleanup(&dcmi->mdev);
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	dma_release_channel(dcmi->dma_chan);
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_cistatic __maybe_unused int dcmi_runtime_suspend(struct device *dev)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	clk_disable_unprepare(dcmi->mclk);
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	return 0;
211662306a36Sopenharmony_ci}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_cistatic __maybe_unused int dcmi_runtime_resume(struct device *dev)
211962306a36Sopenharmony_ci{
212062306a36Sopenharmony_ci	struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
212162306a36Sopenharmony_ci	int ret;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	ret = clk_prepare_enable(dcmi->mclk);
212462306a36Sopenharmony_ci	if (ret)
212562306a36Sopenharmony_ci		dev_err(dev, "%s: Failed to prepare_enable clock\n", __func__);
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	return ret;
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_cistatic __maybe_unused int dcmi_suspend(struct device *dev)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	/* disable clock */
213362306a36Sopenharmony_ci	pm_runtime_force_suspend(dev);
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/* change pinctrl state */
213662306a36Sopenharmony_ci	pinctrl_pm_select_sleep_state(dev);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	return 0;
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_cistatic __maybe_unused int dcmi_resume(struct device *dev)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	/* restore pinctl default state */
214462306a36Sopenharmony_ci	pinctrl_pm_select_default_state(dev);
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	/* clock enable */
214762306a36Sopenharmony_ci	pm_runtime_force_resume(dev);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	return 0;
215062306a36Sopenharmony_ci}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_cistatic const struct dev_pm_ops dcmi_pm_ops = {
215362306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(dcmi_suspend, dcmi_resume)
215462306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(dcmi_runtime_suspend,
215562306a36Sopenharmony_ci			   dcmi_runtime_resume, NULL)
215662306a36Sopenharmony_ci};
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_cistatic struct platform_driver stm32_dcmi_driver = {
215962306a36Sopenharmony_ci	.probe		= dcmi_probe,
216062306a36Sopenharmony_ci	.remove_new	= dcmi_remove,
216162306a36Sopenharmony_ci	.driver		= {
216262306a36Sopenharmony_ci		.name = DRV_NAME,
216362306a36Sopenharmony_ci		.of_match_table = of_match_ptr(stm32_dcmi_of_match),
216462306a36Sopenharmony_ci		.pm = &dcmi_pm_ops,
216562306a36Sopenharmony_ci	},
216662306a36Sopenharmony_ci};
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cimodule_platform_driver(stm32_dcmi_driver);
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ciMODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
217162306a36Sopenharmony_ciMODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@st.com>");
217262306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface driver");
217362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2174