]>
Commit | Line | Data |
---|---|---|
e55222ef GL |
1 | /* |
2 | * camera image capture (abstract) bus driver | |
3 | * | |
4 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | |
5 | * | |
6 | * This driver provides an interface between platform-specific camera | |
7 | * busses and camera devices. It should be used if the camera is | |
8 | * connected not over a "proper" bus like PCI or USB, but over a | |
9 | * special bus, like, for example, the Quick Capture interface on PXA270 | |
10 | * SoCs. Later it should also be used for i.MX31 SoCs from Freescale. | |
11 | * It can handle multiple cameras and / or multiple busses, which can | |
12 | * be used, e.g., in stereo-vision applications. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License version 2 as | |
16 | * published by the Free Software Foundation. | |
17 | */ | |
18 | ||
e55222ef | 19 | #include <linux/device.h> |
e55222ef | 20 | #include <linux/err.h> |
0fd327bd GL |
21 | #include <linux/i2c.h> |
22 | #include <linux/init.h> | |
23 | #include <linux/list.h> | |
24 | #include <linux/module.h> | |
e55222ef | 25 | #include <linux/mutex.h> |
0fd327bd | 26 | #include <linux/platform_device.h> |
e55222ef GL |
27 | #include <linux/vmalloc.h> |
28 | ||
0fd327bd | 29 | #include <media/soc_camera.h> |
e55222ef GL |
30 | #include <media/v4l2-common.h> |
31 | #include <media/v4l2-dev.h> | |
0fd327bd | 32 | #include <media/v4l2-ioctl.h> |
092d3921 | 33 | #include <media/videobuf-core.h> |
e55222ef | 34 | |
df2ed070 GL |
35 | /* Default to VGA resolution */ |
36 | #define DEFAULT_WIDTH 640 | |
37 | #define DEFAULT_HEIGHT 480 | |
38 | ||
e55222ef GL |
39 | static LIST_HEAD(hosts); |
40 | static LIST_HEAD(devices); | |
41 | static DEFINE_MUTEX(list_lock); | |
e55222ef | 42 | |
25c4d74e | 43 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( |
abe4c471 | 44 | struct soc_camera_device *icd, unsigned int fourcc) |
e55222ef GL |
45 | { |
46 | unsigned int i; | |
47 | ||
26f1b942 GL |
48 | for (i = 0; i < icd->num_formats; i++) |
49 | if (icd->formats[i].fourcc == fourcc) | |
50 | return icd->formats + i; | |
e55222ef GL |
51 | return NULL; |
52 | } | |
25c4d74e | 53 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); |
e55222ef | 54 | |
c2786ad2 GL |
55 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
56 | struct soc_camera_device *icd, unsigned int fourcc) | |
57 | { | |
58 | unsigned int i; | |
59 | ||
60 | for (i = 0; i < icd->num_user_formats; i++) | |
61 | if (icd->user_formats[i].host_fmt->fourcc == fourcc) | |
62 | return icd->user_formats + i; | |
63 | return NULL; | |
64 | } | |
65 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); | |
66 | ||
bd73b36f GL |
67 | /** |
68 | * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags | |
69 | * @icl: camera platform parameters | |
70 | * @flags: flags to be inverted according to platform configuration | |
71 | * @return: resulting flags | |
72 | */ | |
73 | unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, | |
74 | unsigned long flags) | |
75 | { | |
76 | unsigned long f; | |
77 | ||
78 | /* If only one of the two polarities is supported, switch to the opposite */ | |
79 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { | |
80 | f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); | |
81 | if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW) | |
82 | flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW; | |
83 | } | |
84 | ||
85 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { | |
86 | f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); | |
87 | if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW) | |
88 | flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW; | |
89 | } | |
90 | ||
91 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { | |
92 | f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); | |
93 | if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING) | |
94 | flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; | |
95 | } | |
96 | ||
97 | return flags; | |
98 | } | |
99 | EXPORT_SYMBOL(soc_camera_apply_sensor_flags); | |
100 | ||
72937890 | 101 | static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, |
abe4c471 | 102 | struct v4l2_format *f) |
e55222ef GL |
103 | { |
104 | struct soc_camera_file *icf = file->private_data; | |
105 | struct soc_camera_device *icd = icf->icd; | |
64f5905e | 106 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
107 | |
108 | WARN_ON(priv != file->private_data); | |
109 | ||
ad5f2e85 | 110 | /* limit format to hardware capabilities */ |
06daa1af | 111 | return ici->ops->try_fmt(icd, f); |
e55222ef GL |
112 | } |
113 | ||
114 | static int soc_camera_enum_input(struct file *file, void *priv, | |
115 | struct v4l2_input *inp) | |
116 | { | |
34d359db KM |
117 | struct soc_camera_file *icf = file->private_data; |
118 | struct soc_camera_device *icd = icf->icd; | |
119 | int ret = 0; | |
120 | ||
e55222ef GL |
121 | if (inp->index != 0) |
122 | return -EINVAL; | |
123 | ||
34d359db KM |
124 | if (icd->ops->enum_input) |
125 | ret = icd->ops->enum_input(icd, inp); | |
126 | else { | |
127 | /* default is camera */ | |
128 | inp->type = V4L2_INPUT_TYPE_CAMERA; | |
129 | inp->std = V4L2_STD_UNKNOWN; | |
130 | strcpy(inp->name, "Camera"); | |
131 | } | |
e55222ef | 132 | |
34d359db | 133 | return ret; |
e55222ef GL |
134 | } |
135 | ||
136 | static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i) | |
137 | { | |
138 | *i = 0; | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) | |
144 | { | |
145 | if (i > 0) | |
146 | return -EINVAL; | |
147 | ||
148 | return 0; | |
149 | } | |
150 | ||
151 | static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | |
152 | { | |
513791ab KM |
153 | struct soc_camera_file *icf = file->private_data; |
154 | struct soc_camera_device *icd = icf->icd; | |
155 | int ret = 0; | |
156 | ||
157 | if (icd->ops->set_std) | |
158 | ret = icd->ops->set_std(icd, a); | |
159 | ||
160 | return ret; | |
e55222ef GL |
161 | } |
162 | ||
163 | static int soc_camera_reqbufs(struct file *file, void *priv, | |
164 | struct v4l2_requestbuffers *p) | |
165 | { | |
166 | int ret; | |
167 | struct soc_camera_file *icf = file->private_data; | |
168 | struct soc_camera_device *icd = icf->icd; | |
64f5905e | 169 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
170 | |
171 | WARN_ON(priv != file->private_data); | |
172 | ||
7e28adb2 | 173 | dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory); |
e55222ef GL |
174 | |
175 | ret = videobuf_reqbufs(&icf->vb_vidq, p); | |
176 | if (ret < 0) | |
177 | return ret; | |
178 | ||
b8d9904c | 179 | return ici->ops->reqbufs(icf, p); |
e55222ef GL |
180 | } |
181 | ||
182 | static int soc_camera_querybuf(struct file *file, void *priv, | |
183 | struct v4l2_buffer *p) | |
184 | { | |
185 | struct soc_camera_file *icf = file->private_data; | |
186 | ||
187 | WARN_ON(priv != file->private_data); | |
188 | ||
189 | return videobuf_querybuf(&icf->vb_vidq, p); | |
190 | } | |
191 | ||
192 | static int soc_camera_qbuf(struct file *file, void *priv, | |
193 | struct v4l2_buffer *p) | |
194 | { | |
195 | struct soc_camera_file *icf = file->private_data; | |
196 | ||
197 | WARN_ON(priv != file->private_data); | |
198 | ||
199 | return videobuf_qbuf(&icf->vb_vidq, p); | |
200 | } | |
201 | ||
202 | static int soc_camera_dqbuf(struct file *file, void *priv, | |
203 | struct v4l2_buffer *p) | |
204 | { | |
205 | struct soc_camera_file *icf = file->private_data; | |
206 | ||
207 | WARN_ON(priv != file->private_data); | |
208 | ||
209 | return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); | |
210 | } | |
211 | ||
c2786ad2 GL |
212 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
213 | { | |
214 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | |
215 | int i, fmts = 0; | |
216 | ||
217 | if (!ici->ops->get_formats) | |
218 | /* | |
219 | * Fallback mode - the host will have to serve all | |
220 | * sensor-provided formats one-to-one to the user | |
221 | */ | |
222 | fmts = icd->num_formats; | |
223 | else | |
224 | /* | |
225 | * First pass - only count formats this host-sensor | |
226 | * configuration can provide | |
227 | */ | |
228 | for (i = 0; i < icd->num_formats; i++) | |
229 | fmts += ici->ops->get_formats(icd, i, NULL); | |
230 | ||
231 | if (!fmts) | |
232 | return -ENXIO; | |
233 | ||
234 | icd->user_formats = | |
235 | vmalloc(fmts * sizeof(struct soc_camera_format_xlate)); | |
236 | if (!icd->user_formats) | |
237 | return -ENOMEM; | |
238 | ||
239 | icd->num_user_formats = fmts; | |
c2786ad2 GL |
240 | |
241 | dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); | |
242 | ||
243 | /* Second pass - actually fill data formats */ | |
14df2cce | 244 | fmts = 0; |
c2786ad2 GL |
245 | for (i = 0; i < icd->num_formats; i++) |
246 | if (!ici->ops->get_formats) { | |
247 | icd->user_formats[i].host_fmt = icd->formats + i; | |
248 | icd->user_formats[i].cam_fmt = icd->formats + i; | |
249 | icd->user_formats[i].buswidth = icd->formats[i].depth; | |
250 | } else { | |
251 | fmts += ici->ops->get_formats(icd, i, | |
252 | &icd->user_formats[fmts]); | |
253 | } | |
254 | ||
255 | icd->current_fmt = icd->user_formats[0].host_fmt; | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | static void soc_camera_free_user_formats(struct soc_camera_device *icd) | |
261 | { | |
262 | vfree(icd->user_formats); | |
263 | } | |
264 | ||
df2ed070 GL |
265 | /* Called with .vb_lock held */ |
266 | static int soc_camera_set_fmt(struct soc_camera_file *icf, | |
267 | struct v4l2_format *f) | |
268 | { | |
269 | struct soc_camera_device *icd = icf->icd; | |
270 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | |
271 | struct v4l2_pix_format *pix = &f->fmt.pix; | |
272 | int ret; | |
273 | ||
274 | /* We always call try_fmt() before set_fmt() or set_crop() */ | |
275 | ret = ici->ops->try_fmt(icd, f); | |
276 | if (ret < 0) | |
277 | return ret; | |
278 | ||
279 | ret = ici->ops->set_fmt(icd, f); | |
280 | if (ret < 0) { | |
281 | return ret; | |
282 | } else if (!icd->current_fmt || | |
283 | icd->current_fmt->fourcc != pix->pixelformat) { | |
eff505fa | 284 | dev_err(ici->dev, |
df2ed070 GL |
285 | "Host driver hasn't set up current format correctly!\n"); |
286 | return -EINVAL; | |
287 | } | |
288 | ||
289 | icd->width = pix->width; | |
290 | icd->height = pix->height; | |
025c18a1 GL |
291 | icf->vb_vidq.field = |
292 | icd->field = pix->field; | |
293 | ||
df2ed070 GL |
294 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
295 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", | |
296 | f->type); | |
297 | ||
298 | dev_dbg(&icd->dev, "set width: %d height: %d\n", | |
299 | icd->width, icd->height); | |
300 | ||
301 | /* set physical bus parameters */ | |
302 | return ici->ops->set_bus_param(icd, pix->pixelformat); | |
303 | } | |
304 | ||
bec43661 | 305 | static int soc_camera_open(struct file *file) |
e55222ef | 306 | { |
9dc4e48f GL |
307 | struct video_device *vdev; |
308 | struct soc_camera_device *icd; | |
309 | struct soc_camera_host *ici; | |
e55222ef GL |
310 | struct soc_camera_file *icf; |
311 | int ret; | |
312 | ||
313 | icf = vmalloc(sizeof(*icf)); | |
314 | if (!icf) | |
315 | return -ENOMEM; | |
316 | ||
1c3bb743 GL |
317 | /* |
318 | * It is safe to dereference these pointers now as long as a user has | |
319 | * the video device open - we are protected by the held cdev reference. | |
320 | */ | |
9dc4e48f GL |
321 | |
322 | vdev = video_devdata(file); | |
5e85e732 | 323 | icd = container_of(vdev->parent, struct soc_camera_device, dev); |
9dc4e48f | 324 | ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
325 | |
326 | if (!try_module_get(icd->ops->owner)) { | |
327 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | |
328 | ret = -EINVAL; | |
329 | goto emgd; | |
330 | } | |
331 | ||
b8d9904c | 332 | if (!try_module_get(ici->ops->owner)) { |
e55222ef GL |
333 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); |
334 | ret = -EINVAL; | |
335 | goto emgi; | |
336 | } | |
337 | ||
1c3bb743 GL |
338 | /* Protect against icd->remove() until we module_get() both drivers. */ |
339 | mutex_lock(&icd->video_lock); | |
340 | ||
9dc4e48f | 341 | icf->icd = icd; |
1a0063a9 GL |
342 | icd->use_count++; |
343 | ||
9dc4e48f GL |
344 | /* Now we really have to activate the camera */ |
345 | if (icd->use_count == 1) { | |
025c18a1 | 346 | /* Restore parameters before the last close() per V4L2 API */ |
df2ed070 GL |
347 | struct v4l2_format f = { |
348 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | |
349 | .fmt.pix = { | |
025c18a1 GL |
350 | .width = icd->width, |
351 | .height = icd->height, | |
352 | .field = icd->field, | |
353 | .pixelformat = icd->current_fmt->fourcc, | |
354 | .colorspace = icd->current_fmt->colorspace, | |
df2ed070 GL |
355 | }, |
356 | }; | |
357 | ||
b8d9904c | 358 | ret = ici->ops->add(icd); |
9dc4e48f GL |
359 | if (ret < 0) { |
360 | dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); | |
9dc4e48f GL |
361 | goto eiciadd; |
362 | } | |
df2ed070 | 363 | |
df2ed070 GL |
364 | /* Try to configure with default parameters */ |
365 | ret = soc_camera_set_fmt(icf, &f); | |
366 | if (ret < 0) | |
367 | goto esfmt; | |
9dc4e48f GL |
368 | } |
369 | ||
1c3bb743 | 370 | mutex_unlock(&icd->video_lock); |
9dc4e48f | 371 | |
e55222ef GL |
372 | file->private_data = icf; |
373 | dev_dbg(&icd->dev, "camera device open\n"); | |
374 | ||
a034d1b7 | 375 | ici->ops->init_videobuf(&icf->vb_vidq, icd); |
e55222ef GL |
376 | |
377 | return 0; | |
378 | ||
df2ed070 GL |
379 | /* |
380 | * First three errors are entered with the .video_lock held | |
381 | * and use_count == 1 | |
382 | */ | |
383 | esfmt: | |
384 | ici->ops->remove(icd); | |
9dc4e48f | 385 | eiciadd: |
c2786ad2 | 386 | icd->use_count--; |
1c3bb743 | 387 | mutex_unlock(&icd->video_lock); |
b8d9904c | 388 | module_put(ici->ops->owner); |
e55222ef GL |
389 | emgi: |
390 | module_put(icd->ops->owner); | |
391 | emgd: | |
392 | vfree(icf); | |
393 | return ret; | |
394 | } | |
395 | ||
bec43661 | 396 | static int soc_camera_close(struct file *file) |
e55222ef GL |
397 | { |
398 | struct soc_camera_file *icf = file->private_data; | |
399 | struct soc_camera_device *icd = icf->icd; | |
400 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | |
401 | struct video_device *vdev = icd->vdev; | |
402 | ||
1c3bb743 | 403 | mutex_lock(&icd->video_lock); |
9dc4e48f | 404 | icd->use_count--; |
025c18a1 | 405 | if (!icd->use_count) |
b8d9904c | 406 | ici->ops->remove(icd); |
025c18a1 | 407 | |
1c3bb743 GL |
408 | mutex_unlock(&icd->video_lock); |
409 | ||
e55222ef | 410 | module_put(icd->ops->owner); |
b8d9904c | 411 | module_put(ici->ops->owner); |
9dc4e48f | 412 | |
1a0063a9 | 413 | vfree(icf); |
e55222ef | 414 | |
5e85e732 | 415 | dev_dbg(vdev->parent, "camera device close\n"); |
e55222ef GL |
416 | |
417 | return 0; | |
418 | } | |
419 | ||
aba360d8 | 420 | static ssize_t soc_camera_read(struct file *file, char __user *buf, |
abe4c471 | 421 | size_t count, loff_t *ppos) |
e55222ef GL |
422 | { |
423 | struct soc_camera_file *icf = file->private_data; | |
424 | struct soc_camera_device *icd = icf->icd; | |
425 | struct video_device *vdev = icd->vdev; | |
426 | int err = -EINVAL; | |
427 | ||
5e85e732 | 428 | dev_err(vdev->parent, "camera device read not implemented\n"); |
e55222ef GL |
429 | |
430 | return err; | |
431 | } | |
432 | ||
433 | static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) | |
434 | { | |
435 | struct soc_camera_file *icf = file->private_data; | |
436 | struct soc_camera_device *icd = icf->icd; | |
437 | int err; | |
438 | ||
439 | dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | |
440 | ||
441 | err = videobuf_mmap_mapper(&icf->vb_vidq, vma); | |
442 | ||
443 | dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n", | |
444 | (unsigned long)vma->vm_start, | |
445 | (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, | |
446 | err); | |
447 | ||
448 | return err; | |
449 | } | |
450 | ||
451 | static unsigned int soc_camera_poll(struct file *file, poll_table *pt) | |
452 | { | |
453 | struct soc_camera_file *icf = file->private_data; | |
454 | struct soc_camera_device *icd = icf->icd; | |
64f5905e | 455 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
456 | |
457 | if (list_empty(&icf->vb_vidq.stream)) { | |
458 | dev_err(&icd->dev, "Trying to poll with no queued buffers!\n"); | |
459 | return POLLERR; | |
460 | } | |
461 | ||
b8d9904c | 462 | return ici->ops->poll(file, pt); |
e55222ef GL |
463 | } |
464 | ||
bec43661 | 465 | static struct v4l2_file_operations soc_camera_fops = { |
e55222ef GL |
466 | .owner = THIS_MODULE, |
467 | .open = soc_camera_open, | |
468 | .release = soc_camera_close, | |
469 | .ioctl = video_ioctl2, | |
470 | .read = soc_camera_read, | |
471 | .mmap = soc_camera_mmap, | |
472 | .poll = soc_camera_poll, | |
e55222ef GL |
473 | }; |
474 | ||
72937890 | 475 | static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, |
abe4c471 | 476 | struct v4l2_format *f) |
e55222ef GL |
477 | { |
478 | struct soc_camera_file *icf = file->private_data; | |
479 | struct soc_camera_device *icd = icf->icd; | |
e55222ef | 480 | int ret; |
e55222ef GL |
481 | |
482 | WARN_ON(priv != file->private_data); | |
483 | ||
1c3bb743 GL |
484 | mutex_lock(&icf->vb_vidq.vb_lock); |
485 | ||
486 | if (videobuf_queue_is_busy(&icf->vb_vidq)) { | |
487 | dev_err(&icd->dev, "S_FMT denied: queue busy\n"); | |
488 | ret = -EBUSY; | |
489 | goto unlock; | |
490 | } | |
491 | ||
df2ed070 | 492 | ret = soc_camera_set_fmt(icf, f); |
1c3bb743 GL |
493 | |
494 | unlock: | |
495 | mutex_unlock(&icf->vb_vidq.vb_lock); | |
496 | ||
497 | return ret; | |
e55222ef GL |
498 | } |
499 | ||
72937890 | 500 | static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, |
abe4c471 | 501 | struct v4l2_fmtdesc *f) |
e55222ef GL |
502 | { |
503 | struct soc_camera_file *icf = file->private_data; | |
504 | struct soc_camera_device *icd = icf->icd; | |
505 | const struct soc_camera_data_format *format; | |
506 | ||
507 | WARN_ON(priv != file->private_data); | |
508 | ||
c2786ad2 | 509 | if (f->index >= icd->num_user_formats) |
e55222ef GL |
510 | return -EINVAL; |
511 | ||
c2786ad2 | 512 | format = icd->user_formats[f->index].host_fmt; |
e55222ef GL |
513 | |
514 | strlcpy(f->description, format->name, sizeof(f->description)); | |
515 | f->pixelformat = format->fourcc; | |
516 | return 0; | |
517 | } | |
518 | ||
72937890 | 519 | static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, |
abe4c471 | 520 | struct v4l2_format *f) |
e55222ef GL |
521 | { |
522 | struct soc_camera_file *icf = file->private_data; | |
523 | struct soc_camera_device *icd = icf->icd; | |
64f5905e | 524 | struct v4l2_pix_format *pix = &f->fmt.pix; |
e55222ef GL |
525 | |
526 | WARN_ON(priv != file->private_data); | |
527 | ||
64f5905e GL |
528 | pix->width = icd->width; |
529 | pix->height = icd->height; | |
530 | pix->field = icf->vb_vidq.field; | |
531 | pix->pixelformat = icd->current_fmt->fourcc; | |
532 | pix->bytesperline = pix->width * | |
25c4d74e | 533 | DIV_ROUND_UP(icd->current_fmt->depth, 8); |
64f5905e | 534 | pix->sizeimage = pix->height * pix->bytesperline; |
e55222ef GL |
535 | dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", |
536 | icd->current_fmt->fourcc); | |
537 | return 0; | |
538 | } | |
539 | ||
540 | static int soc_camera_querycap(struct file *file, void *priv, | |
541 | struct v4l2_capability *cap) | |
542 | { | |
543 | struct soc_camera_file *icf = file->private_data; | |
544 | struct soc_camera_device *icd = icf->icd; | |
64f5905e | 545 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
546 | |
547 | WARN_ON(priv != file->private_data); | |
548 | ||
549 | strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver)); | |
b8d9904c | 550 | return ici->ops->querycap(ici, cap); |
e55222ef GL |
551 | } |
552 | ||
553 | static int soc_camera_streamon(struct file *file, void *priv, | |
554 | enum v4l2_buf_type i) | |
555 | { | |
556 | struct soc_camera_file *icf = file->private_data; | |
557 | struct soc_camera_device *icd = icf->icd; | |
1c3bb743 | 558 | int ret; |
e55222ef GL |
559 | |
560 | WARN_ON(priv != file->private_data); | |
561 | ||
7e28adb2 | 562 | dev_dbg(&icd->dev, "%s\n", __func__); |
e55222ef GL |
563 | |
564 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
565 | return -EINVAL; | |
566 | ||
1c3bb743 GL |
567 | mutex_lock(&icd->video_lock); |
568 | ||
e55222ef GL |
569 | icd->ops->start_capture(icd); |
570 | ||
571 | /* This calls buf_queue from host driver's videobuf_queue_ops */ | |
1c3bb743 GL |
572 | ret = videobuf_streamon(&icf->vb_vidq); |
573 | ||
574 | mutex_unlock(&icd->video_lock); | |
575 | ||
576 | return ret; | |
e55222ef GL |
577 | } |
578 | ||
579 | static int soc_camera_streamoff(struct file *file, void *priv, | |
580 | enum v4l2_buf_type i) | |
581 | { | |
582 | struct soc_camera_file *icf = file->private_data; | |
583 | struct soc_camera_device *icd = icf->icd; | |
584 | ||
585 | WARN_ON(priv != file->private_data); | |
586 | ||
7e28adb2 | 587 | dev_dbg(&icd->dev, "%s\n", __func__); |
e55222ef GL |
588 | |
589 | if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
590 | return -EINVAL; | |
591 | ||
1c3bb743 GL |
592 | mutex_lock(&icd->video_lock); |
593 | ||
e55222ef GL |
594 | /* This calls buf_release from host driver's videobuf_queue_ops for all |
595 | * remaining buffers. When the last buffer is freed, stop capture */ | |
596 | videobuf_streamoff(&icf->vb_vidq); | |
597 | ||
598 | icd->ops->stop_capture(icd); | |
599 | ||
1c3bb743 GL |
600 | mutex_unlock(&icd->video_lock); |
601 | ||
e55222ef GL |
602 | return 0; |
603 | } | |
604 | ||
605 | static int soc_camera_queryctrl(struct file *file, void *priv, | |
606 | struct v4l2_queryctrl *qc) | |
607 | { | |
608 | struct soc_camera_file *icf = file->private_data; | |
609 | struct soc_camera_device *icd = icf->icd; | |
610 | int i; | |
611 | ||
612 | WARN_ON(priv != file->private_data); | |
613 | ||
614 | if (!qc->id) | |
615 | return -EINVAL; | |
616 | ||
617 | for (i = 0; i < icd->ops->num_controls; i++) | |
618 | if (qc->id == icd->ops->controls[i].id) { | |
619 | memcpy(qc, &(icd->ops->controls[i]), | |
620 | sizeof(*qc)); | |
621 | return 0; | |
622 | } | |
623 | ||
624 | return -EINVAL; | |
625 | } | |
626 | ||
627 | static int soc_camera_g_ctrl(struct file *file, void *priv, | |
628 | struct v4l2_control *ctrl) | |
629 | { | |
630 | struct soc_camera_file *icf = file->private_data; | |
631 | struct soc_camera_device *icd = icf->icd; | |
632 | ||
633 | WARN_ON(priv != file->private_data); | |
634 | ||
635 | switch (ctrl->id) { | |
636 | case V4L2_CID_GAIN: | |
637 | if (icd->gain == (unsigned short)~0) | |
638 | return -EINVAL; | |
639 | ctrl->value = icd->gain; | |
640 | return 0; | |
641 | case V4L2_CID_EXPOSURE: | |
642 | if (icd->exposure == (unsigned short)~0) | |
643 | return -EINVAL; | |
644 | ctrl->value = icd->exposure; | |
645 | return 0; | |
646 | } | |
647 | ||
648 | if (icd->ops->get_control) | |
649 | return icd->ops->get_control(icd, ctrl); | |
650 | return -EINVAL; | |
651 | } | |
652 | ||
653 | static int soc_camera_s_ctrl(struct file *file, void *priv, | |
654 | struct v4l2_control *ctrl) | |
655 | { | |
656 | struct soc_camera_file *icf = file->private_data; | |
657 | struct soc_camera_device *icd = icf->icd; | |
658 | ||
659 | WARN_ON(priv != file->private_data); | |
660 | ||
661 | if (icd->ops->set_control) | |
662 | return icd->ops->set_control(icd, ctrl); | |
663 | return -EINVAL; | |
664 | } | |
665 | ||
666 | static int soc_camera_cropcap(struct file *file, void *fh, | |
667 | struct v4l2_cropcap *a) | |
668 | { | |
669 | struct soc_camera_file *icf = file->private_data; | |
670 | struct soc_camera_device *icd = icf->icd; | |
671 | ||
672 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
673 | a->bounds.left = icd->x_min; | |
674 | a->bounds.top = icd->y_min; | |
675 | a->bounds.width = icd->width_max; | |
676 | a->bounds.height = icd->height_max; | |
677 | a->defrect.left = icd->x_min; | |
678 | a->defrect.top = icd->y_min; | |
df2ed070 GL |
679 | a->defrect.width = DEFAULT_WIDTH; |
680 | a->defrect.height = DEFAULT_HEIGHT; | |
e55222ef GL |
681 | a->pixelaspect.numerator = 1; |
682 | a->pixelaspect.denominator = 1; | |
683 | ||
684 | return 0; | |
685 | } | |
686 | ||
687 | static int soc_camera_g_crop(struct file *file, void *fh, | |
688 | struct v4l2_crop *a) | |
689 | { | |
690 | struct soc_camera_file *icf = file->private_data; | |
691 | struct soc_camera_device *icd = icf->icd; | |
692 | ||
693 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
694 | a->c.left = icd->x_current; | |
695 | a->c.top = icd->y_current; | |
696 | a->c.width = icd->width; | |
697 | a->c.height = icd->height; | |
698 | ||
699 | return 0; | |
700 | } | |
701 | ||
702 | static int soc_camera_s_crop(struct file *file, void *fh, | |
703 | struct v4l2_crop *a) | |
704 | { | |
705 | struct soc_camera_file *icf = file->private_data; | |
706 | struct soc_camera_device *icd = icf->icd; | |
64f5905e | 707 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
708 | int ret; |
709 | ||
710 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
711 | return -EINVAL; | |
712 | ||
1c3bb743 GL |
713 | /* Cropping is allowed during a running capture, guard consistency */ |
714 | mutex_lock(&icf->vb_vidq.vb_lock); | |
715 | ||
09e231b3 | 716 | ret = ici->ops->set_crop(icd, &a->c); |
e55222ef GL |
717 | if (!ret) { |
718 | icd->width = a->c.width; | |
719 | icd->height = a->c.height; | |
720 | icd->x_current = a->c.left; | |
721 | icd->y_current = a->c.top; | |
722 | } | |
723 | ||
1c3bb743 GL |
724 | mutex_unlock(&icf->vb_vidq.vb_lock); |
725 | ||
e55222ef GL |
726 | return ret; |
727 | } | |
728 | ||
729 | static int soc_camera_g_chip_ident(struct file *file, void *fh, | |
aecde8b5 | 730 | struct v4l2_dbg_chip_ident *id) |
e55222ef GL |
731 | { |
732 | struct soc_camera_file *icf = file->private_data; | |
733 | struct soc_camera_device *icd = icf->icd; | |
734 | ||
735 | if (!icd->ops->get_chip_id) | |
736 | return -EINVAL; | |
737 | ||
738 | return icd->ops->get_chip_id(icd, id); | |
739 | } | |
740 | ||
741 | #ifdef CONFIG_VIDEO_ADV_DEBUG | |
742 | static int soc_camera_g_register(struct file *file, void *fh, | |
aecde8b5 | 743 | struct v4l2_dbg_register *reg) |
e55222ef GL |
744 | { |
745 | struct soc_camera_file *icf = file->private_data; | |
746 | struct soc_camera_device *icd = icf->icd; | |
747 | ||
748 | if (!icd->ops->get_register) | |
749 | return -EINVAL; | |
750 | ||
751 | return icd->ops->get_register(icd, reg); | |
752 | } | |
753 | ||
754 | static int soc_camera_s_register(struct file *file, void *fh, | |
aecde8b5 | 755 | struct v4l2_dbg_register *reg) |
e55222ef GL |
756 | { |
757 | struct soc_camera_file *icf = file->private_data; | |
758 | struct soc_camera_device *icd = icf->icd; | |
759 | ||
760 | if (!icd->ops->set_register) | |
761 | return -EINVAL; | |
762 | ||
763 | return icd->ops->set_register(icd, reg); | |
764 | } | |
765 | #endif | |
766 | ||
767 | static int device_register_link(struct soc_camera_device *icd) | |
768 | { | |
eee1663f GL |
769 | int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); |
770 | ||
771 | if (!ret) | |
772 | ret = device_register(&icd->dev); | |
e55222ef GL |
773 | |
774 | if (ret < 0) { | |
775 | /* Prevent calling device_unregister() */ | |
776 | icd->dev.parent = NULL; | |
777 | dev_err(&icd->dev, "Cannot register device: %d\n", ret); | |
778 | /* Even if probe() was unsuccessful for all registered drivers, | |
779 | * device_register() returns 0, and we add the link, just to | |
780 | * document this camera's control device */ | |
781 | } else if (icd->control) | |
782 | /* Have to sysfs_remove_link() before device_unregister()? */ | |
783 | if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj, | |
784 | "control")) | |
785 | dev_warn(&icd->dev, | |
786 | "Failed creating the control symlink\n"); | |
787 | return ret; | |
788 | } | |
789 | ||
790 | /* So far this function cannot fail */ | |
791 | static void scan_add_host(struct soc_camera_host *ici) | |
792 | { | |
793 | struct soc_camera_device *icd; | |
794 | ||
795 | mutex_lock(&list_lock); | |
796 | ||
797 | list_for_each_entry(icd, &devices, list) { | |
798 | if (icd->iface == ici->nr) { | |
eff505fa | 799 | icd->dev.parent = ici->dev; |
e55222ef GL |
800 | device_register_link(icd); |
801 | } | |
802 | } | |
803 | ||
804 | mutex_unlock(&list_lock); | |
805 | } | |
806 | ||
807 | /* return: 0 if no match found or a match found and | |
808 | * device_register() successful, error code otherwise */ | |
809 | static int scan_add_device(struct soc_camera_device *icd) | |
810 | { | |
811 | struct soc_camera_host *ici; | |
812 | int ret = 0; | |
813 | ||
814 | mutex_lock(&list_lock); | |
815 | ||
816 | list_add_tail(&icd->list, &devices); | |
817 | ||
818 | /* Watch out for class_for_each_device / class_find_device API by | |
819 | * Dave Young <hidave.darkstar@gmail.com> */ | |
820 | list_for_each_entry(ici, &hosts, list) { | |
821 | if (icd->iface == ici->nr) { | |
822 | ret = 1; | |
eff505fa | 823 | icd->dev.parent = ici->dev; |
e55222ef GL |
824 | break; |
825 | } | |
826 | } | |
827 | ||
828 | mutex_unlock(&list_lock); | |
829 | ||
830 | if (ret) | |
831 | ret = device_register_link(icd); | |
832 | ||
833 | return ret; | |
834 | } | |
835 | ||
836 | static int soc_camera_probe(struct device *dev) | |
837 | { | |
838 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | |
64f5905e | 839 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
e55222ef GL |
840 | int ret; |
841 | ||
1c3bb743 GL |
842 | /* |
843 | * Possible race scenario: | |
844 | * modprobe <camera-host-driver> triggers __func__ | |
845 | * at this moment respective <camera-sensor-driver> gets rmmod'ed | |
846 | * to protect take module references. | |
847 | */ | |
848 | ||
849 | if (!try_module_get(icd->ops->owner)) { | |
850 | dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); | |
851 | ret = -EINVAL; | |
852 | goto emgd; | |
853 | } | |
854 | ||
855 | if (!try_module_get(ici->ops->owner)) { | |
856 | dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); | |
857 | ret = -EINVAL; | |
858 | goto emgi; | |
859 | } | |
860 | ||
861 | mutex_lock(&icd->video_lock); | |
862 | ||
9dc4e48f GL |
863 | /* We only call ->add() here to activate and probe the camera. |
864 | * We shall ->remove() and deactivate it immediately afterwards. */ | |
b8d9904c | 865 | ret = ici->ops->add(icd); |
e55222ef | 866 | if (ret < 0) |
1c3bb743 | 867 | goto eiadd; |
e55222ef | 868 | |
26f1b942 | 869 | ret = icd->ops->probe(icd); |
9dc4e48f | 870 | if (ret >= 0) { |
e55222ef GL |
871 | const struct v4l2_queryctrl *qctrl; |
872 | ||
873 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN); | |
874 | icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0; | |
875 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | |
876 | icd->exposure = qctrl ? qctrl->default_value : | |
877 | (unsigned short)~0; | |
025c18a1 GL |
878 | |
879 | ret = soc_camera_init_user_formats(icd); | |
c06950ae GL |
880 | if (ret < 0) { |
881 | if (icd->ops->remove) | |
882 | icd->ops->remove(icd); | |
025c18a1 | 883 | goto eiufmt; |
c06950ae | 884 | } |
025c18a1 GL |
885 | |
886 | icd->height = DEFAULT_HEIGHT; | |
887 | icd->width = DEFAULT_WIDTH; | |
888 | icd->field = V4L2_FIELD_ANY; | |
e55222ef GL |
889 | } |
890 | ||
025c18a1 GL |
891 | eiufmt: |
892 | ici->ops->remove(icd); | |
1c3bb743 GL |
893 | eiadd: |
894 | mutex_unlock(&icd->video_lock); | |
895 | module_put(ici->ops->owner); | |
896 | emgi: | |
897 | module_put(icd->ops->owner); | |
898 | emgd: | |
e55222ef GL |
899 | return ret; |
900 | } | |
901 | ||
902 | /* This is called on device_unregister, which only means we have to disconnect | |
903 | * from the host, but not remove ourselves from the device list */ | |
904 | static int soc_camera_remove(struct device *dev) | |
905 | { | |
906 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | |
e55222ef | 907 | |
c06950ae | 908 | mutex_lock(&icd->video_lock); |
26f1b942 GL |
909 | if (icd->ops->remove) |
910 | icd->ops->remove(icd); | |
c06950ae | 911 | mutex_unlock(&icd->video_lock); |
e55222ef | 912 | |
025c18a1 GL |
913 | soc_camera_free_user_formats(icd); |
914 | ||
e55222ef GL |
915 | return 0; |
916 | } | |
917 | ||
2e521061 RJ |
918 | static int soc_camera_suspend(struct device *dev, pm_message_t state) |
919 | { | |
920 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | |
921 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | |
922 | int ret = 0; | |
923 | ||
924 | if (ici->ops->suspend) | |
925 | ret = ici->ops->suspend(icd, state); | |
926 | ||
927 | return ret; | |
928 | } | |
929 | ||
930 | static int soc_camera_resume(struct device *dev) | |
931 | { | |
932 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | |
933 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | |
934 | int ret = 0; | |
935 | ||
936 | if (ici->ops->resume) | |
937 | ret = ici->ops->resume(icd); | |
938 | ||
939 | return ret; | |
940 | } | |
941 | ||
e55222ef GL |
942 | static struct bus_type soc_camera_bus_type = { |
943 | .name = "soc-camera", | |
944 | .probe = soc_camera_probe, | |
945 | .remove = soc_camera_remove, | |
2e521061 RJ |
946 | .suspend = soc_camera_suspend, |
947 | .resume = soc_camera_resume, | |
e55222ef GL |
948 | }; |
949 | ||
950 | static struct device_driver ic_drv = { | |
951 | .name = "camera", | |
952 | .bus = &soc_camera_bus_type, | |
953 | .owner = THIS_MODULE, | |
954 | }; | |
955 | ||
e55222ef GL |
956 | static void dummy_release(struct device *dev) |
957 | { | |
958 | } | |
959 | ||
b8d9904c | 960 | int soc_camera_host_register(struct soc_camera_host *ici) |
e55222ef | 961 | { |
e55222ef GL |
962 | struct soc_camera_host *ix; |
963 | ||
64f5905e GL |
964 | if (!ici || !ici->ops || |
965 | !ici->ops->try_fmt || | |
966 | !ici->ops->set_fmt || | |
09e231b3 | 967 | !ici->ops->set_crop || |
64f5905e GL |
968 | !ici->ops->set_bus_param || |
969 | !ici->ops->querycap || | |
970 | !ici->ops->init_videobuf || | |
971 | !ici->ops->reqbufs || | |
972 | !ici->ops->add || | |
973 | !ici->ops->remove || | |
eff505fa GL |
974 | !ici->ops->poll || |
975 | !ici->dev) | |
e55222ef GL |
976 | return -EINVAL; |
977 | ||
e55222ef GL |
978 | mutex_lock(&list_lock); |
979 | list_for_each_entry(ix, &hosts, list) { | |
980 | if (ix->nr == ici->nr) { | |
981 | mutex_unlock(&list_lock); | |
982 | return -EBUSY; | |
983 | } | |
984 | } | |
985 | ||
eff505fa GL |
986 | dev_set_drvdata(ici->dev, ici); |
987 | ||
e55222ef GL |
988 | list_add_tail(&ici->list, &hosts); |
989 | mutex_unlock(&list_lock); | |
990 | ||
e55222ef GL |
991 | scan_add_host(ici); |
992 | ||
993 | return 0; | |
e55222ef GL |
994 | } |
995 | EXPORT_SYMBOL(soc_camera_host_register); | |
996 | ||
997 | /* Unregister all clients! */ | |
998 | void soc_camera_host_unregister(struct soc_camera_host *ici) | |
999 | { | |
1000 | struct soc_camera_device *icd; | |
1001 | ||
1002 | mutex_lock(&list_lock); | |
1003 | ||
1004 | list_del(&ici->list); | |
1005 | ||
1006 | list_for_each_entry(icd, &devices, list) { | |
eff505fa | 1007 | if (icd->dev.parent == ici->dev) { |
e55222ef GL |
1008 | device_unregister(&icd->dev); |
1009 | /* Not before device_unregister(), .remove | |
b8d9904c | 1010 | * needs parent to call ici->ops->remove() */ |
e55222ef GL |
1011 | icd->dev.parent = NULL; |
1012 | memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj)); | |
1013 | } | |
1014 | } | |
1015 | ||
1016 | mutex_unlock(&list_lock); | |
1017 | ||
eff505fa | 1018 | dev_set_drvdata(ici->dev, NULL); |
e55222ef GL |
1019 | } |
1020 | EXPORT_SYMBOL(soc_camera_host_unregister); | |
1021 | ||
1022 | /* Image capture device */ | |
1023 | int soc_camera_device_register(struct soc_camera_device *icd) | |
1024 | { | |
1025 | struct soc_camera_device *ix; | |
1026 | int num = -1, i; | |
1027 | ||
64f5905e GL |
1028 | if (!icd || !icd->ops || |
1029 | !icd->ops->probe || | |
1030 | !icd->ops->init || | |
1031 | !icd->ops->release || | |
1032 | !icd->ops->start_capture || | |
1033 | !icd->ops->stop_capture || | |
09e231b3 | 1034 | !icd->ops->set_crop || |
64f5905e GL |
1035 | !icd->ops->set_fmt || |
1036 | !icd->ops->try_fmt || | |
1037 | !icd->ops->query_bus_param || | |
1038 | !icd->ops->set_bus_param) | |
e55222ef GL |
1039 | return -EINVAL; |
1040 | ||
1041 | for (i = 0; i < 256 && num < 0; i++) { | |
1042 | num = i; | |
1043 | list_for_each_entry(ix, &devices, list) { | |
1044 | if (ix->iface == icd->iface && ix->devnum == i) { | |
1045 | num = -1; | |
1046 | break; | |
1047 | } | |
1048 | } | |
1049 | } | |
1050 | ||
1051 | if (num < 0) | |
1052 | /* ok, we have 256 cameras on this host... | |
1053 | * man, stay reasonable... */ | |
1054 | return -ENOMEM; | |
1055 | ||
1056 | icd->devnum = num; | |
1057 | icd->dev.bus = &soc_camera_bus_type; | |
e55222ef | 1058 | |
64f5905e GL |
1059 | icd->dev.release = dummy_release; |
1060 | icd->use_count = 0; | |
1061 | icd->host_priv = NULL; | |
1c3bb743 | 1062 | mutex_init(&icd->video_lock); |
e55222ef | 1063 | |
e55222ef GL |
1064 | return scan_add_device(icd); |
1065 | } | |
1066 | EXPORT_SYMBOL(soc_camera_device_register); | |
1067 | ||
1068 | void soc_camera_device_unregister(struct soc_camera_device *icd) | |
1069 | { | |
1070 | mutex_lock(&list_lock); | |
1071 | list_del(&icd->list); | |
1072 | ||
1073 | /* The bus->remove will be eventually called */ | |
1074 | if (icd->dev.parent) | |
1075 | device_unregister(&icd->dev); | |
1076 | mutex_unlock(&list_lock); | |
1077 | } | |
1078 | EXPORT_SYMBOL(soc_camera_device_unregister); | |
1079 | ||
a399810c HV |
1080 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { |
1081 | .vidioc_querycap = soc_camera_querycap, | |
1082 | .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, | |
1083 | .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, | |
1084 | .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, | |
1085 | .vidioc_enum_input = soc_camera_enum_input, | |
1086 | .vidioc_g_input = soc_camera_g_input, | |
1087 | .vidioc_s_input = soc_camera_s_input, | |
1088 | .vidioc_s_std = soc_camera_s_std, | |
1089 | .vidioc_reqbufs = soc_camera_reqbufs, | |
1090 | .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, | |
1091 | .vidioc_querybuf = soc_camera_querybuf, | |
1092 | .vidioc_qbuf = soc_camera_qbuf, | |
1093 | .vidioc_dqbuf = soc_camera_dqbuf, | |
1094 | .vidioc_streamon = soc_camera_streamon, | |
1095 | .vidioc_streamoff = soc_camera_streamoff, | |
1096 | .vidioc_queryctrl = soc_camera_queryctrl, | |
1097 | .vidioc_g_ctrl = soc_camera_g_ctrl, | |
1098 | .vidioc_s_ctrl = soc_camera_s_ctrl, | |
1099 | .vidioc_cropcap = soc_camera_cropcap, | |
1100 | .vidioc_g_crop = soc_camera_g_crop, | |
1101 | .vidioc_s_crop = soc_camera_s_crop, | |
1102 | .vidioc_g_chip_ident = soc_camera_g_chip_ident, | |
1103 | #ifdef CONFIG_VIDEO_ADV_DEBUG | |
1104 | .vidioc_g_register = soc_camera_g_register, | |
1105 | .vidioc_s_register = soc_camera_s_register, | |
1106 | #endif | |
1107 | }; | |
1108 | ||
1c3bb743 GL |
1109 | /* |
1110 | * Usually called from the struct soc_camera_ops .probe() method, i.e., from | |
1111 | * soc_camera_probe() above with .video_lock held | |
1112 | */ | |
e55222ef GL |
1113 | int soc_camera_video_start(struct soc_camera_device *icd) |
1114 | { | |
1115 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | |
1116 | int err = -ENOMEM; | |
1117 | struct video_device *vdev; | |
1118 | ||
1119 | if (!icd->dev.parent) | |
1120 | return -ENODEV; | |
1121 | ||
1122 | vdev = video_device_alloc(); | |
1123 | if (!vdev) | |
1124 | goto evidallocd; | |
eff505fa | 1125 | dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); |
e55222ef GL |
1126 | |
1127 | strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); | |
1c3bb743 | 1128 | |
5e85e732 | 1129 | vdev->parent = &icd->dev; |
e55222ef GL |
1130 | vdev->current_norm = V4L2_STD_UNKNOWN; |
1131 | vdev->fops = &soc_camera_fops; | |
a399810c | 1132 | vdev->ioctl_ops = &soc_camera_ioctl_ops; |
e55222ef GL |
1133 | vdev->release = video_device_release; |
1134 | vdev->minor = -1; | |
1135 | vdev->tvnorms = V4L2_STD_UNKNOWN, | |
e55222ef | 1136 | |
e55222ef GL |
1137 | err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); |
1138 | if (err < 0) { | |
5e85e732 | 1139 | dev_err(vdev->parent, "video_register_device failed\n"); |
e55222ef GL |
1140 | goto evidregd; |
1141 | } | |
1142 | icd->vdev = vdev; | |
1143 | ||
1144 | return 0; | |
1145 | ||
1146 | evidregd: | |
1147 | video_device_release(vdev); | |
1148 | evidallocd: | |
1149 | return err; | |
1150 | } | |
1151 | EXPORT_SYMBOL(soc_camera_video_start); | |
1152 | ||
c06950ae | 1153 | /* Called from client .remove() methods with .video_lock held */ |
e55222ef GL |
1154 | void soc_camera_video_stop(struct soc_camera_device *icd) |
1155 | { | |
1156 | struct video_device *vdev = icd->vdev; | |
1157 | ||
7e28adb2 | 1158 | dev_dbg(&icd->dev, "%s\n", __func__); |
e55222ef GL |
1159 | |
1160 | if (!icd->dev.parent || !vdev) | |
1161 | return; | |
1162 | ||
e55222ef GL |
1163 | video_unregister_device(vdev); |
1164 | icd->vdev = NULL; | |
e55222ef GL |
1165 | } |
1166 | EXPORT_SYMBOL(soc_camera_video_stop); | |
1167 | ||
0fd327bd GL |
1168 | static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) |
1169 | { | |
1170 | struct soc_camera_link *icl = pdev->dev.platform_data; | |
1171 | struct i2c_adapter *adap; | |
1172 | struct i2c_client *client; | |
1173 | ||
1174 | if (!icl) | |
1175 | return -EINVAL; | |
1176 | ||
1177 | adap = i2c_get_adapter(icl->i2c_adapter_id); | |
1178 | if (!adap) { | |
1179 | dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n", | |
1180 | icl->i2c_adapter_id); | |
1181 | /* -ENODEV and -ENXIO do not produce an error on probe()... */ | |
1182 | return -ENOENT; | |
1183 | } | |
1184 | ||
1185 | icl->board_info->platform_data = icl; | |
1186 | client = i2c_new_device(adap, icl->board_info); | |
1187 | if (!client) { | |
1188 | i2c_put_adapter(adap); | |
1189 | return -ENOMEM; | |
1190 | } | |
1191 | ||
1192 | platform_set_drvdata(pdev, client); | |
1193 | ||
1194 | return 0; | |
1195 | } | |
1196 | ||
1197 | static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) | |
1198 | { | |
1199 | struct i2c_client *client = platform_get_drvdata(pdev); | |
1200 | ||
1201 | if (!client) | |
1202 | return -ENODEV; | |
1203 | ||
1204 | i2c_unregister_device(client); | |
1205 | i2c_put_adapter(client->adapter); | |
1206 | ||
1207 | return 0; | |
1208 | } | |
1209 | ||
1210 | static struct platform_driver __refdata soc_camera_pdrv = { | |
1211 | .probe = soc_camera_pdrv_probe, | |
e36bc31f | 1212 | .remove = __devexit_p(soc_camera_pdrv_remove), |
0fd327bd GL |
1213 | .driver = { |
1214 | .name = "soc-camera-pdrv", | |
1215 | .owner = THIS_MODULE, | |
1216 | }, | |
1217 | }; | |
1218 | ||
e55222ef GL |
1219 | static int __init soc_camera_init(void) |
1220 | { | |
1221 | int ret = bus_register(&soc_camera_bus_type); | |
1222 | if (ret) | |
1223 | return ret; | |
1224 | ret = driver_register(&ic_drv); | |
1225 | if (ret) | |
1226 | goto edrvr; | |
e55222ef | 1227 | |
0fd327bd GL |
1228 | ret = platform_driver_register(&soc_camera_pdrv); |
1229 | if (ret) | |
1230 | goto epdr; | |
1231 | ||
e55222ef GL |
1232 | return 0; |
1233 | ||
0fd327bd GL |
1234 | epdr: |
1235 | driver_unregister(&ic_drv); | |
e55222ef GL |
1236 | edrvr: |
1237 | bus_unregister(&soc_camera_bus_type); | |
1238 | return ret; | |
1239 | } | |
1240 | ||
1241 | static void __exit soc_camera_exit(void) | |
1242 | { | |
0fd327bd | 1243 | platform_driver_unregister(&soc_camera_pdrv); |
e55222ef GL |
1244 | driver_unregister(&ic_drv); |
1245 | bus_unregister(&soc_camera_bus_type); | |
1246 | } | |
1247 | ||
1248 | module_init(soc_camera_init); | |
1249 | module_exit(soc_camera_exit); | |
1250 | ||
1251 | MODULE_DESCRIPTION("Image capture bus driver"); | |
1252 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | |
1253 | MODULE_LICENSE("GPL"); | |
0fd327bd | 1254 | MODULE_ALIAS("platform:soc-camera-pdrv"); |