2 * Driver for M-5MOLS 8M Pixel camera sensor with ISP
4 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
5 * Author: HeungJun Kim, riverful.kim@samsung.com
7 * Copyright (C) 2009 Samsung Electronics Co., Ltd.
8 * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
16 #include <linux/i2c.h>
17 #include <linux/slab.h>
18 #include <linux/irq.h>
19 #include <linux/interrupt.h>
20 #include <linux/delay.h>
21 #include <linux/version.h>
22 #include <linux/gpio.h>
23 #include <linux/regulator/consumer.h>
24 #include <linux/videodev2.h>
25 #include <media/v4l2-ctrls.h>
26 #include <media/v4l2-device.h>
27 #include <media/v4l2-subdev.h>
28 #include <media/m5mols.h>
31 #include "m5mols_reg.h"
34 module_param(m5mols_debug, int, 0644);
36 #define MOD_NAME "M5MOLS"
37 #define M5MOLS_I2C_CHECK_RETRY 500
39 /* M-5MOLS regulator consumer names */
40 /* The DEFAULT names of power are referenced with M-5MOLS datasheet. */
41 static struct regulator_bulk_data supplies[] = {
43 .supply = "core", /* ARM core power, 1.2V */
45 .supply = "dig_18", /* digital power 1, 1.8V */
47 .supply = "d_sensor", /* sensor power 1, 1.8V */
49 .supply = "dig_28", /* digital power 2, 2.8V */
51 .supply = "a_sensor", /* analog power */
53 .supply = "dig_12", /* digital power 3, 1.2V */
57 const struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
58 [M5MOLS_RESTYPE_MONITOR] = {
61 .code = V4L2_MBUS_FMT_VYUY8_2X8,
62 .field = V4L2_FIELD_NONE,
63 .colorspace = V4L2_COLORSPACE_JPEG,
65 [M5MOLS_RESTYPE_CAPTURE] = {
68 .code = V4L2_MBUS_FMT_JPEG_1X8,
69 .field = V4L2_FIELD_NONE,
70 .colorspace = V4L2_COLORSPACE_JPEG,
74 static const struct m5mols_resolution m5mols_reg_res[] = {
76 { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */
77 { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */
78 { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */
79 { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, /* 176*176 */
80 { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* 1 QVGA */
81 { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */
82 { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* l WQVGA */
83 { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */
84 { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */
85 { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, /* 480*360 */
86 { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */
87 { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */
88 { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, /* 720x480 */
89 { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */
90 { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */
91 { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */
92 { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */
93 { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 8M (2.63fps) */
94 { 0x30, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* 60fps slow motion */
95 { 0x31, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* 120fps slow motion */
96 { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */
98 /* CAPTURE(JPEG or Bayer RAW or YUV Raw) size */
99 { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */
100 { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */
101 { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, /* 480 x 360 */
102 { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */
103 { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */
104 { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */
105 { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */
106 { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */
107 { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */
108 { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */
109 { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3M */
110 { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, /* 3M */
111 { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4M */
112 { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, /* 4M */
113 { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5M */
114 { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6M */
115 { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, /* 6M */
116 { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8M */
120 * m5mols_swap_byte() - byte array to integer conversion
122 * Convert I2C data byte array with performing any required byte
123 * reordering to assure proper values for each data type, regardless
124 * of the architecture endianness.
126 static u32 m5mols_swap_byte(u8 *data, enum m5mols_i2c_size size)
128 if (size == I2C_8BIT)
130 else if (size == I2C_16BIT)
131 return be16_to_cpu(*((u16 *)data));
133 return be32_to_cpu(*((u32 *)data));
137 * m5mols_read_reg() / m5mols_write_reg() - handle sensor's I2C communications.
139 * The I2C command packet of M-5MOLS is made up 3 kinds of I2C bytes(category,
140 * command, bytes). Reference m5mols.h.
142 * The packet is needed 2, when M-5MOLS is read through I2C.
143 * The packet is needed 1, when M-5MOLS is written through I2C.
145 * I2C packet common order(including both reading/writing)
146 * 1st : size (data size + 4)
147 * 2nd : READ/WRITE (R - 0x01, W - 0x02)
151 * I2C packet order for READING operation
152 * 5th : data real size for reading
153 * And, read another I2C packet again, until data size.
155 * I2C packet order for WRITING operation
156 * 5th to 8th: an actual data to write
159 #define M5MOLS_BYTE_READ 0x01
160 #define M5MOLS_BYTE_WRITE 0x02
162 int m5mols_read_reg(struct v4l2_subdev *sd, enum m5mols_i2c_size size,
163 u8 category, u8 cmd, u32 *val)
165 struct i2c_client *client = v4l2_get_subdevdata(sd);
166 struct i2c_msg msg[2];
167 u8 wbuf[5], rbuf[I2C_MAX + 1];
170 if (!client->adapter)
173 if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT)
176 /* 1st I2C operation for writing category & command. */
177 msg[0].addr = client->addr;
179 msg[0].len = 5; /* 1(cmd size per bytes) + 4 */
182 wbuf[1] = M5MOLS_BYTE_READ;
187 /* 2nd I2C operation for reading data. */
188 msg[1].addr = client->addr;
189 msg[1].flags = I2C_M_RD;
190 msg[1].len = size + 1;
193 usleep_range(200, 200); /* must be for stabilization */
195 ret = i2c_transfer(client->adapter, msg, 2);
197 dev_err(&client->dev,
198 "failed READ[%d] at cat[%02x] cmd[%02x]\n",
199 size, category, cmd);
203 *val = m5mols_swap_byte(&rbuf[1], size);
208 int m5mols_write_reg(struct v4l2_subdev *sd, enum m5mols_i2c_size size,
209 u8 category, u8 cmd, u32 val)
211 struct i2c_client *client = v4l2_get_subdevdata(sd);
212 struct device *cdev = &client->dev;
213 struct i2c_msg msg[1];
214 u8 wbuf[I2C_MAX + 4];
215 u32 *buf = (u32 *)&wbuf[4];
218 if (!client->adapter)
221 if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT) {
222 dev_err(cdev, "Wrong data size\n");
226 msg->addr = client->addr;
231 wbuf[1] = M5MOLS_BYTE_WRITE;
235 *buf = m5mols_swap_byte((u8 *)&val, size);
237 usleep_range(200, 200); /* must be for stabilization */
239 ret = i2c_transfer(client->adapter, msg, 1);
241 dev_err(&client->dev,
242 "failed WRITE[%d] at cat[%02x] cmd[%02x], ret %d\n",
243 size, msg->buf[2], msg->buf[3], ret);
250 int m5mols_check_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask)
255 for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
256 ret = m5mols_read_reg(sd, I2C_8BIT, category, cmd, &busy);
267 int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg)
269 struct m5mols_info *info = to_m5mols(sd);
273 /* Clear interrupt all bit. */
274 ret = i2c_r8_system(sd, CAT0_INT_FACTOR, &dummy);
276 /* If AF algorithm don't exist, clear REG_INT_AF bit. */
277 ret = i2c_w8_system(sd, CAT0_INT_ENABLE,
278 (reg & REG_INT_AF) && info->ver.af ? reg :
279 reg & ~(REG_INT_AF));
284 * m5mols_change_mode() - manage the M-5MOLS's mode.
286 * All M-5MOLS commands belong to a specific unique mode. Each functionality
287 * works properly only after the sensor is switched into its corresponding mode.
289 * Th below functions manage the operating mode of M-5MOLS. There are 3 distinct
290 * modes: PARAMETER, MONITOR and CAPTURE. Each command category is assigned
291 * to a selected mode. The category to mode assignment is as following:
292 * +============================================================+
293 * | mode | category |
294 * +============================================================+
295 * | PARAMETER | PARAMETER |
296 * | MONITOR | MONITOR(preview), Auto Focus, Face Detection |
297 * | CAPTURE | Single CAPTURE, Preview(recording) |
298 * +============================================================+
300 * The possible route between each modes is the following:
301 * ============================================================
302 * +-----------+ +---------+ +---------+
303 * | PARAMETER |<------->| MONITOR |<-------->| CAPTURE |
304 * +-----------+ +---------+ +---------+
306 static int m5mols_write_mode(struct v4l2_subdev *sd, u32 mode)
308 int ret = i2c_w8_system(sd, CAT0_SYSMODE, mode);
310 ret = m5mols_check_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
315 int m5mols_change_mode(struct m5mols_info *info, u32 mode)
317 struct v4l2_subdev *sd = &info->sd;
318 struct i2c_client *client = v4l2_get_subdevdata(sd);
322 if (mode != REG_MODE_PARAM && mode != REG_MODE_MONITOR &&
323 mode != REG_MODE_CAPTURE)
326 /* Retrieve the current mode */
327 ret = i2c_r8_system(sd, CAT0_SYSMODE, ®);
328 if ((!ret && reg == mode) || ret)
331 /* Save current mode */
332 info->mode = (u32)reg;
334 switch (info->mode) {
336 ret = m5mols_write_mode(sd, REG_MODE_MONITOR);
337 if (!ret && mode == REG_MODE_MONITOR)
340 ret = m5mols_write_mode(sd, REG_MODE_CAPTURE);
343 case REG_MODE_MONITOR:
344 if (mode == REG_MODE_PARAM) {
345 ret = m5mols_write_mode(sd, REG_MODE_PARAM);
349 ret = m5mols_write_mode(sd, REG_MODE_CAPTURE);
352 case REG_MODE_CAPTURE:
353 ret = m5mols_write_mode(sd, REG_MODE_MONITOR);
354 if (!ret && mode == REG_MODE_MONITOR)
357 ret = m5mols_write_mode(sd, REG_MODE_PARAM);
361 dev_warn(&client->dev, "Wrong mode: %d", mode);
371 * m5mols_get_version() - Retrieve M-5MOLS revisions including H/W and firmware
372 * revision, AF alghorithm version and the version string.
374 static int m5mols_get_version(struct v4l2_subdev *sd)
376 struct m5mols_info *info = to_m5mols(sd);
377 struct i2c_client *client = v4l2_get_subdevdata(sd);
378 struct device *cdev = &client->dev;
380 struct m5mols_version ver;
381 u8 bytes[VERSION_SIZE];
383 int ret, i = CAT0_CUSTOMER_CODE;
385 /* get all from CUSTOMER CODE version to AWB version */
386 for (; i <= CAT0_VERSION_AWB; i++) {
387 ret = i2c_r8_system(sd, i, (u32 *)&value.bytes[i]);
392 /* get version string */
393 for (; i < VERSION_SIZE - 1; i++)
394 ret = i2c_r8_system(sd, CAT0_VERSION_STRING,
395 (u32 *)&value.bytes[i]);
396 value.bytes[i] = '\0';
399 ret = i2c_r8_lens(sd, CATA_AF_VERSION, (u32 *)&value.bytes[i]);
403 /* store version to be available to read */
404 info->ver = value.ver;
405 info->ver.fw = be16_to_cpu(info->ver.fw);
406 info->ver.hw = be16_to_cpu(info->ver.hw);
407 info->ver.param = be16_to_cpu(info->ver.param);
408 info->ver.awb = be16_to_cpu(info->ver.awb);
410 dev_info(cdev, "Manufacturer\t[%s]\n",
411 is_manufacturer(info, SAMSUNG_OPTICS_SONY) ?
412 "Samsung Fiber-Optics + Sony" :
413 is_manufacturer(info, SAMSUNG_OPTICS_LSI) ?
414 "Samsung Fiber-Optics + LSI" :
415 is_manufacturer(info, SAMSUNG_ELECTRO) ?
416 "Samsung Electro-Machanics" :
417 is_manufacturer(info, SAMSUNG_OPTICS) ?
418 "Samsung Fiber-Optics" :
419 is_manufacturer(info, SAMSUNG_TECHWIN) ?
420 "Samsung Techwin" : "None");
421 dev_info(cdev, "Customer/Project\t[0x%02x/0x%02x]\n",
422 info->ver.customer, info->ver.project);
424 dev_info(cdev, "No support Auto Focus on this firmware\n");
430 * find_res_preset() - look up M-5MOLS resolution register value
431 * corresponding to the pixel resolution and
432 * the resolution type.
434 * @width: pixel width
435 * @height: pixel height
436 * @type: resolution type corresponding to the sensor's operation mode
438 static int find_res_preset(struct v4l2_subdev *sd, u16 width, u16 height,
439 enum m5mols_restype type, u32 *resolution)
443 for (i = 0; i < ARRAY_SIZE(m5mols_reg_res); i++) {
444 if ((type == m5mols_reg_res[i].type) &&
445 (width == m5mols_reg_res[i].width) &&
446 (height == m5mols_reg_res[i].height))
450 if (i == ARRAY_SIZE(m5mols_reg_res))
453 *resolution = m5mols_reg_res[i].reg;
459 * find_res_type() - look up M-5MOLS resolution type corresponding to
464 static int find_res_type(enum v4l2_mbus_pixelcode code,
465 enum m5mols_restype *type)
469 for (i = 0; i < ARRAY_SIZE(m5mols_default_ffmt); i++)
470 if (code == m5mols_default_ffmt[i].code)
473 if (i == ARRAY_SIZE(m5mols_default_ffmt))
476 *type = (enum m5mols_restype)i;
481 static int m5mols_get_fmt(struct v4l2_subdev *sd,
482 struct v4l2_mbus_framefmt *ffmt)
484 struct m5mols_info *info = to_m5mols(sd);
485 enum m5mols_restype type;
488 ret = find_res_type(ffmt->code, &type);
490 *ffmt = info->ffmt[type];
491 info->code = ffmt->code;
497 static int m5mols_set_fmt(struct v4l2_subdev *sd,
498 struct v4l2_mbus_framefmt *ffmt)
500 struct m5mols_info *info = to_m5mols(sd);
501 enum m5mols_restype type;
502 int width = ffmt->width;
503 int height = ffmt->height;
504 u32 code = ffmt->code;
508 ret = find_res_type(code, &type);
510 ret = find_res_preset(sd, width, height, type, &resolution);
512 info->ffmt[type] = m5mols_default_ffmt[type];
514 info->ffmt[type].width = width;
515 info->ffmt[type].height = height;
516 info->resolution = resolution;
519 *ffmt = info->ffmt[type];
523 printk("%s:%d ==== M5MOLS: SET_FMT: "
524 "w,h: %d,%d type [%s] resolution %d, ret %d\n",
527 type == M5MOLS_RESTYPE_MONITOR ? "VYUY" : "JPEG",
533 static int m5mols_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
534 enum v4l2_mbus_pixelcode *code)
536 if (!code || index >= ARRAY_SIZE(m5mols_default_ffmt))
539 *code = m5mols_default_ffmt[index].code;
544 /* M-5MOLS default FPS */
545 static const struct v4l2_fract default_fps = {
547 .denominator = M5MOLS_FPS_AUTO,
550 static u8 m5mols_reg_fps[] = {
551 [M5MOLS_FPS_AUTO] = 0x01,
552 [M5MOLS_FPS_10] = 0x05,
553 [M5MOLS_FPS_12] = 0x04,
554 [M5MOLS_FPS_15] = 0x03,
555 [M5MOLS_FPS_20] = 0x08,
556 [M5MOLS_FPS_21] = 0x09,
557 [M5MOLS_FPS_22] = 0x0a,
558 [M5MOLS_FPS_23] = 0x0b,
559 [M5MOLS_FPS_24] = 0x07,
560 [M5MOLS_FPS_30] = 0x02,
564 * get_fps() - calc & check FPS from v4l2_captureparm, if FPS is adequate, set.
566 * In M-5MOLS case, the denominator means FPS. The values of numerator and
567 * denominator should not be minus both. If numerator is 0, it sets AUTO FPS.
568 * If numerator is not 1, it recalculates denominator. After it checks, the
569 * denominator is set to timeperframe.denominator, and used by FPS.
571 static int get_fps(struct v4l2_subdev *sd,
572 struct v4l2_captureparm *parm)
574 int numerator = parm->timeperframe.numerator;
575 int denominator = parm->timeperframe.denominator;
577 /* The denominator should be +, except 0. The numerator shoud be +. */
578 if (numerator < 0 || denominator <= 0)
581 /* The numerator is 0, return auto fps. */
582 if (numerator == 0) {
583 parm->timeperframe.denominator = M5MOLS_FPS_AUTO;
587 /* calc FPS(not time per frame) per 1 numerator */
588 denominator = denominator / numerator;
590 if (denominator < M5MOLS_FPS_AUTO || denominator > M5MOLS_FPS_MAX)
593 if (!m5mols_reg_fps[denominator])
599 static int m5mols_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
601 struct m5mols_info *info = to_m5mols(sd);
602 struct v4l2_captureparm *cp = &parms->parm.capture;
604 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
605 parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
608 cp->capability = V4L2_CAP_TIMEPERFRAME;
609 cp->timeperframe = info->fract;
614 static int m5mols_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
616 struct m5mols_info *info = to_m5mols(sd);
617 struct v4l2_captureparm *cp = &parms->parm.capture;
620 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
621 parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
624 ret = get_fps(sd, cp); /* set right FPS to denominator. */
626 info->fps = m5mols_reg_fps[cp->timeperframe.denominator];
628 cp->capability = V4L2_CAP_TIMEPERFRAME;
629 info->fract = cp->timeperframe;
635 int m5mols_sync_control(struct m5mols_info *info)
639 if (!is_ctrl_synced(info)) {
640 /* Do the default scenemode at first */
641 ret = m5mols_change_scenemode(info, REG_SCENE_NORMAL);
646 * Then, call default control value. There is some commands
647 * overlapped on the scenemode's one in the default control.
648 * But, these commands of control should be prior to the
649 * scenemode, of course it's executed only af first booting
652 v4l2_ctrl_handler_setup(&info->handle);
654 /* And this should be called once, after probing the driver. */
655 info->ctrl_sync = true;
661 static int m5mols_start_monitor(struct m5mols_info *info)
663 struct v4l2_subdev *sd = &info->sd;
664 struct i2c_client *client = v4l2_get_subdevdata(sd);
667 ret = m5mols_change_mode(info, REG_MODE_PARAM);
669 ret = i2c_w8_param(sd, CAT1_MONITOR_SIZE, info->resolution);
671 ret = i2c_w8_param(sd, CAT1_MONITOR_FPS, REG_FPS_30);
673 ret = m5mols_change_mode(info, REG_MODE_MONITOR);
675 ret = m5mols_sync_control(info);
680 static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
682 struct m5mols_info *info = to_m5mols(sd);
687 /* The stream mode is determined according to media bus code */
688 if (is_code(info->code, M5MOLS_RESTYPE_MONITOR))
689 ret = m5mols_start_monitor(info);
690 if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE))
691 ret = m5mols_start_capture(info);
694 printk("%s:%d ==== M5MOLS: S_STREAM %s, ret %d\n",
696 info->code == V4L2_MBUS_FMT_JPEG_1X8 ?
698 info->code == V4L2_MBUS_FMT_VYUY8_2X8 ?
699 "YUYV" : "None", ret);
704 return m5mols_change_mode(info, REG_MODE_PARAM);
707 static const struct v4l2_subdev_video_ops m5mols_video_ops = {
708 .g_mbus_fmt = m5mols_get_fmt,
709 .s_mbus_fmt = m5mols_set_fmt,
710 .enum_mbus_fmt = m5mols_enum_mbus_fmt,
711 .g_parm = m5mols_g_parm,
712 .s_parm = m5mols_s_parm,
713 .s_stream = m5mols_s_stream,
716 static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
718 struct v4l2_subdev *sd = to_sd(ctrl);
719 struct m5mols_info *info = to_m5mols(sd);
722 info->mode_save = info->mode;
724 ret = m5mols_change_mode(info, REG_MODE_PARAM);
726 ret = m5mols_set_ctrl(ctrl);
728 ret = m5mols_change_mode(info, info->mode_save);
733 static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
734 .s_ctrl = m5mols_s_ctrl,
737 /* m5mols_sensor_power() - handle sensor power up/down. */
738 static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
740 struct v4l2_subdev *sd = &info->sd;
741 struct i2c_client *client = v4l2_get_subdevdata(sd);
742 const struct m5mols_platform_data *pdata = info->pdata;
746 if (is_powered(info))
749 /* Optional power on callback to the board code. */
750 if (info->set_power) {
751 ret = info->set_power(&client->dev, 1);
756 ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
760 gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
761 usleep_range(1000, 1000);
767 if (!is_powered(info))
770 ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
774 /* Optional power off callback */
775 if (info->set_power) {
776 ret = info->set_power(&client->dev, 0);
781 gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
782 usleep_range(1000, 1000);
788 /* m5mols_update_fw() - m5mols_update_fw() is optional. */
789 int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
790 int (*set_power)(struct m5mols_info *, bool))
796 * m5mols_sensor_armboot() - booting M-5MOLS internal ARM core.
798 * Booting internal ARM core makes the M-5MOLS is ready for getting commands
799 * with I2C. It's the first thing to be done after it powered up. It must wait
800 * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
802 static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
804 struct i2c_client *client = v4l2_get_subdevdata(sd);
807 /* ARM(M-5MOLS core) booting */
808 ret = i2c_w8_flash(sd, CATF_CAM_START, REG_START_ARM_BOOT);
814 /* Checking version & update firmware if the function exists. */
815 ret = m5mols_get_version(sd);
817 ret = m5mols_update_fw(sd, m5mols_sensor_power);
821 dev_dbg(&client->dev, "Success ARM Booting\n");
823 /* Set interface & interrupt */
824 ret = i2c_w8_param(sd, CAT1_DATA_INTERFACE, REG_INTERFACE_MIPI);
826 ret = m5mols_enable_interrupt(sd, REG_INT_AF);
831 /* m5mols_init_controls() - initialization for v4l2 control */
832 static int m5mols_init_controls(struct m5mols_info *info)
834 struct v4l2_subdev *sd = &info->sd;
835 struct i2c_client *client = v4l2_get_subdevdata(sd);
836 u16 max_exposure, step_zoom;
839 /* Determine value's range & step of controls for various FW version */
840 ret = i2c_r16_ae(sd, CAT3_MAX_GAIN_MON, (u32 *)&max_exposure);
842 step_zoom = is_manufacturer(info, SAMSUNG_OPTICS) ? 31 : 1;
846 v4l2_ctrl_handler_init(&info->handle, 12);
847 info->autowb = v4l2_ctrl_new_std(&info->handle,
848 &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
850 info->saturation = v4l2_ctrl_new_std(&info->handle,
851 &m5mols_ctrl_ops, V4L2_CID_SATURATION,
853 info->zoom = v4l2_ctrl_new_std(&info->handle,
854 &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
855 1, 70, step_zoom, 1);
856 info->exposure = v4l2_ctrl_new_std(&info->handle,
857 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
858 0, max_exposure, 1, (int)max_exposure/2);
859 info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
860 &m5mols_ctrl_ops, V4L2_CID_COLORFX,
861 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
862 info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
863 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
864 1, 0, V4L2_EXPOSURE_MANUAL);
865 info->autofocus = v4l2_ctrl_new_std(&info->handle,
866 &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO,
868 info->focusmode = v4l2_ctrl_new_std_menu(&info->handle,
869 &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO_MODE,
870 5, 0, V4L2_FOCUS_AUTO_NORMAL);
871 /* the maximum value of rectangle focus mode has been referenced by
872 * the maximun resolution of M-5MOLS */
873 info->focusrect_left = v4l2_ctrl_new_std(&info->handle,
874 &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO_RECTANGLE_LEFT,
875 0, 3263, 1, (s32)3264/2);
876 info->focusrect_top = v4l2_ctrl_new_std(&info->handle,
877 &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO_RECTANGLE_TOP,
878 0, 2447, 1, (s32)2448/2);
879 info->focusrect_width = v4l2_ctrl_new_std(&info->handle,
880 &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO_RECTANGLE_WIDTH,
881 0, 3263, 1, (s32)3264/2);
882 info->focusrect_height = v4l2_ctrl_new_std(&info->handle,
883 &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO_RECTANGLE_HEIGHT,
884 0, 2447, 1, (s32)2448/2);
886 sd->ctrl_handler = &info->handle;
887 if (info->handle.error) {
888 dev_err(&client->dev, "Failed to init controls, %d\n", ret);
889 v4l2_ctrl_handler_free(&info->handle);
890 return info->handle.error;
893 v4l2_ctrl_cluster(2, &info->autoexposure);
894 v4l2_ctrl_cluster(2, &info->autofocus);
899 static int m5mols_s_power(struct v4l2_subdev *sd, int on)
901 struct m5mols_info *info = to_m5mols(sd);
902 struct i2c_client *client = v4l2_get_subdevdata(sd);
906 ret = m5mols_sensor_power(info, true);
908 ret = m5mols_sensor_armboot(sd);
910 ret = m5mols_init_controls(info);
912 info->ffmt[M5MOLS_RESTYPE_MONITOR] =
913 m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
914 info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
915 m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
922 * power off AF - Do Lens soft-landing algorithm.
924 * The lens soft-landing algorithm is only verified when the sensor
925 * uses Samsung Techwin F/W.
927 if (is_manufacturer(info, SAMSUNG_TECHWIN)) {
928 ret = m5mols_change_mode(info, REG_MODE_MONITOR);
930 ret = i2c_w8_lens(sd, CATA_AF_EXECUTE, REG_AF_STOP);
932 ret = i2c_w8_lens(sd, CATA_AF_MODE,
933 REG_AF_MODE_POWEROFF);
935 ret = m5mols_check_busy(sd, CAT_SYSTEM, CAT0_STATUS,
938 dev_info(&client->dev, "Success soft-landing lens\n");
942 * Switch the sensor's power off regardless of the AF shutdown
943 * status. And then, the ctrl_sync can be set true.
945 ret = m5mols_sensor_power(info, false);
947 info->ctrl_sync = false;
952 static int m5mols_log_status(struct v4l2_subdev *sd)
954 struct m5mols_info *info = to_m5mols(sd);
956 v4l2_ctrl_handler_log_status(&info->handle, sd->name);
961 static const struct v4l2_subdev_core_ops m5mols_core_ops = {
962 .s_power = m5mols_s_power,
963 .g_ctrl = v4l2_subdev_g_ctrl,
964 .s_ctrl = v4l2_subdev_s_ctrl,
965 .queryctrl = v4l2_subdev_queryctrl,
966 .querymenu = v4l2_subdev_querymenu,
967 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
968 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
969 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
970 .log_status = m5mols_log_status,
973 static const struct v4l2_subdev_ops m5mols_ops = {
974 .core = &m5mols_core_ops,
975 .video = &m5mols_video_ops,
978 static void m5mols_irq_work(struct work_struct *work)
980 struct m5mols_info *info = container_of(work, struct m5mols_info,
982 struct v4l2_subdev *sd = &info->sd;
983 struct i2c_client *client = v4l2_get_subdevdata(sd);
988 * For preventing I2C operation when it's not powered and prepared for
991 if (!is_powered(info) ||
992 i2c_r8_system(sd, CAT0_INT_FACTOR, &info->interrupt))
995 switch (info->interrupt & REG_INT_MASK) {
998 ret = i2c_r8_lens(sd, CATA_AF_STATUS, ®);
999 dev_dbg(&client->dev, "= AF %s\n",
1000 reg == REG_AF_FAIL ? "Failed" :
1001 reg == REG_AF_SUCCESS ? "Success" :
1002 reg == REG_AF_IDLE ? "Idle" : "Busy");
1005 case REG_INT_CAPTURE:
1006 if (!is_captured(info)) {
1007 wake_up_interruptible(&info->wait_capture);
1008 info->capture = true;
1010 dev_dbg(&client->dev, "= CAPTURE\n");
1013 case REG_INT_FRAMESYNC:
1015 case REG_INT_LENS_INIT:
1018 dev_dbg(&client->dev, "= Nothing : %02x\n", reg);
1025 static irqreturn_t m5mols_irq_handler(int irq, void *data)
1027 struct v4l2_subdev *sd = data;
1028 struct m5mols_info *info = to_m5mols(sd);
1030 schedule_work(&info->work_irq);
1035 static int m5mols_probe(struct i2c_client *client,
1036 const struct i2c_device_id *id)
1038 const struct m5mols_platform_data *pdata =
1039 client->dev.platform_data;
1040 struct m5mols_info *info;
1041 struct v4l2_subdev *sd;
1044 if (pdata == NULL) {
1045 dev_err(&client->dev, "No platform data\n");
1049 if (!gpio_is_valid(pdata->gpio_reset)) {
1050 dev_err(&client->dev, "No valid RESET GPIO specified\n");
1055 dev_err(&client->dev, "Interrupt not assigned\n");
1059 info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
1061 dev_err(&client->dev, "Failed to allocate info\n");
1065 info->pdata = pdata;
1066 info->set_power = pdata->set_power;
1068 ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
1070 dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
1074 gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
1076 ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
1078 dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
1083 strlcpy(sd->name, MOD_NAME, sizeof(sd->name));
1084 v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
1085 INIT_WORK(&info->work_focus, m5mols_focus_work);
1087 init_waitqueue_head(&info->wait_capture);
1088 INIT_WORK(&info->work_irq, m5mols_irq_work);
1089 ret = request_irq(pdata->irq, m5mols_irq_handler,
1090 IRQF_TRIGGER_RISING, MOD_NAME, sd);
1092 dev_err(&client->dev, "Failed to request irq: %d\n", ret);
1096 v4l2_dbg(1, m5mols_debug, sd, "Probed m5mols driver.\n");
1101 regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
1103 gpio_free(pdata->gpio_reset);
1109 static int m5mols_remove(struct i2c_client *client)
1111 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1112 struct m5mols_info *info = to_m5mols(sd);
1114 v4l2_dbg(1, m5mols_debug, sd, "Removing m5mols driver\n");
1116 v4l2_device_unregister_subdev(sd);
1117 v4l2_ctrl_handler_free(&info->handle);
1118 free_irq(info->pdata->irq, sd);
1120 regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
1121 gpio_free(info->pdata->gpio_reset);
1127 static const struct i2c_device_id m5mols_id[] = {
1131 MODULE_DEVICE_TABLE(i2c, m5mols_id);
1133 static struct i2c_driver m5mols_i2c_driver = {
1137 .probe = m5mols_probe,
1138 .remove = m5mols_remove,
1139 .id_table = m5mols_id,
1142 static int __init m5mols_mod_init(void)
1144 return i2c_add_driver(&m5mols_i2c_driver);
1147 static void __exit m5mols_mod_exit(void)
1149 i2c_del_driver(&m5mols_i2c_driver);
1152 module_init(m5mols_mod_init);
1153 module_exit(m5mols_mod_exit);
1155 MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
1156 MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
1157 MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
1158 MODULE_LICENSE("GPL");