Re: [PATCH v2 2/2] media: Add a driver for the ov5645 camera sensor.
Hi Stan, Thanks for the review. On 05/20/2016 06:20 PM, Stanimir Varbanov wrote: > Hi Todor, > > Thanks for the patch, few comments below. > > On 05/18/2016 02:50 PM, Todor Tomov wrote: >> The ov5645 sensor from Omnivision supports up to 2592x1944 >> and CSI2 interface. >> >> The driver adds support for the following modes: >> - 1280x960 >> - 1920x1080 >> - 2592x1944 >> >> Output format is packed 8bit UYVY. >> >> Signed-off-by: Todor Tomov >> --- >> drivers/media/i2c/Kconfig | 11 + >> drivers/media/i2c/Makefile |1 + >> drivers/media/i2c/ov5645.c | 1425 >> >> 3 files changed, 1437 insertions(+) >> create mode 100644 drivers/media/i2c/ov5645.c >> >> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig >> index 521bbf1..aa17eba 100644 >> --- a/drivers/media/i2c/Kconfig >> +++ b/drivers/media/i2c/Kconfig >> @@ -490,6 +490,17 @@ config VIDEO_OV2659 >>To compile this driver as a module, choose M here: the >>module will be called ov2659. >> >> +config VIDEO_OV5645 >> +tristate "OmniVision OV5645 sensor support" >> +depends on I2C && VIDEO_V4L2 >> +depends on MEDIA_CAMERA_SUPPORT > > depends on OF ? Yes, the driver expects to be able to parse data from DT, so I'll add "depends on OF". > > > >> + >> +struct ov5645 { >> +struct i2c_client *i2c_client; >> +struct device *dev; >> +struct v4l2_subdev sd; >> +struct media_pad pad; >> +struct v4l2_of_endpoint ep; >> +struct v4l2_mbus_framefmt fmt; >> +struct v4l2_rect crop; >> +struct clk *xclk; >> +u32 xclk_freq; > > this become unused? Yes, I'll remove it. > >> + >> +struct regulator *io_regulator; >> +struct regulator *core_regulator; >> +struct regulator *analog_regulator; >> + >> +enum ov5645_mode current_mode; >> + >> +/* Cached control values */ >> +struct v4l2_ctrl_handler ctrls; >> +struct v4l2_ctrl *saturation; >> +struct v4l2_ctrl *hflip; >> +struct v4l2_ctrl *vflip; >> +struct v4l2_ctrl *autogain; >> +struct v4l2_ctrl *autoexposure; >> +struct v4l2_ctrl *awb; >> +struct v4l2_ctrl *pattern; >> + >> +struct mutex power_lock; /* lock to protect power state */ >> +int power; >> + >> +struct gpio_desc *pwdn_gpio; >> +struct gpio_desc *rst_gpio; >> +}; >> + >> +static inline struct ov5645 *to_ov5645(struct v4l2_subdev *sd) >> +{ >> +return container_of(sd, struct ov5645, sd); >> +} > > > >> +static int ov5645_s_power(struct v4l2_subdev *sd, int on) >> +{ >> +struct ov5645 *ov5645 = to_ov5645(sd); >> +int ret = 0; >> + >> +dev_dbg(ov5645->dev, "%s: on = %d\n", __func__, on); >> + >> +mutex_lock(&ov5645->power_lock); >> + >> +/* If the power count is modified from 0 to != 0 or from != 0 to 0, >> + * update the power state. >> + */ >> +if (ov5645->power == !on) { >> +if (on) { >> +ret = ov5645_set_power_on(ov5645); >> +if (ret < 0) { >> +dev_err(ov5645->dev, "could not set power %s\n", >> +on ? "on" : "off"); >> +goto exit; >> +} >> + >> +ret = ov5645_init(ov5645); >> +if (ret < 0) { >> +dev_err(ov5645->dev, >> +"could not set init registers\n"); >> +goto exit; >> +} >> + >> +ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, >> + OV5645_SYSTEM_CTRL0_STOP); > > please check the error code. Ok. > >> +} else { >> +ov5645_set_power_off(ov5645); >> +} >> + >> +/* Update the power count. */ >> +ov5645->power += on ? 1 : -1; >> +WARN_ON(ov5645->power < 0); >> +} >> + >> +exit: >> +mutex_unlock(&ov5645->power_lock); >> + >> +return ret; >> +} >> + > > > >> + >> +static int ov5645_registered(struct v4l2_subdev *subdev) >> +{ >> +struct i2c_client *client = v4l2_get_subdevdata(subdev); >> +struct ov5645 *ov5645 = to_ov5645(subdev); >> +u8 chip_id_high, chip_id_low; >> +int ret; >> + >> +ov5645_s_power(&ov5645->sd, true); > > check for error here and on the other places where call s_power. Ok. > >> + >> +ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH_REG, &chip_id_high); >> +if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH) { >> +dev_err(ov5645->dev, "could not read ID high\n"); >> +ret = -ENODEV; >> +goto reg_power_off; >> +} >> +ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW_REG, &chip_id_low); >> +if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW) { >> +dev_err(ov5645->dev, "could not read ID low\n"); >> +ret = -ENODEV; >> +goto reg_power_off; >>
Re: [PATCH v2 2/2] media: Add a driver for the ov5645 camera sensor.
Hi Hans, Thanks for the review. On 05/23/2016 01:36 PM, Hans Verkuil wrote: > Hi Todor, > > Thanks for the patch series! I got a few comments: > > On 05/18/2016 01:50 PM, Todor Tomov wrote: >> The ov5645 sensor from Omnivision supports up to 2592x1944 >> and CSI2 interface. >> >> The driver adds support for the following modes: >> - 1280x960 >> - 1920x1080 >> - 2592x1944 >> >> Output format is packed 8bit UYVY. >> >> Signed-off-by: Todor Tomov >> --- >> drivers/media/i2c/Kconfig | 11 + >> drivers/media/i2c/Makefile |1 + >> drivers/media/i2c/ov5645.c | 1425 >> >> 3 files changed, 1437 insertions(+) >> create mode 100644 drivers/media/i2c/ov5645.c > > > >> >> +static int ov5645_change_mode(struct ov5645 *ov5645, enum ov5645_mode mode) >> +{ >> +struct reg_value *settings; >> +u32 num_settings; >> +int ret = 0; >> + >> +settings = ov5645_mode_info_data[mode].data; >> +num_settings = ov5645_mode_info_data[mode].data_size; >> +ret = ov5645_set_register_array(ov5645, settings, num_settings); > > Just do 'return ov5645_set_register_array(ov5645, settings, num_settings);' > No need for the 'ret' variable. Ok. > >> + >> +return ret; >> +} >> + >> +static int ov5645_set_power_on(struct ov5645 *ov5645) >> +{ >> +int ret = 0; >> + >> +dev_dbg(ov5645->dev, "%s: Enter\n", __func__); >> + >> +ret = clk_prepare_enable(ov5645->xclk); >> +if (ret < 0) { >> +dev_err(ov5645->dev, "clk prepare enable failed\n"); >> +return ret; >> +} >> + >> +ret = ov5645_regulators_enable(ov5645); >> +if (ret < 0) { >> +clk_disable_unprepare(ov5645->xclk); >> +return ret; >> +} >> + >> +usleep_range(5000, 15000); >> +if (ov5645->pwdn_gpio) >> +gpiod_set_value_cansleep(ov5645->pwdn_gpio, 1); >> + >> +usleep_range(1000, 2000); >> +if (ov5645->rst_gpio) >> +gpiod_set_value_cansleep(ov5645->rst_gpio, 1); >> +msleep(20); >> + >> +return ret; >> +} >> + >> +static void ov5645_set_power_off(struct ov5645 *ov5645) >> +{ >> +dev_dbg(ov5645->dev, "%s: Enter\n", __func__); >> + >> +if (ov5645->rst_gpio) >> +gpiod_set_value_cansleep(ov5645->rst_gpio, 0); >> +if (ov5645->pwdn_gpio) >> +gpiod_set_value_cansleep(ov5645->pwdn_gpio, 0); >> +ov5645_regulators_disable(ov5645); >> +clk_disable_unprepare(ov5645->xclk); >> +} >> + >> +static int ov5645_s_power(struct v4l2_subdev *sd, int on) >> +{ >> +struct ov5645 *ov5645 = to_ov5645(sd); >> +int ret = 0; >> + >> +dev_dbg(ov5645->dev, "%s: on = %d\n", __func__, on); >> + >> +mutex_lock(&ov5645->power_lock); >> + >> +/* If the power count is modified from 0 to != 0 or from != 0 to 0, >> + * update the power state. >> + */ >> +if (ov5645->power == !on) { >> +if (on) { >> +ret = ov5645_set_power_on(ov5645); >> +if (ret < 0) { >> +dev_err(ov5645->dev, "could not set power %s\n", >> +on ? "on" : "off"); >> +goto exit; >> +} >> + >> +ret = ov5645_init(ov5645); >> +if (ret < 0) { >> +dev_err(ov5645->dev, >> +"could not set init registers\n"); >> +goto exit; >> +} >> + >> +ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, >> + OV5645_SYSTEM_CTRL0_STOP); >> +} else { >> +ov5645_set_power_off(ov5645); >> +} >> + >> +/* Update the power count. */ >> +ov5645->power += on ? 1 : -1; > > Huh? Is ov5645->power a bool or a counter? If it is a counter then this line > should be outside this 'if'. If it is a bool, then the comments (and the > power field itself!) should be updated. > > As far as I can tell, the 'power' field should be a bool and everything should > be updated accordingly. Yes, I'll change it to bool. > > >> +WARN_ON(ov5645->power < 0); >> +} >> + >> +exit: >> +mutex_unlock(&ov5645->power_lock); >> + >> +return ret; >> +} >> + >> + >> +static int ov5645_set_saturation(struct ov5645 *ov5645, s32 value) >> +{ >> +u32 reg_value = (value * 0x10) + 0x40; >> +int ret = 0; >> + >> +ret |= ov5645_write_reg(ov5645, OV5645_SDE_SAT_U, reg_value); >> +ret |= ov5645_write_reg(ov5645, OV5645_SDE_SAT_V, reg_value); >> + >> +dev_dbg(ov5645->dev, "%s: value = %d\n", __func__, value); >> + >> +return ret; >> +} >> + >> +static int ov5645_set_hflip(struct ov5645 *ov5645, s32 value) >> +{ >> +u8 val; >> + >> +ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21, &val); >> +if (value == 0) >> +val &= ~(OV5645_SENSOR_MIRROR); >> +else >> +
Re: [PATCH v2 2/2] media: Add a driver for the ov5645 camera sensor.
Hi Todor, Thanks for the patch series! I got a few comments: On 05/18/2016 01:50 PM, Todor Tomov wrote: > The ov5645 sensor from Omnivision supports up to 2592x1944 > and CSI2 interface. > > The driver adds support for the following modes: > - 1280x960 > - 1920x1080 > - 2592x1944 > > Output format is packed 8bit UYVY. > > Signed-off-by: Todor Tomov > --- > drivers/media/i2c/Kconfig | 11 + > drivers/media/i2c/Makefile |1 + > drivers/media/i2c/ov5645.c | 1425 > > 3 files changed, 1437 insertions(+) > create mode 100644 drivers/media/i2c/ov5645.c > > +static int ov5645_change_mode(struct ov5645 *ov5645, enum ov5645_mode mode) > +{ > + struct reg_value *settings; > + u32 num_settings; > + int ret = 0; > + > + settings = ov5645_mode_info_data[mode].data; > + num_settings = ov5645_mode_info_data[mode].data_size; > + ret = ov5645_set_register_array(ov5645, settings, num_settings); Just do 'return ov5645_set_register_array(ov5645, settings, num_settings);' No need for the 'ret' variable. > + > + return ret; > +} > + > +static int ov5645_set_power_on(struct ov5645 *ov5645) > +{ > + int ret = 0; > + > + dev_dbg(ov5645->dev, "%s: Enter\n", __func__); > + > + ret = clk_prepare_enable(ov5645->xclk); > + if (ret < 0) { > + dev_err(ov5645->dev, "clk prepare enable failed\n"); > + return ret; > + } > + > + ret = ov5645_regulators_enable(ov5645); > + if (ret < 0) { > + clk_disable_unprepare(ov5645->xclk); > + return ret; > + } > + > + usleep_range(5000, 15000); > + if (ov5645->pwdn_gpio) > + gpiod_set_value_cansleep(ov5645->pwdn_gpio, 1); > + > + usleep_range(1000, 2000); > + if (ov5645->rst_gpio) > + gpiod_set_value_cansleep(ov5645->rst_gpio, 1); > + msleep(20); > + > + return ret; > +} > + > +static void ov5645_set_power_off(struct ov5645 *ov5645) > +{ > + dev_dbg(ov5645->dev, "%s: Enter\n", __func__); > + > + if (ov5645->rst_gpio) > + gpiod_set_value_cansleep(ov5645->rst_gpio, 0); > + if (ov5645->pwdn_gpio) > + gpiod_set_value_cansleep(ov5645->pwdn_gpio, 0); > + ov5645_regulators_disable(ov5645); > + clk_disable_unprepare(ov5645->xclk); > +} > + > +static int ov5645_s_power(struct v4l2_subdev *sd, int on) > +{ > + struct ov5645 *ov5645 = to_ov5645(sd); > + int ret = 0; > + > + dev_dbg(ov5645->dev, "%s: on = %d\n", __func__, on); > + > + mutex_lock(&ov5645->power_lock); > + > + /* If the power count is modified from 0 to != 0 or from != 0 to 0, > + * update the power state. > + */ > + if (ov5645->power == !on) { > + if (on) { > + ret = ov5645_set_power_on(ov5645); > + if (ret < 0) { > + dev_err(ov5645->dev, "could not set power %s\n", > + on ? "on" : "off"); > + goto exit; > + } > + > + ret = ov5645_init(ov5645); > + if (ret < 0) { > + dev_err(ov5645->dev, > + "could not set init registers\n"); > + goto exit; > + } > + > + ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, > + OV5645_SYSTEM_CTRL0_STOP); > + } else { > + ov5645_set_power_off(ov5645); > + } > + > + /* Update the power count. */ > + ov5645->power += on ? 1 : -1; Huh? Is ov5645->power a bool or a counter? If it is a counter then this line should be outside this 'if'. If it is a bool, then the comments (and the power field itself!) should be updated. As far as I can tell, the 'power' field should be a bool and everything should be updated accordingly. > + WARN_ON(ov5645->power < 0); > + } > + > +exit: > + mutex_unlock(&ov5645->power_lock); > + > + return ret; > +} > + > + > +static int ov5645_set_saturation(struct ov5645 *ov5645, s32 value) > +{ > + u32 reg_value = (value * 0x10) + 0x40; > + int ret = 0; > + > + ret |= ov5645_write_reg(ov5645, OV5645_SDE_SAT_U, reg_value); > + ret |= ov5645_write_reg(ov5645, OV5645_SDE_SAT_V, reg_value); > + > + dev_dbg(ov5645->dev, "%s: value = %d\n", __func__, value); > + > + return ret; > +} > + > +static int ov5645_set_hflip(struct ov5645 *ov5645, s32 value) > +{ > + u8 val; > + > + ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21, &val); > + if (value == 0) > + val &= ~(OV5645_SENSOR_MIRROR); > + else > + val |= (OV5645_SENSOR_MIRROR); > + > + dev_dbg(ov5645->dev, "%s: value = %d\n", __func__, value); > + > + return ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG21, val); > +} > + > +static int ov5645
Re: [PATCH v2 2/2] media: Add a driver for the ov5645 camera sensor.
Hi Todor, Thanks for the patch, few comments below. On 05/18/2016 02:50 PM, Todor Tomov wrote: > The ov5645 sensor from Omnivision supports up to 2592x1944 > and CSI2 interface. > > The driver adds support for the following modes: > - 1280x960 > - 1920x1080 > - 2592x1944 > > Output format is packed 8bit UYVY. > > Signed-off-by: Todor Tomov > --- > drivers/media/i2c/Kconfig | 11 + > drivers/media/i2c/Makefile |1 + > drivers/media/i2c/ov5645.c | 1425 > > 3 files changed, 1437 insertions(+) > create mode 100644 drivers/media/i2c/ov5645.c > > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig > index 521bbf1..aa17eba 100644 > --- a/drivers/media/i2c/Kconfig > +++ b/drivers/media/i2c/Kconfig > @@ -490,6 +490,17 @@ config VIDEO_OV2659 > To compile this driver as a module, choose M here: the > module will be called ov2659. > > +config VIDEO_OV5645 > + tristate "OmniVision OV5645 sensor support" > + depends on I2C && VIDEO_V4L2 > + depends on MEDIA_CAMERA_SUPPORT depends on OF ? > + > +struct ov5645 { > + struct i2c_client *i2c_client; > + struct device *dev; > + struct v4l2_subdev sd; > + struct media_pad pad; > + struct v4l2_of_endpoint ep; > + struct v4l2_mbus_framefmt fmt; > + struct v4l2_rect crop; > + struct clk *xclk; > + u32 xclk_freq; this become unused? > + > + struct regulator *io_regulator; > + struct regulator *core_regulator; > + struct regulator *analog_regulator; > + > + enum ov5645_mode current_mode; > + > + /* Cached control values */ > + struct v4l2_ctrl_handler ctrls; > + struct v4l2_ctrl *saturation; > + struct v4l2_ctrl *hflip; > + struct v4l2_ctrl *vflip; > + struct v4l2_ctrl *autogain; > + struct v4l2_ctrl *autoexposure; > + struct v4l2_ctrl *awb; > + struct v4l2_ctrl *pattern; > + > + struct mutex power_lock; /* lock to protect power state */ > + int power; > + > + struct gpio_desc *pwdn_gpio; > + struct gpio_desc *rst_gpio; > +}; > + > +static inline struct ov5645 *to_ov5645(struct v4l2_subdev *sd) > +{ > + return container_of(sd, struct ov5645, sd); > +} > +static int ov5645_s_power(struct v4l2_subdev *sd, int on) > +{ > + struct ov5645 *ov5645 = to_ov5645(sd); > + int ret = 0; > + > + dev_dbg(ov5645->dev, "%s: on = %d\n", __func__, on); > + > + mutex_lock(&ov5645->power_lock); > + > + /* If the power count is modified from 0 to != 0 or from != 0 to 0, > + * update the power state. > + */ > + if (ov5645->power == !on) { > + if (on) { > + ret = ov5645_set_power_on(ov5645); > + if (ret < 0) { > + dev_err(ov5645->dev, "could not set power %s\n", > + on ? "on" : "off"); > + goto exit; > + } > + > + ret = ov5645_init(ov5645); > + if (ret < 0) { > + dev_err(ov5645->dev, > + "could not set init registers\n"); > + goto exit; > + } > + > + ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, > + OV5645_SYSTEM_CTRL0_STOP); please check the error code. > + } else { > + ov5645_set_power_off(ov5645); > + } > + > + /* Update the power count. */ > + ov5645->power += on ? 1 : -1; > + WARN_ON(ov5645->power < 0); > + } > + > +exit: > + mutex_unlock(&ov5645->power_lock); > + > + return ret; > +} > + > + > +static int ov5645_registered(struct v4l2_subdev *subdev) > +{ > + struct i2c_client *client = v4l2_get_subdevdata(subdev); > + struct ov5645 *ov5645 = to_ov5645(subdev); > + u8 chip_id_high, chip_id_low; > + int ret; > + > + ov5645_s_power(&ov5645->sd, true); check for error here and on the other places where call s_power. > + > + ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH_REG, &chip_id_high); > + if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH) { > + dev_err(ov5645->dev, "could not read ID high\n"); > + ret = -ENODEV; > + goto reg_power_off; > + } > + ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW_REG, &chip_id_low); > + if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW) { > + dev_err(ov5645->dev, "could not read ID low\n"); > + ret = -ENODEV; > + goto reg_power_off; > + } > + > + dev_info(&client->dev, "OV5645 detected at address 0x%02x\n", > + client->addr); > + > + ov5645_s_power(&ov5645->sd, false); > + > + return 0; > + > +reg_power_off: > + ov5645_s_power(&ov5645->sd, false); > + return ret; > +} > + > +static int ov5645_s_stre
[PATCH v2 2/2] media: Add a driver for the ov5645 camera sensor.
The ov5645 sensor from Omnivision supports up to 2592x1944 and CSI2 interface. The driver adds support for the following modes: - 1280x960 - 1920x1080 - 2592x1944 Output format is packed 8bit UYVY. Signed-off-by: Todor Tomov --- drivers/media/i2c/Kconfig | 11 + drivers/media/i2c/Makefile |1 + drivers/media/i2c/ov5645.c | 1425 3 files changed, 1437 insertions(+) create mode 100644 drivers/media/i2c/ov5645.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 521bbf1..aa17eba 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -490,6 +490,17 @@ config VIDEO_OV2659 To compile this driver as a module, choose M here: the module will be called ov2659. +config VIDEO_OV5645 + tristate "OmniVision OV5645 sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV5645 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5645. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 07db257..29003df 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o +obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c new file mode 100644 index 000..7fafbcf --- /dev/null +++ b/drivers/media/i2c/ov5645.c @@ -0,0 +1,1425 @@ +/* + * Driver for the OV5645 camera sensor. + * + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 By Tech Design S.L. All Rights Reserved. + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Based on: + * - the OV5645 driver from QC msm-3.10 kernel on codeaurora.org: + * https://us.codeaurora.org/cgit/quic/la/kernel/msm-3.10/tree/drivers/ + * media/platform/msm/camera_v2/sensor/ov5645.c?h=LA.BR.1.2.4_rb1.41 + * - the OV5640 driver posted on linux-media: + * https://www.mail-archive.com/linux-media%40vger.kernel.org/msg92671.html + */ + +/* + * 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. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV5645_VOLTAGE_ANALOG 280 +#define OV5645_VOLTAGE_DIGITAL_CORE 150 +#define OV5645_VOLTAGE_DIGITAL_IO 180 + +#define OV5645_XCLK_MIN 600 +#define OV5645_XCLK_MAX 2400 + +#define OV5645_SYSTEM_CTRL00x3008 +#defineOV5645_SYSTEM_CTRL0_START 0x02 +#defineOV5645_SYSTEM_CTRL0_STOP0x42 +#define OV5645_CHIP_ID_HIGH_REG0x300A +#defineOV5645_CHIP_ID_HIGH 0x56 +#define OV5645_CHIP_ID_LOW_REG 0x300B +#defineOV5645_CHIP_ID_LOW 0x45 +#define OV5645_AWB_MANUAL_CONTROL 0x3406 +#defineOV5645_AWB_MANUAL_ENABLEBIT(0) +#define OV5645_AEC_PK_MANUAL 0x3503 +#defineOV5645_AEC_MANUAL_ENABLEBIT(0) +#defineOV5645_AGC_MANUAL_ENABLEBIT(1) +#define OV5645_TIMING_TC_REG20 0x3820 +#defineOV5645_SENSOR_VFLIP BIT(1) +#defineOV5645_ISP_VFLIPBIT(2) +#define OV5645_TIMING_TC_REG21 0x3821 +#defineOV5645_SENSOR_MIRRORBIT(1) +#define OV5645_PRE_ISP_TEST_SETTING_1 0x503d +#defineOV5645_TEST_PATTERN_MASK0x3 +#defineOV5645_SET_TEST_PATTERN(x) ((x) & OV5645_TEST_PATTERN_MASK) +#defineOV5645_TEST_PATTERN_ENABLE BIT(7) +#define OV5645_SDE_SAT_U 0x5583 +#define OV5645_SDE_SAT_V 0x5584 + +enum ov5645_mode { + OV5645_MODE_MIN = 0, + OV5645_MODE_SXGA = 0, + OV5645_MODE_1080P = 1, + OV5645_MODE_FULL = 2, + OV5