Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

emma_ov2640.c

/*
 * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>

#include "mxc_v4l2_capture.h"

enum ov2640_mode {
      ov2640_mode_1600_1120,
      ov2640_mode_800_600
};

struct reg_value {
      u8 reg;
      u8 value;
      int delay_ms;
};

static struct reg_value ov2640_setting_1600_1120[] = {
      {0xff, 0x1, 0}, {0x12, 0x80, 1}, {0xff, 0, 0}, {0x2c, 0xff, 0},
      {0x2e, 0xdf, 0}, {0xff, 0x1, 0}, {0x3c, 0x32, 0}, {0x11, 0x01, 0},
      {0x09, 0x00, 0}, {0x04, 0x28, 0}, {0x13, 0xe5, 0}, {0x14, 0x48, 0},
      {0x2c, 0x0c, 0}, {0x33, 0x78, 0}, {0x3a, 0x33, 0}, {0x3b, 0xfb, 0},
      {0x3e, 0x00, 0}, {0x43, 0x11, 0}, {0x16, 0x10, 0}, {0x39, 0x82, 0},
      {0x35, 0x88, 0}, {0x22, 0x0a, 0}, {0x37, 0x40, 0}, {0x23, 0x00, 0},
      {0x34, 0xa0, 0}, {0x36, 0x1a, 0}, {0x06, 0x02, 0}, {0x07, 0xc0, 0},
      {0x0d, 0xb7, 0}, {0x0e, 0x01, 0}, {0x4c, 0x00, 0}, {0x4a, 0x81, 0},
      {0x21, 0x99, 0}, {0x24, 0x40, 0}, {0x25, 0x38, 0}, {0x26, 0x82, 0},
      {0x5c, 0x00, 0}, {0x63, 0x00, 0}, {0x46, 0x3f, 0}, {0x0c, 0x3c, 0},
      {0x5d, 0x55, 0}, {0x5e, 0x7d, 0}, {0x5f, 0x7d, 0}, {0x60, 0x55, 0},
      {0x61, 0x70, 0}, {0x62, 0x80, 0}, {0x7c, 0x05, 0}, {0x20, 0x80, 0},
      {0x28, 0x30, 0}, {0x6c, 0x00, 0}, {0x6d, 0x80, 0}, {0x6e, 00, 0},
      {0x70, 0x02, 0}, {0x71, 0x94, 0}, {0x73, 0xc1, 0}, {0x3d, 0x34, 0},
      {0x5a, 0x57, 0}, {0x4f, 0xbb, 0}, {0x50, 0x9c, 0}, {0xff, 0x00, 0},
      {0xe5, 0x7f, 0}, {0xf9, 0xc0, 0}, {0x41, 0x24, 0}, {0x44, 0x06, 0},
      {0xe0, 0x14, 0}, {0x76, 0xff, 0}, {0x33, 0xa0, 0}, {0x42, 0x20, 0},
      {0x43, 0x18, 0}, {0x4c, 0x00, 0}, {0x87, 0xd0, 0}, {0xd7, 0x03, 0},
      {0xd9, 0x10, 0}, {0xd3, 0x82, 0}, {0xc8, 0x08, 0}, {0xc9, 0x80, 0},
      {0x7c, 0x00, 0}, {0x7d, 0x00, 0}, {0x7c, 0x03, 0}, {0x7d, 0x48, 0},
      {0x7d, 0x48, 0}, {0x7c, 0x08, 0}, {0x7d, 0x20, 0}, {0x7d, 0x10, 0},
      {0x7d, 0x0e, 0}, {0x90, 0x00, 0}, {0x91, 0x0e, 0}, {0x91, 0x1a, 0},
      {0x91, 0x31, 0}, {0x91, 0x5a, 0}, {0x91, 0x69, 0}, {0x91, 0x75, 0},
      {0x91, 0x7e, 0}, {0x91, 0x88, 0}, {0x91, 0x8f, 0}, {0x91, 0x96, 0},
      {0x91, 0xa3, 0}, {0x91, 0xaf, 0}, {0x91, 0xc4, 0}, {0x91, 0xd7, 0},
      {0x91, 0xe8, 0}, {0x91, 0x20, 0}, {0x92, 0x00, 0}, {0x93, 0x06, 0},
      {0x93, 0xe3, 0}, {0x93, 0x03, 0}, {0x93, 0x03, 0}, {0x93, 0x00, 0},
      {0x93, 0x02, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0},
      {0x93, 0x00, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0},
      {0x96, 0x00, 0}, {0x97, 0x08, 0}, {0x97, 0x19, 0}, {0x97, 0x02, 0},
      {0x97, 0x0c, 0}, {0x97, 0x24, 0}, {0x97, 0x30, 0}, {0x97, 0x28, 0},
      {0x97, 0x26, 0}, {0x97, 0x02, 0}, {0x97, 0x98, 0}, {0x97, 0x80, 0},
      {0x97, 0x00, 0}, {0x97, 0x00, 0}, {0xa4, 0x00, 0}, {0xa8, 0x00, 0},
      {0xc5, 0x11, 0}, {0xc6, 0x51, 0}, {0xbf, 0x80, 0}, {0xc7, 0x10, 0},
      {0xb6, 0x66, 0}, {0xb8, 0xa5, 0}, {0xb7, 0x64, 0}, {0xb9, 0x7c, 0},
      {0xb3, 0xaf, 0}, {0xb4, 0x97, 0}, {0xb5, 0xff, 0}, {0xb0, 0xc5, 0},
      {0xb1, 0x94, 0}, {0xb2, 0x0f, 0}, {0xc4, 0x5c, 0}, {0xa6, 0x00, 0},
      {0xa7, 0x20, 0}, {0xa7, 0xd8, 0}, {0xa7, 0x1b, 0}, {0xa7, 0x31, 0},
      {0xa7, 0x00, 0}, {0xa7, 0x18, 0}, {0xa7, 0x20, 0}, {0xa7, 0xd8, 0},
      {0xa7, 0x19, 0}, {0xa7, 0x31, 0}, {0xa7, 0x00, 0}, {0xa7, 0x18, 0},
      {0xa7, 0x20, 0}, {0xa7, 0xd8, 0}, {0xa7, 0x19, 0}, {0xa7, 0x31, 0},
      {0xa7, 0x00, 0}, {0xa7, 0x18, 0}, {0xc0, 0xc8, 0}, {0xc1, 0x96, 0},
      {0x86, 0x3d, 0}, {0x50, 0x00, 0}, {0x51, 0x90, 0}, {0x52, 0x18, 0},
      {0x53, 0x00, 0}, {0x54, 0x00, 0}, {0x55, 0x88, 0}, {0x57, 0x00, 0},
      {0x5a, 0x90, 0}, {0x5b, 0x18, 0}, {0x5c, 0x05, 0}, {0xc3, 0xef, 0},
      {0x7f, 0x00, 0}, {0xda, 0x01, 0}, {0xe5, 0x1f, 0}, {0xe1, 0x67, 0},
      {0xe0, 0x00, 0}, {0xdd, 0x7f, 0}, {0x05, 0x00, 0}
};

static struct reg_value ov2640_setting_800_600[] = {
      {0xff, 0, 0}, {0xff, 1, 0}, {0x12, 0x80, 1}, {0xff, 00, 0},
      {0x2c, 0xff, 0}, {0x2e, 0xdf, 0}, {0xff, 0x1, 0}, {0x3c, 0x32, 0},
      {0x11, 0x01, 0}, {0x09, 0x00, 0}, {0x04, 0x28, 0}, {0x13, 0xe5, 0},
      {0x14, 0x48, 0}, {0x2c, 0x0c, 0}, {0x33, 0x78, 0}, {0x3a, 0x33, 0},
      {0x3b, 0xfb, 0}, {0x3e, 0x00, 0}, {0x43, 0x11, 0}, {0x16, 0x10, 0},
      {0x39, 0x92, 0}, {0x35, 0xda, 0}, {0x22, 0x1a, 0}, {0x37, 0xc3, 0},
      {0x23, 0x00, 0}, {0x34, 0xc0, 0}, {0x36, 0x1a, 0}, {0x06, 0x88, 0},
      {0x07, 0xc0, 0}, {0x0d, 0x87, 0}, {0x0e, 0x41, 0}, {0x4c, 0x00, 0},
      {0x4a, 0x81, 0}, {0x21, 0x99, 0}, {0x24, 0x40, 0}, {0x25, 0x38, 0},
      {0x26, 0x82, 0}, {0x5c, 0x00, 0}, {0x63, 0x00, 0}, {0x46, 0x22, 0},
      {0x0c, 0x3c, 0}, {0x5d, 0x55, 0}, {0x5e, 0x7d, 0}, {0x5f, 0x7d, 0},
      {0x60, 0x55, 0}, {0x61, 0x70, 0}, {0x62, 0x80, 0}, {0x7c, 0x05, 0},
      {0x20, 0x80, 0}, {0x28, 0x30, 0}, {0x6c, 0x00, 0}, {0x6d, 0x80, 0},
      {0x6e, 00, 0}, {0x70, 0x02, 0}, {0x71, 0x94, 0}, {0x73, 0xc1, 0},
      {0x12, 0x40, 0}, {0x17, 0x11, 0}, {0x18, 0x43, 0}, {0x19, 0x00, 0},
      {0x1a, 0x4b, 0}, {0x32, 0x09, 0}, {0x37, 0xc0, 0}, {0x4f, 0xca, 0},
      {0x50, 0xa8, 0}, {0x6d, 0x00, 0}, {0x3d, 0x38, 0}, {0xff, 0x00, 0},
      {0xe5, 0x7f, 0}, {0xf9, 0xc0, 0}, {0x41, 0x24, 0}, {0x44, 0x06, 0},
      {0xe0, 0x14, 0}, {0x76, 0xff, 0}, {0x33, 0xa0, 0}, {0x42, 0x20, 0},
      {0x43, 0x18, 0}, {0x4c, 0x00, 0}, {0x87, 0xd0, 0}, {0x88, 0x3f, 0},
      {0xd7, 0x03, 0}, {0xd9, 0x10, 0}, {0xd3, 0x82, 0}, {0xc8, 0x08, 0},
      {0xc9, 0x80, 0}, {0x7c, 0x00, 0}, {0x7d, 0x00, 0}, {0x7c, 0x03, 0},
      {0x7d, 0x48, 0}, {0x7d, 0x48, 0}, {0x7c, 0x08, 0}, {0x7d, 0x20, 0},
      {0x7d, 0x10, 0}, {0x7d, 0x0e, 0}, {0x90, 0x00, 0}, {0x91, 0x0e, 0},
      {0x91, 0x1a, 0}, {0x91, 0x31, 0}, {0x91, 0x5a, 0}, {0x91, 0x69, 0},
      {0x91, 0x75, 0}, {0x91, 0x7e, 0}, {0x91, 0x88, 0}, {0x91, 0x8f, 0},
      {0x91, 0x96, 0}, {0x91, 0xa3, 0}, {0x91, 0xaf, 0}, {0x91, 0xc4, 0},
      {0x91, 0xd7, 0}, {0x91, 0xe8, 0}, {0x91, 0x20, 0}, {0x92, 0x00, 0},
      {0x93, 0x06, 0}, {0x93, 0xe3, 0}, {0x93, 0x03, 0}, {0x93, 0x03, 0},
      {0x93, 0x00, 0}, {0x93, 0x02, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0},
      {0x93, 0x00, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0}, {0x93, 0x00, 0},
      {0x93, 0x00, 0}, {0x96, 0x00, 0}, {0x97, 0x08, 0}, {0x97, 0x19, 0},
      {0x97, 0x02, 0}, {0x97, 0x0c, 0}, {0x97, 0x24, 0}, {0x97, 0x30, 0},
      {0x97, 0x28, 0}, {0x97, 0x26, 0}, {0x97, 0x02, 0}, {0x97, 0x98, 0},
      {0x97, 0x80, 0}, {0x97, 0x00, 0}, {0x97, 0x00, 0}, {0xa4, 0x00, 0},
      {0xa8, 0x00, 0}, {0xc5, 0x11, 0}, {0xc6, 0x51, 0}, {0xbf, 0x80, 0},
      {0xc7, 0x10, 0}, {0xb6, 0x66, 0}, {0xb8, 0xa5, 0}, {0xb7, 0x64, 0},
      {0xb9, 0x7c, 0}, {0xb3, 0xaf, 0}, {0xb4, 0x97, 0}, {0xb5, 0xff, 0},
      {0xb0, 0xc5, 0}, {0xb1, 0x94, 0}, {0xb2, 0x0f, 0}, {0xc4, 0x5c, 0},
      {0xa6, 0x00, 0}, {0xa7, 0x20, 0}, {0xa7, 0xd8, 0}, {0xa7, 0x1b, 0},
      {0xa7, 0x31, 0}, {0xa7, 0x00, 0}, {0xa7, 0x18, 0}, {0xa7, 0x20, 0},
      {0xa7, 0xd8, 0}, {0xa7, 0x19, 0}, {0xa7, 0x31, 0}, {0xa7, 0x00, 0},
      {0xa7, 0x18, 0}, {0xa7, 0x20, 0}, {0xa7, 0xd8, 0}, {0xa7, 0x19, 0},
      {0xa7, 0x31, 0}, {0xa7, 0x00, 0}, {0xa7, 0x18, 0}, {0xc0, 0x64, 0},
      {0xc1, 0x4b, 0}, {0x86, 0x1d, 0}, {0x50, 0x00, 0}, {0x51, 0xc8, 0},
      {0x52, 0x96, 0}, {0x53, 0x00, 0}, {0x54, 0x00, 0}, {0x55, 0x00, 0},
      {0x57, 0x00, 0}, {0x5a, 0xc8, 0}, {0x5b, 0x96, 0}, {0x5c, 0x00, 0},
      {0xc3, 0xef, 0}, {0x7f, 0x00, 0}, {0xda, 0x01, 0}, {0xe5, 0x1f, 0},
      {0xe1, 0x67, 0}, {0xe0, 0x00, 0}, {0xdd, 0x7f, 0}, {0x05, 0x00, 0}
};

static struct regulator *io_regulator;
static struct regulator *core_regulator;
static struct regulator *analog_regulator;
static struct regulator *gpo_regulator;
u32 mclk = 24000000;

struct i2c_client *ov2640_i2c_client;

static sensor_interface *interface_param;
static int reset_frame_rate = 30;
static int ov2640_probe(struct i2c_client *adapter,
                  const struct i2c_device_id *id);
static int ov2640_remove(struct i2c_client *client);

static const struct i2c_device_id ov2640_id[] = {
      {"ov2640", 0},
      {},
};

MODULE_DEVICE_TABLE(i2c, ov2640_id);

static struct i2c_driver ov2640_i2c_driver = {
      .driver = {
               .owner = THIS_MODULE,
               .name = "ov2640",
               },
      .probe = ov2640_probe,
      .remove = ov2640_remove,
      .id_table = ov2640_id,
};

/*!
 * ov2640 I2C attach function
 *
 * @param adapter            struct i2c_adapter *
 * @return  Error code indicating success or failure
 */
