blob: 07525e74c4b4a82a46f5fc33da597f44b0ac4be0 [file] [log] [blame]
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001/*
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
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030019#include <linux/device.h>
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030020#include <linux/err.h>
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -030021#include <linux/i2c.h>
22#include <linux/init.h>
23#include <linux/list.h>
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030024#include <linux/mutex.h>
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -030025#include <linux/module.h>
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -030026#include <linux/platform_device.h>
Alberto Panizzo96e442c2010-12-02 07:43:37 -030027#include <linux/regulator/consumer.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -030029#include <linux/pm_runtime.h>
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030030#include <linux/vmalloc.h>
31
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030032#include <media/soc_camera.h>
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -030033#include <media/v4l2-common.h>
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -030034#include <media/v4l2-ioctl.h>
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -030035#include <media/v4l2-dev.h>
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -030036#include <media/videobuf-core.h>
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -030037#include <media/videobuf2-core.h>
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -030038#include <media/soc_mediabus.h>
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030039
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -030040/* Default to VGA resolution */
41#define DEFAULT_WIDTH 640
42#define DEFAULT_HEIGHT 480
43
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030044static LIST_HEAD(hosts);
45static LIST_HEAD(devices);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -030046static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030047
Alberto Panizzo96e442c2010-12-02 07:43:37 -030048static int soc_camera_power_set(struct soc_camera_device *icd,
49 struct soc_camera_link *icl,
50 int power_on)
51{
52 int ret;
53
54 if (power_on) {
55 ret = regulator_bulk_enable(icl->num_regulators,
56 icl->regulators);
57 if (ret < 0) {
58 dev_err(&icd->dev, "Cannot enable regulators\n");
59 return ret;
60 }
61
62 if (icl->power)
63 ret = icl->power(icd->pdev, power_on);
64 if (ret < 0) {
65 dev_err(&icd->dev,
66 "Platform failed to power-on the camera.\n");
67
68 regulator_bulk_disable(icl->num_regulators,
69 icl->regulators);
70 return ret;
71 }
72 } else {
73 ret = 0;
74 if (icl->power)
75 ret = icl->power(icd->pdev, 0);
76 if (ret < 0) {
77 dev_err(&icd->dev,
78 "Platform failed to power-off the camera.\n");
79 return ret;
80 }
81
82 ret = regulator_bulk_disable(icl->num_regulators,
83 icl->regulators);
84 if (ret < 0) {
85 dev_err(&icd->dev, "Cannot disable regulators\n");
86 return ret;
87 }
88 }
89
90 return 0;
91}
92
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -030093const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
94 struct soc_camera_device *icd, unsigned int fourcc)
95{
96 unsigned int i;
97
98 for (i = 0; i < icd->num_user_formats; i++)
99 if (icd->user_formats[i].host_fmt->fourcc == fourcc)
100 return icd->user_formats + i;
101 return NULL;
102}
103EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
104
Guennadi Liakhovetskibd73b362008-12-23 05:54:45 -0300105/**
106 * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
107 * @icl: camera platform parameters
108 * @flags: flags to be inverted according to platform configuration
109 * @return: resulting flags
110 */
111unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
112 unsigned long flags)
113{
114 unsigned long f;
115
116 /* If only one of the two polarities is supported, switch to the opposite */
117 if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
118 f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
119 if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW)
120 flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW;
121 }
122
123 if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
124 f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
125 if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW)
126 flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW;
127 }
128
129 if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
130 f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
131 if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING)
132 flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING;
133 }
134
135 return flags;
136}
137EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
138
Hans Verkuil72937892008-06-01 10:35:18 -0300139static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300140 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300141{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300142 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300143 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300144
145 WARN_ON(priv != file->private_data);
146
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300147 /* limit format to hardware capabilities */
Guennadi Liakhovetski06daa1a2008-12-18 12:52:08 -0300148 return ici->ops->try_fmt(icd, f);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300149}
150
151static int soc_camera_enum_input(struct file *file, void *priv,
152 struct v4l2_input *inp)
153{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300154 struct soc_camera_device *icd = file->private_data;
Kuninori Morimoto34d359d2008-12-18 12:47:46 -0300155 int ret = 0;
156
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300157 if (inp->index != 0)
158 return -EINVAL;
159
Kuninori Morimoto34d359d2008-12-18 12:47:46 -0300160 if (icd->ops->enum_input)
161 ret = icd->ops->enum_input(icd, inp);
162 else {
163 /* default is camera */
164 inp->type = V4L2_INPUT_TYPE_CAMERA;
165 inp->std = V4L2_STD_UNKNOWN;
166 strcpy(inp->name, "Camera");
167 }
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300168
Kuninori Morimoto34d359d2008-12-18 12:47:46 -0300169 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300170}
171
172static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
173{
174 *i = 0;
175
176 return 0;
177}
178
179static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
180{
181 if (i > 0)
182 return -EINVAL;
183
184 return 0;
185}
186
187static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
188{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300189 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300190 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Kuninori Morimoto513791a2008-12-18 12:46:45 -0300191
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300192 return v4l2_subdev_call(sd, core, s_std, *a);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300193}
194
Qing Xued5b65d2011-01-20 05:19:40 -0300195static int soc_camera_enum_fsizes(struct file *file, void *fh,
196 struct v4l2_frmsizeenum *fsize)
197{
198 struct soc_camera_device *icd = file->private_data;
199 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
200
201 return ici->ops->enum_fsizes(icd, fsize);
202}
203
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300204static int soc_camera_reqbufs(struct file *file, void *priv,
205 struct v4l2_requestbuffers *p)
206{
207 int ret;
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300208 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300209 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300210
211 WARN_ON(priv != file->private_data);
212
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300213 if (icd->streamer && icd->streamer != file)
214 return -EBUSY;
215
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300216 if (ici->ops->init_videobuf) {
217 ret = videobuf_reqbufs(&icd->vb_vidq, p);
218 if (ret < 0)
219 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300220
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300221 ret = ici->ops->reqbufs(icd, p);
222 } else {
223 ret = vb2_reqbufs(&icd->vb2_vidq, p);
224 }
225
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300226 if (!ret && !icd->streamer)
227 icd->streamer = file;
228
229 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300230}
231
232static int soc_camera_querybuf(struct file *file, void *priv,
233 struct v4l2_buffer *p)
234{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300235 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300236 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300237
238 WARN_ON(priv != file->private_data);
239
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300240 if (ici->ops->init_videobuf)
241 return videobuf_querybuf(&icd->vb_vidq, p);
242 else
243 return vb2_querybuf(&icd->vb2_vidq, p);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300244}
245
246static int soc_camera_qbuf(struct file *file, void *priv,
247 struct v4l2_buffer *p)
248{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300249 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300250 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300251
252 WARN_ON(priv != file->private_data);
253
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300254 if (icd->streamer != file)
255 return -EBUSY;
256
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300257 if (ici->ops->init_videobuf)
258 return videobuf_qbuf(&icd->vb_vidq, p);
259 else
260 return vb2_qbuf(&icd->vb2_vidq, p);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300261}
262
263static int soc_camera_dqbuf(struct file *file, void *priv,
264 struct v4l2_buffer *p)
265{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300266 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300267 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300268
269 WARN_ON(priv != file->private_data);
270
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300271 if (icd->streamer != file)
272 return -EBUSY;
273
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300274 if (ici->ops->init_videobuf)
275 return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
276 else
277 return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300278}
279
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300280/* Always entered with .video_lock held */
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300281static int soc_camera_init_user_formats(struct soc_camera_device *icd)
282{
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300283 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300284 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Hans Verkuil3805f202010-05-08 17:55:00 -0300285 unsigned int i, fmts = 0, raw_fmts = 0;
286 int ret;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300287 enum v4l2_mbus_pixelcode code;
288
289 while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
290 raw_fmts++;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300291
292 if (!ici->ops->get_formats)
293 /*
294 * Fallback mode - the host will have to serve all
295 * sensor-provided formats one-to-one to the user
296 */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300297 fmts = raw_fmts;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300298 else
299 /*
300 * First pass - only count formats this host-sensor
301 * configuration can provide
302 */
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300303 for (i = 0; i < raw_fmts; i++) {
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -0300304 ret = ici->ops->get_formats(icd, i, NULL);
305 if (ret < 0)
306 return ret;
307 fmts += ret;
308 }
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300309
310 if (!fmts)
311 return -ENXIO;
312
313 icd->user_formats =
314 vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
315 if (!icd->user_formats)
316 return -ENOMEM;
317
318 icd->num_user_formats = fmts;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300319
320 dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
321
322 /* Second pass - actually fill data formats */
Stefan Herbrechtsmeier14df2cc2009-06-24 10:31:25 -0300323 fmts = 0;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300324 for (i = 0; i < raw_fmts; i++)
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300325 if (!ici->ops->get_formats) {
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300326 v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
327 icd->user_formats[i].host_fmt =
328 soc_mbus_get_fmtdesc(code);
329 icd->user_formats[i].code = code;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300330 } else {
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -0300331 ret = ici->ops->get_formats(icd, i,
332 &icd->user_formats[fmts]);
333 if (ret < 0)
334 goto egfmt;
335 fmts += ret;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300336 }
337
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300338 icd->current_fmt = &icd->user_formats[0];
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300339
340 return 0;
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -0300341
342egfmt:
343 icd->num_user_formats = 0;
344 vfree(icd->user_formats);
345 return ret;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300346}
347
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300348/* Always entered with .video_lock held */
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300349static void soc_camera_free_user_formats(struct soc_camera_device *icd)
350{
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -0300351 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
352
353 if (ici->ops->put_formats)
354 ici->ops->put_formats(icd);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300355 icd->current_fmt = NULL;
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -0300356 icd->num_user_formats = 0;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300357 vfree(icd->user_formats);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300358 icd->user_formats = NULL;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300359}
360
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300361#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
362 ((x) >> 24) & 0xff
363
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300364/* Called with .vb_lock held, or from the first open(2), see comment there */
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300365static int soc_camera_set_fmt(struct soc_camera_device *icd,
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300366 struct v4l2_format *f)
367{
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300368 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
369 struct v4l2_pix_format *pix = &f->fmt.pix;
370 int ret;
371
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300372 dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n",
373 pixfmtstr(pix->pixelformat), pix->width, pix->height);
374
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300375 /* We always call try_fmt() before set_fmt() or set_crop() */
376 ret = ici->ops->try_fmt(icd, f);
377 if (ret < 0)
378 return ret;
379
380 ret = ici->ops->set_fmt(icd, f);
381 if (ret < 0) {
382 return ret;
383 } else if (!icd->current_fmt ||
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300384 icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
Guennadi Liakhovetski2aa58db2009-08-25 11:47:00 -0300385 dev_err(&icd->dev,
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300386 "Host driver hasn't set up current format correctly!\n");
387 return -EINVAL;
388 }
389
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300390 icd->user_width = pix->width;
391 icd->user_height = pix->height;
Sergio Aguirre0e4c1802011-03-07 21:49:48 -0300392 icd->bytesperline = pix->bytesperline;
393 icd->sizeimage = pix->sizeimage;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300394 icd->colorspace = pix->colorspace;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300395 icd->field = pix->field;
396 if (ici->ops->init_videobuf)
397 icd->vb_vidq.field = pix->field;
Guennadi Liakhovetski025c18a2009-03-13 06:08:20 -0300398
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300399 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
400 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
401 f->type);
402
403 dev_dbg(&icd->dev, "set width: %d height: %d\n",
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300404 icd->user_width, icd->user_height);
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300405
406 /* set physical bus parameters */
407 return ici->ops->set_bus_param(icd, pix->pixelformat);
408}
409
Hans Verkuilbec43662008-12-30 06:58:20 -0300410static int soc_camera_open(struct file *file)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300411{
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300412 struct video_device *vdev = video_devdata(file);
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -0300413 struct soc_camera_device *icd = container_of(vdev->parent,
414 struct soc_camera_device,
415 dev);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300416 struct soc_camera_link *icl = to_soc_camera_link(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300417 struct soc_camera_host *ici;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300418 int ret;
419
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300420 if (!icd->ops)
421 /* No device driver attached */
422 return -ENODEV;
423
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300424 ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300425
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300426 if (!try_module_get(ici->ops->owner)) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300427 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300428 return -EINVAL;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300429 }
430
Guennadi Liakhovetski1a0063a2008-04-04 13:46:34 -0300431 icd->use_count++;
432
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300433 /* Now we really have to activate the camera */
434 if (icd->use_count == 1) {
Guennadi Liakhovetski025c18a2009-03-13 06:08:20 -0300435 /* Restore parameters before the last close() per V4L2 API */
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300436 struct v4l2_format f = {
437 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
438 .fmt.pix = {
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300439 .width = icd->user_width,
440 .height = icd->user_height,
Guennadi Liakhovetski025c18a2009-03-13 06:08:20 -0300441 .field = icd->field,
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300442 .colorspace = icd->colorspace,
443 .pixelformat =
444 icd->current_fmt->host_fmt->fourcc,
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300445 },
446 };
447
Alberto Panizzo96e442c2010-12-02 07:43:37 -0300448 ret = soc_camera_power_set(icd, icl, 1);
449 if (ret < 0)
450 goto epower;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300451
452 /* The camera could have been already on, try to reset */
453 if (icl->reset)
454 icl->reset(icd->pdev);
455
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300456 ret = ici->ops->add(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300457 if (ret < 0) {
458 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300459 goto eiciadd;
460 }
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300461
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -0300462 pm_runtime_enable(&icd->vdev->dev);
463 ret = pm_runtime_resume(&icd->vdev->dev);
464 if (ret < 0 && ret != -ENOSYS)
465 goto eresume;
466
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300467 /*
468 * Try to configure with default parameters. Notice: this is the
469 * very first open, so, we cannot race against other calls,
470 * apart from someone else calling open() simultaneously, but
471 * .video_lock is protecting us against it.
472 */
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300473 ret = soc_camera_set_fmt(icd, &f);
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300474 if (ret < 0)
475 goto esfmt;
Guennadi Liakhovetski24d8c022010-12-25 18:29:52 -0300476
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300477 if (ici->ops->init_videobuf) {
478 ici->ops->init_videobuf(&icd->vb_vidq, icd);
479 } else {
480 ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd);
481 if (ret < 0)
482 goto einitvb;
483 }
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300484 }
485
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300486 file->private_data = icd;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300487 dev_dbg(&icd->dev, "camera device open\n");
488
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300489 return 0;
490
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300491 /*
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -0300492 * First four errors are entered with the .video_lock held
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300493 * and use_count == 1
494 */
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300495einitvb:
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300496esfmt:
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -0300497 pm_runtime_disable(&icd->vdev->dev);
498eresume:
Guennadi Liakhovetskidf2ed072009-03-13 06:08:20 -0300499 ici->ops->remove(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300500eiciadd:
Alberto Panizzo96e442c2010-12-02 07:43:37 -0300501 soc_camera_power_set(icd, icl, 0);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300502epower:
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300503 icd->use_count--;
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300504 module_put(ici->ops->owner);
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300505
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300506 return ret;
507}
508
Hans Verkuilbec43662008-12-30 06:58:20 -0300509static int soc_camera_close(struct file *file)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300510{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300511 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300512 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300513
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300514 icd->use_count--;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300515 if (!icd->use_count) {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300516 struct soc_camera_link *icl = to_soc_camera_link(icd);
517
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -0300518 pm_runtime_suspend(&icd->vdev->dev);
519 pm_runtime_disable(&icd->vdev->dev);
520
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300521 ici->ops->remove(icd);
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300522 if (ici->ops->init_videobuf2)
523 vb2_queue_release(&icd->vb2_vidq);
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -0300524
Alberto Panizzo96e442c2010-12-02 07:43:37 -0300525 soc_camera_power_set(icd, icl, 0);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300526 }
Guennadi Liakhovetski025c18a2009-03-13 06:08:20 -0300527
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300528 if (icd->streamer == file)
529 icd->streamer = NULL;
530
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300531 module_put(ici->ops->owner);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300532
Guennadi Liakhovetski2aa58db2009-08-25 11:47:00 -0300533 dev_dbg(&icd->dev, "camera device close\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300534
535 return 0;
536}
537
Andrew Mortonaba360d2008-04-22 14:45:59 -0300538static ssize_t soc_camera_read(struct file *file, char __user *buf,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300539 size_t count, loff_t *ppos)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300540{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300541 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300542 int err = -EINVAL;
543
Guennadi Liakhovetski2aa58db2009-08-25 11:47:00 -0300544 dev_err(&icd->dev, "camera device read not implemented\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300545
546 return err;
547}
548
549static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
550{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300551 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300552 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300553 int err;
554
555 dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
556
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300557 if (icd->streamer != file)
558 return -EBUSY;
559
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300560 if (ici->ops->init_videobuf)
561 err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
562 else
563 err = vb2_mmap(&icd->vb2_vidq, vma);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300564
565 dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
566 (unsigned long)vma->vm_start,
567 (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
568 err);
569
570 return err;
571}
572
573static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
574{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300575 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300576 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300577
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300578 if (icd->streamer != file)
579 return -EBUSY;
580
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300581 if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300582 dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
583 return POLLERR;
584 }
585
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300586 return ici->ops->poll(file, pt);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300587}
588
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300589void soc_camera_lock(struct vb2_queue *vq)
590{
591 struct soc_camera_device *icd = vb2_get_drv_priv(vq);
592 mutex_lock(&icd->video_lock);
593}
594EXPORT_SYMBOL(soc_camera_lock);
595
596void soc_camera_unlock(struct vb2_queue *vq)
597{
598 struct soc_camera_device *icd = vb2_get_drv_priv(vq);
599 mutex_unlock(&icd->video_lock);
600}
601EXPORT_SYMBOL(soc_camera_unlock);
602
Hans Verkuilbec43662008-12-30 06:58:20 -0300603static struct v4l2_file_operations soc_camera_fops = {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300604 .owner = THIS_MODULE,
605 .open = soc_camera_open,
606 .release = soc_camera_close,
Guennadi Liakhovetskib6a633c2010-12-25 17:40:26 -0300607 .unlocked_ioctl = video_ioctl2,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300608 .read = soc_camera_read,
609 .mmap = soc_camera_mmap,
610 .poll = soc_camera_poll,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300611};
612
Hans Verkuil72937892008-06-01 10:35:18 -0300613static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300614 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300615{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300616 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300617 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300618
619 WARN_ON(priv != file->private_data);
620
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300621 if (icd->streamer && icd->streamer != file)
622 return -EBUSY;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300623
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300624 if (icd->vb_vidq.bufs[0]) {
Guennadi Liakhovetskib897a912009-08-25 11:46:53 -0300625 dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
Guennadi Liakhovetskib6a633c2010-12-25 17:40:26 -0300626 return -EBUSY;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300627 }
628
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300629 ret = soc_camera_set_fmt(icd, f);
630
631 if (!ret && !icd->streamer)
632 icd->streamer = file;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300633
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300634 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300635}
636
Hans Verkuil72937892008-06-01 10:35:18 -0300637static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300638 struct v4l2_fmtdesc *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300639{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300640 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300641 const struct soc_mbus_pixelfmt *format;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300642
643 WARN_ON(priv != file->private_data);
644
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300645 if (f->index >= icd->num_user_formats)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300646 return -EINVAL;
647
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300648 format = icd->user_formats[f->index].host_fmt;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300649
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300650 if (format->name)
651 strlcpy(f->description, format->name, sizeof(f->description));
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300652 f->pixelformat = format->fourcc;
653 return 0;
654}
655
Hans Verkuil72937892008-06-01 10:35:18 -0300656static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300657 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300658{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300659 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300660 struct v4l2_pix_format *pix = &f->fmt.pix;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300661
662 WARN_ON(priv != file->private_data);
663
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300664 pix->width = icd->user_width;
665 pix->height = icd->user_height;
Sergio Aguirre0e4c1802011-03-07 21:49:48 -0300666 pix->bytesperline = icd->bytesperline;
667 pix->sizeimage = icd->sizeimage;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300668 pix->field = icd->field;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300669 pix->pixelformat = icd->current_fmt->host_fmt->fourcc;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300670 pix->colorspace = icd->colorspace;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300671 dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -0300672 icd->current_fmt->host_fmt->fourcc);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300673 return 0;
674}
675
676static int soc_camera_querycap(struct file *file, void *priv,
677 struct v4l2_capability *cap)
678{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300679 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300680 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300681
682 WARN_ON(priv != file->private_data);
683
684 strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300685 return ici->ops->querycap(ici, cap);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300686}
687
688static int soc_camera_streamon(struct file *file, void *priv,
689 enum v4l2_buf_type i)
690{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300691 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300692 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300693 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300694 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300695
696 WARN_ON(priv != file->private_data);
697
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300698 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
699 return -EINVAL;
700
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300701 if (icd->streamer != file)
702 return -EBUSY;
703
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300704 /* This calls buf_queue from host driver's videobuf_queue_ops */
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300705 if (ici->ops->init_videobuf)
706 ret = videobuf_streamon(&icd->vb_vidq);
707 else
708 ret = vb2_streamon(&icd->vb2_vidq, i);
709
Anatolij Gustschin7fdbd852011-01-31 09:19:32 -0300710 if (!ret)
711 v4l2_subdev_call(sd, video, s_stream, 1);
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300712
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300713 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300714}
715
716static int soc_camera_streamoff(struct file *file, void *priv,
717 enum v4l2_buf_type i)
718{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300719 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300720 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300721 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300722
723 WARN_ON(priv != file->private_data);
724
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300725 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
726 return -EINVAL;
727
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300728 if (icd->streamer != file)
729 return -EBUSY;
730
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -0300731 /*
732 * This calls buf_release from host driver's videobuf_queue_ops for all
733 * remaining buffers. When the last buffer is freed, stop capture
734 */
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -0300735 if (ici->ops->init_videobuf)
736 videobuf_streamoff(&icd->vb_vidq);
737 else
738 vb2_streamoff(&icd->vb2_vidq, i);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300739
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300740 v4l2_subdev_call(sd, video, s_stream, 0);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300741
742 return 0;
743}
744
745static int soc_camera_queryctrl(struct file *file, void *priv,
746 struct v4l2_queryctrl *qc)
747{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300748 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski2840d242009-08-25 11:44:15 -0300749 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300750 int i;
751
752 WARN_ON(priv != file->private_data);
753
754 if (!qc->id)
755 return -EINVAL;
756
Guennadi Liakhovetski2840d242009-08-25 11:44:15 -0300757 /* First check host controls */
758 for (i = 0; i < ici->ops->num_controls; i++)
759 if (qc->id == ici->ops->controls[i].id) {
760 memcpy(qc, &(ici->ops->controls[i]),
761 sizeof(*qc));
762 return 0;
763 }
764
765 /* Then device controls */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300766 for (i = 0; i < icd->ops->num_controls; i++)
767 if (qc->id == icd->ops->controls[i].id) {
768 memcpy(qc, &(icd->ops->controls[i]),
769 sizeof(*qc));
770 return 0;
771 }
772
773 return -EINVAL;
774}
775
776static int soc_camera_g_ctrl(struct file *file, void *priv,
777 struct v4l2_control *ctrl)
778{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300779 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300780 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300781 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetski2840d242009-08-25 11:44:15 -0300782 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300783
784 WARN_ON(priv != file->private_data);
785
Guennadi Liakhovetski2840d242009-08-25 11:44:15 -0300786 if (ici->ops->get_ctrl) {
787 ret = ici->ops->get_ctrl(icd, ctrl);
788 if (ret != -ENOIOCTLCMD)
789 return ret;
790 }
791
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300792 return v4l2_subdev_call(sd, core, g_ctrl, ctrl);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300793}
794
795static int soc_camera_s_ctrl(struct file *file, void *priv,
796 struct v4l2_control *ctrl)
797{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300798 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300799 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300800 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetski2840d242009-08-25 11:44:15 -0300801 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300802
803 WARN_ON(priv != file->private_data);
804
Guennadi Liakhovetski2840d242009-08-25 11:44:15 -0300805 if (ici->ops->set_ctrl) {
806 ret = ici->ops->set_ctrl(icd, ctrl);
807 if (ret != -ENOIOCTLCMD)
808 return ret;
809 }
810
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300811 return v4l2_subdev_call(sd, core, s_ctrl, ctrl);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300812}
813
814static int soc_camera_cropcap(struct file *file, void *fh,
815 struct v4l2_cropcap *a)
816{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300817 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300818 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300819
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300820 return ici->ops->cropcap(icd, a);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300821}
822
823static int soc_camera_g_crop(struct file *file, void *fh,
824 struct v4l2_crop *a)
825{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300826 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300827 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
828 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300829
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300830 ret = ici->ops->get_crop(icd, a);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300831
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300832 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300833}
834
Guennadi Liakhovetski68a54f02009-08-25 11:46:52 -0300835/*
836 * According to the V4L2 API, drivers shall not update the struct v4l2_crop
837 * argument with the actual geometry, instead, the user shall use G_CROP to
Guennadi Liakhovetskiab56d5e2010-03-23 11:31:46 -0300838 * retrieve it.
Guennadi Liakhovetski68a54f02009-08-25 11:46:52 -0300839 */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300840static int soc_camera_s_crop(struct file *file, void *fh,
841 struct v4l2_crop *a)
842{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300843 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300844 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300845 struct v4l2_rect *rect = &a->c;
846 struct v4l2_crop current_crop;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300847 int ret;
848
849 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
850 return -EINVAL;
851
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300852 dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
853 rect->width, rect->height, rect->left, rect->top);
854
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300855 /* If get_crop fails, we'll let host and / or client drivers decide */
856 ret = ici->ops->get_crop(icd, &current_crop);
857
Guennadi Liakhovetskib897a912009-08-25 11:46:53 -0300858 /* Prohibit window size change with initialised buffers */
Guennadi Liakhovetski103754a2010-08-05 19:23:44 -0300859 if (ret < 0) {
860 dev_err(&icd->dev,
861 "S_CROP denied: getting current crop failed\n");
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300862 } else if (icd->vb_vidq.bufs[0] &&
Guennadi Liakhovetski103754a2010-08-05 19:23:44 -0300863 (a->c.width != current_crop.c.width ||
864 a->c.height != current_crop.c.height)) {
Guennadi Liakhovetskib897a912009-08-25 11:46:53 -0300865 dev_err(&icd->dev,
866 "S_CROP denied: queue initialised and sizes differ\n");
867 ret = -EBUSY;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -0300868 } else {
869 ret = ici->ops->set_crop(icd, a);
Guennadi Liakhovetskib897a912009-08-25 11:46:53 -0300870 }
871
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300872 return ret;
873}
874
Guennadi Liakhovetskic9f6ef62010-02-09 18:00:30 +0100875static int soc_camera_g_parm(struct file *file, void *fh,
876 struct v4l2_streamparm *a)
877{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300878 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9f6ef62010-02-09 18:00:30 +0100879 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
880
881 if (ici->ops->get_parm)
882 return ici->ops->get_parm(icd, a);
883
884 return -ENOIOCTLCMD;
885}
886
887static int soc_camera_s_parm(struct file *file, void *fh,
888 struct v4l2_streamparm *a)
889{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300890 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9f6ef62010-02-09 18:00:30 +0100891 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
892
893 if (ici->ops->set_parm)
894 return ici->ops->set_parm(icd, a);
895
896 return -ENOIOCTLCMD;
897}
898
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300899static int soc_camera_g_chip_ident(struct file *file, void *fh,
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300900 struct v4l2_dbg_chip_ident *id)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300901{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300902 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300903 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300904
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300905 return v4l2_subdev_call(sd, core, g_chip_ident, id);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300906}
907
908#ifdef CONFIG_VIDEO_ADV_DEBUG
909static int soc_camera_g_register(struct file *file, void *fh,
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300910 struct v4l2_dbg_register *reg)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300911{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300912 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300913 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300914
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300915 return v4l2_subdev_call(sd, core, g_register, reg);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300916}
917
918static int soc_camera_s_register(struct file *file, void *fh,
Hans Verkuilaecde8b52008-12-30 07:14:19 -0300919 struct v4l2_dbg_register *reg)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300920{
Guennadi Liakhovetski57bee292010-08-17 14:29:51 -0300921 struct soc_camera_device *icd = file->private_data;
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300922 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300923
Guennadi Liakhovetskic9c1f1c2009-08-25 11:46:59 -0300924 return v4l2_subdev_call(sd, core, s_register, reg);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300925}
926#endif
927
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300928/* So far this function cannot fail */
929static void scan_add_host(struct soc_camera_host *ici)
930{
931 struct soc_camera_device *icd;
932
933 mutex_lock(&list_lock);
934
935 list_for_each_entry(icd, &devices, list) {
936 if (icd->iface == ici->nr) {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300937 int ret;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300938 icd->dev.parent = ici->v4l2_dev.dev;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300939 dev_set_name(&icd->dev, "%u-%u", icd->iface,
940 icd->devnum);
941 ret = device_register(&icd->dev);
942 if (ret < 0) {
943 icd->dev.parent = NULL;
944 dev_err(&icd->dev,
945 "Cannot register device: %d\n", ret);
946 }
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300947 }
948 }
949
950 mutex_unlock(&list_lock);
951}
952
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300953#ifdef CONFIG_I2C_BOARDINFO
954static int soc_camera_init_i2c(struct soc_camera_device *icd,
955 struct soc_camera_link *icl)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300956{
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300957 struct i2c_client *client;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300958 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300959 struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300960 struct v4l2_subdev *subdev;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300961
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300962 if (!adap) {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300963 dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
964 icl->i2c_adapter_id);
965 goto ei2cga;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300966 }
967
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300968 icl->board_info->platform_data = icd;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300969
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300970 subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
Laurent Pinchart9a1f8b32010-09-24 10:16:44 -0300971 icl->board_info, NULL);
Magnus Dammd74f8412010-02-09 17:40:40 +0900972 if (!subdev)
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300973 goto ei2cnd;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300974
Laurent Pinchartc4ce6d12010-07-30 17:24:54 -0300975 client = v4l2_get_subdevdata(subdev);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300976
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300977 /* Use to_i2c_client(dev) to recover the i2c client */
978 dev_set_drvdata(&icd->dev, &client->dev);
979
980 return 0;
981ei2cnd:
982 i2c_put_adapter(adap);
983ei2cga:
Magnus Dammd74f8412010-02-09 17:40:40 +0900984 return -ENODEV;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300985}
986
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300987static void soc_camera_free_i2c(struct soc_camera_device *icd)
988{
989 struct i2c_client *client =
990 to_i2c_client(to_soc_camera_control(icd));
991 dev_set_drvdata(&icd->dev, NULL);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -0300992 v4l2_device_unregister_subdev(i2c_get_clientdata(client));
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -0300993 i2c_unregister_device(client);
994 i2c_put_adapter(client->adapter);
995}
996#else
997#define soc_camera_init_i2c(icd, icl) (-ENODEV)
998#define soc_camera_free_i2c(icd) do {} while (0)
999#endif
1000
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001001static int soc_camera_video_start(struct soc_camera_device *icd);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001002static int video_dev_create(struct soc_camera_device *icd);
1003/* Called during host-driver probe */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001004static int soc_camera_probe(struct device *dev)
1005{
1006 struct soc_camera_device *icd = to_soc_camera_dev(dev);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001007 struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001008 struct soc_camera_link *icl = to_soc_camera_link(icd);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001009 struct device *control = NULL;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001010 struct v4l2_subdev *sd;
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -03001011 struct v4l2_mbus_framefmt mf;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001012 int ret;
1013
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001014 dev_info(dev, "Probing %s\n", dev_name(dev));
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001015
Alberto Panizzo96e442c2010-12-02 07:43:37 -03001016 ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
1017 icl->regulators);
1018 if (ret < 0)
1019 goto ereg;
1020
1021 ret = soc_camera_power_set(icd, icl, 1);
1022 if (ret < 0)
1023 goto epower;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001024
1025 /* The camera could have been already on, try to reset */
1026 if (icl->reset)
1027 icl->reset(icd->pdev);
1028
1029 ret = ici->ops->add(icd);
1030 if (ret < 0)
1031 goto eadd;
1032
1033 /* Must have icd->vdev before registering the device */
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001034 ret = video_dev_create(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001035 if (ret < 0)
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001036 goto evdc;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001037
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001038 /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
1039 if (icl->board_info) {
1040 ret = soc_camera_init_i2c(icd, icl);
1041 if (ret < 0)
1042 goto eadddev;
1043 } else if (!icl->add_device || !icl->del_device) {
1044 ret = -EINVAL;
1045 goto eadddev;
1046 } else {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001047 if (icl->module_name)
1048 ret = request_module(icl->module_name);
1049
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001050 ret = icl->add_device(icl, &icd->dev);
1051 if (ret < 0)
1052 goto eadddev;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001053
Guennadi Liakhovetski96c75392009-08-25 11:53:23 -03001054 /*
1055 * FIXME: this is racy, have to use driver-binding notification,
1056 * when it is available
1057 */
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001058 control = to_soc_camera_control(icd);
Guennadi Liakhovetski08590b92009-08-25 11:46:54 -03001059 if (!control || !control->driver || !dev_get_drvdata(control) ||
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001060 !try_module_get(control->driver->owner)) {
1061 icl->del_device(icl);
1062 goto enodrv;
1063 }
Guennadi Liakhovetski025c18a2009-03-13 06:08:20 -03001064 }
1065
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -03001066 /* At this point client .probe() should have run already */
1067 ret = soc_camera_init_user_formats(icd);
1068 if (ret < 0)
1069 goto eiufmt;
1070
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -03001071 icd->field = V4L2_FIELD_ANY;
1072
Guennadi Liakhovetskib6a633c2010-12-25 17:40:26 -03001073 icd->vdev->lock = &icd->video_lock;
1074
1075 /*
1076 * ..._video_start() will create a device node, video_register_device()
1077 * itself is protected against concurrent open() calls, but we also have
1078 * to protect our data.
1079 */
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001080 mutex_lock(&icd->video_lock);
1081
1082 ret = soc_camera_video_start(icd);
1083 if (ret < 0)
1084 goto evidstart;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001085
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001086 /* Try to improve our guess of a reasonable window format */
1087 sd = soc_camera_to_subdev(icd);
Guennadi Liakhovetski760697b2009-12-11 11:46:49 -03001088 if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
1089 icd->user_width = mf.width;
1090 icd->user_height = mf.height;
1091 icd->colorspace = mf.colorspace;
1092 icd->field = mf.field;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001093 }
1094
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001095 /* Do we have to sysfs_remove_link() before device_unregister()? */
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001096 if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001097 "control"))
1098 dev_warn(&icd->dev, "Failed creating the control symlink\n");
1099
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001100 ici->ops->remove(icd);
1101
Alberto Panizzo96e442c2010-12-02 07:43:37 -03001102 soc_camera_power_set(icd, icl, 0);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001103
1104 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001105
1106 return 0;
1107
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001108evidstart:
1109 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -03001110 soc_camera_free_user_formats(icd);
1111eiufmt:
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001112 if (icl->board_info) {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001113 soc_camera_free_i2c(icd);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001114 } else {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001115 icl->del_device(icl);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001116 module_put(control->driver->owner);
1117 }
1118enodrv:
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001119eadddev:
1120 video_device_release(icd->vdev);
1121evdc:
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001122 ici->ops->remove(icd);
1123eadd:
Alberto Panizzo96e442c2010-12-02 07:43:37 -03001124 soc_camera_power_set(icd, icl, 0);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001125epower:
Alberto Panizzo96e442c2010-12-02 07:43:37 -03001126 regulator_bulk_free(icl->num_regulators, icl->regulators);
1127ereg:
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001128 return ret;
1129}
1130
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -03001131/*
1132 * This is called on device_unregister, which only means we have to disconnect
1133 * from the host, but not remove ourselves from the device list
1134 */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001135static int soc_camera_remove(struct device *dev)
1136{
1137 struct soc_camera_device *icd = to_soc_camera_dev(dev);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001138 struct soc_camera_link *icl = to_soc_camera_link(icd);
1139 struct video_device *vdev = icd->vdev;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001140
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001141 BUG_ON(!dev->parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001142
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001143 if (vdev) {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001144 video_unregister_device(vdev);
1145 icd->vdev = NULL;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001146 }
1147
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001148 if (icl->board_info) {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001149 soc_camera_free_i2c(icd);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001150 } else {
1151 struct device_driver *drv = to_soc_camera_control(icd) ?
1152 to_soc_camera_control(icd)->driver : NULL;
1153 if (drv) {
1154 icl->del_device(icl);
1155 module_put(drv->owner);
1156 }
1157 }
Guennadi Liakhovetskifa489842009-08-25 11:46:43 -03001158 soc_camera_free_user_formats(icd);
Guennadi Liakhovetski025c18a2009-03-13 06:08:20 -03001159
Alberto Panizzo96e442c2010-12-02 07:43:37 -03001160 regulator_bulk_free(icl->num_regulators, icl->regulators);
1161
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001162 return 0;
1163}
1164
Robert Jarzmik2e521062008-08-01 20:14:50 -03001165static int soc_camera_suspend(struct device *dev, pm_message_t state)
1166{
1167 struct soc_camera_device *icd = to_soc_camera_dev(dev);
1168 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1169 int ret = 0;
1170
1171 if (ici->ops->suspend)
1172 ret = ici->ops->suspend(icd, state);
1173
1174 return ret;
1175}
1176
1177static int soc_camera_resume(struct device *dev)
1178{
1179 struct soc_camera_device *icd = to_soc_camera_dev(dev);
1180 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1181 int ret = 0;
1182
1183 if (ici->ops->resume)
1184 ret = ici->ops->resume(icd);
1185
1186 return ret;
1187}
1188
Guennadi Liakhovetski52d268a2010-07-26 11:37:13 -03001189struct bus_type soc_camera_bus_type = {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001190 .name = "soc-camera",
1191 .probe = soc_camera_probe,
1192 .remove = soc_camera_remove,
Robert Jarzmik2e521062008-08-01 20:14:50 -03001193 .suspend = soc_camera_suspend,
1194 .resume = soc_camera_resume,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001195};
Guennadi Liakhovetski52d268a2010-07-26 11:37:13 -03001196EXPORT_SYMBOL_GPL(soc_camera_bus_type);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001197
1198static struct device_driver ic_drv = {
1199 .name = "camera",
1200 .bus = &soc_camera_bus_type,
1201 .owner = THIS_MODULE,
1202};
1203
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001204static void dummy_release(struct device *dev)
1205{
1206}
1207
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001208static int default_cropcap(struct soc_camera_device *icd,
1209 struct v4l2_cropcap *a)
1210{
1211 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1212 return v4l2_subdev_call(sd, video, cropcap, a);
1213}
1214
1215static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
1216{
1217 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1218 return v4l2_subdev_call(sd, video, g_crop, a);
1219}
1220
1221static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
1222{
1223 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1224 return v4l2_subdev_call(sd, video, s_crop, a);
1225}
1226
Janusz Krzysztofik06e17822010-09-10 22:26:16 -03001227static int default_g_parm(struct soc_camera_device *icd,
1228 struct v4l2_streamparm *parm)
1229{
1230 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1231 return v4l2_subdev_call(sd, video, g_parm, parm);
1232}
1233
1234static int default_s_parm(struct soc_camera_device *icd,
1235 struct v4l2_streamparm *parm)
1236{
1237 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1238 return v4l2_subdev_call(sd, video, s_parm, parm);
1239}
1240
Qing Xued5b65d2011-01-20 05:19:40 -03001241static int default_enum_fsizes(struct soc_camera_device *icd,
1242 struct v4l2_frmsizeenum *fsize)
1243{
1244 int ret;
1245 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1246 const struct soc_camera_format_xlate *xlate;
1247 __u32 pixfmt = fsize->pixel_format;
1248 struct v4l2_frmsizeenum fsize_mbus = *fsize;
1249
1250 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
1251 if (!xlate)
1252 return -EINVAL;
1253 /* map xlate-code to pixel_format, sensor only handle xlate-code*/
1254 fsize_mbus.pixel_format = xlate->code;
1255
1256 ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus);
1257 if (ret < 0)
1258 return ret;
1259
1260 *fsize = fsize_mbus;
1261 fsize->pixel_format = pixfmt;
1262
1263 return 0;
1264}
1265
Guennadi Liakhovetski64ff9ba2009-11-09 16:12:37 -03001266static void soc_camera_device_init(struct device *dev, void *pdata)
1267{
1268 dev->platform_data = pdata;
1269 dev->bus = &soc_camera_bus_type;
1270 dev->release = dummy_release;
1271}
1272
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -03001273int soc_camera_host_register(struct soc_camera_host *ici)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001274{
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001275 struct soc_camera_host *ix;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001276 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001277
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -03001278 if (!ici || !ici->ops ||
1279 !ici->ops->try_fmt ||
1280 !ici->ops->set_fmt ||
1281 !ici->ops->set_bus_param ||
1282 !ici->ops->querycap ||
Guennadi Liakhovetski592c2ab2011-01-29 12:44:51 -03001283 ((!ici->ops->init_videobuf ||
1284 !ici->ops->reqbufs) &&
1285 !ici->ops->init_videobuf2) ||
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -03001286 !ici->ops->add ||
1287 !ici->ops->remove ||
Guennadi Liakhovetskieff505f2009-04-24 12:55:48 -03001288 !ici->ops->poll ||
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001289 !ici->v4l2_dev.dev)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001290 return -EINVAL;
1291
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001292 if (!ici->ops->set_crop)
1293 ici->ops->set_crop = default_s_crop;
1294 if (!ici->ops->get_crop)
1295 ici->ops->get_crop = default_g_crop;
1296 if (!ici->ops->cropcap)
1297 ici->ops->cropcap = default_cropcap;
Janusz Krzysztofik06e17822010-09-10 22:26:16 -03001298 if (!ici->ops->set_parm)
1299 ici->ops->set_parm = default_s_parm;
1300 if (!ici->ops->get_parm)
1301 ici->ops->get_parm = default_g_parm;
Qing Xued5b65d2011-01-20 05:19:40 -03001302 if (!ici->ops->enum_fsizes)
1303 ici->ops->enum_fsizes = default_enum_fsizes;
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001304
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001305 mutex_lock(&list_lock);
1306 list_for_each_entry(ix, &hosts, list) {
1307 if (ix->nr == ici->nr) {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001308 ret = -EBUSY;
1309 goto edevreg;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001310 }
1311 }
1312
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001313 ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
1314 if (ret < 0)
1315 goto edevreg;
Guennadi Liakhovetskieff505f2009-04-24 12:55:48 -03001316
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001317 list_add_tail(&ici->list, &hosts);
1318 mutex_unlock(&list_lock);
1319
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001320 scan_add_host(ici);
1321
1322 return 0;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001323
1324edevreg:
1325 mutex_unlock(&list_lock);
1326 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001327}
1328EXPORT_SYMBOL(soc_camera_host_register);
1329
1330/* Unregister all clients! */
1331void soc_camera_host_unregister(struct soc_camera_host *ici)
1332{
1333 struct soc_camera_device *icd;
1334
1335 mutex_lock(&list_lock);
1336
1337 list_del(&ici->list);
1338
1339 list_for_each_entry(icd, &devices, list) {
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001340 if (icd->iface == ici->nr) {
Guennadi Liakhovetski64ff9ba2009-11-09 16:12:37 -03001341 void *pdata = icd->dev.platform_data;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001342 /* The bus->remove will be called */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001343 device_unregister(&icd->dev);
Guennadi Liakhovetski76823b72009-10-05 12:54:54 -03001344 /*
1345 * Not before device_unregister(), .remove
1346 * needs parent to call ici->ops->remove().
1347 * If the host module is loaded again, device_register()
1348 * would complain "already initialised," since 2.6.32
1349 * this is also needed to prevent use-after-free of the
1350 * device private data.
1351 */
1352 memset(&icd->dev, 0, sizeof(icd->dev));
Guennadi Liakhovetski64ff9ba2009-11-09 16:12:37 -03001353 soc_camera_device_init(&icd->dev, pdata);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001354 }
1355 }
1356
1357 mutex_unlock(&list_lock);
1358
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001359 v4l2_device_unregister(&ici->v4l2_dev);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001360}
1361EXPORT_SYMBOL(soc_camera_host_unregister);
1362
1363/* Image capture device */
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001364static int soc_camera_device_register(struct soc_camera_device *icd)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001365{
1366 struct soc_camera_device *ix;
1367 int num = -1, i;
1368
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001369 for (i = 0; i < 256 && num < 0; i++) {
1370 num = i;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001371 /* Check if this index is available on this interface */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001372 list_for_each_entry(ix, &devices, list) {
1373 if (ix->iface == icd->iface && ix->devnum == i) {
1374 num = -1;
1375 break;
1376 }
1377 }
1378 }
1379
1380 if (num < 0)
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -03001381 /*
1382 * ok, we have 256 cameras on this host...
1383 * man, stay reasonable...
1384 */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001385 return -ENOMEM;
1386
Guennadi Liakhovetski64ff9ba2009-11-09 16:12:37 -03001387 icd->devnum = num;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -03001388 icd->use_count = 0;
1389 icd->host_priv = NULL;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001390 mutex_init(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001391
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001392 list_add_tail(&icd->list, &devices);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001393
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001394 return 0;
1395}
1396
1397static void soc_camera_device_unregister(struct soc_camera_device *icd)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001398{
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001399 list_del(&icd->list);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001400}
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001401
Hans Verkuila3998102008-07-21 02:57:38 -03001402static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
1403 .vidioc_querycap = soc_camera_querycap,
1404 .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
1405 .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
1406 .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
1407 .vidioc_enum_input = soc_camera_enum_input,
1408 .vidioc_g_input = soc_camera_g_input,
1409 .vidioc_s_input = soc_camera_s_input,
1410 .vidioc_s_std = soc_camera_s_std,
Qing Xued5b65d2011-01-20 05:19:40 -03001411 .vidioc_enum_framesizes = soc_camera_enum_fsizes,
Hans Verkuila3998102008-07-21 02:57:38 -03001412 .vidioc_reqbufs = soc_camera_reqbufs,
1413 .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
1414 .vidioc_querybuf = soc_camera_querybuf,
1415 .vidioc_qbuf = soc_camera_qbuf,
1416 .vidioc_dqbuf = soc_camera_dqbuf,
1417 .vidioc_streamon = soc_camera_streamon,
1418 .vidioc_streamoff = soc_camera_streamoff,
1419 .vidioc_queryctrl = soc_camera_queryctrl,
1420 .vidioc_g_ctrl = soc_camera_g_ctrl,
1421 .vidioc_s_ctrl = soc_camera_s_ctrl,
1422 .vidioc_cropcap = soc_camera_cropcap,
1423 .vidioc_g_crop = soc_camera_g_crop,
1424 .vidioc_s_crop = soc_camera_s_crop,
Guennadi Liakhovetskic9f6ef62010-02-09 18:00:30 +01001425 .vidioc_g_parm = soc_camera_g_parm,
1426 .vidioc_s_parm = soc_camera_s_parm,
Hans Verkuila3998102008-07-21 02:57:38 -03001427 .vidioc_g_chip_ident = soc_camera_g_chip_ident,
1428#ifdef CONFIG_VIDEO_ADV_DEBUG
1429 .vidioc_g_register = soc_camera_g_register,
1430 .vidioc_s_register = soc_camera_s_register,
1431#endif
1432};
1433
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001434static int video_dev_create(struct soc_camera_device *icd)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001435{
1436 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001437 struct video_device *vdev = video_device_alloc();
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001438
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001439 if (!vdev)
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001440 return -ENOMEM;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001441
1442 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001443
Hans Verkuil5e85e732008-07-20 06:31:39 -03001444 vdev->parent = &icd->dev;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001445 vdev->current_norm = V4L2_STD_UNKNOWN;
1446 vdev->fops = &soc_camera_fops;
Hans Verkuila3998102008-07-21 02:57:38 -03001447 vdev->ioctl_ops = &soc_camera_ioctl_ops;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001448 vdev->release = video_device_release;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001449 vdev->tvnorms = V4L2_STD_UNKNOWN;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001450
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001451 icd->vdev = vdev;
1452
1453 return 0;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001454}
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001455
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001456/*
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001457 * Called from soc_camera_probe() above (with .video_lock held???)
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001458 */
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001459static int soc_camera_video_start(struct soc_camera_device *icd)
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001460{
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -03001461 struct device_type *type = icd->vdev->dev.type;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001462 int ret;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001463
1464 if (!icd->dev.parent)
1465 return -ENODEV;
1466
1467 if (!icd->ops ||
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001468 !icd->ops->query_bus_param ||
1469 !icd->ops->set_bus_param)
1470 return -EINVAL;
1471
Laurent Pinchart46b21092009-12-10 11:51:38 -02001472 ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001473 if (ret < 0) {
1474 dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
1475 return ret;
1476 }
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001477
Mauro Carvalho Chehab4f9fb5e2010-05-18 00:46:09 -03001478 /* Restore device type, possibly set by the subdevice driver */
1479 icd->vdev->dev.type = type;
1480
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001481 return 0;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001482}
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001483
Guennadi Liakhovetskic41deba2009-08-25 11:06:21 -03001484static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
1485{
1486 struct soc_camera_link *icl = pdev->dev.platform_data;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001487 struct soc_camera_device *icd;
1488 int ret;
Guennadi Liakhovetskic41deba2009-08-25 11:06:21 -03001489
1490 if (!icl)
1491 return -EINVAL;
1492
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001493 icd = kzalloc(sizeof(*icd), GFP_KERNEL);
1494 if (!icd)
1495 return -ENOMEM;
Guennadi Liakhovetskic41deba2009-08-25 11:06:21 -03001496
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001497 icd->iface = icl->bus_id;
Guennadi Liakhovetski979ea1d2009-08-25 11:43:33 -03001498 icd->pdev = &pdev->dev;
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001499 platform_set_drvdata(pdev, icd);
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001500
1501 ret = soc_camera_device_register(icd);
1502 if (ret < 0)
1503 goto escdevreg;
1504
Guennadi Liakhovetski64ff9ba2009-11-09 16:12:37 -03001505 soc_camera_device_init(&icd->dev, icl);
1506
Guennadi Liakhovetski6a6c8782009-08-25 11:50:46 -03001507 icd->user_width = DEFAULT_WIDTH;
1508 icd->user_height = DEFAULT_HEIGHT;
1509
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001510 return 0;
1511
1512escdevreg:
1513 kfree(icd);
1514
1515 return ret;
Guennadi Liakhovetskic41deba2009-08-25 11:06:21 -03001516}
1517
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -03001518/*
1519 * Only called on rmmod for each platform device, since they are not
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001520 * hot-pluggable. Now we know, that all our users - hosts and devices have
Guennadi Liakhovetski5d28d522009-12-11 11:15:05 -03001521 * been unloaded already
1522 */
Guennadi Liakhovetskic41deba2009-08-25 11:06:21 -03001523static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
1524{
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001525 struct soc_camera_device *icd = platform_get_drvdata(pdev);
Guennadi Liakhovetskic41deba2009-08-25 11:06:21 -03001526
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001527 if (!icd)
1528 return -EINVAL;
1529
1530 soc_camera_device_unregister(icd);
1531
1532 kfree(icd);
1533
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -03001534 return 0;
1535}
1536
1537static struct platform_driver __refdata soc_camera_pdrv = {
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001538 .remove = __devexit_p(soc_camera_pdrv_remove),
1539 .driver = {
1540 .name = "soc-camera-pdrv",
1541 .owner = THIS_MODULE,
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -03001542 },
1543};
1544
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001545static int __init soc_camera_init(void)
1546{
1547 int ret = bus_register(&soc_camera_bus_type);
1548 if (ret)
1549 return ret;
1550 ret = driver_register(&ic_drv);
1551 if (ret)
1552 goto edrvr;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001553
Guennadi Liakhovetski40e2e092009-08-25 11:28:22 -03001554 ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -03001555 if (ret)
1556 goto epdr;
1557
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001558 return 0;
1559
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -03001560epdr:
1561 driver_unregister(&ic_drv);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001562edrvr:
1563 bus_unregister(&soc_camera_bus_type);
1564 return ret;
1565}
1566
1567static void __exit soc_camera_exit(void)
1568{
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -03001569 platform_driver_unregister(&soc_camera_pdrv);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001570 driver_unregister(&ic_drv);
1571 bus_unregister(&soc_camera_bus_type);
1572}
1573
1574module_init(soc_camera_init);
1575module_exit(soc_camera_exit);
1576
1577MODULE_DESCRIPTION("Image capture bus driver");
1578MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
1579MODULE_LICENSE("GPL");
Guennadi Liakhovetski0fd327b2009-05-07 13:25:32 -03001580MODULE_ALIAS("platform:soc-camera-pdrv");