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