0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/clk.h>
0014 #include <linux/crc32.h>
0015 #include <linux/ctype.h>
0016 #include <linux/delay.h>
0017 #include <linux/firmware.h>
0018 #include <linux/gpio.h>
0019 #include <linux/i2c.h>
0020 #include <linux/module.h>
0021 #include <linux/regulator/consumer.h>
0022 #include <linux/slab.h>
0023 #include <asm/unaligned.h>
0024
0025 #include <media/media-entity.h>
0026 #include <media/i2c/s5k4ecgx.h>
0027 #include <media/v4l2-ctrls.h>
0028 #include <media/v4l2-device.h>
0029 #include <media/v4l2-mediabus.h>
0030 #include <media/v4l2-subdev.h>
0031
0032 static int debug;
0033 module_param(debug, int, 0644);
0034
0035 #define S5K4ECGX_DRIVER_NAME "s5k4ecgx"
0036 #define S5K4ECGX_FIRMWARE "s5k4ecgx.bin"
0037
0038
0039 #define REG_FW_REVISION 0x700001a6
0040 #define REG_FW_VERSION 0x700001a4
0041 #define S5K4ECGX_REVISION_1_1 0x11
0042 #define S5K4ECGX_FW_VERSION 0x4ec0
0043
0044
0045 #define REG_USER_BRIGHTNESS 0x7000022c
0046 #define REG_USER_CONTRAST 0x7000022e
0047 #define REG_USER_SATURATION 0x70000230
0048
0049 #define REG_G_ENABLE_PREV 0x7000023e
0050 #define REG_G_ENABLE_PREV_CHG 0x70000240
0051 #define REG_G_NEW_CFG_SYNC 0x7000024a
0052 #define REG_G_PREV_IN_WIDTH 0x70000250
0053 #define REG_G_PREV_IN_HEIGHT 0x70000252
0054 #define REG_G_PREV_IN_XOFFS 0x70000254
0055 #define REG_G_PREV_IN_YOFFS 0x70000256
0056 #define REG_G_CAP_IN_WIDTH 0x70000258
0057 #define REG_G_CAP_IN_HEIGHT 0x7000025a
0058 #define REG_G_CAP_IN_XOFFS 0x7000025c
0059 #define REG_G_CAP_IN_YOFFS 0x7000025e
0060 #define REG_G_INPUTS_CHANGE_REQ 0x70000262
0061 #define REG_G_ACTIVE_PREV_CFG 0x70000266
0062 #define REG_G_PREV_CFG_CHG 0x70000268
0063 #define REG_G_PREV_OPEN_AFTER_CH 0x7000026a
0064
0065
0066 #define PREG(n, x) ((n) * 0x30 + (x))
0067 #define REG_P_OUT_WIDTH(n) PREG(n, 0x700002a6)
0068 #define REG_P_OUT_HEIGHT(n) PREG(n, 0x700002a8)
0069 #define REG_P_FMT(n) PREG(n, 0x700002aa)
0070 #define REG_P_PVI_MASK(n) PREG(n, 0x700002b4)
0071 #define REG_P_FR_TIME_TYPE(n) PREG(n, 0x700002be)
0072 #define FR_TIME_DYNAMIC 0
0073 #define FR_TIME_FIXED 1
0074 #define FR_TIME_FIXED_ACCURATE 2
0075 #define REG_P_FR_TIME_Q_TYPE(n) PREG(n, 0x700002c0)
0076 #define FR_TIME_Q_DYNAMIC 0
0077 #define FR_TIME_Q_BEST_FRRATE 1
0078 #define FR_TIME_Q_BEST_QUALITY 2
0079
0080
0081 #define REG_P_MAX_FR_TIME(n) PREG(n, 0x700002c2)
0082 #define REG_P_MIN_FR_TIME(n) PREG(n, 0x700002c4)
0083 #define US_TO_FR_TIME(__t) ((__t) / 100)
0084 #define REG_P_PREV_MIRROR(n) PREG(n, 0x700002d0)
0085 #define REG_P_CAP_MIRROR(n) PREG(n, 0x700002d2)
0086
0087 #define REG_G_PREVZOOM_IN_WIDTH 0x70000494
0088 #define REG_G_PREVZOOM_IN_HEIGHT 0x70000496
0089 #define REG_G_PREVZOOM_IN_XOFFS 0x70000498
0090 #define REG_G_PREVZOOM_IN_YOFFS 0x7000049a
0091 #define REG_G_CAPZOOM_IN_WIDTH 0x7000049c
0092 #define REG_G_CAPZOOM_IN_HEIGHT 0x7000049e
0093 #define REG_G_CAPZOOM_IN_XOFFS 0x700004a0
0094 #define REG_G_CAPZOOM_IN_YOFFS 0x700004a2
0095
0096
0097 #define REG_USER_SHARPNESS(n) (0x70000a28 + (n) * 0xb6)
0098
0099
0100 #define SHARPNESS_DIV 8208
0101 #define TOK_TERM 0xffffffff
0102
0103
0104
0105
0106
0107
0108 #define AHB_MSB_ADDR_PTR 0xfcfc
0109 #define GEN_REG_OFFSH 0xd000
0110 #define REG_CMDWR_ADDRH 0x0028
0111 #define REG_CMDWR_ADDRL 0x002a
0112 #define REG_CMDRD_ADDRH 0x002c
0113 #define REG_CMDRD_ADDRL 0x002e
0114 #define REG_CMDBUF0_ADDR 0x0f12
0115
0116 struct s5k4ecgx_frmsize {
0117 struct v4l2_frmsize_discrete size;
0118
0119 struct v4l2_rect input_window;
0120 };
0121
0122 struct regval_list {
0123 u32 addr;
0124 u16 val;
0125 };
0126
0127
0128
0129
0130
0131 static const struct s5k4ecgx_frmsize s5k4ecgx_prev_sizes[] = {
0132 {
0133 .size = { 176, 144 },
0134 .input_window = { 0x00, 0x00, 0x928, 0x780 },
0135 }, {
0136 .size = { 352, 288 },
0137 .input_window = { 0x00, 0x00, 0x928, 0x780 },
0138 }, {
0139 .size = { 640, 480 },
0140 .input_window = { 0x00, 0x00, 0xa00, 0x780 },
0141 }, {
0142 .size = { 720, 480 },
0143 .input_window = { 0x00, 0x00, 0xa00, 0x6a8 },
0144 }
0145 };
0146
0147 #define S5K4ECGX_NUM_PREV ARRAY_SIZE(s5k4ecgx_prev_sizes)
0148
0149 struct s5k4ecgx_pixfmt {
0150 u32 code;
0151 u32 colorspace;
0152
0153 u16 reg_p_format;
0154 };
0155
0156
0157 static const struct s5k4ecgx_pixfmt s5k4ecgx_formats[] = {
0158 { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
0159 };
0160
0161 static const char * const s5k4ecgx_supply_names[] = {
0162
0163
0164
0165
0166 "vdda",
0167 "vddio",
0168 "vddcore",
0169 "vddreg",
0170 };
0171
0172 #define S5K4ECGX_NUM_SUPPLIES ARRAY_SIZE(s5k4ecgx_supply_names)
0173
0174 enum s5k4ecgx_gpio_id {
0175 STBY,
0176 RSET,
0177 GPIO_NUM,
0178 };
0179
0180 struct s5k4ecgx {
0181 struct v4l2_subdev sd;
0182 struct media_pad pad;
0183 struct v4l2_ctrl_handler handler;
0184
0185 struct s5k4ecgx_platform_data *pdata;
0186 const struct s5k4ecgx_pixfmt *curr_pixfmt;
0187 const struct s5k4ecgx_frmsize *curr_frmsize;
0188 struct mutex lock;
0189 u8 streaming;
0190 u8 set_params;
0191
0192 struct regulator_bulk_data supplies[S5K4ECGX_NUM_SUPPLIES];
0193 struct s5k4ecgx_gpio gpio[GPIO_NUM];
0194 };
0195
0196 static inline struct s5k4ecgx *to_s5k4ecgx(struct v4l2_subdev *sd)
0197 {
0198 return container_of(sd, struct s5k4ecgx, sd);
0199 }
0200
0201 static int s5k4ecgx_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
0202 {
0203 u8 wbuf[2] = { addr >> 8, addr & 0xff };
0204 struct i2c_msg msg[2];
0205 u8 rbuf[2];
0206 int ret;
0207
0208 msg[0].addr = client->addr;
0209 msg[0].flags = 0;
0210 msg[0].len = 2;
0211 msg[0].buf = wbuf;
0212
0213 msg[1].addr = client->addr;
0214 msg[1].flags = I2C_M_RD;
0215 msg[1].len = 2;
0216 msg[1].buf = rbuf;
0217
0218 ret = i2c_transfer(client->adapter, msg, 2);
0219 *val = be16_to_cpu(*((__be16 *)rbuf));
0220
0221 v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
0222
0223 return ret == 2 ? 0 : ret;
0224 }
0225
0226 static int s5k4ecgx_i2c_write(struct i2c_client *client, u16 addr, u16 val)
0227 {
0228 u8 buf[4] = { addr >> 8, addr & 0xff, val >> 8, val & 0xff };
0229
0230 int ret = i2c_master_send(client, buf, 4);
0231 v4l2_dbg(4, debug, client, "i2c_write: 0x%04x : 0x%04x\n", addr, val);
0232
0233 return ret == 4 ? 0 : ret;
0234 }
0235
0236 static int s5k4ecgx_write(struct i2c_client *client, u32 addr, u16 val)
0237 {
0238 u16 high = addr >> 16, low = addr & 0xffff;
0239 int ret;
0240
0241 v4l2_dbg(3, debug, client, "write: 0x%08x : 0x%04x\n", addr, val);
0242
0243 ret = s5k4ecgx_i2c_write(client, REG_CMDWR_ADDRH, high);
0244 if (!ret)
0245 ret = s5k4ecgx_i2c_write(client, REG_CMDWR_ADDRL, low);
0246 if (!ret)
0247 ret = s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR, val);
0248
0249 return ret;
0250 }
0251
0252 static int s5k4ecgx_read(struct i2c_client *client, u32 addr, u16 *val)
0253 {
0254 u16 high = addr >> 16, low = addr & 0xffff;
0255 int ret;
0256
0257 ret = s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRH, high);
0258 if (!ret)
0259 ret = s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRL, low);
0260 if (!ret)
0261 ret = s5k4ecgx_i2c_read(client, REG_CMDBUF0_ADDR, val);
0262
0263 return ret;
0264 }
0265
0266 static int s5k4ecgx_read_fw_ver(struct v4l2_subdev *sd)
0267 {
0268 struct i2c_client *client = v4l2_get_subdevdata(sd);
0269 u16 hw_rev, fw_ver = 0;
0270 int ret;
0271
0272 ret = s5k4ecgx_read(client, REG_FW_VERSION, &fw_ver);
0273 if (ret < 0 || fw_ver != S5K4ECGX_FW_VERSION) {
0274 v4l2_err(sd, "FW version check failed!\n");
0275 return -ENODEV;
0276 }
0277
0278 ret = s5k4ecgx_read(client, REG_FW_REVISION, &hw_rev);
0279 if (ret < 0)
0280 return ret;
0281
0282 v4l2_info(sd, "chip found FW ver: 0x%x, HW rev: 0x%x\n",
0283 fw_ver, hw_rev);
0284 return 0;
0285 }
0286
0287 static int s5k4ecgx_set_ahb_address(struct v4l2_subdev *sd)
0288 {
0289 struct i2c_client *client = v4l2_get_subdevdata(sd);
0290 int ret;
0291
0292
0293 ret = s5k4ecgx_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
0294 if (ret < 0)
0295 return ret;
0296
0297
0298
0299
0300
0301 ret = s5k4ecgx_i2c_write(client, 0x0010, 0x0001);
0302 if (ret < 0)
0303 return ret;
0304
0305 ret = s5k4ecgx_i2c_write(client, 0x1030, 0x0000);
0306 if (ret < 0)
0307 return ret;
0308
0309 return s5k4ecgx_i2c_write(client, 0x0014, 0x0001);
0310 }
0311
0312 #define FW_CRC_SIZE 4
0313
0314 #define FW_RECORD_SIZE 6
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324 static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
0325 {
0326 struct i2c_client *client = v4l2_get_subdevdata(sd);
0327 const struct firmware *fw;
0328 const u8 *ptr;
0329 int err, i, regs_num;
0330 u32 addr, crc, crc_file, addr_inc = 0;
0331 u16 val;
0332
0333 err = request_firmware(&fw, S5K4ECGX_FIRMWARE, sd->v4l2_dev->dev);
0334 if (err) {
0335 v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE);
0336 return err;
0337 }
0338 regs_num = get_unaligned_le32(fw->data);
0339
0340 v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n",
0341 S5K4ECGX_FIRMWARE, fw->size, regs_num);
0342
0343 regs_num++;
0344 if (fw->size != regs_num * FW_RECORD_SIZE + FW_CRC_SIZE) {
0345 err = -EINVAL;
0346 goto fw_out;
0347 }
0348 crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE);
0349 crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE);
0350 if (crc != crc_file) {
0351 v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file);
0352 err = -EINVAL;
0353 goto fw_out;
0354 }
0355 ptr = fw->data + FW_RECORD_SIZE;
0356 for (i = 1; i < regs_num; i++) {
0357 addr = get_unaligned_le32(ptr);
0358 ptr += sizeof(u32);
0359 val = get_unaligned_le16(ptr);
0360 ptr += sizeof(u16);
0361 if (addr - addr_inc != 2)
0362 err = s5k4ecgx_write(client, addr, val);
0363 else
0364 err = s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR, val);
0365 if (err)
0366 break;
0367 addr_inc = addr;
0368 }
0369 fw_out:
0370 release_firmware(fw);
0371 return err;
0372 }
0373
0374
0375 static int s5k4ecgx_set_input_window(struct i2c_client *c,
0376 const struct v4l2_rect *r)
0377 {
0378 int ret;
0379
0380 ret = s5k4ecgx_write(c, REG_G_PREV_IN_WIDTH, r->width);
0381 if (!ret)
0382 ret = s5k4ecgx_write(c, REG_G_PREV_IN_HEIGHT, r->height);
0383 if (!ret)
0384 ret = s5k4ecgx_write(c, REG_G_PREV_IN_XOFFS, r->left);
0385 if (!ret)
0386 ret = s5k4ecgx_write(c, REG_G_PREV_IN_YOFFS, r->top);
0387 if (!ret)
0388 ret = s5k4ecgx_write(c, REG_G_CAP_IN_WIDTH, r->width);
0389 if (!ret)
0390 ret = s5k4ecgx_write(c, REG_G_CAP_IN_HEIGHT, r->height);
0391 if (!ret)
0392 ret = s5k4ecgx_write(c, REG_G_CAP_IN_XOFFS, r->left);
0393 if (!ret)
0394 ret = s5k4ecgx_write(c, REG_G_CAP_IN_YOFFS, r->top);
0395
0396 return ret;
0397 }
0398
0399
0400 static int s5k4ecgx_set_zoom_window(struct i2c_client *c,
0401 const struct v4l2_rect *r)
0402 {
0403 int ret;
0404
0405 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width);
0406 if (!ret)
0407 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height);
0408 if (!ret)
0409 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left);
0410 if (!ret)
0411 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top);
0412 if (!ret)
0413 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_WIDTH, r->width);
0414 if (!ret)
0415 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_HEIGHT, r->height);
0416 if (!ret)
0417 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_XOFFS, r->left);
0418 if (!ret)
0419 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_YOFFS, r->top);
0420
0421 return ret;
0422 }
0423
0424 static int s5k4ecgx_set_output_framefmt(struct s5k4ecgx *priv)
0425 {
0426 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
0427 int ret;
0428
0429 ret = s5k4ecgx_write(client, REG_P_OUT_WIDTH(0),
0430 priv->curr_frmsize->size.width);
0431 if (!ret)
0432 ret = s5k4ecgx_write(client, REG_P_OUT_HEIGHT(0),
0433 priv->curr_frmsize->size.height);
0434 if (!ret)
0435 ret = s5k4ecgx_write(client, REG_P_FMT(0),
0436 priv->curr_pixfmt->reg_p_format);
0437 return ret;
0438 }
0439
0440 static int s5k4ecgx_init_sensor(struct v4l2_subdev *sd)
0441 {
0442 int ret;
0443
0444 ret = s5k4ecgx_set_ahb_address(sd);
0445
0446
0447 msleep(100);
0448
0449 if (!ret)
0450 ret = s5k4ecgx_load_firmware(sd);
0451 if (ret)
0452 v4l2_err(sd, "Failed to write initial settings\n");
0453
0454 return ret;
0455 }
0456
0457 static int s5k4ecgx_gpio_set_value(struct s5k4ecgx *priv, int id, u32 val)
0458 {
0459 if (!gpio_is_valid(priv->gpio[id].gpio))
0460 return 0;
0461 gpio_set_value(priv->gpio[id].gpio, val);
0462
0463 return 1;
0464 }
0465
0466 static int __s5k4ecgx_power_on(struct s5k4ecgx *priv)
0467 {
0468 int ret;
0469
0470 ret = regulator_bulk_enable(S5K4ECGX_NUM_SUPPLIES, priv->supplies);
0471 if (ret)
0472 return ret;
0473 usleep_range(30, 50);
0474
0475
0476 if (s5k4ecgx_gpio_set_value(priv, STBY, priv->gpio[STBY].level))
0477 usleep_range(30, 50);
0478
0479 if (s5k4ecgx_gpio_set_value(priv, RSET, priv->gpio[RSET].level))
0480 usleep_range(30, 50);
0481
0482 return 0;
0483 }
0484
0485 static int __s5k4ecgx_power_off(struct s5k4ecgx *priv)
0486 {
0487 if (s5k4ecgx_gpio_set_value(priv, RSET, !priv->gpio[RSET].level))
0488 usleep_range(30, 50);
0489
0490 if (s5k4ecgx_gpio_set_value(priv, STBY, !priv->gpio[STBY].level))
0491 usleep_range(30, 50);
0492
0493 priv->streaming = 0;
0494
0495 return regulator_bulk_disable(S5K4ECGX_NUM_SUPPLIES, priv->supplies);
0496 }
0497
0498
0499 static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf,
0500 const struct s5k4ecgx_frmsize **size)
0501 {
0502 unsigned int min_err = ~0;
0503 int i = ARRAY_SIZE(s5k4ecgx_prev_sizes);
0504 const struct s5k4ecgx_frmsize *fsize = &s5k4ecgx_prev_sizes[0],
0505 *match = NULL;
0506
0507 while (i--) {
0508 int err = abs(fsize->size.width - mf->width)
0509 + abs(fsize->size.height - mf->height);
0510 if (err < min_err) {
0511 min_err = err;
0512 match = fsize;
0513 }
0514 fsize++;
0515 }
0516 if (match) {
0517 mf->width = match->size.width;
0518 mf->height = match->size.height;
0519 if (size)
0520 *size = match;
0521 return 0;
0522 }
0523
0524 return -EINVAL;
0525 }
0526
0527 static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
0528 struct v4l2_subdev_state *sd_state,
0529 struct v4l2_subdev_mbus_code_enum *code)
0530 {
0531 if (code->index >= ARRAY_SIZE(s5k4ecgx_formats))
0532 return -EINVAL;
0533 code->code = s5k4ecgx_formats[code->index].code;
0534
0535 return 0;
0536 }
0537
0538 static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd,
0539 struct v4l2_subdev_state *sd_state,
0540 struct v4l2_subdev_format *fmt)
0541 {
0542 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
0543 struct v4l2_mbus_framefmt *mf;
0544
0545 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
0546 if (sd_state) {
0547 mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
0548 fmt->format = *mf;
0549 }
0550 return 0;
0551 }
0552
0553 mf = &fmt->format;
0554
0555 mutex_lock(&priv->lock);
0556 mf->width = priv->curr_frmsize->size.width;
0557 mf->height = priv->curr_frmsize->size.height;
0558 mf->code = priv->curr_pixfmt->code;
0559 mf->colorspace = priv->curr_pixfmt->colorspace;
0560 mf->field = V4L2_FIELD_NONE;
0561 mutex_unlock(&priv->lock);
0562
0563 return 0;
0564 }
0565
0566 static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd,
0567 struct v4l2_mbus_framefmt *mf)
0568 {
0569 int i = ARRAY_SIZE(s5k4ecgx_formats);
0570
0571 while (--i)
0572 if (mf->code == s5k4ecgx_formats[i].code)
0573 break;
0574 mf->code = s5k4ecgx_formats[i].code;
0575
0576 return &s5k4ecgx_formats[i];
0577 }
0578
0579 static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd,
0580 struct v4l2_subdev_state *sd_state,
0581 struct v4l2_subdev_format *fmt)
0582 {
0583 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
0584 const struct s5k4ecgx_frmsize *fsize = NULL;
0585 const struct s5k4ecgx_pixfmt *pf;
0586 struct v4l2_mbus_framefmt *mf;
0587 int ret = 0;
0588
0589 pf = s5k4ecgx_try_fmt(sd, &fmt->format);
0590 s5k4ecgx_try_frame_size(&fmt->format, &fsize);
0591 fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
0592 fmt->format.field = V4L2_FIELD_NONE;
0593
0594 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
0595 if (sd_state) {
0596 mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
0597 *mf = fmt->format;
0598 }
0599 return 0;
0600 }
0601
0602 mutex_lock(&priv->lock);
0603 if (!priv->streaming) {
0604 priv->curr_frmsize = fsize;
0605 priv->curr_pixfmt = pf;
0606 priv->set_params = 1;
0607 } else {
0608 ret = -EBUSY;
0609 }
0610 mutex_unlock(&priv->lock);
0611
0612 return ret;
0613 }
0614
0615 static const struct v4l2_subdev_pad_ops s5k4ecgx_pad_ops = {
0616 .enum_mbus_code = s5k4ecgx_enum_mbus_code,
0617 .get_fmt = s5k4ecgx_get_fmt,
0618 .set_fmt = s5k4ecgx_set_fmt,
0619 };
0620
0621
0622
0623
0624 static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl)
0625 {
0626 struct v4l2_subdev *sd = &container_of(ctrl->handler, struct s5k4ecgx,
0627 handler)->sd;
0628 struct i2c_client *client = v4l2_get_subdevdata(sd);
0629 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
0630 unsigned int i;
0631 int err = 0;
0632
0633 v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
0634
0635 mutex_lock(&priv->lock);
0636 switch (ctrl->id) {
0637 case V4L2_CID_CONTRAST:
0638 err = s5k4ecgx_write(client, REG_USER_CONTRAST, ctrl->val);
0639 break;
0640
0641 case V4L2_CID_SATURATION:
0642 err = s5k4ecgx_write(client, REG_USER_SATURATION, ctrl->val);
0643 break;
0644
0645 case V4L2_CID_SHARPNESS:
0646
0647 for (i = 0; i < 4 && !err; i++)
0648 err = s5k4ecgx_write(client, REG_USER_SHARPNESS(i),
0649 ctrl->val * SHARPNESS_DIV);
0650 break;
0651
0652 case V4L2_CID_BRIGHTNESS:
0653 err = s5k4ecgx_write(client, REG_USER_BRIGHTNESS, ctrl->val);
0654 break;
0655 }
0656 mutex_unlock(&priv->lock);
0657 if (err < 0)
0658 v4l2_err(sd, "Failed to write s_ctrl err %d\n", err);
0659
0660 return err;
0661 }
0662
0663 static const struct v4l2_ctrl_ops s5k4ecgx_ctrl_ops = {
0664 .s_ctrl = s5k4ecgx_s_ctrl,
0665 };
0666
0667
0668
0669
0670 static int s5k4ecgx_registered(struct v4l2_subdev *sd)
0671 {
0672 int ret;
0673 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
0674
0675 mutex_lock(&priv->lock);
0676 ret = __s5k4ecgx_power_on(priv);
0677 if (!ret) {
0678 ret = s5k4ecgx_read_fw_ver(sd);
0679 __s5k4ecgx_power_off(priv);
0680 }
0681 mutex_unlock(&priv->lock);
0682
0683 return ret;
0684 }
0685
0686
0687
0688
0689 static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
0690 {
0691 struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
0692 fh->state,
0693 0);
0694
0695 mf->width = s5k4ecgx_prev_sizes[0].size.width;
0696 mf->height = s5k4ecgx_prev_sizes[0].size.height;
0697 mf->code = s5k4ecgx_formats[0].code;
0698 mf->colorspace = V4L2_COLORSPACE_JPEG;
0699 mf->field = V4L2_FIELD_NONE;
0700
0701 return 0;
0702 }
0703
0704 static const struct v4l2_subdev_internal_ops s5k4ecgx_subdev_internal_ops = {
0705 .registered = s5k4ecgx_registered,
0706 .open = s5k4ecgx_open,
0707 };
0708
0709 static int s5k4ecgx_s_power(struct v4l2_subdev *sd, int on)
0710 {
0711 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
0712 int ret;
0713
0714 v4l2_dbg(1, debug, sd, "Switching %s\n", on ? "on" : "off");
0715
0716 if (on) {
0717 ret = __s5k4ecgx_power_on(priv);
0718 if (ret < 0)
0719 return ret;
0720
0721 msleep(100);
0722 ret = s5k4ecgx_init_sensor(sd);
0723 if (ret < 0)
0724 __s5k4ecgx_power_off(priv);
0725 else
0726 priv->set_params = 1;
0727 } else {
0728 ret = __s5k4ecgx_power_off(priv);
0729 }
0730
0731 return ret;
0732 }
0733
0734 static int s5k4ecgx_log_status(struct v4l2_subdev *sd)
0735 {
0736 v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
0737
0738 return 0;
0739 }
0740
0741 static const struct v4l2_subdev_core_ops s5k4ecgx_core_ops = {
0742 .s_power = s5k4ecgx_s_power,
0743 .log_status = s5k4ecgx_log_status,
0744 };
0745
0746 static int __s5k4ecgx_s_params(struct s5k4ecgx *priv)
0747 {
0748 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
0749 const struct v4l2_rect *crop_rect = &priv->curr_frmsize->input_window;
0750 int ret;
0751
0752 ret = s5k4ecgx_set_input_window(client, crop_rect);
0753 if (!ret)
0754 ret = s5k4ecgx_set_zoom_window(client, crop_rect);
0755 if (!ret)
0756 ret = s5k4ecgx_write(client, REG_G_INPUTS_CHANGE_REQ, 1);
0757 if (!ret)
0758 ret = s5k4ecgx_write(client, 0x70000a1e, 0x28);
0759 if (!ret)
0760 ret = s5k4ecgx_write(client, 0x70000ad4, 0x3c);
0761 if (!ret)
0762 ret = s5k4ecgx_set_output_framefmt(priv);
0763 if (!ret)
0764 ret = s5k4ecgx_write(client, REG_P_PVI_MASK(0), 0x52);
0765 if (!ret)
0766 ret = s5k4ecgx_write(client, REG_P_FR_TIME_TYPE(0),
0767 FR_TIME_DYNAMIC);
0768 if (!ret)
0769 ret = s5k4ecgx_write(client, REG_P_FR_TIME_Q_TYPE(0),
0770 FR_TIME_Q_BEST_FRRATE);
0771 if (!ret)
0772 ret = s5k4ecgx_write(client, REG_P_MIN_FR_TIME(0),
0773 US_TO_FR_TIME(33300));
0774 if (!ret)
0775 ret = s5k4ecgx_write(client, REG_P_MAX_FR_TIME(0),
0776 US_TO_FR_TIME(66600));
0777 if (!ret)
0778 ret = s5k4ecgx_write(client, REG_P_PREV_MIRROR(0), 0);
0779 if (!ret)
0780 ret = s5k4ecgx_write(client, REG_P_CAP_MIRROR(0), 0);
0781 if (!ret)
0782 ret = s5k4ecgx_write(client, REG_G_ACTIVE_PREV_CFG, 0);
0783 if (!ret)
0784 ret = s5k4ecgx_write(client, REG_G_PREV_OPEN_AFTER_CH, 1);
0785 if (!ret)
0786 ret = s5k4ecgx_write(client, REG_G_NEW_CFG_SYNC, 1);
0787 if (!ret)
0788 ret = s5k4ecgx_write(client, REG_G_PREV_CFG_CHG, 1);
0789
0790 return ret;
0791 }
0792
0793 static int __s5k4ecgx_s_stream(struct s5k4ecgx *priv, int on)
0794 {
0795 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
0796 int ret;
0797
0798 if (on && priv->set_params) {
0799 ret = __s5k4ecgx_s_params(priv);
0800 if (ret < 0)
0801 return ret;
0802 priv->set_params = 0;
0803 }
0804
0805
0806
0807
0808 ret = s5k4ecgx_write(client, REG_G_ENABLE_PREV, on);
0809 if (ret < 0)
0810 return ret;
0811 return s5k4ecgx_write(client, REG_G_ENABLE_PREV_CHG, 1);
0812 }
0813
0814 static int s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
0815 {
0816 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
0817 int ret = 0;
0818
0819 v4l2_dbg(1, debug, sd, "Turn streaming %s\n", on ? "on" : "off");
0820
0821 mutex_lock(&priv->lock);
0822
0823 if (priv->streaming == !on) {
0824 ret = __s5k4ecgx_s_stream(priv, on);
0825 if (!ret)
0826 priv->streaming = on & 1;
0827 }
0828
0829 mutex_unlock(&priv->lock);
0830 return ret;
0831 }
0832
0833 static const struct v4l2_subdev_video_ops s5k4ecgx_video_ops = {
0834 .s_stream = s5k4ecgx_s_stream,
0835 };
0836
0837 static const struct v4l2_subdev_ops s5k4ecgx_ops = {
0838 .core = &s5k4ecgx_core_ops,
0839 .pad = &s5k4ecgx_pad_ops,
0840 .video = &s5k4ecgx_video_ops,
0841 };
0842
0843
0844
0845
0846 static int s5k4ecgx_config_gpio(int nr, int val, const char *name)
0847 {
0848 unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
0849 int ret;
0850
0851 if (!gpio_is_valid(nr))
0852 return 0;
0853 ret = gpio_request_one(nr, flags, name);
0854 if (!ret)
0855 gpio_export(nr, 0);
0856
0857 return ret;
0858 }
0859
0860 static void s5k4ecgx_free_gpios(struct s5k4ecgx *priv)
0861 {
0862 int i;
0863
0864 for (i = 0; i < ARRAY_SIZE(priv->gpio); i++) {
0865 if (!gpio_is_valid(priv->gpio[i].gpio))
0866 continue;
0867 gpio_free(priv->gpio[i].gpio);
0868 priv->gpio[i].gpio = -EINVAL;
0869 }
0870 }
0871
0872 static int s5k4ecgx_config_gpios(struct s5k4ecgx *priv,
0873 const struct s5k4ecgx_platform_data *pdata)
0874 {
0875 const struct s5k4ecgx_gpio *gpio = &pdata->gpio_stby;
0876 int ret;
0877
0878 priv->gpio[STBY].gpio = -EINVAL;
0879 priv->gpio[RSET].gpio = -EINVAL;
0880
0881 ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_STBY");
0882
0883 if (ret) {
0884 s5k4ecgx_free_gpios(priv);
0885 return ret;
0886 }
0887 priv->gpio[STBY] = *gpio;
0888 if (gpio_is_valid(gpio->gpio))
0889 gpio_set_value(gpio->gpio, 0);
0890
0891 gpio = &pdata->gpio_reset;
0892
0893 ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_RST");
0894 if (ret) {
0895 s5k4ecgx_free_gpios(priv);
0896 return ret;
0897 }
0898 priv->gpio[RSET] = *gpio;
0899 if (gpio_is_valid(gpio->gpio))
0900 gpio_set_value(gpio->gpio, 0);
0901
0902 return 0;
0903 }
0904
0905 static int s5k4ecgx_init_v4l2_ctrls(struct s5k4ecgx *priv)
0906 {
0907 const struct v4l2_ctrl_ops *ops = &s5k4ecgx_ctrl_ops;
0908 struct v4l2_ctrl_handler *hdl = &priv->handler;
0909 int ret;
0910
0911 ret = v4l2_ctrl_handler_init(hdl, 4);
0912 if (ret)
0913 return ret;
0914
0915 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -208, 127, 1, 0);
0916 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
0917 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
0918
0919
0920 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704/SHARPNESS_DIV,
0921 24612/SHARPNESS_DIV, 1, 2);
0922 if (hdl->error) {
0923 ret = hdl->error;
0924 v4l2_ctrl_handler_free(hdl);
0925 return ret;
0926 }
0927 priv->sd.ctrl_handler = hdl;
0928
0929 return 0;
0930 };
0931
0932 static int s5k4ecgx_probe(struct i2c_client *client,
0933 const struct i2c_device_id *id)
0934 {
0935 struct s5k4ecgx_platform_data *pdata = client->dev.platform_data;
0936 struct v4l2_subdev *sd;
0937 struct s5k4ecgx *priv;
0938 int ret, i;
0939
0940 if (pdata == NULL) {
0941 dev_err(&client->dev, "platform data is missing!\n");
0942 return -EINVAL;
0943 }
0944
0945 priv = devm_kzalloc(&client->dev, sizeof(struct s5k4ecgx), GFP_KERNEL);
0946 if (!priv)
0947 return -ENOMEM;
0948
0949 mutex_init(&priv->lock);
0950 priv->streaming = 0;
0951
0952 sd = &priv->sd;
0953
0954 v4l2_i2c_subdev_init(sd, client, &s5k4ecgx_ops);
0955
0956 strscpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
0957
0958 sd->internal_ops = &s5k4ecgx_subdev_internal_ops;
0959
0960 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
0961
0962 priv->pad.flags = MEDIA_PAD_FL_SOURCE;
0963 sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
0964 ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
0965 if (ret)
0966 return ret;
0967
0968 ret = s5k4ecgx_config_gpios(priv, pdata);
0969 if (ret) {
0970 dev_err(&client->dev, "Failed to set gpios\n");
0971 goto out_err1;
0972 }
0973 for (i = 0; i < S5K4ECGX_NUM_SUPPLIES; i++)
0974 priv->supplies[i].supply = s5k4ecgx_supply_names[i];
0975
0976 ret = devm_regulator_bulk_get(&client->dev, S5K4ECGX_NUM_SUPPLIES,
0977 priv->supplies);
0978 if (ret) {
0979 dev_err(&client->dev, "Failed to get regulators\n");
0980 goto out_err2;
0981 }
0982 ret = s5k4ecgx_init_v4l2_ctrls(priv);
0983 if (ret)
0984 goto out_err2;
0985
0986 priv->curr_pixfmt = &s5k4ecgx_formats[0];
0987 priv->curr_frmsize = &s5k4ecgx_prev_sizes[0];
0988
0989 return 0;
0990
0991 out_err2:
0992 s5k4ecgx_free_gpios(priv);
0993 out_err1:
0994 media_entity_cleanup(&priv->sd.entity);
0995
0996 return ret;
0997 }
0998
0999 static int s5k4ecgx_remove(struct i2c_client *client)
1000 {
1001 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1002 struct s5k4ecgx *priv = to_s5k4ecgx(sd);
1003
1004 mutex_destroy(&priv->lock);
1005 s5k4ecgx_free_gpios(priv);
1006 v4l2_device_unregister_subdev(sd);
1007 v4l2_ctrl_handler_free(&priv->handler);
1008 media_entity_cleanup(&sd->entity);
1009
1010 return 0;
1011 }
1012
1013 static const struct i2c_device_id s5k4ecgx_id[] = {
1014 { S5K4ECGX_DRIVER_NAME, 0 },
1015 {}
1016 };
1017 MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id);
1018
1019 static struct i2c_driver v4l2_i2c_driver = {
1020 .driver = {
1021 .name = S5K4ECGX_DRIVER_NAME,
1022 },
1023 .probe = s5k4ecgx_probe,
1024 .remove = s5k4ecgx_remove,
1025 .id_table = s5k4ecgx_id,
1026 };
1027
1028 module_i2c_driver(v4l2_i2c_driver);
1029
1030 MODULE_DESCRIPTION("Samsung S5K4ECGX 5MP SOC camera");
1031 MODULE_AUTHOR("Sangwook Lee <sangwook.lee@linaro.org>");
1032 MODULE_AUTHOR("Seok-Young Jang <quartz.jang@samsung.com>");
1033 MODULE_LICENSE("GPL");
1034 MODULE_FIRMWARE(S5K4ECGX_FIRMWARE);