IMX046: Add support for Sony imx046 sensor.
Subsystems (2)
PATCH 3/6 IMX046: Add support for Sony imx046 sensor.
From: Dominic Curran <[email protected]>
Subject: [OMAPZOOM][PATCH 3/6] IMX046: Add support for Sony imx046 sensor.
This patch adds the driver files for the Sony IMX046 8MP camera sensor. Driver sets up the sensor to send frame data via the MIPI CSI2 i/f. Sensor is setup to output the following base sizes:
- 3280 x 2464 (8MP)
- 3280 x 616 (2MP)
- 820 x 616
Sensor's output image format is Bayer10 (GrR/BGb).
Driver has V4L2 controls for:
- Exposure
- Analog Gain
--- drivers/media/video/Kconfig | 8 drivers/media/video/Makefile | 1 drivers/media/video/imx046.c | 1635 +++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/imx046.h | 326 ++++++++ 4 files changed, 1970 insertions(+) create mode 100644 drivers/media/video/imx046.c create mode 100644 drivers/media/video/imx046.h
drivers/media/video/Kconfig +8 -0
@@ -334,6 +334,14 @@ config VIDEO_OV3640_CSI2 This enables the use of the CSI2 serial bus for the ov3640 camera. +config VIDEO_IMX046 + tristate "Sony IMX046 sensor driver (8MP)" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Sony + IMX046 camera. It is currently working with the TI OMAP3 + camera controller. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2C
drivers/media/video/Makefile +1 -0
@@ -115,6 +115,7 @@ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_MT9P012) += mt9p012.o obj-$(CONFIG_VIDEO_DW9710) += dw9710.o obj-$(CONFIG_VIDEO_OV3640) += ov3640.o +obj-$(CONFIG_VIDEO_IMX046) += imx046.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o
drivers/media/video/imx046.c new file +1635 -0
1,635 lines not on this page · raw message
drivers/media/video/imx046.h new file +326 -0
326 lines not on this page · raw message
Thanks,
Vaibhav Hiremath
Quoted 90 lines
-----Original Message-----
From: [email protected] [mailto:video4linux-list- [email protected]] On Behalf Of Dominic Curran
Sent: Friday, January 30, 2009 6:24 AM
To: linux-omap; [email protected]
Cc: [email protected]
Subject: [OMAPZOOM][PATCH 3/6] IMX046: Add support for Sony imx046 sensor.From: Dominic Curran <[email protected]>
Subject: [OMAPZOOM][PATCH 3/6] IMX046: Add support for Sony imx046 sensor.This patch adds the driver files for the Sony IMX046 8MP camera sensor.
Driver sets up the sensor to send frame data via the MIPI CSI2 i/f. Sensor is setup to output the following base sizes:
- 3280 x 2464 (8MP)
- 3280 x 616 (2MP)
- 820 x 616
Sensor's output image format is Bayer10 (GrR/BGb).Driver has V4L2 controls for:
- Exposure
- Analog GainSigned-off-by Greg Hofer <[email protected]>Signed-off-by Dominic Curran <[email protected]>--- drivers/media/video/Kconfig | 8 drivers/media/video/Makefile | 1 drivers/media/video/imx046.c | 1635 +++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/imx046.h | 326 ++++++++ 4 files changed, 1970 insertions(+) create mode 100644 drivers/media/video/imx046.c create mode 100644 drivers/media/video/imx046.hIndex: omapzoom04/drivers/media/video/Kconfig
===================================================================drivers/media/video/Kconfig +8
-0@@ -334,6 +334,14 @@ config VIDEO_OV3640_CSI2 This enables the use of the CSI2 serial bus for the ov3640 camera. +config VIDEO_IMX046 + tristate "Sony IMX046 sensor driver (8MP)" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Sony + IMX046 camera. It is currently working with the TI OMAP3 + camera controller. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2CIndex: omapzoom04/drivers/media/video/Makefile
===================================================================drivers/media/video/Makefile +1
-0@@ -115,6 +115,7 @@ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_MT9P012) += mt9p012.o obj-$(CONFIG_VIDEO_DW9710) += dw9710.o obj-$(CONFIG_VIDEO_OV3640) += ov3640.o +obj-$(CONFIG_VIDEO_IMX046) += imx046.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.oIndex:
omapzoom04/drivers/media/video/imx046.c
===================================================================drivers/media/video/imx046.c new file +11
-0@@ -0,0 +1,1635 @@ +/* +* drivers/media/video/imx046.c +* +* Sony imx046 sensor driver +* +* +* Copyright (C) 2008 Hewlett Packard +* +* Leverage mt9p012.c +* +* This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
drivers/media/video/imx046.c line 19
Quoted 5 lines
drivers/media/video/imx046.c new file +5
-0+ +#include <linux/i2c.h> +#include <linux/delay.h> +#include <media/v4l2-int-device.h> +
[Hiremath, Vaibhav] line break needed.
Quoted 330 lines
drivers/media/video/imx046.c new file +56
-0+#include "imx046.h" +#include "omap34xxcam.h" +#include "isp/isp.h" +#include "isp/ispcsi2.h" + + +#define IMX046_DRIVER_NAME "imx046" +#define IMX046_MOD_NAME "IMX046: " + +#define I2C_M_WR 0 + + +/* from IMX046ES_registerSetting_I2C_MIPI_2lane_def_080925.xls */ +const static struct imx046_reg initial_list[] = { + {IMX046_REG_IMAGE_ORIENTATION ,0x03 ,I2C_8BIT }, + {IMX046_REG_COARSE_INT_TIME ,0x0120 ,I2C_16BIT }, + {IMX046_REG_ANALOG_GAIN_GLOBAL ,0x80 ,I2C_16BIT }, + {0x300A ,0x80 ,I2C_8BIT }, + {IMX046_REG_Y_OPBADDR_START_DI ,0x08 ,I2C_8BIT }, + {IMX046_REG_Y_OPBADDR_END_DI ,0x37 ,I2C_8BIT }, + {IMX046_REG_CHCODE_OUTCHSINGLE ,0x60 ,I2C_8BIT }, + {IMX046_REG_OUTIF ,0x01 ,I2C_8BIT }, + {IMX046_REG_RGPOF_RGPOFV2 ,0x28 ,I2C_8BIT }, + {IMX046_REG_CPCKAUTOEN ,0x00 ,I2C_8BIT }, + {IMX046_REG_RGCPVFB ,0x60 ,I2C_8BIT }, + {IMX046_REG_RGAZPDRV ,0x24 ,I2C_8BIT }, + {IMX046_REG_RGAZTEST ,0x34 ,I2C_8BIT }, + {IMX046_REG_RGVSUNLV ,0x3B ,I2C_8BIT }, + {IMX046_REG_CLPOWER ,0x30 ,I2C_8BIT }, + {IMX046_REG_CLPOWERSP ,0x00 ,I2C_8BIT }, + {IMX046_REG_ACLDIRV_TVADDCLP ,0x00 ,I2C_8BIT }, + {IMX046_REG_OPB_CTRL ,0x0080 ,I2C_16BIT }, + {0x30AB ,0x1C ,I2C_8BIT }, + {0x30B0 ,0x32 ,I2C_8BIT }, + {0x30B2 ,0x83 ,I2C_8BIT }, + {IMX046_REG_RAW10CH2V2P_LO ,0xD8 ,I2C_8BIT }, + {IMX046_REG_RAW10CH2V2D_LO ,0x17 ,I2C_8BIT }, + {IMX046_REG_COMP8CH1V2P_LO ,0xCF ,I2C_8BIT }, + {IMX046_REG_COMP8CH1V2D_LO ,0xF1 ,I2C_8BIT }, + {IMX046_REG_RAW10CH1V2P_LO ,0xD8 ,I2C_8BIT }, + {IMX046_REG_RAW10CH1V2D_LO ,0x17 ,I2C_8BIT }, + {0x3302 ,0x0A ,I2C_8BIT }, + {0x3303 ,0x09 ,I2C_8BIT }, + {IMX046_REG_RGTLPX ,0x05 ,I2C_8BIT }, + {IMX046_REG_RGTCLKPREPARE ,0x04 ,I2C_8BIT }, + {IMX046_REG_RGTCLKZERO ,0x15 ,I2C_8BIT }, + {IMX046_REG_RGTCLKPRE ,0x03 ,I2C_8BIT }, + {IMX046_REG_RGTCLKPOST ,0x13 ,I2C_8BIT }, + {IMX046_REG_RGTCLKTRAIL ,0x05 ,I2C_8BIT }, + {IMX046_REG_RGTHSEXIT ,0x0B ,I2C_8BIT }, + {0x302B ,0x38 ,I2C_8BIT },/* for 18Mhz xclk */ + {I2C_REG_TERM ,I2C_VAL_TERM ,I2C_LEN_TERM } +}; + +/** +* struct imx046_sensor - main structure for storage of sensor information
+ * @pdata: access functions and data for platform level information
+ * @v4l2_int_device: V4L2 device structure structure
+ * @i2c_client: iic client device structure
+ * @pix: V4L2 pixel format information structure
+ * @timeperframe: time per frame expressed as V4L fraction
+ * @scaler:
+ * @ver: imx046 chip version
+ * @fps: frames per second value
+ */drivers/media/video/imx046.c new file +186
-0+struct imx046_sensor { +const struct imx046_platform_data *pdata; +struct v4l2_int_device *v4l2_int_device; +struct i2c_client *i2c_client; +struct v4l2_pix_format pix; +struct v4l2_fract timeperframe; +int scaler; +int ver; +int fps; +int state; +bool resuming; +}; + +static struct imx046_sensor imx046; +static struct i2c_driver imx046sensor_i2c_driver; +static unsigned long xclk_current =IMX046_XCLK_NOM_1 ; +static enum imx046_image_size isize_current =EIGHT_MP ; + +/* list of image formats supported by imx046 sensor */ +const static struct v4l2_fmtdesc imx046_formats[] = { + { + .description ="Bayer10 (GrR/BGb)" , + .pixelformat =V4L2_PIX_FMT_SGRBG10 , + } +}; + +#define NUM_CAPTURE_FORMATS ARRAY_SIZE(imx046_formats) + +static u32 min_exposure_time =1000 ; +static u32 max_exposure_time =128000 ; +static enum v4l2_power current_power_state; + +/* Structure of Sensor settings that change with image size */ +static struct imx046_sensor_settings sensor_settings[] = { +/* NOTE: must be in same order as image_size array */ + +/* HALF_MP */ + { + .clk = { + .pre_pll_div =1 , + .pll_mult =18 , + .post_pll_div =1 , + .vt_pix_clk_div =10 , + .vt_sys_clk_div =1 , + }, + .mipi = { + .data_lanes =1 , + .ths_prepare =2 , + .ths_zero =5 , + .ths_settle_lower =8 , + .ths_settle_upper =28 , + }, + .frame = { + .frame_len_lines_min =629 , + .line_len_pck =3440 , + .x_addr_start =0 , + .x_addr_end =3279 , + .y_addr_start =0 , + .y_addr_end =2463 , + .x_output_size =820 , + .y_output_size =616 , + .x_even_inc =5 , + .x_odd_inc =3 , + .y_even_inc =5 , + .y_odd_inc =3 , + .v_mode_add =0 , + .h_mode_add =0 , + .h_add_ave =1 , + }, + }, + +/* TWO_MP */ + { + .clk = { + .pre_pll_div =1 , + .pll_mult =18 , + .post_pll_div =1 , + .vt_pix_clk_div =10 , + .vt_sys_clk_div =1 , + }, + .mipi = { + .data_lanes =2 , + .ths_prepare =4 , + .ths_zero =5 , + .ths_settle_lower =13 , + .ths_settle_upper =33 , + }, + .frame = { + .frame_len_lines_min =629 , + .line_len_pck =3440 , + .x_addr_start =0 , + .x_addr_end =3279 , + .y_addr_start =0 , + .y_addr_end =2463 , + .x_output_size =3280 , + .y_output_size =618 , + .x_even_inc =1 , + .x_odd_inc =1 , + .y_even_inc =5 , + .y_odd_inc =3 , + .v_mode_add =0 , + .h_mode_add =0 , + .h_add_ave =0 , + }, + }, + +/* EIGHT_MP */ + { + .clk = { + .pre_pll_div =1 , + .pll_mult =18 , + .post_pll_div =1 , + .vt_pix_clk_div =10 , + .vt_sys_clk_div =1 , + }, + .mipi = { + .data_lanes =2 , + .ths_prepare =4 , + .ths_zero =5 , + .ths_settle_lower =13 , + .ths_settle_upper =33 , + }, + .frame = { + .frame_len_lines_min =2510 , + .line_len_pck =3440 , + .x_addr_start =0 , + .x_addr_end =3279 , + .y_addr_start =0 , + .y_addr_end =2463 , + .x_output_size =3280 , + .y_output_size =2464 , + .x_even_inc =1 , + .x_odd_inc =1 , + .y_even_inc =1 , + .y_odd_inc =1 , + .v_mode_add =0 , + .h_mode_add =0 , + .h_add_ave =0 , + }, + }, +}; + +static struct imx046_clock_freq current_clk; + +struct i2c_list { +struct i2c_msg *reg_list; +unsigned int list_size; +}; + +/** +* struct vcontrol - Video controls +* @v4l2_queryctrl: V4L2 VIDIOC_QUERYCTRL ioctl structure +* @current_value: current value of this control +*/ +static struct vcontrol { +struct v4l2_queryctrl qc; +int current_value; +} imx046sensor_video_control[] = { + { + { + .id =V4L2_CID_EXPOSURE , + .type =V4L2_CTRL_TYPE_INTEGER , + .name ="Exposure" , + .minimum =IMX046_MIN_EXPOSURE , + .maximum =IMX046_MAX_EXPOSURE , + .step =IMX046_EXPOSURE_STEP , + .default_value =IMX046_DEF_EXPOSURE , + }, + .current_value =IMX046_DEF_EXPOSURE , + }, + { + { + .id =V4L2_CID_GAIN , + .type =V4L2_CTRL_TYPE_INTEGER , + .name ="Analog Gain" , + .minimum =IMX046_MIN_GAIN , + .maximum =IMX046_MAX_GAIN , + .step =IMX046_GAIN_STEP , + .default_value =IMX046_DEF_GAIN , + }, + .current_value =IMX046_DEF_GAIN , + } +}; + +/** +* find_vctrl - Finds the requested ID in the video control structure array
+ * @id: ID of control to search the video control array for
+ *
+ * Returns the index of the requested ID from the control structure array
+ */drivers/media/video/imx046.c new file +9
-0+static int +find_vctrl (int id) +{ +int i; + +if (id <V4L2_CID_BASE ) +return -EDOM ; + + for (i = (ARRAY_SIZE(imx046sensor_video_control) - 1); i >= 0;i--)
drivers/media/video/imx046.c new file +9
-0+if (imx046sensor_video_control[i].qc.id == id) +break ; +if (i <0 ) + i = -EINVAL ; +return i; +} + +/** +* imx046_read_reg - Read a value from a register in an imx046 sensor device
+ * @client: i2c driver client structure
+ * @data_length: length of data to be read
+ * @reg: register address / offset
+ * @val: stores the value that gets read
+ *
+ * Read a value from a register in an imx046 sensor device.
+ * The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */drivers/media/video/imx046.c new file +2
-0+static int +imx046_read_reg(struct i2c_client *client, u16 data_length, u16reg, u32 *val)
drivers/media/video/imx046.c new file +40
-0+{ +int err; +struct i2c_msg msg[1 ]; +unsigned char data[4 ]; + +if (!client->adapter) +return -ENODEV ; +if (data_length !=I2C_8BIT && data_length !=I2C_16BIT + && data_length !=I2C_32BIT ) +return -EINVAL ; + + msg->addr = client->addr; + msg->flags =0 ; + msg->len =2 ; + msg->buf = data; + +/* Write addr - high byte goes out first */ + data[0 ] = (u8) (reg >>8 );; + data[1 ] = (u8) (reg &0xff ); + err =i2c_transfer (client->adapter, msg,1 ); + +/* Read back data */ +if (err >=0 ) { + msg->len = data_length; + msg->flags =I2C_M_RD ; + err =i2c_transfer (client->adapter, msg,1 ); + } +if (err >=0 ) { + *val =0 ; +/* high byte comes first */ +if (data_length ==I2C_8BIT ) + *val = data[0 ]; +else if (data_length ==I2C_16BIT ) + *val = data[1 ] + (data[0 ] <<8 ); +else + *val = data[3 ] + (data[2 ] <<8 ) + + (data[1 ] <<16 ) + (data[0 ] <<24 ); +return 0 ; + } + dev_err(&client->dev, "read from offset 0x%x error %d", reg,
Quoted 1 line
err);
[Hiremath, Vaibhav] Since this lies under V4l framework I would recommend using v4l_xxx instead of dev_xxx.
Quoted 11 lines
drivers/media/video/imx046.c new file +11
-0+return err; +} + +/** +* Write a value to a register in imx046 sensor device. +* @client: i2c driver client structure. +* @reg: Address of the register to read value from. +* @val: Value to be written to a specific register. +* Returns zero if successful, or non-zero otherwise. +*/ +static int imx046_write_reg(struct i2c_client *client, u16 reg,
drivers/media/video/imx046.c line 364
Quoted 10 lines
drivers/media/video/imx046.c new file +10
-0+ u32 val, u16 data_length) +{ + int err = 0; +struct i2c_msg msg[1 ]; +unsigned char data[6 ]; +int retries =0 ; + +if (!client->adapter) +return -ENODEV ; +
[Hiremath, Vaibhav] Don't we need to validate data_length here, similar to read?
Quoted 21 lines
drivers/media/video/imx046.c new file +21
-0+retry: + msg->addr = client->addr; + msg->flags =I2C_M_WR ; + msg->len = data_length+2 ;/* add address bytes */ + msg->buf = data; + +/* high byte goes out first */ + data[0 ] = (u8) (reg >>8 ); + data[1 ] = (u8) (reg &0xff ); +if (data_length ==I2C_8BIT ) { + data[2 ] = val &0xff ; + }else if (data_length ==I2C_16BIT ) { + data[2 ] = (val >>8 ) &0xff ; + data[3 ] = val &0xff ; + }else { + data[2 ] = (val >>24 ) &0xff ; + data[3 ] = (val >>16 ) &0xff ; + data[4 ] = (val >>8 ) &0xff ; + data[5 ] = val &0xff ; + } +
drivers/media/video/imx046.c line 395
Quoted 10 lines
drivers/media/video/imx046.c new file +10
-0+if (data_length ==1 ) +dev_dbg (&client->dev,"IMX046 Wrt:[0x%04X]=0x%02X\n" , + reg, val); +else if (data_length ==2 ) +dev_dbg (&client->dev,"IMX046 Wrt:[0x%04X]=0x%04X\n" , + reg, val); + + err =i2c_transfer (client->adapter, msg,1 ); +udelay (50 ); +
[Hiremath, Vaibhav] Do we need delay here?
drivers/media/video/imx046.c line 402
Quoted 7 lines
drivers/media/video/imx046.c new file +7
-0+if (err >=0 ) +return 0 ; + +if (retries <=5 ) { +dev_dbg (&client->dev,"Retrying I2C... %d" , retries); + retries++; +set_current_state (TASK_UNINTERRUPTIBLE );
[Hiremath, Vaibhav] Why this is uninterruptible?
Quoted 16 lines
drivers/media/video/imx046.c new file +16
-0+schedule_timeout (msecs_to_jiffies (20 )); + goto retry; + } + +return err; +} + +/** +* Initialize a list of imx046 registers. +* The list of registers is terminated by the pair of values +* {OV3640_REG_TERM, OV3640_VAL_TERM}. +* @client: i2c driver client structure. +* @reglist[]: List of address of the registers to write data. +* Returns zero if successful, or non-zero otherwise. +*/ +static int imx046_write_regs(struct i2c_client *client,
drivers/media/video/imx046.c line 428
Quoted 10 lines
drivers/media/video/imx046.c new file +10
-0+ const struct imx046_reg reglist[]) +{ +int err =0 ; +const struct imx046_reg *list = reglist; + +while (!((list->reg ==I2C_REG_TERM ) + && (list->val ==I2C_VAL_TERM ))) { + err =imx046_write_reg (client, list->reg, + list->val, list->length); +udelay (100 );
[Hiremath, Vaibhav] Again why delay?
We already have udelay(50) in imx046_write_reg.
Quoted 1,653 lines
drivers/media/video/imx046.c new file +9
-0+if (err) +return err; + list++; + } +return 0 ; +} + +/** +* imx046_find_size - Find the best match for a requested image capture size
+ * @width: requested image width in pixels
+ * @height: requested image height in pixels
+ *
+ * Find the best match for a requested image capture size. The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ * Since the available sizes are subsampled in the vertical direction only,
+ * the routine will find the size with a height that is equal to or less
+ * than the requested height.
+ */drivers/media/video/imx046.c new file +26
-0+static enum imx046_image_size imx046_find_size (unsigned int width, +unsigned int height) +{ +enum imx046_image_size isize; + +for (isize =HALF_MP ; isize <=EIGHT_MP ; isize++) { +if ((imx046_sizes[isize].height >= height) && + (imx046_sizes[isize].width >= width)) { +break ; + } + } + +printk (KERN_DEBUG "imx046_find_size: Req Size=%dx%d, " +"Calc Size=%dx%d\n" , + width, height, (int )imx046_sizes[isize].width, + (int )imx046_sizes[isize].height); + +return isize; +} + +/** +* Set CSI2 Virtual ID. +* @client: i2c client driver structure +* @id: Virtual channel ID. +* +* Sets the channel ID which identifies data packets sent by this device
+ * on the CSI2 bus.
+ **/drivers/media/video/imx046.c new file +8
-0+static int imx046_set_virtual_id (struct i2c_client *client,u32 id) +{ +return imx046_write_reg (client,IMX046_REG_CCP2_CHANNEL_ID , + (0x3 & id),I2C_8BIT ); +} + +/** +* imx046_set_framerate - Sets framerate by adjusting
frame_length_linesreg.
+ * @s: pointer to standard V4L2 device structure
+ * @fper: frame period numerator and denominator in seconds
+ *
+ * The maximum exposure time is also updated since it is affected by the
+ * frame rate.
+ **/drivers/media/video/imx046.c new file +45
-0+static int imx046_set_framerate (struct v4l2_int_device *s, +struct v4l2_fract *fper) +{ +int err =0 ; +u16 isize = isize_current; +u32 frame_length_lines, line_time_q8; +struct imx046_sensor *sensor = s->priv; +struct i2c_client *client = sensor->i2c_client; +struct imx046_sensor_settings *ss; + +if ((fper->numerator ==0 ) || (fper->denominator ==0 )) { +/* supply a default nominal_timeperframe */ + fper->numerator =1 ; + fper->denominator =IMX046_DEF_FPS ; + } + + sensor->fps = fper->denominator / fper->numerator; +if (sensor->fps <IMX046_MIN_FPS ) { + sensor->fps =IMX046_MIN_FPS ; + fper->numerator =1 ; + fper->denominator = sensor->fps; + }else if (sensor->fps >IMX046_MAX_FPS ) { + sensor->fps =IMX046_MAX_FPS ; + fper->numerator =1 ; + fper->denominator = sensor->fps; + } + + ss = &sensor_settings[isize_current]; + + line_time_q8 = ((u32 )ss->frame.line_len_pck *1000000 ) / + (current_clk.vt_pix_clk >>8 );/* usec's */ + + frame_length_lines = (((u32 )fper->numerator *1000000 *256 / + fper->denominator)) / line_time_q8; + +/* Range check frame_length_lines */ +if (frame_length_lines >IMX046_MAX_FRAME_LENGTH_LINES ) + frame_length_lines =IMX046_MAX_FRAME_LENGTH_LINES ; +else if (frame_length_lines < ss->frame.frame_len_lines_min) + frame_length_lines = ss->frame.frame_len_lines_min; + +imx046_write_reg (client,IMX046_REG_FRAME_LEN_LINES , + frame_length_lines,I2C_16BIT ); + + sensor_settings[isize].frame.frame_len_lines =
frame_length_lines;drivers/media/video/imx046.c new file +3
-0+ +/* Update max exposure time */ + max_exposure_time = (line_time_q8 * (frame_length_lines -1 ))Quoted 1 line
Quoted 1 line
8;
drivers/media/video/imx046.c new file +4
-0+ + printk(KERN_DEBUG "IMX046 Set Framerate: fper=%d/%d, " + "frame_len_lines=%d, max_expT=%dus\n", fper->numerator, + fper->denominator, frame_length_lines,
max_exposure_time);drivers/media/video/imx046.c new file +22
-0+ +return err; +} + +/** +* imx046sensor_calc_xclk - Calculate the required xclk frequency +* +* Xclk is not determined from framerate for the IMX046 +*/ +static unsigned long imx046sensor_calc_xclk (void ) +{ + xclk_current =IMX046_XCLK_NOM_1 ; + +return xclk_current; +} + +/** +* Sets the correct orientation based on the sensor version. +* IU046F2-Z version=2 orientation=3 +* IU046F4-2D version>2 orientation=0 +*/ +static int imx046_set_orientation(struct i2c_client *client, u32ver)
drivers/media/video/imx046.c new file +12
-0+{ +int err; +u8 orient; + + orient = (ver <=0x2 ) ?0x3 :0x0 ; + err =imx046_write_reg (client,IMX046_REG_IMAGE_ORIENTATION , + orient,I2C_8BIT ); +return err; +} + +/** +* imx046sensor_set_exposure_time - sets exposure time per input value
+ * @exp_time: exposure time to be set on device (in usec)
+ * @s: pointer to standard V4L2 device structure
+ * @lvc: pointer to V4L2 exposure entry inimx046sensor_video_controlsarray
+ *
+ * If the requested exposure time is within the allowed limits, the HW
+ * is configured to use the new exposure time, and the
+ * imx046sensor_video_control[] array is updated with the new current value.
+ * The function returns 0 upon success. Otherwise an error code is
+ * returned.
+ */
+int imx046sensor_set_exposure_time(u32exp_time, structv4l2_int_device*s,drivers/media/video/imx046.c new file +10
-0+ struct vcontrol *lvc) +{ + int err = 0, i; + struct imx046_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + u16 coarse_int_time = 0; + u32 line_time_q8 = 0; + struct imx046_sensor_settings *ss; + + if ((current_power_state == V4L2_POWER_ON) || sensor-Quoted 1 line
resuming) {
drivers/media/video/imx046.c new file +2
-0+if (exp_time < min_exposure_time) { + dev_err(&client->dev, "Exposure time %d us notwithin"
drivers/media/video/imx046.c new file +2
-0+ " the legal range.\n", exp_time); + dev_err(&client->dev, "Exposure time must bebetween"
drivers/media/video/imx046.c new file +7
-0+" %d us and %d us\n" , + min_exposure_time, max_exposure_time); + exp_time = min_exposure_time; + } + +if (exp_time > max_exposure_time) { + dev_err(&client->dev, "Exposure time %d us notwithin"
drivers/media/video/imx046.c new file +2
-0+ " the legal range.\n", exp_time); + dev_err(&client->dev, "Exposure time must bebetween"
drivers/media/video/imx046.c new file +12
-0+" %d us and %d us\n" , + min_exposure_time, max_exposure_time); + exp_time = max_exposure_time; + } + + ss = &sensor_settings[isize_current]; + + line_time_q8 = + ((u32 )ss->frame.line_len_pck *1000000 ) / + (current_clk.vt_pix_clk >>8 );/* usec's */ + + coarse_int_time = ((exp_time * 256) + (line_time_q8 >>1)) /
drivers/media/video/imx046.c new file +6
-0+ line_time_q8; + +if (coarse_int_time > ss->frame.frame_len_lines -2 ) + coarse_int_time = ss->frame.frame_len_lines -2 ; + + err = imx046_write_reg(client,
IMX046_REG_COARSE_INT_TIME,drivers/media/video/imx046.c new file +5
-0+ coarse_int_time, I2C_16BIT); + } + +if (err) { + dev_err(&client->dev, "Error setting exposure time: %d",err);
drivers/media/video/imx046.c new file +16
-0+ }else { + i =find_vctrl (V4L2_CID_EXPOSURE ); +if (i >=0 ) { + lvc = &imx046sensor_video_control[i]; + lvc->current_value = exp_time; + } + } + +return err; +} + +/** +* imx046sensor_set_gain - sets sensor analog gain per input value +* @gain: analog gain value to be set on device +* @s: pointer to standard V4L2 device structure +* @lvc: pointer to V4L2 analog gain entry in
imx046sensor_video_controlarray
+ *
+ * If the requested analog gain is within the allowed limits, the HW
+ * is configured to use the new gain value, and theimx046sensor_video_control
+ * array is updated with the new current value.
+ * The function returns 0 upon success. Otherwise an error code is
+ * returned.
+ */
+int imx046sensor_set_gain(u16 lineargain, structv4l2_int_device*s,drivers/media/video/imx046.c new file +9
-0+ struct vcontrol *lvc) +{ +int err =0 , i; +u16 reg_gain =0 ; + +struct imx046_sensor *sensor = s->priv; +struct i2c_client *client = sensor->i2c_client; + +if (current_power_state ==V4L2_POWER_ON || sensor->resuming){
drivers/media/video/imx046.c new file +17
-0+if (lineargain <IMX046_MIN_GAIN ) { + lineargain =IMX046_MIN_GAIN ; +dev_err (&client->dev,"Gain out of legal range." ); + } +if (lineargain >IMX046_MAX_GAIN ) { + lineargain =IMX046_MAX_GAIN ; +dev_err (&client->dev,"Gain out of legal range." ); + } + +/* Convert gain from linear to register value +- reg_gain = 256 - 256 / linear_gain +- do divide with rounding +*/ + reg_gain =256 - + ((((u32)(256 <<9 ) + (1 <<8 )) / lineargain) + >>1 ); + dev_dbg(&client->dev, "set_gain: lineargain=%dreg_gain=%d\n",
drivers/media/video/imx046.c new file +3
-0+ lineargain, reg_gain); + + err = imx046_write_reg(client,
IMX046_REG_ANALOG_GAIN_GLOBAL,drivers/media/video/imx046.c new file +5
-0+ reg_gain, I2C_16BIT); + } + +if (err) { + dev_err(&client->dev, "Error setting analog gain: %d",err);
drivers/media/video/imx046.c new file +13
-0+ }else { + i =find_vctrl (V4L2_CID_GAIN ); +if (i >=0 ) { + lvc = &imx046sensor_video_control[i]; + lvc->current_value = lineargain; + } + } + +return err; +} + +/** +* imx046_update_clocks - calcs sensor clocks based on sensor settings.
+ * @isize: image size enum
+ */drivers/media/video/imx046.c new file +32
-0+int imx046_update_clocks (u32 xclk,enum imx046_image_size isize) +{ + current_clk.vco_clk = + xclk * sensor_settings[isize].clk.pll_mult / + sensor_settings[isize].clk.pre_pll_div / + sensor_settings[isize].clk.post_pll_div; + + current_clk.vt_pix_clk = current_clk.vco_clk *2 / + (sensor_settings[isize].clk.vt_pix_clk_div * + sensor_settings[isize].clk.vt_sys_clk_div); + +if (sensor_settings[isize].mipi.data_lanes ==2 ) + current_clk.mipi_clk = current_clk.vco_clk; +else + current_clk.mipi_clk = current_clk.vco_clk /2 ; + + current_clk.ddr_clk = current_clk.mipi_clk /2 ; + +printk (KERN_DEBUG "IMX046: xclk=%u, vco_clk=%u, " +"vt_pix_clk=%u, mipi_clk=%u, ddr_clk=%u\n" , + xclk, current_clk.vco_clk, current_clk.vt_pix_clk, + current_clk.mipi_clk, current_clk.ddr_clk); + +return 0 ; +} + +/** +* imx046_setup_pll - initializes sensor PLL registers. +* @c: i2c client driver structure +* @isize: image size enum +*/ +int imx046_setup_pll(struct i2c_client *client, enum
imx046_image_sizeisize)drivers/media/video/imx046.c new file +14
-0+{ +u32 rgpltd_reg; +u32 rgpltd[3 ] = {2 ,0 ,1 }; + +imx046_write_reg (client,IMX046_REG_PRE_PLL_CLK_DIV , + sensor_settings[isize].clk.pre_pll_div,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_PLL_MULTIPLIER , + sensor_settings[isize].clk.pll_mult,I2C_16BIT ); + +imx046_read_reg (client,I2C_8BIT ,IMX046_REG_RGPLTD_RGCLKEN , + &rgpltd_reg); + rgpltd_reg &= ~RGPLTD_MASK ; + rgpltd_reg |= rgpltd[sensor_settings[isize].clk.post_pll_divQuoted 1 line
Quoted 1 line
1];
drivers/media/video/imx046.c new file +33
-0+imx046_write_reg (client,IMX046_REG_RGPLTD_RGCLKEN , + rgpltd_reg,I2C_8BIT ); + +imx046_write_reg (client,IMX046_REG_VT_PIX_CLK_DIV , + sensor_settings[isize].clk.vt_pix_clk_div,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_VT_SYS_CLK_DIV , + sensor_settings[isize].clk.vt_sys_clk_div,I2C_16BIT ); + +printk (KERN_DEBUG "IMX046: pre_pll_clk_div=%u, pll_mult=%u, " +"rgpltd=0x%x, vt_pix_clk_div=%u, vt_sys_clk_div=%u\n" , + sensor_settings[isize].clk.pre_pll_div, + sensor_settings[isize].clk.pll_mult, rgpltd_reg, + sensor_settings[isize].clk.vt_pix_clk_div, + sensor_settings[isize].clk.vt_sys_clk_div); + +return 0 ; +} + +/** +* imx046_setup_mipi - initializes sensor & isp MIPI registers. +* @c: i2c client driver structure +* @isize: image size enum +*/ +int imx046_setup_mipi (struct imx046_sensor *sensor, +enum imx046_image_size isize) +{ +struct i2c_client *client = sensor->i2c_client; + +/* NOTE: Make sure imx046_update_clocks is called 1st */ + +/* Enable MIPI */ + imx046_write_reg(client, IMX046_REG_RGOUTSEL1, 0x00,
I2C_8BIT);drivers/media/video/imx046.c new file +4
-0+imx046_write_reg (client,IMX046_REG_TESTDI ,0x04 ,I2C_8BIT ); + +/* Set sensor Mipi timing params */ + imx046_write_reg(client, IMX046_REG_RGTHSTRAIL, 0x06,
I2C_8BIT);drivers/media/video/imx046.c new file +10
-0+ +imx046_write_reg (client,IMX046_REG_RGTHSPREPARE , + sensor_settings[isize].mipi.ths_prepare,I2C_8BIT ); + +imx046_write_reg (client,IMX046_REG_RGTHSZERO , + sensor_settings[isize].mipi.ths_zero,I2C_8BIT ); + +/* Set number of lanes in sensor */ +if (sensor_settings[isize].mipi.data_lanes ==2 ) + imx046_write_reg(client, IMX046_REG_RGLANESEL, 0x00,
I2C_8BIT);drivers/media/video/imx046.c new file +2
-0+else + imx046_write_reg(client, IMX046_REG_RGLANESEL, 0x01,
I2C_8BIT);drivers/media/video/imx046.c new file +3
-0+ +/* Set number of lanes in isp */ + sensor->pdata-Quoted 1 line
csi2_lane_count(sensor_settings[isize].mipi.data_lanes);drivers/media/video/imx046.c new file +29
-0+ +/* Send settings to ISP-CSI2 Receiver PHY */ + sensor->pdata->csi2_calc_phy_cfg0 (current_clk.mipi_clk, + sensor_settings[isize].mipi.ths_settle_lower, + sensor_settings[isize].mipi.ths_settle_upper); + +/* Dump some registers for debug purposes */ +printk (KERN_DEBUG "imx:THSPREPARE=0x%02X\n" , + sensor_settings[isize].mipi.ths_prepare); +printk (KERN_DEBUG "imx:THSZERO=0x%02X\n" , + sensor_settings[isize].mipi.ths_zero); +printk (KERN_DEBUG "imx:LANESEL=0x%02X\n" , + (sensor_settings[isize].mipi.data_lanes ==2 ) ?0 :1 ); + +return 0 ; +} + +/** +* imx046_configure_frame - initializes image frame registers +* @c: i2c client driver structure +* @isize: image size enum +*/ +int imx046_configure_frame (struct i2c_client *client, +enum imx046_image_size isize) +{ +u32 val; + + imx046_write_reg(client, IMX046_REG_FRAME_LEN_LINES, + sensor_settings[isize].frame.frame_len_lines_min,
I2C_16BIT);drivers/media/video/imx046.c new file +35
-0+ +imx046_write_reg (client,IMX046_REG_LINE_LEN_PCK , + sensor_settings[isize].frame.line_len_pck,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_X_ADDR_START , + sensor_settings[isize].frame.x_addr_start,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_X_ADDR_END , + sensor_settings[isize].frame.x_addr_end,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_Y_ADDR_START , + sensor_settings[isize].frame.y_addr_start,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_Y_ADDR_END , + sensor_settings[isize].frame.y_addr_end,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_X_OUTPUT_SIZE , + sensor_settings[isize].frame.x_output_size,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_Y_OUTPUT_SIZE , + sensor_settings[isize].frame.y_output_size,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_X_EVEN_INC , + sensor_settings[isize].frame.x_even_inc,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_X_ODD_INC , + sensor_settings[isize].frame.x_odd_inc,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_Y_EVEN_INC , + sensor_settings[isize].frame.y_even_inc,I2C_16BIT ); + +imx046_write_reg (client,IMX046_REG_Y_ODD_INC , + sensor_settings[isize].frame.y_odd_inc,I2C_16BIT ); + + imx046_read_reg(client, I2C_8BIT, IMX046_REG_PGACUR_VMODEADD,&val);
drivers/media/video/imx046.c new file +2
-0+ val &= ~VMODEADD_MASK ; + val |= sensor_settings[isize].frame.v_mode_add <<
VMODEADD_SHIFT;
+ imx046_write_reg(client,IMX046_REG_PGACUR_VMODEADD, val,I2C_8BIT);drivers/media/video/imx046.c new file +4
-0+ +imx046_read_reg (client,I2C_8BIT ,IMX046_REG_HMODEADD , &val); + val &= ~HMODEADD_MASK ; + val |= sensor_settings[isize].frame.h_mode_add <<
HMODEADD_SHIFT;drivers/media/video/imx046.c new file +5
-0+imx046_write_reg (client,IMX046_REG_HMODEADD , val,I2C_8BIT ); + +imx046_read_reg (client,I2C_8BIT ,IMX046_REG_HADDAVE , &val); + val &= ~HADDAVE_MASK ; + val |= sensor_settings[isize].frame.h_add_ave <<
HADDAVE_SHIFT;drivers/media/video/imx046.c new file +7
-0+imx046_write_reg (client,IMX046_REG_HADDAVE , val,I2C_8BIT ); + +return 0 ; +} + +/** +* imx046_configure - Configure the imx046 for the specified image mode
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Configure the imx046 for a specified image size, pixel format, and frame
+ * period. xclk is the frequency (in Hz) of the xclk input to the imx046.
+ * fper is the frame period (in seconds) expressed as a fraction.
+ * Returns zero if successful, or non-zero otherwise.
+ * The actual frame period is returned in fper.
+ */drivers/media/video/imx046.c new file +13
-0+static int imx046_configure (struct v4l2_int_device *s) +{ +struct imx046_sensor *sensor = s->priv; +struct v4l2_pix_format *pix = &sensor->pix; +struct i2c_client *client = sensor->i2c_client; +enum imx046_image_size isize; +int err, i; +struct vcontrol *lvc =NULL ; + + isize =imx046_find_size (pix->width, pix->height); + isize_current = isize; + + err = imx046_write_reg(client, IMX046_REG_SW_RESET, 0x01,
I2C_8BIT);drivers/media/video/imx046.c new file +42
-0+mdelay (5 ); + +imx046_write_regs (client, initial_list); + +imx046_update_clocks (xclk_current, isize); +imx046_setup_pll (client, isize); + +imx046_setup_mipi (sensor, isize); + +/* configure image size and pixel format */ +imx046_configure_frame (client, isize); + +/* Setting of frame rate */ + err =imx046_set_framerate (s, &sensor->timeperframe); + +imx046_set_orientation (client, sensor->ver); + + sensor->pdata->cfg_interface_bridge (0x00 ); + sensor->pdata->csi2_cfg_vp_out_ctrl (2 ); + sensor->pdata->csi2_ctrl_update (false); + + sensor->pdata->csi2_cfg_virtual_id (0 ,IMX046_CSI2_VIRTUAL_ID ); + sensor->pdata->csi2_ctx_update (0 , false); +imx046_set_virtual_id (client,IMX046_CSI2_VIRTUAL_ID ); + +/* Set initial exposure and gain */ + i =find_vctrl (V4L2_CID_EXPOSURE ); +if (i >=0 ) { + lvc = &imx046sensor_video_control[i]; +imx046sensor_set_exposure_time (lvc->current_value, + sensor->v4l2_int_device, lvc); + } + + i =find_vctrl (V4L2_CID_GAIN ); +if (i >=0 ) { + lvc = &imx046sensor_video_control[i]; +imx046sensor_set_gain (lvc->current_value, + sensor->v4l2_int_device, lvc); + } + +/* configure streaming ON */ + err = imx046_write_reg(client, IMX046_REG_MODE_SELECT, 0x01,
I2C_8BIT);drivers/media/video/imx046.c new file +7
-0+mdelay (1 ); + +return err; +} + +/** +* imx046_detect - Detect if an imx046 is present, and if so which revision
+ * @client: pointer to the i2c client driver structure
+ *
+ * Detect if an imx046 is present, and if so which revision.
+ * A device is considered to be detected if the manufacturer ID (MIDH and MIDL)
+ * and the product ID (PID) registers match the expected values.
+ * Any value of the version ID (VER) register is accepted.
+ * Returns a negative error number if no device is detected, or the
+ * non-negative value of the version ID register if a device is detected.
+ */drivers/media/video/imx046.c new file +15
-0+static int +imx046_detect (struct i2c_client *client) +{ +u32 model_id, mfr_id, rev; +struct imx046_sensor *sensor; + +dev_dbg (&client->dev,"imx046_detect client.addr=0x%x\n" , + client->addr); + +if (!client) +return -ENODEV ; + + sensor =i2c_get_clientdata (client); + + if (imx046_read_reg(client, I2C_16BIT, IMX046_REG_MODEL_ID,
&model_id))drivers/media/video/imx046.c new file +2
-0+return -ENODEV ; + if (imx046_read_reg(client, I2C_8BIT, IMX046_REG_MFR_ID,
&mfr_id))drivers/media/video/imx046.c new file +2
-0+return -ENODEV ; + if (imx046_read_reg(client, I2C_8BIT, IMX046_REG_REV_NUMBER,&rev))
drivers/media/video/imx046.c new file +3
-0+return -ENODEV ; + + dev_info(&client->dev, "model id detected 0x%x mfr 0x%x, rev#0x%x\n",
drivers/media/video/imx046.c new file +2
-0+ model_id, mfr_id, rev); +if ((model_id !=IMX046_MOD_ID ) || (mfr_id !=IMX046_MFR_ID )){
drivers/media/video/imx046.c new file +4
-0+/* We didn't read the values we expected, so +* this must not be an IMX046. +*/ + dev_warn(&client->dev, "model id mismatch 0x%x mfr0x%x\n",
drivers/media/video/imx046.c new file +9
-0+ model_id, mfr_id); + +return -ENODEV ; + } +return rev; +} + +/** +* ioctl_queryctrl - V4L2 sensor interface handler for
VIDIOC_QUERYCTRLioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qc: standard V4L2VIDIOC_QUERYCTRLioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * from the imx046sensor_video_control[] array.
+ * Otherwise, returns-EINVALif the control is not supported.
+ */drivers/media/video/imx046.c new file +18
-0+static int ioctl_queryctrl (struct v4l2_int_device *s, +struct v4l2_queryctrl *qc) +{ +int i; + + i =find_vctrl (qc->id); +if (i == -EINVAL ) + qc->flags =V4L2_CTRL_FLAG_DISABLED ; + +if (i <0 ) +return -EINVAL ; + + *qc = imx046sensor_video_control[i].qc; +return 0 ; +} + +/** +* ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2VIDIOC_G_CTRLioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the imx046sensor_video_control[] array.
+ * Otherwise, returns-EINVALif the control is not supported.
+ */drivers/media/video/imx046.c new file +25
-0+static int ioctl_g_ctrl (struct v4l2_int_device *s, +struct v4l2_control *vc) +{ +struct vcontrol *lvc; +int i; + + i =find_vctrl (vc->id); +if (i <0 ) +return -EINVAL ; + lvc = &imx046sensor_video_control[i]; + +switch (vc->id) { +case V4L2_CID_EXPOSURE : + vc->value = lvc->current_value; +break ; +case V4L2_CID_GAIN : + vc->value = lvc->current_value; +break ; + } + +return 0 ; +} + +/** +* ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2VIDIOC_S_CTRLioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the imx046sensor_video_control[] array).
+ * Otherwise, * returns-EINVALif the control is not supported.
+ */drivers/media/video/imx046.c new file +15
-0+static int ioctl_s_ctrl (struct v4l2_int_device *s, +struct v4l2_control *vc) +{ +int retval = -EINVAL ; +int i; +struct vcontrol *lvc; + + i =find_vctrl (vc->id); +if (i <0 ) +return -EINVAL ; + lvc = &imx046sensor_video_control[i]; + +switch (vc->id) { +case V4L2_CID_EXPOSURE : + retval = imx046sensor_set_exposure_time(vc->value, s,lvc);
drivers/media/video/imx046.c new file +11
-0+break ; +case V4L2_CID_GAIN : + retval =imx046sensor_set_gain (vc->value, s, lvc); +break ; + } + +return retval; +} + +/** +* ioctl_enum_fmt_cap - Implement the CAPTURE buffer
VIDIOC_ENUM_FMTioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: standard V4L2VIDIOC_ENUM_FMTioctl structure
+ *
+ * Implement theVIDIOC_ENUM_FMTioctl for the CAPTURE buffer type.
+ */drivers/media/video/imx046.c new file +29
-0+static int ioctl_enum_fmt_cap (struct v4l2_int_device *s, +struct v4l2_fmtdesc *fmt) +{ +int index = fmt->index; +enum v4l2_buf_type type = fmt->type; + +memset (fmt,0 ,sizeof (*fmt)); + fmt->index = index; + fmt->type = type; + +switch (fmt->type) { +case V4L2_BUF_TYPE_VIDEO_CAPTURE : +if (index >=NUM_CAPTURE_FORMATS ) +return -EINVAL ; +break ; +default : +return -EINVAL ; + } + + fmt->flags = imx046_formats[index].flags; +strlcpy (fmt->description, imx046_formats[index].description, +sizeof (fmt->description)); + fmt->pixelformat = imx046_formats[index].pixelformat; + +return 0 ; +} + +/** +* ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2VIDIOC_TRY_FMTioctl structure
+ *
+ * Implement theVIDIOC_TRY_FMTioctl for the CAPTURE buffer type. This
+ * ioctl is used to negotiate the image capture size and pixel format
+ * without actually making it take effect.
+ */drivers/media/video/imx046.c new file +15
-0+static int ioctl_try_fmt_cap (struct v4l2_int_device *s, +struct v4l2_format *f) +{ +enum imx046_image_size isize; +int ifmt; +struct v4l2_pix_format *pix = &f->fmt.pix; +struct imx046_sensor *sensor = s->priv; +struct v4l2_pix_format *pix2 = &sensor->pix; + + isize =imx046_find_size (pix->width, pix->height); + + pix->width = imx046_sizes[isize].width; + pix->height = imx046_sizes[isize].height; +for (ifmt =0 ; ifmt <NUM_CAPTURE_FORMATS ; ifmt++) { + if (pix->pixelformat ==imx046_formats[ifmt].pixelformat)
drivers/media/video/imx046.c new file +16
-0+break ; + } +if (ifmt ==NUM_CAPTURE_FORMATS ) + ifmt =0 ; + pix->pixelformat = imx046_formats[ifmt].pixelformat; + pix->field =V4L2_FIELD_NONE ; + pix->bytesperline = pix->width *2 ; + pix->sizeimage = pix->bytesperline * pix->height; + pix->priv =0 ; + pix->colorspace =V4L2_COLORSPACE_SRGB ; + *pix2 = *pix; +return 0 ; +} + +/** +* ioctl_s_fmt_cap - V4L2 sensor interface handler for VIDIOC_S_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2VIDIOC_S_FMTioctl structure
+ *
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */drivers/media/video/imx046.c new file +19
-0+static int ioctl_s_fmt_cap (struct v4l2_int_device *s, +struct v4l2_format *f) +{ +struct imx046_sensor *sensor = s->priv; +struct v4l2_pix_format *pix = &f->fmt.pix; +int rval; + + rval =ioctl_try_fmt_cap (s, f); +if (rval) +return rval; +else + sensor->pix = *pix; + + +return rval; +} + +/** +* ioctl_g_fmt_cap - V4L2 sensor interface handler for
ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2v4l2_formatstructure
+ *
+ * Returns the sensor's current pixel format in thev4l2_format
+ * parameter.
+ */drivers/media/video/imx046.c new file +11
-0+static int ioctl_g_fmt_cap (struct v4l2_int_device *s, +struct v4l2_format *f) +{ +struct imx046_sensor *sensor = s->priv; + f->fmt.pix = sensor->pix; + +return 0 ; +} + +/** +* ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2VIDIOC_G_PARMioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */drivers/media/video/imx046.c new file +20
-0+static int ioctl_g_parm (struct v4l2_int_device *s, +struct v4l2_streamparm *a) +{ +struct imx046_sensor *sensor = s->priv; +struct v4l2_captureparm *cparm = &a->parm.capture; + +if (a->type !=V4L2_BUF_TYPE_VIDEO_CAPTURE ) +return -EINVAL ; + +memset (a,0 ,sizeof (*a)); + a->type =V4L2_BUF_TYPE_VIDEO_CAPTURE ; + + cparm->capability =V4L2_CAP_TIMEPERFRAME ; + cparm->timeperframe = sensor->timeperframe; + +return 0 ; +} + +/** +* ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2VIDIOC_S_PARMioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */drivers/media/video/imx046.c new file +5
-0+static int ioctl_s_parm (struct v4l2_int_device *s, +struct v4l2_streamparm *a) +{ +struct imx046_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &a-Quoted 1 line
parm.capture.timeperframe;
drivers/media/video/imx046.c new file +11
-0+ + sensor->timeperframe = *timeperframe; +imx046sensor_calc_xclk (); + *timeperframe = sensor->timeperframe; + +return 0 ; +} + + +/** +* ioctl_g_priv - V4L2 sensor interface handler for
vidioc_int_g_priv_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: void pointer to hold sensor's private data address
+ *
+ * Returns device's (sensor's) private data area address in p parameter
+ */drivers/media/video/imx046.c new file +9
-0+static int ioctl_g_priv (struct v4l2_int_device *s,void *p) +{ +struct imx046_sensor *sensor = s->priv; + +return sensor->pdata->priv_data_set (p); +} + +/** +* ioctl_s_power - V4L2 sensor interface handler for
vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ */
+static intioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)drivers/media/video/imx046.c new file +14
-0+{ +struct imx046_sensor *sensor = s->priv; +struct i2c_client *c = sensor->i2c_client; +struct omap34xxcam_hw_config hw_config; +struct vcontrol *lvc; +int rval, i; + + rval =ioctl_g_priv (s, &hw_config); +if (rval) { +dev_err (&c->dev,"Unable to get hw params\n" ); +return rval; + } + + if ((on == V4L2_POWER_STANDBY) && (sensor->state ==
SENSOR_DETECTED)) {drivers/media/video/imx046.c new file +8
-0+/* imx046_write_regs(c, stream_off_list, +I2C_STREAM_OFF_LIST_SIZE); */ + } + +if (on !=V4L2_POWER_ON ) + sensor->pdata->set_xclk (0 , hw_config.u.sensor.xclk); +else + sensor->pdata->set_xclk(xclk_current,hw_config.u.sensor.xclk);
drivers/media/video/imx046.c new file +17
-0+ + rval = sensor->pdata->power_set (on); +if (rval <0 ) { +dev_err (&c->dev,"Unable to set the power state: " +IMX046_DRIVER_NAME " sensor\n" ); + sensor->pdata->set_xclk (0 , hw_config.u.sensor.xclk); +return rval; + } + +if ((current_power_state ==V4L2_POWER_STANDBY ) && + (on ==V4L2_POWER_ON ) && + (sensor->state ==SENSOR_DETECTED )) { + sensor->resuming = true; +imx046_configure (s); + } + + if ((on == V4L2_POWER_ON) && (sensor->state ==
SENSOR_NOT_DETECTED)) {drivers/media/video/imx046.c new file +10
-0+ rval =imx046_detect (c); +if (rval <0 ) { +dev_err (&c->dev,"Unable to detect " +IMX046_DRIVER_NAME " sensor\n" ); + sensor->state =SENSOR_NOT_DETECTED ; +return rval; + } + sensor->state =SENSOR_DETECTED ; + sensor->ver = rval; + pr_info(IMX046_DRIVER_NAME " chip version 0x%02xdetected\n",
drivers/media/video/imx046.c new file +35
-0+ sensor->ver); + } + +if (on ==V4L2_POWER_OFF ) { +/* Reset defaults for controls */ + i =find_vctrl (V4L2_CID_GAIN ); +if (i >=0 ) { + lvc = &imx046sensor_video_control[i]; + lvc->current_value =IMX046_DEF_GAIN ; + } + i =find_vctrl (V4L2_CID_EXPOSURE ); +if (i >=0 ) { + lvc = &imx046sensor_video_control[i]; + lvc->current_value =IMX046_DEF_EXPOSURE ; + } + } + + sensor->resuming = false; + current_power_state = on; +return 0 ; +} + +/** +* ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT +* @s: pointer to standard V4L2 device structure +* +* Initialize the sensor device (call imx046_configure()) +*/ +static int ioctl_init (struct v4l2_int_device *s) +{ +return 0 ; +} + +/** +* ioctl_dev_exit - V4L2 sensor interface handler for
vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the dev. at slave detach. The complement ofioctl_dev_init.
+ */drivers/media/video/imx046.c new file +7
-0+static int ioctl_dev_exit (struct v4l2_int_device *s) +{ +return 0 ; +} + +/** +* ioctl_dev_init - V4L2 sensor interface handler for
vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master. Returns 0 if
+ * imx046 device could be found, otherwise returns appropriate error.
+ */drivers/media/video/imx046.c new file +22
-0+static int ioctl_dev_init (struct v4l2_int_device *s) +{ +struct imx046_sensor *sensor = s->priv; +struct i2c_client *c = sensor->i2c_client; +int err; + + err =imx046_detect (c); +if (err <0 ) { +dev_err (&c->dev,"Unable to detect " IMX046_DRIVER_NAME +" sensor\n" ); +return err; + } + + sensor->ver = err; +pr_info (IMX046_DRIVER_NAME " chip version 0x%02x detected\n" , + sensor->ver); + +return 0 ; +} + +/** +* ioctl_enum_framesizes - V4L2 sensor if handler for
vidioc_int_enum_framesizes
+ * @s: pointer to standard V4L2 device structure
+ * @frms: pointer to standard V4L2 framesizes enumeration structure
+ *
+ * Returns possible framesizes depending on choosen pixel format
+ **/drivers/media/video/imx046.c new file +7
-0+static int ioctl_enum_framesizes (struct v4l2_int_device *s, +struct v4l2_frmsizeenum *frms) +{ +int ifmt; + +for (ifmt =0 ; ifmt <NUM_CAPTURE_FORMATS ; ifmt++) { + if (frms->pixel_format ==imx046_formats[ifmt].pixelformat)
drivers/media/video/imx046.c new file +31
-0+break ; + } +/* Is requested pixelformat not found on sensor? */ +if (ifmt ==NUM_CAPTURE_FORMATS ) +return -EINVAL ; + +/* Check that the index we are being asked for is not +out of bounds. */ +if (frms->index >=ARRAY_SIZE (imx046_sizes)) +return -EINVAL ; + + frms->type =V4L2_FRMSIZE_TYPE_DISCRETE ; + frms->discrete.width = imx046_sizes[frms->index].width; + frms->discrete.height = imx046_sizes[frms->index].height; + +return 0 ; +} + +const struct v4l2_fract imx046_frameintervals[] = { + { .numerator =3 , .denominator =30 }, + { .numerator =1 , .denominator =30 }, +}; + +static int ioctl_enum_frameintervals (struct v4l2_int_device *s, +struct v4l2_frmivalenum *frmi) +{ +int ifmt; + +/* Check that the requested format is one we support */ +for (ifmt =0 ; ifmt <NUM_CAPTURE_FORMATS ; ifmt++) { + if (frmi->pixel_format ==imx046_formats[ifmt].pixelformat)
drivers/media/video/imx046.c new file +20
-0+break ; + } + +if (ifmt ==NUM_CAPTURE_FORMATS ) +return -EINVAL ; + +/* Check that the index we are being asked for is not +out of bounds. */ +if (frmi->index >=ARRAY_SIZE (imx046_frameintervals)) +return -EINVAL ; + +/* Make sure that the 8MP size reports a max of 10fps */ +if (frmi->width ==3280 && frmi->height ==2464 ) { +if (frmi->index !=0 ) +return -EINVAL ; + } + + frmi->type =V4L2_FRMIVAL_TYPE_DISCRETE ; + frmi->discrete.numerator = + imx046_frameintervals[frmi-Quoted 1 line
index].numerator;
drivers/media/video/imx046.c new file +2
-0+ frmi->discrete.denominator = + imx046_frameintervals[frmi-Quoted 1 line
index].denominator;
drivers/media/video/imx046.c new file +83
-0+ +return 0 ; +} + +static struct v4l2_int_ioctl_desc imx046_ioctl_desc[] = { + { .num = vidioc_int_enum_framesizes_num, + .func = (v4l2_int_ioctl_func *)ioctl_enum_framesizes}, + { .num = vidioc_int_enum_frameintervals_num, + .func = (v4l2_int_ioctl_func *)ioctl_enum_frameintervals}, + { .num = vidioc_int_dev_init_num, + .func = (v4l2_int_ioctl_func *)ioctl_dev_init}, + { .num = vidioc_int_dev_exit_num, + .func = (v4l2_int_ioctl_func *)ioctl_dev_exit}, + { .num = vidioc_int_s_power_num, + .func = (v4l2_int_ioctl_func *)ioctl_s_power }, + { .num = vidioc_int_g_priv_num, + .func = (v4l2_int_ioctl_func *)ioctl_g_priv }, + { .num = vidioc_int_init_num, + .func = (v4l2_int_ioctl_func *)ioctl_init }, + { .num = vidioc_int_enum_fmt_cap_num, + .func = (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, + { .num = vidioc_int_try_fmt_cap_num, + .func = (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, + { .num = vidioc_int_g_fmt_cap_num, + .func = (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, + { .num = vidioc_int_s_fmt_cap_num, + .func = (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, + { .num = vidioc_int_g_parm_num, + .func = (v4l2_int_ioctl_func *)ioctl_g_parm }, + { .num = vidioc_int_s_parm_num, + .func = (v4l2_int_ioctl_func *)ioctl_s_parm }, + { .num = vidioc_int_queryctrl_num, + .func = (v4l2_int_ioctl_func *)ioctl_queryctrl }, + { .num = vidioc_int_g_ctrl_num, + .func = (v4l2_int_ioctl_func *)ioctl_g_ctrl }, + { .num = vidioc_int_s_ctrl_num, + .func = (v4l2_int_ioctl_func *)ioctl_s_ctrl }, +}; + +static struct v4l2_int_slave imx046_slave = { + .ioctls = imx046_ioctl_desc, + .num_ioctls =ARRAY_SIZE (imx046_ioctl_desc), +}; + +static struct v4l2_int_device imx046_int_device = { + .module =THIS_MODULE , + .name =IMX046_DRIVER_NAME , + .priv = &imx046, + .type = v4l2_int_type_slave, + .u = { + .slave = &imx046_slave, + }, +}; + +/** +* imx046_probe - sensor driver i2c probe handler +* @client: i2c driver client device structure +* +* Register sensor as an i2c client device and V4L2 +* device. +*/ +static int __devinit imx046_probe (struct i2c_client *client, +const struct i2c_device_id *id) +{ +struct imx046_sensor *sensor = &imx046; +int err; + +if (i2c_get_clientdata (client)) +return -EBUSY ; + + sensor->pdata = client->dev.platform_data; + +if (!sensor->pdata) { +dev_err (&client->dev,"no platform data?\n" ); +return -ENODEV ; + } + + sensor->v4l2_int_device = &imx046_int_device; + sensor->i2c_client = client; + +i2c_set_clientdata (client, sensor); + +/* Make the default capture format QCIF V4L2_PIX_FMT_SGRBG10 */
drivers/media/video/imx046.c new file +69
-0+ sensor->pix.width =IMX046_IMAGE_WIDTH_MAX ; + sensor->pix.height =IMX046_IMAGE_HEIGHT_MAX ; + sensor->pix.pixelformat =V4L2_PIX_FMT_SGRBG10 ; + + err =v4l2_int_device_register (sensor->v4l2_int_device); +if (err) +i2c_set_clientdata (client,NULL ); + +return 0 ; +} + +/** +* imx046_remove - sensor driver i2c remove handler +* @client: i2c driver client device structure +* +* Unregister sensor as an i2c client device and V4L2 +* device. Complement of imx046_probe(). +*/ +static int __exit +imx046_remove (struct i2c_client *client) +{ +struct imx046_sensor *sensor =i2c_get_clientdata (client); + +if (!client->adapter) +return -ENODEV ;/* our client isn't attached */ + +v4l2_int_device_unregister (sensor->v4l2_int_device); +i2c_set_clientdata (client,NULL ); + +return 0 ; +} + +static const struct i2c_device_id imx046_id[] = { + {IMX046_DRIVER_NAME ,0 }, + { }, +}; +MODULE_DEVICE_TABLE (i2c, imx046_id); + +static struct i2c_driver imx046sensor_i2c_driver = { + .driver = { + .name =IMX046_DRIVER_NAME , + .owner =THIS_MODULE , + }, + .probe = imx046_probe, + .remove =__exit_p (imx046_remove), + .id_table = imx046_id, +}; + +static struct imx046_sensor imx046 = { + .timeperframe = { + .numerator =1 , + .denominator =30 , + }, + .state =SENSOR_NOT_DETECTED , +}; + +/** +* imx046sensor_init - sensor driver module_init handler +* +* Registers driver as an i2c client driver. Returns 0 on success, +* error code otherwise. +*/ +static int __init imx046sensor_init (void ) +{ +int err; + + err =i2c_add_driver (&imx046sensor_i2c_driver); +if (err) { + printk(KERN_ERR "Failed to register" IMX046_DRIVER_NAME".\n");
drivers/media/video/imx046.c new file +20
-0+return err; + } +return 0 ; +} +late_initcall (imx046sensor_init); + +/** +* imx046sensor_cleanup - sensor driver module_exit handler +* +* Unregisters/deletes driver as an i2c client driver. +* Complement of imx046sensor_init. +*/ +static void __exit imx046sensor_cleanup(void) +{ +i2c_del_driver (&imx046sensor_i2c_driver); +} +module_exit (imx046sensor_cleanup); + +MODULE_LICENSE ("GPL" ); +MODULE_DESCRIPTION ("imx046 camera sensor driver" );Index:
omapzoom04/drivers/media/video/imx046.h
===================================================================drivers/media/video/imx046.h new file +10
-0@@ -0,0 +1,326 @@ +/* +* drivers/media/video/imx046.h +* +* Register definitions for the IMX046 Sensor. +* +* Leverage MT9P012.h +* +* Copyright (C) 2008 Hewlett Packard. +* +* This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */drivers/media/video/imx046.h new file +93
-0+ +#ifndef IMX046_H +#define IMX046_H + +#define IMX046_I2C_ADDR 0x1A + +/* The ID values we are looking for */ +#define IMX046_MOD_ID 0x0046 +#define IMX046_MFR_ID 0x000B + +#define VAUX_2_8_V 0x09 +#define VAUX_1_8_V 0x05 +#define VAUX_DEV_GRP_P1 0x20 +#define VAUX_DEV_GRP_NONE 0x00 + +/* IMX046 has 8/16/32 I2C registers */ +#define I2C_8BIT 1 +#define I2C_16BIT 2 +#define I2C_32BIT 4 + +/* Terminating list entry for reg */ +#define I2C_REG_TERM 0xFFFF +/* Terminating list entry for val */ +#define I2C_VAL_TERM 0xFFFFFFFF +/* Terminating list entry for len */ +#define I2C_LEN_TERM 0xFFFF + +/* terminating token for reg list */ +#define IMX046_TOK_TERM 0xFF + +/* delay token for reg list */ +#define IMX046_TOK_DELAY 100 + +/* Sensor specific GPIO signals */ +#define IMX046_RESET_GPIO 98 +#define IMX046_STANDBY_GPIO 58 + +/* CSI2 Virtual ID */ +#define IMX046_CSI2_VIRTUAL_ID 0x0 + +#define IMX046_CLKRC 0x11 + +/* Average black level */ +#define IMX046_BLACK_LEVEL_AVG 64 + +/* Used registers */ +#define IMX046_REG_MODEL_ID 0x0000 +#define IMX046_REG_REV_NUMBER 0x0002 +#define IMX046_REG_MFR_ID 0x0003 + +#define IMX046_REG_MODE_SELECT 0x0100 +#define IMX046_REG_IMAGE_ORIENTATION 0x0101 +#define IMX046_REG_SW_RESET 0x0103 +#define IMX046_REG_GROUPED_PAR_HOLD 0x0104 +#define IMX046_REG_CCP2_CHANNEL_ID 0x0110 + +#define IMX046_REG_FINE_INT_TIME 0x0200 +#define IMX046_REG_COARSE_INT_TIME 0x0202 + +#define IMX046_REG_ANALOG_GAIN_GLOBAL 0x0204 +#define IMX046_REG_ANALOG_GAIN_GREENR 0x0206 +#define IMX046_REG_ANALOG_GAIN_RED 0x0208 +#define IMX046_REG_ANALOG_GAIN_BLUE 0x020A +#define IMX046_REG_ANALOG_GAIN_GREENB 0x020C +#define IMX046_REG_DIGITAL_GAIN_GREENR 0x020E +#define IMX046_REG_DIGITAL_GAIN_RED 0x0210 +#define IMX046_REG_DIGITAL_GAIN_BLUE 0x0212 +#define IMX046_REG_DIGITAL_GAIN_GREENB 0x0214 + +#define IMX046_REG_VT_PIX_CLK_DIV 0x0300 +#define IMX046_REG_VT_SYS_CLK_DIV 0x0302 +#define IMX046_REG_PRE_PLL_CLK_DIV 0x0304 +#define IMX046_REG_PLL_MULTIPLIER 0x0306 +#define IMX046_REG_OP_PIX_CLK_DIV 0x0308 +#define IMX046_REG_OP_SYS_CLK_DIV 0x030A + +#define IMX046_REG_FRAME_LEN_LINES 0x0340 +#define IMX046_REG_LINE_LEN_PCK 0x0342 + +#define IMX046_REG_X_ADDR_START 0x0344 +#define IMX046_REG_Y_ADDR_START 0x0346 +#define IMX046_REG_X_ADDR_END 0x0348 +#define IMX046_REG_Y_ADDR_END 0x034A +#define IMX046_REG_X_OUTPUT_SIZE 0x034C +#define IMX046_REG_Y_OUTPUT_SIZE 0x034E +#define IMX046_REG_X_EVEN_INC 0x0380 +#define IMX046_REG_X_ODD_INC 0x0382 +#define IMX046_REG_Y_EVEN_INC 0x0384 +#define IMX046_REG_Y_ODD_INC 0x0386 + +#define IMX046_REG_HMODEADD 0x3001 +#define HMODEADD_SHIFT 7 +#define HMODEADD_MASK (0x1 <<
HMODEADD_SHIFT)drivers/media/video/imx046.h new file +6
-0+#define IMX046_REG_OPB_CTRL 0x300C +#define IMX046_REG_Y_OPBADDR_START_DI 0x3014 +#define IMX046_REG_Y_OPBADDR_END_DI 0x3015 +#define IMX046_REG_PGACUR_VMODEADD 0x3016 +#define VMODEADD_SHIFT 6 +#define VMODEADD_MASK (0x1 <<
VMODEADD_SHIFT)drivers/media/video/imx046.h new file +17
-0+#define IMX046_REG_CHCODE_OUTCHSINGLE 0x3017 +#define IMX046_REG_OUTIF 0x301C +#define IMX046_REG_RGPLTD_RGCLKEN 0x3022 +#define RGPLTD_MASK 0x3 +#define IMX046_REG_RGPOF_RGPOFV2 0x3031 +#define IMX046_REG_CPCKAUTOEN 0x3040 +#define IMX046_REG_RGCPVFB 0x3041 +#define IMX046_REG_RGAZPDRV 0x3051 +#define IMX046_REG_RGAZTEST 0x3053 +#define IMX046_REG_RGVSUNLV 0x3055 +#define IMX046_REG_CLPOWER 0x3060 +#define IMX046_REG_CLPOWERSP 0x3065 +#define IMX046_REG_ACLDIRV_TVADDCLP 0x30AA +#define IMX046_REG_TESTDI 0x30E5 +#define IMX046_REG_HADDAVE 0x30E8 +#define HADDAVE_SHIFT 7 +#define HADDAVE_MASK (0x1 <<
HADDAVE_SHIFT)drivers/media/video/imx046.h new file +91
-0+ +#define IMX046_REG_RAW10CH2V2P_LO 0x31A4 +#define IMX046_REG_RAW10CH2V2D_LO 0x31A6 +#define IMX046_REG_COMP8CH1V2P_LO 0x31AC +#define IMX046_REG_COMP8CH1V2D_LO 0x31AE +#define IMX046_REG_RAW10CH1V2P_LO 0x31B4 +#define IMX046_REG_RAW10CH1V2D_LO 0x31B6 + +#define IMX046_REG_RGOUTSEL1 0x3300 +#define IMX046_REG_RGLANESEL 0x3301 +#define IMX046_REG_RGTLPX 0x3304 +#define IMX046_REG_RGTCLKPREPARE 0x3305 +#define IMX046_REG_RGTCLKZERO 0x3306 +#define IMX046_REG_RGTCLKPRE 0x3307 +#define IMX046_REG_RGTCLKPOST 0x3308 +#define IMX046_REG_RGTCLKTRAIL 0x3309 +#define IMX046_REG_RGTHSEXIT 0x330A +#define IMX046_REG_RGTHSPREPARE 0x330B +#define IMX046_REG_RGTHSZERO 0x330C +#define IMX046_REG_RGTHSTRAIL 0x330D + + +/* +* The nominal xclk input frequency of the IMX046 is 18MHz, maximum +* frequency is 45MHz, and minimum frequency is 6MHz. +*/ +#define IMX046_XCLK_MIN 6000000 +#define IMX046_XCLK_MAX 45000000 +#define IMX046_XCLK_NOM_1 18000000 +#define IMX046_XCLK_NOM_2 18000000 + +/* FPS Capabilities */ +#define IMX046_MIN_FPS 7 +#define IMX046_DEF_FPS 15 +#define IMX046_MAX_FPS 30 + +#define I2C_RETRY_COUNT 5 + +/* Still capture 8 MP */ +#define IMX046_IMAGE_WIDTH_MAX 3280 +#define IMX046_IMAGE_HEIGHT_MAX 2464 + +/* Analog gain values */ +#define IMX046_MIN_GAIN (256*1) +#define IMX046_MAX_GAIN (256*8) +#define IMX046_DEF_GAIN (256*2) +#define IMX046_GAIN_STEP 0x1 + +/* Exposure time values */ +#define IMX046_MIN_EXPOSURE 250 +#define IMX046_MAX_EXPOSURE 128000 +#define IMX046_DEF_EXPOSURE 33000 +#define IMX046_EXPOSURE_STEP 50 + +#define IMX046_MAX_FRAME_LENGTH_LINES 0xFFFF + +#define SENSOR_DETECTED 1 +#define SENSOR_NOT_DETECTED 0 + +/** +* struct imx046_reg - imx046 register format +* @reg: 16-bit offset to register +* @val: 8/16/32-bit register value +* @length: length of the register +* +* Define a structure for IMX046 register initialization values +*/ +struct imx046_reg { +u16 reg; +u32 val; +u16 length; +}; + +enum imx046_image_size { +HALF_MP , +TWO_MP , +EIGHT_MP +}; + +/** +* struct imx046_capture_size - image capture size information +* @width: image width in pixels +* @height: image height in pixels +*/ +struct imx046_capture_size { +unsigned long width; +unsigned long height; +}; + +/** +* struct imx046_platform_data - platform data values and access functions
+ * @power_set: Power state access function, zero is off, non-zero is on.
+ * @default_regs: Default registers written after power-on or reset.
+ * @ifparm: Interface parameters access function
+ * @priv_data_set: device private data (pointer) access function
+ */drivers/media/video/imx046.h new file +85
-0+struct imx046_platform_data { +int (*power_set)(enum v4l2_power power); +const struct imx046_reg *default_regs; +int (*ifparm)(struct v4l2_ifparm *p); +int (*priv_data_set)(void *); +u32 (*set_xclk)(u32 xclk,u8 xclksel); +int (*cfg_interface_bridge)(u32 ); +int (*csi2_lane_count)(int count); +int (*csi2_cfg_vp_out_ctrl)(u8 vp_out_ctrl); +int (*csi2_ctrl_update)(bool ); +int (*csi2_cfg_virtual_id)(u8 ctx,u8 id); +int (*csi2_ctx_update)(u8 ctx,bool ); +int (*csi2_calc_phy_cfg0)(u32 ,u32 ,u32 ); +}; + +/** +* struct struct clk_settings - struct for storage of sensor +* clock settings +*/ +struct imx046_clk_settings { +u16 pre_pll_div; +u16 pll_mult; +u16 post_pll_div; +u16 vt_pix_clk_div; +u16 vt_sys_clk_div; +}; + +/** +* struct struct mipi_settings - struct for storage of sensor +* mipi settings +*/ +struct imx046_mipi_settings { +u16 data_lanes; +u16 ths_prepare; +u16 ths_zero; +u16 ths_settle_lower; +u16 ths_settle_upper; +}; + +/** +* struct struct frame_settings - struct for storage of sensor +* frame settings +*/ +struct imx046_frame_settings { +u16 frame_len_lines_min; +u16 frame_len_lines; +u16 line_len_pck; +u16 x_addr_start; +u16 x_addr_end; +u16 y_addr_start; +u16 y_addr_end; +u16 x_output_size; +u16 y_output_size; +u16 x_even_inc; +u16 x_odd_inc; +u16 y_even_inc; +u16 y_odd_inc; +u16 v_mode_add; +u16 h_mode_add; +u16 h_add_ave; +}; + +/** +* struct struct imx046_sensor_settings - struct for storage of +* sensor settings. +*/ +struct imx046_sensor_settings { +struct imx046_clk_settings clk; +struct imx046_mipi_settings mipi; +struct imx046_frame_settings frame; +}; + +/** +* struct struct imx046_clock_freq - struct for storage of sensor +* clock frequencies +*/ +struct imx046_clock_freq { +u32 vco_clk; +u32 mipi_clk; +u32 ddr_clk; +u32 vt_pix_clk; +}; + +/** +* Array of image sizes supported by IMX046. These must be ordered from
+ * smallest image size to largest.
+ */drivers/media/video/imx046.h new file +2
-0+const static struct imx046_capture_size imx046_sizes[] = { + {820 ,616 },/* 0.5Mp - 4X Horizontal & Vertical Elim. */
drivers/media/video/imx046.h new file +12
-1+ { 3280, 616 }, /* 2Mp - 4X Vertical Elim. */ + { 3280, 2464}, /* 8MP - Full Resolution */ +}; + +/* PLL settings for imx046 */ +enum imx046_pll_type { + PLL_0_5MP = 0, + PLL_2MP, + PLL_8MP, +}; + +#endif /* ifndef IMX046_H */ --
Quoted 4 lines
video4linux-list mailing list Unsubscribe mailto:video4linux-list- [email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
Hi Dominic!
First a small thing: please post to the new linux-media list in the future as this list is being phased out.
Quoted 34 lines · On Friday 30 January 2009 01:53:38 Dominic Curran wrote:
From: Dominic Curran <[email protected]>
Subject: [OMAPZOOM][PATCH 3/6] IMX046: Add support for Sony imx046 sensor.This patch adds the driver files for the Sony IMX046 8MP camera sensor. Driver sets up the sensor to send frame data via the MIPI CSI2 i/f. Sensor is setup to output the following base sizes:
- 3280 x 2464 (8MP)
- 3280 x 616 (2MP)
- 820 x 616
Sensor's output image format is Bayer10 (GrR/BGb).Driver has V4L2 controls for:
- Exposure
- Analog GainSigned-off-by Greg Hofer <[email protected]>Signed-off-by Dominic Curran <[email protected]>--- drivers/media/video/Kconfig | 8 drivers/media/video/Makefile | 1 drivers/media/video/imx046.c | 1635 +++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/imx046.h | 326 ++++++++ 4 files changed, 1970 insertions(+) create mode 100644 drivers/media/video/imx046.c create mode 100644 drivers/media/video/imx046.hIndex: omapzoom04/drivers/media/video/Kconfig
===================================================================drivers/media/video/Kconfig +0
-0@@ -334,6 +334,14 @@ config VIDEO_OV3640_CSI2 This enables the use of the CSI2 serial bus for the ov3640
drivers/media/video/Kconfig config VIDEO_OV3640_CSI2 · line 344
Quoted 10 lines
drivers/media/video/Kconfig +8
-0camera. +config VIDEO_IMX046 + tristate "Sony IMX046 sensor driver (8MP)" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Sony + IMX046 camera. It is currently working with the TI OMAP3 + camera controller. +
Does this need an OMAP3 dependency? Or is it fully independent from omap?
Quoted 34 lines
drivers/media/video/Kconfig +0
-0config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2CIndex: omapzoom04/drivers/media/video/Makefile
===================================================================drivers/media/video/Makefile +1
-0@@ -115,6 +115,7 @@ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_MT9P012) += mt9p012.o obj-$(CONFIG_VIDEO_DW9710) += dw9710.o obj-$(CONFIG_VIDEO_OV3640) += ov3640.o +obj-$(CONFIG_VIDEO_IMX046) += imx046.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.oIndex:
omapzoom04/drivers/media/video/imx046.c
===================================================================drivers/media/video/imx046.c new file +11
-0@@ -0,0 +1,1635 @@ +/* +* drivers/media/video/imx046.c +* +* Sony imx046 sensor driver +* +* +* Copyright (C) 2008 Hewlett Packard +* +* Leverage mt9p012.c +* +* This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied.
+ */
drivers/media/video/imx046.c line 18
Quoted 4 lines
drivers/media/video/imx046.c new file +4
-0+ +#include <linux/i2c.h> +#include <linux/delay.h> +#include <media/v4l2-int-device.h>
A general note on the usage of v4l2-int-device.h: this will be phased out soon in favor of v4l2-subdev (see Documentation/video4linux/v4l2-framework.txt, introduced in 2.6.29).
You might want to discuss this with Vaibhav Hiremath regarding the timescale of this conversion and whether it is better to wait until omap has been converted before merging this driver. I'm willing to accept the driver using the v4l2-int-device interface as long as I get the assurance that it will be converted later.
Regards,
Hans
Signature · 6 lines
Hans Verkuil - video4linux developer - sponsored by TANDBERG -- video4linux-list mailing list Unsubscribe mailto:[email protected]?subject=unsubscribe https://www.redhat.com/mailman/listinfo/video4linux-list
Quoted 9 lines
-----Original Message-----
From: Hans Verkuil [mailto:[email protected]]
Sent: Friday, January 30, 2009 2:54 AM
To: [email protected]
Cc: Curran, Dominic; linux-omap; [email protected]
Subject: Re: [OMAPZOOM][PATCH 3/6] IMX046: Add support for Sony imx046 sensor.
Quoted 4 lines
Hi Dominic!
First a small thing: please post to the new linux-media list in the future as this list is being phased out.
[DC]
OK, I have now subscribed to that list and will post to it when I resubmit. Thanks.
Quoted 37 lines · On Friday 30 January 2009 01:53:38 Dominic Curran wrote:
Quoted 36 lines
From: Dominic Curran <[email protected]>
Subject: [OMAPZOOM][PATCH 3/6] IMX046: Add support for Sony imx046 sensor.This patch adds the driver files for the Sony IMX046 8MP camera sensor. Driver sets up the sensor to send frame data via the MIPI CSI2 i/f. Sensor is setup to output the following base sizes:
- 3280 x 2464 (8MP)
- 3280 x 616 (2MP)
- 820 x 616
Sensor's output image format is Bayer10 (GrR/BGb).Driver has V4L2 controls for:
- Exposure
- Analog GainSigned-off-by Greg Hofer <[email protected]>Signed-off-by Dominic Curran <[email protected]>--- drivers/media/video/Kconfig | 8 drivers/media/video/Makefile | 1 drivers/media/video/imx046.c | 1635 +++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/imx046.h | 326 ++++++++ 4 files changed, 1970 insertions(+) create mode 100644 drivers/media/video/imx046.c create mode 100644 drivers/media/video/imx046.hIndex: omapzoom04/drivers/media/video/Kconfig
===================================================================drivers/media/video/Kconfig +0
-0@@ -334,6 +334,14 @@ config VIDEO_OV3640_CSI2 This enables the use of the CSI2 serial bus for the ov3640 camera.
Quoted 10 lines
drivers/media/video/Kconfig config VIDEO_OV3640_CSI2 · line 344
Quoted 8 lines
drivers/media/video/Kconfig +8
-0+config VIDEO_IMX046 + tristate "Sony IMX046 sensor driver (8MP)" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Sony + IMX046 camera. It is currently working with the TI OMAP3 + camera controller. +Does this need an OMAP3 dependency? Or is it fully independent from omap?
[DC]
OK, I have removed the text concerning OMAP3.
Yes, the driver 'should' be independent of OMAP.
Quoted 43 lines
Quoted 34 lines
drivers/media/video/Kconfig +0
-0config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2CIndex: omapzoom04/drivers/media/video/Makefile
===================================================================drivers/media/video/Makefile +1
-0@@ -115,6 +115,7 @@ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_MT9P012) += mt9p012.o obj-$(CONFIG_VIDEO_DW9710) += dw9710.o obj-$(CONFIG_VIDEO_OV3640) += ov3640.o +obj-$(CONFIG_VIDEO_IMX046) += imx046.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.oIndex:
omapzoom04/drivers/media/video/imx046.c
===================================================================drivers/media/video/imx046.c new file +11
-0@@ -0,0 +1,1635 @@ +/* +* drivers/media/video/imx046.c +* +* Sony imx046 sensor driver +* +* +* Copyright (C) 2008 Hewlett Packard +* +* Leverage mt9p012.c +* +* This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied.
+ */drivers/media/video/imx046.c line 18
Quoted 4 lines
drivers/media/video/imx046.c new file +4
-0+ +#include <linux/i2c.h> +#include <linux/delay.h> +#include <media/v4l2-int-device.h> A general note on the usage of
v4l2-int-device.h: this will be phased out soon in favor of v4l2-subdev (seeDocumentation/video4linux/v4l2-framework.txt, introduced in 2.6.29).
Quoted 5 lines
You might want to discuss this with Vaibhav Hiremath regarding the timescale of this conversion and whether it is better to wait until omap has been converted before merging this driver. I'm willing to accept the driver using the v4l2-int-device interface as long as I get the assurance that it will be converted later.
[DC]
Yes I certainly would like for the driver to be accepted into the V4L2 tree.
However, my first goal is to:
1) run by v4l2 list and get comments.
2) get it accepted into omapzoom tree.
I believe omapzoom will move to 2.6.29 in near future. At which stage I will patch this driver as appropriate for v4l2-framework and then resubmit to linux-media.
Thanks
dom
Quoted 7 lines
Regards,
Hans
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG
--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list