Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sh_mobile_csi2.c
Go to the documentation of this file.
1 /*
2  * Driver for the SH-Mobile MIPI CSI-2 unit
3  *
4  * Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
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 {
38  struct list_head list;
39  unsigned int irq;
40  unsigned long mipi_flags;
41  void __iomem *base;
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 */
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 */
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) {
106  tmp |= 0x1e; /* YUV422 8 bit */
107  break;
109  tmp |= 0x18; /* YUV420 8 bit */
110  break;
112  tmp |= 0x21; /* RGB555 */
113  break;
115  tmp |= 0x22; /* RGB565 */
116  break;
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 {
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 */
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 
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 <[email protected]>");
397 MODULE_LICENSE("GPL v2");
398 MODULE_ALIAS("platform:sh-mobile-csi2");