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