[PATCH 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor
This dirver implements preview mode of the S5K4ECGX sensor. capture (snapshot) operation, face detection are missing now. Following controls are supported: contrast/saturation/birghtness/sharpness Signed-off-by: Sangwook Lee sangwook@linaro.org --- drivers/media/video/Kconfig|7 + drivers/media/video/Makefile |1 + drivers/media/video/s5k4ecgx.c | 871 include/media/s5k4ecgx.h | 29 ++ 4 files changed, 908 insertions(+) create mode 100644 drivers/media/video/s5k4ecgx.c create mode 100644 include/media/s5k4ecgx.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 99937c9..45d7f99 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -559,6 +559,13 @@ config VIDEO_S5K6AA This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M camera sensor with an embedded SoC image signal processor. +config VIDEO_S5K4ECGX +tristate Samsung S5K4ECGX sensor support +depends on I2C VIDEO_V4L2 VIDEO_V4L2_SUBDEV_API +---help--- + This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M + camera sensor with an embedded SoC image signal processor. + source drivers/media/video/smiapp/Kconfig comment Flash devices diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index d209de0..605bf35 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o obj-$(CONFIG_VIDEO_NOON010PC30)+= noon010pc30.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o +obj-$(CONFIG_VIDEO_S5K4ECGX)+= s5k4ecgx.o obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/ obj-$(CONFIG_VIDEO_ADP1653)+= adp1653.o obj-$(CONFIG_VIDEO_AS3645A)+= as3645a.o diff --git a/drivers/media/video/s5k4ecgx.c b/drivers/media/video/s5k4ecgx.c new file mode 100644 index 000..68a1977 --- /dev/null +++ b/drivers/media/video/s5k4ecgx.c @@ -0,0 +1,871 @@ +/* + * Driver for s5k4ecgx (5MP Camera) from SAMSUNG + * a quarter-inch optical format 1.4 micron 5 megapixel (Mp) + * CMOS image sensor, as reffering to s5k6aa.c + * + * Copyright (C) 2012, Linaro, Sangwook Lee sangwook@linaro.org + * Copyright (C) 2012, Insignal Co,. Ltd, Homin Lee suap...@insignal.co.kr + * Copyright (C) 2011, SAMSUNG ELECTRONICS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/module.h +#include linux/i2c.h +#include linux/delay.h +#include linux/vmalloc.h +#include linux/slab.h + +#include media/v4l2-device.h +#include media/v4l2-subdev.h +#include media/media-entity.h +#include media/v4l2-ctrls.h +#include media/v4l2-mediabus.h +#include media/s5k4ecgx.h + +#include s5k4ecgx_regs.h + +static int debug; +module_param(debug, int, 0644); + +#define S5K4ECGX_DRIVER_NAME s5k4ecgx + +/* Basic windows sizes */ +#define S5K4ECGX_OUT_WIDTH_DEF 640 +#define S5K4ECGX_OUT_HEIGHT_DEF480 +#define S5K4ECGX_WIN_WIDTH_MAX 1024 +#define S5K4ECGX_WIN_HEIGHT_MAX600 +#define S5K4ECGX_WIN_WIDTH_MIN 176 +#define S5K4ECGX_WIN_HEIGHT_MIN144 + +/* Firmware revision information */ +#define S5K4ECGX_REVISION_1_1 0x11 +#define S5K4ECGX_FW_VERSION0x4EC0 +#define REG_FW_VERSION 0x71A4 +#define REG_FW_REVISION0x71A6 + +/* For now we use only one user configuration register set */ +#define S5K4ECGX_MAX_PRESETS 1 + +/* Review this depending on system */ +#define S5K4ECGX_POLL_TIME 1 /* ms */ + +/* General purpose parameters */ +#define REG_USER_BRIGHTNESS0x722C /* Brigthness */ +#define REG_USER_CONTRAST 0x722E /* Contrast */ +#define REG_USER_SATURATION0x7230 /* Saturation */ + +/* FIXME: No information availble about these register from the datasheet */ +#define REG_USER_SHARP10x7A28 +#define REG_USER_SHARP20x7ADE +#define REG_USER_SHARP30x7B94 +#define REG_USER_SHARP40x7C4A +#define REG_USER_SHARP50x7D00 + +#define LSB(X) (((X) 0xFF)) +#define MSB(Y) (((Y) 8) 0xFF) + +/* + * Preview size lists supported by sensor + */ +struct regval_list *pview_size[] = { + s5k4ecgx_176_preview, + s5k4ecgx_352_preview, + s5k4ecgx_640_preview, + s5k4ecgx_720_preview, +}; + +struct s5k4ecgx_framesize { + u32 idx; /* Should indicate index of pview_size */ + u32 width; + u32 height; +}; + +/* + * TODO: currently only preview is supported and snapshopt(capture) + * is not
Re: [PATCH 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor
Hi Sangwook, I've few comments, some just nitpicking. Feel free to disagree. :) On 07/17/2012 07:17 PM, Sangwook Lee wrote: This dirver implements preview mode of the S5K4ECGX sensor. capture (snapshot) operation, face detection are missing now. Following controls are supported: contrast/saturation/birghtness/sharpness Signed-off-by: Sangwook Lee sangwook@linaro.org --- drivers/media/video/Kconfig|7 + drivers/media/video/Makefile |1 + drivers/media/video/s5k4ecgx.c | 871 include/media/s5k4ecgx.h | 29 ++ 4 files changed, 908 insertions(+) create mode 100644 drivers/media/video/s5k4ecgx.c create mode 100644 include/media/s5k4ecgx.h [snip] +/* + * V4L2 subdev controls + */ +static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl) +{ + + struct v4l2_subdev *sd = container_of(ctrl-handler, struct s5k4ecgx, + handler)-sd; + struct s5k4ecgx *priv = to_s5k4ecgx(sd); + int err = 0; + + v4l2_dbg(1, debug, sd, ctrl: 0x%x, value: %d\n, ctrl-id, ctrl-val); + mutex_lock(priv-lock); + + switch (ctrl-id) { + case V4L2_CID_CONTRAST: + err = s5k4ecgx_write_ctrl(sd, REG_USER_CONTRAST, ctrl-val); + break; + + case V4L2_CID_SATURATION: + err = s5k4ecgx_write_ctrl(sd, REG_USER_SATURATION, ctrl-val); + break; + + case V4L2_CID_SHARPNESS: + err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP1, ctrl-val); + err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP2, ctrl-val); + err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP3, ctrl-val); + err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP4, ctrl-val); + err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP5, ctrl-val); + break; + + case V4L2_CID_BRIGHTNESS: + err = s5k4ecgx_write_ctrl(sd, REG_USER_BRIGHTNESS, ctrl-val); + break; + default: + v4l2_dbg(1, debug, sd, unknown set ctrl id 0x%x\n, ctrl-id); + err = -ENOIOCTLCMD; + break; + } + + /* Review this */ + priv-reg_type = TOK_TERM; + + if (err 0) + v4l2_err(sd, Failed to write videoc_s_ctrl err %d\n, err); I like to hold locks only when strictly necessary. You could write this error message after it's released. + mutex_unlock(priv-lock); + + return err; +} + +static const struct v4l2_ctrl_ops s5k4ecgx_ctrl_ops = { + .s_ctrl = s5k4ecgx_s_ctrl, +}; + +/* + * Reading s5k4ecgx version information + */ +static int s5k4ecgx_registered(struct v4l2_subdev *sd) +{ + struct s5k4ecgx *priv = to_s5k4ecgx(sd); + int ret; + + if (!priv-set_power) { + v4l2_err(sd, Failed to call power-up function!\n); Maybe it's more accurate to say function isn't set. + return -EIO; + } + + mutex_lock(priv-lock); + priv-set_power(true); + /* Time to stablize sensor */ + mdelay(priv-mdelay); + ret = s5k4ecgx_read_fw_ver(sd); + priv-set_power(false); + mutex_unlock(priv-lock); + + return ret; +} + +/* + * V4L2 subdev internal operations + */ +static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); + + format-colorspace = s5k4ecgx_formats[0].colorspace; + format-code = s5k4ecgx_formats[0].code; + format-width = S5K4ECGX_OUT_WIDTH_DEF; + format-height = S5K4ECGX_OUT_HEIGHT_DEF; + format-field = V4L2_FIELD_NONE; + + crop-width = S5K4ECGX_WIN_WIDTH_MAX; + crop-height = S5K4ECGX_WIN_HEIGHT_MAX; + crop-left = 0; + crop-top = 0; + + return 0; +} + + +static const struct v4l2_subdev_internal_ops s5k4ecgx_subdev_internal_ops = { + .registered = s5k4ecgx_registered, + .open = s5k4ecgx_open, +}; + +static int s5k4ecgx_s_power(struct v4l2_subdev *sd, int val) +{ + struct s5k4ecgx *priv = to_s5k4ecgx(sd); + + if (!priv-set_power) + return -EIO; + + v4l2_dbg(1, debug, sd, Switching %s\n, val ? on : off); + + if (val) { + priv-set_power(val); + /* Time to stablize sensor */ + mdelay(priv-mdelay); + /* Loading firmware into ARM7 core of sensor */ + if (s5k4ecgx_write_array(sd, s5k4ecgx_init_regs) 0) + return -EIO; Shouldn't you s_power(0) in case of error? + s5k4ecgx_init_parameters(sd); + } else { + priv-set_power(val); + } + + return 0; +} + +static int s5k4ecgx_log_status(struct v4l2_subdev *sd) +{ + v4l2_ctrl_handler_log_status(sd-ctrl_handler, sd-name); + + return 0; +} + +static const struct