diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-20 08:30:09 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-21 06:39:30 -0400 |
commit | 7ba2f84159b479393c2f5149a2867635a1010ed0 (patch) | |
tree | 6db5c26105244c9c9dcf79676cfd6aef6cd656bb /drivers/media/i2c | |
parent | 9b78c5a3007e10a172d4e83bea18509fdff2e8e3 (diff) |
sh_mobile_csi2: move it to the right place
make[4]: *** No rule to make target `drivers/media/platform/sh_mobile_csi2.c',
needed by `drivers/media/platform/sh_mobile_csi2.o'. Stop.
Reported-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r-- | drivers/media/i2c/soc_camera/sh_mobile_csi2.c | 398 |
1 files changed, 0 insertions, 398 deletions
diff --git a/drivers/media/i2c/soc_camera/sh_mobile_csi2.c b/drivers/media/i2c/soc_camera/sh_mobile_csi2.c deleted file mode 100644 index 05286500b4d4..000000000000 --- a/drivers/media/i2c/soc_camera/sh_mobile_csi2.c +++ /dev/null | |||
@@ -1,398 +0,0 @@ | |||
1 | /* | ||
2 | * Driver for the SH-Mobile MIPI CSI-2 unit | ||
3 | * | ||
4 | * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/pm_runtime.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/videodev2.h> | ||
18 | #include <linux/module.h> | ||
19 | |||
20 | #include <media/sh_mobile_ceu.h> | ||
21 | #include <media/sh_mobile_csi2.h> | ||
22 | #include <media/soc_camera.h> | ||
23 | #include <media/soc_mediabus.h> | ||
24 | #include <media/v4l2-common.h> | ||
25 | #include <media/v4l2-dev.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-mediabus.h> | ||
28 | #include <media/v4l2-subdev.h> | ||
29 | |||
30 | #define SH_CSI2_TREF 0x00 | ||
31 | #define SH_CSI2_SRST 0x04 | ||
32 | #define SH_CSI2_PHYCNT 0x08 | ||
33 | #define SH_CSI2_CHKSUM 0x0C | ||
34 | #define SH_CSI2_VCDT 0x10 | ||
35 | |||
36 | struct sh_csi2 { | ||
37 | struct v4l2_subdev subdev; | ||
38 | struct list_head list; | ||
39 | unsigned int irq; | ||
40 | unsigned long mipi_flags; | ||
41 | void __iomem *base; | ||
42 | struct platform_device *pdev; | ||
43 | struct sh_csi2_client_config *client; | ||
44 | }; | ||
45 | |||
46 | static int sh_csi2_try_fmt(struct v4l2_subdev *sd, | ||
47 | struct v4l2_mbus_framefmt *mf) | ||
48 | { | ||
49 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
50 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
51 | |||
52 | if (mf->width > 8188) | ||
53 | mf->width = 8188; | ||
54 | else if (mf->width & 1) | ||
55 | mf->width &= ~1; | ||
56 | |||
57 | switch (pdata->type) { | ||
58 | case SH_CSI2C: | ||
59 | switch (mf->code) { | ||
60 | case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */ | ||
61 | case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */ | ||
62 | case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ | ||
63 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
64 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
65 | break; | ||
66 | default: | ||
67 | /* All MIPI CSI-2 devices must support one of primary formats */ | ||
68 | mf->code = V4L2_MBUS_FMT_YUYV8_2X8; | ||
69 | } | ||
70 | break; | ||
71 | case SH_CSI2I: | ||
72 | switch (mf->code) { | ||
73 | case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ | ||
74 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
75 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
76 | case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */ | ||
77 | case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */ | ||
78 | break; | ||
79 | default: | ||
80 | /* All MIPI CSI-2 devices must support one of primary formats */ | ||
81 | mf->code = V4L2_MBUS_FMT_SBGGR8_1X8; | ||
82 | } | ||
83 | break; | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * We have done our best in try_fmt to try and tell the sensor, which formats | ||
91 | * we support. If now the configuration is unsuitable for us we can only | ||
92 | * error out. | ||
93 | */ | ||
94 | static int sh_csi2_s_fmt(struct v4l2_subdev *sd, | ||
95 | struct v4l2_mbus_framefmt *mf) | ||
96 | { | ||
97 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
98 | u32 tmp = (priv->client->channel & 3) << 8; | ||
99 | |||
100 | dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); | ||
101 | if (mf->width > 8188 || mf->width & 1) | ||
102 | return -EINVAL; | ||
103 | |||
104 | switch (mf->code) { | ||
105 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
106 | tmp |= 0x1e; /* YUV422 8 bit */ | ||
107 | break; | ||
108 | case V4L2_MBUS_FMT_YUYV8_1_5X8: | ||
109 | tmp |= 0x18; /* YUV420 8 bit */ | ||
110 | break; | ||
111 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: | ||
112 | tmp |= 0x21; /* RGB555 */ | ||
113 | break; | ||
114 | case V4L2_MBUS_FMT_RGB565_2X8_BE: | ||
115 | tmp |= 0x22; /* RGB565 */ | ||
116 | break; | ||
117 | case V4L2_MBUS_FMT_Y8_1X8: | ||
118 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
119 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
120 | tmp |= 0x2a; /* RAW8 */ | ||
121 | break; | ||
122 | default: | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | iowrite32(tmp, priv->base + SH_CSI2_VCDT); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd, | ||
132 | struct v4l2_mbus_config *cfg) | ||
133 | { | ||
134 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
135 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
136 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
137 | cfg->type = V4L2_MBUS_PARALLEL; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, | ||
143 | const struct v4l2_mbus_config *cfg) | ||
144 | { | ||
145 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
146 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); | ||
147 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
148 | struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, | ||
149 | .flags = priv->mipi_flags}; | ||
150 | |||
151 | return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg); | ||
152 | } | ||
153 | |||
154 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { | ||
155 | .s_mbus_fmt = sh_csi2_s_fmt, | ||
156 | .try_mbus_fmt = sh_csi2_try_fmt, | ||
157 | .g_mbus_config = sh_csi2_g_mbus_config, | ||
158 | .s_mbus_config = sh_csi2_s_mbus_config, | ||
159 | }; | ||
160 | |||
161 | static void sh_csi2_hwinit(struct sh_csi2 *priv) | ||
162 | { | ||
163 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
164 | __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */ | ||
165 | |||
166 | /* Reflect registers immediately */ | ||
167 | iowrite32(0x00000001, priv->base + SH_CSI2_TREF); | ||
168 | /* reset CSI2 harware */ | ||
169 | iowrite32(0x00000001, priv->base + SH_CSI2_SRST); | ||
170 | udelay(5); | ||
171 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); | ||
172 | |||
173 | switch (pdata->type) { | ||
174 | case SH_CSI2C: | ||
175 | if (priv->client->lanes == 1) | ||
176 | tmp |= 1; | ||
177 | else | ||
178 | /* Default - both lanes */ | ||
179 | tmp |= 3; | ||
180 | break; | ||
181 | case SH_CSI2I: | ||
182 | if (!priv->client->lanes || priv->client->lanes > 4) | ||
183 | /* Default - all 4 lanes */ | ||
184 | tmp |= 0xf; | ||
185 | else | ||
186 | tmp |= (1 << priv->client->lanes) - 1; | ||
187 | } | ||
188 | |||
189 | if (priv->client->phy == SH_CSI2_PHY_MAIN) | ||
190 | tmp |= 0x8000; | ||
191 | |||
192 | iowrite32(tmp, priv->base + SH_CSI2_PHYCNT); | ||
193 | |||
194 | tmp = 0; | ||
195 | if (pdata->flags & SH_CSI2_ECC) | ||
196 | tmp |= 2; | ||
197 | if (pdata->flags & SH_CSI2_CRC) | ||
198 | tmp |= 1; | ||
199 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); | ||
200 | } | ||
201 | |||
202 | static int sh_csi2_client_connect(struct sh_csi2 *priv) | ||
203 | { | ||
204 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | ||
205 | struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev); | ||
206 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
207 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); | ||
208 | struct v4l2_mbus_config cfg; | ||
209 | unsigned long common_flags, csi2_flags; | ||
210 | int i, ret; | ||
211 | |||
212 | if (priv->client) | ||
213 | return -EBUSY; | ||
214 | |||
215 | for (i = 0; i < pdata->num_clients; i++) | ||
216 | if (&pdata->clients[i].pdev->dev == icd->pdev) | ||
217 | break; | ||
218 | |||
219 | dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i); | ||
220 | |||
221 | if (i == pdata->num_clients) | ||
222 | return -ENODEV; | ||
223 | |||
224 | /* Check if we can support this camera */ | ||
225 | csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE; | ||
226 | |||
227 | switch (pdata->type) { | ||
228 | case SH_CSI2C: | ||
229 | if (pdata->clients[i].lanes != 1) | ||
230 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
231 | break; | ||
232 | case SH_CSI2I: | ||
233 | switch (pdata->clients[i].lanes) { | ||
234 | default: | ||
235 | csi2_flags |= V4L2_MBUS_CSI2_4_LANE; | ||
236 | case 3: | ||
237 | csi2_flags |= V4L2_MBUS_CSI2_3_LANE; | ||
238 | case 2: | ||
239 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | cfg.type = V4L2_MBUS_CSI2; | ||
244 | ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg); | ||
245 | if (ret == -ENOIOCTLCMD) | ||
246 | common_flags = csi2_flags; | ||
247 | else if (!ret) | ||
248 | common_flags = soc_mbus_config_compatible(&cfg, | ||
249 | csi2_flags); | ||
250 | else | ||
251 | common_flags = 0; | ||
252 | |||
253 | if (!common_flags) | ||
254 | return -EINVAL; | ||
255 | |||
256 | /* All good: camera MIPI configuration supported */ | ||
257 | priv->mipi_flags = common_flags; | ||
258 | priv->client = pdata->clients + i; | ||
259 | |||
260 | pm_runtime_get_sync(dev); | ||
261 | |||
262 | sh_csi2_hwinit(priv); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) | ||
268 | { | ||
269 | if (!priv->client) | ||
270 | return; | ||
271 | |||
272 | priv->client = NULL; | ||
273 | |||
274 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | ||
275 | } | ||
276 | |||
277 | static int sh_csi2_s_power(struct v4l2_subdev *sd, int on) | ||
278 | { | ||
279 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
280 | |||
281 | if (on) | ||
282 | return sh_csi2_client_connect(priv); | ||
283 | |||
284 | sh_csi2_client_disconnect(priv); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = { | ||
289 | .s_power = sh_csi2_s_power, | ||
290 | }; | ||
291 | |||
292 | static struct v4l2_subdev_ops sh_csi2_subdev_ops = { | ||
293 | .core = &sh_csi2_subdev_core_ops, | ||
294 | .video = &sh_csi2_subdev_video_ops, | ||
295 | }; | ||
296 | |||
297 | static __devinit int sh_csi2_probe(struct platform_device *pdev) | ||
298 | { | ||
299 | struct resource *res; | ||
300 | unsigned int irq; | ||
301 | int ret; | ||
302 | struct sh_csi2 *priv; | ||
303 | /* Platform data specify the PHY, lanes, ECC, CRC */ | ||
304 | struct sh_csi2_pdata *pdata = pdev->dev.platform_data; | ||
305 | |||
306 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
307 | /* Interrupt unused so far */ | ||
308 | irq = platform_get_irq(pdev, 0); | ||
309 | |||
310 | if (!res || (int)irq <= 0 || !pdata) { | ||
311 | dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n"); | ||
312 | return -ENODEV; | ||
313 | } | ||
314 | |||
315 | /* TODO: Add support for CSI2I. Careful: different register layout! */ | ||
316 | if (pdata->type != SH_CSI2C) { | ||
317 | dev_err(&pdev->dev, "Only CSI2C supported ATM.\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL); | ||
322 | if (!priv) | ||
323 | return -ENOMEM; | ||
324 | |||
325 | priv->irq = irq; | ||
326 | |||
327 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | ||
328 | dev_err(&pdev->dev, "CSI2 register region already claimed\n"); | ||
329 | ret = -EBUSY; | ||
330 | goto ereqreg; | ||
331 | } | ||
332 | |||
333 | priv->base = ioremap(res->start, resource_size(res)); | ||
334 | if (!priv->base) { | ||
335 | ret = -ENXIO; | ||
336 | dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n"); | ||
337 | goto eremap; | ||
338 | } | ||
339 | |||
340 | priv->pdev = pdev; | ||
341 | platform_set_drvdata(pdev, priv); | ||
342 | |||
343 | v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops); | ||
344 | v4l2_set_subdevdata(&priv->subdev, &pdev->dev); | ||
345 | |||
346 | snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi", | ||
347 | dev_name(pdata->v4l2_dev->dev)); | ||
348 | ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev); | ||
349 | dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); | ||
350 | if (ret < 0) | ||
351 | goto esdreg; | ||
352 | |||
353 | pm_runtime_enable(&pdev->dev); | ||
354 | |||
355 | dev_dbg(&pdev->dev, "CSI2 probed.\n"); | ||
356 | |||
357 | return 0; | ||
358 | |||
359 | esdreg: | ||
360 | iounmap(priv->base); | ||
361 | eremap: | ||
362 | release_mem_region(res->start, resource_size(res)); | ||
363 | ereqreg: | ||
364 | kfree(priv); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | static __devexit int sh_csi2_remove(struct platform_device *pdev) | ||
370 | { | ||
371 | struct sh_csi2 *priv = platform_get_drvdata(pdev); | ||
372 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
373 | |||
374 | v4l2_device_unregister_subdev(&priv->subdev); | ||
375 | pm_runtime_disable(&pdev->dev); | ||
376 | iounmap(priv->base); | ||
377 | release_mem_region(res->start, resource_size(res)); | ||
378 | platform_set_drvdata(pdev, NULL); | ||
379 | kfree(priv); | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static struct platform_driver __refdata sh_csi2_pdrv = { | ||
385 | .remove = __devexit_p(sh_csi2_remove), | ||
386 | .probe = sh_csi2_probe, | ||
387 | .driver = { | ||
388 | .name = "sh-mobile-csi2", | ||
389 | .owner = THIS_MODULE, | ||
390 | }, | ||
391 | }; | ||
392 | |||
393 | module_platform_driver(sh_csi2_pdrv); | ||
394 | |||
395 | MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); | ||
396 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
397 | MODULE_LICENSE("GPL v2"); | ||
398 | MODULE_ALIAS("platform:sh-mobile-csi2"); | ||