From: <hap...@us...> - 2007-06-22 19:19:11
|
Revision: 1044 http://svn.sourceforge.net/hackndev/?rev=1044&view=rev Author: happy-slapin Date: 2007-06-22 12:19:08 -0700 (Fri, 22 Jun 2007) Log Message: ----------- OV9640: Added i2c module code Added Paths: ----------- linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.c linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.h Added: linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.c =================================================================== --- linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.c (rev 0) +++ linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.c 2007-06-22 19:19:08 UTC (rev 1044) @@ -0,0 +1,303 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <asm/hardware.h> +#include <asm/types.h> +#include <linux/delay.h> + +#include "i2c-ov9640.h" + +#define DEBUG 1 +#define DPRINTK(fmt,args...) do { if (DEBUG) printk("in function %s "fmt,__FUNCTION__,##args);} while(0) +extern int i2c_adapter_id(struct i2c_adapter *adap); + +int i2c_ov9640_cleanup(void); +void i2c_ov9640_inc_use (struct i2c_client *client); +void i2c_ov9640_dec_use (struct i2c_client *client); +int i2c_ov9640_attach_adapter(struct i2c_adapter *adapter); +int i2c_ov9640_detect_client(struct i2c_adapter *, int, unsigned short, int); +int i2c_ov9640_detach_client(struct i2c_client *client); + +struct i2c_driver ov9640_driver = +{ + name: "ov9640 driver", /* name */ + id: I2C_DRIVERID_OV9640, /* id */ + flags: I2C_DF_NOTIFY, /* flags */ + attach_adapter: &i2c_ov9640_attach_adapter, /* attach_adapter */ + detach_client: &i2c_ov9640_detach_client, /* detach_client */ + command: NULL, + inc_use: &i2c_ov9640_inc_use, + dec_use: &i2c_ov9640_dec_use +}; + +extern struct i2c_adapter *i2cdev_adaps[]; +/* Unique ID allocation */ +static int ov9640_id = 0; +struct i2c_client *g_client = NULL; +static unsigned short normal_i2c[] = {OV9640_SLAVE_ADDR ,I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; +I2C_CLIENT_INSMOD; + +/* + * This call returns a unique low identifier for each registered adapter, + * or -1 if the adapter was not registered. + */ +void i2c_ov9640_inc_use (struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +#ifdef MODULE +#endif +} + +void i2c_ov9640_dec_use (struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +#ifdef MODULE +#endif +} + +char ov9640_read(u8 addr, u8 *pvalue) +{ + int res=0; + char buf=0; + struct i2c_msg msgs[2] = { + { 0, I2C_M_WR, 1, &addr }, + { 0, I2C_M_RD, 1, &buf }}; + + if( g_client == NULL ) + return -1; + i2c_ov9640_inc_use(g_client); + msgs[0].addr=msgs[1].addr=g_client->addr; + res=i2c_transfer(g_client->adapter,&msgs[0],1); + if (res<=0) + goto out; + res=i2c_transfer(g_client->adapter,&msgs[1],1); + if (res<=0) + goto out; + *pvalue = buf; + i2c_ov9640_dec_use(g_client); +out: + DPRINTK(KERN_INFO "In funtion %s addr:%x,value=%x\n", __FUNCTION__, addr,*pvalue); + if (res<=0) DPRINTK("res = %d \n",res); + return res; +} + +int ov9640_write(u8 addr, u8 value) +{ + int res=0; + if( g_client == NULL ) + return -1; + /* + char buf=0; + struct i2c_msg msgs[2] = { + { 0, I2C_M_WR, 1, &addr }, + { 0, I2C_M_WR, 1, &value }}; + msgs[0].addr=msgs[1].addr=g_client->addr; + res=i2c_transfer(g_client->adapter,&msgs[0],1); + if (res<=0) return res; + res=i2c_transfer(g_client->adapter,&msgs[1],1); + if (res<=0) return res; + + + res=i2c_smbus_write_byte_data(g_client, addr, value ); + */ + char buf[2]={addr,value}; + i2c_ov9640_inc_use(g_client); + res = i2c_master_send(g_client, buf, 2); + i2c_ov9640_dec_use(g_client); + if (res >0) res =0; + else res =-1; + DPRINTK(KERN_INFO "In funtion %s addr:%x value:%xreturn %d \n", __FUNCTION__, addr,value,res); + return res; +} + + +int i2c_ov9640_read(struct i2c_client *client, u8 reg) +{ + unsigned char msgbuf=0; + DPRINTK("in function %s\n",__FUNCTION__); + i2c_master_recv(client,&msgbuf,1); + return msgbuf; + /* + */ +// return i2c_smbus_read_word_data(client,reg); +// return i2c_smbus_read_byte_data(client,reg); +} + +int i2c_ov9640_write(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client,reg,value); +} + + +int i2c_ov9640_attach_adapter(struct i2c_adapter *adap) +{ + DPRINTK("In function %s.\n", __FUNCTION__); + return i2c_probe(adap,&addr_data,i2c_ov9640_detect_client); +} + + +int i2c_ov9640_detect_client(struct i2c_adapter *adapter, int address, unsigned short flags, int kind) +{ + struct i2c_client *new_client; + int err = 0; + struct ov9640_data *data; + + /*check if */ + if(g_client != NULL) { + err = -ENXIO; + goto ERROR0; + } + + + DPRINTK(KERN_INFO "In funtion %s. address=0X%X\n", __FUNCTION__, address); + /* Let's see whether this adapter can support what we need. + Please substitute the things you need here! */ + if ( !i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA) ) { + DPRINTK(KERN_INFO "Word op is not permited.\n"); + goto ERROR0; + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access several i2c functions safely */ + + /* Note that we reserve some space for ov9640_data too. If you don't + need it, remove it. We do it here to help to lessen memory + fragmentation. */ + + new_client=kmalloc(sizeof(struct i2c_client)+sizeof(struct ov9640_data), + GFP_KERNEL ); + + if ( !new_client ) { + err = -ENOMEM; + goto ERROR0; + } + + data = (struct ov9640_data *) (new_client + 1); + + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &ov9640_driver; + new_client->flags = 0; + + g_client = new_client; + + /* Now, we do the remaining detection. If no `force' parameter is used. */ + + /* First, the generic detection (if any), that is skipped if any force + parameter was used. */ + + if (kind <= 0) { + char res = -1; + mdelay(2000); + ov9640_read(REV,&res); + /* The below is of course bogus */ + DPRINTK("I2C: Probe ov9640 chip..addr=0x%x, REV=%d, res=0x%x\n", address, REV, res); + /*ov9640 chip id is 0x9648 + if(res != OV9640_CHIP_ID) { + DPRINTK(KERN_WARNING "Failed.product id =%d \n",res); + goto ERROR1; + } + else { + DPRINTK("OV9640 chip id is 0X%04X\n", OV9640_CHIP_ID); + if ( ov9640_id == 0 ) + DPRINTK(" detected.\n"); + }*/ + } + + strcpy(new_client->name, "ov9640"); + /* Automatically unique */ + new_client->id = ov9640_id++; + + /* Only if you use this field */ + data->valid = 0; + + /* Only if you use this field */ + init_MUTEX(&data->update_lock); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* This function can write default values to the client registers, if + needed. */ + /* ov9640_init_client(new_client); */ + return 0; + + /* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + +ERROR3: +ERROR1: + kfree(new_client); + g_client = NULL; +ERROR0: + return err; +} + +int i2c_ov9640_detach_client(struct i2c_client *client) +{ + int err; + + /* Try to detach the client from i2c space */ + if ((err = i2c_detach_client(client))) { + DPRINTK("ov9640.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); /* Frees client data too, if allocated at the same time */ + g_client = NULL; + return 0; +} + +/* Keep track of how far we got in the initialization process. If several + things have to initialized, and we fail halfway, only those things + have to be cleaned up! */ +static int ov9640_initialized = 0; + +int i2c_ov9640_init(void) +{ + int res; + + if (ov9640_initialized) + return 0; + DPRINTK("I2C: driver for device ov9640.\n"); + if ( (res = i2c_add_driver(&ov9640_driver)) ) { + DPRINTK("ov9640: Driver registration failed, module not inserted.\n"); + i2c_ov9640_cleanup(); + return res; + } + ov9640_initialized ++; + if(g_client != NULL) + DPRINTK("I2C: driver for device %s registed!.\n", g_client->name); + else + DPRINTK("I2C: driver for device unregisted!.\n"); + return 0; +} + +int i2c_ov9640_cleanup(void) +{ + int res; + + if (ov9640_initialized == 1) { + if ((res = i2c_del_driver(&ov9640_driver))) { + DPRINTK("ov9640: Driver registration failed, module not removed.\n"); + return res; + } + ov9640_initialized --; + } + return 0; +} + +EXPORT_SYMBOL(i2c_ov9640_init); +EXPORT_SYMBOL(ov9640_write); +EXPORT_SYMBOL(ov9640_read); +EXPORT_SYMBOL(i2c_ov9640_cleanup); +//module_init(i2c_ov9640_init); +//module_exit(i2c_ov9640_cleanup); +MODULE_LICENSE("GPL"); + Added: linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.h =================================================================== --- linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.h (rev 0) +++ linux4palm/linux/trunk/drivers/i2c/chips/i2c-ov9640.h 2007-06-22 19:19:08 UTC (rev 1044) @@ -0,0 +1,42 @@ +#ifndef __I2C_OV9640_H__ +#define __I2C_OV9640_H__ + +#define DEBUG + +/* Calculating the Module Block Number */ +#define BLOCK(a) (u8)((a) >> 7) /* register's module block address. */ +#define OFFSET(a) (u8)((a) & 0x7F ) /* register's offset to this block. */ + +/* Update the block address.*/ +#define BLOCK_SWITCH_CMD 0xFE + +#define OV9640_SLAVE_ADDR (0x60>>1) /* 60 for write , 61 for read */ +// #define SENSOR_SLAVE_ADDR 0x0055 /* tbd: */ + + +#define I2C_DRIVERID_OV9640 I2C_DRIVERID_EXP2 + +/*ov9640 chip id*/ +#define OV9640_CHIP_ID 0x9648 + +/* Register definitions in OV9640's chip. */ +#define PID 0xA +#define REV 0xA + +struct ov9640_data { + /* + * Because the i2c bus is slow, it is often useful to cache the read + * information of a chip for some time (for example, 1 or 2 seconds). + * It depends of course on the device whether this is really worthwhile + * or even sensible. + */ + struct semaphore update_lock; /* When we are reading lots of information, + another process should not update the + below information */ + + char valid; /* != 0 if the following fields are valid. */ + int blockaddr; /* current using block address. */ + unsigned long last_updated; /* In jiffies */ +}; +#endif + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |