diff options
author | Arnd Bergmann <arnd@arndb.de> | 2018-03-09 11:30:07 -0500 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2018-03-26 09:56:47 -0400 |
commit | 3e3a5f7d5731f4db3b252d09332732bd051a8468 (patch) | |
tree | 5bdfe92770180b7a19e08be474a0fbef79d27d97 | |
parent | c14094a48d00768ee2a1defff1fee0e51dbe15bb (diff) |
media: platform: remove blackfin capture driver
The blackfin architecture is getting removed, so the video
capture driver is also obsolete.
Acked-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Acked-by: Aaron Wu <aaron.wu@analog.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | drivers/media/platform/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/platform/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/platform/blackfin/Kconfig | 16 | ||||
-rw-r--r-- | drivers/media/platform/blackfin/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/platform/blackfin/bfin_capture.c | 989 | ||||
-rw-r--r-- | drivers/media/platform/blackfin/ppi.c | 361 | ||||
-rw-r--r-- | include/media/blackfin/bfin_capture.h | 39 | ||||
-rw-r--r-- | include/media/blackfin/ppi.h | 94 |
8 files changed, 0 insertions, 1505 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 614fbef08ddc..00158b35c7db 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -31,8 +31,6 @@ source "drivers/media/platform/davinci/Kconfig" | |||
31 | 31 | ||
32 | source "drivers/media/platform/omap/Kconfig" | 32 | source "drivers/media/platform/omap/Kconfig" |
33 | 33 | ||
34 | source "drivers/media/platform/blackfin/Kconfig" | ||
35 | |||
36 | config VIDEO_SH_VOU | 34 | config VIDEO_SH_VOU |
37 | tristate "SuperH VOU video output driver" | 35 | tristate "SuperH VOU video output driver" |
38 | depends on MEDIA_CAMERA_SUPPORT | 36 | depends on MEDIA_CAMERA_SUPPORT |
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 7f3080437be6..e2b5cb36ee84 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile | |||
@@ -53,8 +53,6 @@ obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra-cec/ | |||
53 | 53 | ||
54 | obj-y += stm32/ | 54 | obj-y += stm32/ |
55 | 55 | ||
56 | obj-y += blackfin/ | ||
57 | |||
58 | obj-y += davinci/ | 56 | obj-y += davinci/ |
59 | 57 | ||
60 | obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o | 58 | obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o |
diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig deleted file mode 100644 index 68fa90151b8f..000000000000 --- a/drivers/media/platform/blackfin/Kconfig +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | config VIDEO_BLACKFIN_CAPTURE | ||
2 | tristate "Blackfin Video Capture Driver" | ||
3 | depends on VIDEO_V4L2 && BLACKFIN && I2C | ||
4 | depends on HAS_DMA | ||
5 | select VIDEOBUF2_DMA_CONTIG | ||
6 | help | ||
7 | V4L2 bridge driver for Blackfin video capture device. | ||
8 | Choose PPI or EPPI as its interface. | ||
9 | |||
10 | To compile this driver as a module, choose M here: the | ||
11 | module will be called bfin_capture. | ||
12 | |||
13 | config VIDEO_BLACKFIN_PPI | ||
14 | tristate | ||
15 | depends on VIDEO_BLACKFIN_CAPTURE | ||
16 | default VIDEO_BLACKFIN_CAPTURE | ||
diff --git a/drivers/media/platform/blackfin/Makefile b/drivers/media/platform/blackfin/Makefile deleted file mode 100644 index 30421bc23080..000000000000 --- a/drivers/media/platform/blackfin/Makefile +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_capture.o | ||
2 | obj-$(CONFIG_VIDEO_BLACKFIN_PPI) += ppi.o | ||
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c deleted file mode 100644 index 41f179117fb0..000000000000 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ /dev/null | |||
@@ -1,989 +0,0 @@ | |||
1 | /* | ||
2 | * Analog Devices video capture driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/completion.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/types.h> | ||
30 | |||
31 | #include <media/v4l2-common.h> | ||
32 | #include <media/v4l2-ctrls.h> | ||
33 | #include <media/v4l2-device.h> | ||
34 | #include <media/v4l2-ioctl.h> | ||
35 | #include <media/videobuf2-dma-contig.h> | ||
36 | |||
37 | #include <asm/dma.h> | ||
38 | |||
39 | #include <media/blackfin/bfin_capture.h> | ||
40 | #include <media/blackfin/ppi.h> | ||
41 | |||
42 | #define CAPTURE_DRV_NAME "bfin_capture" | ||
43 | |||
44 | struct bcap_format { | ||
45 | char *desc; | ||
46 | u32 pixelformat; | ||
47 | u32 mbus_code; | ||
48 | int bpp; /* bits per pixel */ | ||
49 | int dlen; /* data length for ppi in bits */ | ||
50 | }; | ||
51 | |||
52 | struct bcap_buffer { | ||
53 | struct vb2_v4l2_buffer vb; | ||
54 | struct list_head list; | ||
55 | }; | ||
56 | |||
57 | struct bcap_device { | ||
58 | /* capture device instance */ | ||
59 | struct v4l2_device v4l2_dev; | ||
60 | /* v4l2 control handler */ | ||
61 | struct v4l2_ctrl_handler ctrl_handler; | ||
62 | /* device node data */ | ||
63 | struct video_device video_dev; | ||
64 | /* sub device instance */ | ||
65 | struct v4l2_subdev *sd; | ||
66 | /* capture config */ | ||
67 | struct bfin_capture_config *cfg; | ||
68 | /* ppi interface */ | ||
69 | struct ppi_if *ppi; | ||
70 | /* current input */ | ||
71 | unsigned int cur_input; | ||
72 | /* current selected standard */ | ||
73 | v4l2_std_id std; | ||
74 | /* current selected dv_timings */ | ||
75 | struct v4l2_dv_timings dv_timings; | ||
76 | /* used to store pixel format */ | ||
77 | struct v4l2_pix_format fmt; | ||
78 | /* bits per pixel*/ | ||
79 | int bpp; | ||
80 | /* data length for ppi in bits */ | ||
81 | int dlen; | ||
82 | /* used to store sensor supported format */ | ||
83 | struct bcap_format *sensor_formats; | ||
84 | /* number of sensor formats array */ | ||
85 | int num_sensor_formats; | ||
86 | /* pointing to current video buffer */ | ||
87 | struct bcap_buffer *cur_frm; | ||
88 | /* buffer queue used in videobuf2 */ | ||
89 | struct vb2_queue buffer_queue; | ||
90 | /* queue of filled frames */ | ||
91 | struct list_head dma_queue; | ||
92 | /* used in videobuf2 callback */ | ||
93 | spinlock_t lock; | ||
94 | /* used to access capture device */ | ||
95 | struct mutex mutex; | ||
96 | /* used to wait ppi to complete one transfer */ | ||
97 | struct completion comp; | ||
98 | /* prepare to stop */ | ||
99 | bool stop; | ||
100 | /* vb2 buffer sequence counter */ | ||
101 | unsigned sequence; | ||
102 | }; | ||
103 | |||
104 | static const struct bcap_format bcap_formats[] = { | ||
105 | { | ||
106 | .desc = "YCbCr 4:2:2 Interleaved UYVY", | ||
107 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
108 | .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
109 | .bpp = 16, | ||
110 | .dlen = 8, | ||
111 | }, | ||
112 | { | ||
113 | .desc = "YCbCr 4:2:2 Interleaved YUYV", | ||
114 | .pixelformat = V4L2_PIX_FMT_YUYV, | ||
115 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
116 | .bpp = 16, | ||
117 | .dlen = 8, | ||
118 | }, | ||
119 | { | ||
120 | .desc = "YCbCr 4:2:2 Interleaved UYVY", | ||
121 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
122 | .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, | ||
123 | .bpp = 16, | ||
124 | .dlen = 16, | ||
125 | }, | ||
126 | { | ||
127 | .desc = "RGB 565", | ||
128 | .pixelformat = V4L2_PIX_FMT_RGB565, | ||
129 | .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, | ||
130 | .bpp = 16, | ||
131 | .dlen = 8, | ||
132 | }, | ||
133 | { | ||
134 | .desc = "RGB 444", | ||
135 | .pixelformat = V4L2_PIX_FMT_RGB444, | ||
136 | .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, | ||
137 | .bpp = 16, | ||
138 | .dlen = 8, | ||
139 | }, | ||
140 | |||
141 | }; | ||
142 | #define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats) | ||
143 | |||
144 | static irqreturn_t bcap_isr(int irq, void *dev_id); | ||
145 | |||
146 | static struct bcap_buffer *to_bcap_vb(struct vb2_v4l2_buffer *vb) | ||
147 | { | ||
148 | return container_of(vb, struct bcap_buffer, vb); | ||
149 | } | ||
150 | |||
151 | static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) | ||
152 | { | ||
153 | struct v4l2_subdev_mbus_code_enum code = { | ||
154 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
155 | }; | ||
156 | struct bcap_format *sf; | ||
157 | unsigned int num_formats = 0; | ||
158 | int i, j; | ||
159 | |||
160 | while (!v4l2_subdev_call(bcap_dev->sd, pad, | ||
161 | enum_mbus_code, NULL, &code)) { | ||
162 | num_formats++; | ||
163 | code.index++; | ||
164 | } | ||
165 | if (!num_formats) | ||
166 | return -ENXIO; | ||
167 | |||
168 | sf = kcalloc(num_formats, sizeof(*sf), GFP_KERNEL); | ||
169 | if (!sf) | ||
170 | return -ENOMEM; | ||
171 | |||
172 | for (i = 0; i < num_formats; i++) { | ||
173 | code.index = i; | ||
174 | v4l2_subdev_call(bcap_dev->sd, pad, | ||
175 | enum_mbus_code, NULL, &code); | ||
176 | for (j = 0; j < BCAP_MAX_FMTS; j++) | ||
177 | if (code.code == bcap_formats[j].mbus_code) | ||
178 | break; | ||
179 | if (j == BCAP_MAX_FMTS) { | ||
180 | /* we don't allow this sensor working with our bridge */ | ||
181 | kfree(sf); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | sf[i] = bcap_formats[j]; | ||
185 | } | ||
186 | bcap_dev->sensor_formats = sf; | ||
187 | bcap_dev->num_sensor_formats = num_formats; | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) | ||
192 | { | ||
193 | bcap_dev->num_sensor_formats = 0; | ||
194 | kfree(bcap_dev->sensor_formats); | ||
195 | bcap_dev->sensor_formats = NULL; | ||
196 | } | ||
197 | |||
198 | static int bcap_queue_setup(struct vb2_queue *vq, | ||
199 | unsigned int *nbuffers, unsigned int *nplanes, | ||
200 | unsigned int sizes[], struct device *alloc_devs[]) | ||
201 | { | ||
202 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
203 | |||
204 | if (vq->num_buffers + *nbuffers < 2) | ||
205 | *nbuffers = 2; | ||
206 | |||
207 | if (*nplanes) | ||
208 | return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0; | ||
209 | |||
210 | *nplanes = 1; | ||
211 | sizes[0] = bcap_dev->fmt.sizeimage; | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int bcap_buffer_prepare(struct vb2_buffer *vb) | ||
217 | { | ||
218 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
219 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
220 | unsigned long size = bcap_dev->fmt.sizeimage; | ||
221 | |||
222 | if (vb2_plane_size(vb, 0) < size) { | ||
223 | v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", | ||
224 | vb2_plane_size(vb, 0), size); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | vb2_set_plane_payload(vb, 0, size); | ||
228 | |||
229 | vbuf->field = bcap_dev->fmt.field; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static void bcap_buffer_queue(struct vb2_buffer *vb) | ||
235 | { | ||
236 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
237 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
238 | struct bcap_buffer *buf = to_bcap_vb(vbuf); | ||
239 | unsigned long flags; | ||
240 | |||
241 | spin_lock_irqsave(&bcap_dev->lock, flags); | ||
242 | list_add_tail(&buf->list, &bcap_dev->dma_queue); | ||
243 | spin_unlock_irqrestore(&bcap_dev->lock, flags); | ||
244 | } | ||
245 | |||
246 | static void bcap_buffer_cleanup(struct vb2_buffer *vb) | ||
247 | { | ||
248 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
249 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); | ||
250 | struct bcap_buffer *buf = to_bcap_vb(vbuf); | ||
251 | unsigned long flags; | ||
252 | |||
253 | spin_lock_irqsave(&bcap_dev->lock, flags); | ||
254 | list_del_init(&buf->list); | ||
255 | spin_unlock_irqrestore(&bcap_dev->lock, flags); | ||
256 | } | ||
257 | |||
258 | static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
259 | { | ||
260 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
261 | struct ppi_if *ppi = bcap_dev->ppi; | ||
262 | struct bcap_buffer *buf, *tmp; | ||
263 | struct ppi_params params; | ||
264 | dma_addr_t addr; | ||
265 | int ret; | ||
266 | |||
267 | /* enable streamon on the sub device */ | ||
268 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); | ||
269 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
270 | v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); | ||
271 | goto err; | ||
272 | } | ||
273 | |||
274 | /* set ppi params */ | ||
275 | params.width = bcap_dev->fmt.width; | ||
276 | params.height = bcap_dev->fmt.height; | ||
277 | params.bpp = bcap_dev->bpp; | ||
278 | params.dlen = bcap_dev->dlen; | ||
279 | params.ppi_control = bcap_dev->cfg->ppi_control; | ||
280 | params.int_mask = bcap_dev->cfg->int_mask; | ||
281 | if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities | ||
282 | & V4L2_IN_CAP_DV_TIMINGS) { | ||
283 | struct v4l2_bt_timings *bt = &bcap_dev->dv_timings.bt; | ||
284 | |||
285 | params.hdelay = bt->hsync + bt->hbackporch; | ||
286 | params.vdelay = bt->vsync + bt->vbackporch; | ||
287 | params.line = V4L2_DV_BT_FRAME_WIDTH(bt); | ||
288 | params.frame = V4L2_DV_BT_FRAME_HEIGHT(bt); | ||
289 | } else if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities | ||
290 | & V4L2_IN_CAP_STD) { | ||
291 | params.hdelay = 0; | ||
292 | params.vdelay = 0; | ||
293 | if (bcap_dev->std & V4L2_STD_525_60) { | ||
294 | params.line = 858; | ||
295 | params.frame = 525; | ||
296 | } else { | ||
297 | params.line = 864; | ||
298 | params.frame = 625; | ||
299 | } | ||
300 | } else { | ||
301 | params.hdelay = 0; | ||
302 | params.vdelay = 0; | ||
303 | params.line = params.width + bcap_dev->cfg->blank_pixels; | ||
304 | params.frame = params.height; | ||
305 | } | ||
306 | ret = ppi->ops->set_params(ppi, ¶ms); | ||
307 | if (ret < 0) { | ||
308 | v4l2_err(&bcap_dev->v4l2_dev, | ||
309 | "Error in setting ppi params\n"); | ||
310 | goto err; | ||
311 | } | ||
312 | |||
313 | /* attach ppi DMA irq handler */ | ||
314 | ret = ppi->ops->attach_irq(ppi, bcap_isr); | ||
315 | if (ret < 0) { | ||
316 | v4l2_err(&bcap_dev->v4l2_dev, | ||
317 | "Error in attaching interrupt handler\n"); | ||
318 | goto err; | ||
319 | } | ||
320 | |||
321 | bcap_dev->sequence = 0; | ||
322 | |||
323 | reinit_completion(&bcap_dev->comp); | ||
324 | bcap_dev->stop = false; | ||
325 | |||
326 | /* get the next frame from the dma queue */ | ||
327 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | ||
328 | struct bcap_buffer, list); | ||
329 | /* remove buffer from the dma queue */ | ||
330 | list_del_init(&bcap_dev->cur_frm->list); | ||
331 | addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb.vb2_buf, | ||
332 | 0); | ||
333 | /* update DMA address */ | ||
334 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
335 | /* enable ppi */ | ||
336 | ppi->ops->start(ppi); | ||
337 | |||
338 | return 0; | ||
339 | |||
340 | err: | ||
341 | list_for_each_entry_safe(buf, tmp, &bcap_dev->dma_queue, list) { | ||
342 | list_del(&buf->list); | ||
343 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
344 | } | ||
345 | |||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static void bcap_stop_streaming(struct vb2_queue *vq) | ||
350 | { | ||
351 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | ||
352 | struct ppi_if *ppi = bcap_dev->ppi; | ||
353 | int ret; | ||
354 | |||
355 | bcap_dev->stop = true; | ||
356 | wait_for_completion(&bcap_dev->comp); | ||
357 | ppi->ops->stop(ppi); | ||
358 | ppi->ops->detach_irq(ppi); | ||
359 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0); | ||
360 | if (ret && (ret != -ENOIOCTLCMD)) | ||
361 | v4l2_err(&bcap_dev->v4l2_dev, | ||
362 | "stream off failed in subdev\n"); | ||
363 | |||
364 | /* release all active buffers */ | ||
365 | if (bcap_dev->cur_frm) | ||
366 | vb2_buffer_done(&bcap_dev->cur_frm->vb.vb2_buf, | ||
367 | VB2_BUF_STATE_ERROR); | ||
368 | |||
369 | while (!list_empty(&bcap_dev->dma_queue)) { | ||
370 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | ||
371 | struct bcap_buffer, list); | ||
372 | list_del_init(&bcap_dev->cur_frm->list); | ||
373 | vb2_buffer_done(&bcap_dev->cur_frm->vb.vb2_buf, | ||
374 | VB2_BUF_STATE_ERROR); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | static const struct vb2_ops bcap_video_qops = { | ||
379 | .queue_setup = bcap_queue_setup, | ||
380 | .buf_prepare = bcap_buffer_prepare, | ||
381 | .buf_cleanup = bcap_buffer_cleanup, | ||
382 | .buf_queue = bcap_buffer_queue, | ||
383 | .wait_prepare = vb2_ops_wait_prepare, | ||
384 | .wait_finish = vb2_ops_wait_finish, | ||
385 | .start_streaming = bcap_start_streaming, | ||
386 | .stop_streaming = bcap_stop_streaming, | ||
387 | }; | ||
388 | |||
389 | static irqreturn_t bcap_isr(int irq, void *dev_id) | ||
390 | { | ||
391 | struct ppi_if *ppi = dev_id; | ||
392 | struct bcap_device *bcap_dev = ppi->priv; | ||
393 | struct vb2_v4l2_buffer *vbuf = &bcap_dev->cur_frm->vb; | ||
394 | struct vb2_buffer *vb = &vbuf->vb2_buf; | ||
395 | dma_addr_t addr; | ||
396 | |||
397 | spin_lock(&bcap_dev->lock); | ||
398 | |||
399 | if (!list_empty(&bcap_dev->dma_queue)) { | ||
400 | vb->timestamp = ktime_get_ns(); | ||
401 | if (ppi->err) { | ||
402 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
403 | ppi->err = false; | ||
404 | } else { | ||
405 | vbuf->sequence = bcap_dev->sequence++; | ||
406 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
407 | } | ||
408 | bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, | ||
409 | struct bcap_buffer, list); | ||
410 | list_del_init(&bcap_dev->cur_frm->list); | ||
411 | } else { | ||
412 | /* clear error flag, we will get a new frame */ | ||
413 | if (ppi->err) | ||
414 | ppi->err = false; | ||
415 | } | ||
416 | |||
417 | ppi->ops->stop(ppi); | ||
418 | |||
419 | if (bcap_dev->stop) { | ||
420 | complete(&bcap_dev->comp); | ||
421 | } else { | ||
422 | addr = vb2_dma_contig_plane_dma_addr( | ||
423 | &bcap_dev->cur_frm->vb.vb2_buf, 0); | ||
424 | ppi->ops->update_addr(ppi, (unsigned long)addr); | ||
425 | ppi->ops->start(ppi); | ||
426 | } | ||
427 | |||
428 | spin_unlock(&bcap_dev->lock); | ||
429 | |||
430 | return IRQ_HANDLED; | ||
431 | } | ||
432 | |||
433 | static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
434 | { | ||
435 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
436 | struct v4l2_input input; | ||
437 | |||
438 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
439 | if (!(input.capabilities & V4L2_IN_CAP_STD)) | ||
440 | return -ENODATA; | ||
441 | |||
442 | return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); | ||
443 | } | ||
444 | |||
445 | static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
446 | { | ||
447 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
448 | struct v4l2_input input; | ||
449 | |||
450 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
451 | if (!(input.capabilities & V4L2_IN_CAP_STD)) | ||
452 | return -ENODATA; | ||
453 | |||
454 | *std = bcap_dev->std; | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) | ||
459 | { | ||
460 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
461 | struct v4l2_input input; | ||
462 | int ret; | ||
463 | |||
464 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
465 | if (!(input.capabilities & V4L2_IN_CAP_STD)) | ||
466 | return -ENODATA; | ||
467 | |||
468 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
469 | return -EBUSY; | ||
470 | |||
471 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_std, std); | ||
472 | if (ret < 0) | ||
473 | return ret; | ||
474 | |||
475 | bcap_dev->std = std; | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int bcap_enum_dv_timings(struct file *file, void *priv, | ||
480 | struct v4l2_enum_dv_timings *timings) | ||
481 | { | ||
482 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
483 | struct v4l2_input input; | ||
484 | |||
485 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
486 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
487 | return -ENODATA; | ||
488 | |||
489 | timings->pad = 0; | ||
490 | |||
491 | return v4l2_subdev_call(bcap_dev->sd, pad, | ||
492 | enum_dv_timings, timings); | ||
493 | } | ||
494 | |||
495 | static int bcap_query_dv_timings(struct file *file, void *priv, | ||
496 | struct v4l2_dv_timings *timings) | ||
497 | { | ||
498 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
499 | struct v4l2_input input; | ||
500 | |||
501 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
502 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
503 | return -ENODATA; | ||
504 | |||
505 | return v4l2_subdev_call(bcap_dev->sd, video, | ||
506 | query_dv_timings, timings); | ||
507 | } | ||
508 | |||
509 | static int bcap_g_dv_timings(struct file *file, void *priv, | ||
510 | struct v4l2_dv_timings *timings) | ||
511 | { | ||
512 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
513 | struct v4l2_input input; | ||
514 | |||
515 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
516 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
517 | return -ENODATA; | ||
518 | |||
519 | *timings = bcap_dev->dv_timings; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int bcap_s_dv_timings(struct file *file, void *priv, | ||
524 | struct v4l2_dv_timings *timings) | ||
525 | { | ||
526 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
527 | struct v4l2_input input; | ||
528 | int ret; | ||
529 | |||
530 | input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; | ||
531 | if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) | ||
532 | return -ENODATA; | ||
533 | |||
534 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
535 | return -EBUSY; | ||
536 | |||
537 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_dv_timings, timings); | ||
538 | if (ret < 0) | ||
539 | return ret; | ||
540 | |||
541 | bcap_dev->dv_timings = *timings; | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int bcap_enum_input(struct file *file, void *priv, | ||
546 | struct v4l2_input *input) | ||
547 | { | ||
548 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
549 | struct bfin_capture_config *config = bcap_dev->cfg; | ||
550 | int ret; | ||
551 | u32 status; | ||
552 | |||
553 | if (input->index >= config->num_inputs) | ||
554 | return -EINVAL; | ||
555 | |||
556 | *input = config->inputs[input->index]; | ||
557 | /* get input status */ | ||
558 | ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status); | ||
559 | if (!ret) | ||
560 | input->status = status; | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static int bcap_g_input(struct file *file, void *priv, unsigned int *index) | ||
565 | { | ||
566 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
567 | |||
568 | *index = bcap_dev->cur_input; | ||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int bcap_s_input(struct file *file, void *priv, unsigned int index) | ||
573 | { | ||
574 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
575 | struct bfin_capture_config *config = bcap_dev->cfg; | ||
576 | struct bcap_route *route; | ||
577 | int ret; | ||
578 | |||
579 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
580 | return -EBUSY; | ||
581 | |||
582 | if (index >= config->num_inputs) | ||
583 | return -EINVAL; | ||
584 | |||
585 | route = &config->routes[index]; | ||
586 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, | ||
587 | route->input, route->output, 0); | ||
588 | if ((ret < 0) && (ret != -ENOIOCTLCMD)) { | ||
589 | v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); | ||
590 | return ret; | ||
591 | } | ||
592 | bcap_dev->cur_input = index; | ||
593 | /* if this route has specific config, update ppi control */ | ||
594 | if (route->ppi_control) | ||
595 | config->ppi_control = route->ppi_control; | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int bcap_try_format(struct bcap_device *bcap, | ||
600 | struct v4l2_pix_format *pixfmt, | ||
601 | struct bcap_format *bcap_fmt) | ||
602 | { | ||
603 | struct bcap_format *sf = bcap->sensor_formats; | ||
604 | struct bcap_format *fmt = NULL; | ||
605 | struct v4l2_subdev_pad_config pad_cfg; | ||
606 | struct v4l2_subdev_format format = { | ||
607 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
608 | }; | ||
609 | int ret, i; | ||
610 | |||
611 | for (i = 0; i < bcap->num_sensor_formats; i++) { | ||
612 | fmt = &sf[i]; | ||
613 | if (pixfmt->pixelformat == fmt->pixelformat) | ||
614 | break; | ||
615 | } | ||
616 | if (i == bcap->num_sensor_formats) | ||
617 | fmt = &sf[0]; | ||
618 | |||
619 | v4l2_fill_mbus_format(&format.format, pixfmt, fmt->mbus_code); | ||
620 | ret = v4l2_subdev_call(bcap->sd, pad, set_fmt, &pad_cfg, | ||
621 | &format); | ||
622 | if (ret < 0) | ||
623 | return ret; | ||
624 | v4l2_fill_pix_format(pixfmt, &format.format); | ||
625 | if (bcap_fmt) { | ||
626 | for (i = 0; i < bcap->num_sensor_formats; i++) { | ||
627 | fmt = &sf[i]; | ||
628 | if (format.format.code == fmt->mbus_code) | ||
629 | break; | ||
630 | } | ||
631 | *bcap_fmt = *fmt; | ||
632 | } | ||
633 | pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; | ||
634 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int bcap_enum_fmt_vid_cap(struct file *file, void *priv, | ||
639 | struct v4l2_fmtdesc *fmt) | ||
640 | { | ||
641 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
642 | struct bcap_format *sf = bcap_dev->sensor_formats; | ||
643 | |||
644 | if (fmt->index >= bcap_dev->num_sensor_formats) | ||
645 | return -EINVAL; | ||
646 | |||
647 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
648 | strlcpy(fmt->description, | ||
649 | sf[fmt->index].desc, | ||
650 | sizeof(fmt->description)); | ||
651 | fmt->pixelformat = sf[fmt->index].pixelformat; | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int bcap_try_fmt_vid_cap(struct file *file, void *priv, | ||
656 | struct v4l2_format *fmt) | ||
657 | { | ||
658 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
659 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
660 | |||
661 | return bcap_try_format(bcap_dev, pixfmt, NULL); | ||
662 | } | ||
663 | |||
664 | static int bcap_g_fmt_vid_cap(struct file *file, void *priv, | ||
665 | struct v4l2_format *fmt) | ||
666 | { | ||
667 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
668 | |||
669 | fmt->fmt.pix = bcap_dev->fmt; | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int bcap_s_fmt_vid_cap(struct file *file, void *priv, | ||
674 | struct v4l2_format *fmt) | ||
675 | { | ||
676 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
677 | struct v4l2_subdev_format format = { | ||
678 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
679 | }; | ||
680 | struct bcap_format bcap_fmt; | ||
681 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
682 | int ret; | ||
683 | |||
684 | if (vb2_is_busy(&bcap_dev->buffer_queue)) | ||
685 | return -EBUSY; | ||
686 | |||
687 | /* see if format works */ | ||
688 | ret = bcap_try_format(bcap_dev, pixfmt, &bcap_fmt); | ||
689 | if (ret < 0) | ||
690 | return ret; | ||
691 | |||
692 | v4l2_fill_mbus_format(&format.format, pixfmt, bcap_fmt.mbus_code); | ||
693 | ret = v4l2_subdev_call(bcap_dev->sd, pad, set_fmt, NULL, &format); | ||
694 | if (ret < 0) | ||
695 | return ret; | ||
696 | bcap_dev->fmt = *pixfmt; | ||
697 | bcap_dev->bpp = bcap_fmt.bpp; | ||
698 | bcap_dev->dlen = bcap_fmt.dlen; | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int bcap_querycap(struct file *file, void *priv, | ||
703 | struct v4l2_capability *cap) | ||
704 | { | ||
705 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
706 | |||
707 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
708 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
709 | strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); | ||
710 | strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info)); | ||
711 | strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card)); | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int bcap_g_parm(struct file *file, void *fh, | ||
716 | struct v4l2_streamparm *a) | ||
717 | { | ||
718 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
719 | |||
720 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
721 | return -EINVAL; | ||
722 | return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); | ||
723 | } | ||
724 | |||
725 | static int bcap_s_parm(struct file *file, void *fh, | ||
726 | struct v4l2_streamparm *a) | ||
727 | { | ||
728 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
729 | |||
730 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
731 | return -EINVAL; | ||
732 | return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); | ||
733 | } | ||
734 | |||
735 | static int bcap_log_status(struct file *file, void *priv) | ||
736 | { | ||
737 | struct bcap_device *bcap_dev = video_drvdata(file); | ||
738 | /* status for sub devices */ | ||
739 | v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status); | ||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static const struct v4l2_ioctl_ops bcap_ioctl_ops = { | ||
744 | .vidioc_querycap = bcap_querycap, | ||
745 | .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap, | ||
746 | .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap, | ||
747 | .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap, | ||
748 | .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap, | ||
749 | .vidioc_enum_input = bcap_enum_input, | ||
750 | .vidioc_g_input = bcap_g_input, | ||
751 | .vidioc_s_input = bcap_s_input, | ||
752 | .vidioc_querystd = bcap_querystd, | ||
753 | .vidioc_s_std = bcap_s_std, | ||
754 | .vidioc_g_std = bcap_g_std, | ||
755 | .vidioc_s_dv_timings = bcap_s_dv_timings, | ||
756 | .vidioc_g_dv_timings = bcap_g_dv_timings, | ||
757 | .vidioc_query_dv_timings = bcap_query_dv_timings, | ||
758 | .vidioc_enum_dv_timings = bcap_enum_dv_timings, | ||
759 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
760 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
761 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
762 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
763 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
764 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
765 | .vidioc_streamon = vb2_ioctl_streamon, | ||
766 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
767 | .vidioc_g_parm = bcap_g_parm, | ||
768 | .vidioc_s_parm = bcap_s_parm, | ||
769 | .vidioc_log_status = bcap_log_status, | ||
770 | }; | ||
771 | |||
772 | static const struct v4l2_file_operations bcap_fops = { | ||
773 | .owner = THIS_MODULE, | ||
774 | .open = v4l2_fh_open, | ||
775 | .release = vb2_fop_release, | ||
776 | .unlocked_ioctl = video_ioctl2, | ||
777 | .mmap = vb2_fop_mmap, | ||
778 | #ifndef CONFIG_MMU | ||
779 | .get_unmapped_area = vb2_fop_get_unmapped_area, | ||
780 | #endif | ||
781 | .poll = vb2_fop_poll | ||
782 | }; | ||
783 | |||
784 | static int bcap_probe(struct platform_device *pdev) | ||
785 | { | ||
786 | struct bcap_device *bcap_dev; | ||
787 | struct video_device *vfd; | ||
788 | struct i2c_adapter *i2c_adap; | ||
789 | struct bfin_capture_config *config; | ||
790 | struct vb2_queue *q; | ||
791 | struct bcap_route *route; | ||
792 | int ret; | ||
793 | |||
794 | config = pdev->dev.platform_data; | ||
795 | if (!config || !config->num_inputs) { | ||
796 | v4l2_err(pdev->dev.driver, "Unable to get board config\n"); | ||
797 | return -ENODEV; | ||
798 | } | ||
799 | |||
800 | bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); | ||
801 | if (!bcap_dev) | ||
802 | return -ENOMEM; | ||
803 | |||
804 | bcap_dev->cfg = config; | ||
805 | |||
806 | bcap_dev->ppi = ppi_create_instance(pdev, config->ppi_info); | ||
807 | if (!bcap_dev->ppi) { | ||
808 | v4l2_err(pdev->dev.driver, "Unable to create ppi\n"); | ||
809 | ret = -ENODEV; | ||
810 | goto err_free_dev; | ||
811 | } | ||
812 | bcap_dev->ppi->priv = bcap_dev; | ||
813 | |||
814 | vfd = &bcap_dev->video_dev; | ||
815 | /* initialize field of video device */ | ||
816 | vfd->release = video_device_release_empty; | ||
817 | vfd->fops = &bcap_fops; | ||
818 | vfd->ioctl_ops = &bcap_ioctl_ops; | ||
819 | vfd->tvnorms = 0; | ||
820 | vfd->v4l2_dev = &bcap_dev->v4l2_dev; | ||
821 | strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); | ||
822 | |||
823 | ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); | ||
824 | if (ret) { | ||
825 | v4l2_err(pdev->dev.driver, | ||
826 | "Unable to register v4l2 device\n"); | ||
827 | goto err_free_ppi; | ||
828 | } | ||
829 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); | ||
830 | |||
831 | bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler; | ||
832 | ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0); | ||
833 | if (ret) { | ||
834 | v4l2_err(&bcap_dev->v4l2_dev, | ||
835 | "Unable to init control handler\n"); | ||
836 | goto err_unreg_v4l2; | ||
837 | } | ||
838 | |||
839 | spin_lock_init(&bcap_dev->lock); | ||
840 | /* initialize queue */ | ||
841 | q = &bcap_dev->buffer_queue; | ||
842 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
843 | q->io_modes = VB2_MMAP | VB2_DMABUF; | ||
844 | q->drv_priv = bcap_dev; | ||
845 | q->buf_struct_size = sizeof(struct bcap_buffer); | ||
846 | q->ops = &bcap_video_qops; | ||
847 | q->mem_ops = &vb2_dma_contig_memops; | ||
848 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
849 | q->lock = &bcap_dev->mutex; | ||
850 | q->min_buffers_needed = 1; | ||
851 | q->dev = &pdev->dev; | ||
852 | |||
853 | ret = vb2_queue_init(q); | ||
854 | if (ret) | ||
855 | goto err_free_handler; | ||
856 | |||
857 | mutex_init(&bcap_dev->mutex); | ||
858 | init_completion(&bcap_dev->comp); | ||
859 | |||
860 | /* init video dma queues */ | ||
861 | INIT_LIST_HEAD(&bcap_dev->dma_queue); | ||
862 | |||
863 | vfd->lock = &bcap_dev->mutex; | ||
864 | vfd->queue = q; | ||
865 | |||
866 | /* register video device */ | ||
867 | ret = video_register_device(&bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); | ||
868 | if (ret) { | ||
869 | v4l2_err(&bcap_dev->v4l2_dev, | ||
870 | "Unable to register video device\n"); | ||
871 | goto err_free_handler; | ||
872 | } | ||
873 | video_set_drvdata(&bcap_dev->video_dev, bcap_dev); | ||
874 | v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", | ||
875 | video_device_node_name(vfd)); | ||
876 | |||
877 | /* load up the subdevice */ | ||
878 | i2c_adap = i2c_get_adapter(config->i2c_adapter_id); | ||
879 | if (!i2c_adap) { | ||
880 | v4l2_err(&bcap_dev->v4l2_dev, | ||
881 | "Unable to find i2c adapter\n"); | ||
882 | ret = -ENODEV; | ||
883 | goto err_unreg_vdev; | ||
884 | |||
885 | } | ||
886 | bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev, | ||
887 | i2c_adap, | ||
888 | &config->board_info, | ||
889 | NULL); | ||
890 | if (bcap_dev->sd) { | ||
891 | int i; | ||
892 | |||
893 | /* update tvnorms from the sub devices */ | ||
894 | for (i = 0; i < config->num_inputs; i++) | ||
895 | vfd->tvnorms |= config->inputs[i].std; | ||
896 | } else { | ||
897 | v4l2_err(&bcap_dev->v4l2_dev, | ||
898 | "Unable to register sub device\n"); | ||
899 | ret = -ENODEV; | ||
900 | goto err_unreg_vdev; | ||
901 | } | ||
902 | |||
903 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); | ||
904 | |||
905 | /* | ||
906 | * explicitly set input, otherwise some boards | ||
907 | * may not work at the state as we expected | ||
908 | */ | ||
909 | route = &config->routes[0]; | ||
910 | ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, | ||
911 | route->input, route->output, 0); | ||
912 | if ((ret < 0) && (ret != -ENOIOCTLCMD)) { | ||
913 | v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); | ||
914 | goto err_unreg_vdev; | ||
915 | } | ||
916 | bcap_dev->cur_input = 0; | ||
917 | /* if this route has specific config, update ppi control */ | ||
918 | if (route->ppi_control) | ||
919 | config->ppi_control = route->ppi_control; | ||
920 | |||
921 | /* now we can probe the default state */ | ||
922 | if (config->inputs[0].capabilities & V4L2_IN_CAP_STD) { | ||
923 | v4l2_std_id std; | ||
924 | ret = v4l2_subdev_call(bcap_dev->sd, video, g_std, &std); | ||
925 | if (ret) { | ||
926 | v4l2_err(&bcap_dev->v4l2_dev, | ||
927 | "Unable to get std\n"); | ||
928 | goto err_unreg_vdev; | ||
929 | } | ||
930 | bcap_dev->std = std; | ||
931 | } | ||
932 | if (config->inputs[0].capabilities & V4L2_IN_CAP_DV_TIMINGS) { | ||
933 | struct v4l2_dv_timings dv_timings; | ||
934 | ret = v4l2_subdev_call(bcap_dev->sd, video, | ||
935 | g_dv_timings, &dv_timings); | ||
936 | if (ret) { | ||
937 | v4l2_err(&bcap_dev->v4l2_dev, | ||
938 | "Unable to get dv timings\n"); | ||
939 | goto err_unreg_vdev; | ||
940 | } | ||
941 | bcap_dev->dv_timings = dv_timings; | ||
942 | } | ||
943 | ret = bcap_init_sensor_formats(bcap_dev); | ||
944 | if (ret) { | ||
945 | v4l2_err(&bcap_dev->v4l2_dev, | ||
946 | "Unable to create sensor formats table\n"); | ||
947 | goto err_unreg_vdev; | ||
948 | } | ||
949 | return 0; | ||
950 | err_unreg_vdev: | ||
951 | video_unregister_device(&bcap_dev->video_dev); | ||
952 | err_free_handler: | ||
953 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | ||
954 | err_unreg_v4l2: | ||
955 | v4l2_device_unregister(&bcap_dev->v4l2_dev); | ||
956 | err_free_ppi: | ||
957 | ppi_delete_instance(bcap_dev->ppi); | ||
958 | err_free_dev: | ||
959 | kfree(bcap_dev); | ||
960 | return ret; | ||
961 | } | ||
962 | |||
963 | static int bcap_remove(struct platform_device *pdev) | ||
964 | { | ||
965 | struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); | ||
966 | struct bcap_device *bcap_dev = container_of(v4l2_dev, | ||
967 | struct bcap_device, v4l2_dev); | ||
968 | |||
969 | bcap_free_sensor_formats(bcap_dev); | ||
970 | video_unregister_device(&bcap_dev->video_dev); | ||
971 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | ||
972 | v4l2_device_unregister(v4l2_dev); | ||
973 | ppi_delete_instance(bcap_dev->ppi); | ||
974 | kfree(bcap_dev); | ||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | static struct platform_driver bcap_driver = { | ||
979 | .driver = { | ||
980 | .name = CAPTURE_DRV_NAME, | ||
981 | }, | ||
982 | .probe = bcap_probe, | ||
983 | .remove = bcap_remove, | ||
984 | }; | ||
985 | module_platform_driver(bcap_driver); | ||
986 | |||
987 | MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); | ||
988 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
989 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c deleted file mode 100644 index d3dc765c1609..000000000000 --- a/drivers/media/platform/blackfin/ppi.c +++ /dev/null | |||
@@ -1,361 +0,0 @@ | |||
1 | /* | ||
2 | * ppi.c Analog Devices Parallel Peripheral Interface driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | |||
20 | #include <asm/bfin_ppi.h> | ||
21 | #include <asm/blackfin.h> | ||
22 | #include <asm/cacheflush.h> | ||
23 | #include <asm/dma.h> | ||
24 | #include <asm/portmux.h> | ||
25 | |||
26 | #include <media/blackfin/ppi.h> | ||
27 | |||
28 | static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler); | ||
29 | static void ppi_detach_irq(struct ppi_if *ppi); | ||
30 | static int ppi_start(struct ppi_if *ppi); | ||
31 | static int ppi_stop(struct ppi_if *ppi); | ||
32 | static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params); | ||
33 | static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr); | ||
34 | |||
35 | static const struct ppi_ops ppi_ops = { | ||
36 | .attach_irq = ppi_attach_irq, | ||
37 | .detach_irq = ppi_detach_irq, | ||
38 | .start = ppi_start, | ||
39 | .stop = ppi_stop, | ||
40 | .set_params = ppi_set_params, | ||
41 | .update_addr = ppi_update_addr, | ||
42 | }; | ||
43 | |||
44 | static irqreturn_t ppi_irq_err(int irq, void *dev_id) | ||
45 | { | ||
46 | struct ppi_if *ppi = dev_id; | ||
47 | const struct ppi_info *info = ppi->info; | ||
48 | |||
49 | switch (info->type) { | ||
50 | case PPI_TYPE_PPI: | ||
51 | { | ||
52 | struct bfin_ppi_regs *reg = info->base; | ||
53 | unsigned short status; | ||
54 | |||
55 | /* register on bf561 is cleared when read | ||
56 | * others are W1C | ||
57 | */ | ||
58 | status = bfin_read16(®->status); | ||
59 | if (status & 0x3000) | ||
60 | ppi->err = true; | ||
61 | bfin_write16(®->status, 0xff00); | ||
62 | break; | ||
63 | } | ||
64 | case PPI_TYPE_EPPI: | ||
65 | { | ||
66 | struct bfin_eppi_regs *reg = info->base; | ||
67 | unsigned short status; | ||
68 | |||
69 | status = bfin_read16(®->status); | ||
70 | if (status & 0x2) | ||
71 | ppi->err = true; | ||
72 | bfin_write16(®->status, 0xffff); | ||
73 | break; | ||
74 | } | ||
75 | case PPI_TYPE_EPPI3: | ||
76 | { | ||
77 | struct bfin_eppi3_regs *reg = info->base; | ||
78 | unsigned long stat; | ||
79 | |||
80 | stat = bfin_read32(®->stat); | ||
81 | if (stat & 0x2) | ||
82 | ppi->err = true; | ||
83 | bfin_write32(®->stat, 0xc0ff); | ||
84 | break; | ||
85 | } | ||
86 | default: | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | return IRQ_HANDLED; | ||
91 | } | ||
92 | |||
93 | static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler) | ||
94 | { | ||
95 | const struct ppi_info *info = ppi->info; | ||
96 | int ret; | ||
97 | |||
98 | ret = request_dma(info->dma_ch, "PPI_DMA"); | ||
99 | |||
100 | if (ret) { | ||
101 | pr_err("Unable to allocate DMA channel for PPI\n"); | ||
102 | return ret; | ||
103 | } | ||
104 | set_dma_callback(info->dma_ch, handler, ppi); | ||
105 | |||
106 | if (ppi->err_int) { | ||
107 | ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi); | ||
108 | if (ret) { | ||
109 | pr_err("Unable to allocate IRQ for PPI\n"); | ||
110 | free_dma(info->dma_ch); | ||
111 | } | ||
112 | } | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | static void ppi_detach_irq(struct ppi_if *ppi) | ||
117 | { | ||
118 | const struct ppi_info *info = ppi->info; | ||
119 | |||
120 | if (ppi->err_int) | ||
121 | free_irq(info->irq_err, ppi); | ||
122 | free_dma(info->dma_ch); | ||
123 | } | ||
124 | |||
125 | static int ppi_start(struct ppi_if *ppi) | ||
126 | { | ||
127 | const struct ppi_info *info = ppi->info; | ||
128 | |||
129 | /* enable DMA */ | ||
130 | enable_dma(info->dma_ch); | ||
131 | |||
132 | /* enable PPI */ | ||
133 | ppi->ppi_control |= PORT_EN; | ||
134 | switch (info->type) { | ||
135 | case PPI_TYPE_PPI: | ||
136 | { | ||
137 | struct bfin_ppi_regs *reg = info->base; | ||
138 | bfin_write16(®->control, ppi->ppi_control); | ||
139 | break; | ||
140 | } | ||
141 | case PPI_TYPE_EPPI: | ||
142 | { | ||
143 | struct bfin_eppi_regs *reg = info->base; | ||
144 | bfin_write32(®->control, ppi->ppi_control); | ||
145 | break; | ||
146 | } | ||
147 | case PPI_TYPE_EPPI3: | ||
148 | { | ||
149 | struct bfin_eppi3_regs *reg = info->base; | ||
150 | bfin_write32(®->ctl, ppi->ppi_control); | ||
151 | break; | ||
152 | } | ||
153 | default: | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | SSYNC(); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int ppi_stop(struct ppi_if *ppi) | ||
162 | { | ||
163 | const struct ppi_info *info = ppi->info; | ||
164 | |||
165 | /* disable PPI */ | ||
166 | ppi->ppi_control &= ~PORT_EN; | ||
167 | switch (info->type) { | ||
168 | case PPI_TYPE_PPI: | ||
169 | { | ||
170 | struct bfin_ppi_regs *reg = info->base; | ||
171 | bfin_write16(®->control, ppi->ppi_control); | ||
172 | break; | ||
173 | } | ||
174 | case PPI_TYPE_EPPI: | ||
175 | { | ||
176 | struct bfin_eppi_regs *reg = info->base; | ||
177 | bfin_write32(®->control, ppi->ppi_control); | ||
178 | break; | ||
179 | } | ||
180 | case PPI_TYPE_EPPI3: | ||
181 | { | ||
182 | struct bfin_eppi3_regs *reg = info->base; | ||
183 | bfin_write32(®->ctl, ppi->ppi_control); | ||
184 | break; | ||
185 | } | ||
186 | default: | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | /* disable DMA */ | ||
191 | clear_dma_irqstat(info->dma_ch); | ||
192 | disable_dma(info->dma_ch); | ||
193 | |||
194 | SSYNC(); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) | ||
199 | { | ||
200 | const struct ppi_info *info = ppi->info; | ||
201 | int dma32 = 0; | ||
202 | int dma_config, bytes_per_line; | ||
203 | int hcount, hdelay, samples_per_line; | ||
204 | |||
205 | #ifdef CONFIG_PINCTRL | ||
206 | static const char * const pin_state[] = {"8bit", "16bit", "24bit"}; | ||
207 | struct pinctrl *pctrl; | ||
208 | struct pinctrl_state *pstate; | ||
209 | |||
210 | if (params->dlen > 24 || params->dlen <= 0) | ||
211 | return -EINVAL; | ||
212 | pctrl = devm_pinctrl_get(ppi->dev); | ||
213 | if (IS_ERR(pctrl)) | ||
214 | return PTR_ERR(pctrl); | ||
215 | pstate = pinctrl_lookup_state(pctrl, | ||
216 | pin_state[(params->dlen + 7) / 8 - 1]); | ||
217 | if (pinctrl_select_state(pctrl, pstate)) | ||
218 | return -EINVAL; | ||
219 | #endif | ||
220 | |||
221 | bytes_per_line = params->width * params->bpp / 8; | ||
222 | /* convert parameters unit from pixels to samples */ | ||
223 | hcount = params->width * params->bpp / params->dlen; | ||
224 | hdelay = params->hdelay * params->bpp / params->dlen; | ||
225 | samples_per_line = params->line * params->bpp / params->dlen; | ||
226 | if (params->int_mask == 0xFFFFFFFF) | ||
227 | ppi->err_int = false; | ||
228 | else | ||
229 | ppi->err_int = true; | ||
230 | |||
231 | dma_config = (DMA_FLOW_STOP | RESTART | DMA2D | DI_EN_Y); | ||
232 | ppi->ppi_control = params->ppi_control & ~PORT_EN; | ||
233 | if (!(ppi->ppi_control & PORT_DIR)) | ||
234 | dma_config |= WNR; | ||
235 | switch (info->type) { | ||
236 | case PPI_TYPE_PPI: | ||
237 | { | ||
238 | struct bfin_ppi_regs *reg = info->base; | ||
239 | |||
240 | if (params->ppi_control & DMA32) | ||
241 | dma32 = 1; | ||
242 | |||
243 | bfin_write16(®->control, ppi->ppi_control); | ||
244 | bfin_write16(®->count, samples_per_line - 1); | ||
245 | bfin_write16(®->frame, params->frame); | ||
246 | break; | ||
247 | } | ||
248 | case PPI_TYPE_EPPI: | ||
249 | { | ||
250 | struct bfin_eppi_regs *reg = info->base; | ||
251 | |||
252 | if ((params->ppi_control & PACK_EN) | ||
253 | || (params->ppi_control & 0x38000) > DLEN_16) | ||
254 | dma32 = 1; | ||
255 | |||
256 | bfin_write32(®->control, ppi->ppi_control); | ||
257 | bfin_write16(®->line, samples_per_line); | ||
258 | bfin_write16(®->frame, params->frame); | ||
259 | bfin_write16(®->hdelay, hdelay); | ||
260 | bfin_write16(®->vdelay, params->vdelay); | ||
261 | bfin_write16(®->hcount, hcount); | ||
262 | bfin_write16(®->vcount, params->height); | ||
263 | break; | ||
264 | } | ||
265 | case PPI_TYPE_EPPI3: | ||
266 | { | ||
267 | struct bfin_eppi3_regs *reg = info->base; | ||
268 | |||
269 | if ((params->ppi_control & PACK_EN) | ||
270 | || (params->ppi_control & 0x70000) > DLEN_16) | ||
271 | dma32 = 1; | ||
272 | |||
273 | bfin_write32(®->ctl, ppi->ppi_control); | ||
274 | bfin_write32(®->line, samples_per_line); | ||
275 | bfin_write32(®->frame, params->frame); | ||
276 | bfin_write32(®->hdly, hdelay); | ||
277 | bfin_write32(®->vdly, params->vdelay); | ||
278 | bfin_write32(®->hcnt, hcount); | ||
279 | bfin_write32(®->vcnt, params->height); | ||
280 | if (params->int_mask) | ||
281 | bfin_write32(®->imsk, params->int_mask & 0xFF); | ||
282 | if (ppi->ppi_control & PORT_DIR) { | ||
283 | u32 hsync_width, vsync_width, vsync_period; | ||
284 | |||
285 | hsync_width = params->hsync | ||
286 | * params->bpp / params->dlen; | ||
287 | vsync_width = params->vsync * samples_per_line; | ||
288 | vsync_period = samples_per_line * params->frame; | ||
289 | bfin_write32(®->fs1_wlhb, hsync_width); | ||
290 | bfin_write32(®->fs1_paspl, samples_per_line); | ||
291 | bfin_write32(®->fs2_wlvb, vsync_width); | ||
292 | bfin_write32(®->fs2_palpf, vsync_period); | ||
293 | } | ||
294 | break; | ||
295 | } | ||
296 | default: | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | |||
300 | if (dma32) { | ||
301 | dma_config |= WDSIZE_32 | PSIZE_32; | ||
302 | set_dma_x_count(info->dma_ch, bytes_per_line >> 2); | ||
303 | set_dma_x_modify(info->dma_ch, 4); | ||
304 | set_dma_y_modify(info->dma_ch, 4); | ||
305 | } else { | ||
306 | dma_config |= WDSIZE_16 | PSIZE_16; | ||
307 | set_dma_x_count(info->dma_ch, bytes_per_line >> 1); | ||
308 | set_dma_x_modify(info->dma_ch, 2); | ||
309 | set_dma_y_modify(info->dma_ch, 2); | ||
310 | } | ||
311 | set_dma_y_count(info->dma_ch, params->height); | ||
312 | set_dma_config(info->dma_ch, dma_config); | ||
313 | |||
314 | SSYNC(); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr) | ||
319 | { | ||
320 | set_dma_start_addr(ppi->info->dma_ch, addr); | ||
321 | } | ||
322 | |||
323 | struct ppi_if *ppi_create_instance(struct platform_device *pdev, | ||
324 | const struct ppi_info *info) | ||
325 | { | ||
326 | struct ppi_if *ppi; | ||
327 | |||
328 | if (!info || !info->pin_req) | ||
329 | return NULL; | ||
330 | |||
331 | #ifndef CONFIG_PINCTRL | ||
332 | if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) { | ||
333 | dev_err(&pdev->dev, "request peripheral failed\n"); | ||
334 | return NULL; | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); | ||
339 | if (!ppi) { | ||
340 | peripheral_free_list(info->pin_req); | ||
341 | return NULL; | ||
342 | } | ||
343 | ppi->ops = &ppi_ops; | ||
344 | ppi->info = info; | ||
345 | ppi->dev = &pdev->dev; | ||
346 | |||
347 | pr_info("ppi probe success\n"); | ||
348 | return ppi; | ||
349 | } | ||
350 | EXPORT_SYMBOL(ppi_create_instance); | ||
351 | |||
352 | void ppi_delete_instance(struct ppi_if *ppi) | ||
353 | { | ||
354 | peripheral_free_list(ppi->info->pin_req); | ||
355 | kfree(ppi); | ||
356 | } | ||
357 | EXPORT_SYMBOL(ppi_delete_instance); | ||
358 | |||
359 | MODULE_DESCRIPTION("Analog Devices PPI driver"); | ||
360 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
361 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/media/blackfin/bfin_capture.h b/include/media/blackfin/bfin_capture.h deleted file mode 100644 index a999a3970c69..000000000000 --- a/include/media/blackfin/bfin_capture.h +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _BFIN_CAPTURE_H_ | ||
3 | #define _BFIN_CAPTURE_H_ | ||
4 | |||
5 | #include <linux/i2c.h> | ||
6 | |||
7 | struct v4l2_input; | ||
8 | struct ppi_info; | ||
9 | |||
10 | struct bcap_route { | ||
11 | u32 input; | ||
12 | u32 output; | ||
13 | u32 ppi_control; | ||
14 | }; | ||
15 | |||
16 | struct bfin_capture_config { | ||
17 | /* card name */ | ||
18 | char *card_name; | ||
19 | /* inputs available at the sub device */ | ||
20 | struct v4l2_input *inputs; | ||
21 | /* number of inputs supported */ | ||
22 | int num_inputs; | ||
23 | /* routing information for each input */ | ||
24 | struct bcap_route *routes; | ||
25 | /* i2c bus adapter no */ | ||
26 | int i2c_adapter_id; | ||
27 | /* i2c subdevice board info */ | ||
28 | struct i2c_board_info board_info; | ||
29 | /* ppi board info */ | ||
30 | const struct ppi_info *ppi_info; | ||
31 | /* ppi control */ | ||
32 | unsigned long ppi_control; | ||
33 | /* ppi interrupt mask */ | ||
34 | u32 int_mask; | ||
35 | /* horizontal blanking pixels */ | ||
36 | int blank_pixels; | ||
37 | }; | ||
38 | |||
39 | #endif | ||
diff --git a/include/media/blackfin/ppi.h b/include/media/blackfin/ppi.h deleted file mode 100644 index 987e49e8f9c9..000000000000 --- a/include/media/blackfin/ppi.h +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | /* | ||
2 | * Analog Devices PPI header file | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _PPI_H_ | ||
17 | #define _PPI_H_ | ||
18 | |||
19 | #include <linux/interrupt.h> | ||
20 | #include <asm/blackfin.h> | ||
21 | #include <asm/bfin_ppi.h> | ||
22 | |||
23 | /* EPPI */ | ||
24 | #ifdef EPPI_EN | ||
25 | #define PORT_EN EPPI_EN | ||
26 | #define PORT_DIR EPPI_DIR | ||
27 | #define DMA32 0 | ||
28 | #define PACK_EN PACKEN | ||
29 | #endif | ||
30 | |||
31 | /* EPPI3 */ | ||
32 | #ifdef EPPI0_CTL2 | ||
33 | #define PORT_EN EPPI_CTL_EN | ||
34 | #define PORT_DIR EPPI_CTL_DIR | ||
35 | #define PACK_EN EPPI_CTL_PACKEN | ||
36 | #define DMA32 0 | ||
37 | #define DLEN_8 EPPI_CTL_DLEN08 | ||
38 | #define DLEN_16 EPPI_CTL_DLEN16 | ||
39 | #endif | ||
40 | |||
41 | struct ppi_if; | ||
42 | |||
43 | struct ppi_params { | ||
44 | u32 width; /* width in pixels */ | ||
45 | u32 height; /* height in lines */ | ||
46 | u32 hdelay; /* delay after the HSYNC in pixels */ | ||
47 | u32 vdelay; /* delay after the VSYNC in lines */ | ||
48 | u32 line; /* total pixels per line */ | ||
49 | u32 frame; /* total lines per frame */ | ||
50 | u32 hsync; /* HSYNC length in pixels */ | ||
51 | u32 vsync; /* VSYNC length in lines */ | ||
52 | int bpp; /* bits per pixel */ | ||
53 | int dlen; /* data length for ppi in bits */ | ||
54 | u32 ppi_control; /* ppi configuration */ | ||
55 | u32 int_mask; /* interrupt mask */ | ||
56 | }; | ||
57 | |||
58 | struct ppi_ops { | ||
59 | int (*attach_irq)(struct ppi_if *ppi, irq_handler_t handler); | ||
60 | void (*detach_irq)(struct ppi_if *ppi); | ||
61 | int (*start)(struct ppi_if *ppi); | ||
62 | int (*stop)(struct ppi_if *ppi); | ||
63 | int (*set_params)(struct ppi_if *ppi, struct ppi_params *params); | ||
64 | void (*update_addr)(struct ppi_if *ppi, unsigned long addr); | ||
65 | }; | ||
66 | |||
67 | enum ppi_type { | ||
68 | PPI_TYPE_PPI, | ||
69 | PPI_TYPE_EPPI, | ||
70 | PPI_TYPE_EPPI3, | ||
71 | }; | ||
72 | |||
73 | struct ppi_info { | ||
74 | enum ppi_type type; | ||
75 | int dma_ch; | ||
76 | int irq_err; | ||
77 | void __iomem *base; | ||
78 | const unsigned short *pin_req; | ||
79 | }; | ||
80 | |||
81 | struct ppi_if { | ||
82 | struct device *dev; | ||
83 | unsigned long ppi_control; | ||
84 | const struct ppi_ops *ops; | ||
85 | const struct ppi_info *info; | ||
86 | bool err_int; /* if we need request error interrupt */ | ||
87 | bool err; /* if ppi has fifo error */ | ||
88 | void *priv; | ||
89 | }; | ||
90 | |||
91 | struct ppi_if *ppi_create_instance(struct platform_device *pdev, | ||
92 | const struct ppi_info *info); | ||
93 | void ppi_delete_instance(struct ppi_if *ppi); | ||
94 | #endif | ||