From b09164c8b6fea263887a62fcdc31bc3f1106b668 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 26 Jan 2007 12:08:48 +0100 Subject: [PATCH] Driver for the Atmel AT76C451BC-MY15AT digital camera Add driver for the Atmel AT76C451BC-MY15AT Eye-On-Si(tm) CMOS digital camera for use with the atmel-isi driver. Signed-off-by: Haavard Skinnemoen --- drivers/media/video/Kconfig | 8 + drivers/media/video/Makefile | 1 + drivers/media/video/at76c451bc.c | 655 ++++++++++++++++++++++++++++++++++++++ drivers/media/video/at76c451bc.h | 81 +++++ include/linux/i2c-id.h | 1 + 5 files changed, 746 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/at76c451bc.c create mode 100644 drivers/media/video/at76c451bc.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 34acb25..10383ae 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -20,6 +20,14 @@ config VIDEO_AVR32_ISI This module will enable the AVR32 Image Sensor Interface and it can be accessed like a normal 4vl2 device. +config VIDEO_AT76C451BC + tristate "Atmel AT76C451BC Eye-On-Si(tm)" + default n + depends on VIDEO_AVR32_ISI && I2C + help + This will add support for the Atmel AT76C451BC Eye-On-Si(tm) + digital camera. + config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality" default n diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 20746bc..c623883 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_AVR32_ISI) += atmel-isi.o +obj-$(CONFIG_VIDEO_AT76C451BC) += at76c451bc.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEO_BUF) += video-buf.o diff --git a/drivers/media/video/at76c451bc.c b/drivers/media/video/at76c451bc.c new file mode 100644 index 0000000..f3792b2 --- /dev/null +++ b/drivers/media/video/at76c451bc.c @@ -0,0 +1,655 @@ +/* + * Atmel AT76C451BC Eye-On-Si(tm) Digital Camera driver + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atmel-isi.h" +#include "at76c451bc.h" + +#define AT76C451BC_MY15AT 0x3300 +#define I2C_AT76C451BC 0x12 + +static unsigned short normal_i2c[] = { + I2C_AT76C451BC, + I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; + +static char mclk_name[32] = "gclk0"; +static char mclk_parent_name[32] = "osc0"; +module_param_string(mclk, mclk_name, sizeof(mclk_name), 0644); +MODULE_PARM_DESC(mclk, "Name of the clock used as camera clock input"); +module_param_string(mclk_parent, mclk_parent_name, + sizeof(mclk_parent_name), 0644); +MODULE_PARM_DESC(mclk, "Name of mclk parent clock"); + +#ifdef CONFIG_DEBUG_FS +struct reg_dbg { + struct at76c451 *is; + struct dentry *dentry; + unsigned int offset; +}; +#endif + +struct at76c451 { + struct mutex mutex; + u8 miscel_ctrl; + u16 pll_avr_ctrl; + struct clk *mclk; + struct i2c_client client; + struct atmel_isi_camera cam; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + struct reg_dbg debugfs_reg[0x100]; +#endif +}; +#define to_at76c451(cam) container_of(cam, struct at76c451, cam) + +static struct i2c_driver at76c451bc_driver; + +static int at76_write_8(struct at76c451 *is, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(&is->client, reg, value); +} + +static int at76_write_16(struct at76c451 *is, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(&is->client, reg, + cpu_to_le16(value)); +} + +static int at76_read_8(struct at76c451 *is, u8 reg) +{ + return i2c_smbus_read_byte_data(&is->client, reg); +} + +static int at76_read_16(struct at76c451 *is, u8 reg) +{ + int ret; + + ret = i2c_smbus_read_word_data(&is->client, reg); + if (ret < 0) + return ret; + + return le16_to_cpu(ret); +} + +#ifdef CONFIG_DEBUG_FS +#include +#include + +/* + * Generated from the data sheet using the following awk program: + * print "\t[REG_" toupper($3) "]" \ + * substr("\t\t\t\t\t", 0, (33 - length($3)) / 8) \ + * "= \"" tolower($3) "\","; + */ +static const char *reg_name[256] = { + [REG_SYNCHROSEL] = "synchrosel", + [REG_MISCEL_CTRL] = "miscel_ctrl", + [REG_TYPE_MOTIF] = "type_motif", + [REG_TB_MOTIF] = "tb_motif", + [REG_EB_MOTIF] = "eb_motif", + [REG_TM_MOTIF] = "tm_motif", + [REG_EM_MOTIF] = "em_motif", + [REG_R_GAIN1] = "r_gain1", + [REG_G_GAIN1] = "g_gain1", + [REG_B_GAIN1] = "b_gain1", + [REG_R_GAIN2] = "r_gain2", + [REG_B_GAIN2] = "b_gain2", + [REG_GAIN3] = "gain3", + [REG_PLL_PREDIV] = "pll_prediv", + [REG_PLL_LOOPDIV] = "pll_loopdiv", + [REG_SYS_STATUS] = "sys_status", + [REG_YAE_REF] = "yae_ref", + [REG_GAIN_MAX] = "gain_max", + [REG_TINT_MAX] = "tint_max", + [REG_AE_CTRL] = "ae_ctrl", + [REG_AE_TOLERANCE] = "ae_tolerance", + [REG_AEC_PERIOD] = "aec_period", + [REG_AEC_SPEED] = "aec_speed", + [REG_AWB_CTRL] = "awb_ctrl", + [REG_AWB_PERIOD] = "awb_period", + [REG_AWB_DELAY] = "awb_delay", + [REG_FLICKER_CTRL] = "flicker_ctrl", + [REG_G_GAIN1_AVR] = "g_gain1_avr", + [REG_R_GAIN2_AVR] = "r_gain2_avr", + [REG_B_GAIN2_AVR] = "b_gain2_avr", + [REG_GAIN3_AVR] = "gain3_avr", + [REG_VIGNETTING_SLOPE] = "vignetting_slope", + [REG_EDS_GAIN] = "eds_gain", + [REG_CSA_GAIN] = "csa_gain", + [REG_CORING_NOISE_LEVEL] = "coring_noise_level", + [REG_COLCOR_RR] = "colcor_rr", + [REG_COLCOR_RG] = "colcor_rg", + [REG_COLCOR_RB] = "colcor_rb", + [REG_COLCOR_GR] = "colcor_gr", + [REG_COLCOR_GG] = "colcor_gg", + [REG_COLCOR_GB] = "colcor_gb", + [REG_COLCOR_BR] = "colcor_br", + [REG_COLCOR_BG] = "colcor_bg", + [REG_COLCOR_BB] = "colcor_bb", + [REG_TINT] = "tint", + [REG_FRAME_PERIOD] = "frame_period", + [REG_LINE_LENGTH_SEQ] = "line_length_seq", + [REG_TINT_SEQ] = "tint_seq", + [REG_FRAME_PERIOD_SEQ] = "frame_period_seq", + [REG_TINT_AVR] = "tint_avr", + [REG_ROI0C] = "roi0c", + [REG_ROI0L] = "roi0l", + [REG_ROIW] = "roiw", + [REG_ROIH] = "roih", + [REG_GAMMA_INV] = "gamma_inv", + [REG_BYPASS] = "bypass", + [REG_CHIP_ID] = "chip_id", + [REG_MISC_TEST] = "misc_test", + [REG_PLL_AVR_CTRL] = "pll_avr_ctrl", +}; + +static u64 reg_dbg_get(void *data) +{ + struct reg_dbg *reg = data; + int ret; + + mutex_lock(®->is->mutex); + if (reg->offset < 128) + ret = at76_read_8(reg->is, reg->offset); + else + ret = at76_read_16(reg->is, reg->offset); + mutex_unlock(®->is->mutex); + + if (ret < 0) { + printk("%s: failed to read reg 0x%02x: %d\n", + reg->is->cam.name, reg->offset, ret); + return ~0ULL; + } + + return ret; +} + +static void reg_dbg_set(void *data, u64 val) +{ + struct reg_dbg *reg = data; + int ret; + + mutex_lock(®->is->mutex); + if (reg->offset < 128) + ret = at76_write_8(reg->is, reg->offset, val); + else + ret = at76_write_16(reg->is, reg->offset, val); + mutex_unlock(®->is->mutex); + + if (ret < 0) + printk("%s: failed to write reg 0x%02x: %d\n", + reg->is->cam.name, reg->offset, ret); +} +DEFINE_SIMPLE_ATTRIBUTE(reg_dbg_fops, reg_dbg_get, reg_dbg_set, "%04llx\n"); + +static void at76_init_debugfs(struct at76c451 *is) +{ + struct dentry *root, *reg; + unsigned int i; + + root = debugfs_create_dir(is->cam.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + is->debugfs_root = root; + + for (i = 0; i < ARRAY_SIZE(is->debugfs_reg); i++) { + if (!reg_name[i]) + continue; + + is->debugfs_reg[i].is = is; + is->debugfs_reg[i].offset = i; + + reg = debugfs_create_file(reg_name[i], S_IRUGO | S_IWUSR, + root, &is->debugfs_reg[i], + ®_dbg_fops); + if (!reg) + goto err_reg; + is->debugfs_reg[i].dentry = reg; + } + + return; + +err_reg: + while (i--) + debugfs_remove(is->debugfs_reg[i].dentry); + debugfs_remove(root); +err_root: + is->debugfs_root = NULL; + printk(KERN_ERR "%s: failed to initialize debugfs\n", + is->cam.name); +} + +static void at76_cleanup_debugfs(struct at76c451 *is) +{ + unsigned int i; + + if (is->debugfs_root) { + for (i = 0; i < ARRAY_SIZE(is->debugfs_reg); i++) + debugfs_remove(is->debugfs_reg[i].dentry); + debugfs_remove(is->debugfs_root); + } +} +#else +static inline void at76_init_debugfs(struct at76c451 *is) +{ + +} + +static inline void at76_cleanup_debugfs(struct at76c451 *is) +{ + +} +#endif /* CONFIG_DEBUG_FS */ + +static int at76_get_format(struct atmel_isi_camera *cam, + struct atmel_isi_format *fmt) +{ + struct at76c451 *is = to_at76c451(cam); + int ret = 0; + + fmt->pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->input_format = ATMEL_ISI_PIXFMT_CbYCrY; + +#if 0 + mutex_lock(&is->mutex); + + ret = at76_read_16(is, REG_ROIW); + if (ret < 0) + goto out; + fmt->pix.width = ret; + + ret = at76_read_16(is, REG_ROIH); + if (ret < 0) + goto out; + fmt->pix.height = ret; + +out: + mutex_unlock(&is->mutex); +#else + fmt->pix.width = 320; + fmt->pix.height = 240; +#endif + + return ret; +} + +static int at76_set_format(struct atmel_isi_camera *cam, + struct atmel_isi_format *fmt) +{ + struct at76c451 *is = to_at76c451(cam); + int ret; + + fmt->pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->input_format = ATMEL_ISI_PIXFMT_CbYCrY; + + mutex_lock(&is->mutex); + +#if 0 + if (fmt->pix.width > AT76_MAX_WIDTH) + fmt->pix.height = AT76_MAX_WIDTH; + if (fmt->pix.height > AT76_MAX_HEIGHT) + fmt->pix.height = AT76_MAX_HEIGHT; + + ret = at76_write_16(is, REG_ROIW, fmt->pix.width); + if (ret) + goto out; + ret = at76_write_16(is, REG_ROIH, fmt->pix.height); +#else + /* Force QVGA mode for now (320x240) */ + fmt->pix.width = 320; + fmt->pix.height = 240; + ret = at76_write_8(is, REG_TYPE_MOTIF, 0x05); +#endif + + if (ret) + goto out; + + pr_debug("%s: set_format %ux%u\n", cam->name, + fmt->pix.width, fmt->pix.height); + +out: + mutex_unlock(&is->mutex); + return ret; +} + +static int at76_start_capture(struct atmel_isi_camera *cam) +{ + struct at76c451 *is = to_at76c451(cam); + int ret; + + mutex_lock(&is->mutex); + + ret = at76_write_8(is, REG_MISCEL_CTRL, + is->miscel_ctrl & ~AT76_STANDBY); + if (ret) + goto out; + is->miscel_ctrl &= ~AT76_STANDBY; + + ret = at76_write_16(is, REG_PLL_AVR_CTRL, + is->pll_avr_ctrl | 0x0002); + if (ret) + goto out; + is->pll_avr_ctrl |= 0x0002; + + ret = at76_write_16(is, REG_MISC_TEST, 0x2e03); + ret |= at76_write_8(is, REG_YAE_REF, 0x10); + ret |= at76_write_8(is, REG_GAIN_MAX, 0x7f); + if (ret) + goto out; + + msleep(500); + + ret = at76_write_16(is, REG_MISC_TEST, 0x2e00); + ret |= at76_write_8(is, REG_YAE_REF, 0x6e); + ret |= at76_write_8(is, REG_GAIN_MAX, 0x10); + +out: + mutex_unlock(&is->mutex); + return ret; +} + +static int at76_stop_capture(struct atmel_isi_camera *cam) +{ + struct at76c451 *is = to_at76c451(cam); + int ret; + + mutex_lock(&is->mutex); + + ret = at76_write_8(is, REG_MISCEL_CTRL, + is->miscel_ctrl | AT76_STANDBY); + if (!ret) + is->miscel_ctrl |= AT76_STANDBY; + + mutex_unlock(&is->mutex); + + return ret; +} + +static void at76_reset_hardware(struct at76c451 *is) +{ + u8 buf = 0x06; + struct i2c_msg msg = { + .addr = 0x00, + .len = 1, + .buf = &buf, + }; + + if (i2c_transfer(is->client.adapter, &msg, 1) < 0) + printk(KERN_ERR "%s: reset failed\n", is->cam.name); +} + +static int at76_init_hardware(struct at76c451 *is) +{ + unsigned long mck_rate, mul, div; + int timeout; + int chip_id; + int ret; + + at76_reset_hardware(is); + + /* Try to identify the camera */ + chip_id = at76_read_16(is, REG_CHIP_ID); + if (chip_id < 0) + return -EIO; + + if (chip_id != AT76C451BC_MY15AT) { + printk(KERN_ERR "%s: Unknown chip ID 0x%04x\n", + is->cam.name, chip_id); + return -ENODEV; + } + + /* Load some sane defaults: Standby mode with avr switched off */ + is->miscel_ctrl = 0x39; + if (at76_write_8(is, REG_MISCEL_CTRL, is->miscel_ctrl)) + return -EIO; + ret = at76_read_16(is, REG_PLL_AVR_CTRL); + if (ret < 0) + return -EIO; + is->pll_avr_ctrl = ret & ~(1 << 1); + if (at76_write_16(is, REG_PLL_AVR_CTRL, is->pll_avr_ctrl)) + return -EIO; + + /* + * Initialize the PLL. Try to get as close to 1 MHz as + * possible on the PLL input and 27 MHz on the output. + */ + mck_rate = clk_get_rate(is->mclk); + if (mck_rate > 128000000) { + printk(KERN_ERR + "%s: Master clock too fast (%lu Hz, max 128 MHz)\n", + is->cam.name, mck_rate); + return -ENODEV; + } + div = (mck_rate + 500000UL) / 1000000UL; + mul = (27000000UL * div + mck_rate / 2) / mck_rate; + + pr_debug("%s: PLL configuration: (%lu / %lu) * %lu = %lu\n", + is->cam.name, mck_rate, div, mul, + (mck_rate / div) * mul); + + /* Use external clock while reprogramming the PLL */ + if (at76_write_8(is, REG_MISCEL_CTRL, 0x31)) + return -EIO; + if (at76_write_8(is, REG_MISCEL_CTRL, 0x21)) + return -EIO; + + if (at76_write_8(is, REG_PLL_PREDIV, div)) + return -EIO; + if (at76_write_8(is, REG_PLL_LOOPDIV, mul)) + return -EIO; + + /* Wait for PLL to lock (2 seconds max) */ + timeout = 2000; + while (--timeout) { + ret = at76_read_8(is, REG_SYS_STATUS); + pr_debug("sys_status=0x%02x\n", ret); + if (ret >= 0 && (ret & 0x01)) + break; + msleep(1); + } + + if (!timeout) { + printk(KERN_ERR "%s: timed out waiting for PLL lock\n", + is->cam.name); + return -EIO; + } + + /* Switch to PLL and return to standby mode */ + if (at76_write_8(is, REG_MISCEL_CTRL, 0x31)) + return -EIO; + if (at76_write_8(is, REG_MISCEL_CTRL, is->miscel_ctrl)) + return -EIO; + + /* Set up synchronization: We want FEN/LEN instead of HSYNC/VSYNC */ + if (at76_write_8(is, REG_SYNCHROSEL, 0)) + return -EIO; + + /* Hey, that was easy. */ + return 0; +} + +static int at76_detect_client(struct i2c_adapter *adapter, + int address, int kind) +{ + struct i2c_client *client; + struct at76c451 *is; + int ret; + + pr_debug("at76c451bc: detecting client on address 0x%x\n", address); + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, + (I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_WORD_DATA + | I2C_FUNC_SMBUS_WRITE_WORD_DATA))) + return 0; + + is = kzalloc(sizeof(struct at76c451), GFP_KERNEL); + if (!is) + return -ENOMEM; + + client = &is->client; + client->addr = address; + client->adapter = adapter; + client->driver = &at76c451bc_driver; + strcpy(client->name, "at76c451bc-my15at"); + + is->cam.name = client->name; + is->cam.hsync_act_low = 1; + is->cam.vsync_act_low = 0; + is->cam.pclk_act_falling = 0; + is->cam.has_emb_sync = 1; + is->cam.get_format = at76_get_format; + is->cam.set_format = at76_set_format; + is->cam.start_capture = at76_start_capture; + is->cam.stop_capture = at76_stop_capture; + + mutex_init(&is->mutex); + + is->mclk = clk_get(NULL, mclk_name); + if (IS_ERR(is->mclk)) { + ret = PTR_ERR(is->mclk); + goto err_clk; + } + clk_enable(is->mclk); + + ret = i2c_attach_client(client); + if (ret) + goto err_attach; + + i2c_set_clientdata(client, is); + + ret = at76_init_hardware(is); + if (ret) + goto err_init_hw; + + /* We're up and running. Notify the ISI driver */ + ret = atmel_isi_register_camera(&is->cam); + if (ret) + goto err_register; + + printk(KERN_INFO "AT76C451BC-MY15AT Image Sensor at %s:0x%02x\n", + adapter->name, address); + + at76_init_debugfs(is); + + return 0; + +err_register: +err_init_hw: + at76_reset_hardware(is); + i2c_detach_client(client); +err_attach: + clk_disable(is->mclk); + clk_put(is->mclk); +err_clk: + kfree(is); + return ret; +} + +static int at76_attach_adapter(struct i2c_adapter *adapter) +{ + pr_debug("at76c451bc: starting probe for adapter %s (%u)\n", + adapter->name, adapter->id); + return i2c_probe(adapter, &addr_data, &at76_detect_client); +} + +static int at76_detach_client(struct i2c_client *client) +{ + struct at76c451 *is = i2c_get_clientdata(client); + int ret; + + at76_cleanup_debugfs(is); + atmel_isi_unregister_camera(&is->cam); + + at76_reset_hardware(is); + + ret = i2c_detach_client(client); + if (ret) + return ret; + + clk_disable(is->mclk); + clk_put(is->mclk); + kfree(is); + + return 0; +} + +static struct i2c_driver at76c451bc_driver = { + .driver = { + .name = "at76c451bc", + }, + .id = I2C_DRIVERID_AT76C451BC, + .attach_adapter = &at76_attach_adapter, + .detach_client = &at76_detach_client, +}; + +static struct clk *mclk; +static struct clk *mclk_parent; + +static int __init at76c451bc_init(void) +{ + /* + * Set up the master clock, if available. If clk_get() fails, + * this hopefully means that the board generates a suitable + * master clock some other way, which is fine by us. + * + * We need to do this before probing the i2c bus, as the + * camera won't ack any messages when it doesn't have a clock. + */ + mclk_parent = clk_get(NULL, mclk_parent_name); + if (!IS_ERR(mclk_parent)) + clk_enable(mclk_parent); + else + mclk_parent = NULL; + + mclk = clk_get(NULL, mclk_name); + if (!IS_ERR(mclk)) { + if (mclk_parent) + clk_set_parent(mclk, mclk_parent); + + clk_set_rate(mclk, 27000000); + clk_enable(mclk); + } else { + mclk = NULL; + } + + return i2c_add_driver(&at76c451bc_driver); +} +module_init(at76c451bc_init); + +static void __exit at76c451bc_exit(void) +{ + if (mclk) { + clk_disable(mclk); + clk_put(mclk); + } + if (mclk_parent) { + clk_disable(mclk_parent); + clk_put(mclk_parent); + } + i2c_del_driver(&at76c451bc_driver); +} +module_exit(at76c451bc_exit); + +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_DESCRIPTION("Atmel AT76C451BC-MY15AT Eye-On-Si(tm) Image Sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/at76c451bc.h b/drivers/media/video/at76c451bc.h new file mode 100644 index 0000000..2b70c4f --- /dev/null +++ b/drivers/media/video/at76c451bc.h @@ -0,0 +1,81 @@ +/* + * Atmel AT76C451BC Eye-On-Si(tm) Digital Camera driver + * + * Copyright (C) 2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __DRIVERS_MEDIA_VIDEO_AT76C451BC_H +#define __DRIVERS_MEDIA_VIDEO_AT76C451BC_H + +/* + * Generated from the data sheet using the following awk program: + * print "#define REG_" toupper($3) \ + * substr("\t\t\t\t", 0, (27 - length($3)) / 8) $1; + */ +#define REG_SYNCHROSEL 0 +#define REG_MISCEL_CTRL 1 +#define REG_TYPE_MOTIF 2 +#define REG_TB_MOTIF 3 +#define REG_EB_MOTIF 4 +#define REG_TM_MOTIF 5 +#define REG_EM_MOTIF 6 +#define REG_R_GAIN1 7 +#define REG_G_GAIN1 8 +#define REG_B_GAIN1 9 +#define REG_R_GAIN2 10 +#define REG_B_GAIN2 11 +#define REG_GAIN3 12 +#define REG_PLL_PREDIV 13 +#define REG_PLL_LOOPDIV 14 +#define REG_SYS_STATUS 15 +#define REG_YAE_REF 16 +#define REG_GAIN_MAX 17 +#define REG_TINT_MAX 18 +#define REG_AE_CTRL 19 +#define REG_AE_TOLERANCE 20 +#define REG_AEC_PERIOD 21 +#define REG_AEC_SPEED 22 +#define REG_AWB_CTRL 23 +#define REG_AWB_PERIOD 24 +#define REG_AWB_DELAY 25 +#define REG_FLICKER_CTRL 26 +#define REG_G_GAIN1_AVR 27 +#define REG_R_GAIN2_AVR 28 +#define REG_B_GAIN2_AVR 29 +#define REG_GAIN3_AVR 30 +#define REG_VIGNETTING_SLOPE 31 +#define REG_EDS_GAIN 32 +#define REG_CSA_GAIN 33 +#define REG_CORING_NOISE_LEVEL 34 +#define REG_COLCOR_RR 35 +#define REG_COLCOR_RG 36 +#define REG_COLCOR_RB 37 +#define REG_COLCOR_GR 38 +#define REG_COLCOR_GG 39 +#define REG_COLCOR_GB 40 +#define REG_COLCOR_BR 41 +#define REG_COLCOR_BG 42 +#define REG_COLCOR_BB 43 +#define REG_TINT 128 +#define REG_FRAME_PERIOD 129 +#define REG_LINE_LENGTH_SEQ 130 +#define REG_TINT_SEQ 131 +#define REG_FRAME_PERIOD_SEQ 132 +#define REG_TINT_AVR 133 +#define REG_ROI0C 134 +#define REG_ROI0L 135 +#define REG_ROIW 136 +#define REG_ROIH 137 +#define REG_GAMMA_INV 138 +#define REG_BYPASS 139 +#define REG_CHIP_ID 140 +#define REG_MISC_TEST 193 +#define REG_PLL_AVR_CTRL 212 + +/* Bit definitions */ +#define AT76_STANDBY (1 << 3) + +#endif /* __DRIVERS_MEDIA_VIDEO_AT76C451BC_H */ diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index aa83d41..13ca311 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -118,6 +118,7 @@ #define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */ #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */ +#define I2C_DRIVERID_AT76C451BC 92 /* Atmel AT76C451BC image sensor */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ -- 1.5.2.3