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 */
rcar_drif_write(struct rcar_drif * ch,u32 offset,u32 data)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
rcar_drif_read(struct rcar_drif * ch,u32 offset)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 */
rcar_drif_release_dmachannels(struct rcar_drif_sdr * sdr)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 */
rcar_drif_alloc_dmachannels(struct rcar_drif_sdr * sdr)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 */
rcar_drif_release_queued_bufs(struct rcar_drif_sdr * sdr,enum vb2_buffer_state state)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 */
rcar_drif_set_mdr1(struct rcar_drif_sdr * sdr)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 */
rcar_drif_set_format(struct rcar_drif_sdr * sdr)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 */
rcar_drif_release_buf(struct rcar_drif_sdr * sdr)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 */
rcar_drif_request_buf(struct rcar_drif_sdr * sdr)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 */
rcar_drif_queue_setup(struct vb2_queue * vq,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])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);
427*36e3faf9SBenjamin Gaignard unsigned int q_num_bufs = vb2_get_num_buffers(vq);
428ee4a77a3SMauro Carvalho Chehab
429ee4a77a3SMauro Carvalho Chehab /* Need at least 16 buffers */
430*36e3faf9SBenjamin Gaignard if (q_num_bufs + *num_buffers < 16)
431*36e3faf9SBenjamin Gaignard *num_buffers = 16 - q_num_bufs;
432ee4a77a3SMauro Carvalho Chehab
433ee4a77a3SMauro Carvalho Chehab *num_planes = 1;
434ee4a77a3SMauro Carvalho Chehab sizes[0] = PAGE_ALIGN(sdr->fmt->buffersize);
435ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "num_bufs %d sizes[0] %d\n", *num_buffers, sizes[0]);
436ee4a77a3SMauro Carvalho Chehab
437ee4a77a3SMauro Carvalho Chehab return 0;
438ee4a77a3SMauro Carvalho Chehab }
439ee4a77a3SMauro Carvalho Chehab
440ee4a77a3SMauro Carvalho Chehab /* Enqueue buffer */
rcar_drif_buf_queue(struct vb2_buffer * vb)441ee4a77a3SMauro Carvalho Chehab static void rcar_drif_buf_queue(struct vb2_buffer *vb)
442ee4a77a3SMauro Carvalho Chehab {
443ee4a77a3SMauro Carvalho Chehab struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
444ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vb->vb2_queue);
445ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf =
446ee4a77a3SMauro Carvalho Chehab container_of(vbuf, struct rcar_drif_frame_buf, vb);
447ee4a77a3SMauro Carvalho Chehab unsigned long flags;
448ee4a77a3SMauro Carvalho Chehab
449ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "buf_queue idx %u\n", vb->index);
450ee4a77a3SMauro Carvalho Chehab spin_lock_irqsave(&sdr->queued_bufs_lock, flags);
451ee4a77a3SMauro Carvalho Chehab list_add_tail(&fbuf->list, &sdr->queued_bufs);
452ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags);
453ee4a77a3SMauro Carvalho Chehab }
454ee4a77a3SMauro Carvalho Chehab
455ee4a77a3SMauro Carvalho Chehab /* Get a frame buf from list */
456ee4a77a3SMauro Carvalho Chehab static struct rcar_drif_frame_buf *
rcar_drif_get_fbuf(struct rcar_drif_sdr * sdr)457ee4a77a3SMauro Carvalho Chehab rcar_drif_get_fbuf(struct rcar_drif_sdr *sdr)
458ee4a77a3SMauro Carvalho Chehab {
459ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf;
460ee4a77a3SMauro Carvalho Chehab unsigned long flags;
461ee4a77a3SMauro Carvalho Chehab
462ee4a77a3SMauro Carvalho Chehab spin_lock_irqsave(&sdr->queued_bufs_lock, flags);
463ee4a77a3SMauro Carvalho Chehab fbuf = list_first_entry_or_null(&sdr->queued_bufs, struct
464ee4a77a3SMauro Carvalho Chehab rcar_drif_frame_buf, list);
465ee4a77a3SMauro Carvalho Chehab if (!fbuf) {
466ee4a77a3SMauro Carvalho Chehab /*
467ee4a77a3SMauro Carvalho Chehab * App is late in enqueing buffers. Samples lost & there will
468ee4a77a3SMauro Carvalho Chehab * be a gap in sequence number when app recovers
469ee4a77a3SMauro Carvalho Chehab */
470ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "\napp late: prod %u\n", sdr->produced);
471ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags);
472ee4a77a3SMauro Carvalho Chehab return NULL;
473ee4a77a3SMauro Carvalho Chehab }
474ee4a77a3SMauro Carvalho Chehab list_del(&fbuf->list);
475ee4a77a3SMauro Carvalho Chehab spin_unlock_irqrestore(&sdr->queued_bufs_lock, flags);
476ee4a77a3SMauro Carvalho Chehab
477ee4a77a3SMauro Carvalho Chehab return fbuf;
478ee4a77a3SMauro Carvalho Chehab }
479ee4a77a3SMauro Carvalho Chehab
480ee4a77a3SMauro Carvalho Chehab /* Helpers to set/clear buf pair status */
rcar_drif_bufs_done(struct rcar_drif_hwbuf ** buf)481ee4a77a3SMauro Carvalho Chehab static inline bool rcar_drif_bufs_done(struct rcar_drif_hwbuf **buf)
482ee4a77a3SMauro Carvalho Chehab {
483ee4a77a3SMauro Carvalho Chehab return (buf[0]->status & buf[1]->status & RCAR_DRIF_BUF_DONE);
484ee4a77a3SMauro Carvalho Chehab }
485ee4a77a3SMauro Carvalho Chehab
rcar_drif_bufs_overflow(struct rcar_drif_hwbuf ** buf)486ee4a77a3SMauro Carvalho Chehab static inline bool rcar_drif_bufs_overflow(struct rcar_drif_hwbuf **buf)
487ee4a77a3SMauro Carvalho Chehab {
488ee4a77a3SMauro Carvalho Chehab return ((buf[0]->status | buf[1]->status) & RCAR_DRIF_BUF_OVERFLOW);
489ee4a77a3SMauro Carvalho Chehab }
490ee4a77a3SMauro Carvalho Chehab
rcar_drif_bufs_clear(struct rcar_drif_hwbuf ** buf,unsigned int bit)491ee4a77a3SMauro Carvalho Chehab static inline void rcar_drif_bufs_clear(struct rcar_drif_hwbuf **buf,
492ee4a77a3SMauro Carvalho Chehab unsigned int bit)
493ee4a77a3SMauro Carvalho Chehab {
494ee4a77a3SMauro Carvalho Chehab unsigned int i;
495ee4a77a3SMauro Carvalho Chehab
496ee4a77a3SMauro Carvalho Chehab for (i = 0; i < RCAR_DRIF_MAX_CHANNEL; i++)
497ee4a77a3SMauro Carvalho Chehab buf[i]->status &= ~bit;
498ee4a77a3SMauro Carvalho Chehab }
499ee4a77a3SMauro Carvalho Chehab
500ee4a77a3SMauro Carvalho Chehab /* Channel DMA complete */
rcar_drif_channel_complete(struct rcar_drif * ch,u32 idx)501ee4a77a3SMauro Carvalho Chehab static void rcar_drif_channel_complete(struct rcar_drif *ch, u32 idx)
502ee4a77a3SMauro Carvalho Chehab {
503ee4a77a3SMauro Carvalho Chehab u32 str;
504ee4a77a3SMauro Carvalho Chehab
505ee4a77a3SMauro Carvalho Chehab ch->buf[idx].status |= RCAR_DRIF_BUF_DONE;
506ee4a77a3SMauro Carvalho Chehab
507ee4a77a3SMauro Carvalho Chehab /* Check for DRIF errors */
508ee4a77a3SMauro Carvalho Chehab str = rcar_drif_read(ch, RCAR_DRIF_SISTR);
509ee4a77a3SMauro Carvalho Chehab if (unlikely(str & RCAR_DRIF_RFOVF)) {
510ee4a77a3SMauro Carvalho Chehab /* Writing the same clears it */
511ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SISTR, str);
512ee4a77a3SMauro Carvalho Chehab
513ee4a77a3SMauro Carvalho Chehab /* Overflow: some samples are lost */
514ee4a77a3SMauro Carvalho Chehab ch->buf[idx].status |= RCAR_DRIF_BUF_OVERFLOW;
515ee4a77a3SMauro Carvalho Chehab }
516ee4a77a3SMauro Carvalho Chehab }
517ee4a77a3SMauro Carvalho Chehab
518ee4a77a3SMauro Carvalho Chehab /* DMA callback for each stage */
rcar_drif_dma_complete(void * dma_async_param)519ee4a77a3SMauro Carvalho Chehab static void rcar_drif_dma_complete(void *dma_async_param)
520ee4a77a3SMauro Carvalho Chehab {
521ee4a77a3SMauro Carvalho Chehab struct rcar_drif *ch = dma_async_param;
522ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr;
523ee4a77a3SMauro Carvalho Chehab struct rcar_drif_hwbuf *buf[RCAR_DRIF_MAX_CHANNEL];
524ee4a77a3SMauro Carvalho Chehab struct rcar_drif_frame_buf *fbuf;
525ee4a77a3SMauro Carvalho Chehab bool overflow = false;
526ee4a77a3SMauro Carvalho Chehab u32 idx, produced;
527ee4a77a3SMauro Carvalho Chehab unsigned int i;
528ee4a77a3SMauro Carvalho Chehab
529ee4a77a3SMauro Carvalho Chehab spin_lock(&sdr->dma_lock);
530ee4a77a3SMauro Carvalho Chehab
531ee4a77a3SMauro Carvalho Chehab /* DMA can be terminated while the callback was waiting on lock */
532ee4a77a3SMauro Carvalho Chehab if (!vb2_is_streaming(&sdr->vb_queue)) {
533ee4a77a3SMauro Carvalho Chehab spin_unlock(&sdr->dma_lock);
534ee4a77a3SMauro Carvalho Chehab return;
535ee4a77a3SMauro Carvalho Chehab }
536ee4a77a3SMauro Carvalho Chehab
537ee4a77a3SMauro Carvalho Chehab idx = sdr->produced % RCAR_DRIF_NUM_HWBUFS;
538ee4a77a3SMauro Carvalho Chehab rcar_drif_channel_complete(ch, idx);
539ee4a77a3SMauro Carvalho Chehab
540ee4a77a3SMauro Carvalho Chehab if (sdr->num_cur_ch == RCAR_DRIF_MAX_CHANNEL) {
541ee4a77a3SMauro Carvalho Chehab buf[0] = ch->num ? to_rcar_drif_buf_pair(sdr, ch->num, idx) :
542ee4a77a3SMauro Carvalho Chehab &ch->buf[idx];
543ee4a77a3SMauro Carvalho Chehab buf[1] = ch->num ? &ch->buf[idx] :
544ee4a77a3SMauro Carvalho Chehab to_rcar_drif_buf_pair(sdr, ch->num, idx);
545ee4a77a3SMauro Carvalho Chehab
546ee4a77a3SMauro Carvalho Chehab /* Check if both DMA buffers are done */
547ee4a77a3SMauro Carvalho Chehab if (!rcar_drif_bufs_done(buf)) {
548ee4a77a3SMauro Carvalho Chehab spin_unlock(&sdr->dma_lock);
549ee4a77a3SMauro Carvalho Chehab return;
550ee4a77a3SMauro Carvalho Chehab }
551ee4a77a3SMauro Carvalho Chehab
552ee4a77a3SMauro Carvalho Chehab /* Clear buf done status */
553ee4a77a3SMauro Carvalho Chehab rcar_drif_bufs_clear(buf, RCAR_DRIF_BUF_DONE);
554ee4a77a3SMauro Carvalho Chehab
555ee4a77a3SMauro Carvalho Chehab if (rcar_drif_bufs_overflow(buf)) {
556ee4a77a3SMauro Carvalho Chehab overflow = true;
557ee4a77a3SMauro Carvalho Chehab /* Clear the flag in status */
558ee4a77a3SMauro Carvalho Chehab rcar_drif_bufs_clear(buf, RCAR_DRIF_BUF_OVERFLOW);
559ee4a77a3SMauro Carvalho Chehab }
560ee4a77a3SMauro Carvalho Chehab } else {
561ee4a77a3SMauro Carvalho Chehab buf[0] = &ch->buf[idx];
562ee4a77a3SMauro Carvalho Chehab if (buf[0]->status & RCAR_DRIF_BUF_OVERFLOW) {
563ee4a77a3SMauro Carvalho Chehab overflow = true;
564ee4a77a3SMauro Carvalho Chehab /* Clear the flag in status */
565ee4a77a3SMauro Carvalho Chehab buf[0]->status &= ~RCAR_DRIF_BUF_OVERFLOW;
566ee4a77a3SMauro Carvalho Chehab }
567ee4a77a3SMauro Carvalho Chehab }
568ee4a77a3SMauro Carvalho Chehab
569ee4a77a3SMauro Carvalho Chehab /* Buffer produced for consumption */
570ee4a77a3SMauro Carvalho Chehab produced = sdr->produced++;
571ee4a77a3SMauro Carvalho Chehab spin_unlock(&sdr->dma_lock);
572ee4a77a3SMauro Carvalho Chehab
573ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "ch%u: prod %u\n", ch->num, produced);
574ee4a77a3SMauro Carvalho Chehab
575ee4a77a3SMauro Carvalho Chehab /* Get fbuf */
576ee4a77a3SMauro Carvalho Chehab fbuf = rcar_drif_get_fbuf(sdr);
577ee4a77a3SMauro Carvalho Chehab if (!fbuf)
578ee4a77a3SMauro Carvalho Chehab return;
579ee4a77a3SMauro Carvalho Chehab
580ee4a77a3SMauro Carvalho Chehab for (i = 0; i < RCAR_DRIF_MAX_CHANNEL; i++)
581ee4a77a3SMauro Carvalho Chehab memcpy(vb2_plane_vaddr(&fbuf->vb.vb2_buf, 0) +
582ee4a77a3SMauro Carvalho Chehab i * sdr->hwbuf_size, buf[i]->addr, sdr->hwbuf_size);
583ee4a77a3SMauro Carvalho Chehab
584ee4a77a3SMauro Carvalho Chehab fbuf->vb.field = V4L2_FIELD_NONE;
585ee4a77a3SMauro Carvalho Chehab fbuf->vb.sequence = produced;
586ee4a77a3SMauro Carvalho Chehab fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
587ee4a77a3SMauro Carvalho Chehab vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, sdr->fmt->buffersize);
588ee4a77a3SMauro Carvalho Chehab
589ee4a77a3SMauro Carvalho Chehab /* Set error state on overflow */
590ee4a77a3SMauro Carvalho Chehab vb2_buffer_done(&fbuf->vb.vb2_buf,
591ee4a77a3SMauro Carvalho Chehab overflow ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
592ee4a77a3SMauro Carvalho Chehab }
593ee4a77a3SMauro Carvalho Chehab
rcar_drif_qbuf(struct rcar_drif * ch)594ee4a77a3SMauro Carvalho Chehab static int rcar_drif_qbuf(struct rcar_drif *ch)
595ee4a77a3SMauro Carvalho Chehab {
596ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr;
597ee4a77a3SMauro Carvalho Chehab dma_addr_t addr = ch->dma_handle;
598ee4a77a3SMauro Carvalho Chehab struct dma_async_tx_descriptor *rxd;
599ee4a77a3SMauro Carvalho Chehab dma_cookie_t cookie;
600ee4a77a3SMauro Carvalho Chehab int ret = -EIO;
601ee4a77a3SMauro Carvalho Chehab
602ee4a77a3SMauro Carvalho Chehab /* Setup cyclic DMA with given buffers */
603ee4a77a3SMauro Carvalho Chehab rxd = dmaengine_prep_dma_cyclic(ch->dmach, addr,
604ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size * RCAR_DRIF_NUM_HWBUFS,
605ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size, DMA_DEV_TO_MEM,
606ee4a77a3SMauro Carvalho Chehab DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
607ee4a77a3SMauro Carvalho Chehab if (!rxd) {
608ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: prep dma cyclic failed\n", ch->num);
609ee4a77a3SMauro Carvalho Chehab return ret;
610ee4a77a3SMauro Carvalho Chehab }
611ee4a77a3SMauro Carvalho Chehab
612ee4a77a3SMauro Carvalho Chehab /* Submit descriptor */
613ee4a77a3SMauro Carvalho Chehab rxd->callback = rcar_drif_dma_complete;
614ee4a77a3SMauro Carvalho Chehab rxd->callback_param = ch;
615ee4a77a3SMauro Carvalho Chehab cookie = dmaengine_submit(rxd);
616ee4a77a3SMauro Carvalho Chehab if (dma_submit_error(cookie)) {
617ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: dma submit failed\n", ch->num);
618ee4a77a3SMauro Carvalho Chehab return ret;
619ee4a77a3SMauro Carvalho Chehab }
620ee4a77a3SMauro Carvalho Chehab
621ee4a77a3SMauro Carvalho Chehab dma_async_issue_pending(ch->dmach);
622ee4a77a3SMauro Carvalho Chehab return 0;
623ee4a77a3SMauro Carvalho Chehab }
624ee4a77a3SMauro Carvalho Chehab
625ee4a77a3SMauro Carvalho Chehab /* Enable reception */
rcar_drif_enable_rx(struct rcar_drif_sdr * sdr)626ee4a77a3SMauro Carvalho Chehab static int rcar_drif_enable_rx(struct rcar_drif_sdr *sdr)
627ee4a77a3SMauro Carvalho Chehab {
628ee4a77a3SMauro Carvalho Chehab unsigned int i;
629ee4a77a3SMauro Carvalho Chehab u32 ctr;
630ee4a77a3SMauro Carvalho Chehab int ret = -EINVAL;
631ee4a77a3SMauro Carvalho Chehab
632ee4a77a3SMauro Carvalho Chehab /*
633ee4a77a3SMauro Carvalho Chehab * When both internal channels are enabled, they can be synchronized
634ee4a77a3SMauro Carvalho Chehab * only by the master
635ee4a77a3SMauro Carvalho Chehab */
636ee4a77a3SMauro Carvalho Chehab
637ee4a77a3SMauro Carvalho Chehab /* Enable receive */
638ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
639ee4a77a3SMauro Carvalho Chehab ctr = rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR);
640ee4a77a3SMauro Carvalho Chehab ctr |= (RCAR_DRIF_SICTR_RX_RISING_EDGE |
641ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_SICTR_RX_EN);
642ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SICTR, ctr);
643ee4a77a3SMauro Carvalho Chehab }
644ee4a77a3SMauro Carvalho Chehab
645ee4a77a3SMauro Carvalho Chehab /* Check receive enabled */
646ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
647ee4a77a3SMauro Carvalho Chehab ret = readl_poll_timeout(sdr->ch[i]->base + RCAR_DRIF_SICTR,
648ee4a77a3SMauro Carvalho Chehab ctr, ctr & RCAR_DRIF_SICTR_RX_EN, 7, 100000);
649ee4a77a3SMauro Carvalho Chehab if (ret) {
650ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: rx en failed. ctr 0x%08x\n", i,
651ee4a77a3SMauro Carvalho Chehab rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR));
652ee4a77a3SMauro Carvalho Chehab break;
653ee4a77a3SMauro Carvalho Chehab }
654ee4a77a3SMauro Carvalho Chehab }
655ee4a77a3SMauro Carvalho Chehab return ret;
656ee4a77a3SMauro Carvalho Chehab }
657ee4a77a3SMauro Carvalho Chehab
658ee4a77a3SMauro Carvalho Chehab /* Disable reception */
rcar_drif_disable_rx(struct rcar_drif_sdr * sdr)659ee4a77a3SMauro Carvalho Chehab static void rcar_drif_disable_rx(struct rcar_drif_sdr *sdr)
660ee4a77a3SMauro Carvalho Chehab {
661ee4a77a3SMauro Carvalho Chehab unsigned int i;
662ee4a77a3SMauro Carvalho Chehab u32 ctr;
663ee4a77a3SMauro Carvalho Chehab int ret;
664ee4a77a3SMauro Carvalho Chehab
665ee4a77a3SMauro Carvalho Chehab /* Disable receive */
666ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
667ee4a77a3SMauro Carvalho Chehab ctr = rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR);
668ee4a77a3SMauro Carvalho Chehab ctr &= ~RCAR_DRIF_SICTR_RX_EN;
669ee4a77a3SMauro Carvalho Chehab rcar_drif_write(sdr->ch[i], RCAR_DRIF_SICTR, ctr);
670ee4a77a3SMauro Carvalho Chehab }
671ee4a77a3SMauro Carvalho Chehab
672ee4a77a3SMauro Carvalho Chehab /* Check receive disabled */
673ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
674ee4a77a3SMauro Carvalho Chehab ret = readl_poll_timeout(sdr->ch[i]->base + RCAR_DRIF_SICTR,
675ee4a77a3SMauro Carvalho Chehab ctr, !(ctr & RCAR_DRIF_SICTR_RX_EN), 7, 100000);
676ee4a77a3SMauro Carvalho Chehab if (ret)
677ee4a77a3SMauro Carvalho Chehab dev_warn(&sdr->vdev->dev,
678ee4a77a3SMauro Carvalho Chehab "ch%u: failed to disable rx. ctr 0x%08x\n",
679ee4a77a3SMauro Carvalho Chehab i, rcar_drif_read(sdr->ch[i], RCAR_DRIF_SICTR));
680ee4a77a3SMauro Carvalho Chehab }
681ee4a77a3SMauro Carvalho Chehab }
682ee4a77a3SMauro Carvalho Chehab
683ee4a77a3SMauro Carvalho Chehab /* Stop channel */
rcar_drif_stop_channel(struct rcar_drif * ch)684ee4a77a3SMauro Carvalho Chehab static void rcar_drif_stop_channel(struct rcar_drif *ch)
685ee4a77a3SMauro Carvalho Chehab {
686ee4a77a3SMauro Carvalho Chehab /* Disable DMA receive interrupt */
687ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SIIER, 0x00000000);
688ee4a77a3SMauro Carvalho Chehab
689ee4a77a3SMauro Carvalho Chehab /* Terminate all DMA transfers */
690ee4a77a3SMauro Carvalho Chehab dmaengine_terminate_sync(ch->dmach);
691ee4a77a3SMauro Carvalho Chehab }
692ee4a77a3SMauro Carvalho Chehab
693ee4a77a3SMauro Carvalho Chehab /* Stop receive operation */
rcar_drif_stop(struct rcar_drif_sdr * sdr)694ee4a77a3SMauro Carvalho Chehab static void rcar_drif_stop(struct rcar_drif_sdr *sdr)
695ee4a77a3SMauro Carvalho Chehab {
696ee4a77a3SMauro Carvalho Chehab unsigned int i;
697ee4a77a3SMauro Carvalho Chehab
698ee4a77a3SMauro Carvalho Chehab /* Disable Rx */
699ee4a77a3SMauro Carvalho Chehab rcar_drif_disable_rx(sdr);
700ee4a77a3SMauro Carvalho Chehab
701ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask)
702ee4a77a3SMauro Carvalho Chehab rcar_drif_stop_channel(sdr->ch[i]);
703ee4a77a3SMauro Carvalho Chehab }
704ee4a77a3SMauro Carvalho Chehab
705ee4a77a3SMauro Carvalho Chehab /* Start channel */
rcar_drif_start_channel(struct rcar_drif * ch)706ee4a77a3SMauro Carvalho Chehab static int rcar_drif_start_channel(struct rcar_drif *ch)
707ee4a77a3SMauro Carvalho Chehab {
708ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = ch->sdr;
709ee4a77a3SMauro Carvalho Chehab u32 ctr, str;
710ee4a77a3SMauro Carvalho Chehab int ret;
711ee4a77a3SMauro Carvalho Chehab
712ee4a77a3SMauro Carvalho Chehab /* Reset receive */
713ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SICTR, RCAR_DRIF_SICTR_RESET);
714ee4a77a3SMauro Carvalho Chehab ret = readl_poll_timeout(ch->base + RCAR_DRIF_SICTR, ctr,
715ee4a77a3SMauro Carvalho Chehab !(ctr & RCAR_DRIF_SICTR_RESET), 7, 100000);
716ee4a77a3SMauro Carvalho Chehab if (ret) {
717ee4a77a3SMauro Carvalho Chehab rdrif_err(sdr, "ch%u: failed to reset rx. ctr 0x%08x\n",
718ee4a77a3SMauro Carvalho Chehab ch->num, rcar_drif_read(ch, RCAR_DRIF_SICTR));
719ee4a77a3SMauro Carvalho Chehab return ret;
720ee4a77a3SMauro Carvalho Chehab }
721ee4a77a3SMauro Carvalho Chehab
722ee4a77a3SMauro Carvalho Chehab /* Queue buffers for DMA */
723ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_qbuf(ch);
724ee4a77a3SMauro Carvalho Chehab if (ret)
725ee4a77a3SMauro Carvalho Chehab return ret;
726ee4a77a3SMauro Carvalho Chehab
727ee4a77a3SMauro Carvalho Chehab /* Clear status register flags */
728ee4a77a3SMauro Carvalho Chehab str = RCAR_DRIF_RFFUL | RCAR_DRIF_REOF | RCAR_DRIF_RFSERR |
729ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_RFUDF | RCAR_DRIF_RFOVF;
730ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SISTR, str);
731ee4a77a3SMauro Carvalho Chehab
732ee4a77a3SMauro Carvalho Chehab /* Enable DMA receive interrupt */
733ee4a77a3SMauro Carvalho Chehab rcar_drif_write(ch, RCAR_DRIF_SIIER, 0x00009000);
734ee4a77a3SMauro Carvalho Chehab
735ee4a77a3SMauro Carvalho Chehab return ret;
736ee4a77a3SMauro Carvalho Chehab }
737ee4a77a3SMauro Carvalho Chehab
738ee4a77a3SMauro Carvalho Chehab /* Start receive operation */
rcar_drif_start(struct rcar_drif_sdr * sdr)739ee4a77a3SMauro Carvalho Chehab static int rcar_drif_start(struct rcar_drif_sdr *sdr)
740ee4a77a3SMauro Carvalho Chehab {
741ee4a77a3SMauro Carvalho Chehab unsigned long enabled = 0;
742ee4a77a3SMauro Carvalho Chehab unsigned int i;
743ee4a77a3SMauro Carvalho Chehab int ret;
744ee4a77a3SMauro Carvalho Chehab
745ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
746ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_start_channel(sdr->ch[i]);
747ee4a77a3SMauro Carvalho Chehab if (ret)
748ee4a77a3SMauro Carvalho Chehab goto start_error;
749ee4a77a3SMauro Carvalho Chehab enabled |= BIT(i);
750ee4a77a3SMauro Carvalho Chehab }
751ee4a77a3SMauro Carvalho Chehab
752ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_enable_rx(sdr);
753ee4a77a3SMauro Carvalho Chehab if (ret)
754ee4a77a3SMauro Carvalho Chehab goto enable_error;
755ee4a77a3SMauro Carvalho Chehab
756ee4a77a3SMauro Carvalho Chehab sdr->produced = 0;
757ee4a77a3SMauro Carvalho Chehab return ret;
758ee4a77a3SMauro Carvalho Chehab
759ee4a77a3SMauro Carvalho Chehab enable_error:
760ee4a77a3SMauro Carvalho Chehab rcar_drif_disable_rx(sdr);
761ee4a77a3SMauro Carvalho Chehab start_error:
762ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &enabled)
763ee4a77a3SMauro Carvalho Chehab rcar_drif_stop_channel(sdr->ch[i]);
764ee4a77a3SMauro Carvalho Chehab
765ee4a77a3SMauro Carvalho Chehab return ret;
766ee4a77a3SMauro Carvalho Chehab }
767ee4a77a3SMauro Carvalho Chehab
768ee4a77a3SMauro Carvalho Chehab /* Start streaming */
rcar_drif_start_streaming(struct vb2_queue * vq,unsigned int count)769ee4a77a3SMauro Carvalho Chehab static int rcar_drif_start_streaming(struct vb2_queue *vq, unsigned int count)
770ee4a77a3SMauro Carvalho Chehab {
771ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq);
772ee4a77a3SMauro Carvalho Chehab unsigned long enabled = 0;
773ee4a77a3SMauro Carvalho Chehab unsigned int i;
774ee4a77a3SMauro Carvalho Chehab int ret;
775ee4a77a3SMauro Carvalho Chehab
776ee4a77a3SMauro Carvalho Chehab mutex_lock(&sdr->v4l2_mutex);
777ee4a77a3SMauro Carvalho Chehab
778ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
779ee4a77a3SMauro Carvalho Chehab ret = clk_prepare_enable(sdr->ch[i]->clk);
780ee4a77a3SMauro Carvalho Chehab if (ret)
781ee4a77a3SMauro Carvalho Chehab goto error;
782ee4a77a3SMauro Carvalho Chehab enabled |= BIT(i);
783ee4a77a3SMauro Carvalho Chehab }
784ee4a77a3SMauro Carvalho Chehab
785ee4a77a3SMauro Carvalho Chehab /* Set default MDRx settings */
786ee4a77a3SMauro Carvalho Chehab rcar_drif_set_mdr1(sdr);
787ee4a77a3SMauro Carvalho Chehab
788ee4a77a3SMauro Carvalho Chehab /* Set new format */
789ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_set_format(sdr);
790ee4a77a3SMauro Carvalho Chehab if (ret)
791ee4a77a3SMauro Carvalho Chehab goto error;
792ee4a77a3SMauro Carvalho Chehab
793ee4a77a3SMauro Carvalho Chehab if (sdr->num_cur_ch == RCAR_DRIF_MAX_CHANNEL)
794ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size = sdr->fmt->buffersize / RCAR_DRIF_MAX_CHANNEL;
795ee4a77a3SMauro Carvalho Chehab else
796ee4a77a3SMauro Carvalho Chehab sdr->hwbuf_size = sdr->fmt->buffersize;
797ee4a77a3SMauro Carvalho Chehab
798ee4a77a3SMauro Carvalho Chehab rdrif_dbg(sdr, "num hwbufs %u, hwbuf_size %u\n",
799ee4a77a3SMauro Carvalho Chehab RCAR_DRIF_NUM_HWBUFS, sdr->hwbuf_size);
800ee4a77a3SMauro Carvalho Chehab
801ee4a77a3SMauro Carvalho Chehab /* Alloc DMA channel */
802ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_alloc_dmachannels(sdr);
803ee4a77a3SMauro Carvalho Chehab if (ret)
804ee4a77a3SMauro Carvalho Chehab goto error;
805ee4a77a3SMauro Carvalho Chehab
806ee4a77a3SMauro Carvalho Chehab /* Request buffers */
807ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_request_buf(sdr);
808ee4a77a3SMauro Carvalho Chehab if (ret)
809ee4a77a3SMauro Carvalho Chehab goto error;
810ee4a77a3SMauro Carvalho Chehab
811ee4a77a3SMauro Carvalho Chehab /* Start Rx */
812ee4a77a3SMauro Carvalho Chehab ret = rcar_drif_start(sdr);
813ee4a77a3SMauro Carvalho Chehab if (ret)
814ee4a77a3SMauro Carvalho Chehab goto error;
815ee4a77a3SMauro Carvalho Chehab
816ee4a77a3SMauro Carvalho Chehab mutex_unlock(&sdr->v4l2_mutex);
817ee4a77a3SMauro Carvalho Chehab
818ee4a77a3SMauro Carvalho Chehab return ret;
819ee4a77a3SMauro Carvalho Chehab
820ee4a77a3SMauro Carvalho Chehab error:
821ee4a77a3SMauro Carvalho Chehab rcar_drif_release_queued_bufs(sdr, VB2_BUF_STATE_QUEUED);
822ee4a77a3SMauro Carvalho Chehab rcar_drif_release_buf(sdr);
823ee4a77a3SMauro Carvalho Chehab rcar_drif_release_dmachannels(sdr);
824ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &enabled)
825ee4a77a3SMauro Carvalho Chehab clk_disable_unprepare(sdr->ch[i]->clk);
826ee4a77a3SMauro Carvalho Chehab
827ee4a77a3SMauro Carvalho Chehab mutex_unlock(&sdr->v4l2_mutex);
828ee4a77a3SMauro Carvalho Chehab
829ee4a77a3SMauro Carvalho Chehab return ret;
830ee4a77a3SMauro Carvalho Chehab }
831ee4a77a3SMauro Carvalho Chehab
832ee4a77a3SMauro Carvalho Chehab /* Stop streaming */
rcar_drif_stop_streaming(struct vb2_queue * vq)833ee4a77a3SMauro Carvalho Chehab static void rcar_drif_stop_streaming(struct vb2_queue *vq)
834ee4a77a3SMauro Carvalho Chehab {
835ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq);
836ee4a77a3SMauro Carvalho Chehab unsigned int i;
837ee4a77a3SMauro Carvalho Chehab
838ee4a77a3SMauro Carvalho Chehab mutex_lock(&sdr->v4l2_mutex);
839ee4a77a3SMauro Carvalho Chehab
840ee4a77a3SMauro Carvalho Chehab /* Stop hardware streaming */
841ee4a77a3SMauro Carvalho Chehab rcar_drif_stop(sdr);
842ee4a77a3SMauro Carvalho Chehab
843ee4a77a3SMauro Carvalho Chehab /* Return all queued buffers to vb2 */
844ee4a77a3SMauro Carvalho Chehab rcar_drif_release_queued_bufs(sdr, VB2_BUF_STATE_ERROR);
845ee4a77a3SMauro Carvalho Chehab
846ee4a77a3SMauro Carvalho Chehab /* Release buf */
847ee4a77a3SMauro Carvalho Chehab rcar_drif_release_buf(sdr);
848ee4a77a3SMauro Carvalho Chehab
849ee4a77a3SMauro Carvalho Chehab /* Release DMA channel resources */
850ee4a77a3SMauro Carvalho Chehab rcar_drif_release_dmachannels(sdr);
851ee4a77a3SMauro Carvalho Chehab
852ee4a77a3SMauro Carvalho Chehab for_each_rcar_drif_channel(i, &sdr->cur_ch_mask)
853ee4a77a3SMauro Carvalho Chehab clk_disable_unprepare(sdr->ch[i]->clk);
854ee4a77a3SMauro Carvalho Chehab
855ee4a77a3SMauro Carvalho Chehab mutex_unlock(&sdr->v4l2_mutex);
856ee4a77a3SMauro Carvalho Chehab }
857ee4a77a3SMauro Carvalho Chehab
858ee4a77a3SMauro Carvalho Chehab /* Vb2 ops */
859ee4a77a3SMauro Carvalho Chehab static const struct vb2_ops rcar_drif_vb2_ops = {
860ee4a77a3SMauro Carvalho Chehab .queue_setup = rcar_drif_queue_setup,
861ee4a77a3SMauro Carvalho Chehab .buf_queue = rcar_drif_buf_queue,
862ee4a77a3SMauro Carvalho Chehab .start_streaming = rcar_drif_start_streaming,
863ee4a77a3SMauro Carvalho Chehab .stop_streaming = rcar_drif_stop_streaming,
864ee4a77a3SMauro Carvalho Chehab .wait_prepare = vb2_ops_wait_prepare,
865ee4a77a3SMauro Carvalho Chehab .wait_finish = vb2_ops_wait_finish,
866ee4a77a3SMauro Carvalho Chehab };
867ee4a77a3SMauro Carvalho Chehab
rcar_drif_querycap(struct file * file,void * fh,struct v4l2_capability * cap)868ee4a77a3SMauro Carvalho Chehab static int rcar_drif_querycap(struct file *file, void *fh,
869ee4a77a3SMauro Carvalho Chehab struct v4l2_capability *cap)
870ee4a77a3SMauro Carvalho Chehab {
871ee4a77a3SMauro Carvalho Chehab struct rcar_drif_sdr *sdr = video_drvdata(file);
872ee4a77a3SMauro Carvalho Chehab
873ee4a77a3SMauro Carvalho Chehab strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
874ee4a77a3SMauro Carvalho Chehab strscpy(cap->card, sdr->vdev->name, sizeof(cap->card));
87537272d21SHans Verkuil strscpy(cap->bus_info, "platform:R-Car DRIF", sizeof(cap->bus_info));
876ee4a77a3SMauro Carvalho Chehab
877ee4a77a3SMauro Carvalho Chehab return 0;
878ee4a77a3SMauro Carvalho Chehab }
879ee4a77a3SMauro Carvalho Chehab
rcar_drif_set_default_format(struct rcar_drif_sdr * sdr)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
rcar_drif_enum_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)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
rcar_drif_g_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_format * f)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
rcar_drif_s_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_format * f)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
rcar_drif_try_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_format * f)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 */
rcar_drif_enum_freq_bands(struct file * file,void * priv,struct v4l2_frequency_band * band)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
rcar_drif_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)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
rcar_drif_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)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
rcar_drif_g_tuner(struct file * file,void * priv,struct v4l2_tuner * vt)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
rcar_drif_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * vt)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
rcar_drif_sdr_register(struct rcar_drif_sdr * sdr)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
rcar_drif_sdr_unregister(struct rcar_drif_sdr * sdr)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 */
rcar_drif_notify_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)1099ee4a77a3SMauro Carvalho Chehab static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier,
1100ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev *subdev,
1101adb2dcd5SSakari 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 */
rcar_drif_notify_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)1114ee4a77a3SMauro Carvalho Chehab static void rcar_drif_notify_unbind(struct v4l2_async_notifier *notifier,
1115ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev *subdev,
1116adb2dcd5SSakari 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 */
rcar_drif_notify_complete(struct v4l2_async_notifier * notifier)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 */
rcar_drif_get_ep_properties(struct rcar_drif_sdr * sdr,struct fwnode_handle * fwnode)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 */
rcar_drif_parse_subdevs(struct rcar_drif_sdr * sdr)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;
1209adb2dcd5SSakari Ailus struct v4l2_async_connection *asd;
1210ee4a77a3SMauro Carvalho Chehab
1211b8ec754aSSakari Ailus v4l2_async_nf_init(&sdr->notifier, &sdr->v4l2_dev);
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,
1229adb2dcd5SSakari 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 */
rcar_drif_primary_bond(struct platform_device * pdev)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 */
rcar_drif_bond_enabled(struct platform_device * p)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 */
rcar_drif_bond_available(struct rcar_drif_sdr * sdr,struct device_node * np)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 */
rcar_drif_sdr_probe(struct rcar_drif_sdr * sdr)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 */
1345b8ec754aSSakari Ailus ret = v4l2_async_nf_register(&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 */
rcar_drif_sdr_remove(struct rcar_drif_sdr * sdr)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 */
rcar_drif_probe(struct platform_device * pdev)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 */
rcar_drif_remove(struct platform_device * pdev)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 */
rcar_drif_suspend(struct device * dev)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
rcar_drif_resume(struct device * dev)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