Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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