static int ov2640_probe(struct i2c_client *client,
                  const struct i2c_device_id *id)
{
      struct mxc_camera_platform_data *plat_data = client->dev.platform_data;

      ov2640_i2c_client = client;
      mclk = plat_data->mclk;

      io_regulator = regulator_get(&client->dev, plat_data->io_regulator);
      core_regulator = regulator_get(&client->dev, plat_data->core_regulator);
      analog_regulator =
          regulator_get(&client->dev, plat_data->analog_regulator);
      gpo_regulator = regulator_get(&client->dev, plat_data->gpo_regulator);

      interface_param = (sensor_interface *)
          kmalloc(sizeof(sensor_interface), GFP_KERNEL);
      if (!interface_param) {
            dev_dbg(&ov2640_i2c_client->dev,
                  "ov2640_probe: kmalloc failed \n");
            return -1;
      }

      return 0;
}

/*!
 * ov2640 I2C detach function
 *
 * @param client            struct i2c_client *
 * @return  Error code indicating success or failure
 */
static int ov2640_remove(struct i2c_client *client)
{
      kfree(interface_param);
      interface_param = NULL;

      if (!IS_ERR_VALUE((unsigned long)io_regulator)) {
            regulator_disable(io_regulator);
            regulator_put(io_regulator);
      }

      if (!IS_ERR_VALUE((unsigned long)core_regulator)) {
            regulator_disable(core_regulator);
            regulator_put(core_regulator);
      }

      if (!IS_ERR_VALUE((unsigned long)gpo_regulator)) {
            regulator_disable(gpo_regulator);
            regulator_put(gpo_regulator);
      }

      if (!IS_ERR_VALUE((unsigned long)analog_regulator)) {
            regulator_disable(analog_regulator);
            regulator_put(analog_regulator);
      }

      return 0;
}

