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

2012-08-02 Thread Sangwook Lee
This driver implements preview mode of the S5K4ECGX sensor.
capture (snapshot) operation, face detection are missing now.

Following controls are supported:
contrast/saturation/brightness/sharpness

Signed-off-by: Sangwook Lee sangwook@linaro.org
---
 drivers/media/video/Kconfig|8 +
 drivers/media/video/Makefile   |1 +
 drivers/media/video/s5k4ecgx.c |  839 
 include/media/s5k4ecgx.h   |   39 ++
 4 files changed, 887 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 c128fac..2c3f434 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -580,6 +580,14 @@ 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 MEDIA_CAMERA_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 b7da9fa..ec39c47 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -80,6 +80,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..cfc90b8
--- /dev/null
+++ b/drivers/media/video/s5k4ecgx.c
@@ -0,0 +1,839 @@
+/*
+ * Driver for s5k4ecgx (5MP Camera) from Samsung
+ * a quarter-inch optical format 1.4 micron 5 megapixel (Mp)
+ * CMOS image sensor.
+ *
+ * Copyright (C) 2012, Linaro, Sangwook Lee sangwook@linaro.org
+ * Copyright (C) 2012, Insignal Co,. Ltd,  Homin Lee suap...@insignal.co.kr
+ *
+ * Based on s5k6aa, noon010pc30 driver
+ * Copyright (C) 2011, Samsung Electronics Co., Ltd.
+ *
+ * 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/clk.h
+#include linux/delay.h
+#include linux/gpio.h
+#include linux/i2c.h
+#include linux/module.h
+#include linux/regulator/consumer.h
+#include linux/slab.h
+#include linux/vmalloc.h
+
+#include media/media-entity.h
+#include media/s5k4ecgx.h
+#include media/v4l2-ctrls.h
+#include media/v4l2-device.h
+#include media/v4l2-mediabus.h
+#include media/v4l2-subdev.h
+
+#include s5k4ecgx_regs.h
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define S5K4ECGX_DRIVER_NAME   s5k4ecgx
+
+/* Firmware revision information */
+#define REG_FW_REVISION0x71a6
+#define REG_FW_VERSION 0x71a4
+#define S5K4ECGX_REVISION_1_1  0x11
+#define S5K4ECGX_FW_VERSION0x4ec0
+
+/* General purpose parameters */
+#define REG_USER_BRIGHTNESS0x722c /* Brigthness */
+#define REG_USER_CONTRAST  0x722e /* Contrast */
+#define REG_USER_SATURATION0x7230 /* Saturation */
+
+#define REG_USER_SHARP10x7a28
+#define REG_USER_SHARP20x7ade
+#define REG_USER_SHARP30x7b94
+#define REG_USER_SHARP40x7c4a
+#define REG_USER_SHARP50x7d00
+
+/* Reduce sharpness range for user space API */
+#define SHARPNESS_DIV  8208
+
+#define TOK_TERM   0x
+
+/*
+ * FIMXE: This is copied from s5k6aa, because of no information
+ * in s5k4ecgx's datasheet
+ * H/W register Interface (0xd000 - 0xdfff)
+ */
+#define AHB_MSB_ADDR_PTR   0xfcfc
+#define GEN_REG_OFFSH  0xd000
+#define REG_CMDWR_ADDRH0x0028
+#define REG_CMDWR_ADDRL0x002a
+#define REG_CMDRD_ADDRH0x002c
+#define REG_CMDRD_ADDRL0x002e
+#define REG_CMDBUF0_ADDR   0x0f12
+
+/*
+ * Preview size lists supported by sensor
+ */
+static const struct regval_list *prev_regs[] = {
+   s5k4ecgx_176_preview,
+   s5k4ecgx_352_preview,
+   s5k4ecgx_640_preview,
+   s5k4ecgx_720_preview,
+};
+
+struct s5k4ecgx_frmsize {
+   u32 idx; /* Should 

Re: [PATH v3 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor

2012-08-02 Thread Sylwester Nawrocki
On 08/02/2012 03:42 PM, Sangwook Lee wrote:
 This driver implements preview mode of the S5K4ECGX sensor.
 capture (snapshot) operation, face detection are missing now.
 
 Following controls are supported:
 contrast/saturation/brightness/sharpness
 
 Signed-off-by: Sangwook 
 Leesangwook.lee-qsej5fyqhm4dnm+yrof...@public.gmane.org
 ---
...
 +static const char * const s5k4ecgx_supply_names[] = {
 + /*
 +  * vdd_2.8v is for Analog power supply 2.8V(vdda)
 +  * and Digital IO(vddio, vddd_core)
 +  */
 + vdd_2.8v,

Might be better to avoid voltage value in regulator supply names. Can you
just make it on of: vdda, vddio, vddcore ? On some systems all 3 power pads
might be used and all 3 voltage supply names might be needed. I guess it can
be changed if there is a need for it. Also we could specify all 3 entries as
above and add such regulator supply names at a corresponding regulator.

 + /* vdd_1.8v is for regulator input */
 + vdd_1.8v,

I would suggest just using vddreg.

 +static int s5k4ecgx_write(struct i2c_client *client, u32 addr, u16 val)
 +{
 + int ret = 0;

Unneeded initialization.

 + u16 high = addr  16, low =  addr  0x;
 +
 + ret = s5k4ecgx_i2c_write(client, REG_CMDWR_ADDRH, high);
 + ret |= s5k4ecgx_i2c_write(client, REG_CMDWR_ADDRL, low);
 + ret |= s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR, val);
 + if (ret)
 + return -ENODEV;
 +
 + return 0;
 +}
 +
 +static int s5k4ecgx_read(struct i2c_client *client, u32 addr, u16 *val)
 +{
 + int ret = 0;

Ditto.

 + u16 high = addr  16, low =  addr  0x;
 +
 + ret  = s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRH, high);
 + ret  |= s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRL, low);
 + ret  |= s5k4ecgx_i2c_read(client, REG_CMDBUF0_ADDR, val);
 + if (ret) {
 + dev_err(client-dev, Failed to execute read command\n);
 + return -ENODEV;
 + }
 +
 + return 0;
 +}
 +
 +static int s5k4ecgx_set_ahb_address(struct v4l2_subdev *sd)
 +{
 + int ret;
 + struct i2c_client *client = v4l2_get_subdevdata(sd);
 +
 + /* Set APB peripherals start address */
 + ret = s5k4ecgx_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH);
 + if (ret)
 + return ret;
 + /*
 +  * FIMXE: This is copied from s5k6aa, because of no information
 +  * in s5k4ecgx's datasheet.
 +  * sw_reset is activated to put device into idle status
 +  */
 + ret = s5k4ecgx_i2c_write(client, 0x0010, 0x0001);
 + if (ret)
 + return ret;
 +
 + /* FIXME: no information avaialbe about this register */

