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, [email protected]
> >> + *
> >> + * Copyright (C) 2009 Samsung Electronics Co., Ltd.
> >> + * Author: Dongsoo Nathaniel Kim, [email protected]
> >> + *
> >> + * 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, ®);
> >> + 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, ®);
> >> + 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 <[email protected]>");
> >> +MODULE_AUTHOR("Dongsoo Kim <[email protected]>");
> >> +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, [email protected]
> >> + *
> >> + * Copyright (C) 2009 Samsung Electronics Co., Ltd.
> >> + * Author: Dongsoo Nathaniel Kim, [email protected]
> >> + *
> >> + * 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html