static int ov2640_write_reg(u8 reg, u8 val)
{
      if (i2c_smbus_write_byte_data(ov2640_i2c_client, reg, val) < 0) {
            dev_dbg(&ov2640_i2c_client->dev,
                  "%s:write reg errorr:reg=%x,val=%x\n", __func__, reg,
                  val);
            return -1;
      }
      return 0;
}

static int ov2640_init_mode(enum ov2640_mode mode)
{
      struct reg_value *setting;
      int i, num;

      switch (mode) {
      case ov2640_mode_1600_1120:
            setting = ov2640_setting_1600_1120;
            num = ARRAY_SIZE(ov2640_setting_1600_1120);
            break;
      case ov2640_mode_800_600:
            setting = ov2640_setting_800_600;
            num = ARRAY_SIZE(ov2640_setting_800_600);
            break;
      default:
            return 0;
      }

      for (i = 0; i < num; i++) {
            ov2640_write_reg(setting[i].reg, setting[i].value);
            if (setting[i].delay_ms > 0)
                  msleep(setting[i].delay_ms);
      }

      return 0;
}

/*!
 * ov2640 sensor interface Initialization
 * @param param            sensor_interface *
 * @param width            u32
 * @param height           u32
 * @return  None
 */
static void ov2640_interface(sensor_interface *param, u32 width, u32 height)
{
      param->Vsync_pol = 0x0;
      param->clk_mode = 0x0;  /*gated */
      param->pixclk_pol = 0x0;
      param->data_width = 0x1;
      param->data_pol = 0x0;
      param->ext_vsync = 0x0;
      param->Vsync_pol = 0x0;
      param->Hsync_pol = 0x0;
      param->width = width - 1;
      param->height = height - 1;
      param->active_width = width;
      param->active_height = height;
      param->pixel_fmt = IPU_PIX_FMT_UYVY;
      param->mclk = mclk;
}

