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 33struct 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 43static 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_GREY8_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_GREY8_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 */ 91static 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_GREY8_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 128static 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 133static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops; 134 135static struct v4l2_subdev_ops sh_csi2_subdev_ops = { 136 .core = &sh_csi2_subdev_core_ops, 137 .video = &sh_csi2_subdev_video_ops, 138}; 139 140static 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 171static int sh_csi2_set_bus_param(struct soc_camera_device *icd, 172 unsigned long flags) 173{ 174 return 0; 175} 176 177static 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 187static 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 241static __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 305eremap: 306 release_mem_region(res->start, resource_size(res)); 307ereqreg: 308 bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier); 309ernotify: 310 kfree(priv); 311 312 return ret; 313} 314 315static __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 330static 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 338static int __init sh_csi2_init(void) 339{ 340 return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe); 341} 342 343static void __exit sh_csi2_exit(void) 344{ 345 platform_driver_unregister(&sh_csi2_pdrv); 346} 347 348module_init(sh_csi2_init); 349module_exit(sh_csi2_exit); 350 351MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); 352MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); 353MODULE_LICENSE("GPL v2"); 354MODULE_ALIAS("platform:sh-mobile-csi2"); 355