[PATCH 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor

2012-07-17 Thread Sangwook Lee
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

2012-07-17 Thread David Cohen

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