static void ov2640_set_color(int bright, int saturation, int red, int green,
                       int blue)
{

}

static void ov2640_get_color(int *bright, int *saturation, int *red, int *green,
                       int *blue)
{

}
static void ov2640_set_ae_mode(int ae_mode)
{

}
static void ov2640_get_ae_mode(int *ae_mode)
{

}

extern void gpio_sensor_active(void);

static sensor_interface *ov2640_config(int *frame_rate, int high_quality)
{

      u32 out_width, out_height;

      /*set io votage */
      if (!IS_ERR_VALUE((unsigned long)io_regulator)) {
            regulator_set_voltage(io_regulator, 2800000, 2800000);
            if (regulator_enable(io_regulator) != 0) {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:io set voltage error\n", __func__);
                  return NULL;
            } else {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:io set voltage ok\n", __func__);
            }
      }

      /*core votage */
      if (!IS_ERR_VALUE((unsigned long)core_regulator)) {
            regulator_set_voltage(core_regulator, 1300000, 1300000);
            if (regulator_enable(core_regulator) != 0) {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:core set voltage error\n", __func__);
                  return NULL;
            } else {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:core set voltage ok\n", __func__);
            }
      }

      /*GPO 3 */
      if (!IS_ERR_VALUE((unsigned long)gpo_regulator)) {
            if (regulator_enable(gpo_regulator) != 0) {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:gpo3 enable error\n", __func__);
                  return NULL;
            } else {
                  dev_dbg(&ov2640_i2c_client->dev, "%s:gpo3 enable ok\n",
                        __func__);
            }
      }

      if (!IS_ERR_VALUE((unsigned long)analog_regulator)) {
            regulator_set_voltage(analog_regulator, 2000000, 2000000);
            if (regulator_enable(analog_regulator) != 0) {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:analog set voltage error\n", __func__);
                  return NULL;
            } else {
                  dev_dbg(&ov2640_i2c_client->dev,
                        "%s:analog set voltage ok\n", __func__);
            }
      }

      gpio_sensor_active();

      if (high_quality) {
            out_width = 1600;
            out_height = 1120;
      } else {
            out_width = 800;
            out_height = 600;
      }
      ov2640_interface(interface_param, out_width, out_height);
      set_mclk_rate(&interface_param->mclk);

      if (high_quality)
            ov2640_init_mode(ov2640_mode_1600_1120);
      else
            ov2640_init_mode(ov2640_mode_800_600);

      msleep(300);

      return interface_param;
}

static sensor_interface *ov2640_reset(void)
{
      return ov2640_config(&reset_frame_rate, 0);
}

struct camera_sensor camera_sensor_if = {
      .set_color = ov2640_set_color,
      .get_color = ov2640_get_color,
      .set_ae_mode = ov2640_set_ae_mode,
      .get_ae_mode = ov2640_get_ae_mode,
      .config = ov2640_config,
      .reset = ov2640_reset,
};

EXPORT_SYMBOL(camera_sensor_if);

/*!
 * ov2640 init function
 *
 * @return  Error code indicating success or failure
 */
static __init int ov2640_init(void)
{
      u8 err;

      err = i2c_add_driver(&ov2640_i2c_driver);

      return err;
}

extern void gpio_sensor_inactive(void);
/*!
 * OV2640 cleanup function
 *
 * @return  Error code indicating success or failure
 */
static void __exit ov2640_clean(void)
{
      i2c_del_driver(&ov2640_i2c_driver);

      gpio_sensor_inactive();
}

module_init(ov2640_init);
module_exit(ov2640_clean);

MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("OV2640 Camera Driver");
MODULE_LICENSE("GPL");

Generated by  Doxygen 1.6.0   Back to index