Re: [PATCH v9] Add support for M-5MOLS 8 Mega Pixel camera ISP

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, May 26, 2011 at 04:12:47PM +0900, Kim, HeungJun wrote:
> Hi Sakari,

Hi HeungJun,

> 2011-05-25 ?????? 10:54, Sakari Ailus ??? ???:
> > Hi HeungJun,
> > 
> > Thanks for the patch!
> Also, thanks for the interests of this driver!

You'we welcome! :-)

> > 
> > I'm happy to see that Samsung is interested in getting such a driver to
> > mainline. :-) I suppose that theoretically nothing would prevent plugging
> > such a sensor to the OMAP 3 ISP, for example. It's just that the sensor
> > already does image processing and the ISP might not be that useful because
> > of this. But the interfaces would match, both in software and in hardware.
> This sensor(actually integrated ISP functionality as you know) is powerful,
> and I think this driver can help to make the controls for digital camera.
> 
> But, TI OMAP 3 has also ISP independently, so I think having the ISP module
> in the Processor is more better option cause of choice of various sensors,
> although the driver's developer has more issues which should be handled.
> 
> I hope to handle ISP directly in the Samsung Processor.
> 
> > 
> > This is a subdev driver and uses the control framework. Good. I have
> > comments on the code below. 
> Before that, this driver is already merged in Mauro's branch, and
> I have spent a few months making this drivers for submitting this.
> Some of your comments looks good and needed for this driver.
> But, if I fix this and resend it and another comments happened,
> this may be endless alone fight to reach "mergeing". :)

Sounds good to me. I have a few additional comments.

> So, I want that I keep this comments in mind, and I'll guarantee the fixes
> will be adapted the next time by type of the patch, after this driver patch
> is merged fully in 3.0.
[clip]

> >> +/**
> >> + * struct m5mols_version - firmware version information
> >> + * @customer:	customer information
> >> + * @project:	version of project information according to customer
> >> + * @fw:		firmware revision
> >> + * @hw:		hardware revision
> >> + * @param:	version of the parameter
> >> + * @awb:	Auto WhiteBalance algorithm version
> >> + * @str:	information about manufacturer and packaging vendor
> >> + * @af:		Auto Focus version
> >> + *
> >> + * The register offset starts the customer version at 0x0, and it ends
> >> + * the awb version at 0x09. The customer, project information occupies 1 bytes
> >> + * each. And also the fw, hw, param, awb each requires 2 bytes. The str is
> >> + * unique string associated with firmware's version. It includes information
> >> + * about manufacturer and the vendor of the sensor's packaging. The least
> >> + * significant 2 bytes of the string indicate packaging manufacturer.
> >> + */
> >> +#define VERSION_STRING_SIZE	22
> >> +struct m5mols_version {
> >> +	u8	customer;
> >> +	u8	project;
> >> +	u16	fw;
> >> +	u16	hw;
> >> +	u16	param;
> >> +	u16	awb;
> >> +	u8	str[VERSION_STRING_SIZE];
> >> +	u8	af;
> >> +};
> >> +#define VERSION_SIZE sizeof(struct m5mols_version)
> > 
> > You're using VERSION_SIZE in two places in one function. Is that worth
> > making it a macro? :-)
> Just make for being readable. Until this 9th version of this patch,
> I'm very taking care of over 80 character and for being readable.
> Updating each version, any other word is not used MACRO, and the other word
> need more space, on each line. At the next version, it happened that
> the one not used MACRO should use MACRO. And switching like this
> will be continued repedately.
> 
> So, I think it's no meaningless to use just twice. and want to fix.
> 
> And the other thing commented as belows, are most of same reason.

I'm fine with this.

> > 
> > I think you should add attribute ((packed)) to the definition as well.
> It looks needed. I added attibute packed for this struct for the next time.
> 
> > 
> >> +/**
> >> + * struct m5mols_info - M-5MOLS driver data structure
> >> + * @pdata: platform data
> >> + * @sd: v4l-subdev instance
> >> + * @pad: media pad
> >> + * @ffmt: current fmt according to resolution type
> >> + * @res_type: current resolution type
> >> + * @code: current code
> >> + * @irq_waitq: waitqueue for the capture
> >> + * @work_irq: workqueue for the IRQ
> >> + * @flags: state variable for the interrupt handler
> >> + * @handle: control handler
> >> + * @autoexposure: Auto Exposure control
> >> + * @exposure: Exposure control
> >> + * @autowb: Auto White Balance control
> >> + * @colorfx: Color effect control
> >> + * @saturation:	Saturation control
> >> + * @zoom: Zoom control
> >> + * @ver: information of the version
> >> + * @cap: the capture mode attributes
> >> + * @power: current sensor's power status
> >> + * @ctrl_sync: true means all controls of the sensor are initialized
> >> + * @int_capture: true means the capture interrupt is issued once
> >> + * @lock_ae: true means the Auto Exposure is locked
> >> + * @lock_awb: true means the Aut WhiteBalance is locked
> >> + * @resolution:	register value for current resolution
> >> + * @interrupt: register value for current interrupt status
> >> + * @mode: register value for current operation mode
> >> + * @mode_save: register value for current operation mode for saving
> >> + * @set_power: optional power callback to the board code
> >> + */
> >> +struct m5mols_info {
> >> +	const struct m5mols_platform_data *pdata;
> >> +	struct v4l2_subdev sd;
> >> +	struct media_pad pad;
> >> +	struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
> >> +	int res_type;
> >> +	enum v4l2_mbus_pixelcode code;
> >> +	wait_queue_head_t irq_waitq;
> >> +	struct work_struct work_irq;
> >> +	unsigned long flags;
> > 
> > You want to keep flags in the stack, not in a context independent location.
> > This will move to functions which actually use it.
> I don't understand well what you mean "stack" and "context". Sorry for lack of
> English skill. Tell me more specific detailed.

Please ignore my previous comment on this. In confused this with something
else.

> And as I tell about this variable "flags", this should be shared in the two files,
> m5mols_capture.c and m5mols_core.c. 
> 
> > 
> >> +
> >> +	struct v4l2_ctrl_handler handle;
> >> +	/* Autoexposure/exposure control cluster */
> >> +	struct {
> >> +		struct v4l2_ctrl *autoexposure;
> >> +		struct v4l2_ctrl *exposure;
> >> +	};
> > 
> > Would it be different without the anonymous struct?
> These two v4l2_ctrl is clustered. So, anonymous struct should be used
> for v4l2_ctrl_cluster().

It makes no difference in how the pointers are arranged in the memory.

[clip]

> >> +	[REG_SCENE_FIRE] = {
> >> +		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
> >> +		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
> >> +		REG_AF_NORMAL, REG_FD_OFF,
> >> +		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
> >> +		6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
> >> +	},
> >> +	[REG_SCENE_TEXT] = {
> >> +		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
> >> +		REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
> >> +		REG_AF_MACRO, REG_FD_OFF,
> >> +		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
> >> +		6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
> >> +	},
> >> +	[REG_SCENE_CANDLE] = {
> >> +		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
> >> +		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
> >> +		REG_AF_NORMAL, REG_FD_OFF,
> >> +		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
> >> +		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
> >> +	},
> > 
> > As it seems this functionality is dynamically configurable, and much of that
> > looks like something user space might want to choose independently,
> It's not. The preset itself can be user space APIs, but the order and procedure
> should be handled in the driver or kernel, at least in this case.
> 
> The wrong order and missing command are not completed the one of scenemode.
> 
> > shouldn't the underlying low level controls be exposed to user space as
> > such?
> > 
> > There definitely are different approaches to this; providing higher level
> > interface is restricting but on the other hand it may be better depending on
> > an application.
> > 
> > Some of these parameters would already have a V4L2 control for them.
> Actually, I have a plan to prepare RFC to expose some controls and
> things related with control timing. :)

