Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[pandora-kernel.git] / drivers / media / video / sh_mobile_csi2.c
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
19 #include <media/sh_mobile_csi2.h>
20 #include <media/soc_camera.h>
21 #include <media/v4l2-common.h>
22 #include <media/v4l2-dev.h>
23 #include <media/v4l2-device.h>
24 #include <media/v4l2-mediabus.h>
25 #include <media/v4l2-subdev.h>
26
27 #define SH_CSI2_TREF    0x00
28 #define SH_CSI2_SRST    0x04
29 #define SH_CSI2_PHYCNT  0x08
30 #define SH_CSI2_CHKSUM  0x0C
31 #define SH_CSI2_VCDT    0x10
32
33 struct sh_csi2 {
34         struct v4l2_subdev              subdev;
35         struct list_head                list;
36         struct notifier_block           notifier;
37         unsigned int                    irq;
38         void __iomem                    *base;
39         struct platform_device          *pdev;
40         struct sh_csi2_client_config    *client;
41 };
42
43 static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
44                            struct v4l2_mbus_framefmt *mf)
45 {
46         struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
47         struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
48
49         if (mf->width > 8188)
50                 mf->width = 8188;
51         else if (mf->width & 1)
52                 mf->width &= ~1;
53
54         switch (pdata->type) {
55         case SH_CSI2C:
56                 switch (mf->code) {
57                 case V4L2_MBUS_FMT_UYVY8_2X8:           /* YUV422 */
58                 case V4L2_MBUS_FMT_YUYV8_1_5X8:         /* YUV420 */
59                 case V4L2_MBUS_FMT_Y8_1X8:              /* RAW8 */
60                 case V4L2_MBUS_FMT_SBGGR8_1X8:
61                 case V4L2_MBUS_FMT_SGRBG8_1X8:
62                         break;
63                 default:
64                         /* All MIPI CSI-2 devices must support one of primary formats */
65                         mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
66                 }
67                 break;
68         case SH_CSI2I:
69                 switch (mf->code) {
70                 case V4L2_MBUS_FMT_Y8_1X8:              /* RAW8 */
71                 case V4L2_MBUS_FMT_SBGGR8_1X8:
72                 case V4L2_MBUS_FMT_SGRBG8_1X8:
73                 case V4L2_MBUS_FMT_SBGGR10_1X10:        /* RAW10 */
74                 case V4L2_MBUS_FMT_SBGGR12_1X12:        /* RAW12 */
75                         break;
76                 default:
77                         /* All MIPI CSI-2 devices must support one of primary formats */
78                         mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
79                 }
80                 break;
81         }
82
83         return 0;
84 }
85
86 /*
87  * We have done our best in try_fmt to try and tell the sensor, which formats
88  * we support. If now the configuration is unsuitable for us we can only
89  * error out.
90  */
91 static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
92                          struct v4l2_mbus_framefmt *mf)
93 {
94         struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
95         u32 tmp = (priv->client->channel & 3) << 8;
96
97         dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
98         if (mf->width > 8188 || mf->width & 1)
99                 return -EINVAL;
100
101         switch (mf->code) {
102         case V4L2_MBUS_FMT_UYVY8_2X8:
103                 tmp |= 0x1e;    /* YUV422 8 bit */
104                 break;
105         case V4L2_MBUS_FMT_YUYV8_1_5X8:
106                 tmp |= 0x18;    /* YUV420 8 bit */
107                 break;
108         case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
109                 tmp |= 0x21;    /* RGB555 */
110                 break;
111         case V4L2_MBUS_FMT_RGB565_2X8_BE:
112                 tmp |= 0x22;    /* RGB565 */
113                 break;
114         case V4L2_MBUS_FMT_Y8_1X8:
115         case V4L2_MBUS_FMT_SBGGR8_1X8:
116         case V4L2_MBUS_FMT_SGRBG8_1X8:
117                 tmp |= 0x2a;    /* RAW8 */
118                 break;
119         default:
120                 return -EINVAL;
121         }
122
123         iowrite32(tmp, priv->base + SH_CSI2_VCDT);
124
125         return 0;
126 }
127
128 static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
129         .s_mbus_fmt     = sh_csi2_s_fmt,
130         .try_mbus_fmt   = sh_csi2_try_fmt,
131 };
132
133 static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
134
135 static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
136         .core   = &sh_csi2_subdev_core_ops,
137         .video  = &sh_csi2_subdev_video_ops,
138 };
139
140 static void sh_csi2_hwinit(struct sh_csi2 *priv)
141 {
142         struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
143         __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
144
145         /* Reflect registers immediately */
146         iowrite32(0x00000001, priv->base + SH_CSI2_TREF);
147         /* reset CSI2 harware */
148         iowrite32(0x00000001, priv->base + SH_CSI2_SRST);
149         udelay(5);
150         iowrite32(0x00000000, priv->base + SH_CSI2_SRST);
151
152         if (priv->client->lanes & 3)
153                 tmp |= priv->client->lanes & 3;
154         else
155                 /* Default - both lanes */
156                 tmp |= 3;
157
158         if (priv->client->phy == SH_CSI2_PHY_MAIN)
159                 tmp |= 0x8000;
160
161         iowrite32(tmp, priv->base + SH_CSI2_PHYCNT);
162
163         tmp = 0;
164         if (pdata->flags & SH_CSI2_ECC)
165                 tmp |= 2;
166         if (pdata->flags & SH_CSI2_CRC)
167                 tmp |= 1;
168         iowrite32(tmp, priv->base + SH_CSI2_CHKSUM);
169 }
170
171 static int sh_csi2_set_bus_param(struct soc_camera_device *icd,
172                                  unsigned long flags)
173 {
174         return 0;
175 }
176
177 static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
178 {
179         struct soc_camera_link *icl = to_soc_camera_link(icd);
180         const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
181                 SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
182                 SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH;
183
184         return soc_camera_apply_sensor_flags(icl, flags);
185 }
186
187 static int sh_csi2_notify(struct notifier_block *nb,
188                           unsigned long action, void *data)
189 {
190         struct device *dev = data;
191         struct soc_camera_device *icd = to_soc_camera_dev(dev);
192         struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
193         struct sh_csi2 *priv =
194                 container_of(nb, struct sh_csi2, notifier);
195         struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
196         int ret, i;
197
198         for (i = 0; i < pdata->num_clients; i++)
199                 if (&pdata->clients[i].pdev->dev == icd->pdev)
200                         break;
201
202         dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
203
204         if (i == pdata->num_clients)
205                 return NOTIFY_DONE;
206
207         switch (action) {
208         case BUS_NOTIFY_BOUND_DRIVER:
209                 snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
210                          dev_name(v4l2_dev->dev), ".mipi-csi");
211                 ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
212                 dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
213                 if (ret < 0)
214                         return NOTIFY_DONE;
215
216                 priv->client = pdata->clients + i;
217
218                 icd->ops->set_bus_param         = sh_csi2_set_bus_param;
219                 icd->ops->query_bus_param       = sh_csi2_query_bus_param;
220
221                 pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
222
223                 sh_csi2_hwinit(priv);
224                 break;
225         case BUS_NOTIFY_UNBIND_DRIVER:
226                 priv->client = NULL;
227
228                 /* Driver is about to be unbound */
229                 icd->ops->set_bus_param         = NULL;
230                 icd->ops->query_bus_param       = NULL;
231
232                 v4l2_device_unregister_subdev(&priv->subdev);
233
234                 pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
235                 break;
236         }
237
238         return NOTIFY_OK;
239 }
240
241 static __devinit int sh_csi2_probe(struct platform_device *pdev)
242 {
243         struct resource *res;
244         unsigned int irq;
245         int ret;
246         struct sh_csi2 *priv;
247         /* Platform data specify the PHY, lanes, ECC, CRC */
248         struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
249
250         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
251         /* Interrupt unused so far */
252         irq = platform_get_irq(pdev, 0);
253
254         if (!res || (int)irq <= 0 || !pdata) {
255                 dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
256                 return -ENODEV;
257         }
258
259         /* TODO: Add support for CSI2I. Careful: different register layout! */
260         if (pdata->type != SH_CSI2C) {
261                 dev_err(&pdev->dev, "Only CSI2C supported ATM.\n");
262                 return -EINVAL;
263         }
264
265         priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
266         if (!priv)
267                 return -ENOMEM;
268
269         priv->irq = irq;
270         priv->notifier.notifier_call = sh_csi2_notify;
271
272         /* We MUST attach after the MIPI sensor */
273         ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
274         if (ret < 0) {
275                 dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
276                 goto ernotify;
277         }
278
279         if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
280                 dev_err(&pdev->dev, "CSI2 register region already claimed\n");
281                 ret = -EBUSY;
282                 goto ereqreg;
283         }
284
285         priv->base = ioremap(res->start, resource_size(res));
286         if (!priv->base) {
287                 ret = -ENXIO;
288                 dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
289                 goto eremap;
290         }
291
292         priv->pdev = pdev;
293
294         v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
295         v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
296
297         platform_set_drvdata(pdev, priv);
298
299         pm_runtime_enable(&pdev->dev);
300
301         dev_dbg(&pdev->dev, "CSI2 probed.\n");
302
303         return 0;
304
305 eremap:
306         release_mem_region(res->start, resource_size(res));
307 ereqreg:
308         bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
309 ernotify:
310         kfree(priv);
311
312         return ret;
313 }
314
315 static __devexit int sh_csi2_remove(struct platform_device *pdev)
316 {
317         struct sh_csi2 *priv = platform_get_drvdata(pdev);
318         struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
319
320         bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
321         pm_runtime_disable(&pdev->dev);
322         iounmap(priv->base);
323         release_mem_region(res->start, resource_size(res));
324         platform_set_drvdata(pdev, NULL);
325         kfree(priv);
326
327         return 0;
328 }
329
330 static struct platform_driver __refdata sh_csi2_pdrv = {
331         .remove  = __devexit_p(sh_csi2_remove),
332         .driver  = {
333                 .name   = "sh-mobile-csi2",
334                 .owner  = THIS_MODULE,
335         },
336 };
337
338 static int __init sh_csi2_init(void)
339 {
340         return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
341 }
342
343 static void __exit sh_csi2_exit(void)
344 {
345         platform_driver_unregister(&sh_csi2_pdrv);
346 }
347
348 module_init(sh_csi2_init);
349 module_exit(sh_csi2_exit);
350
351 MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
352 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
353 MODULE_LICENSE("GPL v2");
354 MODULE_ALIAS("platform:sh-mobile-csi2");