Re: [RFC PATCH v5] media: add v4l2 subdev driver for S5K4ECGX sensor

2012-09-06 Thread Sangwook Lee
Hi Sylwester

Thank you for the review again.

On 5 September 2012 22:56, Sylwester Nawrocki
 wrote:
> Hi Sangwook,
>
> On 09/05/2012 02:28 PM, Sangwook Lee wrote:
[snip]
>> +#include
>
> What do we need this header for ?

Ok, let me delete this.

>
>> +
>> +#include
>> +#include
>> +#include
>> +#include
>> +#include
>> +#include
> ...
>> +
>> +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;
>> + /*
>> +  * FIXME: 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 available about this register */
>
> Let's drop that comment, we will fix all magic numbers once proper
> documentation is available.

Ok.

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

OK, I will fix this.

>> +}
>> +
>> +#define FW_HEAD 6
>> +/* Register address, value are 4, 2 bytes */
>> +#define FW_REG_SIZE 6
>
> FW_REG_SIZE is a bit confusing, maybe we could name this FW_RECORD_SIZE
> or something similar ?

Fair enough

>
>> +/*
>> + * Firmware has the following format:
>> + *,<  record 0>,
>> + *<  record N - 1>,<  CRC32-CCITT (4-bytes)>
>> + * where "record" is a 4-byte register address followed by 2-byte
>> + * register value (little endian)
>> + */
>> +static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
>> +{
>> + const struct firmware *fw;
>> + int err, i, regs_num;
>> + struct i2c_client *client = v4l2_get_subdevdata(sd);
>> + u16 val;
>> + u32 addr, crc, crc_file, addr_inc = 0;
>> + u8 *fwbuf;
>> +
>> + err = request_firmware(&fw, S5K4ECGX_FIRMWARE, sd->v4l2_dev->dev);
>> + if (err) {
>> + v4l2_err(sd, "Failed to read firmware %s\n", 
>> S5K4ECGX_FIRMWARE);
>> + goto fw_out1;
>
> return err;

OK, I will fix this.

>
> ?
>> + }
>> + fwbuf = kmemdup(fw->data, fw->size, GFP_KERNEL);
>
> Why do we need this kmemdup ? Couldn't we just use fw->data ?

OK,  Iet me reconsider this.

>
>> + if (!fwbuf) {
>> + err = -ENOMEM;
>> + goto fw_out2;
>> + }
>> + crc_file = *(u32 *)(fwbuf + regs_num * FW_REG_SIZE);
>
> regs_num is uninitialized ?
>
>> + crc = crc32_le(~0, fwbuf, regs_num * FW_REG_SIZE);
>> + if (crc != crc_file) {
>> + v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file);
>> + err = -EINVAL;
>> + goto fw_out3;
>> + }
>> + regs_num = *(u32 *)(fwbuf);
>
> I guess this needs to be moved up. I would make it
>
> regs_num = le32_to_cpu(*(u32 *)fw->data);
>
> And perhaps we need a check like:
>
> if (fw->size < regs_num * FW_REG_SIZE)
> return -EINVAL;
> ?
>> + v4l2_dbg(3, debug, sd, "FW: %s size %d register sets %d\n",
>> +  S5K4ECGX_FIRMWARE, fw->size, regs_num);
>> + regs_num++; /* Add header */
>> + for (i = 1; i<  regs_num; i++) {
>> + addr = *(u32 *)(fwbuf + i * FW_REG_SIZE);
>> + val = *(u16 *)(fwbuf + i * FW_REG_SIZE + 4);
>
> I think you need to access addr and val through le32_to_cpu() as well,
> even though your ARM system might be little-endian by default, this
> driver could possibly be used on machines with different endianness.
>
> Something like this could be more optimal:
>
> const u8 *ptr = fw->data + FW_REG_SIZE;
>
> for (i = 1; i < regs_num; i++) {
> addr = le32_to_cpu(*(u32 *)ptr);
> ptr += 4;
> val = le16_to_cpu(*(u16 *)ptr);
> ptr += FW_REG_SIZE;
>

Thanks for your advice. I will take le32(16)_to_cpu.


>> + if (addr - addr_inc != 2)
>> + err = s5k4ecgx_write(client, addr, val);
>> + else
>> + err = s5k4ecgx_i2c_write(client, REG_CMDBUF0_ADDR, 
>> val);
>> + if (err)
>> + goto fw_out3;
>
> nit: break instead of goto ?
Ok, I will fix this.

>
>> + addr_inc = addr;
>> + }
>> +fw_out3:
>> + kfree(fwbuf);
>> +fw_out2:
>> + release_firmware(fw);
>> +fw_out1:
>> +
>> + return err;
>> +}
> ...
>> +static int s5k4ecgx_init_sensor(struct v4l2_subdev *sd)
>> +{
>> + int ret;
>> +
>> + ret = s5k4ecgx_set_ahb_address(sd);
>> + /* The delay is from manufacturer's settings */
>> + msleep(100);

Re: [RFC PATCH v5] media: add v4l2 subdev driver for S5K4ECGX sensor

2012-09-05 Thread Sylwester Nawrocki
Hi Sangwook,

On 09/05/2012 02:28 PM, Sangwook Lee wrote:
> This patch adds driver for S5K4ECGX sensor with embedded ISP SoC,
> S5K4ECGX, which is a 5M CMOS Image sensor from Samsung
> The 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
> Cc: Sylwester Nawrocki
> Cc: Scott Bambrough

Overall it looks good, thank you for patiently addressing all my 
comments ;) There might be some rough edges here and there, but it's 
all easy to fix. Please see below.