I'm looking forward to this. Control timing is also something I'm interested
in.

> Briefly saying that, the current control framework can handle independently,
> but it's possible to handle any control attached the other control(s).
> So, some controls to supposed to be attached is combined with final specific control,
> or IOCTL, and if any specific control is called by user, the other controls
> is doing by orderly.
> 
> The benefit of such thing, is easy to handle controls in the user defined
> circumstance like camera, more user-friendly. And, at the kernel or driver side,
> it's supported only things which the device proivde.
> The driver's code will be simple and the user is happy.
> 
> Anyway, this is not part of this story, so let's talk about this later.

[clip]

> >> diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
> >> new file mode 100644
> >> index 0000000..76eac26
> >> --- /dev/null
> >> +++ b/drivers/media/video/m5mols/m5mols_core.c
> >> @@ -0,0 +1,1004 @@
> >> +/*
> >> + * Driver for M-5MOLS 8M Pixel camera sensor with ISP
> >> + *
> >> + * Copyright (C) 2011 Samsung Electronics Co., Ltd.
> >> + * Author: HeungJun Kim, riverful.kim@xxxxxxxxxxx
> >> + *
> >> + * Copyright (C) 2009 Samsung Electronics Co., Ltd.
> >> + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@xxxxxxxxxxx
> >> + *
> >> + * 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/i2c.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/irq.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/delay.h>
> >> +#include <linux/version.h>
> >> +#include <linux/gpio.h>
> >> +#include <linux/regulator/consumer.h>
> >> +#include <linux/videodev2.h>
> >> +#include <media/v4l2-ctrls.h>
> >> +#include <media/v4l2-device.h>
> >> +#include <media/v4l2-subdev.h>
> >> +#include <media/m5mols.h>
> >> +
> >> +#include "m5mols.h"
> >> +#include "m5mols_reg.h"
> >> +
> >> +int m5mols_debug;
> >> +module_param(m5mols_debug, int, 0644);
> >> +
> >> +#define MODULE_NAME		"M5MOLS"
> >> +#define M5MOLS_I2C_CHECK_RETRY	500
> >> +
> >> +/* The regulator consumer names for external voltage regulators */
> >> +static struct regulator_bulk_data supplies[] = {
> >> +	{
> >> +		.supply = "core",	/* ARM core power, 1.2V */
> >> +	}, {
> >> +		.supply	= "dig_18",	/* digital power 1, 1.8V */
> >> +	}, {
> >> +		.supply	= "d_sensor",	/* sensor power 1, 1.8V */
> >> +	}, {
> >> +		.supply	= "dig_28",	/* digital power 2, 2.8V */
> >> +	}, {
> >> +		.supply	= "a_sensor",	/* analog power */
> >> +	}, {
> >> +		.supply	= "dig_12",	/* digital power 3, 1.2V */
> >> +	},
> >> +};
> > 
> > This looks like something that belongs to board code, or perhaps in the near
> > future, to the device tree. The power supplies that are required by a device
> > is highly board dependent.
> If the regulator name is not common all M-5MOLS, You're right.
> But the regulator name of M-5MOLS is fixed.

As far as I understand, M-5MOLS is a sensor which you can, in principle,
attach to more or less random hardware. The regulators are not part of the
sensor. If someone adds a board which has regulators names or otherwise
arranged differently, this change must be done at that time.

> The benefit fixed in the driver helps that the developer can attach the driver,
> if he/she knows the names of regulators.
> 
> Commonly, you're right, but in this case(documented accurately with M-5MOLS
> datasheet), it's better.
>  
[clip]