avaialbe - available

 + ret = s5k4ecgx_i2c_write(client, 0x1030, 0x);
 + if (ret)
 + return ret;
 + /* Halt ARM CPU */
 + ret = s5k4ecgx_i2c_write(client, 0x0014, 0x0001);
 +
 + return ret;

return s5k4ecgx_i2c_write(...); ?
 +}
 +
 +static int s5k4ecgx_write_array(struct v4l2_subdev *sd,
 + const struct regval_list *reg)
 +{
 + struct i2c_client *client = v4l2_get_subdevdata(sd);
 + u16 addr_incr = 0;
 + int ret = 0;

Unneeded initialization.

 +
 + while (reg-addr != TOK_TERM) {
 + if (addr_incr != 2)
 + ret = s5k4ecgx_write(client, reg-addr, reg-val);
 + else
 + ret = s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR,
 + reg-val);
 + if (ret)
 + break;
 + /* Assume that msg-addr is always less than 0xfffc */
 + addr_incr = (reg + 1)-addr - reg-addr;
 + reg++;
 + }
 +
 + return ret;
 +}
...
 +
 +static int s5k4ecgx_init_sensor(struct v4l2_subdev *sd)
 +{
 + int ret = 0;

Ditto.

 +
 + ret = s5k4ecgx_set_ahb_address(sd);
 + /* The delay is from manufacturer's settings */
 + msleep(100);
 +
 + ret |= s5k4ecgx_write_array(sd, s5k4ecgx_apb_regs);
 + ret |= s5k4ecgx_write_array(sd, s5k4ecgx_img_regs);
 +
 + if (ret)
 + v4l2_err(sd, Failed to write initial settings\n);
 +
 + return 0;
 +}
 +
...
 +static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl)
 +{
 +
 + struct v4l2_subdev *sd =container_of(ctrl-handler, struct s5k4ecgx,
 + handler)-sd;
 + struct i2c_client *client = v4l2_get_subdevdata(sd);
 + struct s5k4ecgx *priv = to_s5k4ecgx(sd);
 + int err = 0;

Unneded initilization.

 +
 + 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(client, REG_USER_CONTRAST, ctrl-val);
 + break;
 +
 + case V4L2_CID_SATURATION:
 + err = s5k4ecgx_write(client, REG_USER_SATURATION, ctrl-val);
 + break;
 +
 + case V4L2_CID_SHARPNESS:
 + ctrl-val *= SHARPNESS_DIV;
 + err |=