Reviewed-by: Sylwester Nawrocki 

> ---
> Changes since v4:
> - replaced register tables with the function from Sylwester
> - updated firmware parsing function with CRC32 check
>firmware generator from user space:
>git://git.linaro.org/people/sangwook/fimc-v4l2-app.git
> 
> Changes since v3:
> - used request_firmware to configure initial settings
> - added parsing functions to read initial settings
> - updated regulator API
> - reduced preview setting tables by experiment
> 
> Changes since v2:
> - added GPIO (reset/stby) and regulators
> - updated I2C read/write, based on s5k6aa datasheet
> - fixed set_fmt errors
> - reduced register tables a bit
> - removed vmalloc
> 
> Changes since v1:
> - fixed s_stream(0) when it called twice
> - changed mutex_X position to be used when strictly necessary
> - add additional s_power(0) in case that error happens
> - update more accurate debugging statements
> - remove dummy else
> 
>   drivers/media/i2c/Kconfig|7 +
>   drivers/media/i2c/Makefile   |1 +
>   drivers/media/i2c/s5k4ecgx.c | 1019 
> ++
>   include/media/s5k4ecgx.h |   37 ++
>   4 files changed, 1064 insertions(+)
>   create mode 100644 drivers/media/i2c/s5k4ecgx.c
>   create mode 100644 include/media/s5k4ecgx.h
> 
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 9a5a059..55b3bbb 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -484,6 +484,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/i2c/smiapp/Kconfig"
> 
>   comment "Flash devices"
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index 088a460..a720812 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
>   obj-$(CONFIG_VIDEO_SR030PC30)   += sr030pc30.o
>   obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
>   obj-$(CONFIG_VIDEO_S5K6AA)  += s5k6aa.o
> +obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o
>   obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
>   obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
>   obj-$(CONFIG_VIDEO_SMIAPP_PLL)  += smiapp-pll.o
> diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
> new file mode 100644
> index 000..0f12d46
> --- /dev/null
> +++ b/drivers/media/i2c/s5k4ecgx.c
> @@ -0,0 +1,1019 @@
> +/*
> + * 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
> + * Copyright (C) 2012, Insignal Co,. Ltd,  Homin Lee
> + *
> + * 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
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include

What do we need this header for ?

> +
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
...
> +
> +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;
> + /*
> +  * FIXME: 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