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