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

[media] V4L: Add S5C73M3 camera driver

Add driver for S5C73M3 image sensor. The driver exposes the sensor as
two subdevs: pure sensor and output interface. Two subdev architecture
supports interleaved UYVY/JPEG image format with separate frame size
for both sub-formats, there is a spearate pad for each sub-format.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Andrzej Hajda and committed by
Mauro Carvalho Chehab
cac47f18 6e83e6e2

+2949
+7
drivers/media/i2c/Kconfig
··· 523 523 524 524 source "drivers/media/i2c/smiapp/Kconfig" 525 525 526 + config VIDEO_S5C73M3 527 + tristate "Samsung S5C73M3 sensor support" 528 + depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API 529 + ---help--- 530 + This is a V4L2 sensor-level driver for Samsung S5C73M3 531 + 8 Mpixel camera. 532 + 526 533 comment "Flash devices" 527 534 528 535 config VIDEO_ADP1653
+1
drivers/media/i2c/Makefile
··· 59 59 obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o 60 60 obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o 61 61 obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o 62 + obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ 62 63 obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o 63 64 obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o 64 65 obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
+2
drivers/media/i2c/s5c73m3/Makefile
··· 1 + s5c73m3-objs := s5c73m3-core.o s5c73m3-spi.o s5c73m3-ctrls.o 2 + obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3.o
+1706
drivers/media/i2c/s5c73m3/s5c73m3-core.c
··· 1 + /* 2 + * Samsung LSI S5C73M3 8M pixel camera driver 3 + * 4 + * Copyright (C) 2012, Samsung Electronics, Co., Ltd. 5 + * Sylwester Nawrocki <s.nawrocki@samsung.com> 6 + * Andrzej Hajda <a.hajda@samsung.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/sizes.h> 19 + #include <linux/delay.h> 20 + #include <linux/firmware.h> 21 + #include <linux/gpio.h> 22 + #include <linux/i2c.h> 23 + #include <linux/init.h> 24 + #include <linux/media.h> 25 + #include <linux/module.h> 26 + #include <linux/regulator/consumer.h> 27 + #include <linux/slab.h> 28 + #include <linux/spi/spi.h> 29 + #include <linux/videodev2.h> 30 + #include <media/media-entity.h> 31 + #include <media/v4l2-ctrls.h> 32 + #include <media/v4l2-device.h> 33 + #include <media/v4l2-subdev.h> 34 + #include <media/v4l2-mediabus.h> 35 + #include <media/s5c73m3.h> 36 + 37 + #include "s5c73m3.h" 38 + 39 + int s5c73m3_dbg; 40 + module_param_named(debug, s5c73m3_dbg, int, 0644); 41 + 42 + int boot_from_rom = 1; 43 + module_param(boot_from_rom, int, 0644); 44 + 45 + int update_fw; 46 + module_param(update_fw, int, 0644); 47 + 48 + #define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K 49 + 50 + static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = { 51 + "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */ 52 + "vdda", /* Analog Core supply (1.2V), CAM_SENSOR_CORE_1.2V */ 53 + "vdd-reg", /* Regulator input supply (2.8V), CAM_SENSOR_A2.8V */ 54 + "vddio-host", /* Digital Host I/O power supply (1.8V...2.8V), 55 + CAM_ISP_SENSOR_1.8V */ 56 + "vddio-cis", /* Digital CIS I/O power (1.2V...1.8V), 57 + CAM_ISP_MIPI_1.2V */ 58 + "vdd-af", /* Lens, CAM_AF_2.8V */ 59 + }; 60 + 61 + static const struct s5c73m3_frame_size s5c73m3_isp_resolutions[] = { 62 + { 320, 240, COMM_CHG_MODE_YUV_320_240 }, 63 + { 352, 288, COMM_CHG_MODE_YUV_352_288 }, 64 + { 640, 480, COMM_CHG_MODE_YUV_640_480 }, 65 + { 880, 720, COMM_CHG_MODE_YUV_880_720 }, 66 + { 960, 720, COMM_CHG_MODE_YUV_960_720 }, 67 + { 1008, 672, COMM_CHG_MODE_YUV_1008_672 }, 68 + { 1184, 666, COMM_CHG_MODE_YUV_1184_666 }, 69 + { 1280, 720, COMM_CHG_MODE_YUV_1280_720 }, 70 + { 1536, 864, COMM_CHG_MODE_YUV_1536_864 }, 71 + { 1600, 1200, COMM_CHG_MODE_YUV_1600_1200 }, 72 + { 1632, 1224, COMM_CHG_MODE_YUV_1632_1224 }, 73 + { 1920, 1080, COMM_CHG_MODE_YUV_1920_1080 }, 74 + { 1920, 1440, COMM_CHG_MODE_YUV_1920_1440 }, 75 + { 2304, 1296, COMM_CHG_MODE_YUV_2304_1296 }, 76 + { 3264, 2448, COMM_CHG_MODE_YUV_3264_2448 }, 77 + }; 78 + 79 + static const struct s5c73m3_frame_size s5c73m3_jpeg_resolutions[] = { 80 + { 640, 480, COMM_CHG_MODE_JPEG_640_480 }, 81 + { 800, 450, COMM_CHG_MODE_JPEG_800_450 }, 82 + { 800, 600, COMM_CHG_MODE_JPEG_800_600 }, 83 + { 1024, 768, COMM_CHG_MODE_JPEG_1024_768 }, 84 + { 1280, 720, COMM_CHG_MODE_JPEG_1280_720 }, 85 + { 1280, 960, COMM_CHG_MODE_JPEG_1280_960 }, 86 + { 1600, 900, COMM_CHG_MODE_JPEG_1600_900 }, 87 + { 1600, 1200, COMM_CHG_MODE_JPEG_1600_1200 }, 88 + { 2048, 1152, COMM_CHG_MODE_JPEG_2048_1152 }, 89 + { 2048, 1536, COMM_CHG_MODE_JPEG_2048_1536 }, 90 + { 2560, 1440, COMM_CHG_MODE_JPEG_2560_1440 }, 91 + { 2560, 1920, COMM_CHG_MODE_JPEG_2560_1920 }, 92 + { 3264, 1836, COMM_CHG_MODE_JPEG_3264_1836 }, 93 + { 3264, 2176, COMM_CHG_MODE_JPEG_3264_2176 }, 94 + { 3264, 2448, COMM_CHG_MODE_JPEG_3264_2448 }, 95 + }; 96 + 97 + static const struct s5c73m3_frame_size * const s5c73m3_resolutions[] = { 98 + [RES_ISP] = s5c73m3_isp_resolutions, 99 + [RES_JPEG] = s5c73m3_jpeg_resolutions 100 + }; 101 + 102 + static const int s5c73m3_resolutions_len[] = { 103 + [RES_ISP] = ARRAY_SIZE(s5c73m3_isp_resolutions), 104 + [RES_JPEG] = ARRAY_SIZE(s5c73m3_jpeg_resolutions) 105 + }; 106 + 107 + static const struct s5c73m3_interval s5c73m3_intervals[] = { 108 + { COMM_FRAME_RATE_FIXED_7FPS, {142857, 1000000}, {3264, 2448} }, 109 + { COMM_FRAME_RATE_FIXED_15FPS, {66667, 1000000}, {3264, 2448} }, 110 + { COMM_FRAME_RATE_FIXED_20FPS, {50000, 1000000}, {2304, 1296} }, 111 + { COMM_FRAME_RATE_FIXED_30FPS, {33333, 1000000}, {2304, 1296} }, 112 + }; 113 + 114 + #define S5C73M3_DEFAULT_FRAME_INTERVAL 3 /* 30 fps */ 115 + 116 + static void s5c73m3_fill_mbus_fmt(struct v4l2_mbus_framefmt *mf, 117 + const struct s5c73m3_frame_size *fs, 118 + u32 code) 119 + { 120 + mf->width = fs->width; 121 + mf->height = fs->height; 122 + mf->code = code; 123 + mf->colorspace = V4L2_COLORSPACE_JPEG; 124 + mf->field = V4L2_FIELD_NONE; 125 + } 126 + 127 + static int s5c73m3_i2c_write(struct i2c_client *client, u16 addr, u16 data) 128 + { 129 + u8 buf[4] = { addr >> 8, addr & 0xff, data >> 8, data & 0xff }; 130 + 131 + int ret = i2c_master_send(client, buf, sizeof(buf)); 132 + 133 + v4l_dbg(4, s5c73m3_dbg, client, "%s: addr 0x%04x, data 0x%04x\n", 134 + __func__, addr, data); 135 + 136 + if (ret == 4) 137 + return 0; 138 + 139 + return ret < 0 ? ret : -EREMOTEIO; 140 + } 141 + 142 + static int s5c73m3_i2c_read(struct i2c_client *client, u16 addr, u16 *data) 143 + { 144 + int ret; 145 + u8 rbuf[2], wbuf[2] = { addr >> 8, addr & 0xff }; 146 + struct i2c_msg msg[2] = { 147 + { 148 + .addr = client->addr, 149 + .flags = 0, 150 + .len = sizeof(wbuf), 151 + .buf = wbuf 152 + }, { 153 + .addr = client->addr, 154 + .flags = I2C_M_RD, 155 + .len = sizeof(rbuf), 156 + .buf = rbuf 157 + } 158 + }; 159 + /* 160 + * Issue repeated START after writing 2 address bytes and 161 + * just one STOP only after reading the data bytes. 162 + */ 163 + ret = i2c_transfer(client->adapter, msg, 2); 164 + if (ret == 2) { 165 + *data = be16_to_cpup((u16 *)rbuf); 166 + v4l2_dbg(4, s5c73m3_dbg, client, 167 + "%s: addr: 0x%04x, data: 0x%04x\n", 168 + __func__, addr, *data); 169 + return 0; 170 + } 171 + 172 + v4l2_err(client, "I2C read failed: addr: %04x, (%d)\n", addr, ret); 173 + 174 + return ret >= 0 ? -EREMOTEIO : ret; 175 + } 176 + 177 + int s5c73m3_write(struct s5c73m3 *state, u32 addr, u16 data) 178 + { 179 + struct i2c_client *client = state->i2c_client; 180 + int ret; 181 + 182 + if ((addr ^ state->i2c_write_address) & 0xffff0000) { 183 + ret = s5c73m3_i2c_write(client, REG_CMDWR_ADDRH, addr >> 16); 184 + if (ret < 0) { 185 + state->i2c_write_address = 0; 186 + return ret; 187 + } 188 + } 189 + 190 + if ((addr ^ state->i2c_write_address) & 0xffff) { 191 + ret = s5c73m3_i2c_write(client, REG_CMDWR_ADDRL, addr & 0xffff); 192 + if (ret < 0) { 193 + state->i2c_write_address = 0; 194 + return ret; 195 + } 196 + } 197 + 198 + state->i2c_write_address = addr; 199 + 200 + ret = s5c73m3_i2c_write(client, REG_CMDBUF_ADDR, data); 201 + if (ret < 0) 202 + return ret; 203 + 204 + state->i2c_write_address += 2; 205 + 206 + return ret; 207 + } 208 + 209 + int s5c73m3_read(struct s5c73m3 *state, u32 addr, u16 *data) 210 + { 211 + struct i2c_client *client = state->i2c_client; 212 + int ret; 213 + 214 + if ((addr ^ state->i2c_read_address) & 0xffff0000) { 215 + ret = s5c73m3_i2c_write(client, REG_CMDRD_ADDRH, addr >> 16); 216 + if (ret < 0) { 217 + state->i2c_read_address = 0; 218 + return ret; 219 + } 220 + } 221 + 222 + if ((addr ^ state->i2c_read_address) & 0xffff) { 223 + ret = s5c73m3_i2c_write(client, REG_CMDRD_ADDRL, addr & 0xffff); 224 + if (ret < 0) { 225 + state->i2c_read_address = 0; 226 + return ret; 227 + } 228 + } 229 + 230 + state->i2c_read_address = addr; 231 + 232 + ret = s5c73m3_i2c_read(client, REG_CMDBUF_ADDR, data); 233 + if (ret < 0) 234 + return ret; 235 + 236 + state->i2c_read_address += 2; 237 + 238 + return ret; 239 + } 240 + 241 + static int s5c73m3_check_status(struct s5c73m3 *state, unsigned int value) 242 + { 243 + unsigned long start = jiffies; 244 + unsigned long end = start + msecs_to_jiffies(2000); 245 + int ret = 0; 246 + u16 status; 247 + int count = 0; 248 + 249 + while (time_is_after_jiffies(end)) { 250 + ret = s5c73m3_read(state, REG_STATUS, &status); 251 + if (ret < 0 || status == value) 252 + break; 253 + usleep_range(500, 1000); 254 + ++count; 255 + } 256 + 257 + if (count > 0) 258 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, 259 + "status check took %dms\n", 260 + jiffies_to_msecs(jiffies - start)); 261 + 262 + if (ret == 0 && status != value) { 263 + u16 i2c_status = 0; 264 + u16 i2c_seq_status = 0; 265 + 266 + s5c73m3_read(state, REG_I2C_STATUS, &i2c_status); 267 + s5c73m3_read(state, REG_I2C_SEQ_STATUS, &i2c_seq_status); 268 + 269 + v4l2_err(&state->sensor_sd, 270 + "wrong status %#x, expected: %#x, i2c_status: %#x/%#x\n", 271 + status, value, i2c_status, i2c_seq_status); 272 + 273 + return -ETIMEDOUT; 274 + } 275 + 276 + return ret; 277 + } 278 + 279 + int s5c73m3_isp_command(struct s5c73m3 *state, u16 command, u16 data) 280 + { 281 + int ret; 282 + 283 + ret = s5c73m3_check_status(state, REG_STATUS_ISP_COMMAND_COMPLETED); 284 + if (ret < 0) 285 + return ret; 286 + 287 + ret = s5c73m3_write(state, 0x00095000, command); 288 + if (ret < 0) 289 + return ret; 290 + 291 + ret = s5c73m3_write(state, 0x00095002, data); 292 + if (ret < 0) 293 + return ret; 294 + 295 + return s5c73m3_write(state, REG_STATUS, 0x0001); 296 + } 297 + 298 + int s5c73m3_isp_comm_result(struct s5c73m3 *state, u16 command, u16 *data) 299 + { 300 + return s5c73m3_read(state, COMM_RESULT_OFFSET + command, data); 301 + } 302 + 303 + static int s5c73m3_set_af_softlanding(struct s5c73m3 *state) 304 + { 305 + unsigned long start = jiffies; 306 + u16 af_softlanding; 307 + int count = 0; 308 + int ret; 309 + const char *msg; 310 + 311 + ret = s5c73m3_isp_command(state, COMM_AF_SOFTLANDING, 312 + COMM_AF_SOFTLANDING_ON); 313 + if (ret < 0) { 314 + v4l2_info(&state->sensor_sd, "AF soft-landing failed\n"); 315 + return ret; 316 + } 317 + 318 + for (;;) { 319 + ret = s5c73m3_isp_comm_result(state, COMM_AF_SOFTLANDING, 320 + &af_softlanding); 321 + if (ret < 0) { 322 + msg = "failed"; 323 + break; 324 + } 325 + if (af_softlanding == COMM_AF_SOFTLANDING_RES_COMPLETE) { 326 + msg = "succeeded"; 327 + break; 328 + } 329 + if (++count > 100) { 330 + ret = -ETIME; 331 + msg = "timed out"; 332 + break; 333 + } 334 + msleep(25); 335 + } 336 + 337 + v4l2_info(&state->sensor_sd, "AF soft-landing %s after %dms\n", 338 + msg, jiffies_to_msecs(jiffies - start)); 339 + 340 + return ret; 341 + } 342 + 343 + static int s5c73m3_load_fw(struct v4l2_subdev *sd) 344 + { 345 + struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); 346 + struct i2c_client *client = state->i2c_client; 347 + const struct firmware *fw; 348 + int ret; 349 + char fw_name[20]; 350 + 351 + snprintf(fw_name, sizeof(fw_name), "SlimISP_%.2s.bin", 352 + state->fw_file_version); 353 + ret = request_firmware(&fw, fw_name, &client->dev); 354 + if (ret < 0) { 355 + v4l2_err(sd, "Firmware request failed (%s)\n", fw_name); 356 + return -EINVAL; 357 + } 358 + 359 + v4l2_info(sd, "Loading firmware (%s, %d B)\n", fw_name, fw->size); 360 + 361 + ret = s5c73m3_spi_write(state, fw->data, fw->size, 64); 362 + 363 + if (ret >= 0) 364 + state->isp_ready = 1; 365 + else 366 + v4l2_err(sd, "SPI write failed\n"); 367 + 368 + release_firmware(fw); 369 + 370 + return ret; 371 + } 372 + 373 + static int s5c73m3_set_frame_size(struct s5c73m3 *state) 374 + { 375 + const struct s5c73m3_frame_size *prev_size = 376 + state->sensor_pix_size[RES_ISP]; 377 + const struct s5c73m3_frame_size *cap_size = 378 + state->sensor_pix_size[RES_JPEG]; 379 + unsigned int chg_mode; 380 + 381 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, 382 + "Preview size: %dx%d, reg_val: 0x%x\n", 383 + prev_size->width, prev_size->height, prev_size->reg_val); 384 + 385 + chg_mode = prev_size->reg_val | COMM_CHG_MODE_NEW; 386 + 387 + if (state->mbus_code == S5C73M3_JPEG_FMT) { 388 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, 389 + "Capture size: %dx%d, reg_val: 0x%x\n", 390 + cap_size->width, cap_size->height, cap_size->reg_val); 391 + chg_mode |= cap_size->reg_val; 392 + } 393 + 394 + return s5c73m3_isp_command(state, COMM_CHG_MODE, chg_mode); 395 + } 396 + 397 + static int s5c73m3_set_frame_rate(struct s5c73m3 *state) 398 + { 399 + int ret; 400 + 401 + if (state->ctrls.stabilization->val) 402 + return 0; 403 + 404 + if (WARN_ON(state->fiv == NULL)) 405 + return -EINVAL; 406 + 407 + ret = s5c73m3_isp_command(state, COMM_FRAME_RATE, state->fiv->fps_reg); 408 + if (!ret) 409 + state->apply_fiv = 0; 410 + 411 + return ret; 412 + } 413 + 414 + static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd, 415 + int on) 416 + { 417 + u16 mode; 418 + int ret; 419 + 420 + if (on && state->apply_fmt) { 421 + if (state->mbus_code == S5C73M3_JPEG_FMT) 422 + mode = COMM_IMG_OUTPUT_INTERLEAVED; 423 + else 424 + mode = COMM_IMG_OUTPUT_YUV; 425 + 426 + ret = s5c73m3_isp_command(state, COMM_IMG_OUTPUT, mode); 427 + if (!ret) 428 + ret = s5c73m3_set_frame_size(state); 429 + if (ret) 430 + return ret; 431 + state->apply_fmt = 0; 432 + } 433 + 434 + ret = s5c73m3_isp_command(state, COMM_SENSOR_STREAMING, !!on); 435 + if (ret) 436 + return ret; 437 + 438 + state->streaming = !!on; 439 + 440 + if (!on) 441 + return ret; 442 + 443 + if (state->apply_fiv) { 444 + ret = s5c73m3_set_frame_rate(state); 445 + if (ret < 0) 446 + v4l2_err(sd, "Error setting frame rate(%d)\n", ret); 447 + } 448 + 449 + return s5c73m3_check_status(state, REG_STATUS_ISP_COMMAND_COMPLETED); 450 + } 451 + 452 + static int s5c73m3_oif_s_stream(struct v4l2_subdev *sd, int on) 453 + { 454 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 455 + int ret; 456 + 457 + mutex_lock(&state->lock); 458 + ret = __s5c73m3_s_stream(state, sd, on); 459 + mutex_unlock(&state->lock); 460 + 461 + return ret; 462 + } 463 + 464 + static int s5c73m3_system_status_wait(struct s5c73m3 *state, u32 value, 465 + unsigned int delay, unsigned int steps) 466 + { 467 + u16 reg = 0; 468 + 469 + while (steps-- > 0) { 470 + int ret = s5c73m3_read(state, 0x30100010, &reg); 471 + if (ret < 0) 472 + return ret; 473 + if (reg == value) 474 + return 0; 475 + usleep_range(delay, delay + 25); 476 + } 477 + return -ETIMEDOUT; 478 + } 479 + 480 + static int s5c73m3_read_fw_version(struct s5c73m3 *state) 481 + { 482 + struct v4l2_subdev *sd = &state->sensor_sd; 483 + int i, ret; 484 + u16 data[2]; 485 + int offset; 486 + 487 + offset = state->isp_ready ? 0x60 : 0; 488 + 489 + for (i = 0; i < S5C73M3_SENSOR_FW_LEN / 2; i++) { 490 + ret = s5c73m3_read(state, offset + i * 2, data); 491 + if (ret < 0) 492 + return ret; 493 + state->sensor_fw[i * 2] = (char)(*data & 0xff); 494 + state->sensor_fw[i * 2 + 1] = (char)(*data >> 8); 495 + } 496 + state->sensor_fw[S5C73M3_SENSOR_FW_LEN] = '\0'; 497 + 498 + 499 + for (i = 0; i < S5C73M3_SENSOR_TYPE_LEN / 2; i++) { 500 + ret = s5c73m3_read(state, offset + 6 + i * 2, data); 501 + if (ret < 0) 502 + return ret; 503 + state->sensor_type[i * 2] = (char)(*data & 0xff); 504 + state->sensor_type[i * 2 + 1] = (char)(*data >> 8); 505 + } 506 + state->sensor_type[S5C73M3_SENSOR_TYPE_LEN] = '\0'; 507 + 508 + ret = s5c73m3_read(state, offset + 0x14, data); 509 + if (ret >= 0) { 510 + ret = s5c73m3_read(state, offset + 0x16, data + 1); 511 + if (ret >= 0) 512 + state->fw_size = data[0] + (data[1] << 16); 513 + } 514 + 515 + v4l2_info(sd, "Sensor type: %s, FW version: %s\n", 516 + state->sensor_type, state->sensor_fw); 517 + return ret; 518 + } 519 + 520 + static int s5c73m3_fw_update_from(struct s5c73m3 *state) 521 + { 522 + struct v4l2_subdev *sd = &state->sensor_sd; 523 + u16 status = COMM_FW_UPDATE_NOT_READY; 524 + int ret; 525 + int count = 0; 526 + 527 + v4l2_warn(sd, "Updating F-ROM firmware.\n"); 528 + do { 529 + if (status == COMM_FW_UPDATE_NOT_READY) { 530 + ret = s5c73m3_isp_command(state, COMM_FW_UPDATE, 0); 531 + if (ret < 0) 532 + return ret; 533 + } 534 + 535 + ret = s5c73m3_read(state, 0x00095906, &status); 536 + if (ret < 0) 537 + return ret; 538 + switch (status) { 539 + case COMM_FW_UPDATE_FAIL: 540 + v4l2_warn(sd, "Updating F-ROM firmware failed.\n"); 541 + return -EIO; 542 + case COMM_FW_UPDATE_SUCCESS: 543 + v4l2_warn(sd, "Updating F-ROM firmware finished.\n"); 544 + return 0; 545 + } 546 + ++count; 547 + msleep(20); 548 + } while (count < 500); 549 + 550 + v4l2_warn(sd, "Updating F-ROM firmware timed-out.\n"); 551 + return -ETIMEDOUT; 552 + } 553 + 554 + static int s5c73m3_spi_boot(struct s5c73m3 *state, bool load_fw) 555 + { 556 + struct v4l2_subdev *sd = &state->sensor_sd; 557 + int ret; 558 + 559 + /* Run ARM MCU */ 560 + ret = s5c73m3_write(state, 0x30000004, 0xffff); 561 + if (ret < 0) 562 + return ret; 563 + 564 + usleep_range(400, 500); 565 + 566 + /* Check booting status */ 567 + ret = s5c73m3_system_status_wait(state, 0x0c, 100, 3); 568 + if (ret < 0) { 569 + v4l2_err(sd, "booting failed: %d\n", ret); 570 + return ret; 571 + } 572 + 573 + /* P,M,S and Boot Mode */ 574 + ret = s5c73m3_write(state, 0x30100014, 0x2146); 575 + if (ret < 0) 576 + return ret; 577 + 578 + ret = s5c73m3_write(state, 0x30100010, 0x210c); 579 + if (ret < 0) 580 + return ret; 581 + 582 + usleep_range(200, 250); 583 + 584 + /* Check SPI status */ 585 + ret = s5c73m3_system_status_wait(state, 0x210d, 100, 300); 586 + if (ret < 0) 587 + v4l2_err(sd, "SPI not ready: %d\n", ret); 588 + 589 + /* Firmware download over SPI */ 590 + if (load_fw) 591 + s5c73m3_load_fw(sd); 592 + 593 + /* MCU reset */ 594 + ret = s5c73m3_write(state, 0x30000004, 0xfffd); 595 + if (ret < 0) 596 + return ret; 597 + 598 + /* Remap */ 599 + ret = s5c73m3_write(state, 0x301000a4, 0x0183); 600 + if (ret < 0) 601 + return ret; 602 + 603 + /* MCU restart */ 604 + ret = s5c73m3_write(state, 0x30000004, 0xffff); 605 + if (ret < 0 || !load_fw) 606 + return ret; 607 + 608 + ret = s5c73m3_read_fw_version(state); 609 + if (ret < 0) 610 + return ret; 611 + 612 + if (load_fw && update_fw) { 613 + ret = s5c73m3_fw_update_from(state); 614 + update_fw = 0; 615 + } 616 + 617 + return ret; 618 + } 619 + 620 + static int s5c73m3_set_timing_register_for_vdd(struct s5c73m3 *state) 621 + { 622 + static const u32 regs[][2] = { 623 + { 0x30100018, 0x0618 }, 624 + { 0x3010001c, 0x10c1 }, 625 + { 0x30100020, 0x249e } 626 + }; 627 + int ret; 628 + int i; 629 + 630 + for (i = 0; i < ARRAY_SIZE(regs); i++) { 631 + ret = s5c73m3_write(state, regs[i][0], regs[i][1]); 632 + if (ret < 0) 633 + return ret; 634 + } 635 + 636 + return 0; 637 + } 638 + 639 + static void s5c73m3_set_fw_file_version(struct s5c73m3 *state) 640 + { 641 + switch (state->sensor_fw[0]) { 642 + case 'G': 643 + case 'O': 644 + state->fw_file_version[0] = 'G'; 645 + break; 646 + case 'S': 647 + case 'Z': 648 + state->fw_file_version[0] = 'Z'; 649 + break; 650 + } 651 + 652 + switch (state->sensor_fw[1]) { 653 + case 'C'...'F': 654 + state->fw_file_version[1] = state->sensor_fw[1]; 655 + break; 656 + } 657 + } 658 + 659 + static int s5c73m3_get_fw_version(struct s5c73m3 *state) 660 + { 661 + struct v4l2_subdev *sd = &state->sensor_sd; 662 + int ret; 663 + 664 + /* Run ARM MCU */ 665 + ret = s5c73m3_write(state, 0x30000004, 0xffff); 666 + if (ret < 0) 667 + return ret; 668 + usleep_range(400, 500); 669 + 670 + /* Check booting status */ 671 + ret = s5c73m3_system_status_wait(state, 0x0c, 100, 3); 672 + if (ret < 0) { 673 + 674 + v4l2_err(sd, "%s: booting failed: %d\n", __func__, ret); 675 + return ret; 676 + } 677 + 678 + /* Change I/O Driver Current in order to read from F-ROM */ 679 + ret = s5c73m3_write(state, 0x30100120, 0x0820); 680 + ret = s5c73m3_write(state, 0x30100124, 0x0820); 681 + 682 + /* Offset Setting */ 683 + ret = s5c73m3_write(state, 0x00010418, 0x0008); 684 + 685 + /* P,M,S and Boot Mode */ 686 + ret = s5c73m3_write(state, 0x30100014, 0x2146); 687 + if (ret < 0) 688 + return ret; 689 + ret = s5c73m3_write(state, 0x30100010, 0x230c); 690 + if (ret < 0) 691 + return ret; 692 + 693 + usleep_range(200, 250); 694 + 695 + /* Check SPI status */ 696 + ret = s5c73m3_system_status_wait(state, 0x230e, 100, 300); 697 + if (ret < 0) 698 + v4l2_err(sd, "SPI not ready: %d\n", ret); 699 + 700 + /* ARM reset */ 701 + ret = s5c73m3_write(state, 0x30000004, 0xfffd); 702 + if (ret < 0) 703 + return ret; 704 + 705 + /* Remap */ 706 + ret = s5c73m3_write(state, 0x301000a4, 0x0183); 707 + if (ret < 0) 708 + return ret; 709 + 710 + s5c73m3_set_timing_register_for_vdd(state); 711 + 712 + ret = s5c73m3_read_fw_version(state); 713 + 714 + s5c73m3_set_fw_file_version(state); 715 + 716 + return ret; 717 + } 718 + 719 + static int s5c73m3_rom_boot(struct s5c73m3 *state, bool load_fw) 720 + { 721 + static const u32 boot_regs[][2] = { 722 + { 0x3100010c, 0x0044 }, 723 + { 0x31000108, 0x000d }, 724 + { 0x31000304, 0x0001 }, 725 + { 0x00010000, 0x5800 }, 726 + { 0x00010002, 0x0002 }, 727 + { 0x31000000, 0x0001 }, 728 + { 0x30100014, 0x1b85 }, 729 + { 0x30100010, 0x230c } 730 + }; 731 + struct v4l2_subdev *sd = &state->sensor_sd; 732 + int i, ret; 733 + 734 + /* Run ARM MCU */ 735 + ret = s5c73m3_write(state, 0x30000004, 0xffff); 736 + if (ret < 0) 737 + return ret; 738 + usleep_range(400, 450); 739 + 740 + /* Check booting status */ 741 + ret = s5c73m3_system_status_wait(state, 0x0c, 100, 4); 742 + if (ret < 0) { 743 + v4l2_err(sd, "Booting failed: %d\n", ret); 744 + return ret; 745 + } 746 + 747 + for (i = 0; i < ARRAY_SIZE(boot_regs); i++) { 748 + ret = s5c73m3_write(state, boot_regs[i][0], boot_regs[i][1]); 749 + if (ret < 0) 750 + return ret; 751 + } 752 + msleep(200); 753 + 754 + /* Check the binary read status */ 755 + ret = s5c73m3_system_status_wait(state, 0x230e, 1000, 150); 756 + if (ret < 0) { 757 + v4l2_err(sd, "Binary read failed: %d\n", ret); 758 + return ret; 759 + } 760 + 761 + /* ARM reset */ 762 + ret = s5c73m3_write(state, 0x30000004, 0xfffd); 763 + if (ret < 0) 764 + return ret; 765 + /* Remap */ 766 + ret = s5c73m3_write(state, 0x301000a4, 0x0183); 767 + if (ret < 0) 768 + return ret; 769 + /* MCU re-start */ 770 + ret = s5c73m3_write(state, 0x30000004, 0xffff); 771 + if (ret < 0) 772 + return ret; 773 + 774 + state->isp_ready = 1; 775 + 776 + return s5c73m3_read_fw_version(state); 777 + } 778 + 779 + static int s5c73m3_isp_init(struct s5c73m3 *state) 780 + { 781 + int ret; 782 + 783 + state->i2c_read_address = 0; 784 + state->i2c_write_address = 0; 785 + 786 + ret = s5c73m3_i2c_write(state->i2c_client, AHB_MSB_ADDR_PTR, 0x3310); 787 + if (ret < 0) 788 + return ret; 789 + 790 + if (boot_from_rom) 791 + return s5c73m3_rom_boot(state, true); 792 + else 793 + return s5c73m3_spi_boot(state, true); 794 + } 795 + 796 + static const struct s5c73m3_frame_size *s5c73m3_find_frame_size( 797 + struct v4l2_mbus_framefmt *fmt, 798 + enum s5c73m3_resolution_types idx) 799 + { 800 + const struct s5c73m3_frame_size *fs; 801 + const struct s5c73m3_frame_size *best_fs; 802 + int best_dist = INT_MAX; 803 + int i; 804 + 805 + fs = s5c73m3_resolutions[idx]; 806 + best_fs = NULL; 807 + for (i = 0; i < s5c73m3_resolutions_len[idx]; ++i) { 808 + int dist = abs(fs->width - fmt->width) + 809 + abs(fs->height - fmt->height); 810 + if (dist < best_dist) { 811 + best_dist = dist; 812 + best_fs = fs; 813 + } 814 + ++fs; 815 + } 816 + 817 + return best_fs; 818 + } 819 + 820 + static void s5c73m3_oif_try_format(struct s5c73m3 *state, 821 + struct v4l2_subdev_fh *fh, 822 + struct v4l2_subdev_format *fmt, 823 + const struct s5c73m3_frame_size **fs) 824 + { 825 + u32 code; 826 + 827 + switch (fmt->pad) { 828 + case OIF_ISP_PAD: 829 + *fs = s5c73m3_find_frame_size(&fmt->format, RES_ISP); 830 + code = S5C73M3_ISP_FMT; 831 + break; 832 + case OIF_JPEG_PAD: 833 + *fs = s5c73m3_find_frame_size(&fmt->format, RES_JPEG); 834 + code = S5C73M3_JPEG_FMT; 835 + break; 836 + case OIF_SOURCE_PAD: 837 + default: 838 + if (fmt->format.code == S5C73M3_JPEG_FMT) 839 + code = S5C73M3_JPEG_FMT; 840 + else 841 + code = S5C73M3_ISP_FMT; 842 + 843 + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) 844 + *fs = state->oif_pix_size[RES_ISP]; 845 + else 846 + *fs = s5c73m3_find_frame_size( 847 + v4l2_subdev_get_try_format(fh, 848 + OIF_ISP_PAD), 849 + RES_ISP); 850 + break; 851 + } 852 + 853 + s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code); 854 + } 855 + 856 + static void s5c73m3_try_format(struct s5c73m3 *state, 857 + struct v4l2_subdev_fh *fh, 858 + struct v4l2_subdev_format *fmt, 859 + const struct s5c73m3_frame_size **fs) 860 + { 861 + u32 code; 862 + 863 + if (fmt->pad == S5C73M3_ISP_PAD) { 864 + *fs = s5c73m3_find_frame_size(&fmt->format, RES_ISP); 865 + code = S5C73M3_ISP_FMT; 866 + } else { 867 + *fs = s5c73m3_find_frame_size(&fmt->format, RES_JPEG); 868 + code = S5C73M3_JPEG_FMT; 869 + } 870 + 871 + s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code); 872 + } 873 + 874 + static int s5c73m3_oif_g_frame_interval(struct v4l2_subdev *sd, 875 + struct v4l2_subdev_frame_interval *fi) 876 + { 877 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 878 + 879 + if (fi->pad != OIF_SOURCE_PAD) 880 + return -EINVAL; 881 + 882 + mutex_lock(&state->lock); 883 + fi->interval = state->fiv->interval; 884 + mutex_unlock(&state->lock); 885 + 886 + return 0; 887 + } 888 + 889 + static int __s5c73m3_set_frame_interval(struct s5c73m3 *state, 890 + struct v4l2_subdev_frame_interval *fi) 891 + { 892 + const struct s5c73m3_frame_size *prev_size = 893 + state->sensor_pix_size[RES_ISP]; 894 + const struct s5c73m3_interval *fiv = &s5c73m3_intervals[0]; 895 + unsigned int ret, min_err = UINT_MAX; 896 + unsigned int i, fr_time; 897 + 898 + if (fi->interval.denominator == 0) 899 + return -EINVAL; 900 + 901 + fr_time = fi->interval.numerator * 1000 / fi->interval.denominator; 902 + 903 + for (i = 0; i < ARRAY_SIZE(s5c73m3_intervals); i++) { 904 + const struct s5c73m3_interval *iv = &s5c73m3_intervals[i]; 905 + 906 + if (prev_size->width > iv->size.width || 907 + prev_size->height > iv->size.height) 908 + continue; 909 + 910 + ret = abs(iv->interval.numerator / 1000 - fr_time); 911 + if (ret < min_err) { 912 + fiv = iv; 913 + min_err = ret; 914 + } 915 + } 916 + state->fiv = fiv; 917 + 918 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, 919 + "Changed frame interval to %u us\n", fiv->interval.numerator); 920 + return 0; 921 + } 922 + 923 + static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd, 924 + struct v4l2_subdev_frame_interval *fi) 925 + { 926 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 927 + int ret; 928 + 929 + if (fi->pad != OIF_SOURCE_PAD) 930 + return -EINVAL; 931 + 932 + v4l2_dbg(1, s5c73m3_dbg, sd, "Setting %d/%d frame interval\n", 933 + fi->interval.numerator, fi->interval.denominator); 934 + 935 + mutex_lock(&state->lock); 936 + 937 + ret = __s5c73m3_set_frame_interval(state, fi); 938 + if (!ret) { 939 + if (state->streaming) 940 + ret = s5c73m3_set_frame_rate(state); 941 + else 942 + state->apply_fiv = 1; 943 + } 944 + mutex_unlock(&state->lock); 945 + return ret; 946 + } 947 + 948 + static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, 949 + struct v4l2_subdev_fh *fh, 950 + struct v4l2_subdev_frame_interval_enum *fie) 951 + { 952 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 953 + const struct s5c73m3_interval *fi; 954 + int ret = 0; 955 + 956 + if (fie->pad != OIF_SOURCE_PAD) 957 + return -EINVAL; 958 + if (fie->index > ARRAY_SIZE(s5c73m3_intervals)) 959 + return -EINVAL; 960 + 961 + mutex_lock(&state->lock); 962 + fi = &s5c73m3_intervals[fie->index]; 963 + if (fie->width > fi->size.width || fie->height > fi->size.height) 964 + ret = -EINVAL; 965 + else 966 + fie->interval = fi->interval; 967 + mutex_unlock(&state->lock); 968 + 969 + return ret; 970 + } 971 + 972 + static int s5c73m3_oif_get_pad_code(int pad, int index) 973 + { 974 + if (pad == OIF_SOURCE_PAD) { 975 + if (index > 1) 976 + return -EINVAL; 977 + return (index == 0) ? S5C73M3_ISP_FMT : S5C73M3_JPEG_FMT; 978 + } 979 + 980 + if (index > 0) 981 + return -EINVAL; 982 + 983 + return (pad == OIF_ISP_PAD) ? S5C73M3_ISP_FMT : S5C73M3_JPEG_FMT; 984 + } 985 + 986 + static int s5c73m3_get_fmt(struct v4l2_subdev *sd, 987 + struct v4l2_subdev_fh *fh, 988 + struct v4l2_subdev_format *fmt) 989 + { 990 + struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); 991 + const struct s5c73m3_frame_size *fs; 992 + u32 code; 993 + 994 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 995 + fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); 996 + return 0; 997 + } 998 + 999 + mutex_lock(&state->lock); 1000 + 1001 + switch (fmt->pad) { 1002 + case S5C73M3_ISP_PAD: 1003 + code = S5C73M3_ISP_FMT; 1004 + fs = state->sensor_pix_size[RES_ISP]; 1005 + break; 1006 + case S5C73M3_JPEG_PAD: 1007 + code = S5C73M3_JPEG_FMT; 1008 + fs = state->sensor_pix_size[RES_JPEG]; 1009 + break; 1010 + default: 1011 + mutex_unlock(&state->lock); 1012 + return -EINVAL; 1013 + } 1014 + s5c73m3_fill_mbus_fmt(&fmt->format, fs, code); 1015 + 1016 + mutex_unlock(&state->lock); 1017 + return 0; 1018 + } 1019 + 1020 + static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, 1021 + struct v4l2_subdev_fh *fh, 1022 + struct v4l2_subdev_format *fmt) 1023 + { 1024 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1025 + const struct s5c73m3_frame_size *fs; 1026 + u32 code; 1027 + 1028 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 1029 + fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); 1030 + return 0; 1031 + } 1032 + 1033 + mutex_lock(&state->lock); 1034 + 1035 + switch (fmt->pad) { 1036 + case OIF_ISP_PAD: 1037 + code = S5C73M3_ISP_FMT; 1038 + fs = state->oif_pix_size[RES_ISP]; 1039 + break; 1040 + case OIF_JPEG_PAD: 1041 + code = S5C73M3_JPEG_FMT; 1042 + fs = state->oif_pix_size[RES_JPEG]; 1043 + break; 1044 + case OIF_SOURCE_PAD: 1045 + code = state->mbus_code; 1046 + fs = state->oif_pix_size[RES_ISP]; 1047 + break; 1048 + default: 1049 + mutex_unlock(&state->lock); 1050 + return -EINVAL; 1051 + } 1052 + s5c73m3_fill_mbus_fmt(&fmt->format, fs, code); 1053 + 1054 + mutex_unlock(&state->lock); 1055 + return 0; 1056 + } 1057 + 1058 + static int s5c73m3_set_fmt(struct v4l2_subdev *sd, 1059 + struct v4l2_subdev_fh *fh, 1060 + struct v4l2_subdev_format *fmt) 1061 + { 1062 + const struct s5c73m3_frame_size *frame_size = NULL; 1063 + struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); 1064 + struct v4l2_mbus_framefmt *mf; 1065 + int ret = 0; 1066 + 1067 + mutex_lock(&state->lock); 1068 + 1069 + s5c73m3_try_format(state, fh, fmt, &frame_size); 1070 + 1071 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 1072 + mf = v4l2_subdev_get_try_format(fh, fmt->pad); 1073 + *mf = fmt->format; 1074 + } else { 1075 + switch (fmt->pad) { 1076 + case S5C73M3_ISP_PAD: 1077 + state->sensor_pix_size[RES_ISP] = frame_size; 1078 + break; 1079 + case S5C73M3_JPEG_PAD: 1080 + state->sensor_pix_size[RES_JPEG] = frame_size; 1081 + break; 1082 + default: 1083 + ret = -EBUSY; 1084 + } 1085 + 1086 + if (state->streaming) 1087 + ret = -EBUSY; 1088 + else 1089 + state->apply_fmt = 1; 1090 + } 1091 + 1092 + mutex_unlock(&state->lock); 1093 + 1094 + return ret; 1095 + } 1096 + 1097 + static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, 1098 + struct v4l2_subdev_fh *fh, 1099 + struct v4l2_subdev_format *fmt) 1100 + { 1101 + const struct s5c73m3_frame_size *frame_size = NULL; 1102 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1103 + struct v4l2_mbus_framefmt *mf; 1104 + int ret = 0; 1105 + 1106 + mutex_lock(&state->lock); 1107 + 1108 + s5c73m3_oif_try_format(state, fh, fmt, &frame_size); 1109 + 1110 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 1111 + mf = v4l2_subdev_get_try_format(fh, fmt->pad); 1112 + *mf = fmt->format; 1113 + } else { 1114 + switch (fmt->pad) { 1115 + case OIF_ISP_PAD: 1116 + state->oif_pix_size[RES_ISP] = frame_size; 1117 + break; 1118 + case OIF_JPEG_PAD: 1119 + state->oif_pix_size[RES_JPEG] = frame_size; 1120 + break; 1121 + case OIF_SOURCE_PAD: 1122 + state->mbus_code = fmt->format.code; 1123 + break; 1124 + default: 1125 + ret = -EBUSY; 1126 + } 1127 + 1128 + if (state->streaming) 1129 + ret = -EBUSY; 1130 + else 1131 + state->apply_fmt = 1; 1132 + } 1133 + 1134 + mutex_unlock(&state->lock); 1135 + 1136 + return ret; 1137 + } 1138 + 1139 + static int s5c73m3_oif_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, 1140 + struct v4l2_mbus_frame_desc *fd) 1141 + { 1142 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1143 + int i; 1144 + 1145 + if (pad != OIF_SOURCE_PAD || fd == NULL) 1146 + return -EINVAL; 1147 + 1148 + mutex_lock(&state->lock); 1149 + fd->num_entries = 2; 1150 + for (i = 0; i < fd->num_entries; i++) 1151 + fd->entry[i] = state->frame_desc.entry[i]; 1152 + mutex_unlock(&state->lock); 1153 + 1154 + return 0; 1155 + } 1156 + 1157 + static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, 1158 + struct v4l2_mbus_frame_desc *fd) 1159 + { 1160 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1161 + struct v4l2_mbus_frame_desc *frame_desc = &state->frame_desc; 1162 + int i; 1163 + 1164 + if (pad != OIF_SOURCE_PAD || fd == NULL) 1165 + return -EINVAL; 1166 + 1167 + fd->entry[0].length = 10 * SZ_1M; 1168 + fd->entry[1].length = max_t(u32, fd->entry[1].length, 1169 + S5C73M3_EMBEDDED_DATA_MAXLEN); 1170 + fd->num_entries = 2; 1171 + 1172 + mutex_lock(&state->lock); 1173 + for (i = 0; i < fd->num_entries; i++) 1174 + frame_desc->entry[i] = fd->entry[i]; 1175 + mutex_unlock(&state->lock); 1176 + 1177 + return 0; 1178 + } 1179 + 1180 + static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, 1181 + struct v4l2_subdev_fh *fh, 1182 + struct v4l2_subdev_mbus_code_enum *code) 1183 + { 1184 + static const int codes[] = { 1185 + [S5C73M3_ISP_PAD] = S5C73M3_ISP_FMT, 1186 + [S5C73M3_JPEG_PAD] = S5C73M3_JPEG_FMT}; 1187 + 1188 + if (code->index > 0 || code->pad >= S5C73M3_NUM_PADS) 1189 + return -EINVAL; 1190 + 1191 + code->code = codes[code->pad]; 1192 + 1193 + return 0; 1194 + } 1195 + 1196 + static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, 1197 + struct v4l2_subdev_fh *fh, 1198 + struct v4l2_subdev_mbus_code_enum *code) 1199 + { 1200 + int ret; 1201 + 1202 + ret = s5c73m3_oif_get_pad_code(code->pad, code->index); 1203 + if (ret < 0) 1204 + return ret; 1205 + 1206 + code->code = ret; 1207 + 1208 + return 0; 1209 + } 1210 + 1211 + static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, 1212 + struct v4l2_subdev_fh *fh, 1213 + struct v4l2_subdev_frame_size_enum *fse) 1214 + { 1215 + int idx; 1216 + 1217 + if (fse->pad == S5C73M3_ISP_PAD) { 1218 + if (fse->code != S5C73M3_ISP_FMT) 1219 + return -EINVAL; 1220 + idx = RES_ISP; 1221 + } else{ 1222 + if (fse->code != S5C73M3_JPEG_FMT) 1223 + return -EINVAL; 1224 + idx = RES_JPEG; 1225 + } 1226 + 1227 + if (fse->index >= s5c73m3_resolutions_len[idx]) 1228 + return -EINVAL; 1229 + 1230 + fse->min_width = s5c73m3_resolutions[idx][fse->index].width; 1231 + fse->max_width = fse->min_width; 1232 + fse->max_height = s5c73m3_resolutions[idx][fse->index].height; 1233 + fse->min_height = fse->max_height; 1234 + 1235 + return 0; 1236 + } 1237 + 1238 + static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, 1239 + struct v4l2_subdev_fh *fh, 1240 + struct v4l2_subdev_frame_size_enum *fse) 1241 + { 1242 + int idx; 1243 + 1244 + if (fse->pad == OIF_SOURCE_PAD) { 1245 + if (fse->index > 0) 1246 + return -EINVAL; 1247 + 1248 + switch (fse->code) { 1249 + case S5C73M3_JPEG_FMT: 1250 + case S5C73M3_ISP_FMT: { 1251 + struct v4l2_mbus_framefmt *mf = 1252 + v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); 1253 + 1254 + fse->max_width = fse->min_width = mf->width; 1255 + fse->max_height = fse->min_height = mf->height; 1256 + return 0; 1257 + } 1258 + default: 1259 + return -EINVAL; 1260 + } 1261 + } 1262 + 1263 + if (fse->code != s5c73m3_oif_get_pad_code(fse->pad, 0)) 1264 + return -EINVAL; 1265 + 1266 + if (fse->pad == OIF_JPEG_PAD) 1267 + idx = RES_JPEG; 1268 + else 1269 + idx = RES_ISP; 1270 + 1271 + if (fse->index >= s5c73m3_resolutions_len[idx]) 1272 + return -EINVAL; 1273 + 1274 + fse->min_width = s5c73m3_resolutions[idx][fse->index].width; 1275 + fse->max_width = fse->min_width; 1276 + fse->max_height = s5c73m3_resolutions[idx][fse->index].height; 1277 + fse->min_height = fse->max_height; 1278 + 1279 + return 0; 1280 + } 1281 + 1282 + static int s5c73m3_oif_log_status(struct v4l2_subdev *sd) 1283 + { 1284 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1285 + 1286 + v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); 1287 + 1288 + v4l2_info(sd, "power: %d, apply_fmt: %d\n", state->power, 1289 + state->apply_fmt); 1290 + 1291 + return 0; 1292 + } 1293 + 1294 + static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 1295 + { 1296 + struct v4l2_mbus_framefmt *mf; 1297 + 1298 + mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD); 1299 + s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], 1300 + S5C73M3_ISP_FMT); 1301 + 1302 + mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD); 1303 + s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], 1304 + S5C73M3_JPEG_FMT); 1305 + 1306 + return 0; 1307 + } 1308 + 1309 + static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 1310 + { 1311 + struct v4l2_mbus_framefmt *mf; 1312 + 1313 + mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); 1314 + s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], 1315 + S5C73M3_ISP_FMT); 1316 + 1317 + mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD); 1318 + s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], 1319 + S5C73M3_JPEG_FMT); 1320 + 1321 + mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); 1322 + s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], 1323 + S5C73M3_ISP_FMT); 1324 + return 0; 1325 + } 1326 + 1327 + static int s5c73m3_gpio_set_value(struct s5c73m3 *priv, int id, u32 val) 1328 + { 1329 + if (!gpio_is_valid(priv->gpio[id].gpio)) 1330 + return 0; 1331 + gpio_set_value(priv->gpio[id].gpio, !!val); 1332 + return 1; 1333 + } 1334 + 1335 + static int s5c73m3_gpio_assert(struct s5c73m3 *priv, int id) 1336 + { 1337 + return s5c73m3_gpio_set_value(priv, id, priv->gpio[id].level); 1338 + } 1339 + 1340 + static int s5c73m3_gpio_deassert(struct s5c73m3 *priv, int id) 1341 + { 1342 + return s5c73m3_gpio_set_value(priv, id, !priv->gpio[id].level); 1343 + } 1344 + 1345 + static int __s5c73m3_power_on(struct s5c73m3 *state) 1346 + { 1347 + int i, ret; 1348 + 1349 + for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) { 1350 + ret = regulator_enable(state->supplies[i].consumer); 1351 + if (ret) 1352 + goto err; 1353 + } 1354 + 1355 + s5c73m3_gpio_deassert(state, STBY); 1356 + usleep_range(100, 200); 1357 + 1358 + s5c73m3_gpio_deassert(state, RST); 1359 + usleep_range(50, 100); 1360 + 1361 + return 0; 1362 + err: 1363 + for (--i; i >= 0; i--) 1364 + regulator_disable(state->supplies[i].consumer); 1365 + return ret; 1366 + } 1367 + 1368 + static int __s5c73m3_power_off(struct s5c73m3 *state) 1369 + { 1370 + int i, ret; 1371 + 1372 + if (s5c73m3_gpio_assert(state, RST)) 1373 + usleep_range(10, 50); 1374 + 1375 + if (s5c73m3_gpio_assert(state, STBY)) 1376 + usleep_range(100, 200); 1377 + state->streaming = 0; 1378 + state->isp_ready = 0; 1379 + 1380 + for (i = S5C73M3_MAX_SUPPLIES - 1; i >= 0; i--) { 1381 + ret = regulator_disable(state->supplies[i].consumer); 1382 + if (ret) 1383 + goto err; 1384 + } 1385 + return 0; 1386 + err: 1387 + for (++i; i < S5C73M3_MAX_SUPPLIES; i++) 1388 + regulator_enable(state->supplies[i].consumer); 1389 + 1390 + return ret; 1391 + } 1392 + 1393 + static int s5c73m3_oif_set_power(struct v4l2_subdev *sd, int on) 1394 + { 1395 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1396 + int ret = 0; 1397 + 1398 + mutex_lock(&state->lock); 1399 + 1400 + if (on && !state->power) { 1401 + ret = __s5c73m3_power_on(state); 1402 + if (!ret) 1403 + ret = s5c73m3_isp_init(state); 1404 + if (!ret) { 1405 + state->apply_fiv = 1; 1406 + state->apply_fmt = 1; 1407 + } 1408 + } else if (!on == state->power) { 1409 + ret = s5c73m3_set_af_softlanding(state); 1410 + if (!ret) 1411 + ret = __s5c73m3_power_off(state); 1412 + else 1413 + v4l2_err(sd, "Soft landing lens failed\n"); 1414 + } 1415 + if (!ret) 1416 + state->power += on ? 1 : -1; 1417 + 1418 + v4l2_dbg(1, s5c73m3_dbg, sd, "%s: power: %d\n", 1419 + __func__, state->power); 1420 + 1421 + mutex_unlock(&state->lock); 1422 + return ret; 1423 + } 1424 + 1425 + static int s5c73m3_oif_registered(struct v4l2_subdev *sd) 1426 + { 1427 + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); 1428 + int ret; 1429 + 1430 + ret = v4l2_device_register_subdev(sd->v4l2_dev, &state->sensor_sd); 1431 + if (ret) { 1432 + v4l2_err(sd->v4l2_dev, "Failed to register %s\n", 1433 + state->oif_sd.name); 1434 + return ret; 1435 + } 1436 + 1437 + ret = media_entity_create_link(&state->sensor_sd.entity, 1438 + S5C73M3_ISP_PAD, &state->oif_sd.entity, OIF_ISP_PAD, 1439 + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); 1440 + 1441 + ret = media_entity_create_link(&state->sensor_sd.entity, 1442 + S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD, 1443 + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); 1444 + 1445 + mutex_lock(&state->lock); 1446 + ret = __s5c73m3_power_on(state); 1447 + if (ret == 0) 1448 + s5c73m3_get_fw_version(state); 1449 + 1450 + __s5c73m3_power_off(state); 1451 + mutex_unlock(&state->lock); 1452 + 1453 + v4l2_dbg(1, s5c73m3_dbg, sd, "%s: Booting %s (%d)\n", 1454 + __func__, ret ? "failed" : "succeded", ret); 1455 + 1456 + return ret; 1457 + } 1458 + 1459 + static const struct v4l2_subdev_internal_ops s5c73m3_internal_ops = { 1460 + .open = s5c73m3_open, 1461 + }; 1462 + 1463 + static const struct v4l2_subdev_pad_ops s5c73m3_pad_ops = { 1464 + .enum_mbus_code = s5c73m3_enum_mbus_code, 1465 + .enum_frame_size = s5c73m3_enum_frame_size, 1466 + .get_fmt = s5c73m3_get_fmt, 1467 + .set_fmt = s5c73m3_set_fmt, 1468 + }; 1469 + 1470 + static const struct v4l2_subdev_ops s5c73m3_subdev_ops = { 1471 + .pad = &s5c73m3_pad_ops, 1472 + }; 1473 + 1474 + static const struct v4l2_subdev_internal_ops oif_internal_ops = { 1475 + .registered = s5c73m3_oif_registered, 1476 + .open = s5c73m3_oif_open, 1477 + }; 1478 + 1479 + static const struct v4l2_subdev_pad_ops s5c73m3_oif_pad_ops = { 1480 + .enum_mbus_code = s5c73m3_oif_enum_mbus_code, 1481 + .enum_frame_size = s5c73m3_oif_enum_frame_size, 1482 + .enum_frame_interval = s5c73m3_oif_enum_frame_interval, 1483 + .get_fmt = s5c73m3_oif_get_fmt, 1484 + .set_fmt = s5c73m3_oif_set_fmt, 1485 + .get_frame_desc = s5c73m3_oif_get_frame_desc, 1486 + .set_frame_desc = s5c73m3_oif_set_frame_desc, 1487 + }; 1488 + 1489 + static const struct v4l2_subdev_core_ops s5c73m3_oif_core_ops = { 1490 + .s_power = s5c73m3_oif_set_power, 1491 + .log_status = s5c73m3_oif_log_status, 1492 + }; 1493 + 1494 + static const struct v4l2_subdev_video_ops s5c73m3_oif_video_ops = { 1495 + .s_stream = s5c73m3_oif_s_stream, 1496 + .g_frame_interval = s5c73m3_oif_g_frame_interval, 1497 + .s_frame_interval = s5c73m3_oif_s_frame_interval, 1498 + }; 1499 + 1500 + static const struct v4l2_subdev_ops oif_subdev_ops = { 1501 + .core = &s5c73m3_oif_core_ops, 1502 + .pad = &s5c73m3_oif_pad_ops, 1503 + .video = &s5c73m3_oif_video_ops, 1504 + }; 1505 + 1506 + static int s5c73m3_configure_gpio(int nr, int val, const char *name) 1507 + { 1508 + unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; 1509 + int ret; 1510 + 1511 + if (!gpio_is_valid(nr)) 1512 + return 0; 1513 + ret = gpio_request_one(nr, flags, name); 1514 + if (!ret) 1515 + gpio_export(nr, 0); 1516 + return ret; 1517 + } 1518 + 1519 + static int s5c73m3_free_gpios(struct s5c73m3 *state) 1520 + { 1521 + int i; 1522 + 1523 + for (i = 0; i < ARRAY_SIZE(state->gpio); i++) { 1524 + if (!gpio_is_valid(state->gpio[i].gpio)) 1525 + continue; 1526 + gpio_free(state->gpio[i].gpio); 1527 + state->gpio[i].gpio = -EINVAL; 1528 + } 1529 + return 0; 1530 + } 1531 + 1532 + static int s5c73m3_configure_gpios(struct s5c73m3 *state, 1533 + const struct s5c73m3_platform_data *pdata) 1534 + { 1535 + const struct s5c73m3_gpio *gpio = &pdata->gpio_stby; 1536 + int ret; 1537 + 1538 + state->gpio[STBY].gpio = -EINVAL; 1539 + state->gpio[RST].gpio = -EINVAL; 1540 + 1541 + ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_STBY"); 1542 + if (ret) { 1543 + s5c73m3_free_gpios(state); 1544 + return ret; 1545 + } 1546 + state->gpio[STBY] = *gpio; 1547 + if (gpio_is_valid(gpio->gpio)) 1548 + gpio_set_value(gpio->gpio, 0); 1549 + 1550 + gpio = &pdata->gpio_reset; 1551 + ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_RST"); 1552 + if (ret) { 1553 + s5c73m3_free_gpios(state); 1554 + return ret; 1555 + } 1556 + state->gpio[RST] = *gpio; 1557 + if (gpio_is_valid(gpio->gpio)) 1558 + gpio_set_value(gpio->gpio, 0); 1559 + 1560 + return 0; 1561 + } 1562 + 1563 + static int __devinit s5c73m3_probe(struct i2c_client *client, 1564 + const struct i2c_device_id *id) 1565 + { 1566 + struct device *dev = &client->dev; 1567 + const struct s5c73m3_platform_data *pdata = client->dev.platform_data; 1568 + struct v4l2_subdev *sd; 1569 + struct v4l2_subdev *oif_sd; 1570 + struct s5c73m3 *state; 1571 + int ret, i; 1572 + 1573 + if (pdata == NULL) { 1574 + dev_err(&client->dev, "Platform data not specified\n"); 1575 + return -EINVAL; 1576 + } 1577 + 1578 + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); 1579 + if (!state) 1580 + return -ENOMEM; 1581 + 1582 + mutex_init(&state->lock); 1583 + sd = &state->sensor_sd; 1584 + oif_sd = &state->oif_sd; 1585 + 1586 + v4l2_subdev_init(sd, &s5c73m3_subdev_ops); 1587 + sd->owner = client->driver->driver.owner; 1588 + v4l2_set_subdevdata(sd, state); 1589 + strlcpy(sd->name, "S5C73M3", sizeof(sd->name)); 1590 + 1591 + sd->internal_ops = &s5c73m3_internal_ops; 1592 + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1593 + 1594 + state->sensor_pads[S5C73M3_JPEG_PAD].flags = MEDIA_PAD_FL_SOURCE; 1595 + state->sensor_pads[S5C73M3_ISP_PAD].flags = MEDIA_PAD_FL_SOURCE; 1596 + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; 1597 + 1598 + ret = media_entity_init(&sd->entity, S5C73M3_NUM_PADS, 1599 + state->sensor_pads, 0); 1600 + if (ret < 0) 1601 + return ret; 1602 + 1603 + v4l2_i2c_subdev_init(oif_sd, client, &oif_subdev_ops); 1604 + strcpy(oif_sd->name, "S5C73M3-OIF"); 1605 + 1606 + oif_sd->internal_ops = &oif_internal_ops; 1607 + oif_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1608 + 1609 + state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK; 1610 + state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK; 1611 + state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; 1612 + oif_sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; 1613 + 1614 + ret = media_entity_init(&oif_sd->entity, OIF_NUM_PADS, 1615 + state->oif_pads, 0); 1616 + if (ret < 0) 1617 + return ret; 1618 + 1619 + state->mclk_frequency = pdata->mclk_frequency; 1620 + state->bus_type = pdata->bus_type; 1621 + 1622 + ret = s5c73m3_configure_gpios(state, pdata); 1623 + if (ret) 1624 + goto out_err1; 1625 + 1626 + for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) 1627 + state->supplies[i].supply = s5c73m3_supply_names[i]; 1628 + 1629 + ret = regulator_bulk_get(dev, S5C73M3_MAX_SUPPLIES, 1630 + state->supplies); 1631 + if (ret) { 1632 + dev_err(dev, "failed to get regulators\n"); 1633 + goto out_err2; 1634 + } 1635 + 1636 + ret = s5c73m3_init_controls(state); 1637 + if (ret) 1638 + goto out_err3; 1639 + 1640 + state->sensor_pix_size[RES_ISP] = &s5c73m3_isp_resolutions[1]; 1641 + state->sensor_pix_size[RES_JPEG] = &s5c73m3_jpeg_resolutions[1]; 1642 + state->oif_pix_size[RES_ISP] = state->sensor_pix_size[RES_ISP]; 1643 + state->oif_pix_size[RES_JPEG] = state->sensor_pix_size[RES_JPEG]; 1644 + 1645 + state->mbus_code = S5C73M3_ISP_FMT; 1646 + 1647 + state->fiv = &s5c73m3_intervals[S5C73M3_DEFAULT_FRAME_INTERVAL]; 1648 + 1649 + state->fw_file_version[0] = 'G'; 1650 + state->fw_file_version[1] = 'C'; 1651 + 1652 + ret = s5c73m3_register_spi_driver(state); 1653 + if (ret < 0) 1654 + goto out_err3; 1655 + 1656 + state->i2c_client = client; 1657 + 1658 + v4l2_info(sd, "%s: completed succesfully\n", __func__); 1659 + return 0; 1660 + 1661 + out_err3: 1662 + regulator_bulk_free(S5C73M3_MAX_SUPPLIES, state->supplies); 1663 + out_err2: 1664 + s5c73m3_free_gpios(state); 1665 + out_err1: 1666 + media_entity_cleanup(&sd->entity); 1667 + return ret; 1668 + } 1669 + 1670 + static int __devexit s5c73m3_remove(struct i2c_client *client) 1671 + { 1672 + struct v4l2_subdev *sd = i2c_get_clientdata(client); 1673 + struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); 1674 + 1675 + v4l2_device_unregister_subdev(sd); 1676 + 1677 + v4l2_ctrl_handler_free(sd->ctrl_handler); 1678 + media_entity_cleanup(&sd->entity); 1679 + 1680 + s5c73m3_unregister_spi_driver(state); 1681 + regulator_bulk_free(S5C73M3_MAX_SUPPLIES, state->supplies); 1682 + s5c73m3_free_gpios(state); 1683 + 1684 + return 0; 1685 + } 1686 + 1687 + static const struct i2c_device_id s5c73m3_id[] = { 1688 + { DRIVER_NAME, 0 }, 1689 + { } 1690 + }; 1691 + MODULE_DEVICE_TABLE(i2c, s5c73m3_id); 1692 + 1693 + static struct i2c_driver s5c73m3_i2c_driver = { 1694 + .driver = { 1695 + .name = DRIVER_NAME, 1696 + }, 1697 + .probe = s5c73m3_probe, 1698 + .remove = __devexit_p(s5c73m3_remove), 1699 + .id_table = s5c73m3_id, 1700 + }; 1701 + 1702 + module_i2c_driver(s5c73m3_i2c_driver); 1703 + 1704 + MODULE_DESCRIPTION("Samsung S5C73M3 camera driver"); 1705 + MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); 1706 + MODULE_LICENSE("GPL");
+563
drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
··· 1 + /* 2 + * Samsung LSI S5C73M3 8M pixel camera driver 3 + * 4 + * Copyright (C) 2012, Samsung Electronics, Co., Ltd. 5 + * Sylwester Nawrocki <s.nawrocki@samsung.com> 6 + * Andrzej Hajda <a.hajda@samsung.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/sizes.h> 19 + #include <linux/delay.h> 20 + #include <linux/firmware.h> 21 + #include <linux/gpio.h> 22 + #include <linux/i2c.h> 23 + #include <linux/init.h> 24 + #include <linux/media.h> 25 + #include <linux/module.h> 26 + #include <linux/regulator/consumer.h> 27 + #include <linux/slab.h> 28 + #include <linux/spi/spi.h> 29 + #include <linux/videodev2.h> 30 + #include <media/media-entity.h> 31 + #include <media/v4l2-ctrls.h> 32 + #include <media/v4l2-device.h> 33 + #include <media/v4l2-subdev.h> 34 + #include <media/v4l2-mediabus.h> 35 + #include <media/s5c73m3.h> 36 + 37 + #include "s5c73m3.h" 38 + 39 + static int s5c73m3_get_af_status(struct s5c73m3 *state, struct v4l2_ctrl *ctrl) 40 + { 41 + u16 reg = REG_AF_STATUS_UNFOCUSED; 42 + 43 + int ret = s5c73m3_read(state, REG_AF_STATUS, &reg); 44 + 45 + switch (reg) { 46 + case REG_CAF_STATUS_FIND_SEARCH_DIR: 47 + case REG_AF_STATUS_FOCUSING: 48 + case REG_CAF_STATUS_FOCUSING: 49 + ctrl->val = V4L2_AUTO_FOCUS_STATUS_BUSY; 50 + break; 51 + case REG_CAF_STATUS_FOCUSED: 52 + case REG_AF_STATUS_FOCUSED: 53 + ctrl->val = V4L2_AUTO_FOCUS_STATUS_REACHED; 54 + break; 55 + default: 56 + v4l2_info(&state->sensor_sd, "Unknown AF status %#x\n", reg); 57 + /* Fall through */ 58 + case REG_CAF_STATUS_UNFOCUSED: 59 + case REG_AF_STATUS_UNFOCUSED: 60 + case REG_AF_STATUS_INVALID: 61 + ctrl->val = V4L2_AUTO_FOCUS_STATUS_FAILED; 62 + break; 63 + } 64 + 65 + return ret; 66 + } 67 + 68 + static int s5c73m3_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 69 + { 70 + struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl); 71 + struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); 72 + int ret; 73 + 74 + if (state->power == 0) 75 + return -EBUSY; 76 + 77 + switch (ctrl->id) { 78 + case V4L2_CID_FOCUS_AUTO: 79 + ret = s5c73m3_get_af_status(state, state->ctrls.af_status); 80 + if (ret) 81 + return ret; 82 + break; 83 + } 84 + 85 + return 0; 86 + } 87 + 88 + static int s5c73m3_set_colorfx(struct s5c73m3 *state, int val) 89 + { 90 + static const unsigned short colorfx[][2] = { 91 + { V4L2_COLORFX_NONE, COMM_IMAGE_EFFECT_NONE }, 92 + { V4L2_COLORFX_BW, COMM_IMAGE_EFFECT_MONO }, 93 + { V4L2_COLORFX_SEPIA, COMM_IMAGE_EFFECT_SEPIA }, 94 + { V4L2_COLORFX_NEGATIVE, COMM_IMAGE_EFFECT_NEGATIVE }, 95 + { V4L2_COLORFX_AQUA, COMM_IMAGE_EFFECT_AQUA }, 96 + }; 97 + int i; 98 + 99 + for (i = 0; i < ARRAY_SIZE(colorfx); i++) { 100 + if (colorfx[i][0] != val) 101 + continue; 102 + 103 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, 104 + "Setting %s color effect\n", 105 + v4l2_ctrl_get_menu(state->ctrls.colorfx->id)[i]); 106 + 107 + return s5c73m3_isp_command(state, COMM_IMAGE_EFFECT, 108 + colorfx[i][1]); 109 + } 110 + return -EINVAL; 111 + } 112 + 113 + /* Set exposure metering/exposure bias */ 114 + static int s5c73m3_set_exposure(struct s5c73m3 *state, int auto_exp) 115 + { 116 + struct v4l2_subdev *sd = &state->sensor_sd; 117 + struct s5c73m3_ctrls *ctrls = &state->ctrls; 118 + int ret = 0; 119 + 120 + if (ctrls->exposure_metering->is_new) { 121 + u16 metering; 122 + 123 + switch (ctrls->exposure_metering->val) { 124 + case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: 125 + metering = COMM_METERING_CENTER; 126 + break; 127 + case V4L2_EXPOSURE_METERING_SPOT: 128 + metering = COMM_METERING_SPOT; 129 + break; 130 + default: 131 + metering = COMM_METERING_AVERAGE; 132 + break; 133 + } 134 + 135 + ret = s5c73m3_isp_command(state, COMM_METERING, metering); 136 + } 137 + 138 + if (!ret && ctrls->exposure_bias->is_new) { 139 + u16 exp_bias = ctrls->exposure_bias->val; 140 + ret = s5c73m3_isp_command(state, COMM_EV, exp_bias); 141 + } 142 + 143 + v4l2_dbg(1, s5c73m3_dbg, sd, 144 + "%s: exposure bias: %#x, metering: %#x (%d)\n", __func__, 145 + ctrls->exposure_bias->val, ctrls->exposure_metering->val, ret); 146 + 147 + return ret; 148 + } 149 + 150 + static int s5c73m3_set_white_balance(struct s5c73m3 *state, int val) 151 + { 152 + static const unsigned short wb[][2] = { 153 + { V4L2_WHITE_BALANCE_INCANDESCENT, COMM_AWB_MODE_INCANDESCENT}, 154 + { V4L2_WHITE_BALANCE_FLUORESCENT, COMM_AWB_MODE_FLUORESCENT1}, 155 + { V4L2_WHITE_BALANCE_FLUORESCENT_H, COMM_AWB_MODE_FLUORESCENT2}, 156 + { V4L2_WHITE_BALANCE_CLOUDY, COMM_AWB_MODE_CLOUDY}, 157 + { V4L2_WHITE_BALANCE_DAYLIGHT, COMM_AWB_MODE_DAYLIGHT}, 158 + { V4L2_WHITE_BALANCE_AUTO, COMM_AWB_MODE_AUTO}, 159 + }; 160 + int i; 161 + 162 + for (i = 0; i < ARRAY_SIZE(wb); i++) { 163 + if (wb[i][0] != val) 164 + continue; 165 + 166 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, 167 + "Setting white balance to: %s\n", 168 + v4l2_ctrl_get_menu(state->ctrls.auto_wb->id)[i]); 169 + 170 + return s5c73m3_isp_command(state, COMM_AWB_MODE, wb[i][1]); 171 + } 172 + 173 + return -EINVAL; 174 + } 175 + 176 + static int s5c73m3_af_run(struct s5c73m3 *state, bool on) 177 + { 178 + struct s5c73m3_ctrls *c = &state->ctrls; 179 + 180 + if (!on) 181 + return s5c73m3_isp_command(state, COMM_AF_CON, 182 + COMM_AF_CON_STOP); 183 + 184 + if (c->focus_auto->val) 185 + return s5c73m3_isp_command(state, COMM_AF_MODE, 186 + COMM_AF_MODE_PREVIEW_CAF_START); 187 + 188 + return s5c73m3_isp_command(state, COMM_AF_CON, COMM_AF_CON_START); 189 + } 190 + 191 + static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl) 192 + { 193 + bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; 194 + bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; 195 + bool af_lock = ctrl->val & V4L2_LOCK_FOCUS; 196 + int ret = 0; 197 + 198 + if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) { 199 + ret = s5c73m3_isp_command(state, COMM_AE_CON, 200 + ae_lock ? COMM_AE_STOP : COMM_AE_START); 201 + if (ret) 202 + return ret; 203 + } 204 + 205 + if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE) 206 + && state->ctrls.auto_wb->val) { 207 + ret = s5c73m3_isp_command(state, COMM_AWB_CON, 208 + awb_lock ? COMM_AWB_STOP : COMM_AWB_START); 209 + if (ret) 210 + return ret; 211 + } 212 + 213 + if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS) 214 + ret = s5c73m3_af_run(state, ~af_lock); 215 + 216 + return ret; 217 + } 218 + 219 + static int s5c73m3_set_auto_focus(struct s5c73m3 *state, int caf) 220 + { 221 + struct s5c73m3_ctrls *c = &state->ctrls; 222 + int ret = 1; 223 + 224 + if (c->af_distance->is_new) { 225 + u16 mode = (c->af_distance->val == V4L2_AUTO_FOCUS_RANGE_MACRO) 226 + ? COMM_AF_MODE_MACRO : COMM_AF_MODE_NORMAL; 227 + ret = s5c73m3_isp_command(state, COMM_AF_MODE, mode); 228 + if (ret != 0) 229 + return ret; 230 + } 231 + 232 + if (!ret || (c->focus_auto->is_new && c->focus_auto->val) || 233 + c->af_start->is_new) 234 + ret = s5c73m3_af_run(state, 1); 235 + else if ((c->focus_auto->is_new && !c->focus_auto->val) || 236 + c->af_stop->is_new) 237 + ret = s5c73m3_af_run(state, 0); 238 + else 239 + ret = 0; 240 + 241 + return ret; 242 + } 243 + 244 + static int s5c73m3_set_contrast(struct s5c73m3 *state, int val) 245 + { 246 + u16 reg = (val < 0) ? -val + 2 : val; 247 + return s5c73m3_isp_command(state, COMM_CONTRAST, reg); 248 + } 249 + 250 + static int s5c73m3_set_saturation(struct s5c73m3 *state, int val) 251 + { 252 + u16 reg = (val < 0) ? -val + 2 : val; 253 + return s5c73m3_isp_command(state, COMM_SATURATION, reg); 254 + } 255 + 256 + static int s5c73m3_set_sharpness(struct s5c73m3 *state, int val) 257 + { 258 + u16 reg = (val < 0) ? -val + 2 : val; 259 + return s5c73m3_isp_command(state, COMM_SHARPNESS, reg); 260 + } 261 + 262 + static int s5c73m3_set_iso(struct s5c73m3 *state, int val) 263 + { 264 + u32 iso; 265 + 266 + if (val == V4L2_ISO_SENSITIVITY_MANUAL) 267 + iso = state->ctrls.iso->val + 1; 268 + else 269 + iso = 0; 270 + 271 + return s5c73m3_isp_command(state, COMM_ISO, iso); 272 + } 273 + 274 + static int s5c73m3_set_stabilization(struct s5c73m3 *state, int val) 275 + { 276 + struct v4l2_subdev *sd = &state->sensor_sd; 277 + 278 + v4l2_dbg(1, s5c73m3_dbg, sd, "Image stabilization: %d\n", val); 279 + 280 + return s5c73m3_isp_command(state, COMM_FRAME_RATE, val ? 281 + COMM_FRAME_RATE_ANTI_SHAKE : COMM_FRAME_RATE_AUTO_SET); 282 + } 283 + 284 + static int s5c73m3_set_jpeg_quality(struct s5c73m3 *state, int quality) 285 + { 286 + int reg; 287 + 288 + if (quality <= 65) 289 + reg = COMM_IMAGE_QUALITY_NORMAL; 290 + else if (quality <= 75) 291 + reg = COMM_IMAGE_QUALITY_FINE; 292 + else 293 + reg = COMM_IMAGE_QUALITY_SUPERFINE; 294 + 295 + return s5c73m3_isp_command(state, COMM_IMAGE_QUALITY, reg); 296 + } 297 + 298 + static int s5c73m3_set_scene_program(struct s5c73m3 *state, int val) 299 + { 300 + static const unsigned short scene_lookup[] = { 301 + COMM_SCENE_MODE_NONE, /* V4L2_SCENE_MODE_NONE */ 302 + COMM_SCENE_MODE_AGAINST_LIGHT,/* V4L2_SCENE_MODE_BACKLIGHT */ 303 + COMM_SCENE_MODE_BEACH, /* V4L2_SCENE_MODE_BEACH_SNOW */ 304 + COMM_SCENE_MODE_CANDLE, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ 305 + COMM_SCENE_MODE_DAWN, /* V4L2_SCENE_MODE_DAWN_DUSK */ 306 + COMM_SCENE_MODE_FALL, /* V4L2_SCENE_MODE_FALL_COLORS */ 307 + COMM_SCENE_MODE_FIRE, /* V4L2_SCENE_MODE_FIREWORKS */ 308 + COMM_SCENE_MODE_LANDSCAPE, /* V4L2_SCENE_MODE_LANDSCAPE */ 309 + COMM_SCENE_MODE_NIGHT, /* V4L2_SCENE_MODE_NIGHT */ 310 + COMM_SCENE_MODE_INDOOR, /* V4L2_SCENE_MODE_PARTY_INDOOR */ 311 + COMM_SCENE_MODE_PORTRAIT, /* V4L2_SCENE_MODE_PORTRAIT */ 312 + COMM_SCENE_MODE_SPORTS, /* V4L2_SCENE_MODE_SPORTS */ 313 + COMM_SCENE_MODE_SUNSET, /* V4L2_SCENE_MODE_SUNSET */ 314 + COMM_SCENE_MODE_TEXT, /* V4L2_SCENE_MODE_TEXT */ 315 + }; 316 + 317 + v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, "Setting %s scene mode\n", 318 + v4l2_ctrl_get_menu(state->ctrls.scene_mode->id)[val]); 319 + 320 + return s5c73m3_isp_command(state, COMM_SCENE_MODE, scene_lookup[val]); 321 + } 322 + 323 + static int s5c73m3_set_power_line_freq(struct s5c73m3 *state, int val) 324 + { 325 + unsigned int pwr_line_freq = COMM_FLICKER_NONE; 326 + 327 + switch (val) { 328 + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: 329 + pwr_line_freq = COMM_FLICKER_NONE; 330 + break; 331 + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: 332 + pwr_line_freq = COMM_FLICKER_AUTO_50HZ; 333 + break; 334 + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: 335 + pwr_line_freq = COMM_FLICKER_AUTO_60HZ; 336 + break; 337 + default: 338 + case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: 339 + pwr_line_freq = COMM_FLICKER_NONE; 340 + } 341 + 342 + return s5c73m3_isp_command(state, COMM_FLICKER_MODE, pwr_line_freq); 343 + } 344 + 345 + static int s5c73m3_s_ctrl(struct v4l2_ctrl *ctrl) 346 + { 347 + struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl); 348 + struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); 349 + int ret = 0; 350 + 351 + v4l2_dbg(1, s5c73m3_dbg, sd, "set_ctrl: %s, value: %d\n", 352 + ctrl->name, ctrl->val); 353 + 354 + mutex_lock(&state->lock); 355 + /* 356 + * If the device is not powered up by the host driver do 357 + * not apply any controls to H/W at this time. Instead 358 + * the controls will be restored right after power-up. 359 + */ 360 + if (state->power == 0) 361 + goto unlock; 362 + 363 + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) { 364 + ret = -EINVAL; 365 + goto unlock; 366 + } 367 + 368 + switch (ctrl->id) { 369 + case V4L2_CID_3A_LOCK: 370 + ret = s5c73m3_3a_lock(state, ctrl); 371 + break; 372 + 373 + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: 374 + ret = s5c73m3_set_white_balance(state, ctrl->val); 375 + break; 376 + 377 + case V4L2_CID_CONTRAST: 378 + ret = s5c73m3_set_contrast(state, ctrl->val); 379 + break; 380 + 381 + case V4L2_CID_COLORFX: 382 + ret = s5c73m3_set_colorfx(state, ctrl->val); 383 + break; 384 + 385 + case V4L2_CID_EXPOSURE_AUTO: 386 + ret = s5c73m3_set_exposure(state, ctrl->val); 387 + break; 388 + 389 + case V4L2_CID_FOCUS_AUTO: 390 + ret = s5c73m3_set_auto_focus(state, ctrl->val); 391 + break; 392 + 393 + case V4L2_CID_IMAGE_STABILIZATION: 394 + ret = s5c73m3_set_stabilization(state, ctrl->val); 395 + break; 396 + 397 + case V4L2_CID_ISO_SENSITIVITY: 398 + ret = s5c73m3_set_iso(state, ctrl->val); 399 + break; 400 + 401 + case V4L2_CID_JPEG_COMPRESSION_QUALITY: 402 + ret = s5c73m3_set_jpeg_quality(state, ctrl->val); 403 + break; 404 + 405 + case V4L2_CID_POWER_LINE_FREQUENCY: 406 + ret = s5c73m3_set_power_line_freq(state, ctrl->val); 407 + break; 408 + 409 + case V4L2_CID_SATURATION: 410 + ret = s5c73m3_set_saturation(state, ctrl->val); 411 + break; 412 + 413 + case V4L2_CID_SCENE_MODE: 414 + ret = s5c73m3_set_scene_program(state, ctrl->val); 415 + break; 416 + 417 + case V4L2_CID_SHARPNESS: 418 + ret = s5c73m3_set_sharpness(state, ctrl->val); 419 + break; 420 + 421 + case V4L2_CID_WIDE_DYNAMIC_RANGE: 422 + ret = s5c73m3_isp_command(state, COMM_WDR, !!ctrl->val); 423 + break; 424 + 425 + case V4L2_CID_ZOOM_ABSOLUTE: 426 + ret = s5c73m3_isp_command(state, COMM_ZOOM_STEP, ctrl->val); 427 + break; 428 + } 429 + unlock: 430 + mutex_unlock(&state->lock); 431 + return ret; 432 + } 433 + 434 + static const struct v4l2_ctrl_ops s5c73m3_ctrl_ops = { 435 + .g_volatile_ctrl = s5c73m3_g_volatile_ctrl, 436 + .s_ctrl = s5c73m3_s_ctrl, 437 + }; 438 + 439 + /* Supported manual ISO values */ 440 + static const s64 iso_qmenu[] = { 441 + /* COMM_ISO: 0x0001...0x0004 */ 442 + 100, 200, 400, 800, 443 + }; 444 + 445 + /* Supported exposure bias values (-2.0EV...+2.0EV) */ 446 + static const s64 ev_bias_qmenu[] = { 447 + /* COMM_EV: 0x0000...0x0008 */ 448 + -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000 449 + }; 450 + 451 + int s5c73m3_init_controls(struct s5c73m3 *state) 452 + { 453 + const struct v4l2_ctrl_ops *ops = &s5c73m3_ctrl_ops; 454 + struct s5c73m3_ctrls *ctrls = &state->ctrls; 455 + struct v4l2_ctrl_handler *hdl = &ctrls->handler; 456 + 457 + int ret = v4l2_ctrl_handler_init(hdl, 22); 458 + if (ret) 459 + return ret; 460 + 461 + /* White balance */ 462 + ctrls->auto_wb = v4l2_ctrl_new_std_menu(hdl, ops, 463 + V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, 464 + 9, ~0x15e, V4L2_WHITE_BALANCE_AUTO); 465 + 466 + /* Exposure (only automatic exposure) */ 467 + ctrls->auto_exposure = v4l2_ctrl_new_std_menu(hdl, ops, 468 + V4L2_CID_EXPOSURE_AUTO, 0, ~0x01, V4L2_EXPOSURE_AUTO); 469 + 470 + ctrls->exposure_bias = v4l2_ctrl_new_int_menu(hdl, ops, 471 + V4L2_CID_AUTO_EXPOSURE_BIAS, 472 + ARRAY_SIZE(ev_bias_qmenu) - 1, 473 + ARRAY_SIZE(ev_bias_qmenu)/2 - 1, 474 + ev_bias_qmenu); 475 + 476 + ctrls->exposure_metering = v4l2_ctrl_new_std_menu(hdl, ops, 477 + V4L2_CID_EXPOSURE_METERING, 478 + 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE); 479 + 480 + /* Auto focus */ 481 + ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, 482 + V4L2_CID_FOCUS_AUTO, 0, 1, 1, 0); 483 + 484 + ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, 485 + V4L2_CID_AUTO_FOCUS_START, 0, 1, 1, 0); 486 + 487 + ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, 488 + V4L2_CID_AUTO_FOCUS_STOP, 0, 1, 1, 0); 489 + 490 + ctrls->af_status = v4l2_ctrl_new_std(hdl, ops, 491 + V4L2_CID_AUTO_FOCUS_STATUS, 0, 492 + (V4L2_AUTO_FOCUS_STATUS_BUSY | 493 + V4L2_AUTO_FOCUS_STATUS_REACHED | 494 + V4L2_AUTO_FOCUS_STATUS_FAILED), 495 + 0, V4L2_AUTO_FOCUS_STATUS_IDLE); 496 + 497 + ctrls->af_distance = v4l2_ctrl_new_std_menu(hdl, ops, 498 + V4L2_CID_AUTO_FOCUS_RANGE, 499 + V4L2_AUTO_FOCUS_RANGE_MACRO, 500 + ~(1 << V4L2_AUTO_FOCUS_RANGE_NORMAL | 501 + 1 << V4L2_AUTO_FOCUS_RANGE_MACRO), 502 + V4L2_AUTO_FOCUS_RANGE_NORMAL); 503 + /* ISO sensitivity */ 504 + ctrls->auto_iso = v4l2_ctrl_new_std_menu(hdl, ops, 505 + V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0, 506 + V4L2_ISO_SENSITIVITY_AUTO); 507 + 508 + ctrls->iso = v4l2_ctrl_new_int_menu(hdl, ops, 509 + V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, 510 + ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); 511 + 512 + ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, 513 + V4L2_CID_CONTRAST, -2, 2, 1, 0); 514 + 515 + ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, 516 + V4L2_CID_SATURATION, -2, 2, 1, 0); 517 + 518 + ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops, 519 + V4L2_CID_SHARPNESS, -2, 2, 1, 0); 520 + 521 + ctrls->zoom = v4l2_ctrl_new_std(hdl, ops, 522 + V4L2_CID_ZOOM_ABSOLUTE, 0, 30, 1, 0); 523 + 524 + ctrls->colorfx = v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, 525 + V4L2_COLORFX_AQUA, ~0x40f, V4L2_COLORFX_NONE); 526 + 527 + ctrls->wdr = v4l2_ctrl_new_std(hdl, ops, 528 + V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); 529 + 530 + ctrls->stabilization = v4l2_ctrl_new_std(hdl, ops, 531 + V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0); 532 + 533 + v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, 534 + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 535 + V4L2_CID_POWER_LINE_FREQUENCY_AUTO); 536 + 537 + ctrls->jpeg_quality = v4l2_ctrl_new_std(hdl, ops, 538 + V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80); 539 + 540 + ctrls->scene_mode = v4l2_ctrl_new_std_menu(hdl, ops, 541 + V4L2_CID_SCENE_MODE, V4L2_SCENE_MODE_TEXT, ~0x3fff, 542 + V4L2_SCENE_MODE_NONE); 543 + 544 + ctrls->aaa_lock = v4l2_ctrl_new_std(hdl, ops, 545 + V4L2_CID_3A_LOCK, 0, 0x7, 0, 0); 546 + 547 + if (hdl->error) { 548 + ret = hdl->error; 549 + v4l2_ctrl_handler_free(hdl); 550 + return ret; 551 + } 552 + 553 + v4l2_ctrl_auto_cluster(3, &ctrls->auto_exposure, 0, false); 554 + ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE | 555 + V4L2_CTRL_FLAG_UPDATE; 556 + v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false); 557 + ctrls->af_status->flags |= V4L2_CTRL_FLAG_VOLATILE; 558 + v4l2_ctrl_cluster(6, &ctrls->focus_auto); 559 + 560 + state->sensor_sd.ctrl_handler = hdl; 561 + 562 + return 0; 563 + }
+156
drivers/media/i2c/s5c73m3/s5c73m3-spi.c
··· 1 + /* 2 + * Samsung LSI S5C73M3 8M pixel camera driver 3 + * 4 + * Copyright (C) 2012, Samsung Electronics, Co., Ltd. 5 + * Sylwester Nawrocki <s.nawrocki@samsung.com> 6 + * Andrzej Hajda <a.hajda@samsung.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/sizes.h> 19 + #include <linux/delay.h> 20 + #include <linux/init.h> 21 + #include <linux/media.h> 22 + #include <linux/module.h> 23 + #include <linux/slab.h> 24 + #include <linux/spi/spi.h> 25 + 26 + #include "s5c73m3.h" 27 + 28 + #define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI" 29 + 30 + enum spi_direction { 31 + SPI_DIR_RX, 32 + SPI_DIR_TX 33 + }; 34 + 35 + static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len, 36 + enum spi_direction dir) 37 + { 38 + struct spi_message msg; 39 + int r; 40 + struct spi_transfer xfer = { 41 + .len = len, 42 + }; 43 + 44 + if (dir == SPI_DIR_TX) 45 + xfer.tx_buf = addr; 46 + else 47 + xfer.rx_buf = addr; 48 + 49 + if (spi_dev == NULL) { 50 + dev_err(&spi_dev->dev, "SPI device is uninitialized\n"); 51 + return -ENODEV; 52 + } 53 + 54 + spi_message_init(&msg); 55 + spi_message_add_tail(&xfer, &msg); 56 + 57 + r = spi_sync(spi_dev, &msg); 58 + if (r < 0) 59 + dev_err(&spi_dev->dev, "%s spi_sync failed %d\n", __func__, r); 60 + 61 + return r; 62 + } 63 + 64 + int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr, 65 + const unsigned int len, const unsigned int tx_size) 66 + { 67 + struct spi_device *spi_dev = state->spi_dev; 68 + u32 count = len / tx_size; 69 + u32 extra = len % tx_size; 70 + unsigned int i, j = 0; 71 + u8 padding[32]; 72 + int r = 0; 73 + 74 + memset(padding, 0, sizeof(padding)); 75 + 76 + for (i = 0; i < count ; i++) { 77 + r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX); 78 + if (r < 0) 79 + return r; 80 + j += tx_size; 81 + } 82 + 83 + if (extra > 0) { 84 + r = spi_xmit(spi_dev, (void *)addr + j, extra, SPI_DIR_TX); 85 + if (r < 0) 86 + return r; 87 + } 88 + 89 + return spi_xmit(spi_dev, padding, sizeof(padding), SPI_DIR_TX); 90 + } 91 + 92 + int s5c73m3_spi_read(struct s5c73m3 *state, void *addr, 93 + const unsigned int len, const unsigned int tx_size) 94 + { 95 + struct spi_device *spi_dev = state->spi_dev; 96 + u32 count = len / tx_size; 97 + u32 extra = len % tx_size; 98 + unsigned int i, j = 0; 99 + int r = 0; 100 + 101 + for (i = 0; i < count ; i++) { 102 + r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX); 103 + if (r < 0) 104 + return r; 105 + j += tx_size; 106 + } 107 + 108 + if (extra > 0) 109 + return spi_xmit(spi_dev, addr + j, extra, SPI_DIR_RX); 110 + 111 + return 0; 112 + } 113 + 114 + static int __devinit s5c73m3_spi_probe(struct spi_device *spi) 115 + { 116 + int r; 117 + struct s5c73m3 *state = container_of(spi->dev.driver, struct s5c73m3, 118 + spidrv.driver); 119 + spi->bits_per_word = 32; 120 + 121 + r = spi_setup(spi); 122 + if (r < 0) { 123 + dev_err(&spi->dev, "spi_setup() failed\n"); 124 + return r; 125 + } 126 + 127 + mutex_lock(&state->lock); 128 + state->spi_dev = spi; 129 + mutex_unlock(&state->lock); 130 + 131 + v4l2_info(&state->sensor_sd, "S5C73M3 SPI probed successfully\n"); 132 + return 0; 133 + } 134 + 135 + static int __devexit s5c73m3_spi_remove(struct spi_device *spi) 136 + { 137 + return 0; 138 + } 139 + 140 + int s5c73m3_register_spi_driver(struct s5c73m3 *state) 141 + { 142 + struct spi_driver *spidrv = &state->spidrv; 143 + 144 + spidrv->remove = __devexit_p(s5c73m3_spi_remove); 145 + spidrv->probe = s5c73m3_spi_probe; 146 + spidrv->driver.name = S5C73M3_SPI_DRV_NAME; 147 + spidrv->driver.bus = &spi_bus_type; 148 + spidrv->driver.owner = THIS_MODULE; 149 + 150 + return spi_register_driver(spidrv); 151 + } 152 + 153 + void s5c73m3_unregister_spi_driver(struct s5c73m3 *state) 154 + { 155 + spi_unregister_driver(&state->spidrv); 156 + }
+459
drivers/media/i2c/s5c73m3/s5c73m3.h
··· 1 + /* 2 + * Samsung LSI S5C73M3 8M pixel camera driver 3 + * 4 + * Copyright (C) 2012, Samsung Electronics, Co., Ltd. 5 + * Sylwester Nawrocki <s.nawrocki@samsung.com> 6 + * Andrzej Hajda <a.hajda@samsung.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + #ifndef S5C73M3_H_ 18 + #define S5C73M3_H_ 19 + 20 + #include <linux/kernel.h> 21 + #include <linux/regulator/consumer.h> 22 + #include <media/v4l2-common.h> 23 + #include <media/v4l2-ctrls.h> 24 + #include <media/v4l2-subdev.h> 25 + #include <media/s5c73m3.h> 26 + 27 + #define DRIVER_NAME "S5C73M3" 28 + 29 + #define S5C73M3_ISP_FMT V4L2_MBUS_FMT_VYUY8_2X8 30 + #define S5C73M3_JPEG_FMT V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 31 + 32 + /* Subdevs pad index definitions */ 33 + enum s5c73m3_pads { 34 + S5C73M3_ISP_PAD, 35 + S5C73M3_JPEG_PAD, 36 + S5C73M3_NUM_PADS 37 + }; 38 + 39 + enum s5c73m3_oif_pads { 40 + OIF_ISP_PAD, 41 + OIF_JPEG_PAD, 42 + OIF_SOURCE_PAD, 43 + OIF_NUM_PADS 44 + }; 45 + 46 + #define S5C73M3_SENSOR_FW_LEN 6 47 + #define S5C73M3_SENSOR_TYPE_LEN 12 48 + 49 + #define S5C73M3_REG(_addrh, _addrl) (((_addrh) << 16) | _addrl) 50 + 51 + #define AHB_MSB_ADDR_PTR 0xfcfc 52 + #define REG_CMDWR_ADDRH 0x0050 53 + #define REG_CMDWR_ADDRL 0x0054 54 + #define REG_CMDRD_ADDRH 0x0058 55 + #define REG_CMDRD_ADDRL 0x005c 56 + #define REG_CMDBUF_ADDR 0x0f14 57 + 58 + #define REG_I2C_SEQ_STATUS S5C73M3_REG(0x0009, 0x59A6) 59 + #define SEQ_END_PLL (1<<0x0) 60 + #define SEQ_END_SENSOR (1<<0x1) 61 + #define SEQ_END_GPIO (1<<0x2) 62 + #define SEQ_END_FROM (1<<0x3) 63 + #define SEQ_END_STABLE_AE_AWB (1<<0x4) 64 + #define SEQ_END_READY_I2C_CMD (1<<0x5) 65 + 66 + #define REG_I2C_STATUS S5C73M3_REG(0x0009, 0x599E) 67 + #define I2C_STATUS_CIS_I2C (1<<0x0) 68 + #define I2C_STATUS_AF_INIT (1<<0x1) 69 + #define I2C_STATUS_CAL_DATA (1<<0x2) 70 + #define I2C_STATUS_FRAME_COUNT (1<<0x3) 71 + #define I2C_STATUS_FROM_INIT (1<<0x4) 72 + #define I2C_STATUS_I2C_CIS_STREAM_OFF (1<<0x5) 73 + #define I2C_STATUS_I2C_N_CMD_OVER (1<<0x6) 74 + #define I2C_STATUS_I2C_N_CMD_MISMATCH (1<<0x7) 75 + #define I2C_STATUS_CHECK_BIN_CRC (1<<0x8) 76 + #define I2C_STATUS_EXCEPTION (1<<0x9) 77 + #define I2C_STATUS_INIF_INIT_STATE (0x8) 78 + 79 + #define REG_STATUS S5C73M3_REG(0x0009, 0x5080) 80 + #define REG_STATUS_BOOT_SUB_MAIN_ENTER 0xff01 81 + #define REG_STATUS_BOOT_SRAM_TIMING_OK 0xff02 82 + #define REG_STATUS_BOOT_INTERRUPTS_EN 0xff03 83 + #define REG_STATUS_BOOT_R_PLL_DONE 0xff04 84 + #define REG_STATUS_BOOT_R_PLL_LOCKTIME_DONE 0xff05 85 + #define REG_STATUS_BOOT_DELAY_COUNT_DONE 0xff06 86 + #define REG_STATUS_BOOT_I_PLL_DONE 0xff07 87 + #define REG_STATUS_BOOT_I_PLL_LOCKTIME_DONE 0xff08 88 + #define REG_STATUS_BOOT_PLL_INIT_OK 0xff09 89 + #define REG_STATUS_BOOT_SENSOR_INIT_OK 0xff0a 90 + #define REG_STATUS_BOOT_GPIO_SETTING_OK 0xff0b 91 + #define REG_STATUS_BOOT_READ_CAL_DATA_OK 0xff0c 92 + #define REG_STATUS_BOOT_STABLE_AE_AWB_OK 0xff0d 93 + #define REG_STATUS_ISP_COMMAND_COMPLETED 0xffff 94 + #define REG_STATUS_EXCEPTION_OCCURED 0xdead 95 + 96 + #define COMM_RESULT_OFFSET S5C73M3_REG(0x0009, 0x5000) 97 + 98 + #define COMM_IMG_OUTPUT 0x0902 99 + #define COMM_IMG_OUTPUT_HDR 0x0008 100 + #define COMM_IMG_OUTPUT_YUV 0x0009 101 + #define COMM_IMG_OUTPUT_INTERLEAVED 0x000d 102 + 103 + #define COMM_STILL_PRE_FLASH 0x0a00 104 + #define COMM_STILL_PRE_FLASH_FIRE 0x0000 105 + #define COMM_STILL_PRE_FLASH_NON_FIRED 0x0000 106 + #define COMM_STILL_PRE_FLASH_FIRED 0x0001 107 + 108 + #define COMM_STILL_MAIN_FLASH 0x0a02 109 + #define COMM_STILL_MAIN_FLASH_CANCEL 0x0001 110 + #define COMM_STILL_MAIN_FLASH_FIRE 0x0002 111 + 112 + #define COMM_ZOOM_STEP 0x0b00 113 + 114 + #define COMM_IMAGE_EFFECT 0x0b0a 115 + #define COMM_IMAGE_EFFECT_NONE 0x0001 116 + #define COMM_IMAGE_EFFECT_NEGATIVE 0x0002 117 + #define COMM_IMAGE_EFFECT_AQUA 0x0003 118 + #define COMM_IMAGE_EFFECT_SEPIA 0x0004 119 + #define COMM_IMAGE_EFFECT_MONO 0x0005 120 + 121 + #define COMM_IMAGE_QUALITY 0x0b0c 122 + #define COMM_IMAGE_QUALITY_SUPERFINE 0x0000 123 + #define COMM_IMAGE_QUALITY_FINE 0x0001 124 + #define COMM_IMAGE_QUALITY_NORMAL 0x0002 125 + 126 + #define COMM_FLASH_MODE 0x0b0e 127 + #define COMM_FLASH_MODE_OFF 0x0000 128 + #define COMM_FLASH_MODE_ON 0x0001 129 + #define COMM_FLASH_MODE_AUTO 0x0002 130 + 131 + #define COMM_FLASH_STATUS 0x0b80 132 + #define COMM_FLASH_STATUS_OFF 0x0001 133 + #define COMM_FLASH_STATUS_ON 0x0002 134 + #define COMM_FLASH_STATUS_AUTO 0x0003 135 + 136 + #define COMM_FLASH_TORCH 0x0b12 137 + #define COMM_FLASH_TORCH_OFF 0x0000 138 + #define COMM_FLASH_TORCH_ON 0x0001 139 + 140 + #define COMM_AE_NEEDS_FLASH 0x0cba 141 + #define COMM_AE_NEEDS_FLASH_OFF 0x0000 142 + #define COMM_AE_NEEDS_FLASH_ON 0x0001 143 + 144 + #define COMM_CHG_MODE 0x0b10 145 + #define COMM_CHG_MODE_NEW 0x8000 146 + #define COMM_CHG_MODE_SUBSAMPLING_HALF 0x2000 147 + #define COMM_CHG_MODE_SUBSAMPLING_QUARTER 0x4000 148 + 149 + #define COMM_CHG_MODE_YUV_320_240 0x0001 150 + #define COMM_CHG_MODE_YUV_640_480 0x0002 151 + #define COMM_CHG_MODE_YUV_880_720 0x0003 152 + #define COMM_CHG_MODE_YUV_960_720 0x0004 153 + #define COMM_CHG_MODE_YUV_1184_666 0x0005 154 + #define COMM_CHG_MODE_YUV_1280_720 0x0006 155 + #define COMM_CHG_MODE_YUV_1536_864 0x0007 156 + #define COMM_CHG_MODE_YUV_1600_1200 0x0008 157 + #define COMM_CHG_MODE_YUV_1632_1224 0x0009 158 + #define COMM_CHG_MODE_YUV_1920_1080 0x000a 159 + #define COMM_CHG_MODE_YUV_1920_1440 0x000b 160 + #define COMM_CHG_MODE_YUV_2304_1296 0x000c 161 + #define COMM_CHG_MODE_YUV_3264_2448 0x000d 162 + #define COMM_CHG_MODE_YUV_352_288 0x000e 163 + #define COMM_CHG_MODE_YUV_1008_672 0x000f 164 + 165 + #define COMM_CHG_MODE_JPEG_640_480 0x0010 166 + #define COMM_CHG_MODE_JPEG_800_450 0x0020 167 + #define COMM_CHG_MODE_JPEG_800_600 0x0030 168 + #define COMM_CHG_MODE_JPEG_1280_720 0x0040 169 + #define COMM_CHG_MODE_JPEG_1280_960 0x0050 170 + #define COMM_CHG_MODE_JPEG_1600_900 0x0060 171 + #define COMM_CHG_MODE_JPEG_1600_1200 0x0070 172 + #define COMM_CHG_MODE_JPEG_2048_1152 0x0080 173 + #define COMM_CHG_MODE_JPEG_2048_1536 0x0090 174 + #define COMM_CHG_MODE_JPEG_2560_1440 0x00a0 175 + #define COMM_CHG_MODE_JPEG_2560_1920 0x00b0 176 + #define COMM_CHG_MODE_JPEG_3264_2176 0x00c0 177 + #define COMM_CHG_MODE_JPEG_1024_768 0x00d0 178 + #define COMM_CHG_MODE_JPEG_3264_1836 0x00e0 179 + #define COMM_CHG_MODE_JPEG_3264_2448 0x00f0 180 + 181 + #define COMM_AF_CON 0x0e00 182 + #define COMM_AF_CON_STOP 0x0000 183 + #define COMM_AF_CON_SCAN 0x0001 /* Full Search */ 184 + #define COMM_AF_CON_START 0x0002 /* Fast Search */ 185 + 186 + #define COMM_AF_CAL 0x0e06 187 + #define COMM_AF_TOUCH_AF 0x0e0a 188 + 189 + #define REG_AF_STATUS S5C73M3_REG(0x0009, 0x5e80) 190 + #define REG_CAF_STATUS_FIND_SEARCH_DIR 0x0001 191 + #define REG_CAF_STATUS_FOCUSING 0x0002 192 + #define REG_CAF_STATUS_FOCUSED 0x0003 193 + #define REG_CAF_STATUS_UNFOCUSED 0x0004 194 + #define REG_AF_STATUS_INVALID 0x0010 195 + #define REG_AF_STATUS_FOCUSING 0x0020 196 + #define REG_AF_STATUS_FOCUSED 0x0030 197 + #define REG_AF_STATUS_UNFOCUSED 0x0040 198 + 199 + #define REG_AF_TOUCH_POSITION S5C73M3_REG(0x0009, 0x5e8e) 200 + #define COMM_AF_FACE_ZOOM 0x0e10 201 + 202 + #define COMM_AF_MODE 0x0e02 203 + #define COMM_AF_MODE_NORMAL 0x0000 204 + #define COMM_AF_MODE_MACRO 0x0001 205 + #define COMM_AF_MODE_MOVIE_CAF_START 0x0002 206 + #define COMM_AF_MODE_MOVIE_CAF_STOP 0x0003 207 + #define COMM_AF_MODE_PREVIEW_CAF_START 0x0004 208 + #define COMM_AF_MODE_PREVIEW_CAF_STOP 0x0005 209 + 210 + #define COMM_AF_SOFTLANDING 0x0e16 211 + #define COMM_AF_SOFTLANDING_ON 0x0000 212 + #define COMM_AF_SOFTLANDING_RES_COMPLETE 0x0001 213 + 214 + #define COMM_FACE_DET 0x0e0c 215 + #define COMM_FACE_DET_OFF 0x0000 216 + #define COMM_FACE_DET_ON 0x0001 217 + 218 + #define COMM_FACE_DET_OSD 0x0e0e 219 + #define COMM_FACE_DET_OSD_OFF 0x0000 220 + #define COMM_FACE_DET_OSD_ON 0x0001 221 + 222 + #define COMM_AE_CON 0x0c00 223 + #define COMM_AE_STOP 0x0000 /* lock */ 224 + #define COMM_AE_START 0x0001 /* unlock */ 225 + 226 + #define COMM_ISO 0x0c02 227 + #define COMM_ISO_AUTO 0x0000 228 + #define COMM_ISO_100 0x0001 229 + #define COMM_ISO_200 0x0002 230 + #define COMM_ISO_400 0x0003 231 + #define COMM_ISO_800 0x0004 232 + #define COMM_ISO_SPORTS 0x0005 233 + #define COMM_ISO_NIGHT 0x0006 234 + #define COMM_ISO_INDOOR 0x0007 235 + 236 + /* 0x00000 (-2.0 EV)...0x0008 (2.0 EV), 0.5EV step */ 237 + #define COMM_EV 0x0c04 238 + 239 + #define COMM_METERING 0x0c06 240 + #define COMM_METERING_CENTER 0x0000 241 + #define COMM_METERING_SPOT 0x0001 242 + #define COMM_METERING_AVERAGE 0x0002 243 + #define COMM_METERING_SMART 0x0003 244 + 245 + #define COMM_WDR 0x0c08 246 + #define COMM_WDR_OFF 0x0000 247 + #define COMM_WDR_ON 0x0001 248 + 249 + #define COMM_FLICKER_MODE 0x0c12 250 + #define COMM_FLICKER_NONE 0x0000 251 + #define COMM_FLICKER_MANUAL_50HZ 0x0001 252 + #define COMM_FLICKER_MANUAL_60HZ 0x0002 253 + #define COMM_FLICKER_AUTO 0x0003 254 + #define COMM_FLICKER_AUTO_50HZ 0x0004 255 + #define COMM_FLICKER_AUTO_60HZ 0x0005 256 + 257 + #define COMM_FRAME_RATE 0x0c1e 258 + #define COMM_FRAME_RATE_AUTO_SET 0x0000 259 + #define COMM_FRAME_RATE_FIXED_30FPS 0x0002 260 + #define COMM_FRAME_RATE_FIXED_20FPS 0x0003 261 + #define COMM_FRAME_RATE_FIXED_15FPS 0x0004 262 + #define COMM_FRAME_RATE_FIXED_60FPS 0x0007 263 + #define COMM_FRAME_RATE_FIXED_120FPS 0x0008 264 + #define COMM_FRAME_RATE_FIXED_7FPS 0x0009 265 + #define COMM_FRAME_RATE_FIXED_10FPS 0x000a 266 + #define COMM_FRAME_RATE_FIXED_90FPS 0x000b 267 + #define COMM_FRAME_RATE_ANTI_SHAKE 0x0013 268 + 269 + /* 0x0000...0x0004 -> sharpness: 0, 1, 2, -1, -2 */ 270 + #define COMM_SHARPNESS 0x0c14 271 + 272 + /* 0x0000...0x0004 -> saturation: 0, 1, 2, -1, -2 */ 273 + #define COMM_SATURATION 0x0c16 274 + 275 + /* 0x0000...0x0004 -> contrast: 0, 1, 2, -1, -2 */ 276 + #define COMM_CONTRAST 0x0c18 277 + 278 + #define COMM_SCENE_MODE 0x0c1a 279 + #define COMM_SCENE_MODE_NONE 0x0000 280 + #define COMM_SCENE_MODE_PORTRAIT 0x0001 281 + #define COMM_SCENE_MODE_LANDSCAPE 0x0002 282 + #define COMM_SCENE_MODE_SPORTS 0x0003 283 + #define COMM_SCENE_MODE_INDOOR 0x0004 284 + #define COMM_SCENE_MODE_BEACH 0x0005 285 + #define COMM_SCENE_MODE_SUNSET 0x0006 286 + #define COMM_SCENE_MODE_DAWN 0x0007 287 + #define COMM_SCENE_MODE_FALL 0x0008 288 + #define COMM_SCENE_MODE_NIGHT 0x0009 289 + #define COMM_SCENE_MODE_AGAINST_LIGHT 0x000a 290 + #define COMM_SCENE_MODE_FIRE 0x000b 291 + #define COMM_SCENE_MODE_TEXT 0x000c 292 + #define COMM_SCENE_MODE_CANDLE 0x000d 293 + 294 + #define COMM_AE_AUTO_BRACKET 0x0b14 295 + #define COMM_AE_AUTO_BRAKET_EV05 0x0080 296 + #define COMM_AE_AUTO_BRAKET_EV10 0x0100 297 + #define COMM_AE_AUTO_BRAKET_EV15 0x0180 298 + #define COMM_AE_AUTO_BRAKET_EV20 0x0200 299 + 300 + #define COMM_SENSOR_STREAMING 0x090a 301 + #define COMM_SENSOR_STREAMING_OFF 0x0000 302 + #define COMM_SENSOR_STREAMING_ON 0x0001 303 + 304 + #define COMM_AWB_MODE 0x0d02 305 + #define COMM_AWB_MODE_INCANDESCENT 0x0000 306 + #define COMM_AWB_MODE_FLUORESCENT1 0x0001 307 + #define COMM_AWB_MODE_FLUORESCENT2 0x0002 308 + #define COMM_AWB_MODE_DAYLIGHT 0x0003 309 + #define COMM_AWB_MODE_CLOUDY 0x0004 310 + #define COMM_AWB_MODE_AUTO 0x0005 311 + 312 + #define COMM_AWB_CON 0x0d00 313 + #define COMM_AWB_STOP 0x0000 /* lock */ 314 + #define COMM_AWB_START 0x0001 /* unlock */ 315 + 316 + #define COMM_FW_UPDATE 0x0906 317 + #define COMM_FW_UPDATE_NOT_READY 0x0000 318 + #define COMM_FW_UPDATE_SUCCESS 0x0005 319 + #define COMM_FW_UPDATE_FAIL 0x0007 320 + #define COMM_FW_UPDATE_BUSY 0xffff 321 + 322 + 323 + #define S5C73M3_MAX_SUPPLIES 6 324 + 325 + struct s5c73m3_ctrls { 326 + struct v4l2_ctrl_handler handler; 327 + struct { 328 + /* exposure/exposure bias cluster */ 329 + struct v4l2_ctrl *auto_exposure; 330 + struct v4l2_ctrl *exposure_bias; 331 + struct v4l2_ctrl *exposure_metering; 332 + }; 333 + struct { 334 + /* iso/auto iso cluster */ 335 + struct v4l2_ctrl *auto_iso; 336 + struct v4l2_ctrl *iso; 337 + }; 338 + struct v4l2_ctrl *auto_wb; 339 + struct { 340 + /* continuous auto focus/auto focus cluster */ 341 + struct v4l2_ctrl *focus_auto; 342 + struct v4l2_ctrl *af_start; 343 + struct v4l2_ctrl *af_stop; 344 + struct v4l2_ctrl *af_status; 345 + struct v4l2_ctrl *af_distance; 346 + }; 347 + 348 + struct v4l2_ctrl *aaa_lock; 349 + struct v4l2_ctrl *colorfx; 350 + struct v4l2_ctrl *contrast; 351 + struct v4l2_ctrl *saturation; 352 + struct v4l2_ctrl *sharpness; 353 + struct v4l2_ctrl *zoom; 354 + struct v4l2_ctrl *wdr; 355 + struct v4l2_ctrl *stabilization; 356 + struct v4l2_ctrl *jpeg_quality; 357 + struct v4l2_ctrl *scene_mode; 358 + }; 359 + 360 + enum s5c73m3_gpio_id { 361 + STBY, 362 + RST, 363 + GPIO_NUM, 364 + }; 365 + 366 + enum s5c73m3_resolution_types { 367 + RES_ISP, 368 + RES_JPEG, 369 + }; 370 + 371 + struct s5c73m3_interval { 372 + u16 fps_reg; 373 + struct v4l2_fract interval; 374 + /* Maximum rectangle for the interval */ 375 + struct v4l2_frmsize_discrete size; 376 + }; 377 + 378 + struct s5c73m3 { 379 + struct v4l2_subdev sensor_sd; 380 + struct media_pad sensor_pads[S5C73M3_NUM_PADS]; 381 + 382 + struct v4l2_subdev oif_sd; 383 + struct media_pad oif_pads[OIF_NUM_PADS]; 384 + 385 + struct spi_driver spidrv; 386 + struct spi_device *spi_dev; 387 + struct i2c_client *i2c_client; 388 + u32 i2c_write_address; 389 + u32 i2c_read_address; 390 + 391 + struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES]; 392 + struct s5c73m3_gpio gpio[GPIO_NUM]; 393 + 394 + /* External master clock frequency */ 395 + u32 mclk_frequency; 396 + /* Video bus type - MIPI-CSI2/paralell */ 397 + enum v4l2_mbus_type bus_type; 398 + 399 + const struct s5c73m3_frame_size *sensor_pix_size[2]; 400 + const struct s5c73m3_frame_size *oif_pix_size[2]; 401 + enum v4l2_mbus_pixelcode mbus_code; 402 + 403 + const struct s5c73m3_interval *fiv; 404 + 405 + struct v4l2_mbus_frame_desc frame_desc; 406 + /* protects the struct members below */ 407 + struct mutex lock; 408 + 409 + struct s5c73m3_ctrls ctrls; 410 + 411 + u8 streaming:1; 412 + u8 apply_fmt:1; 413 + u8 apply_fiv:1; 414 + u8 isp_ready:1; 415 + 416 + short power; 417 + 418 + char sensor_fw[S5C73M3_SENSOR_FW_LEN + 2]; 419 + char sensor_type[S5C73M3_SENSOR_TYPE_LEN + 2]; 420 + char fw_file_version[2]; 421 + unsigned int fw_size; 422 + }; 423 + 424 + struct s5c73m3_frame_size { 425 + u32 width; 426 + u32 height; 427 + u8 reg_val; 428 + }; 429 + 430 + extern int s5c73m3_dbg; 431 + 432 + int s5c73m3_register_spi_driver(struct s5c73m3 *state); 433 + void s5c73m3_unregister_spi_driver(struct s5c73m3 *state); 434 + int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr, 435 + const unsigned int len, const unsigned int tx_size); 436 + int s5c73m3_spi_read(struct s5c73m3 *state, void *addr, 437 + const unsigned int len, const unsigned int tx_size); 438 + 439 + int s5c73m3_read(struct s5c73m3 *state, u32 addr, u16 *data); 440 + int s5c73m3_write(struct s5c73m3 *state, u32 addr, u16 data); 441 + int s5c73m3_isp_command(struct s5c73m3 *state, u16 command, u16 data); 442 + int s5c73m3_init_controls(struct s5c73m3 *state); 443 + 444 + static inline struct v4l2_subdev *ctrl_to_sensor_sd(struct v4l2_ctrl *ctrl) 445 + { 446 + return &container_of(ctrl->handler, struct s5c73m3, 447 + ctrls.handler)->sensor_sd; 448 + } 449 + 450 + static inline struct s5c73m3 *sensor_sd_to_s5c73m3(struct v4l2_subdev *sd) 451 + { 452 + return container_of(sd, struct s5c73m3, sensor_sd); 453 + } 454 + 455 + static inline struct s5c73m3 *oif_sd_to_s5c73m3(struct v4l2_subdev *sd) 456 + { 457 + return container_of(sd, struct s5c73m3, oif_sd); 458 + } 459 + #endif /* S5C73M3_H_ */
+55
include/media/s5c73m3.h
··· 1 + /* 2 + * Samsung LSI S5C73M3 8M pixel camera driver 3 + * 4 + * Copyright (C) 2012, Samsung Electronics, Co., Ltd. 5 + * Sylwester Nawrocki <s.nawrocki@samsung.com> 6 + * Andrzej Hajda <a.hajda@samsung.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * version 2 as published by the Free Software Foundation. 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License as published by 14 + * the Free Software Foundation; either version 2 of the License, or 15 + * (at your option) any later version. 16 + */ 17 + #ifndef MEDIA_S5C73M3__ 18 + #define MEDIA_S5C73M3__ 19 + 20 + #include <linux/videodev2.h> 21 + #include <media/v4l2-mediabus.h> 22 + 23 + /** 24 + * struct s5c73m3_gpio - data structure describing a GPIO 25 + * @gpio: GPIO number 26 + * @level: indicates active state of the @gpio 27 + */ 28 + struct s5c73m3_gpio { 29 + int gpio; 30 + int level; 31 + }; 32 + 33 + /** 34 + * struct s5c73m3_platform_data - s5c73m3 driver platform data 35 + * @mclk_frequency: sensor's master clock frequency in Hz 36 + * @gpio_reset: GPIO driving RESET pin 37 + * @gpio_stby: GPIO driving STBY pin 38 + * @nlanes: maximum number of MIPI-CSI lanes used 39 + * @horiz_flip: default horizontal image flip value, non zero to enable 40 + * @vert_flip: default vertical image flip value, non zero to enable 41 + */ 42 + 43 + struct s5c73m3_platform_data { 44 + unsigned long mclk_frequency; 45 + 46 + struct s5c73m3_gpio gpio_reset; 47 + struct s5c73m3_gpio gpio_stby; 48 + 49 + enum v4l2_mbus_type bus_type; 50 + u8 nlanes; 51 + u8 horiz_flip; 52 + u8 vert_flip; 53 + }; 54 + 55 + #endif /* MEDIA_S5C73M3__ */