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/gpio.h>
22 #include <linux/regulator/consumer.h>
23 #include <linux/videodev2.h>
24 #include <media/v4l2-ctrls.h>
25 #include <media/v4l2-device.h>
26 #include <media/v4l2-subdev.h>
27 #include <media/m5mols.h>
30 #include "m5mols_reg.h"
33 module_param(m5mols_debug, int, 0644);
35 #define MODULE_NAME "M5MOLS"
36 #define M5MOLS_I2C_CHECK_RETRY 500
38 /* The regulator consumer names for external voltage regulators */
39 static struct regulator_bulk_data supplies[] = {
41 .supply = "core", /* ARM core power, 1.2V */
43 .supply = "dig_18", /* digital power 1, 1.8V */
45 .supply = "d_sensor", /* sensor power 1, 1.8V */
47 .supply = "dig_28", /* digital power 2, 2.8V */
49 .supply = "a_sensor", /* analog power */
51 .supply = "dig_12", /* digital power 3, 1.2V */
55 static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
56 [M5MOLS_RESTYPE_MONITOR] = {
59 .code = V4L2_MBUS_FMT_VYUY8_2X8,
60 .field = V4L2_FIELD_NONE,
61 .colorspace = V4L2_COLORSPACE_JPEG,
63 [M5MOLS_RESTYPE_CAPTURE] = {
66 .code = V4L2_MBUS_FMT_JPEG_1X8,
67 .field = V4L2_FIELD_NONE,
68 .colorspace = V4L2_COLORSPACE_JPEG,
71 #define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt)
73 static const struct m5mols_resolution m5mols_reg_res[] = {
74 { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */
75 { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */
76 { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */
77 { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 },
78 { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */
79 { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */
80 { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */
81 { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */
82 { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */
83 { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 },
84 { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */
85 { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */
86 { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 },
87 { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */
88 { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */
89 { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */
90 { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */
91 { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */
92 { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */
94 { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */
95 { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */
96 { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 },
97 { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */
98 { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */
99 { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */
100 { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */
101 { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */
102 { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */
103 { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */
104 { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */
105 { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 },
106 { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */
107 { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 },
108 { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */
109 { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */
110 { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 },
111 { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */
115 * m5mols_swap_byte - an byte array to integer conversion function
116 * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet
118 * Convert I2C data byte array with performing any required byte
119 * reordering to assure proper values for each data type, regardless
120 * of the architecture endianness.
122 static u32 m5mols_swap_byte(u8 *data, u8 length)
126 else if (length == 2)
127 return be16_to_cpu(*((u16 *)data));
129 return be32_to_cpu(*((u32 *)data));
133 * m5mols_read - I2C read function
134 * @reg: combination of size, category and command for the I2C packet
135 * @size: desired size of I2C packet
138 static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
140 struct i2c_client *client = v4l2_get_subdevdata(sd);
141 u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
142 u8 category = I2C_CATEGORY(reg);
143 u8 cmd = I2C_COMMAND(reg);
144 struct i2c_msg msg[2];
148 if (!client->adapter)
151 msg[0].addr = client->addr;
156 wbuf[1] = M5MOLS_BYTE_READ;
161 msg[1].addr = client->addr;
162 msg[1].flags = I2C_M_RD;
163 msg[1].len = size + 1;
166 /* minimum stabilization time */
167 usleep_range(200, 200);
169 ret = i2c_transfer(client->adapter, msg, 2);
171 v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
172 size, category, cmd, ret);
176 *val = m5mols_swap_byte(&rbuf[1], size);
181 int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
186 if (I2C_SIZE(reg) != 1) {
187 v4l2_err(sd, "Wrong data size\n");
191 ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
199 int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val)
204 if (I2C_SIZE(reg) != 2) {
205 v4l2_err(sd, "Wrong data size\n");
209 ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
217 int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
219 if (I2C_SIZE(reg) != 4) {
220 v4l2_err(sd, "Wrong data size\n");
224 return m5mols_read(sd, I2C_SIZE(reg), reg, val);
228 * m5mols_write - I2C command write function
229 * @reg: combination of size, category and command for the I2C packet
230 * @val: value to write
232 int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
234 struct i2c_client *client = v4l2_get_subdevdata(sd);
235 u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
236 u8 category = I2C_CATEGORY(reg);
237 u8 cmd = I2C_COMMAND(reg);
238 u8 size = I2C_SIZE(reg);
239 u32 *buf = (u32 *)&wbuf[4];
240 struct i2c_msg msg[1];
243 if (!client->adapter)
246 if (size != 1 && size != 2 && size != 4) {
247 v4l2_err(sd, "Wrong data size\n");
251 msg->addr = client->addr;
253 msg->len = (u16)size + 4;
256 wbuf[1] = M5MOLS_BYTE_WRITE;
260 *buf = m5mols_swap_byte((u8 *)&val, size);
262 usleep_range(200, 200);
264 ret = i2c_transfer(client->adapter, msg, 1);
266 v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
267 size, category, cmd, ret);
274 int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask)
280 for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
281 ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy);
284 if ((busy & mask) == mask)
291 * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
293 * Before writing desired interrupt value the INT_FACTOR register should
294 * be read to clear pending interrupts.
296 int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
298 struct m5mols_info *info = to_m5mols(sd);
299 u8 mask = is_available_af(info) ? REG_INT_AF : 0;
303 ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy);
305 ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
310 * m5mols_reg_mode - Write the mode and check busy status
312 * It always accompanies a little delay changing the M-5MOLS mode, so it is
313 * needed checking current busy status to guarantee right mode.
315 static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
317 int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
319 return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
323 * m5mols_mode - manage the M-5MOLS's mode
324 * @mode: the required operation mode
326 * The commands of M-5MOLS are grouped into specific modes. Each functionality
327 * can be guaranteed only when the sensor is operating in mode which which
328 * a command belongs to.
330 int m5mols_mode(struct m5mols_info *info, u8 mode)
332 struct v4l2_subdev *sd = &info->sd;
336 if (mode < REG_PARAMETER && mode > REG_CAPTURE)
339 ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®);
340 if ((!ret && reg == mode) || ret)
345 ret = m5mols_reg_mode(sd, REG_MONITOR);
346 if (!ret && mode == REG_MONITOR)
349 ret = m5mols_reg_mode(sd, REG_CAPTURE);
353 if (mode == REG_PARAMETER) {
354 ret = m5mols_reg_mode(sd, REG_PARAMETER);
358 ret = m5mols_reg_mode(sd, REG_CAPTURE);
362 ret = m5mols_reg_mode(sd, REG_MONITOR);
363 if (!ret && mode == REG_MONITOR)
366 ret = m5mols_reg_mode(sd, REG_PARAMETER);
370 v4l2_warn(sd, "Wrong mode: %d\n", mode);
380 * m5mols_get_version - retrieve full revisions information of M-5MOLS
382 * The version information includes revisions of hardware and firmware,
383 * AutoFocus alghorithm version and the version string.
385 static int m5mols_get_version(struct v4l2_subdev *sd)
387 struct m5mols_info *info = to_m5mols(sd);
388 struct m5mols_version *ver = &info->ver;
393 ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer);
395 ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project);
397 ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw);
399 ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw);
401 ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param);
403 ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb);
405 ret = m5mols_read_u8(sd, AF_VERSION, &ver->af);
409 for (i = 0; i < VERSION_STRING_SIZE; i++) {
410 ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]);
415 ver->fw = be16_to_cpu(ver->fw);
416 ver->hw = be16_to_cpu(ver->hw);
417 ver->param = be16_to_cpu(ver->param);
418 ver->awb = be16_to_cpu(ver->awb);
420 v4l2_info(sd, "Manufacturer\t[%s]\n",
421 is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
422 "Samsung Electro-Machanics" :
423 is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
424 "Samsung Fiber-Optics" :
425 is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
426 "Samsung Techwin" : "None");
427 v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
428 info->ver.customer, info->ver.project);
430 if (!is_available_af(info))
431 v4l2_info(sd, "No support Auto Focus on this firmware\n");
437 * __find_restype - Lookup M-5MOLS resolution type according to pixel code
440 static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code)
442 enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
445 if (code == m5mols_default_ffmt[type].code)
447 } while (type++ != SIZE_DEFAULT_FFMT);
453 * __find_resolution - Lookup preset and type of M-5MOLS's resolution
454 * @mf: pixel format to find/negotiate the resolution preset for
455 * @type: M-5MOLS resolution type
456 * @resolution: M-5MOLS resolution preset register value
458 * Find nearest resolution matching resolution preset and adjust mf
459 * to supported values.
461 static int __find_resolution(struct v4l2_subdev *sd,
462 struct v4l2_mbus_framefmt *mf,
463 enum m5mols_restype *type,
466 const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
467 const struct m5mols_resolution *match = NULL;
468 enum m5mols_restype stype = __find_restype(mf->code);
469 int i = ARRAY_SIZE(m5mols_reg_res);
470 unsigned int min_err = ~0;
474 if (stype == fsize->type) {
475 err = abs(fsize->width - mf->width)
476 + abs(fsize->height - mf->height);
486 mf->width = match->width;
487 mf->height = match->height;
488 *resolution = match->reg;
496 static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
497 struct v4l2_subdev_fh *fh,
498 enum v4l2_subdev_format_whence which,
499 enum m5mols_restype type)
501 if (which == V4L2_SUBDEV_FORMAT_TRY)
502 return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
504 return &info->ffmt[type];
507 static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
508 struct v4l2_subdev_format *fmt)
510 struct m5mols_info *info = to_m5mols(sd);
511 struct v4l2_mbus_framefmt *format;
516 format = __find_format(info, fh, fmt->which, info->res_type);
520 fmt->format = *format;
524 static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
525 struct v4l2_subdev_format *fmt)
527 struct m5mols_info *info = to_m5mols(sd);
528 struct v4l2_mbus_framefmt *format = &fmt->format;
529 struct v4l2_mbus_framefmt *sfmt;
530 enum m5mols_restype type;
537 ret = __find_resolution(sd, format, &type, &resolution);
541 sfmt = __find_format(info, fh, fmt->which, type);
545 *sfmt = m5mols_default_ffmt[type];
546 sfmt->width = format->width;
547 sfmt->height = format->height;
549 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
550 info->resolution = resolution;
551 info->code = format->code;
552 info->res_type = type;
558 static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
559 struct v4l2_subdev_fh *fh,
560 struct v4l2_subdev_mbus_code_enum *code)
562 if (!code || code->index >= SIZE_DEFAULT_FFMT)
565 code->code = m5mols_default_ffmt[code->index].code;
570 static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
571 .enum_mbus_code = m5mols_enum_mbus_code,
572 .get_fmt = m5mols_get_fmt,
573 .set_fmt = m5mols_set_fmt,
577 * m5mols_sync_controls - Apply default scene mode and the current controls
579 * This is used only streaming for syncing between v4l2_ctrl framework and
580 * m5mols's controls. First, do the scenemode to the sensor, then call
581 * v4l2_ctrl_handler_setup. It can be same between some commands and
582 * the scenemode's in the default v4l2_ctrls. But, such commands of control
583 * should be prior to the scenemode's one.
585 int m5mols_sync_controls(struct m5mols_info *info)
589 if (!is_ctrl_synced(info)) {
590 ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
594 v4l2_ctrl_handler_setup(&info->handle);
595 info->ctrl_sync = true;
602 * m5mols_start_monitor - Start the monitor mode
604 * Before applying the controls setup the resolution and frame rate
605 * in PARAMETER mode, and then switch over to MONITOR mode.
607 static int m5mols_start_monitor(struct m5mols_info *info)
609 struct v4l2_subdev *sd = &info->sd;
612 ret = m5mols_mode(info, REG_PARAMETER);
614 ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
616 ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
618 ret = m5mols_mode(info, REG_MONITOR);
620 ret = m5mols_sync_controls(info);
625 static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
627 struct m5mols_info *info = to_m5mols(sd);
632 if (is_code(info->code, M5MOLS_RESTYPE_MONITOR))
633 ret = m5mols_start_monitor(info);
634 if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE))
635 ret = m5mols_start_capture(info);
640 return m5mols_mode(info, REG_PARAMETER);
643 static const struct v4l2_subdev_video_ops m5mols_video_ops = {
644 .s_stream = m5mols_s_stream,
647 static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
649 struct v4l2_subdev *sd = to_sd(ctrl);
650 struct m5mols_info *info = to_m5mols(sd);
653 info->mode_save = info->mode;
655 ret = m5mols_mode(info, REG_PARAMETER);
657 ret = m5mols_set_ctrl(ctrl);
659 ret = m5mols_mode(info, info->mode_save);
664 static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
665 .s_ctrl = m5mols_s_ctrl,
668 static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
670 struct v4l2_subdev *sd = &info->sd;
671 struct i2c_client *client = v4l2_get_subdevdata(sd);
672 const struct m5mols_platform_data *pdata = info->pdata;
676 if (is_powered(info))
679 if (info->set_power) {
680 ret = info->set_power(&client->dev, 1);
685 ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
687 info->set_power(&client->dev, 0);
691 gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
692 usleep_range(1000, 1000);
698 if (!is_powered(info))
701 ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
706 info->set_power(&client->dev, 0);
708 gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
709 usleep_range(1000, 1000);
715 /* m5mols_update_fw - optional firmware update routine */
716 int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
717 int (*set_power)(struct m5mols_info *, bool))
723 * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
725 * Booting internal ARM core makes the M-5MOLS is ready for getting commands
726 * with I2C. It's the first thing to be done after it powered up. It must wait
727 * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
729 static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
733 ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
739 ret = m5mols_get_version(sd);
741 ret = m5mols_update_fw(sd, m5mols_sensor_power);
745 v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
747 ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
749 ret = m5mols_enable_interrupt(sd, REG_INT_AF);
754 static int m5mols_init_controls(struct m5mols_info *info)
756 struct v4l2_subdev *sd = &info->sd;
761 /* Determine value's range & step of controls for various FW version */
762 ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure);
764 step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
768 v4l2_ctrl_handler_init(&info->handle, 6);
769 info->autowb = v4l2_ctrl_new_std(&info->handle,
770 &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
772 info->saturation = v4l2_ctrl_new_std(&info->handle,
773 &m5mols_ctrl_ops, V4L2_CID_SATURATION,
775 info->zoom = v4l2_ctrl_new_std(&info->handle,
776 &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
777 1, 70, step_zoom, 1);
778 info->exposure = v4l2_ctrl_new_std(&info->handle,
779 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
780 0, max_exposure, 1, (int)max_exposure/2);
781 info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
782 &m5mols_ctrl_ops, V4L2_CID_COLORFX,
783 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
784 info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
785 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
786 1, 0, V4L2_EXPOSURE_MANUAL);
788 sd->ctrl_handler = &info->handle;
789 if (info->handle.error) {
790 v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
791 v4l2_ctrl_handler_free(&info->handle);
792 return info->handle.error;
795 v4l2_ctrl_cluster(2, &info->autoexposure);
801 * m5mols_s_power - Main sensor power control function
803 * To prevent breaking the lens when the sensor is powered off the Soft-Landing
804 * algorithm is called where available. The Soft-Landing algorithm availability
805 * dependends on the firmware provider.
807 static int m5mols_s_power(struct v4l2_subdev *sd, int on)
809 struct m5mols_info *info = to_m5mols(sd);
813 ret = m5mols_sensor_power(info, true);
815 ret = m5mols_sensor_armboot(sd);
817 ret = m5mols_init_controls(info);
821 info->ffmt[M5MOLS_RESTYPE_MONITOR] =
822 m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
823 info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
824 m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
828 if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
829 ret = m5mols_mode(info, REG_MONITOR);
831 ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
833 ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
835 ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS,
838 v4l2_info(sd, "Success soft-landing lens\n");
841 ret = m5mols_sensor_power(info, false);
843 v4l2_ctrl_handler_free(&info->handle);
844 info->ctrl_sync = false;
850 static int m5mols_log_status(struct v4l2_subdev *sd)
852 struct m5mols_info *info = to_m5mols(sd);
854 v4l2_ctrl_handler_log_status(&info->handle, sd->name);
859 static const struct v4l2_subdev_core_ops m5mols_core_ops = {
860 .s_power = m5mols_s_power,
861 .g_ctrl = v4l2_subdev_g_ctrl,
862 .s_ctrl = v4l2_subdev_s_ctrl,
863 .queryctrl = v4l2_subdev_queryctrl,
864 .querymenu = v4l2_subdev_querymenu,
865 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
866 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
867 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
868 .log_status = m5mols_log_status,
871 static const struct v4l2_subdev_ops m5mols_ops = {
872 .core = &m5mols_core_ops,
873 .pad = &m5mols_pad_ops,
874 .video = &m5mols_video_ops,
877 static void m5mols_irq_work(struct work_struct *work)
879 struct m5mols_info *info =
880 container_of(work, struct m5mols_info, work_irq);
881 struct v4l2_subdev *sd = &info->sd;
885 if (!is_powered(info) ||
886 m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt))
889 switch (info->interrupt & REG_INT_MASK) {
891 if (!is_available_af(info))
893 ret = m5mols_read_u8(sd, AF_STATUS, ®);
894 v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
895 reg == REG_AF_FAIL ? "Failed" :
896 reg == REG_AF_SUCCESS ? "Success" :
897 reg == REG_AF_IDLE ? "Idle" : "Busy");
899 case REG_INT_CAPTURE:
900 if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
901 wake_up_interruptible(&info->irq_waitq);
903 v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
906 v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
911 static irqreturn_t m5mols_irq_handler(int irq, void *data)
913 struct v4l2_subdev *sd = data;
914 struct m5mols_info *info = to_m5mols(sd);
916 schedule_work(&info->work_irq);
921 static int __devinit m5mols_probe(struct i2c_client *client,
922 const struct i2c_device_id *id)
924 const struct m5mols_platform_data *pdata = client->dev.platform_data;
925 struct m5mols_info *info;
926 struct v4l2_subdev *sd;
930 dev_err(&client->dev, "No platform data\n");
934 if (!gpio_is_valid(pdata->gpio_reset)) {
935 dev_err(&client->dev, "No valid RESET GPIO specified\n");
940 dev_err(&client->dev, "Interrupt not assigned\n");
944 info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
949 info->set_power = pdata->set_power;
951 ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
953 dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
956 gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
958 ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
960 dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
965 strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
966 v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
968 info->pad.flags = MEDIA_PAD_FL_SOURCE;
969 ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
972 sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
974 init_waitqueue_head(&info->irq_waitq);
975 INIT_WORK(&info->work_irq, m5mols_irq_work);
976 ret = request_irq(client->irq, m5mols_irq_handler,
977 IRQF_TRIGGER_RISING, MODULE_NAME, sd);
979 dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
982 info->res_type = M5MOLS_RESTYPE_MONITOR;
985 media_entity_cleanup(&sd->entity);
987 regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
989 gpio_free(pdata->gpio_reset);
995 static int __devexit m5mols_remove(struct i2c_client *client)
997 struct v4l2_subdev *sd = i2c_get_clientdata(client);
998 struct m5mols_info *info = to_m5mols(sd);
1000 v4l2_device_unregister_subdev(sd);
1001 free_irq(client->irq, sd);
1003 regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
1004 gpio_free(info->pdata->gpio_reset);
1005 media_entity_cleanup(&sd->entity);
1010 static const struct i2c_device_id m5mols_id[] = {
1014 MODULE_DEVICE_TABLE(i2c, m5mols_id);
1016 static struct i2c_driver m5mols_i2c_driver = {
1018 .name = MODULE_NAME,
1020 .probe = m5mols_probe,
1021 .remove = __devexit_p(m5mols_remove),
1022 .id_table = m5mols_id,
1025 static int __init m5mols_mod_init(void)
1027 return i2c_add_driver(&m5mols_i2c_driver);
1030 static void __exit m5mols_mod_exit(void)
1032 i2c_del_driver(&m5mols_i2c_driver);
1035 module_init(m5mols_mod_init);
1036 module_exit(m5mols_mod_exit);
1038 MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
1039 MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
1040 MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
1041 MODULE_LICENSE("GPL");