162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * R-Car Gen3 Digital Radio Interface (DRIF) driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Renesas Electronics Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * The R-Car DRIF is a receive only MSIOF like controller with an 1062306a36Sopenharmony_ci * external master device driving the SCK. It receives data into a FIFO, 1162306a36Sopenharmony_ci * then this driver uses the SYS-DMAC engine to move the data from 1262306a36Sopenharmony_ci * the device to memory. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Each DRIF channel DRIFx (as per datasheet) contains two internal 1562306a36Sopenharmony_ci * channels DRIFx0 & DRIFx1 within itself with each having its own resources 1662306a36Sopenharmony_ci * like module clk, register set, irq and dma. These internal channels share 1762306a36Sopenharmony_ci * common CLK & SYNC from master. The two data pins D0 & D1 shall be 1862306a36Sopenharmony_ci * considered to represent the two internal channels. This internal split 1962306a36Sopenharmony_ci * is not visible to the master device. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Depending on the master device, a DRIF channel can use 2262306a36Sopenharmony_ci * (1) both internal channels (D0 & D1) to receive data in parallel (or) 2362306a36Sopenharmony_ci * (2) one internal channel (D0 or D1) to receive data 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * The primary design goal of this controller is to act as a Digital Radio 2662306a36Sopenharmony_ci * Interface that receives digital samples from a tuner device. Hence the 2762306a36Sopenharmony_ci * driver exposes the device as a V4L2 SDR device. In order to qualify as 2862306a36Sopenharmony_ci * a V4L2 SDR device, it should possess a tuner interface as mandated by the 2962306a36Sopenharmony_ci * framework. This driver expects a tuner driver (sub-device) to bind 3062306a36Sopenharmony_ci * asynchronously with this device and the combined drivers shall expose 3162306a36Sopenharmony_ci * a V4L2 compliant SDR device. The DRIF driver is independent of the 3262306a36Sopenharmony_ci * tuner vendor. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * The DRIF h/w can support I2S mode and Frame start synchronization pulse mode. 3562306a36Sopenharmony_ci * This driver is tested for I2S mode only because of the availability of 3662306a36Sopenharmony_ci * suitable master devices. Hence, not all configurable options of DRIF h/w 3762306a36Sopenharmony_ci * like lsb/msb first, syncdl, dtdl etc. are exposed via DT and I2S defaults 3862306a36Sopenharmony_ci * are used. These can be exposed later if needed after testing. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci#include <linux/bitops.h> 4162306a36Sopenharmony_ci#include <linux/clk.h> 4262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4362306a36Sopenharmony_ci#include <linux/dmaengine.h> 4462306a36Sopenharmony_ci#include <linux/ioctl.h> 4562306a36Sopenharmony_ci#include <linux/iopoll.h> 4662306a36Sopenharmony_ci#include <linux/module.h> 4762306a36Sopenharmony_ci#include <linux/of.h> 4862306a36Sopenharmony_ci#include <linux/of_graph.h> 4962306a36Sopenharmony_ci#include <linux/of_platform.h> 5062306a36Sopenharmony_ci#include <linux/platform_device.h> 5162306a36Sopenharmony_ci#include <linux/sched.h> 5262306a36Sopenharmony_ci#include <media/v4l2-async.h> 5362306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 5462306a36Sopenharmony_ci#include <media/v4l2-device.h> 5562306a36Sopenharmony_ci#include <media/v4l2-event.h> 5662306a36Sopenharmony_ci#include <media/v4l2-fh.h> 5762306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 5862306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h> 5962306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* DRIF register offsets */ 6262306a36Sopenharmony_ci#define RCAR_DRIF_SITMDR1 0x00 6362306a36Sopenharmony_ci#define RCAR_DRIF_SITMDR2 0x04 6462306a36Sopenharmony_ci#define RCAR_DRIF_SITMDR3 0x08 6562306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1 0x10 6662306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR2 0x14 6762306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR3 0x18 6862306a36Sopenharmony_ci#define RCAR_DRIF_SICTR 0x28 6962306a36Sopenharmony_ci#define RCAR_DRIF_SIFCTR 0x30 7062306a36Sopenharmony_ci#define RCAR_DRIF_SISTR 0x40 7162306a36Sopenharmony_ci#define RCAR_DRIF_SIIER 0x44 7262306a36Sopenharmony_ci#define RCAR_DRIF_SIRFDR 0x60 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define RCAR_DRIF_RFOVF BIT(3) /* Receive FIFO overflow */ 7562306a36Sopenharmony_ci#define RCAR_DRIF_RFUDF BIT(4) /* Receive FIFO underflow */ 7662306a36Sopenharmony_ci#define RCAR_DRIF_RFSERR BIT(5) /* Receive frame sync error */ 7762306a36Sopenharmony_ci#define RCAR_DRIF_REOF BIT(7) /* Frame reception end */ 7862306a36Sopenharmony_ci#define RCAR_DRIF_RDREQ BIT(12) /* Receive data xfer req */ 7962306a36Sopenharmony_ci#define RCAR_DRIF_RFFUL BIT(13) /* Receive FIFO full */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* SIRMDR1 */ 8262306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCMD_FRAME (0 << 28) 8362306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCMD_LR (3 << 28) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH (0 << 25) 8662306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCAC_POL_LOW (1 << 25) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_MSB_FIRST (0 << 24) 8962306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_LSB_FIRST (1 << 24) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_DTDL_0 (0 << 20) 9262306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_DTDL_1 (1 << 20) 9362306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_DTDL_2 (2 << 20) 9462306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_DTDL_0PT5 (5 << 20) 9562306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_DTDL_1PT5 (6 << 20) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCDL_0 (0 << 20) 9862306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCDL_1 (1 << 20) 9962306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCDL_2 (2 << 20) 10062306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCDL_3 (3 << 20) 10162306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCDL_0PT5 (5 << 20) 10262306a36Sopenharmony_ci#define RCAR_DRIF_SIRMDR1_SYNCDL_1PT5 (6 << 20) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define RCAR_DRIF_MDR_GRPCNT(n) (((n) - 1) << 30) 10562306a36Sopenharmony_ci#define RCAR_DRIF_MDR_BITLEN(n) (((n) - 1) << 24) 10662306a36Sopenharmony_ci#define RCAR_DRIF_MDR_WDCNT(n) (((n) - 1) << 16) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Hidden Transmit register that controls CLK & SYNC */ 10962306a36Sopenharmony_ci#define RCAR_DRIF_SITMDR1_PCON BIT(30) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define RCAR_DRIF_SICTR_RX_RISING_EDGE BIT(26) 11262306a36Sopenharmony_ci#define RCAR_DRIF_SICTR_RX_EN BIT(8) 11362306a36Sopenharmony_ci#define RCAR_DRIF_SICTR_RESET BIT(0) 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* Constants */ 11662306a36Sopenharmony_ci#define RCAR_DRIF_NUM_HWBUFS 32 11762306a36Sopenharmony_ci#define RCAR_DRIF_MAX_DEVS 4 11862306a36Sopenharmony_ci#define RCAR_DRIF_DEFAULT_NUM_HWBUFS 16 11962306a36Sopenharmony_ci#define RCAR_DRIF_DEFAULT_HWBUF_SIZE (4 * PAGE_SIZE) 12062306a36Sopenharmony_ci#define RCAR_DRIF_MAX_CHANNEL 2 12162306a36Sopenharmony_ci#define RCAR_SDR_BUFFER_SIZE SZ_64K 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Internal buffer status flags */ 12462306a36Sopenharmony_ci#define RCAR_DRIF_BUF_DONE BIT(0) /* DMA completed */ 12562306a36Sopenharmony_ci#define RCAR_DRIF_BUF_OVERFLOW BIT(1) /* Overflow detected */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define to_rcar_drif_buf_pair(sdr, ch_num, idx) \ 12862306a36Sopenharmony_ci (&((sdr)->ch[!(ch_num)]->buf[(idx)])) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define for_each_rcar_drif_channel(ch, ch_mask) \ 13162306a36Sopenharmony_ci for_each_set_bit(ch, ch_mask, RCAR_DRIF_MAX_CHANNEL) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Debug */ 13462306a36Sopenharmony_ci#define rdrif_dbg(sdr, fmt, arg...) \ 13562306a36Sopenharmony_ci dev_dbg(sdr->v4l2_dev.dev, fmt, ## arg) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci#define rdrif_err(sdr, fmt, arg...) \ 13862306a36Sopenharmony_ci dev_err(sdr->v4l2_dev.dev, fmt, ## arg) 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* Stream formats */ 14162306a36Sopenharmony_cistruct rcar_drif_format { 14262306a36Sopenharmony_ci u32 pixelformat; 14362306a36Sopenharmony_ci u32 buffersize; 14462306a36Sopenharmony_ci u32 bitlen; 14562306a36Sopenharmony_ci u32 wdcnt; 14662306a36Sopenharmony_ci u32 num_ch; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Format descriptions for capture */ 15062306a36Sopenharmony_cistatic const struct rcar_drif_format formats[] = { 15162306a36Sopenharmony_ci { 15262306a36Sopenharmony_ci .pixelformat = V4L2_SDR_FMT_PCU16BE, 15362306a36Sopenharmony_ci .buffersize = RCAR_SDR_BUFFER_SIZE, 15462306a36Sopenharmony_ci .bitlen = 16, 15562306a36Sopenharmony_ci .wdcnt = 1, 15662306a36Sopenharmony_ci .num_ch = 2, 15762306a36Sopenharmony_ci }, 15862306a36Sopenharmony_ci { 15962306a36Sopenharmony_ci .pixelformat = V4L2_SDR_FMT_PCU18BE, 16062306a36Sopenharmony_ci .buffersize = RCAR_SDR_BUFFER_SIZE, 16162306a36Sopenharmony_ci .bitlen = 18, 16262306a36Sopenharmony_ci .wdcnt = 1, 16362306a36Sopenharmony_ci .num_ch = 2, 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci { 16662306a36Sopenharmony_ci .pixelformat = V4L2_SDR_FMT_PCU20BE, 16762306a36Sopenharmony_ci .buffersize = RCAR_SDR_BUFFER_SIZE, 16862306a36Sopenharmony_ci .bitlen = 20, 16962306a36Sopenharmony_ci .wdcnt = 1, 17062306a36Sopenharmony_ci .num_ch = 2, 17162306a36Sopenharmony_ci }, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* Buffer for a received frame from one or both internal channels */ 17562306a36Sopenharmony_cistruct rcar_drif_frame_buf { 17662306a36Sopenharmony_ci /* Common v4l buffer stuff -- must be first */ 17762306a36Sopenharmony_ci struct vb2_v4l2_buffer vb; 17862306a36Sopenharmony_ci struct list_head list; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* OF graph endpoint's V4L2 async data */ 18262306a36Sopenharmony_cistruct rcar_drif_graph_ep { 18362306a36Sopenharmony_ci struct v4l2_subdev *subdev; /* Async matched subdev */ 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* DMA buffer */ 18762306a36Sopenharmony_cistruct rcar_drif_hwbuf { 18862306a36Sopenharmony_ci void *addr; /* CPU-side address */ 18962306a36Sopenharmony_ci unsigned int status; /* Buffer status flags */ 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* Internal channel */ 19362306a36Sopenharmony_cistruct rcar_drif { 19462306a36Sopenharmony_ci struct rcar_drif_sdr *sdr; /* Group device */ 19562306a36Sopenharmony_ci struct platform_device *pdev; /* Channel's pdev */ 19662306a36Sopenharmony_ci void __iomem *base; /* Base register address */ 19762306a36Sopenharmony_ci resource_size_t start; /* I/O resource offset */ 19862306a36Sopenharmony_ci struct dma_chan *dmach; /* Reserved DMA channel */ 19962306a36Sopenharmony_ci struct clk *clk; /* Module clock */ 20062306a36Sopenharmony_ci struct rcar_drif_hwbuf buf[RCAR_DRIF_NUM_HWBUFS]; /* H/W bufs */ 20162306a36Sopenharmony_ci dma_addr_t dma_handle; /* Handle for all bufs */ 20262306a36Sopenharmony_ci unsigned int num; /* Channel number */ 20362306a36Sopenharmony_ci bool acting_sdr; /* Channel acting as SDR device */ 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* DRIF V4L2 SDR */ 20762306a36Sopenharmony_cistruct rcar_drif_sdr { 20862306a36Sopenharmony_ci struct device *dev; /* Platform device */ 20962306a36Sopenharmony_ci struct video_device *vdev; /* V4L2 SDR device */ 21062306a36Sopenharmony_ci struct v4l2_device v4l2_dev; /* V4L2 device */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Videobuf2 queue and queued buffers list */ 21362306a36Sopenharmony_ci struct vb2_queue vb_queue; 21462306a36Sopenharmony_ci struct list_head queued_bufs; 21562306a36Sopenharmony_ci spinlock_t queued_bufs_lock; /* Protects queued_bufs */ 21662306a36Sopenharmony_ci spinlock_t dma_lock; /* To serialize DMA cb of channels */ 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci struct mutex v4l2_mutex; /* To serialize ioctls */ 21962306a36Sopenharmony_ci struct mutex vb_queue_mutex; /* To serialize streaming ioctls */ 22062306a36Sopenharmony_ci struct v4l2_ctrl_handler ctrl_hdl; /* SDR control handler */ 22162306a36Sopenharmony_ci struct v4l2_async_notifier notifier; /* For subdev (tuner) */ 22262306a36Sopenharmony_ci struct rcar_drif_graph_ep ep; /* Endpoint V4L2 async data */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Current V4L2 SDR format ptr */ 22562306a36Sopenharmony_ci const struct rcar_drif_format *fmt; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Device tree SYNC properties */ 22862306a36Sopenharmony_ci u32 mdr1; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Internals */ 23162306a36Sopenharmony_ci struct rcar_drif *ch[RCAR_DRIF_MAX_CHANNEL]; /* DRIFx0,1 */ 23262306a36Sopenharmony_ci unsigned long hw_ch_mask; /* Enabled channels per DT */ 23362306a36Sopenharmony_ci unsigned long cur_ch_mask; /* Used channels for an SDR FMT */ 23462306a36Sopenharmony_ci u32 num_hw_ch; /* Num of DT enabled channels */ 23562306a36Sopenharmony_ci u32 num_cur_ch; /* Num of used channels */ 23662306a36Sopenharmony_ci u32 hwbuf_size; /* Each DMA buffer size */ 23762306a36Sopenharmony_ci u32 produced; /* Buffers produced by sdr dev */ 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* Register access functions */ 24162306a36Sopenharmony_cistatic void rcar_drif_write(struct rcar_drif *ch, u32 offset, u32 data) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci writel(data, ch->base + offset); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic u32 rcar_drif_read(struct rcar_drif *ch, u32 offset) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci return readl(ch->base + offset); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* Release DMA channels */ 25262306a36Sopenharmony_cistatic void rcar_drif_release_dmachannels(struct rcar_drif_sdr *sdr) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci unsigned int i; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) 25762306a36Sopenharmony_ci if (sdr->ch[i]->dmach) { 25862306a36Sopenharmony_ci dma_release_channel(sdr->ch[i]->dmach); 25962306a36Sopenharmony_ci sdr->ch[i]->dmach = NULL; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* Allocate DMA channels */ 26462306a36Sopenharmony_cistatic int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct dma_slave_config dma_cfg; 26762306a36Sopenharmony_ci unsigned int i; 26862306a36Sopenharmony_ci int ret; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 27162306a36Sopenharmony_ci struct rcar_drif *ch = sdr->ch[i]; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ch->dmach = dma_request_chan(&ch->pdev->dev, "rx"); 27462306a36Sopenharmony_ci if (IS_ERR(ch->dmach)) { 27562306a36Sopenharmony_ci ret = PTR_ERR(ch->dmach); 27662306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 27762306a36Sopenharmony_ci rdrif_err(sdr, 27862306a36Sopenharmony_ci "ch%u: dma channel req failed: %pe\n", 27962306a36Sopenharmony_ci i, ch->dmach); 28062306a36Sopenharmony_ci ch->dmach = NULL; 28162306a36Sopenharmony_ci goto dmach_error; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Configure slave */ 28562306a36Sopenharmony_ci memset(&dma_cfg, 0, sizeof(dma_cfg)); 28662306a36Sopenharmony_ci dma_cfg.src_addr = (phys_addr_t)(ch->start + RCAR_DRIF_SIRFDR); 28762306a36Sopenharmony_ci dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 28862306a36Sopenharmony_ci ret = dmaengine_slave_config(ch->dmach, &dma_cfg); 28962306a36Sopenharmony_ci if (ret) { 29062306a36Sopenharmony_ci rdrif_err(sdr, "ch%u: dma slave config failed\n", i); 29162306a36Sopenharmony_ci goto dmach_error; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cidmach_error: 29762306a36Sopenharmony_ci rcar_drif_release_dmachannels(sdr); 29862306a36Sopenharmony_ci return ret; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* Release queued vb2 buffers */ 30262306a36Sopenharmony_cistatic void rcar_drif_release_queued_bufs(struct rcar_drif_sdr *sdr, 30362306a36Sopenharmony_ci enum vb2_buffer_state state) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct rcar_drif_frame_buf *fbuf, *tmp; 30662306a36Sopenharmony_ci unsigned long flags; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci spin_lock_irqsave(&sdr->queued_bufs_lock, flags); 30962306a36Sopenharmony_ci list_for_each_entry_safe(fbuf, tmp, &sdr->queued_bufs, list) { 31062306a36Sopenharmony_ci list_del(&fbuf->list); 31162306a36Sopenharmony_ci vb2_buffer_done(&fbuf->vb.vb2_buf, state); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* Set MDR defaults */ 31762306a36Sopenharmony_cistatic inline void rcar_drif_set_mdr1(struct rcar_drif_sdr *sdr) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unsigned int i; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Set defaults for enabled internal channels */ 32262306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 32362306a36Sopenharmony_ci /* Refer MSIOF section in manual for this register setting */ 32462306a36Sopenharmony_ci rcar_drif_write(sdr->ch[i], RCAR_DRIF_SITMDR1, 32562306a36Sopenharmony_ci RCAR_DRIF_SITMDR1_PCON); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* Setup MDR1 value */ 32862306a36Sopenharmony_ci rcar_drif_write(sdr->ch[i], RCAR_DRIF_SIRMDR1, sdr->mdr1); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci rdrif_dbg(sdr, "ch%u: mdr1 = 0x%08x", 33162306a36Sopenharmony_ci i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SIRMDR1)); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* Set DRIF receive format */ 33662306a36Sopenharmony_cistatic int rcar_drif_set_format(struct rcar_drif_sdr *sdr) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci unsigned int i; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci rdrif_dbg(sdr, "setfmt: bitlen %u wdcnt %u num_ch %u\n", 34162306a36Sopenharmony_ci sdr->fmt->bitlen, sdr->fmt->wdcnt, sdr->fmt->num_ch); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Sanity check */ 34462306a36Sopenharmony_ci if (sdr->fmt->num_ch > sdr->num_cur_ch) { 34562306a36Sopenharmony_ci rdrif_err(sdr, "fmt num_ch %u cur_ch %u mismatch\n", 34662306a36Sopenharmony_ci sdr->fmt->num_ch, sdr->num_cur_ch); 34762306a36Sopenharmony_ci return -EINVAL; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Setup group, bitlen & wdcnt */ 35162306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 35262306a36Sopenharmony_ci u32 mdr; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Two groups */ 35562306a36Sopenharmony_ci mdr = RCAR_DRIF_MDR_GRPCNT(2) | 35662306a36Sopenharmony_ci RCAR_DRIF_MDR_BITLEN(sdr->fmt->bitlen) | 35762306a36Sopenharmony_ci RCAR_DRIF_MDR_WDCNT(sdr->fmt->wdcnt); 35862306a36Sopenharmony_ci rcar_drif_write(sdr->ch[i], RCAR_DRIF_SIRMDR2, mdr); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci mdr = RCAR_DRIF_MDR_BITLEN(sdr->fmt->bitlen) | 36162306a36Sopenharmony_ci RCAR_DRIF_MDR_WDCNT(sdr->fmt->wdcnt); 36262306a36Sopenharmony_ci rcar_drif_write(sdr->ch[i], RCAR_DRIF_SIRMDR3, mdr); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci rdrif_dbg(sdr, "ch%u: new mdr[2,3] = 0x%08x, 0x%08x\n", 36562306a36Sopenharmony_ci i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SIRMDR2), 36662306a36Sopenharmony_ci rcar_drif_read(sdr->ch[i], RCAR_DRIF_SIRMDR3)); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* Release DMA buffers */ 37262306a36Sopenharmony_cistatic void rcar_drif_release_buf(struct rcar_drif_sdr *sdr) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci unsigned int i; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 37762306a36Sopenharmony_ci struct rcar_drif *ch = sdr->ch[i]; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* First entry contains the dma buf ptr */ 38062306a36Sopenharmony_ci if (ch->buf[0].addr) { 38162306a36Sopenharmony_ci dma_free_coherent(&ch->pdev->dev, 38262306a36Sopenharmony_ci sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS, 38362306a36Sopenharmony_ci ch->buf[0].addr, ch->dma_handle); 38462306a36Sopenharmony_ci ch->buf[0].addr = NULL; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/* Request DMA buffers */ 39062306a36Sopenharmony_cistatic int rcar_drif_request_buf(struct rcar_drif_sdr *sdr) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int ret = -ENOMEM; 39362306a36Sopenharmony_ci unsigned int i, j; 39462306a36Sopenharmony_ci void *addr; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 39762306a36Sopenharmony_ci struct rcar_drif *ch = sdr->ch[i]; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Allocate DMA buffers */ 40062306a36Sopenharmony_ci addr = dma_alloc_coherent(&ch->pdev->dev, 40162306a36Sopenharmony_ci sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS, 40262306a36Sopenharmony_ci &ch->dma_handle, GFP_KERNEL); 40362306a36Sopenharmony_ci if (!addr) { 40462306a36Sopenharmony_ci rdrif_err(sdr, 40562306a36Sopenharmony_ci "ch%u: dma alloc failed. num hwbufs %u size %u\n", 40662306a36Sopenharmony_ci i, RCAR_DRIF_NUM_HWBUFS, sdr->hwbuf_size); 40762306a36Sopenharmony_ci goto error; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Split the chunk and populate bufctxt */ 41162306a36Sopenharmony_ci for (j = 0; j < RCAR_DRIF_NUM_HWBUFS; j++) { 41262306a36Sopenharmony_ci ch->buf[j].addr = addr + (j * sdr->hwbuf_size); 41362306a36Sopenharmony_ci ch->buf[j].status = 0; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_cierror: 41862306a36Sopenharmony_ci return ret; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/* Setup vb_queue minimum buffer requirements */ 42262306a36Sopenharmony_cistatic int rcar_drif_queue_setup(struct vb2_queue *vq, 42362306a36Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 42462306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Need at least 16 buffers */ 42962306a36Sopenharmony_ci if (vq->num_buffers + *num_buffers < 16) 43062306a36Sopenharmony_ci *num_buffers = 16 - vq->num_buffers; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci *num_planes = 1; 43362306a36Sopenharmony_ci sizes[0] = PAGE_ALIGN(sdr->fmt->buffersize); 43462306a36Sopenharmony_ci rdrif_dbg(sdr, "num_bufs %d sizes[0] %d\n", *num_buffers, sizes[0]); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* Enqueue buffer */ 44062306a36Sopenharmony_cistatic void rcar_drif_buf_queue(struct vb2_buffer *vb) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 44362306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vb->vb2_queue); 44462306a36Sopenharmony_ci struct rcar_drif_frame_buf *fbuf = 44562306a36Sopenharmony_ci container_of(vbuf, struct rcar_drif_frame_buf, vb); 44662306a36Sopenharmony_ci unsigned long flags; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci rdrif_dbg(sdr, "buf_queue idx %u\n", vb->index); 44962306a36Sopenharmony_ci spin_lock_irqsave(&sdr->queued_bufs_lock, flags); 45062306a36Sopenharmony_ci list_add_tail(&fbuf->list, &sdr->queued_bufs); 45162306a36Sopenharmony_ci spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/* Get a frame buf from list */ 45562306a36Sopenharmony_cistatic struct rcar_drif_frame_buf * 45662306a36Sopenharmony_circar_drif_get_fbuf(struct rcar_drif_sdr *sdr) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct rcar_drif_frame_buf *fbuf; 45962306a36Sopenharmony_ci unsigned long flags; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci spin_lock_irqsave(&sdr->queued_bufs_lock, flags); 46262306a36Sopenharmony_ci fbuf = list_first_entry_or_null(&sdr->queued_bufs, struct 46362306a36Sopenharmony_ci rcar_drif_frame_buf, list); 46462306a36Sopenharmony_ci if (!fbuf) { 46562306a36Sopenharmony_ci /* 46662306a36Sopenharmony_ci * App is late in enqueing buffers. Samples lost & there will 46762306a36Sopenharmony_ci * be a gap in sequence number when app recovers 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_ci rdrif_dbg(sdr, "\napp late: prod %u\n", sdr->produced); 47062306a36Sopenharmony_ci spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 47162306a36Sopenharmony_ci return NULL; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci list_del(&fbuf->list); 47462306a36Sopenharmony_ci spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return fbuf; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/* Helpers to set/clear buf pair status */ 48062306a36Sopenharmony_cistatic inline bool rcar_drif_bufs_done(struct rcar_drif_hwbuf **buf) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci return (buf[0]->status & buf[1]->status & RCAR_DRIF_BUF_DONE); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic inline bool rcar_drif_bufs_overflow(struct rcar_drif_hwbuf **buf) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci return ((buf[0]->status | buf[1]->status) & RCAR_DRIF_BUF_OVERFLOW); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic inline void rcar_drif_bufs_clear(struct rcar_drif_hwbuf **buf, 49162306a36Sopenharmony_ci unsigned int bit) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci unsigned int i; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci for (i = 0; i < RCAR_DRIF_MAX_CHANNEL; i++) 49662306a36Sopenharmony_ci buf[i]->status &= ~bit; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci/* Channel DMA complete */ 50062306a36Sopenharmony_cistatic void rcar_drif_channel_complete(struct rcar_drif *ch, u32 idx) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci u32 str; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci ch->buf[idx].status |= RCAR_DRIF_BUF_DONE; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Check for DRIF errors */ 50762306a36Sopenharmony_ci str = rcar_drif_read(ch, RCAR_DRIF_SISTR); 50862306a36Sopenharmony_ci if (unlikely(str & RCAR_DRIF_RFOVF)) { 50962306a36Sopenharmony_ci /* Writing the same clears it */ 51062306a36Sopenharmony_ci rcar_drif_write(ch, RCAR_DRIF_SISTR, str); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* Overflow: some samples are lost */ 51362306a36Sopenharmony_ci ch->buf[idx].status |= RCAR_DRIF_BUF_OVERFLOW; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* DMA callback for each stage */ 51862306a36Sopenharmony_cistatic void rcar_drif_dma_complete(void *dma_async_param) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct rcar_drif *ch = dma_async_param; 52162306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = ch->sdr; 52262306a36Sopenharmony_ci struct rcar_drif_hwbuf *buf[RCAR_DRIF_MAX_CHANNEL]; 52362306a36Sopenharmony_ci struct rcar_drif_frame_buf *fbuf; 52462306a36Sopenharmony_ci bool overflow = false; 52562306a36Sopenharmony_ci u32 idx, produced; 52662306a36Sopenharmony_ci unsigned int i; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci spin_lock(&sdr->dma_lock); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* DMA can be terminated while the callback was waiting on lock */ 53162306a36Sopenharmony_ci if (!vb2_is_streaming(&sdr->vb_queue)) { 53262306a36Sopenharmony_ci spin_unlock(&sdr->dma_lock); 53362306a36Sopenharmony_ci return; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci idx = sdr->produced % RCAR_DRIF_NUM_HWBUFS; 53762306a36Sopenharmony_ci rcar_drif_channel_complete(ch, idx); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (sdr->num_cur_ch == RCAR_DRIF_MAX_CHANNEL) { 54062306a36Sopenharmony_ci buf[0] = ch->num ? to_rcar_drif_buf_pair(sdr, ch->num, idx) : 54162306a36Sopenharmony_ci &ch->buf[idx]; 54262306a36Sopenharmony_ci buf[1] = ch->num ? &ch->buf[idx] : 54362306a36Sopenharmony_ci to_rcar_drif_buf_pair(sdr, ch->num, idx); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* Check if both DMA buffers are done */ 54662306a36Sopenharmony_ci if (!rcar_drif_bufs_done(buf)) { 54762306a36Sopenharmony_ci spin_unlock(&sdr->dma_lock); 54862306a36Sopenharmony_ci return; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Clear buf done status */ 55262306a36Sopenharmony_ci rcar_drif_bufs_clear(buf, RCAR_DRIF_BUF_DONE); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (rcar_drif_bufs_overflow(buf)) { 55562306a36Sopenharmony_ci overflow = true; 55662306a36Sopenharmony_ci /* Clear the flag in status */ 55762306a36Sopenharmony_ci rcar_drif_bufs_clear(buf, RCAR_DRIF_BUF_OVERFLOW); 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci } else { 56062306a36Sopenharmony_ci buf[0] = &ch->buf[idx]; 56162306a36Sopenharmony_ci if (buf[0]->status & RCAR_DRIF_BUF_OVERFLOW) { 56262306a36Sopenharmony_ci overflow = true; 56362306a36Sopenharmony_ci /* Clear the flag in status */ 56462306a36Sopenharmony_ci buf[0]->status &= ~RCAR_DRIF_BUF_OVERFLOW; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Buffer produced for consumption */ 56962306a36Sopenharmony_ci produced = sdr->produced++; 57062306a36Sopenharmony_ci spin_unlock(&sdr->dma_lock); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci rdrif_dbg(sdr, "ch%u: prod %u\n", ch->num, produced); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Get fbuf */ 57562306a36Sopenharmony_ci fbuf = rcar_drif_get_fbuf(sdr); 57662306a36Sopenharmony_ci if (!fbuf) 57762306a36Sopenharmony_ci return; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci for (i = 0; i < RCAR_DRIF_MAX_CHANNEL; i++) 58062306a36Sopenharmony_ci memcpy(vb2_plane_vaddr(&fbuf->vb.vb2_buf, 0) + 58162306a36Sopenharmony_ci i * sdr->hwbuf_size, buf[i]->addr, sdr->hwbuf_size); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci fbuf->vb.field = V4L2_FIELD_NONE; 58462306a36Sopenharmony_ci fbuf->vb.sequence = produced; 58562306a36Sopenharmony_ci fbuf->vb.vb2_buf.timestamp = ktime_get_ns(); 58662306a36Sopenharmony_ci vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, sdr->fmt->buffersize); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Set error state on overflow */ 58962306a36Sopenharmony_ci vb2_buffer_done(&fbuf->vb.vb2_buf, 59062306a36Sopenharmony_ci overflow ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int rcar_drif_qbuf(struct rcar_drif *ch) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = ch->sdr; 59662306a36Sopenharmony_ci dma_addr_t addr = ch->dma_handle; 59762306a36Sopenharmony_ci struct dma_async_tx_descriptor *rxd; 59862306a36Sopenharmony_ci dma_cookie_t cookie; 59962306a36Sopenharmony_ci int ret = -EIO; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Setup cyclic DMA with given buffers */ 60262306a36Sopenharmony_ci rxd = dmaengine_prep_dma_cyclic(ch->dmach, addr, 60362306a36Sopenharmony_ci sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS, 60462306a36Sopenharmony_ci sdr->hwbuf_size, DMA_DEV_TO_MEM, 60562306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 60662306a36Sopenharmony_ci if (!rxd) { 60762306a36Sopenharmony_ci rdrif_err(sdr, "ch%u: prep dma cyclic failed\n", ch->num); 60862306a36Sopenharmony_ci return ret; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* Submit descriptor */ 61262306a36Sopenharmony_ci rxd->callback = rcar_drif_dma_complete; 61362306a36Sopenharmony_ci rxd->callback_param = ch; 61462306a36Sopenharmony_ci cookie = dmaengine_submit(rxd); 61562306a36Sopenharmony_ci if (dma_submit_error(cookie)) { 61662306a36Sopenharmony_ci rdrif_err(sdr, "ch%u: dma submit failed\n", ch->num); 61762306a36Sopenharmony_ci return ret; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci dma_async_issue_pending(ch->dmach); 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/* Enable reception */ 62562306a36Sopenharmony_cistatic int rcar_drif_enable_rx(struct rcar_drif_sdr *sdr) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci unsigned int i; 62862306a36Sopenharmony_ci u32 ctr; 62962306a36Sopenharmony_ci int ret = -EINVAL; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* 63262306a36Sopenharmony_ci * When both internal channels are enabled, they can be synchronized 63362306a36Sopenharmony_ci * only by the master 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* Enable receive */ 63762306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 63862306a36Sopenharmony_ci ctr = rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR); 63962306a36Sopenharmony_ci ctr |= (RCAR_DRIF_SICTR_RX_RISING_EDGE | 64062306a36Sopenharmony_ci RCAR_DRIF_SICTR_RX_EN); 64162306a36Sopenharmony_ci rcar_drif_write(sdr->ch[i], RCAR_DRIF_SICTR, ctr); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Check receive enabled */ 64562306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 64662306a36Sopenharmony_ci ret = readl_poll_timeout(sdr->ch[i]->base + RCAR_DRIF_SICTR, 64762306a36Sopenharmony_ci ctr, ctr & RCAR_DRIF_SICTR_RX_EN, 7, 100000); 64862306a36Sopenharmony_ci if (ret) { 64962306a36Sopenharmony_ci rdrif_err(sdr, "ch%u: rx en failed. ctr 0x%08x\n", i, 65062306a36Sopenharmony_ci rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR)); 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci return ret; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci/* Disable reception */ 65862306a36Sopenharmony_cistatic void rcar_drif_disable_rx(struct rcar_drif_sdr *sdr) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci unsigned int i; 66162306a36Sopenharmony_ci u32 ctr; 66262306a36Sopenharmony_ci int ret; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Disable receive */ 66562306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 66662306a36Sopenharmony_ci ctr = rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR); 66762306a36Sopenharmony_ci ctr &= ~RCAR_DRIF_SICTR_RX_EN; 66862306a36Sopenharmony_ci rcar_drif_write(sdr->ch[i], RCAR_DRIF_SICTR, ctr); 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* Check receive disabled */ 67262306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 67362306a36Sopenharmony_ci ret = readl_poll_timeout(sdr->ch[i]->base + RCAR_DRIF_SICTR, 67462306a36Sopenharmony_ci ctr, !(ctr & RCAR_DRIF_SICTR_RX_EN), 7, 100000); 67562306a36Sopenharmony_ci if (ret) 67662306a36Sopenharmony_ci dev_warn(&sdr->vdev->dev, 67762306a36Sopenharmony_ci "ch%u: failed to disable rx. ctr 0x%08x\n", 67862306a36Sopenharmony_ci i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR)); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci/* Stop channel */ 68362306a36Sopenharmony_cistatic void rcar_drif_stop_channel(struct rcar_drif *ch) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci /* Disable DMA receive interrupt */ 68662306a36Sopenharmony_ci rcar_drif_write(ch, RCAR_DRIF_SIIER, 0x00000000); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Terminate all DMA transfers */ 68962306a36Sopenharmony_ci dmaengine_terminate_sync(ch->dmach); 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci/* Stop receive operation */ 69362306a36Sopenharmony_cistatic void rcar_drif_stop(struct rcar_drif_sdr *sdr) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci unsigned int i; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* Disable Rx */ 69862306a36Sopenharmony_ci rcar_drif_disable_rx(sdr); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) 70162306a36Sopenharmony_ci rcar_drif_stop_channel(sdr->ch[i]); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/* Start channel */ 70562306a36Sopenharmony_cistatic int rcar_drif_start_channel(struct rcar_drif *ch) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = ch->sdr; 70862306a36Sopenharmony_ci u32 ctr, str; 70962306a36Sopenharmony_ci int ret; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* Reset receive */ 71262306a36Sopenharmony_ci rcar_drif_write(ch, RCAR_DRIF_SICTR, RCAR_DRIF_SICTR_RESET); 71362306a36Sopenharmony_ci ret = readl_poll_timeout(ch->base + RCAR_DRIF_SICTR, ctr, 71462306a36Sopenharmony_ci !(ctr & RCAR_DRIF_SICTR_RESET), 7, 100000); 71562306a36Sopenharmony_ci if (ret) { 71662306a36Sopenharmony_ci rdrif_err(sdr, "ch%u: failed to reset rx. ctr 0x%08x\n", 71762306a36Sopenharmony_ci ch->num, rcar_drif_read(ch, RCAR_DRIF_SICTR)); 71862306a36Sopenharmony_ci return ret; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Queue buffers for DMA */ 72262306a36Sopenharmony_ci ret = rcar_drif_qbuf(ch); 72362306a36Sopenharmony_ci if (ret) 72462306a36Sopenharmony_ci return ret; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Clear status register flags */ 72762306a36Sopenharmony_ci str = RCAR_DRIF_RFFUL | RCAR_DRIF_REOF | RCAR_DRIF_RFSERR | 72862306a36Sopenharmony_ci RCAR_DRIF_RFUDF | RCAR_DRIF_RFOVF; 72962306a36Sopenharmony_ci rcar_drif_write(ch, RCAR_DRIF_SISTR, str); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Enable DMA receive interrupt */ 73262306a36Sopenharmony_ci rcar_drif_write(ch, RCAR_DRIF_SIIER, 0x00009000); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return ret; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci/* Start receive operation */ 73862306a36Sopenharmony_cistatic int rcar_drif_start(struct rcar_drif_sdr *sdr) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci unsigned long enabled = 0; 74162306a36Sopenharmony_ci unsigned int i; 74262306a36Sopenharmony_ci int ret; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 74562306a36Sopenharmony_ci ret = rcar_drif_start_channel(sdr->ch[i]); 74662306a36Sopenharmony_ci if (ret) 74762306a36Sopenharmony_ci goto start_error; 74862306a36Sopenharmony_ci enabled |= BIT(i); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci ret = rcar_drif_enable_rx(sdr); 75262306a36Sopenharmony_ci if (ret) 75362306a36Sopenharmony_ci goto enable_error; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci sdr->produced = 0; 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cienable_error: 75962306a36Sopenharmony_ci rcar_drif_disable_rx(sdr); 76062306a36Sopenharmony_cistart_error: 76162306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &enabled) 76262306a36Sopenharmony_ci rcar_drif_stop_channel(sdr->ch[i]); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return ret; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci/* Start streaming */ 76862306a36Sopenharmony_cistatic int rcar_drif_start_streaming(struct vb2_queue *vq, unsigned int count) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); 77162306a36Sopenharmony_ci unsigned long enabled = 0; 77262306a36Sopenharmony_ci unsigned int i; 77362306a36Sopenharmony_ci int ret; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci mutex_lock(&sdr->v4l2_mutex); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 77862306a36Sopenharmony_ci ret = clk_prepare_enable(sdr->ch[i]->clk); 77962306a36Sopenharmony_ci if (ret) 78062306a36Sopenharmony_ci goto error; 78162306a36Sopenharmony_ci enabled |= BIT(i); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* Set default MDRx settings */ 78562306a36Sopenharmony_ci rcar_drif_set_mdr1(sdr); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* Set new format */ 78862306a36Sopenharmony_ci ret = rcar_drif_set_format(sdr); 78962306a36Sopenharmony_ci if (ret) 79062306a36Sopenharmony_ci goto error; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (sdr->num_cur_ch == RCAR_DRIF_MAX_CHANNEL) 79362306a36Sopenharmony_ci sdr->hwbuf_size = sdr->fmt->buffersize / RCAR_DRIF_MAX_CHANNEL; 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci sdr->hwbuf_size = sdr->fmt->buffersize; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci rdrif_dbg(sdr, "num hwbufs %u, hwbuf_size %u\n", 79862306a36Sopenharmony_ci RCAR_DRIF_NUM_HWBUFS, sdr->hwbuf_size); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Alloc DMA channel */ 80162306a36Sopenharmony_ci ret = rcar_drif_alloc_dmachannels(sdr); 80262306a36Sopenharmony_ci if (ret) 80362306a36Sopenharmony_ci goto error; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* Request buffers */ 80662306a36Sopenharmony_ci ret = rcar_drif_request_buf(sdr); 80762306a36Sopenharmony_ci if (ret) 80862306a36Sopenharmony_ci goto error; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* Start Rx */ 81162306a36Sopenharmony_ci ret = rcar_drif_start(sdr); 81262306a36Sopenharmony_ci if (ret) 81362306a36Sopenharmony_ci goto error; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci mutex_unlock(&sdr->v4l2_mutex); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return ret; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cierror: 82062306a36Sopenharmony_ci rcar_drif_release_queued_bufs(sdr, VB2_BUF_STATE_QUEUED); 82162306a36Sopenharmony_ci rcar_drif_release_buf(sdr); 82262306a36Sopenharmony_ci rcar_drif_release_dmachannels(sdr); 82362306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &enabled) 82462306a36Sopenharmony_ci clk_disable_unprepare(sdr->ch[i]->clk); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci mutex_unlock(&sdr->v4l2_mutex); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci return ret; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci/* Stop streaming */ 83262306a36Sopenharmony_cistatic void rcar_drif_stop_streaming(struct vb2_queue *vq) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); 83562306a36Sopenharmony_ci unsigned int i; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci mutex_lock(&sdr->v4l2_mutex); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* Stop hardware streaming */ 84062306a36Sopenharmony_ci rcar_drif_stop(sdr); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* Return all queued buffers to vb2 */ 84362306a36Sopenharmony_ci rcar_drif_release_queued_bufs(sdr, VB2_BUF_STATE_ERROR); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Release buf */ 84662306a36Sopenharmony_ci rcar_drif_release_buf(sdr); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Release DMA channel resources */ 84962306a36Sopenharmony_ci rcar_drif_release_dmachannels(sdr); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) 85262306a36Sopenharmony_ci clk_disable_unprepare(sdr->ch[i]->clk); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci mutex_unlock(&sdr->v4l2_mutex); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci/* Vb2 ops */ 85862306a36Sopenharmony_cistatic const struct vb2_ops rcar_drif_vb2_ops = { 85962306a36Sopenharmony_ci .queue_setup = rcar_drif_queue_setup, 86062306a36Sopenharmony_ci .buf_queue = rcar_drif_buf_queue, 86162306a36Sopenharmony_ci .start_streaming = rcar_drif_start_streaming, 86262306a36Sopenharmony_ci .stop_streaming = rcar_drif_stop_streaming, 86362306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 86462306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 86562306a36Sopenharmony_ci}; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int rcar_drif_querycap(struct file *file, void *fh, 86862306a36Sopenharmony_ci struct v4l2_capability *cap) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); 87362306a36Sopenharmony_ci strscpy(cap->card, sdr->vdev->name, sizeof(cap->card)); 87462306a36Sopenharmony_ci snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", 87562306a36Sopenharmony_ci sdr->vdev->name); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int rcar_drif_set_default_format(struct rcar_drif_sdr *sdr) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci unsigned int i; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(formats); i++) { 88562306a36Sopenharmony_ci /* Matching fmt based on required channels is set as default */ 88662306a36Sopenharmony_ci if (sdr->num_hw_ch == formats[i].num_ch) { 88762306a36Sopenharmony_ci sdr->fmt = &formats[i]; 88862306a36Sopenharmony_ci sdr->cur_ch_mask = sdr->hw_ch_mask; 88962306a36Sopenharmony_ci sdr->num_cur_ch = sdr->num_hw_ch; 89062306a36Sopenharmony_ci dev_dbg(sdr->dev, "default fmt[%u]: mask %lu num %u\n", 89162306a36Sopenharmony_ci i, sdr->cur_ch_mask, sdr->num_cur_ch); 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci return -EINVAL; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int rcar_drif_enum_fmt_sdr_cap(struct file *file, void *priv, 89962306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci if (f->index >= ARRAY_SIZE(formats)) 90262306a36Sopenharmony_ci return -EINVAL; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci f->pixelformat = formats[f->index].pixelformat; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci return 0; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv, 91062306a36Sopenharmony_ci struct v4l2_format *f) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci f->fmt.sdr.pixelformat = sdr->fmt->pixelformat; 91562306a36Sopenharmony_ci f->fmt.sdr.buffersize = sdr->fmt->buffersize; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return 0; 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic int rcar_drif_s_fmt_sdr_cap(struct file *file, void *priv, 92162306a36Sopenharmony_ci struct v4l2_format *f) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 92462306a36Sopenharmony_ci struct vb2_queue *q = &sdr->vb_queue; 92562306a36Sopenharmony_ci unsigned int i; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (vb2_is_busy(q)) 92862306a36Sopenharmony_ci return -EBUSY; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(formats); i++) { 93162306a36Sopenharmony_ci if (formats[i].pixelformat == f->fmt.sdr.pixelformat) 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (i == ARRAY_SIZE(formats)) 93662306a36Sopenharmony_ci i = 0; /* Set the 1st format as default on no match */ 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci sdr->fmt = &formats[i]; 93962306a36Sopenharmony_ci f->fmt.sdr.pixelformat = sdr->fmt->pixelformat; 94062306a36Sopenharmony_ci f->fmt.sdr.buffersize = formats[i].buffersize; 94162306a36Sopenharmony_ci memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * If a format demands one channel only out of two 94562306a36Sopenharmony_ci * enabled channels, pick the 0th channel. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ci if (formats[i].num_ch < sdr->num_hw_ch) { 94862306a36Sopenharmony_ci sdr->cur_ch_mask = BIT(0); 94962306a36Sopenharmony_ci sdr->num_cur_ch = formats[i].num_ch; 95062306a36Sopenharmony_ci } else { 95162306a36Sopenharmony_ci sdr->cur_ch_mask = sdr->hw_ch_mask; 95262306a36Sopenharmony_ci sdr->num_cur_ch = sdr->num_hw_ch; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci rdrif_dbg(sdr, "cur: idx %u mask %lu num %u\n", 95662306a36Sopenharmony_ci i, sdr->cur_ch_mask, sdr->num_cur_ch); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int rcar_drif_try_fmt_sdr_cap(struct file *file, void *priv, 96262306a36Sopenharmony_ci struct v4l2_format *f) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci unsigned int i; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(formats); i++) { 96762306a36Sopenharmony_ci if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { 96862306a36Sopenharmony_ci f->fmt.sdr.buffersize = formats[i].buffersize; 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci f->fmt.sdr.pixelformat = formats[0].pixelformat; 97462306a36Sopenharmony_ci f->fmt.sdr.buffersize = formats[0].buffersize; 97562306a36Sopenharmony_ci memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return 0; 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci/* Tuner subdev ioctls */ 98162306a36Sopenharmony_cistatic int rcar_drif_enum_freq_bands(struct file *file, void *priv, 98262306a36Sopenharmony_ci struct v4l2_frequency_band *band) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci return v4l2_subdev_call(sdr->ep.subdev, tuner, enum_freq_bands, band); 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic int rcar_drif_g_frequency(struct file *file, void *priv, 99062306a36Sopenharmony_ci struct v4l2_frequency *f) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci return v4l2_subdev_call(sdr->ep.subdev, tuner, g_frequency, f); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic int rcar_drif_s_frequency(struct file *file, void *priv, 99862306a36Sopenharmony_ci const struct v4l2_frequency *f) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci return v4l2_subdev_call(sdr->ep.subdev, tuner, s_frequency, f); 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int rcar_drif_g_tuner(struct file *file, void *priv, 100662306a36Sopenharmony_ci struct v4l2_tuner *vt) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return v4l2_subdev_call(sdr->ep.subdev, tuner, g_tuner, vt); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int rcar_drif_s_tuner(struct file *file, void *priv, 101462306a36Sopenharmony_ci const struct v4l2_tuner *vt) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = video_drvdata(file); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci return v4l2_subdev_call(sdr->ep.subdev, tuner, s_tuner, vt); 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops rcar_drif_ioctl_ops = { 102262306a36Sopenharmony_ci .vidioc_querycap = rcar_drif_querycap, 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci .vidioc_enum_fmt_sdr_cap = rcar_drif_enum_fmt_sdr_cap, 102562306a36Sopenharmony_ci .vidioc_g_fmt_sdr_cap = rcar_drif_g_fmt_sdr_cap, 102662306a36Sopenharmony_ci .vidioc_s_fmt_sdr_cap = rcar_drif_s_fmt_sdr_cap, 102762306a36Sopenharmony_ci .vidioc_try_fmt_sdr_cap = rcar_drif_try_fmt_sdr_cap, 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 103062306a36Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 103162306a36Sopenharmony_ci .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 103262306a36Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 103362306a36Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 103462306a36Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 103762306a36Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci .vidioc_s_frequency = rcar_drif_s_frequency, 104062306a36Sopenharmony_ci .vidioc_g_frequency = rcar_drif_g_frequency, 104162306a36Sopenharmony_ci .vidioc_s_tuner = rcar_drif_s_tuner, 104262306a36Sopenharmony_ci .vidioc_g_tuner = rcar_drif_g_tuner, 104362306a36Sopenharmony_ci .vidioc_enum_freq_bands = rcar_drif_enum_freq_bands, 104462306a36Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 104562306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 104662306a36Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 104762306a36Sopenharmony_ci}; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic const struct v4l2_file_operations rcar_drif_fops = { 105062306a36Sopenharmony_ci .owner = THIS_MODULE, 105162306a36Sopenharmony_ci .open = v4l2_fh_open, 105262306a36Sopenharmony_ci .release = vb2_fop_release, 105362306a36Sopenharmony_ci .read = vb2_fop_read, 105462306a36Sopenharmony_ci .poll = vb2_fop_poll, 105562306a36Sopenharmony_ci .mmap = vb2_fop_mmap, 105662306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 105762306a36Sopenharmony_ci}; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci int ret; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* Init video_device structure */ 106462306a36Sopenharmony_ci sdr->vdev = video_device_alloc(); 106562306a36Sopenharmony_ci if (!sdr->vdev) 106662306a36Sopenharmony_ci return -ENOMEM; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci snprintf(sdr->vdev->name, sizeof(sdr->vdev->name), "R-Car DRIF"); 106962306a36Sopenharmony_ci sdr->vdev->fops = &rcar_drif_fops; 107062306a36Sopenharmony_ci sdr->vdev->ioctl_ops = &rcar_drif_ioctl_ops; 107162306a36Sopenharmony_ci sdr->vdev->release = video_device_release; 107262306a36Sopenharmony_ci sdr->vdev->lock = &sdr->v4l2_mutex; 107362306a36Sopenharmony_ci sdr->vdev->queue = &sdr->vb_queue; 107462306a36Sopenharmony_ci sdr->vdev->queue->lock = &sdr->vb_queue_mutex; 107562306a36Sopenharmony_ci sdr->vdev->ctrl_handler = &sdr->ctrl_hdl; 107662306a36Sopenharmony_ci sdr->vdev->v4l2_dev = &sdr->v4l2_dev; 107762306a36Sopenharmony_ci sdr->vdev->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER | 107862306a36Sopenharmony_ci V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; 107962306a36Sopenharmony_ci video_set_drvdata(sdr->vdev, sdr); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* Register V4L2 SDR device */ 108262306a36Sopenharmony_ci ret = video_register_device(sdr->vdev, VFL_TYPE_SDR, -1); 108362306a36Sopenharmony_ci if (ret) { 108462306a36Sopenharmony_ci video_device_release(sdr->vdev); 108562306a36Sopenharmony_ci sdr->vdev = NULL; 108662306a36Sopenharmony_ci dev_err(sdr->dev, "failed video_register_device (%d)\n", ret); 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci return ret; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic void rcar_drif_sdr_unregister(struct rcar_drif_sdr *sdr) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci video_unregister_device(sdr->vdev); 109562306a36Sopenharmony_ci sdr->vdev = NULL; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci/* Sub-device bound callback */ 109962306a36Sopenharmony_cistatic int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier, 110062306a36Sopenharmony_ci struct v4l2_subdev *subdev, 110162306a36Sopenharmony_ci struct v4l2_async_connection *asd) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = 110462306a36Sopenharmony_ci container_of(notifier, struct rcar_drif_sdr, notifier); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci v4l2_set_subdev_hostdata(subdev, sdr); 110762306a36Sopenharmony_ci sdr->ep.subdev = subdev; 110862306a36Sopenharmony_ci rdrif_dbg(sdr, "bound asd %s\n", subdev->name); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return 0; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci/* Sub-device unbind callback */ 111462306a36Sopenharmony_cistatic void rcar_drif_notify_unbind(struct v4l2_async_notifier *notifier, 111562306a36Sopenharmony_ci struct v4l2_subdev *subdev, 111662306a36Sopenharmony_ci struct v4l2_async_connection *asd) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = 111962306a36Sopenharmony_ci container_of(notifier, struct rcar_drif_sdr, notifier); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (sdr->ep.subdev != subdev) { 112262306a36Sopenharmony_ci rdrif_err(sdr, "subdev %s is not bound\n", subdev->name); 112362306a36Sopenharmony_ci return; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci /* Free ctrl handler if initialized */ 112762306a36Sopenharmony_ci v4l2_ctrl_handler_free(&sdr->ctrl_hdl); 112862306a36Sopenharmony_ci sdr->v4l2_dev.ctrl_handler = NULL; 112962306a36Sopenharmony_ci sdr->ep.subdev = NULL; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci rcar_drif_sdr_unregister(sdr); 113262306a36Sopenharmony_ci rdrif_dbg(sdr, "unbind asd %s\n", subdev->name); 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci/* Sub-device registered notification callback */ 113662306a36Sopenharmony_cistatic int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = 113962306a36Sopenharmony_ci container_of(notifier, struct rcar_drif_sdr, notifier); 114062306a36Sopenharmony_ci int ret; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* 114362306a36Sopenharmony_ci * The subdev tested at this point uses 4 controls. Using 10 as a worst 114462306a36Sopenharmony_ci * case scenario hint. When less controls are needed there will be some 114562306a36Sopenharmony_ci * unused memory and when more controls are needed the framework uses 114662306a36Sopenharmony_ci * hash to manage controls within this number. 114762306a36Sopenharmony_ci */ 114862306a36Sopenharmony_ci ret = v4l2_ctrl_handler_init(&sdr->ctrl_hdl, 10); 114962306a36Sopenharmony_ci if (ret) 115062306a36Sopenharmony_ci return -ENOMEM; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci sdr->v4l2_dev.ctrl_handler = &sdr->ctrl_hdl; 115362306a36Sopenharmony_ci ret = v4l2_device_register_subdev_nodes(&sdr->v4l2_dev); 115462306a36Sopenharmony_ci if (ret) { 115562306a36Sopenharmony_ci rdrif_err(sdr, "failed: register subdev nodes ret %d\n", ret); 115662306a36Sopenharmony_ci goto error; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci ret = v4l2_ctrl_add_handler(&sdr->ctrl_hdl, 116062306a36Sopenharmony_ci sdr->ep.subdev->ctrl_handler, NULL, true); 116162306a36Sopenharmony_ci if (ret) { 116262306a36Sopenharmony_ci rdrif_err(sdr, "failed: ctrl add hdlr ret %d\n", ret); 116362306a36Sopenharmony_ci goto error; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci ret = rcar_drif_sdr_register(sdr); 116762306a36Sopenharmony_ci if (ret) 116862306a36Sopenharmony_ci goto error; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci return ret; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cierror: 117362306a36Sopenharmony_ci v4l2_ctrl_handler_free(&sdr->ctrl_hdl); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci return ret; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations rcar_drif_notify_ops = { 117962306a36Sopenharmony_ci .bound = rcar_drif_notify_bound, 118062306a36Sopenharmony_ci .unbind = rcar_drif_notify_unbind, 118162306a36Sopenharmony_ci .complete = rcar_drif_notify_complete, 118262306a36Sopenharmony_ci}; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci/* Read endpoint properties */ 118562306a36Sopenharmony_cistatic void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr, 118662306a36Sopenharmony_ci struct fwnode_handle *fwnode) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci u32 val; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* Set the I2S defaults for SIRMDR1*/ 119162306a36Sopenharmony_ci sdr->mdr1 = RCAR_DRIF_SIRMDR1_SYNCMD_LR | RCAR_DRIF_SIRMDR1_MSB_FIRST | 119262306a36Sopenharmony_ci RCAR_DRIF_SIRMDR1_DTDL_1 | RCAR_DRIF_SIRMDR1_SYNCDL_0; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* Parse sync polarity from endpoint */ 119562306a36Sopenharmony_ci if (!fwnode_property_read_u32(fwnode, "sync-active", &val)) 119662306a36Sopenharmony_ci sdr->mdr1 |= val ? RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH : 119762306a36Sopenharmony_ci RCAR_DRIF_SIRMDR1_SYNCAC_POL_LOW; 119862306a36Sopenharmony_ci else 119962306a36Sopenharmony_ci sdr->mdr1 |= RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH; /* default */ 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci dev_dbg(sdr->dev, "mdr1 0x%08x\n", sdr->mdr1); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci/* Parse sub-devs (tuner) to find a matching device */ 120562306a36Sopenharmony_cistatic int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct v4l2_async_notifier *notifier = &sdr->notifier; 120862306a36Sopenharmony_ci struct fwnode_handle *fwnode, *ep; 120962306a36Sopenharmony_ci struct v4l2_async_connection *asd; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci v4l2_async_nf_init(&sdr->notifier, &sdr->v4l2_dev); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(sdr->dev->of_node), 121462306a36Sopenharmony_ci NULL); 121562306a36Sopenharmony_ci if (!ep) 121662306a36Sopenharmony_ci return 0; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci /* Get the endpoint properties */ 121962306a36Sopenharmony_ci rcar_drif_get_ep_properties(sdr, ep); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci fwnode = fwnode_graph_get_remote_port_parent(ep); 122262306a36Sopenharmony_ci fwnode_handle_put(ep); 122362306a36Sopenharmony_ci if (!fwnode) { 122462306a36Sopenharmony_ci dev_warn(sdr->dev, "bad remote port parent\n"); 122562306a36Sopenharmony_ci return -EINVAL; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci asd = v4l2_async_nf_add_fwnode(notifier, fwnode, 122962306a36Sopenharmony_ci struct v4l2_async_connection); 123062306a36Sopenharmony_ci fwnode_handle_put(fwnode); 123162306a36Sopenharmony_ci if (IS_ERR(asd)) 123262306a36Sopenharmony_ci return PTR_ERR(asd); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci/* Check if the given device is the primary bond */ 123862306a36Sopenharmony_cistatic bool rcar_drif_primary_bond(struct platform_device *pdev) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci return of_property_read_bool(pdev->dev.of_node, "renesas,primary-bond"); 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci/* Check if both devices of the bond are enabled */ 124462306a36Sopenharmony_cistatic struct device_node *rcar_drif_bond_enabled(struct platform_device *p) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct device_node *np; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci np = of_parse_phandle(p->dev.of_node, "renesas,bonding", 0); 124962306a36Sopenharmony_ci if (np && of_device_is_available(np)) 125062306a36Sopenharmony_ci return np; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return NULL; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci/* Check if the bonded device is probed */ 125662306a36Sopenharmony_cistatic int rcar_drif_bond_available(struct rcar_drif_sdr *sdr, 125762306a36Sopenharmony_ci struct device_node *np) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci struct platform_device *pdev; 126062306a36Sopenharmony_ci struct rcar_drif *ch; 126162306a36Sopenharmony_ci int ret = 0; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci pdev = of_find_device_by_node(np); 126462306a36Sopenharmony_ci if (!pdev) { 126562306a36Sopenharmony_ci dev_err(sdr->dev, "failed to get bonded device from node\n"); 126662306a36Sopenharmony_ci return -ENODEV; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci device_lock(&pdev->dev); 127062306a36Sopenharmony_ci ch = platform_get_drvdata(pdev); 127162306a36Sopenharmony_ci if (ch) { 127262306a36Sopenharmony_ci /* Update sdr data in the bonded device */ 127362306a36Sopenharmony_ci ch->sdr = sdr; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* Update sdr with bonded device data */ 127662306a36Sopenharmony_ci sdr->ch[ch->num] = ch; 127762306a36Sopenharmony_ci sdr->hw_ch_mask |= BIT(ch->num); 127862306a36Sopenharmony_ci } else { 127962306a36Sopenharmony_ci /* Defer */ 128062306a36Sopenharmony_ci dev_info(sdr->dev, "defer probe\n"); 128162306a36Sopenharmony_ci ret = -EPROBE_DEFER; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci device_unlock(&pdev->dev); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci put_device(&pdev->dev); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci return ret; 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci/* V4L2 SDR device probe */ 129162306a36Sopenharmony_cistatic int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci int ret; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* Validate any supported format for enabled channels */ 129662306a36Sopenharmony_ci ret = rcar_drif_set_default_format(sdr); 129762306a36Sopenharmony_ci if (ret) { 129862306a36Sopenharmony_ci dev_err(sdr->dev, "failed to set default format\n"); 129962306a36Sopenharmony_ci return ret; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* Set defaults */ 130362306a36Sopenharmony_ci sdr->hwbuf_size = RCAR_DRIF_DEFAULT_HWBUF_SIZE; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci mutex_init(&sdr->v4l2_mutex); 130662306a36Sopenharmony_ci mutex_init(&sdr->vb_queue_mutex); 130762306a36Sopenharmony_ci spin_lock_init(&sdr->queued_bufs_lock); 130862306a36Sopenharmony_ci spin_lock_init(&sdr->dma_lock); 130962306a36Sopenharmony_ci INIT_LIST_HEAD(&sdr->queued_bufs); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci /* Init videobuf2 queue structure */ 131262306a36Sopenharmony_ci sdr->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; 131362306a36Sopenharmony_ci sdr->vb_queue.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; 131462306a36Sopenharmony_ci sdr->vb_queue.drv_priv = sdr; 131562306a36Sopenharmony_ci sdr->vb_queue.buf_struct_size = sizeof(struct rcar_drif_frame_buf); 131662306a36Sopenharmony_ci sdr->vb_queue.ops = &rcar_drif_vb2_ops; 131762306a36Sopenharmony_ci sdr->vb_queue.mem_ops = &vb2_vmalloc_memops; 131862306a36Sopenharmony_ci sdr->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* Init videobuf2 queue */ 132162306a36Sopenharmony_ci ret = vb2_queue_init(&sdr->vb_queue); 132262306a36Sopenharmony_ci if (ret) { 132362306a36Sopenharmony_ci dev_err(sdr->dev, "failed: vb2_queue_init ret %d\n", ret); 132462306a36Sopenharmony_ci return ret; 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* Register the v4l2_device */ 132862306a36Sopenharmony_ci ret = v4l2_device_register(sdr->dev, &sdr->v4l2_dev); 132962306a36Sopenharmony_ci if (ret) { 133062306a36Sopenharmony_ci dev_err(sdr->dev, "failed: v4l2_device_register ret %d\n", ret); 133162306a36Sopenharmony_ci return ret; 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* 133562306a36Sopenharmony_ci * Parse subdevs after v4l2_device_register because if the subdev 133662306a36Sopenharmony_ci * is already probed, bound and complete will be called immediately 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci ret = rcar_drif_parse_subdevs(sdr); 133962306a36Sopenharmony_ci if (ret) 134062306a36Sopenharmony_ci goto error; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci sdr->notifier.ops = &rcar_drif_notify_ops; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* Register notifier */ 134562306a36Sopenharmony_ci ret = v4l2_async_nf_register(&sdr->notifier); 134662306a36Sopenharmony_ci if (ret < 0) { 134762306a36Sopenharmony_ci dev_err(sdr->dev, "failed: notifier register ret %d\n", ret); 134862306a36Sopenharmony_ci goto cleanup; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return ret; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cicleanup: 135462306a36Sopenharmony_ci v4l2_async_nf_cleanup(&sdr->notifier); 135562306a36Sopenharmony_cierror: 135662306a36Sopenharmony_ci v4l2_device_unregister(&sdr->v4l2_dev); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci return ret; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci/* V4L2 SDR device remove */ 136262306a36Sopenharmony_cistatic void rcar_drif_sdr_remove(struct rcar_drif_sdr *sdr) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci v4l2_async_nf_unregister(&sdr->notifier); 136562306a36Sopenharmony_ci v4l2_async_nf_cleanup(&sdr->notifier); 136662306a36Sopenharmony_ci v4l2_device_unregister(&sdr->v4l2_dev); 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci/* DRIF channel probe */ 137062306a36Sopenharmony_cistatic int rcar_drif_probe(struct platform_device *pdev) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct rcar_drif_sdr *sdr; 137362306a36Sopenharmony_ci struct device_node *np; 137462306a36Sopenharmony_ci struct rcar_drif *ch; 137562306a36Sopenharmony_ci struct resource *res; 137662306a36Sopenharmony_ci int ret; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* Reserve memory for enabled channel */ 137962306a36Sopenharmony_ci ch = devm_kzalloc(&pdev->dev, sizeof(*ch), GFP_KERNEL); 138062306a36Sopenharmony_ci if (!ch) 138162306a36Sopenharmony_ci return -ENOMEM; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci ch->pdev = pdev; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* Module clock */ 138662306a36Sopenharmony_ci ch->clk = devm_clk_get(&pdev->dev, "fck"); 138762306a36Sopenharmony_ci if (IS_ERR(ch->clk)) { 138862306a36Sopenharmony_ci ret = PTR_ERR(ch->clk); 138962306a36Sopenharmony_ci dev_err(&pdev->dev, "clk get failed (%d)\n", ret); 139062306a36Sopenharmony_ci return ret; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* Register map */ 139462306a36Sopenharmony_ci ch->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 139562306a36Sopenharmony_ci if (IS_ERR(ch->base)) 139662306a36Sopenharmony_ci return PTR_ERR(ch->base); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci ch->start = res->start; 139962306a36Sopenharmony_ci platform_set_drvdata(pdev, ch); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci /* Check if both channels of the bond are enabled */ 140262306a36Sopenharmony_ci np = rcar_drif_bond_enabled(pdev); 140362306a36Sopenharmony_ci if (np) { 140462306a36Sopenharmony_ci /* Check if current channel acting as primary-bond */ 140562306a36Sopenharmony_ci if (!rcar_drif_primary_bond(pdev)) { 140662306a36Sopenharmony_ci ch->num = 1; /* Primary bond is channel 0 always */ 140762306a36Sopenharmony_ci of_node_put(np); 140862306a36Sopenharmony_ci return 0; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* Reserve memory for SDR structure */ 141362306a36Sopenharmony_ci sdr = devm_kzalloc(&pdev->dev, sizeof(*sdr), GFP_KERNEL); 141462306a36Sopenharmony_ci if (!sdr) { 141562306a36Sopenharmony_ci of_node_put(np); 141662306a36Sopenharmony_ci return -ENOMEM; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci ch->sdr = sdr; 141962306a36Sopenharmony_ci sdr->dev = &pdev->dev; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* Establish links between SDR and channel(s) */ 142262306a36Sopenharmony_ci sdr->ch[ch->num] = ch; 142362306a36Sopenharmony_ci sdr->hw_ch_mask = BIT(ch->num); 142462306a36Sopenharmony_ci if (np) { 142562306a36Sopenharmony_ci /* Check if bonded device is ready */ 142662306a36Sopenharmony_ci ret = rcar_drif_bond_available(sdr, np); 142762306a36Sopenharmony_ci of_node_put(np); 142862306a36Sopenharmony_ci if (ret) 142962306a36Sopenharmony_ci return ret; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci sdr->num_hw_ch = hweight_long(sdr->hw_ch_mask); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci return rcar_drif_sdr_probe(sdr); 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci/* DRIF channel remove */ 143762306a36Sopenharmony_cistatic void rcar_drif_remove(struct platform_device *pdev) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci struct rcar_drif *ch = platform_get_drvdata(pdev); 144062306a36Sopenharmony_ci struct rcar_drif_sdr *sdr = ch->sdr; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* Channel 0 will be the SDR instance */ 144362306a36Sopenharmony_ci if (ch->num) 144462306a36Sopenharmony_ci return; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci /* SDR instance */ 144762306a36Sopenharmony_ci rcar_drif_sdr_remove(sdr); 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci/* FIXME: Implement suspend/resume support */ 145162306a36Sopenharmony_cistatic int __maybe_unused rcar_drif_suspend(struct device *dev) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci return 0; 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic int __maybe_unused rcar_drif_resume(struct device *dev) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci return 0; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rcar_drif_pm_ops, rcar_drif_suspend, 146262306a36Sopenharmony_ci rcar_drif_resume); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_cistatic const struct of_device_id rcar_drif_of_table[] = { 146562306a36Sopenharmony_ci { .compatible = "renesas,rcar-gen3-drif" }, 146662306a36Sopenharmony_ci { } 146762306a36Sopenharmony_ci}; 146862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rcar_drif_of_table); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci#define RCAR_DRIF_DRV_NAME "rcar_drif" 147162306a36Sopenharmony_cistatic struct platform_driver rcar_drif_driver = { 147262306a36Sopenharmony_ci .driver = { 147362306a36Sopenharmony_ci .name = RCAR_DRIF_DRV_NAME, 147462306a36Sopenharmony_ci .of_match_table = rcar_drif_of_table, 147562306a36Sopenharmony_ci .pm = &rcar_drif_pm_ops, 147662306a36Sopenharmony_ci }, 147762306a36Sopenharmony_ci .probe = rcar_drif_probe, 147862306a36Sopenharmony_ci .remove_new = rcar_drif_remove, 147962306a36Sopenharmony_ci}; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cimodule_platform_driver(rcar_drif_driver); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas R-Car Gen3 DRIF driver"); 148462306a36Sopenharmony_ciMODULE_ALIAS("platform:" RCAR_DRIF_DRV_NAME); 148562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 148662306a36Sopenharmony_ciMODULE_AUTHOR("Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>"); 1487