1ee4a77a3SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+ 2ee4a77a3SMauro Carvalho Chehab /* 3ee4a77a3SMauro Carvalho Chehab * R-Car Gen3 Digital Radio Interface (DRIF) driver 4ee4a77a3SMauro Carvalho Chehab * 5ee4a77a3SMauro Carvalho Chehab * Copyright (C) 2017 Renesas Electronics Corporation 6ee4a77a3SMauro Carvalho Chehab */ 7ee4a77a3SMauro Carvalho Chehab 8ee4a77a3SMauro Carvalho Chehab /* 9ee4a77a3SMauro Carvalho Chehab * The R-Car DRIF is a receive only MSIOF like controller with an 10ee4a77a3SMauro Carvalho Chehab * external master device driving the SCK. It receives data into a FIFO, 11ee4a77a3SMauro Carvalho Chehab * then this driver uses the SYS-DMAC engine to move the data from 12ee4a77a3SMauro Carvalho Chehab * the device to memory. 13ee4a77a3SMauro Carvalho Chehab * 14ee4a77a3SMauro Carvalho Chehab * Each DRIF channel DRIFx (as per datasheet) contains two internal 15ee4a77a3SMauro Carvalho Chehab * channels DRIFx0 & DRIFx1 within itself with each having its own resources 16ee4a77a3SMauro Carvalho Chehab * like module clk, register set, irq and dma. These internal channels share 17ee4a77a3SMauro Carvalho Chehab * common CLK & SYNC from master. The two data pins D0 & D1 shall be 18ee4a77a3SMauro Carvalho Chehab * considered to represent the two internal channels. This internal split 19ee4a77a3SMauro Carvalho Chehab * is not visible to the master device. 20ee4a77a3SMauro Carvalho Chehab * 21ee4a77a3SMauro Carvalho Chehab * Depending on the master device, a DRIF channel can use 22ee4a77a3SMauro Carvalho Chehab * (1) both internal channels (D0 & D1) to receive data in parallel (or) 23ee4a77a3SMauro Carvalho Chehab * (2) one internal channel (D0 or D1) to receive data 24ee4a77a3SMauro Carvalho Chehab * 25ee4a77a3SMauro Carvalho Chehab * The primary design goal of this controller is to act as a Digital Radio 26ee4a77a3SMauro Carvalho Chehab * Interface that receives digital samples from a tuner device. Hence the 27ee4a77a3SMauro Carvalho Chehab * driver exposes the device as a V4L2 SDR device. In order to qualify as 28ee4a77a3SMauro Carvalho Chehab * a V4L2 SDR device, it should possess a tuner interface as mandated by the 29ee4a77a3SMauro Carvalho Chehab * framework. This driver expects a tuner driver (sub-device) to bind 30ee4a77a3SMauro Carvalho Chehab * asynchronously with this device and the combined drivers shall expose 31ee4a77a3SMauro Carvalho Chehab * a V4L2 compliant SDR device. The DRIF driver is independent of the 32ee4a77a3SMauro Carvalho Chehab * tuner vendor. 33ee4a77a3SMauro Carvalho Chehab * 34ee4a77a3SMauro Carvalho Chehab * The DRIF h/w can support I2S mode and Frame start synchronization pulse mode. 35ee4a77a3SMauro Carvalho Chehab * This driver is tested for I2S mode only because of the availability of 36ee4a77a3SMauro Carvalho Chehab * suitable master devices. Hence, not all configurable options of DRIF h/w 37ee4a77a3SMauro Carvalho Chehab * like lsb/msb first, syncdl, dtdl etc. are exposed via DT and I2S defaults 38ee4a77a3SMauro Carvalho Chehab * are used. These can be exposed later if needed after testing. 39ee4a77a3SMauro Carvalho Chehab */ 40ee4a77a3SMauro Carvalho Chehab #include <linux/bitops.h> 41ee4a77a3SMauro Carvalho Chehab #include <linux/clk.h> 42ee4a77a3SMauro Carvalho Chehab #include <linux/dma-mapping.h> 43ee4a77a3SMauro Carvalho Chehab #include <linux/dmaengine.h> 44ee4a77a3SMauro Carvalho Chehab #include <linux/ioctl.h> 45ee4a77a3SMauro Carvalho Chehab #include <linux/iopoll.h> 46ee4a77a3SMauro Carvalho Chehab #include <linux/module.h> 477c7e33b7SRob Herring #include <linux/of.h> 48ee4a77a3SMauro Carvalho Chehab #include <linux/of_graph.h> 497c7e33b7SRob Herring #include <linux/of_platform.h> 50ee4a77a3SMauro Carvalho Chehab #include <linux/platform_device.h> 51ee4a77a3SMauro Carvalho Chehab #include <linux/sched.h> 52ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-async.h> 53ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 54ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-device.h> 55ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-event.h> 56ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-fh.h> 57ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-ioctl.h> 58ee4a77a3SMauro Carvalho Chehab #include <media/videobuf2-v4l2.h> 59ee4a77a3SMauro Carvalho Chehab #include <media/videobuf2-vmalloc.h> 60ee4a77a3SMauro Carvalho Chehab 61ee4a77a3SMauro Carvalho Chehab /* DRIF register offsets */ 62ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SITMDR1 0x00 63ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SITMDR2 0x04 64ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SITMDR3 0x08 65ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1 0x10 66ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR2 0x14 67ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR3 0x18 68ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SICTR 0x28 69ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIFCTR 0x30 70ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SISTR 0x40 71ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIIER 0x44 72ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRFDR 0x60 73ee4a77a3SMauro Carvalho Chehab 74ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_RFOVF BIT(3) /* Receive FIFO overflow */ 75ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_RFUDF BIT(4) /* Receive FIFO underflow */ 76ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_RFSERR BIT(5) /* Receive frame sync error */ 77ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_REOF BIT(7) /* Frame reception end */ 78ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_RDREQ BIT(12) /* Receive data xfer req */ 79ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_RFFUL BIT(13) /* Receive FIFO full */ 80ee4a77a3SMauro Carvalho Chehab 81ee4a77a3SMauro Carvalho Chehab /* SIRMDR1 */ 82ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCMD_FRAME (0 << 28) 83ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCMD_LR (3 << 28) 84ee4a77a3SMauro Carvalho Chehab 85ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH (0 << 25) 86ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCAC_POL_LOW (1 << 25) 87ee4a77a3SMauro Carvalho Chehab 88ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_MSB_FIRST (0 << 24) 89ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_LSB_FIRST (1 << 24) 90ee4a77a3SMauro Carvalho Chehab 91ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_DTDL_0 (0 << 20) 92ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_DTDL_1 (1 << 20) 93ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_DTDL_2 (2 << 20) 94ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_DTDL_0PT5 (5 << 20) 95ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_DTDL_1PT5 (6 << 20) 96ee4a77a3SMauro Carvalho Chehab 97ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCDL_0 (0 << 20) 98ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCDL_1 (1 << 20) 99ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCDL_2 (2 << 20) 100ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCDL_3 (3 << 20) 101ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCDL_0PT5 (5 << 20) 102ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SIRMDR1_SYNCDL_1PT5 (6 << 20) 103ee4a77a3SMauro Carvalho Chehab 104ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_MDR_GRPCNT(n) (((n) - 1) << 30) 105ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_MDR_BITLEN(n) (((n) - 1) << 24) 106ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_MDR_WDCNT(n) (((n) - 1) << 16) 107ee4a77a3SMauro Carvalho Chehab 108ee4a77a3SMauro Carvalho Chehab /* Hidden Transmit register that controls CLK & SYNC */ 109ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SITMDR1_PCON BIT(30) 110ee4a77a3SMauro Carvalho Chehab 111ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SICTR_RX_RISING_EDGE BIT(26) 112ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SICTR_RX_EN BIT(8) 113ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_SICTR_RESET BIT(0) 114ee4a77a3SMauro Carvalho Chehab 115ee4a77a3SMauro Carvalho Chehab /* Constants */ 116ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_NUM_HWBUFS 32 117ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_MAX_DEVS 4 118ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_DEFAULT_NUM_HWBUFS 16 119ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_DEFAULT_HWBUF_SIZE (4 * PAGE_SIZE) 120ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_MAX_CHANNEL 2 121ee4a77a3SMauro Carvalho Chehab #define RCAR_SDR_BUFFER_SIZE SZ_64K 122ee4a77a3SMauro Carvalho Chehab 123ee4a77a3SMauro Carvalho Chehab /* Internal buffer status flags */ 124ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_BUF_DONE BIT(0) /* DMA completed */ 125ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_BUF_OVERFLOW BIT(1) /* Overflow detected */ 126ee4a77a3SMauro Carvalho Chehab 127ee4a77a3SMauro Carvalho Chehab #define to_rcar_drif_buf_pair(sdr, ch_num, idx) \ 128ee4a77a3SMauro Carvalho Chehab (&((sdr)->ch[!(ch_num)]->buf[(idx)])) 129ee4a77a3SMauro Carvalho Chehab 130ee4a77a3SMauro Carvalho Chehab #define for_each_rcar_drif_channel(ch, ch_mask) \ 131ee4a77a3SMauro Carvalho Chehab for_each_set_bit(ch, ch_mask, RCAR_DRIF_MAX_CHANNEL) 132ee4a77a3SMauro Carvalho Chehab 133ee4a77a3SMauro Carvalho Chehab /* Debug */ 134ee4a77a3SMauro Carvalho Chehab #define rdrif_dbg(sdr, fmt, arg...) \ 135ee4a77a3SMauro Carvalho Chehab dev_dbg(sdr->v4l2_dev.dev, fmt, ## arg) 136ee4a77a3SMauro Carvalho Chehab 137ee4a77a3SMauro Carvalho Chehab #define rdrif_err(sdr, fmt, arg...) \ 138ee4a77a3SMauro Carvalho Chehab dev_err(sdr->v4l2_dev.dev, fmt, ## arg) 139ee4a77a3SMauro Carvalho Chehab 140ee4a77a3SMauro Carvalho Chehab /* Stream formats */ 141ee4a77a3SMauro Carvalho Chehab struct rcar_drif_format { 142ee4a77a3SMauro Carvalho Chehab u32 pixelformat; 143ee4a77a3SMauro Carvalho Chehab u32 buffersize; 144ee4a77a3SMauro Carvalho Chehab u32 bitlen; 145ee4a77a3SMauro Carvalho Chehab u32 wdcnt; 146ee4a77a3SMauro Carvalho Chehab u32 num_ch; 147ee4a77a3SMauro Carvalho Chehab }; 148ee4a77a3SMauro Carvalho Chehab 149ee4a77a3SMauro Carvalho Chehab /* Format descriptions for capture */ 150ee4a77a3SMauro Carvalho Chehab static const struct rcar_drif_format formats[] = { 151ee4a77a3SMauro Carvalho Chehab { 152ee4a77a3SMauro Carvalho Chehab .pixelformat = V4L2_SDR_FMT_PCU16BE, 153ee4a77a3SMauro Carvalho Chehab .buffersize = RCAR_SDR_BUFFER_SIZE, 154ee4a77a3SMauro Carvalho Chehab .bitlen = 16, 155ee4a77a3SMauro Carvalho Chehab .wdcnt = 1, 156ee4a77a3SMauro Carvalho Chehab .num_ch = 2, 157ee4a77a3SMauro Carvalho Chehab }, 158ee4a77a3SMauro Carvalho Chehab { 159ee4a77a3SMauro Carvalho Chehab .pixelformat = V4L2_SDR_FMT_PCU18BE, 160ee4a77a3SMauro Carvalho Chehab .buffersize = RCAR_SDR_BUFFER_SIZE, 161ee4a77a3SMauro Carvalho Chehab .bitlen = 18, 162ee4a77a3SMauro Carvalho Chehab .wdcnt = 1, 163ee4a77a3SMauro Carvalho Chehab .num_ch = 2, 164ee4a77a3SMauro Carvalho Chehab }, 165ee4a77a3SMauro Carvalho Chehab { 166ee4a77a3SMauro Carvalho Chehab .pixelformat = V4L2_SDR_FMT_PCU20BE, 167ee4a77a3SMauro Carvalho Chehab .buffersize = RCAR_SDR_BUFFER_SIZE, 168ee4a77a3SMauro Carvalho Chehab .bitlen = 20, 169ee4a77a3SMauro Carvalho Chehab .wdcnt = 1, 170ee4a77a3SMauro Carvalho Chehab .num_ch = 2, 171ee4a77a3SMauro Carvalho Chehab }, 172ee4a77a3SMauro Carvalho Chehab }; 173ee4a77a3SMauro Carvalho Chehab 174ee4a77a3SMauro Carvalho Chehab /* Buffer for a received frame from one or both internal channels */ 175ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf { 176ee4a77a3SMauro Carvalho Chehab /* Common v4l buffer stuff -- must be first */ 177ee4a77a3SMauro Carvalho Chehab struct vb2_v4l2_buffer vb; 178ee4a77a3SMauro Carvalho Chehab struct list_head list; 179ee4a77a3SMauro Carvalho Chehab }; 180ee4a77a3SMauro Carvalho Chehab 181ee4a77a3SMauro Carvalho Chehab /* OF graph endpoint's V4L2 async data */ 182ee4a77a3SMauro Carvalho Chehab struct rcar_drif_graph_ep { 183ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev *subdev; /* Async matched subdev */ 184ee4a77a3SMauro Carvalho Chehab }; 185ee4a77a3SMauro Carvalho Chehab 186ee4a77a3SMauro Carvalho Chehab /* DMA buffer */ 187ee4a77a3SMauro Carvalho Chehab struct rcar_drif_hwbuf { 188ee4a77a3SMauro Carvalho Chehab void *addr; /* CPU-side address */ 189ee4a77a3SMauro Carvalho Chehab unsigned int status; /* Buffer status flags */ 190ee4a77a3SMauro Carvalho Chehab }; 191ee4a77a3SMauro Carvalho Chehab 192ee4a77a3SMauro Carvalho Chehab /* Internal channel */ 193ee4a77a3SMauro Carvalho Chehab struct rcar_drif { 194ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr; /* Group device */ 195ee4a77a3SMauro Carvalho Chehab struct platform_device *pdev; /* Channel's pdev */ 196ee4a77a3SMauro Carvalho Chehab void __iomem *base; /* Base register address */ 197ee4a77a3SMauro Carvalho Chehab resource_size_t start; /* I/O resource offset */ 198ee4a77a3SMauro Carvalho Chehab struct dma_chan *dmach; /* Reserved DMA channel */ 199ee4a77a3SMauro Carvalho Chehab struct clk *clk; /* Module clock */ 200ee4a77a3SMauro Carvalho Chehab struct rcar_drif_hwbuf buf[RCAR_DRIF_NUM_HWBUFS]; /* H/W bufs */ 201ee4a77a3SMauro Carvalho Chehab dma_addr_t dma_handle; /* Handle for all bufs */ 202ee4a77a3SMauro Carvalho Chehab unsigned int num; /* Channel number */ 203ee4a77a3SMauro Carvalho Chehab bool acting_sdr; /* Channel acting as SDR device */ 204ee4a77a3SMauro Carvalho Chehab }; 205ee4a77a3SMauro Carvalho Chehab 206ee4a77a3SMauro Carvalho Chehab /* DRIF V4L2 SDR */ 207ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr { 208ee4a77a3SMauro Carvalho Chehab struct device *dev; /* Platform device */ 209ee4a77a3SMauro Carvalho Chehab struct video_device *vdev; /* V4L2 SDR device */ 210ee4a77a3SMauro Carvalho Chehab struct v4l2_device v4l2_dev; /* V4L2 device */ 211ee4a77a3SMauro Carvalho Chehab 212ee4a77a3SMauro Carvalho Chehab /* Videobuf2 queue and queued buffers list */ 213ee4a77a3SMauro Carvalho Chehab struct vb2_queue vb_queue; 214ee4a77a3SMauro Carvalho Chehab struct list_head queued_bufs; 215ee4a77a3SMauro Carvalho Chehab spinlock_t queued_bufs_lock; /* Protects queued_bufs */ 216ee4a77a3SMauro Carvalho Chehab spinlock_t dma_lock; /* To serialize DMA cb of channels */ 217ee4a77a3SMauro Carvalho Chehab 218ee4a77a3SMauro Carvalho Chehab struct mutex v4l2_mutex; /* To serialize ioctls */ 219ee4a77a3SMauro Carvalho Chehab struct mutex vb_queue_mutex; /* To serialize streaming ioctls */ 220ee4a77a3SMauro Carvalho Chehab struct v4l2_ctrl_handler ctrl_hdl; /* SDR control handler */ 221ee4a77a3SMauro Carvalho Chehab struct v4l2_async_notifier notifier; /* For subdev (tuner) */ 222ee4a77a3SMauro Carvalho Chehab struct rcar_drif_graph_ep ep; /* Endpoint V4L2 async data */ 223ee4a77a3SMauro Carvalho Chehab 224ee4a77a3SMauro Carvalho Chehab /* Current V4L2 SDR format ptr */ 225ee4a77a3SMauro Carvalho Chehab const struct rcar_drif_format *fmt; 226ee4a77a3SMauro Carvalho Chehab 227ee4a77a3SMauro Carvalho Chehab /* Device tree SYNC properties */ 228ee4a77a3SMauro Carvalho Chehab u32 mdr1; 229ee4a77a3SMauro Carvalho Chehab 230ee4a77a3SMauro Carvalho Chehab /* Internals */ 231ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch[RCAR_DRIF_MAX_CHANNEL]; /* DRIFx0,1 */ 232ee4a77a3SMauro Carvalho Chehab unsigned long hw_ch_mask; /* Enabled channels per DT */ 233ee4a77a3SMauro Carvalho Chehab unsigned long cur_ch_mask; /* Used channels for an SDR FMT */ 234ee4a77a3SMauro Carvalho Chehab u32 num_hw_ch; /* Num of DT enabled channels */ 235ee4a77a3SMauro Carvalho Chehab u32 num_cur_ch; /* Num of used channels */ 236ee4a77a3SMauro Carvalho Chehab u32 hwbuf_size; /* Each DMA buffer size */ 237ee4a77a3SMauro Carvalho Chehab u32 produced; /* Buffers produced by sdr dev */ 238ee4a77a3SMauro Carvalho Chehab }; 239ee4a77a3SMauro Carvalho Chehab 240ee4a77a3SMauro Carvalho Chehab /* Register access functions */ 241ee4a77a3SMauro Carvalho Chehab static void rcar_drif_write(struct rcar_drif *ch, u32 offset, u32 data) 242ee4a77a3SMauro Carvalho Chehab { 243ee4a77a3SMauro Carvalho Chehab writel(data, ch->base + offset); 244ee4a77a3SMauro Carvalho Chehab } 245ee4a77a3SMauro Carvalho Chehab 246ee4a77a3SMauro Carvalho Chehab static u32 rcar_drif_read(struct rcar_drif *ch, u32 offset) 247ee4a77a3SMauro Carvalho Chehab { 248ee4a77a3SMauro Carvalho Chehab return readl(ch->base + offset); 249ee4a77a3SMauro Carvalho Chehab } 250ee4a77a3SMauro Carvalho Chehab 251ee4a77a3SMauro Carvalho Chehab /* Release DMA channels */ 252ee4a77a3SMauro Carvalho Chehab static void rcar_drif_release_dmachannels(struct rcar_drif_sdr *sdr) 253ee4a77a3SMauro Carvalho Chehab { 254ee4a77a3SMauro Carvalho Chehab unsigned int i; 255ee4a77a3SMauro Carvalho Chehab 256ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) 257ee4a77a3SMauro Carvalho Chehab if (sdr->ch[i]->dmach) { 258ee4a77a3SMauro Carvalho Chehab dma_release_channel(sdr->ch[i]->dmach); 259ee4a77a3SMauro Carvalho Chehab sdr->ch[i]->dmach = NULL; 260ee4a77a3SMauro Carvalho Chehab } 261ee4a77a3SMauro Carvalho Chehab } 262ee4a77a3SMauro Carvalho Chehab 263ee4a77a3SMauro Carvalho Chehab /* Allocate DMA channels */ 264ee4a77a3SMauro Carvalho Chehab static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) 265ee4a77a3SMauro Carvalho Chehab { 266ee4a77a3SMauro Carvalho Chehab struct dma_slave_config dma_cfg; 267ee4a77a3SMauro Carvalho Chehab unsigned int i; 268ee4a77a3SMauro Carvalho Chehab int ret; 269ee4a77a3SMauro Carvalho Chehab 270ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 271ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch = sdr->ch[i]; 272ee4a77a3SMauro Carvalho Chehab 273ee4a77a3SMauro Carvalho Chehab ch->dmach = dma_request_chan(&ch->pdev->dev, "rx"); 274ee4a77a3SMauro Carvalho Chehab if (IS_ERR(ch->dmach)) { 275ee4a77a3SMauro Carvalho Chehab ret = PTR_ERR(ch->dmach); 276ee4a77a3SMauro Carvalho Chehab if (ret != -EPROBE_DEFER) 277ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, 278ee4a77a3SMauro Carvalho Chehab "ch%u: dma channel req failed: %pe\n", 279ee4a77a3SMauro Carvalho Chehab i, ch->dmach); 280ee4a77a3SMauro Carvalho Chehab ch->dmach = NULL; 281ee4a77a3SMauro Carvalho Chehab goto dmach_error; 282ee4a77a3SMauro Carvalho Chehab } 283ee4a77a3SMauro Carvalho Chehab 284ee4a77a3SMauro Carvalho Chehab /* Configure slave */ 285ee4a77a3SMauro Carvalho Chehab memset(&dma_cfg, 0, sizeof(dma_cfg)); 286ee4a77a3SMauro Carvalho Chehab dma_cfg.src_addr = (phys_addr_t)(ch->start + RCAR_DRIF_SIRFDR); 287ee4a77a3SMauro Carvalho Chehab dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 288ee4a77a3SMauro Carvalho Chehab ret = dmaengine_slave_config(ch->dmach, &dma_cfg); 289ee4a77a3SMauro Carvalho Chehab if (ret) { 290ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: dma slave config failed\n", i); 291ee4a77a3SMauro Carvalho Chehab goto dmach_error; 292ee4a77a3SMauro Carvalho Chehab } 293ee4a77a3SMauro Carvalho Chehab } 294ee4a77a3SMauro Carvalho Chehab return 0; 295ee4a77a3SMauro Carvalho Chehab 296ee4a77a3SMauro Carvalho Chehab dmach_error: 297ee4a77a3SMauro Carvalho Chehab rcar_drif_release_dmachannels(sdr); 298ee4a77a3SMauro Carvalho Chehab return ret; 299ee4a77a3SMauro Carvalho Chehab } 300ee4a77a3SMauro Carvalho Chehab 301ee4a77a3SMauro Carvalho Chehab /* Release queued vb2 buffers */ 302ee4a77a3SMauro Carvalho Chehab static void rcar_drif_release_queued_bufs(struct rcar_drif_sdr *sdr, 303ee4a77a3SMauro Carvalho Chehab enum vb2_buffer_state state) 304ee4a77a3SMauro Carvalho Chehab { 305ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf, *tmp; 306ee4a77a3SMauro Carvalho Chehab unsigned long flags; 307ee4a77a3SMauro Carvalho Chehab 308ee4a77a3SMauro Carvalho Chehab spin_lock_irqsave(&sdr->queued_bufs_lock, flags); 309ee4a77a3SMauro Carvalho Chehab list_for_each_entry_safe(fbuf, tmp, &sdr->queued_bufs, list) { 310ee4a77a3SMauro Carvalho Chehab list_del(&fbuf->list); 311ee4a77a3SMauro Carvalho Chehab vb2_buffer_done(&fbuf->vb.vb2_buf, state); 312ee4a77a3SMauro Carvalho Chehab } 313ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 314ee4a77a3SMauro Carvalho Chehab } 315ee4a77a3SMauro Carvalho Chehab 316ee4a77a3SMauro Carvalho Chehab /* Set MDR defaults */ 317ee4a77a3SMauro Carvalho Chehab static inline void rcar_drif_set_mdr1(struct rcar_drif_sdr *sdr) 318ee4a77a3SMauro Carvalho Chehab { 319ee4a77a3SMauro Carvalho Chehab unsigned int i; 320ee4a77a3SMauro Carvalho Chehab 321ee4a77a3SMauro Carvalho Chehab /* Set defaults for enabled internal channels */ 322ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 323ee4a77a3SMauro Carvalho Chehab /* Refer MSIOF section in manual for this register setting */ 324ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SITMDR1, 325ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_SITMDR1_PCON); 326ee4a77a3SMauro Carvalho Chehab 327ee4a77a3SMauro Carvalho Chehab /* Setup MDR1 value */ 328ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SIRMDR1, sdr->mdr1); 329ee4a77a3SMauro Carvalho Chehab 330ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "ch%u: mdr1 = 0x%08x", 331ee4a77a3SMauro Carvalho Chehab i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SIRMDR1)); 332ee4a77a3SMauro Carvalho Chehab } 333ee4a77a3SMauro Carvalho Chehab } 334ee4a77a3SMauro Carvalho Chehab 335ee4a77a3SMauro Carvalho Chehab /* Set DRIF receive format */ 336ee4a77a3SMauro Carvalho Chehab static int rcar_drif_set_format(struct rcar_drif_sdr *sdr) 337ee4a77a3SMauro Carvalho Chehab { 338ee4a77a3SMauro Carvalho Chehab unsigned int i; 339ee4a77a3SMauro Carvalho Chehab 340ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "setfmt: bitlen %u wdcnt %u num_ch %u\n", 341ee4a77a3SMauro Carvalho Chehab sdr->fmt->bitlen, sdr->fmt->wdcnt, sdr->fmt->num_ch); 342ee4a77a3SMauro Carvalho Chehab 343ee4a77a3SMauro Carvalho Chehab /* Sanity check */ 344ee4a77a3SMauro Carvalho Chehab if (sdr->fmt->num_ch > sdr->num_cur_ch) { 345ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "fmt num_ch %u cur_ch %u mismatch\n", 346ee4a77a3SMauro Carvalho Chehab sdr->fmt->num_ch, sdr->num_cur_ch); 347ee4a77a3SMauro Carvalho Chehab return -EINVAL; 348ee4a77a3SMauro Carvalho Chehab } 349ee4a77a3SMauro Carvalho Chehab 350ee4a77a3SMauro Carvalho Chehab /* Setup group, bitlen & wdcnt */ 351ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 352ee4a77a3SMauro Carvalho Chehab u32 mdr; 353ee4a77a3SMauro Carvalho Chehab 354ee4a77a3SMauro Carvalho Chehab /* Two groups */ 355ee4a77a3SMauro Carvalho Chehab mdr = RCAR_DRIF_MDR_GRPCNT(2) | 356ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_MDR_BITLEN(sdr->fmt->bitlen) | 357ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_MDR_WDCNT(sdr->fmt->wdcnt); 358ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SIRMDR2, mdr); 359ee4a77a3SMauro Carvalho Chehab 360ee4a77a3SMauro Carvalho Chehab mdr = RCAR_DRIF_MDR_BITLEN(sdr->fmt->bitlen) | 361ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_MDR_WDCNT(sdr->fmt->wdcnt); 362ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SIRMDR3, mdr); 363ee4a77a3SMauro Carvalho Chehab 364ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "ch%u: new mdr[2,3] = 0x%08x, 0x%08x\n", 365ee4a77a3SMauro Carvalho Chehab i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SIRMDR2), 366ee4a77a3SMauro Carvalho Chehab rcar_drif_read(sdr->ch[i], RCAR_DRIF_SIRMDR3)); 367ee4a77a3SMauro Carvalho Chehab } 368ee4a77a3SMauro Carvalho Chehab return 0; 369ee4a77a3SMauro Carvalho Chehab } 370ee4a77a3SMauro Carvalho Chehab 371ee4a77a3SMauro Carvalho Chehab /* Release DMA buffers */ 372ee4a77a3SMauro Carvalho Chehab static void rcar_drif_release_buf(struct rcar_drif_sdr *sdr) 373ee4a77a3SMauro Carvalho Chehab { 374ee4a77a3SMauro Carvalho Chehab unsigned int i; 375ee4a77a3SMauro Carvalho Chehab 376ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 377ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch = sdr->ch[i]; 378ee4a77a3SMauro Carvalho Chehab 379ee4a77a3SMauro Carvalho Chehab /* First entry contains the dma buf ptr */ 380ee4a77a3SMauro Carvalho Chehab if (ch->buf[0].addr) { 381ee4a77a3SMauro Carvalho Chehab dma_free_coherent(&ch->pdev->dev, 382ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS, 383ee4a77a3SMauro Carvalho Chehab ch->buf[0].addr, ch->dma_handle); 384ee4a77a3SMauro Carvalho Chehab ch->buf[0].addr = NULL; 385ee4a77a3SMauro Carvalho Chehab } 386ee4a77a3SMauro Carvalho Chehab } 387ee4a77a3SMauro Carvalho Chehab } 388ee4a77a3SMauro Carvalho Chehab 389ee4a77a3SMauro Carvalho Chehab /* Request DMA buffers */ 390ee4a77a3SMauro Carvalho Chehab static int rcar_drif_request_buf(struct rcar_drif_sdr *sdr) 391ee4a77a3SMauro Carvalho Chehab { 392ee4a77a3SMauro Carvalho Chehab int ret = -ENOMEM; 393ee4a77a3SMauro Carvalho Chehab unsigned int i, j; 394ee4a77a3SMauro Carvalho Chehab void *addr; 395ee4a77a3SMauro Carvalho Chehab 396ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 397ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch = sdr->ch[i]; 398ee4a77a3SMauro Carvalho Chehab 399ee4a77a3SMauro Carvalho Chehab /* Allocate DMA buffers */ 400ee4a77a3SMauro Carvalho Chehab addr = dma_alloc_coherent(&ch->pdev->dev, 401ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS, 402ee4a77a3SMauro Carvalho Chehab &ch->dma_handle, GFP_KERNEL); 403ee4a77a3SMauro Carvalho Chehab if (!addr) { 404ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, 405ee4a77a3SMauro Carvalho Chehab "ch%u: dma alloc failed. num hwbufs %u size %u\n", 406ee4a77a3SMauro Carvalho Chehab i, RCAR_DRIF_NUM_HWBUFS, sdr->hwbuf_size); 407ee4a77a3SMauro Carvalho Chehab goto error; 408ee4a77a3SMauro Carvalho Chehab } 409ee4a77a3SMauro Carvalho Chehab 410ee4a77a3SMauro Carvalho Chehab /* Split the chunk and populate bufctxt */ 411ee4a77a3SMauro Carvalho Chehab for (j = 0; j < RCAR_DRIF_NUM_HWBUFS; j++) { 412ee4a77a3SMauro Carvalho Chehab ch->buf[j].addr = addr + (j * sdr->hwbuf_size); 413ee4a77a3SMauro Carvalho Chehab ch->buf[j].status = 0; 414ee4a77a3SMauro Carvalho Chehab } 415ee4a77a3SMauro Carvalho Chehab } 416ee4a77a3SMauro Carvalho Chehab return 0; 417ee4a77a3SMauro Carvalho Chehab error: 418ee4a77a3SMauro Carvalho Chehab return ret; 419ee4a77a3SMauro Carvalho Chehab } 420ee4a77a3SMauro Carvalho Chehab 421ee4a77a3SMauro Carvalho Chehab /* Setup vb_queue minimum buffer requirements */ 422ee4a77a3SMauro Carvalho Chehab static int rcar_drif_queue_setup(struct vb2_queue *vq, 423ee4a77a3SMauro Carvalho Chehab unsigned int *num_buffers, unsigned int *num_planes, 424ee4a77a3SMauro Carvalho Chehab unsigned int sizes[], struct device *alloc_devs[]) 425ee4a77a3SMauro Carvalho Chehab { 426ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); 427ee4a77a3SMauro Carvalho Chehab 428ee4a77a3SMauro Carvalho Chehab /* Need at least 16 buffers */ 429ee4a77a3SMauro Carvalho Chehab if (vq->num_buffers + *num_buffers < 16) 430ee4a77a3SMauro Carvalho Chehab *num_buffers = 16 - vq->num_buffers; 431ee4a77a3SMauro Carvalho Chehab 432ee4a77a3SMauro Carvalho Chehab *num_planes = 1; 433ee4a77a3SMauro Carvalho Chehab sizes[0] = PAGE_ALIGN(sdr->fmt->buffersize); 434ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "num_bufs %d sizes[0] %d\n", *num_buffers, sizes[0]); 435ee4a77a3SMauro Carvalho Chehab 436ee4a77a3SMauro Carvalho Chehab return 0; 437ee4a77a3SMauro Carvalho Chehab } 438ee4a77a3SMauro Carvalho Chehab 439ee4a77a3SMauro Carvalho Chehab /* Enqueue buffer */ 440ee4a77a3SMauro Carvalho Chehab static void rcar_drif_buf_queue(struct vb2_buffer *vb) 441ee4a77a3SMauro Carvalho Chehab { 442ee4a77a3SMauro Carvalho Chehab struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 443ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vb->vb2_queue); 444ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf = 445ee4a77a3SMauro Carvalho Chehab container_of(vbuf, struct rcar_drif_frame_buf, vb); 446ee4a77a3SMauro Carvalho Chehab unsigned long flags; 447ee4a77a3SMauro Carvalho Chehab 448ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "buf_queue idx %u\n", vb->index); 449ee4a77a3SMauro Carvalho Chehab spin_lock_irqsave(&sdr->queued_bufs_lock, flags); 450ee4a77a3SMauro Carvalho Chehab list_add_tail(&fbuf->list, &sdr->queued_bufs); 451ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 452ee4a77a3SMauro Carvalho Chehab } 453ee4a77a3SMauro Carvalho Chehab 454ee4a77a3SMauro Carvalho Chehab /* Get a frame buf from list */ 455ee4a77a3SMauro Carvalho Chehab static struct rcar_drif_frame_buf * 456ee4a77a3SMauro Carvalho Chehab rcar_drif_get_fbuf(struct rcar_drif_sdr *sdr) 457ee4a77a3SMauro Carvalho Chehab { 458ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf; 459ee4a77a3SMauro Carvalho Chehab unsigned long flags; 460ee4a77a3SMauro Carvalho Chehab 461ee4a77a3SMauro Carvalho Chehab spin_lock_irqsave(&sdr->queued_bufs_lock, flags); 462ee4a77a3SMauro Carvalho Chehab fbuf = list_first_entry_or_null(&sdr->queued_bufs, struct 463ee4a77a3SMauro Carvalho Chehab rcar_drif_frame_buf, list); 464ee4a77a3SMauro Carvalho Chehab if (!fbuf) { 465ee4a77a3SMauro Carvalho Chehab /* 466ee4a77a3SMauro Carvalho Chehab * App is late in enqueing buffers. Samples lost & there will 467ee4a77a3SMauro Carvalho Chehab * be a gap in sequence number when app recovers 468ee4a77a3SMauro Carvalho Chehab */ 469ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "\napp late: prod %u\n", sdr->produced); 470ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 471ee4a77a3SMauro Carvalho Chehab return NULL; 472ee4a77a3SMauro Carvalho Chehab } 473ee4a77a3SMauro Carvalho Chehab list_del(&fbuf->list); 474ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags); 475ee4a77a3SMauro Carvalho Chehab 476ee4a77a3SMauro Carvalho Chehab return fbuf; 477ee4a77a3SMauro Carvalho Chehab } 478ee4a77a3SMauro Carvalho Chehab 479ee4a77a3SMauro Carvalho Chehab /* Helpers to set/clear buf pair status */ 480ee4a77a3SMauro Carvalho Chehab static inline bool rcar_drif_bufs_done(struct rcar_drif_hwbuf **buf) 481ee4a77a3SMauro Carvalho Chehab { 482ee4a77a3SMauro Carvalho Chehab return (buf[0]->status & buf[1]->status & RCAR_DRIF_BUF_DONE); 483ee4a77a3SMauro Carvalho Chehab } 484ee4a77a3SMauro Carvalho Chehab 485ee4a77a3SMauro Carvalho Chehab static inline bool rcar_drif_bufs_overflow(struct rcar_drif_hwbuf **buf) 486ee4a77a3SMauro Carvalho Chehab { 487ee4a77a3SMauro Carvalho Chehab return ((buf[0]->status | buf[1]->status) & RCAR_DRIF_BUF_OVERFLOW); 488ee4a77a3SMauro Carvalho Chehab } 489ee4a77a3SMauro Carvalho Chehab 490ee4a77a3SMauro Carvalho Chehab static inline void rcar_drif_bufs_clear(struct rcar_drif_hwbuf **buf, 491ee4a77a3SMauro Carvalho Chehab unsigned int bit) 492ee4a77a3SMauro Carvalho Chehab { 493ee4a77a3SMauro Carvalho Chehab unsigned int i; 494ee4a77a3SMauro Carvalho Chehab 495ee4a77a3SMauro Carvalho Chehab for (i = 0; i < RCAR_DRIF_MAX_CHANNEL; i++) 496ee4a77a3SMauro Carvalho Chehab buf[i]->status &= ~bit; 497ee4a77a3SMauro Carvalho Chehab } 498ee4a77a3SMauro Carvalho Chehab 499ee4a77a3SMauro Carvalho Chehab /* Channel DMA complete */ 500ee4a77a3SMauro Carvalho Chehab static void rcar_drif_channel_complete(struct rcar_drif *ch, u32 idx) 501ee4a77a3SMauro Carvalho Chehab { 502ee4a77a3SMauro Carvalho Chehab u32 str; 503ee4a77a3SMauro Carvalho Chehab 504ee4a77a3SMauro Carvalho Chehab ch->buf[idx].status |= RCAR_DRIF_BUF_DONE; 505ee4a77a3SMauro Carvalho Chehab 506ee4a77a3SMauro Carvalho Chehab /* Check for DRIF errors */ 507ee4a77a3SMauro Carvalho Chehab str = rcar_drif_read(ch, RCAR_DRIF_SISTR); 508ee4a77a3SMauro Carvalho Chehab if (unlikely(str & RCAR_DRIF_RFOVF)) { 509ee4a77a3SMauro Carvalho Chehab /* Writing the same clears it */ 510ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SISTR, str); 511ee4a77a3SMauro Carvalho Chehab 512ee4a77a3SMauro Carvalho Chehab /* Overflow: some samples are lost */ 513ee4a77a3SMauro Carvalho Chehab ch->buf[idx].status |= RCAR_DRIF_BUF_OVERFLOW; 514ee4a77a3SMauro Carvalho Chehab } 515ee4a77a3SMauro Carvalho Chehab } 516ee4a77a3SMauro Carvalho Chehab 517ee4a77a3SMauro Carvalho Chehab /* DMA callback for each stage */ 518ee4a77a3SMauro Carvalho Chehab static void rcar_drif_dma_complete(void *dma_async_param) 519ee4a77a3SMauro Carvalho Chehab { 520ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch = dma_async_param; 521ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr; 522ee4a77a3SMauro Carvalho Chehab struct rcar_drif_hwbuf *buf[RCAR_DRIF_MAX_CHANNEL]; 523ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf; 524ee4a77a3SMauro Carvalho Chehab bool overflow = false; 525ee4a77a3SMauro Carvalho Chehab u32 idx, produced; 526ee4a77a3SMauro Carvalho Chehab unsigned int i; 527ee4a77a3SMauro Carvalho Chehab 528ee4a77a3SMauro Carvalho Chehab spin_lock(&sdr->dma_lock); 529ee4a77a3SMauro Carvalho Chehab 530ee4a77a3SMauro Carvalho Chehab /* DMA can be terminated while the callback was waiting on lock */ 531ee4a77a3SMauro Carvalho Chehab if (!vb2_is_streaming(&sdr->vb_queue)) { 532ee4a77a3SMauro Carvalho Chehab spin_unlock(&sdr->dma_lock); 533ee4a77a3SMauro Carvalho Chehab return; 534ee4a77a3SMauro Carvalho Chehab } 535ee4a77a3SMauro Carvalho Chehab 536ee4a77a3SMauro Carvalho Chehab idx = sdr->produced % RCAR_DRIF_NUM_HWBUFS; 537ee4a77a3SMauro Carvalho Chehab rcar_drif_channel_complete(ch, idx); 538ee4a77a3SMauro Carvalho Chehab 539ee4a77a3SMauro Carvalho Chehab if (sdr->num_cur_ch == RCAR_DRIF_MAX_CHANNEL) { 540ee4a77a3SMauro Carvalho Chehab buf[0] = ch->num ? to_rcar_drif_buf_pair(sdr, ch->num, idx) : 541ee4a77a3SMauro Carvalho Chehab &ch->buf[idx]; 542ee4a77a3SMauro Carvalho Chehab buf[1] = ch->num ? &ch->buf[idx] : 543ee4a77a3SMauro Carvalho Chehab to_rcar_drif_buf_pair(sdr, ch->num, idx); 544ee4a77a3SMauro Carvalho Chehab 545ee4a77a3SMauro Carvalho Chehab /* Check if both DMA buffers are done */ 546ee4a77a3SMauro Carvalho Chehab if (!rcar_drif_bufs_done(buf)) { 547ee4a77a3SMauro Carvalho Chehab spin_unlock(&sdr->dma_lock); 548ee4a77a3SMauro Carvalho Chehab return; 549ee4a77a3SMauro Carvalho Chehab } 550ee4a77a3SMauro Carvalho Chehab 551ee4a77a3SMauro Carvalho Chehab /* Clear buf done status */ 552ee4a77a3SMauro Carvalho Chehab rcar_drif_bufs_clear(buf, RCAR_DRIF_BUF_DONE); 553ee4a77a3SMauro Carvalho Chehab 554ee4a77a3SMauro Carvalho Chehab if (rcar_drif_bufs_overflow(buf)) { 555ee4a77a3SMauro Carvalho Chehab overflow = true; 556ee4a77a3SMauro Carvalho Chehab /* Clear the flag in status */ 557ee4a77a3SMauro Carvalho Chehab rcar_drif_bufs_clear(buf, RCAR_DRIF_BUF_OVERFLOW); 558ee4a77a3SMauro Carvalho Chehab } 559ee4a77a3SMauro Carvalho Chehab } else { 560ee4a77a3SMauro Carvalho Chehab buf[0] = &ch->buf[idx]; 561ee4a77a3SMauro Carvalho Chehab if (buf[0]->status & RCAR_DRIF_BUF_OVERFLOW) { 562ee4a77a3SMauro Carvalho Chehab overflow = true; 563ee4a77a3SMauro Carvalho Chehab /* Clear the flag in status */ 564ee4a77a3SMauro Carvalho Chehab buf[0]->status &= ~RCAR_DRIF_BUF_OVERFLOW; 565ee4a77a3SMauro Carvalho Chehab } 566ee4a77a3SMauro Carvalho Chehab } 567ee4a77a3SMauro Carvalho Chehab 568ee4a77a3SMauro Carvalho Chehab /* Buffer produced for consumption */ 569ee4a77a3SMauro Carvalho Chehab produced = sdr->produced++; 570ee4a77a3SMauro Carvalho Chehab spin_unlock(&sdr->dma_lock); 571ee4a77a3SMauro Carvalho Chehab 572ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "ch%u: prod %u\n", ch->num, produced); 573ee4a77a3SMauro Carvalho Chehab 574ee4a77a3SMauro Carvalho Chehab /* Get fbuf */ 575ee4a77a3SMauro Carvalho Chehab fbuf = rcar_drif_get_fbuf(sdr); 576ee4a77a3SMauro Carvalho Chehab if (!fbuf) 577ee4a77a3SMauro Carvalho Chehab return; 578ee4a77a3SMauro Carvalho Chehab 579ee4a77a3SMauro Carvalho Chehab for (i = 0; i < RCAR_DRIF_MAX_CHANNEL; i++) 580ee4a77a3SMauro Carvalho Chehab memcpy(vb2_plane_vaddr(&fbuf->vb.vb2_buf, 0) + 581ee4a77a3SMauro Carvalho Chehab i * sdr->hwbuf_size, buf[i]->addr, sdr->hwbuf_size); 582ee4a77a3SMauro Carvalho Chehab 583ee4a77a3SMauro Carvalho Chehab fbuf->vb.field = V4L2_FIELD_NONE; 584ee4a77a3SMauro Carvalho Chehab fbuf->vb.sequence = produced; 585ee4a77a3SMauro Carvalho Chehab fbuf->vb.vb2_buf.timestamp = ktime_get_ns(); 586ee4a77a3SMauro Carvalho Chehab vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, sdr->fmt->buffersize); 587ee4a77a3SMauro Carvalho Chehab 588ee4a77a3SMauro Carvalho Chehab /* Set error state on overflow */ 589ee4a77a3SMauro Carvalho Chehab vb2_buffer_done(&fbuf->vb.vb2_buf, 590ee4a77a3SMauro Carvalho Chehab overflow ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 591ee4a77a3SMauro Carvalho Chehab } 592ee4a77a3SMauro Carvalho Chehab 593ee4a77a3SMauro Carvalho Chehab static int rcar_drif_qbuf(struct rcar_drif *ch) 594ee4a77a3SMauro Carvalho Chehab { 595ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr; 596ee4a77a3SMauro Carvalho Chehab dma_addr_t addr = ch->dma_handle; 597ee4a77a3SMauro Carvalho Chehab struct dma_async_tx_descriptor *rxd; 598ee4a77a3SMauro Carvalho Chehab dma_cookie_t cookie; 599ee4a77a3SMauro Carvalho Chehab int ret = -EIO; 600ee4a77a3SMauro Carvalho Chehab 601ee4a77a3SMauro Carvalho Chehab /* Setup cyclic DMA with given buffers */ 602ee4a77a3SMauro Carvalho Chehab rxd = dmaengine_prep_dma_cyclic(ch->dmach, addr, 603ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS, 604ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size, DMA_DEV_TO_MEM, 605ee4a77a3SMauro Carvalho Chehab DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 606ee4a77a3SMauro Carvalho Chehab if (!rxd) { 607ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: prep dma cyclic failed\n", ch->num); 608ee4a77a3SMauro Carvalho Chehab return ret; 609ee4a77a3SMauro Carvalho Chehab } 610ee4a77a3SMauro Carvalho Chehab 611ee4a77a3SMauro Carvalho Chehab /* Submit descriptor */ 612ee4a77a3SMauro Carvalho Chehab rxd->callback = rcar_drif_dma_complete; 613ee4a77a3SMauro Carvalho Chehab rxd->callback_param = ch; 614ee4a77a3SMauro Carvalho Chehab cookie = dmaengine_submit(rxd); 615ee4a77a3SMauro Carvalho Chehab if (dma_submit_error(cookie)) { 616ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: dma submit failed\n", ch->num); 617ee4a77a3SMauro Carvalho Chehab return ret; 618ee4a77a3SMauro Carvalho Chehab } 619ee4a77a3SMauro Carvalho Chehab 620ee4a77a3SMauro Carvalho Chehab dma_async_issue_pending(ch->dmach); 621ee4a77a3SMauro Carvalho Chehab return 0; 622ee4a77a3SMauro Carvalho Chehab } 623ee4a77a3SMauro Carvalho Chehab 624ee4a77a3SMauro Carvalho Chehab /* Enable reception */ 625ee4a77a3SMauro Carvalho Chehab static int rcar_drif_enable_rx(struct rcar_drif_sdr *sdr) 626ee4a77a3SMauro Carvalho Chehab { 627ee4a77a3SMauro Carvalho Chehab unsigned int i; 628ee4a77a3SMauro Carvalho Chehab u32 ctr; 629ee4a77a3SMauro Carvalho Chehab int ret = -EINVAL; 630ee4a77a3SMauro Carvalho Chehab 631ee4a77a3SMauro Carvalho Chehab /* 632ee4a77a3SMauro Carvalho Chehab * When both internal channels are enabled, they can be synchronized 633ee4a77a3SMauro Carvalho Chehab * only by the master 634ee4a77a3SMauro Carvalho Chehab */ 635ee4a77a3SMauro Carvalho Chehab 636ee4a77a3SMauro Carvalho Chehab /* Enable receive */ 637ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 638ee4a77a3SMauro Carvalho Chehab ctr = rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR); 639ee4a77a3SMauro Carvalho Chehab ctr |= (RCAR_DRIF_SICTR_RX_RISING_EDGE | 640ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_SICTR_RX_EN); 641ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SICTR, ctr); 642ee4a77a3SMauro Carvalho Chehab } 643ee4a77a3SMauro Carvalho Chehab 644ee4a77a3SMauro Carvalho Chehab /* Check receive enabled */ 645ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 646ee4a77a3SMauro Carvalho Chehab ret = readl_poll_timeout(sdr->ch[i]->base + RCAR_DRIF_SICTR, 647ee4a77a3SMauro Carvalho Chehab ctr, ctr & RCAR_DRIF_SICTR_RX_EN, 7, 100000); 648ee4a77a3SMauro Carvalho Chehab if (ret) { 649ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: rx en failed. ctr 0x%08x\n", i, 650ee4a77a3SMauro Carvalho Chehab rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR)); 651ee4a77a3SMauro Carvalho Chehab break; 652ee4a77a3SMauro Carvalho Chehab } 653ee4a77a3SMauro Carvalho Chehab } 654ee4a77a3SMauro Carvalho Chehab return ret; 655ee4a77a3SMauro Carvalho Chehab } 656ee4a77a3SMauro Carvalho Chehab 657ee4a77a3SMauro Carvalho Chehab /* Disable reception */ 658ee4a77a3SMauro Carvalho Chehab static void rcar_drif_disable_rx(struct rcar_drif_sdr *sdr) 659ee4a77a3SMauro Carvalho Chehab { 660ee4a77a3SMauro Carvalho Chehab unsigned int i; 661ee4a77a3SMauro Carvalho Chehab u32 ctr; 662ee4a77a3SMauro Carvalho Chehab int ret; 663ee4a77a3SMauro Carvalho Chehab 664ee4a77a3SMauro Carvalho Chehab /* Disable receive */ 665ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 666ee4a77a3SMauro Carvalho Chehab ctr = rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR); 667ee4a77a3SMauro Carvalho Chehab ctr &= ~RCAR_DRIF_SICTR_RX_EN; 668ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SICTR, ctr); 669ee4a77a3SMauro Carvalho Chehab } 670ee4a77a3SMauro Carvalho Chehab 671ee4a77a3SMauro Carvalho Chehab /* Check receive disabled */ 672ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 673ee4a77a3SMauro Carvalho Chehab ret = readl_poll_timeout(sdr->ch[i]->base + RCAR_DRIF_SICTR, 674ee4a77a3SMauro Carvalho Chehab ctr, !(ctr & RCAR_DRIF_SICTR_RX_EN), 7, 100000); 675ee4a77a3SMauro Carvalho Chehab if (ret) 676ee4a77a3SMauro Carvalho Chehab dev_warn(&sdr->vdev->dev, 677ee4a77a3SMauro Carvalho Chehab "ch%u: failed to disable rx. ctr 0x%08x\n", 678ee4a77a3SMauro Carvalho Chehab i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR)); 679ee4a77a3SMauro Carvalho Chehab } 680ee4a77a3SMauro Carvalho Chehab } 681ee4a77a3SMauro Carvalho Chehab 682ee4a77a3SMauro Carvalho Chehab /* Stop channel */ 683ee4a77a3SMauro Carvalho Chehab static void rcar_drif_stop_channel(struct rcar_drif *ch) 684ee4a77a3SMauro Carvalho Chehab { 685ee4a77a3SMauro Carvalho Chehab /* Disable DMA receive interrupt */ 686ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SIIER, 0x00000000); 687ee4a77a3SMauro Carvalho Chehab 688ee4a77a3SMauro Carvalho Chehab /* Terminate all DMA transfers */ 689ee4a77a3SMauro Carvalho Chehab dmaengine_terminate_sync(ch->dmach); 690ee4a77a3SMauro Carvalho Chehab } 691ee4a77a3SMauro Carvalho Chehab 692ee4a77a3SMauro Carvalho Chehab /* Stop receive operation */ 693ee4a77a3SMauro Carvalho Chehab static void rcar_drif_stop(struct rcar_drif_sdr *sdr) 694ee4a77a3SMauro Carvalho Chehab { 695ee4a77a3SMauro Carvalho Chehab unsigned int i; 696ee4a77a3SMauro Carvalho Chehab 697ee4a77a3SMauro Carvalho Chehab /* Disable Rx */ 698ee4a77a3SMauro Carvalho Chehab rcar_drif_disable_rx(sdr); 699ee4a77a3SMauro Carvalho Chehab 700ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) 701ee4a77a3SMauro Carvalho Chehab rcar_drif_stop_channel(sdr->ch[i]); 702ee4a77a3SMauro Carvalho Chehab } 703ee4a77a3SMauro Carvalho Chehab 704ee4a77a3SMauro Carvalho Chehab /* Start channel */ 705ee4a77a3SMauro Carvalho Chehab static int rcar_drif_start_channel(struct rcar_drif *ch) 706ee4a77a3SMauro Carvalho Chehab { 707ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr; 708ee4a77a3SMauro Carvalho Chehab u32 ctr, str; 709ee4a77a3SMauro Carvalho Chehab int ret; 710ee4a77a3SMauro Carvalho Chehab 711ee4a77a3SMauro Carvalho Chehab /* Reset receive */ 712ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SICTR, RCAR_DRIF_SICTR_RESET); 713ee4a77a3SMauro Carvalho Chehab ret = readl_poll_timeout(ch->base + RCAR_DRIF_SICTR, ctr, 714ee4a77a3SMauro Carvalho Chehab !(ctr & RCAR_DRIF_SICTR_RESET), 7, 100000); 715ee4a77a3SMauro Carvalho Chehab if (ret) { 716ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: failed to reset rx. ctr 0x%08x\n", 717ee4a77a3SMauro Carvalho Chehab ch->num, rcar_drif_read(ch, RCAR_DRIF_SICTR)); 718ee4a77a3SMauro Carvalho Chehab return ret; 719ee4a77a3SMauro Carvalho Chehab } 720ee4a77a3SMauro Carvalho Chehab 721ee4a77a3SMauro Carvalho Chehab /* Queue buffers for DMA */ 722ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_qbuf(ch); 723ee4a77a3SMauro Carvalho Chehab if (ret) 724ee4a77a3SMauro Carvalho Chehab return ret; 725ee4a77a3SMauro Carvalho Chehab 726ee4a77a3SMauro Carvalho Chehab /* Clear status register flags */ 727ee4a77a3SMauro Carvalho Chehab str = RCAR_DRIF_RFFUL | RCAR_DRIF_REOF | RCAR_DRIF_RFSERR | 728ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_RFUDF | RCAR_DRIF_RFOVF; 729ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SISTR, str); 730ee4a77a3SMauro Carvalho Chehab 731ee4a77a3SMauro Carvalho Chehab /* Enable DMA receive interrupt */ 732ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SIIER, 0x00009000); 733ee4a77a3SMauro Carvalho Chehab 734ee4a77a3SMauro Carvalho Chehab return ret; 735ee4a77a3SMauro Carvalho Chehab } 736ee4a77a3SMauro Carvalho Chehab 737ee4a77a3SMauro Carvalho Chehab /* Start receive operation */ 738ee4a77a3SMauro Carvalho Chehab static int rcar_drif_start(struct rcar_drif_sdr *sdr) 739ee4a77a3SMauro Carvalho Chehab { 740ee4a77a3SMauro Carvalho Chehab unsigned long enabled = 0; 741ee4a77a3SMauro Carvalho Chehab unsigned int i; 742ee4a77a3SMauro Carvalho Chehab int ret; 743ee4a77a3SMauro Carvalho Chehab 744ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 745ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_start_channel(sdr->ch[i]); 746ee4a77a3SMauro Carvalho Chehab if (ret) 747ee4a77a3SMauro Carvalho Chehab goto start_error; 748ee4a77a3SMauro Carvalho Chehab enabled |= BIT(i); 749ee4a77a3SMauro Carvalho Chehab } 750ee4a77a3SMauro Carvalho Chehab 751ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_enable_rx(sdr); 752ee4a77a3SMauro Carvalho Chehab if (ret) 753ee4a77a3SMauro Carvalho Chehab goto enable_error; 754ee4a77a3SMauro Carvalho Chehab 755ee4a77a3SMauro Carvalho Chehab sdr->produced = 0; 756ee4a77a3SMauro Carvalho Chehab return ret; 757ee4a77a3SMauro Carvalho Chehab 758ee4a77a3SMauro Carvalho Chehab enable_error: 759ee4a77a3SMauro Carvalho Chehab rcar_drif_disable_rx(sdr); 760ee4a77a3SMauro Carvalho Chehab start_error: 761ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &enabled) 762ee4a77a3SMauro Carvalho Chehab rcar_drif_stop_channel(sdr->ch[i]); 763ee4a77a3SMauro Carvalho Chehab 764ee4a77a3SMauro Carvalho Chehab return ret; 765ee4a77a3SMauro Carvalho Chehab } 766ee4a77a3SMauro Carvalho Chehab 767ee4a77a3SMauro Carvalho Chehab /* Start streaming */ 768ee4a77a3SMauro Carvalho Chehab static int rcar_drif_start_streaming(struct vb2_queue *vq, unsigned int count) 769ee4a77a3SMauro Carvalho Chehab { 770ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); 771ee4a77a3SMauro Carvalho Chehab unsigned long enabled = 0; 772ee4a77a3SMauro Carvalho Chehab unsigned int i; 773ee4a77a3SMauro Carvalho Chehab int ret; 774ee4a77a3SMauro Carvalho Chehab 775ee4a77a3SMauro Carvalho Chehab mutex_lock(&sdr->v4l2_mutex); 776ee4a77a3SMauro Carvalho Chehab 777ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { 778ee4a77a3SMauro Carvalho Chehab ret = clk_prepare_enable(sdr->ch[i]->clk); 779ee4a77a3SMauro Carvalho Chehab if (ret) 780ee4a77a3SMauro Carvalho Chehab goto error; 781ee4a77a3SMauro Carvalho Chehab enabled |= BIT(i); 782ee4a77a3SMauro Carvalho Chehab } 783ee4a77a3SMauro Carvalho Chehab 784ee4a77a3SMauro Carvalho Chehab /* Set default MDRx settings */ 785ee4a77a3SMauro Carvalho Chehab rcar_drif_set_mdr1(sdr); 786ee4a77a3SMauro Carvalho Chehab 787ee4a77a3SMauro Carvalho Chehab /* Set new format */ 788ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_set_format(sdr); 789ee4a77a3SMauro Carvalho Chehab if (ret) 790ee4a77a3SMauro Carvalho Chehab goto error; 791ee4a77a3SMauro Carvalho Chehab 792ee4a77a3SMauro Carvalho Chehab if (sdr->num_cur_ch == RCAR_DRIF_MAX_CHANNEL) 793ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size = sdr->fmt->buffersize / RCAR_DRIF_MAX_CHANNEL; 794ee4a77a3SMauro Carvalho Chehab else 795ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size = sdr->fmt->buffersize; 796ee4a77a3SMauro Carvalho Chehab 797ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "num hwbufs %u, hwbuf_size %u\n", 798ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_NUM_HWBUFS, sdr->hwbuf_size); 799ee4a77a3SMauro Carvalho Chehab 800ee4a77a3SMauro Carvalho Chehab /* Alloc DMA channel */ 801ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_alloc_dmachannels(sdr); 802ee4a77a3SMauro Carvalho Chehab if (ret) 803ee4a77a3SMauro Carvalho Chehab goto error; 804ee4a77a3SMauro Carvalho Chehab 805ee4a77a3SMauro Carvalho Chehab /* Request buffers */ 806ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_request_buf(sdr); 807ee4a77a3SMauro Carvalho Chehab if (ret) 808ee4a77a3SMauro Carvalho Chehab goto error; 809ee4a77a3SMauro Carvalho Chehab 810ee4a77a3SMauro Carvalho Chehab /* Start Rx */ 811ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_start(sdr); 812ee4a77a3SMauro Carvalho Chehab if (ret) 813ee4a77a3SMauro Carvalho Chehab goto error; 814ee4a77a3SMauro Carvalho Chehab 815ee4a77a3SMauro Carvalho Chehab mutex_unlock(&sdr->v4l2_mutex); 816ee4a77a3SMauro Carvalho Chehab 817ee4a77a3SMauro Carvalho Chehab return ret; 818ee4a77a3SMauro Carvalho Chehab 819ee4a77a3SMauro Carvalho Chehab error: 820ee4a77a3SMauro Carvalho Chehab rcar_drif_release_queued_bufs(sdr, VB2_BUF_STATE_QUEUED); 821ee4a77a3SMauro Carvalho Chehab rcar_drif_release_buf(sdr); 822ee4a77a3SMauro Carvalho Chehab rcar_drif_release_dmachannels(sdr); 823ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &enabled) 824ee4a77a3SMauro Carvalho Chehab clk_disable_unprepare(sdr->ch[i]->clk); 825ee4a77a3SMauro Carvalho Chehab 826ee4a77a3SMauro Carvalho Chehab mutex_unlock(&sdr->v4l2_mutex); 827ee4a77a3SMauro Carvalho Chehab 828ee4a77a3SMauro Carvalho Chehab return ret; 829ee4a77a3SMauro Carvalho Chehab } 830ee4a77a3SMauro Carvalho Chehab 831ee4a77a3SMauro Carvalho Chehab /* Stop streaming */ 832ee4a77a3SMauro Carvalho Chehab static void rcar_drif_stop_streaming(struct vb2_queue *vq) 833ee4a77a3SMauro Carvalho Chehab { 834ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq); 835ee4a77a3SMauro Carvalho Chehab unsigned int i; 836ee4a77a3SMauro Carvalho Chehab 837ee4a77a3SMauro Carvalho Chehab mutex_lock(&sdr->v4l2_mutex); 838ee4a77a3SMauro Carvalho Chehab 839ee4a77a3SMauro Carvalho Chehab /* Stop hardware streaming */ 840ee4a77a3SMauro Carvalho Chehab rcar_drif_stop(sdr); 841ee4a77a3SMauro Carvalho Chehab 842ee4a77a3SMauro Carvalho Chehab /* Return all queued buffers to vb2 */ 843ee4a77a3SMauro Carvalho Chehab rcar_drif_release_queued_bufs(sdr, VB2_BUF_STATE_ERROR); 844ee4a77a3SMauro Carvalho Chehab 845ee4a77a3SMauro Carvalho Chehab /* Release buf */ 846ee4a77a3SMauro Carvalho Chehab rcar_drif_release_buf(sdr); 847ee4a77a3SMauro Carvalho Chehab 848ee4a77a3SMauro Carvalho Chehab /* Release DMA channel resources */ 849ee4a77a3SMauro Carvalho Chehab rcar_drif_release_dmachannels(sdr); 850ee4a77a3SMauro Carvalho Chehab 851ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) 852ee4a77a3SMauro Carvalho Chehab clk_disable_unprepare(sdr->ch[i]->clk); 853ee4a77a3SMauro Carvalho Chehab 854ee4a77a3SMauro Carvalho Chehab mutex_unlock(&sdr->v4l2_mutex); 855ee4a77a3SMauro Carvalho Chehab } 856ee4a77a3SMauro Carvalho Chehab 857ee4a77a3SMauro Carvalho Chehab /* Vb2 ops */ 858ee4a77a3SMauro Carvalho Chehab static const struct vb2_ops rcar_drif_vb2_ops = { 859ee4a77a3SMauro Carvalho Chehab .queue_setup = rcar_drif_queue_setup, 860ee4a77a3SMauro Carvalho Chehab .buf_queue = rcar_drif_buf_queue, 861ee4a77a3SMauro Carvalho Chehab .start_streaming = rcar_drif_start_streaming, 862ee4a77a3SMauro Carvalho Chehab .stop_streaming = rcar_drif_stop_streaming, 863ee4a77a3SMauro Carvalho Chehab .wait_prepare = vb2_ops_wait_prepare, 864ee4a77a3SMauro Carvalho Chehab .wait_finish = vb2_ops_wait_finish, 865ee4a77a3SMauro Carvalho Chehab }; 866ee4a77a3SMauro Carvalho Chehab 867ee4a77a3SMauro Carvalho Chehab static int rcar_drif_querycap(struct file *file, void *fh, 868ee4a77a3SMauro Carvalho Chehab struct v4l2_capability *cap) 869ee4a77a3SMauro Carvalho Chehab { 870ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 871ee4a77a3SMauro Carvalho Chehab 872ee4a77a3SMauro Carvalho Chehab strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); 873ee4a77a3SMauro Carvalho Chehab strscpy(cap->card, sdr->vdev->name, sizeof(cap->card)); 874ee4a77a3SMauro Carvalho Chehab snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", 875ee4a77a3SMauro Carvalho Chehab sdr->vdev->name); 876ee4a77a3SMauro Carvalho Chehab 877ee4a77a3SMauro Carvalho Chehab return 0; 878ee4a77a3SMauro Carvalho Chehab } 879ee4a77a3SMauro Carvalho Chehab 880ee4a77a3SMauro Carvalho Chehab static int rcar_drif_set_default_format(struct rcar_drif_sdr *sdr) 881ee4a77a3SMauro Carvalho Chehab { 882ee4a77a3SMauro Carvalho Chehab unsigned int i; 883ee4a77a3SMauro Carvalho Chehab 884ee4a77a3SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(formats); i++) { 885ee4a77a3SMauro Carvalho Chehab /* Matching fmt based on required channels is set as default */ 886ee4a77a3SMauro Carvalho Chehab if (sdr->num_hw_ch == formats[i].num_ch) { 887ee4a77a3SMauro Carvalho Chehab sdr->fmt = &formats[i]; 888ee4a77a3SMauro Carvalho Chehab sdr->cur_ch_mask = sdr->hw_ch_mask; 889ee4a77a3SMauro Carvalho Chehab sdr->num_cur_ch = sdr->num_hw_ch; 890ee4a77a3SMauro Carvalho Chehab dev_dbg(sdr->dev, "default fmt[%u]: mask %lu num %u\n", 891ee4a77a3SMauro Carvalho Chehab i, sdr->cur_ch_mask, sdr->num_cur_ch); 892ee4a77a3SMauro Carvalho Chehab return 0; 893ee4a77a3SMauro Carvalho Chehab } 894ee4a77a3SMauro Carvalho Chehab } 895ee4a77a3SMauro Carvalho Chehab return -EINVAL; 896ee4a77a3SMauro Carvalho Chehab } 897ee4a77a3SMauro Carvalho Chehab 898ee4a77a3SMauro Carvalho Chehab static int rcar_drif_enum_fmt_sdr_cap(struct file *file, void *priv, 899ee4a77a3SMauro Carvalho Chehab struct v4l2_fmtdesc *f) 900ee4a77a3SMauro Carvalho Chehab { 901ee4a77a3SMauro Carvalho Chehab if (f->index >= ARRAY_SIZE(formats)) 902ee4a77a3SMauro Carvalho Chehab return -EINVAL; 903ee4a77a3SMauro Carvalho Chehab 904ee4a77a3SMauro Carvalho Chehab f->pixelformat = formats[f->index].pixelformat; 905ee4a77a3SMauro Carvalho Chehab 906ee4a77a3SMauro Carvalho Chehab return 0; 907ee4a77a3SMauro Carvalho Chehab } 908ee4a77a3SMauro Carvalho Chehab 909ee4a77a3SMauro Carvalho Chehab static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv, 910ee4a77a3SMauro Carvalho Chehab struct v4l2_format *f) 911ee4a77a3SMauro Carvalho Chehab { 912ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 913ee4a77a3SMauro Carvalho Chehab 914ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.pixelformat = sdr->fmt->pixelformat; 915ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.buffersize = sdr->fmt->buffersize; 916ee4a77a3SMauro Carvalho Chehab 917ee4a77a3SMauro Carvalho Chehab return 0; 918ee4a77a3SMauro Carvalho Chehab } 919ee4a77a3SMauro Carvalho Chehab 920ee4a77a3SMauro Carvalho Chehab static int rcar_drif_s_fmt_sdr_cap(struct file *file, void *priv, 921ee4a77a3SMauro Carvalho Chehab struct v4l2_format *f) 922ee4a77a3SMauro Carvalho Chehab { 923ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 924ee4a77a3SMauro Carvalho Chehab struct vb2_queue *q = &sdr->vb_queue; 925ee4a77a3SMauro Carvalho Chehab unsigned int i; 926ee4a77a3SMauro Carvalho Chehab 927ee4a77a3SMauro Carvalho Chehab if (vb2_is_busy(q)) 928ee4a77a3SMauro Carvalho Chehab return -EBUSY; 929ee4a77a3SMauro Carvalho Chehab 930ee4a77a3SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(formats); i++) { 931ee4a77a3SMauro Carvalho Chehab if (formats[i].pixelformat == f->fmt.sdr.pixelformat) 932ee4a77a3SMauro Carvalho Chehab break; 933ee4a77a3SMauro Carvalho Chehab } 934ee4a77a3SMauro Carvalho Chehab 935ee4a77a3SMauro Carvalho Chehab if (i == ARRAY_SIZE(formats)) 936ee4a77a3SMauro Carvalho Chehab i = 0; /* Set the 1st format as default on no match */ 937ee4a77a3SMauro Carvalho Chehab 938ee4a77a3SMauro Carvalho Chehab sdr->fmt = &formats[i]; 939ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.pixelformat = sdr->fmt->pixelformat; 940ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.buffersize = formats[i].buffersize; 941ee4a77a3SMauro Carvalho Chehab memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); 942ee4a77a3SMauro Carvalho Chehab 943ee4a77a3SMauro Carvalho Chehab /* 944ee4a77a3SMauro Carvalho Chehab * If a format demands one channel only out of two 945ee4a77a3SMauro Carvalho Chehab * enabled channels, pick the 0th channel. 946ee4a77a3SMauro Carvalho Chehab */ 947ee4a77a3SMauro Carvalho Chehab if (formats[i].num_ch < sdr->num_hw_ch) { 948ee4a77a3SMauro Carvalho Chehab sdr->cur_ch_mask = BIT(0); 949ee4a77a3SMauro Carvalho Chehab sdr->num_cur_ch = formats[i].num_ch; 950ee4a77a3SMauro Carvalho Chehab } else { 951ee4a77a3SMauro Carvalho Chehab sdr->cur_ch_mask = sdr->hw_ch_mask; 952ee4a77a3SMauro Carvalho Chehab sdr->num_cur_ch = sdr->num_hw_ch; 953ee4a77a3SMauro Carvalho Chehab } 954ee4a77a3SMauro Carvalho Chehab 955ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "cur: idx %u mask %lu num %u\n", 956ee4a77a3SMauro Carvalho Chehab i, sdr->cur_ch_mask, sdr->num_cur_ch); 957ee4a77a3SMauro Carvalho Chehab 958ee4a77a3SMauro Carvalho Chehab return 0; 959ee4a77a3SMauro Carvalho Chehab } 960ee4a77a3SMauro Carvalho Chehab 961ee4a77a3SMauro Carvalho Chehab static int rcar_drif_try_fmt_sdr_cap(struct file *file, void *priv, 962ee4a77a3SMauro Carvalho Chehab struct v4l2_format *f) 963ee4a77a3SMauro Carvalho Chehab { 964ee4a77a3SMauro Carvalho Chehab unsigned int i; 965ee4a77a3SMauro Carvalho Chehab 966ee4a77a3SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(formats); i++) { 967ee4a77a3SMauro Carvalho Chehab if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { 968ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.buffersize = formats[i].buffersize; 969ee4a77a3SMauro Carvalho Chehab return 0; 970ee4a77a3SMauro Carvalho Chehab } 971ee4a77a3SMauro Carvalho Chehab } 972ee4a77a3SMauro Carvalho Chehab 973ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.pixelformat = formats[0].pixelformat; 974ee4a77a3SMauro Carvalho Chehab f->fmt.sdr.buffersize = formats[0].buffersize; 975ee4a77a3SMauro Carvalho Chehab memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); 976ee4a77a3SMauro Carvalho Chehab 977ee4a77a3SMauro Carvalho Chehab return 0; 978ee4a77a3SMauro Carvalho Chehab } 979ee4a77a3SMauro Carvalho Chehab 980ee4a77a3SMauro Carvalho Chehab /* Tuner subdev ioctls */ 981ee4a77a3SMauro Carvalho Chehab static int rcar_drif_enum_freq_bands(struct file *file, void *priv, 982ee4a77a3SMauro Carvalho Chehab struct v4l2_frequency_band *band) 983ee4a77a3SMauro Carvalho Chehab { 984ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 985ee4a77a3SMauro Carvalho Chehab 986ee4a77a3SMauro Carvalho Chehab return v4l2_subdev_call(sdr->ep.subdev, tuner, enum_freq_bands, band); 987ee4a77a3SMauro Carvalho Chehab } 988ee4a77a3SMauro Carvalho Chehab 989ee4a77a3SMauro Carvalho Chehab static int rcar_drif_g_frequency(struct file *file, void *priv, 990ee4a77a3SMauro Carvalho Chehab struct v4l2_frequency *f) 991ee4a77a3SMauro Carvalho Chehab { 992ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 993ee4a77a3SMauro Carvalho Chehab 994ee4a77a3SMauro Carvalho Chehab return v4l2_subdev_call(sdr->ep.subdev, tuner, g_frequency, f); 995ee4a77a3SMauro Carvalho Chehab } 996ee4a77a3SMauro Carvalho Chehab 997ee4a77a3SMauro Carvalho Chehab static int rcar_drif_s_frequency(struct file *file, void *priv, 998ee4a77a3SMauro Carvalho Chehab const struct v4l2_frequency *f) 999ee4a77a3SMauro Carvalho Chehab { 1000ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 1001ee4a77a3SMauro Carvalho Chehab 1002ee4a77a3SMauro Carvalho Chehab return v4l2_subdev_call(sdr->ep.subdev, tuner, s_frequency, f); 1003ee4a77a3SMauro Carvalho Chehab } 1004ee4a77a3SMauro Carvalho Chehab 1005ee4a77a3SMauro Carvalho Chehab static int rcar_drif_g_tuner(struct file *file, void *priv, 1006ee4a77a3SMauro Carvalho Chehab struct v4l2_tuner *vt) 1007ee4a77a3SMauro Carvalho Chehab { 1008ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 1009ee4a77a3SMauro Carvalho Chehab 1010ee4a77a3SMauro Carvalho Chehab return v4l2_subdev_call(sdr->ep.subdev, tuner, g_tuner, vt); 1011ee4a77a3SMauro Carvalho Chehab } 1012ee4a77a3SMauro Carvalho Chehab 1013ee4a77a3SMauro Carvalho Chehab static int rcar_drif_s_tuner(struct file *file, void *priv, 1014ee4a77a3SMauro Carvalho Chehab const struct v4l2_tuner *vt) 1015ee4a77a3SMauro Carvalho Chehab { 1016ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file); 1017ee4a77a3SMauro Carvalho Chehab 1018ee4a77a3SMauro Carvalho Chehab return v4l2_subdev_call(sdr->ep.subdev, tuner, s_tuner, vt); 1019ee4a77a3SMauro Carvalho Chehab } 1020ee4a77a3SMauro Carvalho Chehab 1021ee4a77a3SMauro Carvalho Chehab static const struct v4l2_ioctl_ops rcar_drif_ioctl_ops = { 1022ee4a77a3SMauro Carvalho Chehab .vidioc_querycap = rcar_drif_querycap, 1023ee4a77a3SMauro Carvalho Chehab 1024ee4a77a3SMauro Carvalho Chehab .vidioc_enum_fmt_sdr_cap = rcar_drif_enum_fmt_sdr_cap, 1025ee4a77a3SMauro Carvalho Chehab .vidioc_g_fmt_sdr_cap = rcar_drif_g_fmt_sdr_cap, 1026ee4a77a3SMauro Carvalho Chehab .vidioc_s_fmt_sdr_cap = rcar_drif_s_fmt_sdr_cap, 1027ee4a77a3SMauro Carvalho Chehab .vidioc_try_fmt_sdr_cap = rcar_drif_try_fmt_sdr_cap, 1028ee4a77a3SMauro Carvalho Chehab 1029ee4a77a3SMauro Carvalho Chehab .vidioc_reqbufs = vb2_ioctl_reqbufs, 1030ee4a77a3SMauro Carvalho Chehab .vidioc_create_bufs = vb2_ioctl_create_bufs, 1031ee4a77a3SMauro Carvalho Chehab .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 1032ee4a77a3SMauro Carvalho Chehab .vidioc_querybuf = vb2_ioctl_querybuf, 1033ee4a77a3SMauro Carvalho Chehab .vidioc_qbuf = vb2_ioctl_qbuf, 1034ee4a77a3SMauro Carvalho Chehab .vidioc_dqbuf = vb2_ioctl_dqbuf, 1035ee4a77a3SMauro Carvalho Chehab 1036ee4a77a3SMauro Carvalho Chehab .vidioc_streamon = vb2_ioctl_streamon, 1037ee4a77a3SMauro Carvalho Chehab .vidioc_streamoff = vb2_ioctl_streamoff, 1038ee4a77a3SMauro Carvalho Chehab 1039ee4a77a3SMauro Carvalho Chehab .vidioc_s_frequency = rcar_drif_s_frequency, 1040ee4a77a3SMauro Carvalho Chehab .vidioc_g_frequency = rcar_drif_g_frequency, 1041ee4a77a3SMauro Carvalho Chehab .vidioc_s_tuner = rcar_drif_s_tuner, 1042ee4a77a3SMauro Carvalho Chehab .vidioc_g_tuner = rcar_drif_g_tuner, 1043ee4a77a3SMauro Carvalho Chehab .vidioc_enum_freq_bands = rcar_drif_enum_freq_bands, 1044ee4a77a3SMauro Carvalho Chehab .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1045ee4a77a3SMauro Carvalho Chehab .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1046ee4a77a3SMauro Carvalho Chehab .vidioc_log_status = v4l2_ctrl_log_status, 1047ee4a77a3SMauro Carvalho Chehab }; 1048ee4a77a3SMauro Carvalho Chehab 1049ee4a77a3SMauro Carvalho Chehab static const struct v4l2_file_operations rcar_drif_fops = { 1050ee4a77a3SMauro Carvalho Chehab .owner = THIS_MODULE, 1051ee4a77a3SMauro Carvalho Chehab .open = v4l2_fh_open, 1052ee4a77a3SMauro Carvalho Chehab .release = vb2_fop_release, 1053ee4a77a3SMauro Carvalho Chehab .read = vb2_fop_read, 1054ee4a77a3SMauro Carvalho Chehab .poll = vb2_fop_poll, 1055ee4a77a3SMauro Carvalho Chehab .mmap = vb2_fop_mmap, 1056ee4a77a3SMauro Carvalho Chehab .unlocked_ioctl = video_ioctl2, 1057ee4a77a3SMauro Carvalho Chehab }; 1058ee4a77a3SMauro Carvalho Chehab 1059ee4a77a3SMauro Carvalho Chehab static int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr) 1060ee4a77a3SMauro Carvalho Chehab { 1061ee4a77a3SMauro Carvalho Chehab int ret; 1062ee4a77a3SMauro Carvalho Chehab 1063ee4a77a3SMauro Carvalho Chehab /* Init video_device structure */ 1064ee4a77a3SMauro Carvalho Chehab sdr->vdev = video_device_alloc(); 1065ee4a77a3SMauro Carvalho Chehab if (!sdr->vdev) 1066ee4a77a3SMauro Carvalho Chehab return -ENOMEM; 1067ee4a77a3SMauro Carvalho Chehab 1068ee4a77a3SMauro Carvalho Chehab snprintf(sdr->vdev->name, sizeof(sdr->vdev->name), "R-Car DRIF"); 1069ee4a77a3SMauro Carvalho Chehab sdr->vdev->fops = &rcar_drif_fops; 1070ee4a77a3SMauro Carvalho Chehab sdr->vdev->ioctl_ops = &rcar_drif_ioctl_ops; 1071ee4a77a3SMauro Carvalho Chehab sdr->vdev->release = video_device_release; 1072ee4a77a3SMauro Carvalho Chehab sdr->vdev->lock = &sdr->v4l2_mutex; 1073ee4a77a3SMauro Carvalho Chehab sdr->vdev->queue = &sdr->vb_queue; 1074ee4a77a3SMauro Carvalho Chehab sdr->vdev->queue->lock = &sdr->vb_queue_mutex; 1075ee4a77a3SMauro Carvalho Chehab sdr->vdev->ctrl_handler = &sdr->ctrl_hdl; 1076ee4a77a3SMauro Carvalho Chehab sdr->vdev->v4l2_dev = &sdr->v4l2_dev; 1077ee4a77a3SMauro Carvalho Chehab sdr->vdev->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER | 1078ee4a77a3SMauro Carvalho Chehab V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; 1079ee4a77a3SMauro Carvalho Chehab video_set_drvdata(sdr->vdev, sdr); 1080ee4a77a3SMauro Carvalho Chehab 1081ee4a77a3SMauro Carvalho Chehab /* Register V4L2 SDR device */ 1082ee4a77a3SMauro Carvalho Chehab ret = video_register_device(sdr->vdev, VFL_TYPE_SDR, -1); 1083ee4a77a3SMauro Carvalho Chehab if (ret) { 1084ee4a77a3SMauro Carvalho Chehab video_device_release(sdr->vdev); 1085ee4a77a3SMauro Carvalho Chehab sdr->vdev = NULL; 1086ee4a77a3SMauro Carvalho Chehab dev_err(sdr->dev, "failed video_register_device (%d)\n", ret); 1087ee4a77a3SMauro Carvalho Chehab } 1088ee4a77a3SMauro Carvalho Chehab 1089ee4a77a3SMauro Carvalho Chehab return ret; 1090ee4a77a3SMauro Carvalho Chehab } 1091ee4a77a3SMauro Carvalho Chehab 1092ee4a77a3SMauro Carvalho Chehab static void rcar_drif_sdr_unregister(struct rcar_drif_sdr *sdr) 1093ee4a77a3SMauro Carvalho Chehab { 1094ee4a77a3SMauro Carvalho Chehab video_unregister_device(sdr->vdev); 1095ee4a77a3SMauro Carvalho Chehab sdr->vdev = NULL; 1096ee4a77a3SMauro Carvalho Chehab } 1097ee4a77a3SMauro Carvalho Chehab 1098ee4a77a3SMauro Carvalho Chehab /* Sub-device bound callback */ 1099ee4a77a3SMauro Carvalho Chehab static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier, 1100ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev *subdev, 1101*adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 1102ee4a77a3SMauro Carvalho Chehab { 1103ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = 1104ee4a77a3SMauro Carvalho Chehab container_of(notifier, struct rcar_drif_sdr, notifier); 1105ee4a77a3SMauro Carvalho Chehab 1106ee4a77a3SMauro Carvalho Chehab v4l2_set_subdev_hostdata(subdev, sdr); 1107ee4a77a3SMauro Carvalho Chehab sdr->ep.subdev = subdev; 1108ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "bound asd %s\n", subdev->name); 1109ee4a77a3SMauro Carvalho Chehab 1110ee4a77a3SMauro Carvalho Chehab return 0; 1111ee4a77a3SMauro Carvalho Chehab } 1112ee4a77a3SMauro Carvalho Chehab 1113ee4a77a3SMauro Carvalho Chehab /* Sub-device unbind callback */ 1114ee4a77a3SMauro Carvalho Chehab static void rcar_drif_notify_unbind(struct v4l2_async_notifier *notifier, 1115ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev *subdev, 1116*adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 1117ee4a77a3SMauro Carvalho Chehab { 1118ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = 1119ee4a77a3SMauro Carvalho Chehab container_of(notifier, struct rcar_drif_sdr, notifier); 1120ee4a77a3SMauro Carvalho Chehab 1121ee4a77a3SMauro Carvalho Chehab if (sdr->ep.subdev != subdev) { 1122ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "subdev %s is not bound\n", subdev->name); 1123ee4a77a3SMauro Carvalho Chehab return; 1124ee4a77a3SMauro Carvalho Chehab } 1125ee4a77a3SMauro Carvalho Chehab 1126ee4a77a3SMauro Carvalho Chehab /* Free ctrl handler if initialized */ 1127ee4a77a3SMauro Carvalho Chehab v4l2_ctrl_handler_free(&sdr->ctrl_hdl); 1128ee4a77a3SMauro Carvalho Chehab sdr->v4l2_dev.ctrl_handler = NULL; 1129ee4a77a3SMauro Carvalho Chehab sdr->ep.subdev = NULL; 1130ee4a77a3SMauro Carvalho Chehab 1131ee4a77a3SMauro Carvalho Chehab rcar_drif_sdr_unregister(sdr); 1132ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "unbind asd %s\n", subdev->name); 1133ee4a77a3SMauro Carvalho Chehab } 1134ee4a77a3SMauro Carvalho Chehab 1135ee4a77a3SMauro Carvalho Chehab /* Sub-device registered notification callback */ 1136ee4a77a3SMauro Carvalho Chehab static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier) 1137ee4a77a3SMauro Carvalho Chehab { 1138ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = 1139ee4a77a3SMauro Carvalho Chehab container_of(notifier, struct rcar_drif_sdr, notifier); 1140ee4a77a3SMauro Carvalho Chehab int ret; 1141ee4a77a3SMauro Carvalho Chehab 1142ee4a77a3SMauro Carvalho Chehab /* 1143ee4a77a3SMauro Carvalho Chehab * The subdev tested at this point uses 4 controls. Using 10 as a worst 1144ee4a77a3SMauro Carvalho Chehab * case scenario hint. When less controls are needed there will be some 1145ee4a77a3SMauro Carvalho Chehab * unused memory and when more controls are needed the framework uses 1146ee4a77a3SMauro Carvalho Chehab * hash to manage controls within this number. 1147ee4a77a3SMauro Carvalho Chehab */ 1148ee4a77a3SMauro Carvalho Chehab ret = v4l2_ctrl_handler_init(&sdr->ctrl_hdl, 10); 1149ee4a77a3SMauro Carvalho Chehab if (ret) 1150ee4a77a3SMauro Carvalho Chehab return -ENOMEM; 1151ee4a77a3SMauro Carvalho Chehab 1152ee4a77a3SMauro Carvalho Chehab sdr->v4l2_dev.ctrl_handler = &sdr->ctrl_hdl; 1153ee4a77a3SMauro Carvalho Chehab ret = v4l2_device_register_subdev_nodes(&sdr->v4l2_dev); 1154ee4a77a3SMauro Carvalho Chehab if (ret) { 1155ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "failed: register subdev nodes ret %d\n", ret); 1156ee4a77a3SMauro Carvalho Chehab goto error; 1157ee4a77a3SMauro Carvalho Chehab } 1158ee4a77a3SMauro Carvalho Chehab 1159ee4a77a3SMauro Carvalho Chehab ret = v4l2_ctrl_add_handler(&sdr->ctrl_hdl, 1160ee4a77a3SMauro Carvalho Chehab sdr->ep.subdev->ctrl_handler, NULL, true); 1161ee4a77a3SMauro Carvalho Chehab if (ret) { 1162ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "failed: ctrl add hdlr ret %d\n", ret); 1163ee4a77a3SMauro Carvalho Chehab goto error; 1164ee4a77a3SMauro Carvalho Chehab } 1165ee4a77a3SMauro Carvalho Chehab 1166ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_sdr_register(sdr); 1167ee4a77a3SMauro Carvalho Chehab if (ret) 1168ee4a77a3SMauro Carvalho Chehab goto error; 1169ee4a77a3SMauro Carvalho Chehab 1170ee4a77a3SMauro Carvalho Chehab return ret; 1171ee4a77a3SMauro Carvalho Chehab 1172ee4a77a3SMauro Carvalho Chehab error: 1173ee4a77a3SMauro Carvalho Chehab v4l2_ctrl_handler_free(&sdr->ctrl_hdl); 1174ee4a77a3SMauro Carvalho Chehab 1175ee4a77a3SMauro Carvalho Chehab return ret; 1176ee4a77a3SMauro Carvalho Chehab } 1177ee4a77a3SMauro Carvalho Chehab 1178ee4a77a3SMauro Carvalho Chehab static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = { 1179ee4a77a3SMauro Carvalho Chehab .bound = rcar_drif_notify_bound, 1180ee4a77a3SMauro Carvalho Chehab .unbind = rcar_drif_notify_unbind, 1181ee4a77a3SMauro Carvalho Chehab .complete = rcar_drif_notify_complete, 1182ee4a77a3SMauro Carvalho Chehab }; 1183ee4a77a3SMauro Carvalho Chehab 1184ee4a77a3SMauro Carvalho Chehab /* Read endpoint properties */ 1185ee4a77a3SMauro Carvalho Chehab static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr, 1186ee4a77a3SMauro Carvalho Chehab struct fwnode_handle *fwnode) 1187ee4a77a3SMauro Carvalho Chehab { 1188ee4a77a3SMauro Carvalho Chehab u32 val; 1189ee4a77a3SMauro Carvalho Chehab 1190ee4a77a3SMauro Carvalho Chehab /* Set the I2S defaults for SIRMDR1*/ 1191ee4a77a3SMauro Carvalho Chehab sdr->mdr1 = RCAR_DRIF_SIRMDR1_SYNCMD_LR | RCAR_DRIF_SIRMDR1_MSB_FIRST | 1192ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_SIRMDR1_DTDL_1 | RCAR_DRIF_SIRMDR1_SYNCDL_0; 1193ee4a77a3SMauro Carvalho Chehab 1194ee4a77a3SMauro Carvalho Chehab /* Parse sync polarity from endpoint */ 1195ee4a77a3SMauro Carvalho Chehab if (!fwnode_property_read_u32(fwnode, "sync-active", &val)) 1196ee4a77a3SMauro Carvalho Chehab sdr->mdr1 |= val ? RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH : 1197ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_SIRMDR1_SYNCAC_POL_LOW; 1198ee4a77a3SMauro Carvalho Chehab else 1199ee4a77a3SMauro Carvalho Chehab sdr->mdr1 |= RCAR_DRIF_SIRMDR1_SYNCAC_POL_HIGH; /* default */ 1200ee4a77a3SMauro Carvalho Chehab 1201ee4a77a3SMauro Carvalho Chehab dev_dbg(sdr->dev, "mdr1 0x%08x\n", sdr->mdr1); 1202ee4a77a3SMauro Carvalho Chehab } 1203ee4a77a3SMauro Carvalho Chehab 1204ee4a77a3SMauro Carvalho Chehab /* Parse sub-devs (tuner) to find a matching device */ 1205ee4a77a3SMauro Carvalho Chehab static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr) 1206ee4a77a3SMauro Carvalho Chehab { 1207ee4a77a3SMauro Carvalho Chehab struct v4l2_async_notifier *notifier = &sdr->notifier; 1208ee4a77a3SMauro Carvalho Chehab struct fwnode_handle *fwnode, *ep; 1209*adb2dcd5SSakari Ailus struct v4l2_async_connection *asd; 1210ee4a77a3SMauro Carvalho Chehab 1211ee4a77a3SMauro Carvalho Chehab v4l2_async_nf_init(notifier); 1212ee4a77a3SMauro Carvalho Chehab 1213ee4a77a3SMauro Carvalho Chehab ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(sdr->dev->of_node), 1214ee4a77a3SMauro Carvalho Chehab NULL); 1215ee4a77a3SMauro Carvalho Chehab if (!ep) 1216ee4a77a3SMauro Carvalho Chehab return 0; 1217ee4a77a3SMauro Carvalho Chehab 1218ee4a77a3SMauro Carvalho Chehab /* Get the endpoint properties */ 1219ee4a77a3SMauro Carvalho Chehab rcar_drif_get_ep_properties(sdr, ep); 1220ee4a77a3SMauro Carvalho Chehab 1221ee4a77a3SMauro Carvalho Chehab fwnode = fwnode_graph_get_remote_port_parent(ep); 1222ee4a77a3SMauro Carvalho Chehab fwnode_handle_put(ep); 1223ee4a77a3SMauro Carvalho Chehab if (!fwnode) { 1224ee4a77a3SMauro Carvalho Chehab dev_warn(sdr->dev, "bad remote port parent\n"); 1225ee4a77a3SMauro Carvalho Chehab return -EINVAL; 1226ee4a77a3SMauro Carvalho Chehab } 1227ee4a77a3SMauro Carvalho Chehab 1228ee4a77a3SMauro Carvalho Chehab asd = v4l2_async_nf_add_fwnode(notifier, fwnode, 1229*adb2dcd5SSakari Ailus struct v4l2_async_connection); 1230ee4a77a3SMauro Carvalho Chehab fwnode_handle_put(fwnode); 1231ee4a77a3SMauro Carvalho Chehab if (IS_ERR(asd)) 1232ee4a77a3SMauro Carvalho Chehab return PTR_ERR(asd); 1233ee4a77a3SMauro Carvalho Chehab 1234ee4a77a3SMauro Carvalho Chehab return 0; 1235ee4a77a3SMauro Carvalho Chehab } 1236ee4a77a3SMauro Carvalho Chehab 1237ee4a77a3SMauro Carvalho Chehab /* Check if the given device is the primary bond */ 1238ee4a77a3SMauro Carvalho Chehab static bool rcar_drif_primary_bond(struct platform_device *pdev) 1239ee4a77a3SMauro Carvalho Chehab { 1240ee4a77a3SMauro Carvalho Chehab return of_property_read_bool(pdev->dev.of_node, "renesas,primary-bond"); 1241ee4a77a3SMauro Carvalho Chehab } 1242ee4a77a3SMauro Carvalho Chehab 1243ee4a77a3SMauro Carvalho Chehab /* Check if both devices of the bond are enabled */ 1244ee4a77a3SMauro Carvalho Chehab static struct device_node *rcar_drif_bond_enabled(struct platform_device *p) 1245ee4a77a3SMauro Carvalho Chehab { 1246ee4a77a3SMauro Carvalho Chehab struct device_node *np; 1247ee4a77a3SMauro Carvalho Chehab 1248ee4a77a3SMauro Carvalho Chehab np = of_parse_phandle(p->dev.of_node, "renesas,bonding", 0); 1249ee4a77a3SMauro Carvalho Chehab if (np && of_device_is_available(np)) 1250ee4a77a3SMauro Carvalho Chehab return np; 1251ee4a77a3SMauro Carvalho Chehab 1252ee4a77a3SMauro Carvalho Chehab return NULL; 1253ee4a77a3SMauro Carvalho Chehab } 1254ee4a77a3SMauro Carvalho Chehab 1255ee4a77a3SMauro Carvalho Chehab /* Check if the bonded device is probed */ 1256ee4a77a3SMauro Carvalho Chehab static int rcar_drif_bond_available(struct rcar_drif_sdr *sdr, 1257ee4a77a3SMauro Carvalho Chehab struct device_node *np) 1258ee4a77a3SMauro Carvalho Chehab { 1259ee4a77a3SMauro Carvalho Chehab struct platform_device *pdev; 1260ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch; 1261ee4a77a3SMauro Carvalho Chehab int ret = 0; 1262ee4a77a3SMauro Carvalho Chehab 1263ee4a77a3SMauro Carvalho Chehab pdev = of_find_device_by_node(np); 1264ee4a77a3SMauro Carvalho Chehab if (!pdev) { 1265ee4a77a3SMauro Carvalho Chehab dev_err(sdr->dev, "failed to get bonded device from node\n"); 1266ee4a77a3SMauro Carvalho Chehab return -ENODEV; 1267ee4a77a3SMauro Carvalho Chehab } 1268ee4a77a3SMauro Carvalho Chehab 1269ee4a77a3SMauro Carvalho Chehab device_lock(&pdev->dev); 1270ee4a77a3SMauro Carvalho Chehab ch = platform_get_drvdata(pdev); 1271ee4a77a3SMauro Carvalho Chehab if (ch) { 1272ee4a77a3SMauro Carvalho Chehab /* Update sdr data in the bonded device */ 1273ee4a77a3SMauro Carvalho Chehab ch->sdr = sdr; 1274ee4a77a3SMauro Carvalho Chehab 1275ee4a77a3SMauro Carvalho Chehab /* Update sdr with bonded device data */ 1276ee4a77a3SMauro Carvalho Chehab sdr->ch[ch->num] = ch; 1277ee4a77a3SMauro Carvalho Chehab sdr->hw_ch_mask |= BIT(ch->num); 1278ee4a77a3SMauro Carvalho Chehab } else { 1279ee4a77a3SMauro Carvalho Chehab /* Defer */ 1280ee4a77a3SMauro Carvalho Chehab dev_info(sdr->dev, "defer probe\n"); 1281ee4a77a3SMauro Carvalho Chehab ret = -EPROBE_DEFER; 1282ee4a77a3SMauro Carvalho Chehab } 1283ee4a77a3SMauro Carvalho Chehab device_unlock(&pdev->dev); 1284ee4a77a3SMauro Carvalho Chehab 1285ee4a77a3SMauro Carvalho Chehab put_device(&pdev->dev); 1286ee4a77a3SMauro Carvalho Chehab 1287ee4a77a3SMauro Carvalho Chehab return ret; 1288ee4a77a3SMauro Carvalho Chehab } 1289ee4a77a3SMauro Carvalho Chehab 1290ee4a77a3SMauro Carvalho Chehab /* V4L2 SDR device probe */ 1291ee4a77a3SMauro Carvalho Chehab static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) 1292ee4a77a3SMauro Carvalho Chehab { 1293ee4a77a3SMauro Carvalho Chehab int ret; 1294ee4a77a3SMauro Carvalho Chehab 1295ee4a77a3SMauro Carvalho Chehab /* Validate any supported format for enabled channels */ 1296ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_set_default_format(sdr); 1297ee4a77a3SMauro Carvalho Chehab if (ret) { 1298ee4a77a3SMauro Carvalho Chehab dev_err(sdr->dev, "failed to set default format\n"); 1299ee4a77a3SMauro Carvalho Chehab return ret; 1300ee4a77a3SMauro Carvalho Chehab } 1301ee4a77a3SMauro Carvalho Chehab 1302ee4a77a3SMauro Carvalho Chehab /* Set defaults */ 1303ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size = RCAR_DRIF_DEFAULT_HWBUF_SIZE; 1304ee4a77a3SMauro Carvalho Chehab 1305ee4a77a3SMauro Carvalho Chehab mutex_init(&sdr->v4l2_mutex); 1306ee4a77a3SMauro Carvalho Chehab mutex_init(&sdr->vb_queue_mutex); 1307ee4a77a3SMauro Carvalho Chehab spin_lock_init(&sdr->queued_bufs_lock); 1308ee4a77a3SMauro Carvalho Chehab spin_lock_init(&sdr->dma_lock); 1309ee4a77a3SMauro Carvalho Chehab INIT_LIST_HEAD(&sdr->queued_bufs); 1310ee4a77a3SMauro Carvalho Chehab 1311ee4a77a3SMauro Carvalho Chehab /* Init videobuf2 queue structure */ 1312ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; 1313ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; 1314ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.drv_priv = sdr; 1315ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.buf_struct_size = sizeof(struct rcar_drif_frame_buf); 1316ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.ops = &rcar_drif_vb2_ops; 1317ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.mem_ops = &vb2_vmalloc_memops; 1318ee4a77a3SMauro Carvalho Chehab sdr->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1319ee4a77a3SMauro Carvalho Chehab 1320ee4a77a3SMauro Carvalho Chehab /* Init videobuf2 queue */ 1321ee4a77a3SMauro Carvalho Chehab ret = vb2_queue_init(&sdr->vb_queue); 1322ee4a77a3SMauro Carvalho Chehab if (ret) { 1323ee4a77a3SMauro Carvalho Chehab dev_err(sdr->dev, "failed: vb2_queue_init ret %d\n", ret); 1324ee4a77a3SMauro Carvalho Chehab return ret; 1325ee4a77a3SMauro Carvalho Chehab } 1326ee4a77a3SMauro Carvalho Chehab 1327ee4a77a3SMauro Carvalho Chehab /* Register the v4l2_device */ 1328ee4a77a3SMauro Carvalho Chehab ret = v4l2_device_register(sdr->dev, &sdr->v4l2_dev); 1329ee4a77a3SMauro Carvalho Chehab if (ret) { 1330ee4a77a3SMauro Carvalho Chehab dev_err(sdr->dev, "failed: v4l2_device_register ret %d\n", ret); 1331ee4a77a3SMauro Carvalho Chehab return ret; 1332ee4a77a3SMauro Carvalho Chehab } 1333ee4a77a3SMauro Carvalho Chehab 1334ee4a77a3SMauro Carvalho Chehab /* 1335ee4a77a3SMauro Carvalho Chehab * Parse subdevs after v4l2_device_register because if the subdev 1336ee4a77a3SMauro Carvalho Chehab * is already probed, bound and complete will be called immediately 1337ee4a77a3SMauro Carvalho Chehab */ 1338ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_parse_subdevs(sdr); 1339ee4a77a3SMauro Carvalho Chehab if (ret) 1340ee4a77a3SMauro Carvalho Chehab goto error; 1341ee4a77a3SMauro Carvalho Chehab 1342ee4a77a3SMauro Carvalho Chehab sdr->notifier.ops = &rcar_drif_notify_ops; 1343ee4a77a3SMauro Carvalho Chehab 1344ee4a77a3SMauro Carvalho Chehab /* Register notifier */ 1345ee4a77a3SMauro Carvalho Chehab ret = v4l2_async_nf_register(&sdr->v4l2_dev, &sdr->notifier); 1346ee4a77a3SMauro Carvalho Chehab if (ret < 0) { 1347ee4a77a3SMauro Carvalho Chehab dev_err(sdr->dev, "failed: notifier register ret %d\n", ret); 1348ee4a77a3SMauro Carvalho Chehab goto cleanup; 1349ee4a77a3SMauro Carvalho Chehab } 1350ee4a77a3SMauro Carvalho Chehab 1351ee4a77a3SMauro Carvalho Chehab return ret; 1352ee4a77a3SMauro Carvalho Chehab 1353ee4a77a3SMauro Carvalho Chehab cleanup: 1354ee4a77a3SMauro Carvalho Chehab v4l2_async_nf_cleanup(&sdr->notifier); 1355ee4a77a3SMauro Carvalho Chehab error: 1356ee4a77a3SMauro Carvalho Chehab v4l2_device_unregister(&sdr->v4l2_dev); 1357ee4a77a3SMauro Carvalho Chehab 1358ee4a77a3SMauro Carvalho Chehab return ret; 1359ee4a77a3SMauro Carvalho Chehab } 1360ee4a77a3SMauro Carvalho Chehab 1361ee4a77a3SMauro Carvalho Chehab /* V4L2 SDR device remove */ 1362ee4a77a3SMauro Carvalho Chehab static void rcar_drif_sdr_remove(struct rcar_drif_sdr *sdr) 1363ee4a77a3SMauro Carvalho Chehab { 1364ee4a77a3SMauro Carvalho Chehab v4l2_async_nf_unregister(&sdr->notifier); 1365ee4a77a3SMauro Carvalho Chehab v4l2_async_nf_cleanup(&sdr->notifier); 1366ee4a77a3SMauro Carvalho Chehab v4l2_device_unregister(&sdr->v4l2_dev); 1367ee4a77a3SMauro Carvalho Chehab } 1368ee4a77a3SMauro Carvalho Chehab 1369ee4a77a3SMauro Carvalho Chehab /* DRIF channel probe */ 1370ee4a77a3SMauro Carvalho Chehab static int rcar_drif_probe(struct platform_device *pdev) 1371ee4a77a3SMauro Carvalho Chehab { 1372ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr; 1373ee4a77a3SMauro Carvalho Chehab struct device_node *np; 1374ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch; 1375ee4a77a3SMauro Carvalho Chehab struct resource *res; 1376ee4a77a3SMauro Carvalho Chehab int ret; 1377ee4a77a3SMauro Carvalho Chehab 1378ee4a77a3SMauro Carvalho Chehab /* Reserve memory for enabled channel */ 1379ee4a77a3SMauro Carvalho Chehab ch = devm_kzalloc(&pdev->dev, sizeof(*ch), GFP_KERNEL); 1380ee4a77a3SMauro Carvalho Chehab if (!ch) 1381ee4a77a3SMauro Carvalho Chehab return -ENOMEM; 1382ee4a77a3SMauro Carvalho Chehab 1383ee4a77a3SMauro Carvalho Chehab ch->pdev = pdev; 1384ee4a77a3SMauro Carvalho Chehab 1385ee4a77a3SMauro Carvalho Chehab /* Module clock */ 1386ee4a77a3SMauro Carvalho Chehab ch->clk = devm_clk_get(&pdev->dev, "fck"); 1387ee4a77a3SMauro Carvalho Chehab if (IS_ERR(ch->clk)) { 1388ee4a77a3SMauro Carvalho Chehab ret = PTR_ERR(ch->clk); 1389ee4a77a3SMauro Carvalho Chehab dev_err(&pdev->dev, "clk get failed (%d)\n", ret); 1390ee4a77a3SMauro Carvalho Chehab return ret; 1391ee4a77a3SMauro Carvalho Chehab } 1392ee4a77a3SMauro Carvalho Chehab 1393ee4a77a3SMauro Carvalho Chehab /* Register map */ 1394ee4a77a3SMauro Carvalho Chehab ch->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 1395ee4a77a3SMauro Carvalho Chehab if (IS_ERR(ch->base)) 1396ee4a77a3SMauro Carvalho Chehab return PTR_ERR(ch->base); 1397ee4a77a3SMauro Carvalho Chehab 1398ee4a77a3SMauro Carvalho Chehab ch->start = res->start; 1399ee4a77a3SMauro Carvalho Chehab platform_set_drvdata(pdev, ch); 1400ee4a77a3SMauro Carvalho Chehab 1401ee4a77a3SMauro Carvalho Chehab /* Check if both channels of the bond are enabled */ 1402ee4a77a3SMauro Carvalho Chehab np = rcar_drif_bond_enabled(pdev); 1403ee4a77a3SMauro Carvalho Chehab if (np) { 1404ee4a77a3SMauro Carvalho Chehab /* Check if current channel acting as primary-bond */ 1405ee4a77a3SMauro Carvalho Chehab if (!rcar_drif_primary_bond(pdev)) { 1406ee4a77a3SMauro Carvalho Chehab ch->num = 1; /* Primary bond is channel 0 always */ 1407ee4a77a3SMauro Carvalho Chehab of_node_put(np); 1408ee4a77a3SMauro Carvalho Chehab return 0; 1409ee4a77a3SMauro Carvalho Chehab } 1410ee4a77a3SMauro Carvalho Chehab } 1411ee4a77a3SMauro Carvalho Chehab 1412ee4a77a3SMauro Carvalho Chehab /* Reserve memory for SDR structure */ 1413ee4a77a3SMauro Carvalho Chehab sdr = devm_kzalloc(&pdev->dev, sizeof(*sdr), GFP_KERNEL); 1414ee4a77a3SMauro Carvalho Chehab if (!sdr) { 1415ee4a77a3SMauro Carvalho Chehab of_node_put(np); 1416ee4a77a3SMauro Carvalho Chehab return -ENOMEM; 1417ee4a77a3SMauro Carvalho Chehab } 1418ee4a77a3SMauro Carvalho Chehab ch->sdr = sdr; 1419ee4a77a3SMauro Carvalho Chehab sdr->dev = &pdev->dev; 1420ee4a77a3SMauro Carvalho Chehab 1421ee4a77a3SMauro Carvalho Chehab /* Establish links between SDR and channel(s) */ 1422ee4a77a3SMauro Carvalho Chehab sdr->ch[ch->num] = ch; 1423ee4a77a3SMauro Carvalho Chehab sdr->hw_ch_mask = BIT(ch->num); 1424ee4a77a3SMauro Carvalho Chehab if (np) { 1425ee4a77a3SMauro Carvalho Chehab /* Check if bonded device is ready */ 1426ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_bond_available(sdr, np); 1427ee4a77a3SMauro Carvalho Chehab of_node_put(np); 1428ee4a77a3SMauro Carvalho Chehab if (ret) 1429ee4a77a3SMauro Carvalho Chehab return ret; 1430ee4a77a3SMauro Carvalho Chehab } 1431ee4a77a3SMauro Carvalho Chehab sdr->num_hw_ch = hweight_long(sdr->hw_ch_mask); 1432ee4a77a3SMauro Carvalho Chehab 1433ee4a77a3SMauro Carvalho Chehab return rcar_drif_sdr_probe(sdr); 1434ee4a77a3SMauro Carvalho Chehab } 1435ee4a77a3SMauro Carvalho Chehab 1436ee4a77a3SMauro Carvalho Chehab /* DRIF channel remove */ 14372ff72c6cSUwe Kleine-König static void rcar_drif_remove(struct platform_device *pdev) 1438ee4a77a3SMauro Carvalho Chehab { 1439ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch = platform_get_drvdata(pdev); 1440ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr; 1441ee4a77a3SMauro Carvalho Chehab 1442ee4a77a3SMauro Carvalho Chehab /* Channel 0 will be the SDR instance */ 1443ee4a77a3SMauro Carvalho Chehab if (ch->num) 14442ff72c6cSUwe Kleine-König return; 1445ee4a77a3SMauro Carvalho Chehab 1446ee4a77a3SMauro Carvalho Chehab /* SDR instance */ 1447ee4a77a3SMauro Carvalho Chehab rcar_drif_sdr_remove(sdr); 1448ee4a77a3SMauro Carvalho Chehab } 1449ee4a77a3SMauro Carvalho Chehab 1450ee4a77a3SMauro Carvalho Chehab /* FIXME: Implement suspend/resume support */ 1451ee4a77a3SMauro Carvalho Chehab static int __maybe_unused rcar_drif_suspend(struct device *dev) 1452ee4a77a3SMauro Carvalho Chehab { 1453ee4a77a3SMauro Carvalho Chehab return 0; 1454ee4a77a3SMauro Carvalho Chehab } 1455ee4a77a3SMauro Carvalho Chehab 1456ee4a77a3SMauro Carvalho Chehab static int __maybe_unused rcar_drif_resume(struct device *dev) 1457ee4a77a3SMauro Carvalho Chehab { 1458ee4a77a3SMauro Carvalho Chehab return 0; 1459ee4a77a3SMauro Carvalho Chehab } 1460ee4a77a3SMauro Carvalho Chehab 1461ee4a77a3SMauro Carvalho Chehab static SIMPLE_DEV_PM_OPS(rcar_drif_pm_ops, rcar_drif_suspend, 1462ee4a77a3SMauro Carvalho Chehab rcar_drif_resume); 1463ee4a77a3SMauro Carvalho Chehab 1464ee4a77a3SMauro Carvalho Chehab static const struct of_device_id rcar_drif_of_table[] = { 1465ee4a77a3SMauro Carvalho Chehab { .compatible = "renesas,rcar-gen3-drif" }, 1466ee4a77a3SMauro Carvalho Chehab { } 1467ee4a77a3SMauro Carvalho Chehab }; 1468ee4a77a3SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, rcar_drif_of_table); 1469ee4a77a3SMauro Carvalho Chehab 1470ee4a77a3SMauro Carvalho Chehab #define RCAR_DRIF_DRV_NAME "rcar_drif" 1471ee4a77a3SMauro Carvalho Chehab static struct platform_driver rcar_drif_driver = { 1472ee4a77a3SMauro Carvalho Chehab .driver = { 1473ee4a77a3SMauro Carvalho Chehab .name = RCAR_DRIF_DRV_NAME, 1474b73560c8SLaurent Pinchart .of_match_table = rcar_drif_of_table, 1475ee4a77a3SMauro Carvalho Chehab .pm = &rcar_drif_pm_ops, 1476ee4a77a3SMauro Carvalho Chehab }, 1477ee4a77a3SMauro Carvalho Chehab .probe = rcar_drif_probe, 14782ff72c6cSUwe Kleine-König .remove_new = rcar_drif_remove, 1479ee4a77a3SMauro Carvalho Chehab }; 1480ee4a77a3SMauro Carvalho Chehab 1481ee4a77a3SMauro Carvalho Chehab module_platform_driver(rcar_drif_driver); 1482ee4a77a3SMauro Carvalho Chehab 1483ee4a77a3SMauro Carvalho Chehab MODULE_DESCRIPTION("Renesas R-Car Gen3 DRIF driver"); 1484ee4a77a3SMauro Carvalho Chehab MODULE_ALIAS("platform:" RCAR_DRIF_DRV_NAME); 1485ee4a77a3SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 1486ee4a77a3SMauro Carvalho Chehab MODULE_AUTHOR("Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>"); 1487