1/* 2 * Driver for IMX074 CMOS Image Sensor from Sony 3 * 4 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> 5 * 6 * Partially inspired by the IMX074 driver from the Android / MSM tree 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13#include <linux/delay.h> 14#include <linux/i2c.h> 15#include <linux/v4l2-mediabus.h> 16#include <linux/slab.h> 17#include <linux/videodev2.h> 18#include <linux/module.h> 19 20#include <media/soc_camera.h> 21#include <media/v4l2-async.h> 22#include <media/v4l2-clk.h> 23#include <media/v4l2-subdev.h> 24 25/* IMX074 registers */ 26 27#define MODE_SELECT 0x0100 28#define IMAGE_ORIENTATION 0x0101 29#define GROUPED_PARAMETER_HOLD 0x0104 30 31/* Integration Time */ 32#define COARSE_INTEGRATION_TIME_HI 0x0202 33#define COARSE_INTEGRATION_TIME_LO 0x0203 34/* Gain */ 35#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204 36#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205 37 38/* PLL registers */ 39#define PRE_PLL_CLK_DIV 0x0305 40#define PLL_MULTIPLIER 0x0307 41#define PLSTATIM 0x302b 42#define VNDMY_ABLMGSHLMT 0x300a 43#define Y_OPBADDR_START_DI 0x3014 44/* mode setting */ 45#define FRAME_LENGTH_LINES_HI 0x0340 46#define FRAME_LENGTH_LINES_LO 0x0341 47#define LINE_LENGTH_PCK_HI 0x0342 48#define LINE_LENGTH_PCK_LO 0x0343 49#define YADDR_START 0x0347 50#define YADDR_END 0x034b 51#define X_OUTPUT_SIZE_MSB 0x034c 52#define X_OUTPUT_SIZE_LSB 0x034d 53#define Y_OUTPUT_SIZE_MSB 0x034e 54#define Y_OUTPUT_SIZE_LSB 0x034f 55#define X_EVEN_INC 0x0381 56#define X_ODD_INC 0x0383 57#define Y_EVEN_INC 0x0385 58#define Y_ODD_INC 0x0387 59 60#define HMODEADD 0x3001 61#define VMODEADD 0x3016 62#define VAPPLINE_START 0x3069 63#define VAPPLINE_END 0x306b 64#define SHUTTER 0x3086 65#define HADDAVE 0x30e8 66#define LANESEL 0x3301 67 68/* IMX074 supported geometry */ 69#define IMX074_WIDTH 1052 70#define IMX074_HEIGHT 780 71 72/* IMX074 has only one fixed colorspace per pixelcode */ 73struct imx074_datafmt { 74 u32 code; 75 enum v4l2_colorspace colorspace; 76}; 77 78struct imx074 { 79 struct v4l2_subdev subdev; 80 const struct imx074_datafmt *fmt; 81 struct v4l2_clk *clk; 82}; 83 84static const struct imx074_datafmt imx074_colour_fmts[] = { 85 {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, 86}; 87 88static struct imx074 *to_imx074(const struct i2c_client *client) 89{ 90 return container_of(i2c_get_clientdata(client), struct imx074, subdev); 91} 92 93/* Find a data format by a pixel code in an array */ 94static const struct imx074_datafmt *imx074_find_datafmt(u32 code) 95{ 96 int i; 97 98 for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++) 99 if (imx074_colour_fmts[i].code == code) 100 return imx074_colour_fmts + i; 101 102 return NULL; 103} 104 105static int reg_write(struct i2c_client *client, const u16 addr, const u8 data) 106{ 107 struct i2c_adapter *adap = client->adapter; 108 struct i2c_msg msg; 109 unsigned char tx[3]; 110 int ret; 111 112 msg.addr = client->addr; 113 msg.buf = tx; 114 msg.len = 3; 115 msg.flags = 0; 116 117 tx[0] = addr >> 8; 118 tx[1] = addr & 0xff; 119 tx[2] = data; 120 121 ret = i2c_transfer(adap, &msg, 1); 122 123 mdelay(2); 124 125 return ret == 1 ? 0 : -EIO; 126} 127 128static int reg_read(struct i2c_client *client, const u16 addr) 129{ 130 u8 buf[2] = {addr >> 8, addr & 0xff}; 131 int ret; 132 struct i2c_msg msgs[] = { 133 { 134 .addr = client->addr, 135 .flags = 0, 136 .len = 2, 137 .buf = buf, 138 }, { 139 .addr = client->addr, 140 .flags = I2C_M_RD, 141 .len = 2, 142 .buf = buf, 143 }, 144 }; 145 146 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 147 if (ret < 0) { 148 dev_warn(&client->dev, "Reading register %x from %x failed\n", 149 addr, client->addr); 150 return ret; 151 } 152 153 return buf[0] & 0xff; /* no sign-extension */ 154} 155 156static int imx074_try_fmt(struct v4l2_subdev *sd, 157 struct v4l2_mbus_framefmt *mf) 158{ 159 const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code); 160 161 dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); 162 163 if (!fmt) { 164 mf->code = imx074_colour_fmts[0].code; 165 mf->colorspace = imx074_colour_fmts[0].colorspace; 166 } 167 168 mf->width = IMX074_WIDTH; 169 mf->height = IMX074_HEIGHT; 170 mf->field = V4L2_FIELD_NONE; 171 172 return 0; 173} 174 175static int imx074_s_fmt(struct v4l2_subdev *sd, 176 struct v4l2_mbus_framefmt *mf) 177{ 178 struct i2c_client *client = v4l2_get_subdevdata(sd); 179 struct imx074 *priv = to_imx074(client); 180 181 dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); 182 183 /* MIPI CSI could have changed the format, double-check */ 184 if (!imx074_find_datafmt(mf->code)) 185 return -EINVAL; 186 187 imx074_try_fmt(sd, mf); 188 189 priv->fmt = imx074_find_datafmt(mf->code); 190 191 return 0; 192} 193 194static int imx074_g_fmt(struct v4l2_subdev *sd, 195 struct v4l2_mbus_framefmt *mf) 196{ 197 struct i2c_client *client = v4l2_get_subdevdata(sd); 198 struct imx074 *priv = to_imx074(client); 199 200 const struct imx074_datafmt *fmt = priv->fmt; 201 202 mf->code = fmt->code; 203 mf->colorspace = fmt->colorspace; 204 mf->width = IMX074_WIDTH; 205 mf->height = IMX074_HEIGHT; 206 mf->field = V4L2_FIELD_NONE; 207 208 return 0; 209} 210 211static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 212{ 213 struct v4l2_rect *rect = &a->c; 214 215 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 216 rect->top = 0; 217 rect->left = 0; 218 rect->width = IMX074_WIDTH; 219 rect->height = IMX074_HEIGHT; 220 221 return 0; 222} 223 224static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 225{ 226 a->bounds.left = 0; 227 a->bounds.top = 0; 228 a->bounds.width = IMX074_WIDTH; 229 a->bounds.height = IMX074_HEIGHT; 230 a->defrect = a->bounds; 231 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 232 a->pixelaspect.numerator = 1; 233 a->pixelaspect.denominator = 1; 234 235 return 0; 236} 237 238static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index, 239 u32 *code) 240{ 241 if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts)) 242 return -EINVAL; 243 244 *code = imx074_colour_fmts[index].code; 245 return 0; 246} 247 248static int imx074_s_stream(struct v4l2_subdev *sd, int enable) 249{ 250 struct i2c_client *client = v4l2_get_subdevdata(sd); 251 252 /* MODE_SELECT: stream or standby */ 253 return reg_write(client, MODE_SELECT, !!enable); 254} 255 256static int imx074_s_power(struct v4l2_subdev *sd, int on) 257{ 258 struct i2c_client *client = v4l2_get_subdevdata(sd); 259 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); 260 struct imx074 *priv = to_imx074(client); 261 262 return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); 263} 264 265static int imx074_g_mbus_config(struct v4l2_subdev *sd, 266 struct v4l2_mbus_config *cfg) 267{ 268 cfg->type = V4L2_MBUS_CSI2; 269 cfg->flags = V4L2_MBUS_CSI2_2_LANE | 270 V4L2_MBUS_CSI2_CHANNEL_0 | 271 V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 272 273 return 0; 274} 275 276static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { 277 .s_stream = imx074_s_stream, 278 .s_mbus_fmt = imx074_s_fmt, 279 .g_mbus_fmt = imx074_g_fmt, 280 .try_mbus_fmt = imx074_try_fmt, 281 .enum_mbus_fmt = imx074_enum_fmt, 282 .g_crop = imx074_g_crop, 283 .cropcap = imx074_cropcap, 284 .g_mbus_config = imx074_g_mbus_config, 285}; 286 287static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { 288 .s_power = imx074_s_power, 289}; 290 291static struct v4l2_subdev_ops imx074_subdev_ops = { 292 .core = &imx074_subdev_core_ops, 293 .video = &imx074_subdev_video_ops, 294}; 295 296static int imx074_video_probe(struct i2c_client *client) 297{ 298 struct v4l2_subdev *subdev = i2c_get_clientdata(client); 299 int ret; 300 u16 id; 301 302 ret = imx074_s_power(subdev, 1); 303 if (ret < 0) 304 return ret; 305 306 /* Read sensor Model ID */ 307 ret = reg_read(client, 0); 308 if (ret < 0) 309 goto done; 310 311 id = ret << 8; 312 313 ret = reg_read(client, 1); 314 if (ret < 0) 315 goto done; 316 317 id |= ret; 318 319 dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); 320 321 if (id != 0x74) { 322 ret = -ENODEV; 323 goto done; 324 } 325 326 /* PLL Setting EXTCLK=24MHz, 22.5times */ 327 reg_write(client, PLL_MULTIPLIER, 0x2D); 328 reg_write(client, PRE_PLL_CLK_DIV, 0x02); 329 reg_write(client, PLSTATIM, 0x4B); 330 331 /* 2-lane mode */ 332 reg_write(client, 0x3024, 0x00); 333 334 reg_write(client, IMAGE_ORIENTATION, 0x00); 335 336 /* select RAW mode: 337 * 0x08+0x08 = top 8 bits 338 * 0x0a+0x08 = compressed 8-bits 339 * 0x0a+0x0a = 10 bits 340 */ 341 reg_write(client, 0x0112, 0x08); 342 reg_write(client, 0x0113, 0x08); 343 344 /* Base setting for High frame mode */ 345 reg_write(client, VNDMY_ABLMGSHLMT, 0x80); 346 reg_write(client, Y_OPBADDR_START_DI, 0x08); 347 reg_write(client, 0x3015, 0x37); 348 reg_write(client, 0x301C, 0x01); 349 reg_write(client, 0x302C, 0x05); 350 reg_write(client, 0x3031, 0x26); 351 reg_write(client, 0x3041, 0x60); 352 reg_write(client, 0x3051, 0x24); 353 reg_write(client, 0x3053, 0x34); 354 reg_write(client, 0x3057, 0xC0); 355 reg_write(client, 0x305C, 0x09); 356 reg_write(client, 0x305D, 0x07); 357 reg_write(client, 0x3060, 0x30); 358 reg_write(client, 0x3065, 0x00); 359 reg_write(client, 0x30AA, 0x08); 360 reg_write(client, 0x30AB, 0x1C); 361 reg_write(client, 0x30B0, 0x32); 362 reg_write(client, 0x30B2, 0x83); 363 reg_write(client, 0x30D3, 0x04); 364 reg_write(client, 0x3106, 0x78); 365 reg_write(client, 0x310C, 0x82); 366 reg_write(client, 0x3304, 0x05); 367 reg_write(client, 0x3305, 0x04); 368 reg_write(client, 0x3306, 0x11); 369 reg_write(client, 0x3307, 0x02); 370 reg_write(client, 0x3308, 0x0C); 371 reg_write(client, 0x3309, 0x06); 372 reg_write(client, 0x330A, 0x08); 373 reg_write(client, 0x330B, 0x04); 374 reg_write(client, 0x330C, 0x08); 375 reg_write(client, 0x330D, 0x06); 376 reg_write(client, 0x330E, 0x01); 377 reg_write(client, 0x3381, 0x00); 378 379 /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */ 380 /* 1608 = 1560 + 48 (black lines) */ 381 reg_write(client, FRAME_LENGTH_LINES_HI, 0x06); 382 reg_write(client, FRAME_LENGTH_LINES_LO, 0x48); 383 reg_write(client, YADDR_START, 0x00); 384 reg_write(client, YADDR_END, 0x2F); 385 /* 0x838 == 2104 */ 386 reg_write(client, X_OUTPUT_SIZE_MSB, 0x08); 387 reg_write(client, X_OUTPUT_SIZE_LSB, 0x38); 388 /* 0x618 == 1560 */ 389 reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06); 390 reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18); 391 reg_write(client, X_EVEN_INC, 0x01); 392 reg_write(client, X_ODD_INC, 0x03); 393 reg_write(client, Y_EVEN_INC, 0x01); 394 reg_write(client, Y_ODD_INC, 0x03); 395 reg_write(client, HMODEADD, 0x00); 396 reg_write(client, VMODEADD, 0x16); 397 reg_write(client, VAPPLINE_START, 0x24); 398 reg_write(client, VAPPLINE_END, 0x53); 399 reg_write(client, SHUTTER, 0x00); 400 reg_write(client, HADDAVE, 0x80); 401 402 reg_write(client, LANESEL, 0x00); 403 404 reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */ 405 406 ret = 0; 407 408done: 409 imx074_s_power(subdev, 0); 410 return ret; 411} 412 413static int imx074_probe(struct i2c_client *client, 414 const struct i2c_device_id *did) 415{ 416 struct imx074 *priv; 417 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 418 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); 419 int ret; 420 421 if (!ssdd) { 422 dev_err(&client->dev, "IMX074: missing platform data!\n"); 423 return -EINVAL; 424 } 425 426 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 427 dev_warn(&adapter->dev, 428 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); 429 return -EIO; 430 } 431 432 priv = devm_kzalloc(&client->dev, sizeof(struct imx074), GFP_KERNEL); 433 if (!priv) 434 return -ENOMEM; 435 436 v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); 437 438 priv->fmt = &imx074_colour_fmts[0]; 439 440 priv->clk = v4l2_clk_get(&client->dev, "mclk"); 441 if (IS_ERR(priv->clk)) { 442 dev_info(&client->dev, "Error %ld getting clock\n", PTR_ERR(priv->clk)); 443 return -EPROBE_DEFER; 444 } 445 446 ret = soc_camera_power_init(&client->dev, ssdd); 447 if (ret < 0) 448 goto epwrinit; 449 450 ret = imx074_video_probe(client); 451 if (ret < 0) 452 goto eprobe; 453 454 ret = v4l2_async_register_subdev(&priv->subdev); 455 if (!ret) 456 return 0; 457 458epwrinit: 459eprobe: 460 v4l2_clk_put(priv->clk); 461 return ret; 462} 463 464static int imx074_remove(struct i2c_client *client) 465{ 466 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); 467 struct imx074 *priv = to_imx074(client); 468 469 v4l2_async_unregister_subdev(&priv->subdev); 470 v4l2_clk_put(priv->clk); 471 472 if (ssdd->free_bus) 473 ssdd->free_bus(ssdd); 474 475 return 0; 476} 477 478static const struct i2c_device_id imx074_id[] = { 479 { "imx074", 0 }, 480 { } 481}; 482MODULE_DEVICE_TABLE(i2c, imx074_id); 483 484static struct i2c_driver imx074_i2c_driver = { 485 .driver = { 486 .name = "imx074", 487 }, 488 .probe = imx074_probe, 489 .remove = imx074_remove, 490 .id_table = imx074_id, 491}; 492 493module_i2c_driver(imx074_i2c_driver); 494 495MODULE_DESCRIPTION("Sony IMX074 Camera driver"); 496MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); 497MODULE_LICENSE("GPL v2"); 498