> >> +int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
> >> +{
> >> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> >> +	u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
> >> +	u8 category = I2C_CATEGORY(reg);
> >> +	u8 cmd = I2C_COMMAND(reg);
> >> +	u8 size	= I2C_SIZE(reg);
> >> +	u32 *buf = (u32 *)&wbuf[4];
> >> +	struct i2c_msg msg[1];
> >> +	int ret;
> >> +
> >> +	if (!client->adapter)
> >> +		return -ENODEV;
> >> +
> >> +	if (size != 1 && size != 2 && size != 4) {
> > 
> > You could define sizes for the types, e.g.
> > 
> > #define I2C_SIZE_U8	1
> I already try to do like this, using width as definition.
> But it makes many lines over 80 characters. Moreover, using just number
> is more simple in this case.

Wrapping lines is also possible but sometimes it's just better not to.

> Ditto - over 80 characters.
> 
> > 
> >> +		v4l2_err(sd, "Wrong data size\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	msg->addr = client->addr;
> >> +	msg->flags = 0;
> >> +	msg->len = (u16)size + 4;
> >> +	msg->buf = wbuf;
> >> +	wbuf[0] = size + 4;
> >> +	wbuf[1] = M5MOLS_BYTE_WRITE;
> >> +	wbuf[2] = category;
> >> +	wbuf[3] = cmd;
> >> +
> >> +	*buf = m5mols_swap_byte((u8 *)&val, size);
> >> +
> >> +	usleep_range(200, 200);
> > 
> > Why to sleep always? Does the sensor require a delay between each I2C
> > access?
> It's experimental values. The M-5MOLS I2C communication is a litte sensitive,
> and I expect that this sensor is integrated with another ARM-core and internal
> Firmware, and ARM-core's performance is not good. So, the dealy should be needed.

Perhaps a comment telling this would be good?

> 
> > 
> >> +	ret = i2c_transfer(client->adapter, msg, 1);
> >> +	if (ret < 0) {
> >> +		v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
> >> +			size, category, cmd, ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask)
> >> +{
> >> +	u32 busy, i;
> >> +	int ret;
> >> +
> >> +	for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
> >> +		ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy);
> >> +		if (ret < 0)
> >> +			return ret;
> >> +		if ((busy & mask) == mask)
> >> +			return 0;
> >> +	}
> >> +	return -EBUSY;
> >> +}
> >> +
> >> +/**
> >> + * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
> >> + *
> >> + * Before writing desired interrupt value the INT_FACTOR register should
> >> + * be read to clear pending interrupts.
> >> + */
> >> +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +	u32 mask = is_available_af(info) ? REG_INT_AF : 0;
> >> +	u32 dummy;
> >> +	int ret;
> >> +
> >> +	ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy);
> >> +	if (!ret)
> >> +		ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
> >> +	return ret;
> >> +}
> >> +
> >> +/**
> >> + * m5mols_reg_mode - Write the mode and check busy status
> >> + *
> >> + * It always accompanies a little delay changing the M-5MOLS mode, so it is
> >> + * needed checking current busy status to guarantee right mode.
> >> + */
> >> +static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode)
> >> +{
> >> +	int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
> >> +
> >> +	return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
> >> +}
> >> +
> >> +/**
> >> + * m5mols_mode - manage the M-5MOLS's mode
> >> + * @mode: the required operation mode
> >> + *
> >> + * The commands of M-5MOLS are grouped into specific modes. Each functionality
> >> + * can be guaranteed only when the sensor is operating in mode which which
> >> + * a command belongs to.
> >> + */
> >> +int m5mols_mode(struct m5mols_info *info, u32 mode)
> >> +{
> >> +	struct v4l2_subdev *sd = &info->sd;
> >> +	int ret = -EINVAL;
> >> +	u32 reg;
> >> +
> >> +	if (mode < REG_PARAMETER && mode > REG_CAPTURE)
> >> +		return ret;
> >> +
> >> +	ret = m5mols_read(sd, SYSTEM_SYSMODE, &reg);
> >> +	if ((!ret && reg == mode) || ret)
> >> +		return ret;
> >> +
> >> +	switch (reg) {
> >> +	case REG_PARAMETER:
> >> +		ret = m5mols_reg_mode(sd, REG_MONITOR);
> >> +		if (!ret && mode == REG_MONITOR)
> >> +			break;
> >> +		if (!ret)
> >> +			ret = m5mols_reg_mode(sd, REG_CAPTURE);
> >> +		break;
> >> +
> >> +	case REG_MONITOR:
> >> +		if (mode == REG_PARAMETER) {
> >> +			ret = m5mols_reg_mode(sd, REG_PARAMETER);
> >> +			break;
> >> +		}
> >> +
> >> +		ret = m5mols_reg_mode(sd, REG_CAPTURE);
> >> +		break;
> >> +
> >> +	case REG_CAPTURE:
> >> +		ret = m5mols_reg_mode(sd, REG_MONITOR);
> >> +		if (!ret && mode == REG_MONITOR)
> >> +			break;
> >> +		if (!ret)
> >> +			ret = m5mols_reg_mode(sd, REG_PARAMETER);
> >> +		break;
> >> +
> >> +	default:
> >> +		v4l2_warn(sd, "Wrong mode: %d\n", mode);
> >> +	}
> >> +
> >> +	if (!ret)
> >> +		info->mode = mode;
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +/**
> >> + * m5mols_get_version - retrieve full revisions information of M-5MOLS
> >> + *
> >> + * The version information includes revisions of hardware and firmware,
> >> + * AutoFocus alghorithm version and the version string.
> >> + */
> >> +static int m5mols_get_version(struct v4l2_subdev *sd)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +	union {
> >> +		struct m5mols_version ver;
> >> +		u8 bytes[VERSION_SIZE];
> > 
> > You could even use u8 bytes[0] if you really need this union.
> > 
> > ((char *)&ver)[cmd], for example.
> > 
> >> +	} version;
> >> +	u32 *value;
> >> +	u8 cmd = CAT0_VER_CUSTOMER;
> >> +	int ret;
> >> +
> >> +	do {
> >> +		value = (u32 *)&version.bytes[cmd];
> >> +		ret = m5mols_read(sd, SYSTEM_CMD(cmd), value);
> >> +		if (ret)
> >> +			return ret;
> >> +	} while (cmd++ != CAT0_VER_AWB);
> >> +
> >> +	do {
> >> +		value = (u32 *)&version.bytes[cmd];
> >> +		ret = m5mols_read(sd, SYSTEM_VER_STRING, value);
> >> +		if (ret)
> >> +			return ret;
> >> +		if (cmd >= VERSION_SIZE - 1)
> >> +			return -EINVAL;
> >> +	} while (version.bytes[cmd++]);
> > 
> > 
> > Please move cmd++ outside the condition.
> Ok, I'll keep that.
> 
> > 
> > I think you should have a different function to read and write different
> > types, e.g. m5mols_read_u8 and m5mols_read_u16.
> As I said, this is good option and it will be changed like your recommendation.
> I very consider this usage at the next time.
> 
> > 
> > You have the access width encoded in the register value. That would still be
> > checked by the function.
> > 
> > You also could subtract CAT0_VER_CUSTOMER from cmd when using it as index
> > to bytes[] above, as you now rely that it is actually zero.
> > 
> >> +
> >> +	value = (u32 *)&version.bytes[cmd];
> >> +	ret = m5mols_read(sd, AF_VERSION, value);
> > 
> > I think it'd be cleaner to refer to (u32 *)&version.bytes[cmd] directly
> > instead of using value.
> > 
> > Can you be sure that cmd points to the AF version here?
> > 
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	/* store version information swapped for being readable */
> >> +	info->ver	= version.ver;
> > 
> > You could use info->ver straight away and drop version.ver.
> Ok, but this is also making me hard. It's been always stucked by over 80 character.
> And, I choose this the best.
> But, another option is appeared, I'll consider this again.
> 
> > 
> >> +	info->ver.fw	= be16_to_cpu(info->ver.fw);
> >> +	info->ver.hw	= be16_to_cpu(info->ver.hw);
> >> +	info->ver.param	= be16_to_cpu(info->ver.param);
> >> +	info->ver.awb	= be16_to_cpu(info->ver.awb);
> >> +
> >> +	v4l2_info(sd, "Manufacturer\t[%s]\n",
> >> +			is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
> >> +			"Samsung Electro-Machanics" :
> >> +			is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
> >> +			"Samsung Fiber-Optics" :
> >> +			is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
> >> +			"Samsung Techwin" : "None");
> >> +	v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
> >> +			info->ver.customer, info->ver.project);
> >> +
> >> +	if (!is_available_af(info))
> >> +		v4l2_info(sd, "No support Auto Focus on this firmware\n");
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +/**
> >> + * __find_restype - Lookup M-5MOLS resolution type according to pixel code
> >> + * @code: pixel code
> >> + */
> >> +static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code)
> >> +{
> >> +	enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
> >> +
> >> +	do {
> >> +		if (code == m5mols_default_ffmt[type].code)
> >> +			return type;
> > 
> > type++ here, and ++ off of the condition below.
> Ok, I'll adapt this for the next time.
> 
> > 
> >> +	} while (type++ != SIZE_DEFAULT_FFMT);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +/**
> >> + * __find_resolution - Lookup preset and type of M-5MOLS's resolution
> >> + * @mf: pixel format to find/negotiate the resolution preset for
> >> + * @type: M-5MOLS resolution type
> >> + * @resolution:	M-5MOLS resolution preset register value
> >> + *
> >> + * Find nearest resolution matching resolution preset and adjust mf
> >> + * to supported values.
> >> + */
> >> +static int __find_resolution(struct v4l2_subdev *sd,
> >> +			     struct v4l2_mbus_framefmt *mf,
> >> +			     enum m5mols_restype *type,
> >> +			     u32 *resolution)
> >> +{
> >> +	const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
> >> +	const struct m5mols_resolution *match = NULL;
> >> +	enum m5mols_restype stype = __find_restype(mf->code);
> >> +	int i = ARRAY_SIZE(m5mols_reg_res);
> >> +	unsigned int min_err = ~0;
> >> +
> >> +	while (i--) {
> >> +		int err;
> >> +		if (stype == fsize->type) {
> >> +			err = abs(fsize->width - mf->width)
> >> +				+ abs(fsize->height - mf->height);
> >> +
> >> +			if (err < min_err) {
> >> +				min_err = err;
> >> +				match = fsize;
> >> +			}
> >> +		}
> >> +		fsize++;
> >> +	}
> >> +	if (match) {
> >> +		mf->width  = match->width;
> >> +		mf->height = match->height;
> >> +		*resolution = match->reg;
> >> +		*type = stype;
> >> +		return 0;
> >> +	}
> >> +
> >> +	return -EINVAL;
> >> +}
> >> +
> >> +static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
> >> +				struct v4l2_subdev_fh *fh,
> >> +				enum v4l2_subdev_format_whence which,
> >> +				enum m5mols_restype type)
> >> +{
> >> +	if (which == V4L2_SUBDEV_FORMAT_TRY)
> >> +		return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
> >> +
> >> +	return &info->ffmt[type];
> >> +}
> >> +
> >> +static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
> >> +			  struct v4l2_subdev_format *fmt)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +	struct v4l2_mbus_framefmt *format;
> >> +
> >> +	if (fmt->pad != 0)
> >> +		return -EINVAL;
> >> +
> >> +	format = __find_format(info, fh, fmt->which, info->res_type);
> >> +	if (!format)
> >> +		return -EINVAL;
> >> +
> >> +	fmt->format = *format;
> >> +	return 0;
> >> +}
> >> +
> >> +static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
> >> +			  struct v4l2_subdev_format *fmt)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +	struct v4l2_mbus_framefmt *format = &fmt->format;
> >> +	struct v4l2_mbus_framefmt *sfmt;
> >> +	enum m5mols_restype type;
> >> +	u32 resolution = 0;
> >> +	int ret;
> >> +
> >> +	if (fmt->pad != 0)
> >> +		return -EINVAL;
> >> +
> >> +	ret = __find_resolution(sd, format, &type, &resolution);
> >> +	if (ret < 0)
> >> +		return ret;
> >> +
> >> +	sfmt = __find_format(info, fh, fmt->which, type);
> >> +	if (!sfmt)
> >> +		return 0;
> >> +
> >> +	*sfmt		= m5mols_default_ffmt[type];
> >> +	sfmt->width	= format->width;
> >> +	sfmt->height	= format->height;
> >> +
> >> +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> >> +		info->resolution = resolution;
> >> +		info->code = format->code;
> >> +		info->res_type = type;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
> >> +				 struct v4l2_subdev_fh *fh,
> >> +				 struct v4l2_subdev_mbus_code_enum *code)
> >> +{
> >> +	ifv (!code || code->index >= SIZE_DEFAULT_FFMT)
> > 
> > Is it possible that code == NULL?
> It depends on the driver using this subdev driver. 
> The test have done on the s5p-fimc driver for now, but I don't have
> any trouble cause of code == NULL.
> 
> But, probably the code can get through by userspace, so it should be
> needed I guess.

The contents are from user space but the pointer is not. No need to check
for NULL. See subdev_do_ioctl() in v4l2-subdev.c.

[clip]
> > 
> >> +		return -EINVAL;
> >> +
> >> +	code->code = m5mols_default_ffmt[code->index].code;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
> >> +	.enum_mbus_code	= m5mols_enum_mbus_code,
> >> +	.get_fmt	= m5mols_get_fmt,
> >> +	.set_fmt	= m5mols_set_fmt,
> >> +};
> >> +
> >> +/**
> >> + * m5mols_sync_controls - Apply default scene mode and the current controls
> >> + *
> >> + * This is used only streaming for syncing between v4l2_ctrl framework and
> >> + * m5mols's controls. First, do the scenemode to the sensor, then call
> >> + * v4l2_ctrl_handler_setup. It can be same between some commands and
> >> + * the scenemode's in the default v4l2_ctrls. But, such commands of control
> >> + * should be prior to the scenemode's one.
> >> + */
> >> +int m5mols_sync_controls(struct m5mols_info *info)
> >> +{
> >> +	int ret = -EINVAL;
> >> +
> >> +	if (!is_ctrl_synced(info)) {
> >> +		ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
> >> +		if (ret)
> >> +			return ret;
> >> +
> >> +		v4l2_ctrl_handler_setup(&info->handle);
> >> +		info->ctrl_sync = true;
> >> +	}
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +/**
> >> + * m5mols_start_monitor - Start the monitor mode
> >> + *
> >> + * Before applying the controls setup the resolution and frame rate
> >> + * in PARAMETER mode, and then switch over to MONITOR mode.
> >> + */
> >> +static int m5mols_start_monitor(struct m5mols_info *info)
> >> +{
> >> +	struct v4l2_subdev *sd = &info->sd;
> >> +	int ret;
> >> +
> >> +	ret = m5mols_mode(info, REG_PARAMETER);
> >> +	if (!ret)
> >> +		ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
> >> +	if (!ret)
> >> +		ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
> >> +	if (!ret)
> >> +		ret = m5mols_mode(info, REG_MONITOR);
> >> +	if (!ret)
> >> +		ret = m5mols_sync_controls(info);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +
> >> +	if (enable) {
> >> +		int ret = -EINVAL;
> >> +
> >> +		if (is_code(info->code, M5MOLS_RESTYPE_MONITOR))
> >> +			ret = m5mols_start_monitor(info);
> >> +		if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE))
> >> +			ret = m5mols_start_capture(info);
> >> +
> >> +		return ret;
> >> +	}
> >> +
> >> +	return m5mols_mode(info, REG_PARAMETER);
> >> +}
> >> +
> >> +static const struct v4l2_subdev_video_ops m5mols_video_ops = {
> >> +	.s_stream	= m5mols_s_stream,
> >> +};
> >> +
> >> +static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
> >> +{
> >> +	struct v4l2_subdev *sd = to_sd(ctrl);
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +	int ret;
> >> +
> >> +	info->mode_save = info->mode;
> >> +
> >> +	ret = m5mols_mode(info, REG_PARAMETER);
> >> +	if (!ret)
> >> +		ret = m5mols_set_ctrl(ctrl);
> >> +	if (!ret)
> >> +		ret = m5mols_mode(info, info->mode_save);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
> >> +	.s_ctrl	= m5mols_s_ctrl,
> >> +};
> >> +
> >> +static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
> >> +{
> >> +	struct v4l2_subdev *sd = &info->sd;
> >> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> >> +	const struct m5mols_platform_data *pdata = info->pdata;
> >> +	int ret;
> >> +
> >> +	if (enable) {
> >> +		if (is_powered(info))
> >> +			return 0;
> >> +
> >> +		if (info->set_power) {
> >> +			ret = info->set_power(&client->dev, 1);
> >> +			if (ret)
> >> +				return ret;
> >> +		}
> >> +
> >> +		ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
> >> +		if (ret) {
> >> +			info->set_power(&client->dev, 0);
> >> +			return ret;
> >> +		}
> >> +
> >> +		gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
> >> +		usleep_range(1000, 1000);
> >> +		info->power = true;
> >> +
> >> +		return ret;
> >> +	}
> >> +
> >> +	if (!is_powered(info))
> >> +		return 0;
> >> +
> >> +	ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	if (info->set_power)
> >> +		info->set_power(&client->dev, 0);
> >> +
> >> +	gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
> >> +	usleep_range(1000, 1000);
> >> +	info->power = false;
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +/* m5mols_update_fw - optional firmware update routine */
> >> +int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
> >> +		int (*set_power)(struct m5mols_info *, bool))
> >> +{
> >> +	return 0;
> >> +}
> >> +
> >> +/**
> >> + * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
> >> + *
> >> + * Booting internal ARM core makes the M-5MOLS is ready for getting commands
> >> + * with I2C. It's the first thing to be done after it powered up. It must wait
> >> + * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
> >> + */
> >> +static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
> >> +{
> >> +	int ret;
> >> +
> >> +	ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
> >> +	if (ret < 0)
> >> +		return ret;
> >> +
> >> +	msleep(520);
> >> +
> >> +	ret = m5mols_get_version(sd);
> >> +	if (!ret)
> >> +		ret = m5mols_update_fw(sd, m5mols_sensor_power);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
> >> +
> >> +	ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
> >> +	if (!ret)
> >> +		ret = m5mols_enable_interrupt(sd, REG_INT_AF);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int m5mols_init_controls(struct m5mols_info *info)
> >> +{
> >> +	struct v4l2_subdev *sd = &info->sd;
> >> +	u16 max_exposure;
> >> +	u16 step_zoom;
> >> +	int ret;
> >> +
> >> +	/* Determine value's range & step of controls for various FW version */
> >> +	ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure);
> >> +	if (!ret)
> >> +		step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	v4l2_ctrl_handler_init(&info->handle, 6);
> >> +	info->autowb = v4l2_ctrl_new_std(&info->handle,
> >> +			&m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
> >> +			0, 1, 1, 0);
> >> +	info->saturation = v4l2_ctrl_new_std(&info->handle,
> >> +			&m5mols_ctrl_ops, V4L2_CID_SATURATION,
> >> +			1, 5, 1, 3);
> >> +	info->zoom = v4l2_ctrl_new_std(&info->handle,
> >> +			&m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
> >> +			1, 70, step_zoom, 1);
> >> +	info->exposure = v4l2_ctrl_new_std(&info->handle,
> >> +			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
> >> +			0, max_exposure, 1, (int)max_exposure/2);
> >> +	info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
> >> +			&m5mols_ctrl_ops, V4L2_CID_COLORFX,
> >> +			4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
> >> +	info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
> >> +			&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
> >> +			1, 0, V4L2_EXPOSURE_MANUAL);
> >> +
> >> +	sd->ctrl_handler = &info->handle;
> >> +	if (info->handle.error) {
> >> +		v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
> >> +		v4l2_ctrl_handler_free(&info->handle);
> >> +		return info->handle.error;
> >> +	}
> >> +
> >> +	v4l2_ctrl_cluster(2, &info->autoexposure);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +/**
> >> + * m5mols_s_power - Main sensor power control function
> >> + *
> >> + * To prevent breaking the lens when the sensor is powered off the Soft-Landing
> >> + * algorithm is called where available. The Soft-Landing algorithm availability
> >> + * dependends on the firmware provider.
> >> + */
> >> +static int m5mols_s_power(struct v4l2_subdev *sd, int on)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +	int ret;
> >> +
> >> +	if (on) {
> >> +		ret = m5mols_sensor_power(info, true);
> >> +		if (!ret)
> >> +			ret = m5mols_sensor_armboot(sd);
> >> +		if (!ret)
> >> +			ret = m5mols_init_controls(info);
> >> +		if (ret)
> >> +			return ret;
> >> +
> >> +		info->ffmt[M5MOLS_RESTYPE_MONITOR] =
> >> +			m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
> >> +		info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
> >> +			m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
> >> +		return ret;
> >> +	}
> >> +
> >> +	if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
> >> +		ret = m5mols_mode(info, REG_MONITOR);
> >> +		if (!ret)
> >> +			ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
> >> +		if (!ret)
> >> +			ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
> >> +		if (!ret)
> >> +			ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS,
> >> +					REG_AF_IDLE);
> >> +		if (!ret)
> >> +			v4l2_info(sd, "Success soft-landing lens\n");
> >> +	}
> >> +
> >> +	ret = m5mols_sensor_power(info, false);
> >> +	if (!ret) {
> >> +		v4l2_ctrl_handler_free(&info->handle);
> >> +		info->ctrl_sync = false;
> >> +	}
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static int m5mols_log_status(struct v4l2_subdev *sd)
> >> +{
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +
> >> +	v4l2_ctrl_handler_log_status(&info->handle, sd->name);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static const struct v4l2_subdev_core_ops m5mols_core_ops = {
> >> +	.s_power	= m5mols_s_power,
> >> +	.g_ctrl		= v4l2_subdev_g_ctrl,
> >> +	.s_ctrl		= v4l2_subdev_s_ctrl,
> >> +	.queryctrl	= v4l2_subdev_queryctrl,
> >> +	.querymenu	= v4l2_subdev_querymenu,
> >> +	.g_ext_ctrls	= v4l2_subdev_g_ext_ctrls,
> >> +	.try_ext_ctrls	= v4l2_subdev_try_ext_ctrls,
> >> +	.s_ext_ctrls	= v4l2_subdev_s_ext_ctrls,
> >> +	.log_status	= m5mols_log_status,
> >> +};
> >> +
> >> +static const struct v4l2_subdev_ops m5mols_ops = {
> >> +	.core		= &m5mols_core_ops,
> >> +	.pad		= &m5mols_pad_ops,
> >> +	.video		= &m5mols_video_ops,
> >> +};
> >> +
> >> +static void m5mols_irq_work(struct work_struct *work)
> >> +{
> >> +	struct m5mols_info *info =
> >> +		container_of(work, struct m5mols_info, work_irq);
> >> +	struct v4l2_subdev *sd = &info->sd;
> >> +	u32 reg;
> >> +	int ret;
> >> +
> >> +	if (!is_powered(info) ||
> >> +			m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt))
> >> +		return;
> >> +
> >> +	switch (info->interrupt & REG_INT_MASK) {
> >> +	case REG_INT_AF:
> >> +		if (!is_available_af(info))
> >> +			break;
> >> +		ret = m5mols_read(sd, AF_STATUS, &reg);
> >> +		v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
> >> +			 reg == REG_AF_FAIL ? "Failed" :
> >> +			 reg == REG_AF_SUCCESS ? "Success" :
> >> +			 reg == REG_AF_IDLE ? "Idle" : "Busy");
> >> +		break;
> >> +	case REG_INT_CAPTURE:
> >> +		if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
> >> +			wake_up_interruptible(&info->irq_waitq);
> >> +
> >> +		v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
> >> +		break;
> >> +	default:
> >> +		v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
> >> +		break;
> >> +	};
> >> +}
> >> +
> >> +static irqreturn_t m5mols_irq_handler(int irq, void *data)
> >> +{
> >> +	struct v4l2_subdev *sd = data;
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +
> >> +	schedule_work(&info->work_irq);
> >> +
> >> +	return IRQ_HANDLED;
> >> +}
> >> +
> >> +static int __devinit m5mols_probe(struct i2c_client *client,
> >> +				  const struct i2c_device_id *id)
> >> +{
> >> +	const struct m5mols_platform_data *pdata = client->dev.platform_data;
> >> +	struct m5mols_info *info;
> >> +	struct v4l2_subdev *sd;
> >> +	int ret;
> >> +
> >> +	if (pdata == NULL) {
> >> +		dev_err(&client->dev, "No platform data\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	if (!gpio_is_valid(pdata->gpio_reset)) {
> >> +		dev_err(&client->dev, "No valid RESET GPIO specified\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	if (!pdata->irq) {
> >> +		dev_err(&client->dev, "Interrupt not assigned\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
> >> +	if (!info)
> >> +		return -ENOMEM;
> >> +
> >> +	info->pdata = pdata;
> >> +	info->set_power	= pdata->set_power;
> >> +
> >> +	ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
> >> +	if (ret) {
> >> +		dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
> >> +		goto out_free;
> >> +	}
> >> +	gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
> >> +
> >> +	ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
> >> +	if (ret) {
> >> +		dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
> >> +		goto out_gpio;
> >> +	}
> >> +
> >> +	sd = &info->sd;
> >> +	strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
> >> +	v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
> >> +
> >> +	info->pad.flags = MEDIA_PAD_FL_SOURCE;
> >> +	ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
> >> +	if (ret < 0)
> >> +		goto out_reg;
> >> +	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
> >> +
> >> +	init_waitqueue_head(&info->irq_waitq);
> >> +	INIT_WORK(&info->work_irq, m5mols_irq_work);
> >> +	ret = request_irq(pdata->irq, m5mols_irq_handler,
> >> +			  IRQF_TRIGGER_RISING, MODULE_NAME, sd);
> >> +	if (ret) {
> >> +		dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
> >> +		goto out_me;
> >> +	}
> >> +	info->res_type = M5MOLS_RESTYPE_MONITOR;
> >> +	return 0;
> >> +out_me:
> >> +	media_entity_cleanup(&sd->entity);
> >> +out_reg:
> >> +	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
> >> +out_gpio:
> >> +	gpio_free(pdata->gpio_reset);
> >> +out_free:
> >> +	kfree(info);
> >> +	return ret;
> >> +}
> >> +
> >> +static int __devexit m5mols_remove(struct i2c_client *client)
> >> +{
> >> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> >> +	struct m5mols_info *info = to_m5mols(sd);
> >> +
> >> +	v4l2_device_unregister_subdev(sd);
> >> +	free_irq(info->pdata->irq, sd);
> >> +
> >> +	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
> >> +	gpio_free(info->pdata->gpio_reset);
> >> +	media_entity_cleanup(&sd->entity);
> >> +	kfree(info);
> >> +	return 0;
> >> +}
> >> +
> >> +static const struct i2c_device_id m5mols_id[] = {
> >> +	{ MODULE_NAME, 0 },
> >> +	{ },
> >> +};
> >> +MODULE_DEVICE_TABLE(i2c, m5mols_id);
> >> +
> >> +static struct i2c_driver m5mols_i2c_driver = {
> >> +	.driver = {
> >> +		.name	= MODULE_NAME,
> >> +	},
> >> +	.probe		= m5mols_probe,
> >> +	.remove		= __devexit_p(m5mols_remove),
> >> +	.id_table	= m5mols_id,
> >> +};
> >> +
> >> +static int __init m5mols_mod_init(void)
> >> +{
> >> +	return i2c_add_driver(&m5mols_i2c_driver);
> >> +}
> >> +
> >> +static void __exit m5mols_mod_exit(void)
> >> +{
> >> +	i2c_del_driver(&m5mols_i2c_driver);
> >> +}
> >> +
> >> +module_init(m5mols_mod_init);
> >> +module_exit(m5mols_mod_exit);
> >> +
> >> +MODULE_AUTHOR("HeungJun Kim <riverful.kim@xxxxxxxxxxx>");
> >> +MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@xxxxxxxxxxx>");
> >> +MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
> >> +MODULE_LICENSE("GPL");
> >> diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
> >> new file mode 100644
> >> index 0000000..b83e36f
> >> --- /dev/null
> >> +++ b/drivers/media/video/m5mols/m5mols_reg.h
> >> @@ -0,0 +1,399 @@
> >> +/*
> >> + * Register map for M-5MOLS 8M Pixel camera sensor with ISP
> >> + *
> >> + * Copyright (C) 2011 Samsung Electronics Co., Ltd.
> >> + * Author: HeungJun Kim, riverful.kim@xxxxxxxxxxx
> >> + *
> >> + * Copyright (C) 2009 Samsung Electronics Co., Ltd.
> >> + * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@xxxxxxxxxxx
> >> + *
> >> + * 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.
> >> + */
> >> +
> >> +#ifndef M5MOLS_REG_H
> >> +#define M5MOLS_REG_H
> >> +
> >> +#define M5MOLS_I2C_MAX_SIZE	4
> >> +#define M5MOLS_BYTE_READ	0x01
> >> +#define M5MOLS_BYTE_WRITE	0x02
> >> +
> >> +#define I2C_CATEGORY(__cat)		((__cat >> 16) & 0xff)
> >> +#define I2C_COMMAND(__comm)		((__comm >> 8) & 0xff)
> >> +#define I2C_SIZE(__reg_s)		((__reg_s) & 0xff)
> > 
> > I would put category and command to lower 16 bits and size in the upper 16
> > bits, but this is up to you. I think this would improve readability.
> OK. I would deeply consider that :-)
> 
> > 
> >> +#define I2C_REG(__cat, __cmd, __reg_s)	((__cat << 16) | (__cmd << 8) | __reg_s)
> >> +
> >> +/*
> >> + * Category section register
> >> + *
> >> + * The category means set including relevant command of M-5MOLS.
> >> + */
> >> +#define CAT_SYSTEM		0x00
> >> +#define CAT_PARAM		0x01
> >> +#define CAT_MONITOR		0x02
> >> +#define CAT_AE			0x03
> >> +#define CAT_WB			0x06
> >> +#define CAT_EXIF		0x07
> >> +#define CAT_FD			0x09
> >> +#define CAT_LENS		0x0a
> >> +#define CAT_CAPT_PARM		0x0b
> >> +#define CAT_CAPT_CTRL		0x0c
> >> +#define CAT_FLASH		0x0f	/* related to FW, revisions, booting */
> > 
> > What about defining registers so that the category is part of the register
> > address? This is actually how it's in the address space as well.
> > 
> >> +
> >> +/*
> >> + * Category 0 - SYSTEM mode
> >> + *
> >> + * The SYSTEM mode in the M-5MOLS means area available to handle with the whole
> >> + * & all-round system of sensor. It deals with version/interrupt/setting mode &
> >> + * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
> >> + * packaging & manufacturer, even the customer and project code. And the
> >> + * function details may vary among them. The version information helps to
> >> + * determine what methods shall be used in the driver.
> >> + *
> >> + * There is many registers between customer version address and awb one. For
> >> + * more specific contents, see definition if file m5mols.h.
> >> + */
> >> +#define CAT0_VER_CUSTOMER	0x00	/* customer version */
> > 
> > If you keep the definitions as they are, I think "CAT0" should be replaced
> > by "SYSTEM". This would make it clear that the registers belong to that
> > category, instead of a numeric one.
> Actually, this register named on Document of M-5MOLS. I wanted to satisfy
> to keep that name and to looks readable.
> So, I choose only the name pointing the register value, is followed by document,
> and the prefix like SYSTEM_ is used in the code.
> 
> > 
> >> +#define CAT0_VER_AWB		0x09	/* Auto WB version */
> >> +#define CAT0_VER_STRING		0x0a	/* string including M-5MOLS */
> >> +#define CAT0_SYSMODE		0x0b	/* SYSTEM mode register */
> >> +#define CAT0_STATUS		0x0c	/* SYSTEM mode status register */
> >> +#define CAT0_INT_FACTOR		0x10	/* interrupt pending register */
> >> +#define CAT0_INT_ENABLE		0x11	/* interrupt enable register */
> >> +
> >> +#define SYSTEM_SYSMODE		I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
> >> +#define REG_SYSINIT		0x00	/* SYSTEM mode */
> >> +#define REG_PARAMETER		0x01	/* PARAMETER mode */
> >> +#define REG_MONITOR		0x02	/* MONITOR mode */
> >> +#define REG_CAPTURE		0x03	/* CAPTURE mode */
> >> +
> >> +#define SYSTEM_CMD(__cmd)	I2C_REG(CAT_SYSTEM, cmd, 1)
> >> +#define SYSTEM_VER_STRING	I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1)
> >> +#define REG_SAMSUNG_ELECTRO	"SE"	/* Samsung Electro-Mechanics */
> >> +#define REG_SAMSUNG_OPTICS	"OP"	/* Samsung Fiber-Optics */
> >> +#define REG_SAMSUNG_TECHWIN	"TB"	/* Samsung Techwin */
> >> +
> >> +#define SYSTEM_INT_FACTOR	I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1)
> >> +#define SYSTEM_INT_ENABLE	I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1)
> >> +#define REG_INT_MODE		(1 << 0)
> >> +#define REG_INT_AF		(1 << 1)
> >> +#define REG_INT_ZOOM		(1 << 2)
> >> +#define REG_INT_CAPTURE		(1 << 3)
> >> +#define REG_INT_FRAMESYNC	(1 << 4)
> >> +#define REG_INT_FD		(1 << 5)
> >> +#define REG_INT_LENS_INIT	(1 << 6)
> >> +#define REG_INT_SOUND		(1 << 7)
> >> +#define REG_INT_MASK		0x0f
> > 
> > I would prefix the register bit definitions with the name of the register.
> > 
> > E.g.
> > 
> > #define SYSTEM_INT_FACTOR_MODE	(1 << 0)
> It's Ditto "over 80 character"
> 
> If already used once like this, it should use in another case, so
> length of the SYSTEM_INT_FACTOR_MODE does not matter itself, but the other
> case can be troubled.

It's sometimes acceptable to have over 80 characters per line. Yes, it's an
exception but sometimes it's the case. See e.g. videodev2.h, for example.

Regards,

-- 
Sakari Ailus
sakari dot ailus at iki dot fi
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux