/* Common OmniVision camera chip definitions
 *
 * Copyright (c) 1999-2003 Mark McClelland
 *
 * 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. NO WARRANTY OF ANY KIND is expressed or implied.
 */

#ifndef __LINUX_OVCAMCHIP_H
#define __LINUX_OVCAMCHIP_H

#include <linux/videodev.h>
#include <linux/i2c.h>
#include "id.h"
#include "compat.h"

#define OVCAMCHIP_DEBUG

#ifdef OVCAMCHIP_DEBUG
extern int ovcamchip_debug;
	#define PDEBUG(level, fmt, args...) \
		if (ovcamchip_debug >= (level)) info("[%s:%d] " fmt, \
		__PRETTY_FUNCTION__, __LINE__ , ## args)
#else
	#define PDEBUG(level, fmt, args...) do {} while(0)
#endif

#if !defined(err)
#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
#endif

#if !defined(info)
#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , \
 ## arg)
#endif

#if !defined(warn)
#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , \
 ## arg)
#endif


/* Number of times to retry chip detection. Increase this if you are getting
 * "Failed to init camera chip" */
#define I2C_DETECT_RETRIES	10

/* --------------------------------- */
/*           ENUMERATIONS            */
/* --------------------------------- */

/* Controls */
enum {
	OVCAMCHIP_CID_CONT,		/* Contrast */
	OVCAMCHIP_CID_BRIGHT,		/* Brightness */
	OVCAMCHIP_CID_SAT,		/* Saturation */
	OVCAMCHIP_CID_HUE,		/* Hue */
	OVCAMCHIP_CID_EXP,		/* Exposure */
	OVCAMCHIP_CID_FREQ,		/* Light frequency */
	OVCAMCHIP_CID_BANDFILT,		/* Banding filter */
	OVCAMCHIP_CID_AUTOBRIGHT,	/* Auto brightness */
	OVCAMCHIP_CID_AUTOEXP,		/* Auto exposure */
	OVCAMCHIP_CID_BACKLIGHT,	/* Back light compensation */
	OVCAMCHIP_CID_MIRROR,		/* Mirror horizontally */
};

#if defined(HAVE_V4L2)
/* Don't use these values from userspace!! They are translated by the
 * upper-layer driver, and are not guaranteed to remain stable anyway. Instead,
 * find private controls by name. */
#define OVCAMCHIP_V4L2_CID_AEC     (V4L2_CID_PRIVATE_BASE + 0)
#define OVCAMCHIP_V4L2_CID_LASTP1  (V4L2_CID_PRIVATE_BASE + 1) /* Last + 1 */
#endif

/* Chip types */
#define NUM_CC_TYPES	9
enum {
	CC_UNKNOWN,
	CC_OV76BE,
	CC_OV7610,
	CC_OV7620,
	CC_OV7620AE,
	CC_OV6620,
	CC_OV6630,
	CC_OV6630AE,
	CC_OV6630AF,
};

/* --------------------------------- */
/*           I2C ADDRESSES           */
/* --------------------------------- */

#define OV7xx0_SID   (0x42 >> 1)
#define OV6xx0_SID   (0xC0 >> 1)

/* --------------------------------- */
/*                API                */
/* --------------------------------- */

struct ovcamchip_regvals {
	unsigned char reg;
	unsigned char val;
};

struct ovcamchip_control {
	__u32 id;
	__s32 value;
};

struct ovcamchip_ops {
	int (*init)(struct i2c_client *);
	int (*free)(struct i2c_client *);
	int (*command)(struct i2c_client *, unsigned int, void *);
};

struct ovcamchip_window {
	int x;
	int y;
	int width;
	int height;
	int format;
	int quarter;		/* Scale width and height down 2x */

	/* This stuff will be removed eventually */
	int clockdiv;		/* Clock divisor setting */
};

struct ovcamchip {
	struct ovcamchip_ops *sops;
	void *spriv;               /* Private data for OV7x10.c etc... */
	int subtype;               /* = SEN_OV7610 etc... */
	int mono;                  /* Monochrome chip? (invalid until init) */
	int initialized;           /* OVCAMCHIP_CMD_INITIALIZE was successful */

#if defined(HAVE_V4L2)
	/* V4L2 controls */
	struct v4l2_queryctrl qc_brightness;
	struct v4l2_queryctrl qc_contrast;
	struct v4l2_queryctrl qc_saturation;
	struct v4l2_queryctrl qc_red_balance;
	struct v4l2_queryctrl qc_blue_balance;
	struct v4l2_queryctrl qc_agc;
	struct v4l2_queryctrl qc_gain;
	struct v4l2_queryctrl qc_exposure;
	struct v4l2_queryctrl qc_awb;

	/* Private controls */
	struct v4l2_queryctrl qc_aec;
#endif
};

/* Commands */
#define OVCAMCHIP_CMD_Q_SUBTYPE     _IOR  (0x88, 0x00, int)
#define OVCAMCHIP_CMD_INITIALIZE    _IOW  (0x88, 0x01, int)
/* You must call OVCAMCHIP_CMD_INITIALIZE before any of commands below! */
#define OVCAMCHIP_CMD_S_CTRL        _IOW  (0x88, 0x02, struct ovcamchip_control)
#define OVCAMCHIP_CMD_G_CTRL        _IOWR (0x88, 0x03, struct ovcamchip_control)
#define OVCAMCHIP_CMD_S_MODE        _IOW  (0x88, 0x04, struct ovcamchip_window)
#define OVCAMCHIP_MAX_CMD           _IO   (0x88, 0x3f)

/* --------------------------------- */
/*              I2C I/O              */
/* --------------------------------- */

static inline int
ov_read(struct i2c_client *c, unsigned char reg, unsigned char *value)
{	
	int rc;
	
	rc = i2c_smbus_read_byte_data(c, reg);
	*value = (unsigned char) rc;
	return rc;
}

static inline int
ov_write(struct i2c_client *c, unsigned char reg, unsigned char value )
{
	return i2c_smbus_write_byte_data(c, reg, value);
}

/* --------------------------------- */
/*        FUNCTION PROTOTYPES        */
/* --------------------------------- */

/* Functions in ovcamchip.c */

extern int ov_write_regvals(struct i2c_client *c,
			    struct ovcamchip_regvals *rvals);

extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
	      		 unsigned char value, unsigned char mask);

#if defined(HAVE_V4L2)
extern struct v4l2_queryctrl * ovcamchip_get_qc(struct ovcamchip *ov, __u32 id);
#endif

#endif
