diff options
Diffstat (limited to 'uClinux-2.4.20-uc1/drivers/char/w90n745_i2c.c')
-rwxr-xr-x | uClinux-2.4.20-uc1/drivers/char/w90n745_i2c.c | 1200 |
1 files changed, 600 insertions, 600 deletions
diff --git a/uClinux-2.4.20-uc1/drivers/char/w90n745_i2c.c b/uClinux-2.4.20-uc1/drivers/char/w90n745_i2c.c index 7b9cd9b..fd0f815 100755 --- a/uClinux-2.4.20-uc1/drivers/char/w90n745_i2c.c +++ b/uClinux-2.4.20-uc1/drivers/char/w90n745_i2c.c @@ -1,600 +1,600 @@ -/****************************************************************************
- *
- * Copyright (c) 2004 - 2006 Winbond Electronics Corp. All rights reserved.
- *
- ****************************************************************************/
-
-/****************************************************************************
- *
- * FILENAME
- * w90n745_i2c.c
- *
- * VERSION
- * 1.0
- *
- * DESCRIPTION
- * Winbond W90N710 I2C Driver
- *
- * DATA STRUCTURES
- * None
- *
- * FUNCTIONS
- * None
- *
- * HISTORY
- * 2005/05/20 Ver 1.0 Created by PC34 QFu
- *
- * REMARK
- * None
- *************************************************************************/
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
-
-#include "w90n745_i2c.h"
-
-
-//#define I2C_DEBUG
-//#define I2C_DEBUG_PRINT_LINE
-//#define I2C_DEBUG_ENABLE_ENTER_LEAVE
-//#define I2C_DEBUG_ENABLE_MSG
-//#define I2C_DEBUG_ENABLE_MSG2
-
-#ifdef I2C_DEBUG
-#define PDEBUG(fmt, arg...) printk(fmt, ##arg)
-#else
-#define PDEBUG(fmt, arg...)
-#endif
-
-#ifdef I2C_DEBUG_PRINT_LINE
-#define PRN_LINE() PDEBUG("[%-20s] : %d\n", __FUNCTION__, __LINE__)
-#else
-#define PRN_LINE()
-#endif
-
-#ifdef I2C_DEBUG_ENABLE_ENTER_LEAVE
-#define ENTER() PDEBUG("[%-20s] : Enter...\n", __FUNCTION__)
-#define LEAVE() PDEBUG("[%-20s] : Leave...\n", __FUNCTION__)
-#else
-#define ENTER()
-#define LEAVE()
-#endif
-
-#ifdef I2C_DEBUG_ENABLE_MSG
-#define MSG(msg) PDEBUG("[%-20s] : %s", __FUNCTION__, msg)
-#else
-#define MSG(msg)
-#endif
-
-#ifdef I2C_DEBUG_ENABLE_MSG2
-#define MSG2(fmt, arg...) PDEBUG("[%-20s] : "fmt, __FUNCTION__, ##arg)
-#define PRNBUF(buf, count) {int i;MSG2("CID Data: ");for(i=0;i<count;i++)\
- PDEBUG("%02x ", buf[i]);PDEBUG("\n");}
-#else
-#define MSG2(fmt, arg...)
-#define PRNBUF(buf, count)
-#endif
-
-
-
-#define i2c_outl(dev, dword, addr) outl(dword, base[dev->no] + addr)
-#define i2c_inl(dev, addr) inl(base[dev->no] + addr)
-
-
-static const int base[I2C_NUMBER] = {I2C0_IO_BASE, I2C1_IO_BASE};
-static const int irq[I2C_NUMBER] = {I2C0_IRQ, I2C1_IRQ};
-static int bNackValid;
-
-static void i2c_Disable(i2c_dev *dev) /* Disable i2c core and interrupt */
-{
-
- i2c_outl(dev, 0x00, CSR);
-}
-
-static void i2c_Enable(i2c_dev *dev) /* Enable i2c core and interrupt */
-{
- i2c_outl(dev, 0x03, CSR);
-}
-
-static int i2c_SetSpeed(i2c_dev *dev, int sp)
-{
- unsigned int d;
-
- if( sp != 100 && sp != 400)
- return -1;
-
- d = I2C_INPUT_CLOCK/(sp * 5) -1;
-
- i2c_outl(dev, d & 0xffff, DIVIDER);
-
- MSG2("Set Speed = %d\n", sp);
-
- return 0;
-}
-
-static int i2c_IsBusFree(i2c_dev *dev)
-{
- if( (i2c_inl(dev, SWR) & 0x18) == 0x18 && //SDR and SCR keep high
- (i2c_inl(dev, CSR) & 0x0400) == 0 ){ //I2C_BUSY is false
- //MSG("Bus Free\n");
-
- return 1;
- }
- else{
- //MSG("Bus Busy\n");
-
- return 0;
- }
-
-}
-
-static int i2c_Command(i2c_dev *dev, int cmd)
-{
-
-#if 0
- printk("CMD : ");
-
- if(cmd & I2C_CMD_START){
- printk("START ");
- }
-
- if (cmd & I2C_CMD_STOP){
- printk("STOP ");
-
- }
-
- if(cmd & I2C_CMD_NACK){
- printk("NACK ");
- }
-
- if(cmd & I2C_CMD_WRITE){
- printk("WRITE : [%02x]", i2c_inl(dev, TXR) & 0xff);
- }
-
- if(cmd & I2C_CMD_READ){
- printk("READ : [%02x]", i2c_inl(dev, RXR) & 0xff);
- }
-
- printk("\n");
-
-#endif
-
- if(cmd & I2C_CMD_WRITE)
- bNackValid = 1;
- else
- bNackValid = 0;
-
- i2c_outl(dev, cmd, CMDR);
-
- return 0;
-
-}
-
-
-static int i2c_CalculateAddress(i2c_dev *dev, int mode)
-{
- int i;
- unsigned int addr;
- unsigned int subaddr;
-
- subaddr = dev->subaddr;
- addr = dev->addr;
-
- addr = ((addr << 1) & 0xfe) | I2C_WRITE;
-
- dev->buffer[0] = addr & 0xff;
-
- for(i = dev->subaddr_len; i > 0; i--){
- dev->buffer[i] = subaddr & 0xff;
- subaddr >>= 8;
- }
-
- if(mode == I2C_STATE_READ){
- i = dev->subaddr_len + 1;
- dev->buffer[i] = (addr & 0xfe) | I2C_READ;
- }
-
-#ifdef I2C_DEBUG
- if(mode == I2C_STATE_WRITE){
- MSG2("Begin Write to Device [%02x] Address [%02x]\n",
- dev->addr, dev->subaddr);
- MSG("Buffer : \n");
- for(i = 0; i < dev->subaddr_len +1; i++)
- PDEBUG("%02x ", dev->buffer[i]);
- PDEBUG("\n");
- }
- else{
- MSG2("Begin Read from Device [%02x] Address [%02x]\n",
- dev->addr, dev->subaddr);
- MSG("Buffer : \n");
- for(i = 0; i < dev->subaddr_len +2; i++)
- PDEBUG("%02x ", dev->buffer[i]);
- PDEBUG("\n");
- }
-#endif
-
- return 0;
-}
-
-/* init i2c_dev after open */
-static int i2c_ResetI2C(i2c_dev *dev)
-{
- u32 reg;
-
- // configure i2c pin
- reg = inl(REG_GPIO_CFG5);
- reg &= 0x3ff00fff;
- reg |= 0x00055000;
- outl(reg, REG_GPIO_CFG5);
-
- dev->addr = -1;
- dev->last_error = 0;
- dev->subaddr = 0;
- dev->subaddr_len = 0;
-
- init_waitqueue_head(&dev->wq);
-
- return i2c_SetSpeed(dev, 100);
-
-}
-
-void i2c_interrupt(int irq, void *data, struct pt_regs *reg)
-{
- i2c_dev *dev = (i2c_dev *)data;
- int csr, val;
-
- csr = i2c_inl(dev, CSR);
-
- //MSG2("INT : CSR : [%02x] dev->pos = [%02x]\n", csr, dev->pos);
-
- csr |= 0x04;
-
- i2c_outl(dev, csr, CSR);
-
- if(dev->state == I2C_STATE_NOP)
- return;
-
- MSG2("bNackValid = %d\n", bNackValid);
-
- if((csr & 0x800) && bNackValid){ /* NACK only valid in WRITE */
- MSG("NACK Error\n");
- dev->last_error = I2C_ERR_NACK;
- i2c_Command(dev, I2C_CMD_STOP);
- goto wake_up_quit;
- }
- else if(csr & 0x200){ /* Arbitration lost */
- MSG("Arbitration lost\n");
- dev->last_error = I2C_ERR_LOSTARBITRATION;
- i2c_Command(dev, I2C_CMD_STOP);
- goto wake_up_quit;
- }
- else if(!(csr & 0x100)){ /* transmit complete */
- if(dev->pos < dev->subaddr_len + 1){ /* send address state */
- MSG("Send Address\n");
- val = dev->buffer[dev->pos++] & 0xff;
- i2c_outl(dev, val, TXR);
- i2c_Command(dev, I2C_CMD_WRITE);
- }
- else if(dev->state == I2C_STATE_READ){
-
- /* sub address send over , begin restart a read command */
-
- if(dev->pos == dev->subaddr_len + 1){
-
- MSG("Restart Reading...\n");
-
- val = dev->buffer[dev->pos++];
- i2c_outl(dev, val, TXR);
- i2c_Command(dev, I2C_CMD_START | I2C_CMD_WRITE);
- }
- else{
-
- dev->buffer[dev->pos++] = i2c_inl(dev, RXR) & 0xff;
-
- MSG2("Read Pos : [%02x] Data : [%02x]\n",
- dev->pos, dev->buffer[dev->pos-1]);
-
- if( dev->pos < dev->len){
- MSG("Read Next\n");
- if(dev->pos == dev->len -1 ) /* last character */
- i2c_Command(dev, I2C_CMD_READ |
- I2C_CMD_STOP |
- I2C_CMD_NACK);
- else
- i2c_Command(dev, I2C_CMD_READ);
- }
- else{
- MSG("Read Over \n");
- goto wake_up_quit;
- }
- }
- }
- else if(dev->state == I2C_STATE_WRITE){ /* write data */
-
- if( dev->pos < dev->len){
- MSG2("Write Pos : [%02x] Data : [%02x]\n",
- dev->pos, dev->buffer[dev->pos]);
-
- val = dev->buffer[dev->pos];
-
- i2c_outl(dev, val, TXR);
-
- if(dev->pos == dev->len -1 ) /* last character */
- i2c_Command(dev, I2C_CMD_WRITE| I2C_CMD_STOP);
- else
- i2c_Command(dev, I2C_CMD_WRITE);
-
- dev->pos ++;
- }
- else{
- MSG("Write Over\n");
- goto wake_up_quit;
- }
- }
- //else if(dev->state == I2C_STATE_PROBE){
- // MSG2("Probe Address : [%02x]\n", dev->addr);
- // goto wake_up_quit;
- //}
-
- }
-
- return;
-
-wake_up_quit:
-
- MSG("Wake up \n");
-
- dev->state = I2C_STATE_NOP;
- wake_up_interruptible(&dev->wq);
-
- return;
-}
-
-static int i2c_open(struct inode *inode, struct file *filp)
-{
- i2c_dev *dev;
-
- unsigned int num = MINOR(inode->i_rdev);
-
- if( num >= I2C_NUMBER) {
- printk("I2C : no dev\n");
- return -ENODEV;
- }
- dev = (i2c_dev *)kmalloc(sizeof(i2c_dev), GFP_KERNEL);
- if(dev == NULL) {
- printk("no mem\n");
- return -ENOMEM;
- }
- dev->no = num;
-
- if(request_irq(irq[num], i2c_interrupt, SA_INTERRUPT, "i2c", dev) < 0){
- printk("I2C : Request Irq error\n");
- kfree(dev);
- return -EIO;
- }
-
- if(i2c_ResetI2C(dev)){
- free_irq(irq[num], dev);
- kfree(dev);
- printk("eio\n");
- return -EIO;
- }
-
-
- MOD_INC_USE_COUNT;
-
- filp->private_data = dev;
-
- return 0;
-}
-
-static int i2c_release(struct inode *inode, struct file *flip)
-{
- i2c_dev *dev = flip->private_data;
-
- MSG2("Free IRQ %d\n", irq[dev->no]);
-
- free_irq(irq[dev->no], dev);
- kfree(dev);
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
-static int i2c_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
-{
- i2c_dev *dev = (i2c_dev *)filp->private_data;
-
- if(count == 0)
- return 0;
-
- if(!i2c_IsBusFree(dev))
- return -EBUSY;
-
- if(count > I2C_MAX_BUF_LEN - 10)
- count = I2C_MAX_BUF_LEN - 10;
-
- dev->state = I2C_STATE_READ;
- dev->pos = 1;
- dev->len = dev->subaddr_len + 1 + count + 2;/* plus 1 unused char */
- dev->last_error = 0;
-
- i2c_CalculateAddress(dev, I2C_STATE_READ);
-
- i2c_Enable(dev);
-
- i2c_outl(dev, dev->buffer[0] & 0xff, TXR);
-
- i2c_Command(dev, I2C_CMD_START | I2C_CMD_WRITE);
-
- wait_event_interruptible(dev->wq, dev->state == I2C_STATE_NOP);
-
- i2c_Disable(dev);
-
- if(dev->last_error)
- return -EIO;
-
- if(copy_to_user(buf, dev->buffer + dev->subaddr_len + 3, count))
- return -EFAULT;
-
- dev->subaddr += count;
-
- return count;
-}
-
-static int i2c_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
-{
- i2c_dev *dev = (i2c_dev *)filp->private_data;
-
-
- if(count == 0)
- return 0;
-
- if(!i2c_IsBusFree(dev))
- return -EBUSY;
-
-
- if(count > I2C_MAX_BUF_LEN - 10)
- count = I2C_MAX_BUF_LEN - 10;
-
- if(copy_from_user(dev->buffer + dev->subaddr_len + 1 , buf, count))
- return -EFAULT;
-
-
- dev->state = I2C_STATE_WRITE;
- dev->pos = 1;
- dev->len = dev->subaddr_len + 1 + count;
- dev->last_error = 0;
-
- i2c_CalculateAddress(dev, I2C_STATE_WRITE);
-
- i2c_Enable(dev);
-
- i2c_outl(dev, dev->buffer[0] & 0xff, TXR);
-
- i2c_Command(dev, I2C_CMD_START | I2C_CMD_WRITE);
-
- wait_event_interruptible(dev->wq, dev->state == I2C_STATE_NOP);
-
- i2c_Disable(dev);
-
- if(dev->last_error)
- return -EIO;
-
- dev->subaddr += count;
-
- return count;
-}
-
-static int i2c_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg)
-{
- int err = 0, tmp, retval = 0;
- struct sub_address sub_addr;
- i2c_dev *dev =(i2c_dev *)flip->private_data;
-
- if(_IOC_TYPE(cmd) != I2C_IOC_MAGIC) return -ENOTTY;
- if(_IOC_NR(cmd) > I2C_IOC_MAXNR) return -ENOTTY;
-
- if(_IOC_DIR(cmd) & _IOC_READ)
- err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
- else if(_IOC_DIR(cmd) & _IOC_WRITE)
- err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
-
- if(err)
- return -EFAULT;
-
- switch(cmd){
- case I2C_IOC_SET_DEV_ADDRESS:
- dev->addr = arg;
- MSG2("Address : %02x\n", arg&0xff);
- break;
-
- case I2C_IOC_SET_SPEED:
- if(i2c_SetSpeed(dev, arg))
- retval = -EPERM;
-
- break;
-
- case I2C_IOC_GET_LAST_ERROR:
- if(put_user(dev->last_error, (int *)arg)){
- retval = -EFAULT;
- break;
- }
-
- break;
-
- case I2C_IOC_SET_SUB_ADDRESS:
- if(copy_from_user(&sub_addr, (void *)arg, sizeof(sub_addr))){
- retval = -EFAULT;
- break;
- }
-
- if(sub_addr.sub_addr_len > 4){
- retval = -EPERM;
- break;
- }
-
- MSG2("Sub Address = %02x, length = %d\n",
- sub_addr.sub_addr, sub_addr.sub_addr_len);
-
- dev->subaddr = sub_addr.sub_addr;
- dev->subaddr_len = sub_addr.sub_addr_len;
-
- break;
-
- default:
- retval = -ENOTTY;
- break;
- }
-
- return retval;
-
-}
-
-
-struct file_operations i2c_fops =
-{
- owner: THIS_MODULE,
- open: i2c_open,
- release: i2c_release,
- ioctl: i2c_ioctl,
- read: i2c_read,
- write: i2c_write,
-};
-
-static void i2c_module_exit(void)
-{
- unregister_chrdev(I2C_MAJOR, "i2c");
-}
-
-static int __init i2c_module_init(void)
-{
- int i, retval;
-
- retval = register_chrdev(I2C_MAJOR, "i2c", &i2c_fops);
- if(retval < 0)
- goto failed;
-
- printk("I2C Bus Driver has been installed successfully.\n");
-
- return 0;
-
-failed:
-
- i2c_module_exit();
-
- printk("Init I2C Bus Driver failed!\n");
-
- return retval;
-}
-
-module_init(i2c_module_init);
-module_exit(i2c_module_exit);
-
+/**************************************************************************** + * + * Copyright (c) 2004 - 2006 Winbond Electronics Corp. All rights reserved. + * + ****************************************************************************/ + +/**************************************************************************** + * + * FILENAME + * w90n745_i2c.c + * + * VERSION + * 1.0 + * + * DESCRIPTION + * Winbond W90N710 I2C Driver + * + * DATA STRUCTURES + * None + * + * FUNCTIONS + * None + * + * HISTORY + * 2005/05/20 Ver 1.0 Created by PC34 QFu + * + * REMARK + * None + *************************************************************************/ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/semaphore.h> + +#include "w90n745_i2c.h" + + +//#define I2C_DEBUG +//#define I2C_DEBUG_PRINT_LINE +//#define I2C_DEBUG_ENABLE_ENTER_LEAVE +//#define I2C_DEBUG_ENABLE_MSG +//#define I2C_DEBUG_ENABLE_MSG2 + +#ifdef I2C_DEBUG +#define PDEBUG(fmt, arg...) printk(fmt, ##arg) +#else +#define PDEBUG(fmt, arg...) +#endif + +#ifdef I2C_DEBUG_PRINT_LINE +#define PRN_LINE() PDEBUG("[%-20s] : %d\n", __FUNCTION__, __LINE__) +#else +#define PRN_LINE() +#endif + +#ifdef I2C_DEBUG_ENABLE_ENTER_LEAVE +#define ENTER() PDEBUG("[%-20s] : Enter...\n", __FUNCTION__) +#define LEAVE() PDEBUG("[%-20s] : Leave...\n", __FUNCTION__) +#else +#define ENTER() +#define LEAVE() +#endif + +#ifdef I2C_DEBUG_ENABLE_MSG +#define MSG(msg) PDEBUG("[%-20s] : %s", __FUNCTION__, msg) +#else +#define MSG(msg) +#endif + +#ifdef I2C_DEBUG_ENABLE_MSG2 +#define MSG2(fmt, arg...) PDEBUG("[%-20s] : "fmt, __FUNCTION__, ##arg) +#define PRNBUF(buf, count) {int i;MSG2("CID Data: ");for(i=0;i<count;i++)\ + PDEBUG("%02x ", buf[i]);PDEBUG("\n");} +#else +#define MSG2(fmt, arg...) +#define PRNBUF(buf, count) +#endif + + + +#define i2c_outl(dev, dword, addr) outl(dword, base[dev->no] + addr) +#define i2c_inl(dev, addr) inl(base[dev->no] + addr) + + +static const int base[I2C_NUMBER] = {I2C0_IO_BASE, I2C1_IO_BASE}; +static const int irq[I2C_NUMBER] = {I2C0_IRQ, I2C1_IRQ}; +static int bNackValid; + +static void i2c_Disable(i2c_dev *dev) /* Disable i2c core and interrupt */ +{ + + i2c_outl(dev, 0x00, CSR); +} + +static void i2c_Enable(i2c_dev *dev) /* Enable i2c core and interrupt */ +{ + i2c_outl(dev, 0x03, CSR); +} + +static int i2c_SetSpeed(i2c_dev *dev, int sp) +{ + unsigned int d; + + if( sp != 100 && sp != 400) + return -1; + + d = I2C_INPUT_CLOCK/(sp * 5) -1; + + i2c_outl(dev, d & 0xffff, DIVIDER); + + MSG2("Set Speed = %d\n", sp); + + return 0; +} + +static int i2c_IsBusFree(i2c_dev *dev) +{ + if( (i2c_inl(dev, SWR) & 0x18) == 0x18 && //SDR and SCR keep high + (i2c_inl(dev, CSR) & 0x0400) == 0 ){ //I2C_BUSY is false + //MSG("Bus Free\n"); + + return 1; + } + else{ + //MSG("Bus Busy\n"); + + return 0; + } + +} + +static int i2c_Command(i2c_dev *dev, int cmd) +{ + +#if 0 + printk("CMD : "); + + if(cmd & I2C_CMD_START){ + printk("START "); + } + + if (cmd & I2C_CMD_STOP){ + printk("STOP "); + + } + + if(cmd & I2C_CMD_NACK){ + printk("NACK "); + } + + if(cmd & I2C_CMD_WRITE){ + printk("WRITE : [%02x]", i2c_inl(dev, TXR) & 0xff); + } + + if(cmd & I2C_CMD_READ){ + printk("READ : [%02x]", i2c_inl(dev, RXR) & 0xff); + } + + printk("\n"); + +#endif + + if(cmd & I2C_CMD_WRITE) + bNackValid = 1; + else + bNackValid = 0; + + i2c_outl(dev, cmd, CMDR); + + return 0; + +} + + +static int i2c_CalculateAddress(i2c_dev *dev, int mode) +{ + int i; + unsigned int addr; + unsigned int subaddr; + + subaddr = dev->subaddr; + addr = dev->addr; + + addr = ((addr << 1) & 0xfe) | I2C_WRITE; + + dev->buffer[0] = addr & 0xff; + + for(i = dev->subaddr_len; i > 0; i--){ + dev->buffer[i] = subaddr & 0xff; + subaddr >>= 8; + } + + if(mode == I2C_STATE_READ){ + i = dev->subaddr_len + 1; + dev->buffer[i] = (addr & 0xfe) | I2C_READ; + } + +#ifdef I2C_DEBUG + if(mode == I2C_STATE_WRITE){ + MSG2("Begin Write to Device [%02x] Address [%02x]\n", + dev->addr, dev->subaddr); + MSG("Buffer : \n"); + for(i = 0; i < dev->subaddr_len +1; i++) + PDEBUG("%02x ", dev->buffer[i]); + PDEBUG("\n"); + } + else{ + MSG2("Begin Read from Device [%02x] Address [%02x]\n", + dev->addr, dev->subaddr); + MSG("Buffer : \n"); + for(i = 0; i < dev->subaddr_len +2; i++) + PDEBUG("%02x ", dev->buffer[i]); + PDEBUG("\n"); + } +#endif + + return 0; +} + +/* init i2c_dev after open */ +static int i2c_ResetI2C(i2c_dev *dev) +{ + u32 reg; + + // configure i2c pin + reg = inl(REG_GPIO_CFG5); + reg &= 0x3ff00fff; + reg |= 0x00055000; + outl(reg, REG_GPIO_CFG5); + + dev->addr = -1; + dev->last_error = 0; + dev->subaddr = 0; + dev->subaddr_len = 0; + + init_waitqueue_head(&dev->wq); + + return i2c_SetSpeed(dev, 100); + +} + +void i2c_interrupt(int irq, void *data, struct pt_regs *reg) +{ + i2c_dev *dev = (i2c_dev *)data; + int csr, val; + + csr = i2c_inl(dev, CSR); + + //MSG2("INT : CSR : [%02x] dev->pos = [%02x]\n", csr, dev->pos); + + csr |= 0x04; + + i2c_outl(dev, csr, CSR); + + if(dev->state == I2C_STATE_NOP) + return; + + MSG2("bNackValid = %d\n", bNackValid); + + if((csr & 0x800) && bNackValid){ /* NACK only valid in WRITE */ + MSG("NACK Error\n"); + dev->last_error = I2C_ERR_NACK; + i2c_Command(dev, I2C_CMD_STOP); + goto wake_up_quit; + } + else if(csr & 0x200){ /* Arbitration lost */ + MSG("Arbitration lost\n"); + dev->last_error = I2C_ERR_LOSTARBITRATION; + i2c_Command(dev, I2C_CMD_STOP); + goto wake_up_quit; + } + else if(!(csr & 0x100)){ /* transmit complete */ + if(dev->pos < dev->subaddr_len + 1){ /* send address state */ + MSG("Send Address\n"); + val = dev->buffer[dev->pos++] & 0xff; + i2c_outl(dev, val, TXR); + i2c_Command(dev, I2C_CMD_WRITE); + } + else if(dev->state == I2C_STATE_READ){ + + /* sub address send over , begin restart a read command */ + + if(dev->pos == dev->subaddr_len + 1){ + + MSG("Restart Reading...\n"); + + val = dev->buffer[dev->pos++]; + i2c_outl(dev, val, TXR); + i2c_Command(dev, I2C_CMD_START | I2C_CMD_WRITE); + } + else{ + + dev->buffer[dev->pos++] = i2c_inl(dev, RXR) & 0xff; + + MSG2("Read Pos : [%02x] Data : [%02x]\n", + dev->pos, dev->buffer[dev->pos-1]); + + if( dev->pos < dev->len){ + MSG("Read Next\n"); + if(dev->pos == dev->len -1 ) /* last character */ + i2c_Command(dev, I2C_CMD_READ | + I2C_CMD_STOP | + I2C_CMD_NACK); + else + i2c_Command(dev, I2C_CMD_READ); + } + else{ + MSG("Read Over \n"); + goto wake_up_quit; + } + } + } + else if(dev->state == I2C_STATE_WRITE){ /* write data */ + + if( dev->pos < dev->len){ + MSG2("Write Pos : [%02x] Data : [%02x]\n", + dev->pos, dev->buffer[dev->pos]); + + val = dev->buffer[dev->pos]; + + i2c_outl(dev, val, TXR); + + if(dev->pos == dev->len -1 ) /* last character */ + i2c_Command(dev, I2C_CMD_WRITE| I2C_CMD_STOP); + else + i2c_Command(dev, I2C_CMD_WRITE); + + dev->pos ++; + } + else{ + MSG("Write Over\n"); + goto wake_up_quit; + } + } + //else if(dev->state == I2C_STATE_PROBE){ + // MSG2("Probe Address : [%02x]\n", dev->addr); + // goto wake_up_quit; + //} + + } + + return; + +wake_up_quit: + + MSG("Wake up \n"); + + dev->state = I2C_STATE_NOP; + wake_up_interruptible(&dev->wq); + + return; +} + +static int i2c_open(struct inode *inode, struct file *filp) +{ + i2c_dev *dev; + + unsigned int num = MINOR(inode->i_rdev); + + if( num >= I2C_NUMBER) { + printk("I2C : no dev\n"); + return -ENODEV; + } + dev = (i2c_dev *)kmalloc(sizeof(i2c_dev), GFP_KERNEL); + if(dev == NULL) { + printk("no mem\n"); + return -ENOMEM; + } + dev->no = num; + + if(request_irq(irq[num], i2c_interrupt, SA_INTERRUPT, "i2c", dev) < 0){ + printk("I2C : Request Irq error\n"); + kfree(dev); + return -EIO; + } + + if(i2c_ResetI2C(dev)){ + free_irq(irq[num], dev); + kfree(dev); + printk("eio\n"); + return -EIO; + } + + + MOD_INC_USE_COUNT; + + filp->private_data = dev; + + return 0; +} + +static int i2c_release(struct inode *inode, struct file *flip) +{ + i2c_dev *dev = flip->private_data; + + MSG2("Free IRQ %d\n", irq[dev->no]); + + free_irq(irq[dev->no], dev); + kfree(dev); + MOD_DEC_USE_COUNT; + + return 0; +} + +static int i2c_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + i2c_dev *dev = (i2c_dev *)filp->private_data; + + if(count == 0) + return 0; + + if(!i2c_IsBusFree(dev)) + return -EBUSY; + + if(count > I2C_MAX_BUF_LEN - 10) + count = I2C_MAX_BUF_LEN - 10; + + dev->state = I2C_STATE_READ; + dev->pos = 1; + dev->len = dev->subaddr_len + 1 + count + 2;/* plus 1 unused char */ + dev->last_error = 0; + + i2c_CalculateAddress(dev, I2C_STATE_READ); + + i2c_Enable(dev); + + i2c_outl(dev, dev->buffer[0] & 0xff, TXR); + + i2c_Command(dev, I2C_CMD_START | I2C_CMD_WRITE); + + wait_event_interruptible(dev->wq, dev->state == I2C_STATE_NOP); + + i2c_Disable(dev); + + if(dev->last_error) + return -EIO; + + if(copy_to_user(buf, dev->buffer + dev->subaddr_len + 3, count)) + return -EFAULT; + + dev->subaddr += count; + + return count; +} + +static int i2c_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + i2c_dev *dev = (i2c_dev *)filp->private_data; + + + if(count == 0) + return 0; + + if(!i2c_IsBusFree(dev)) + return -EBUSY; + + + if(count > I2C_MAX_BUF_LEN - 10) + count = I2C_MAX_BUF_LEN - 10; + + if(copy_from_user(dev->buffer + dev->subaddr_len + 1 , buf, count)) + return -EFAULT; + + + dev->state = I2C_STATE_WRITE; + dev->pos = 1; + dev->len = dev->subaddr_len + 1 + count; + dev->last_error = 0; + + i2c_CalculateAddress(dev, I2C_STATE_WRITE); + + i2c_Enable(dev); + + i2c_outl(dev, dev->buffer[0] & 0xff, TXR); + + i2c_Command(dev, I2C_CMD_START | I2C_CMD_WRITE); + + wait_event_interruptible(dev->wq, dev->state == I2C_STATE_NOP); + + i2c_Disable(dev); + + if(dev->last_error) + return -EIO; + + dev->subaddr += count; + + return count; +} + +static int i2c_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg) +{ + int err = 0, tmp, retval = 0; + struct sub_address sub_addr; + i2c_dev *dev =(i2c_dev *)flip->private_data; + + if(_IOC_TYPE(cmd) != I2C_IOC_MAGIC) return -ENOTTY; + if(_IOC_NR(cmd) > I2C_IOC_MAXNR) return -ENOTTY; + + if(_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); + else if(_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); + + if(err) + return -EFAULT; + + switch(cmd){ + case I2C_IOC_SET_DEV_ADDRESS: + dev->addr = arg; + MSG2("Address : %02x\n", arg&0xff); + break; + + case I2C_IOC_SET_SPEED: + if(i2c_SetSpeed(dev, arg)) + retval = -EPERM; + + break; + + case I2C_IOC_GET_LAST_ERROR: + if(put_user(dev->last_error, (int *)arg)){ + retval = -EFAULT; + break; + } + + break; + + case I2C_IOC_SET_SUB_ADDRESS: + if(copy_from_user(&sub_addr, (void *)arg, sizeof(sub_addr))){ + retval = -EFAULT; + break; + } + + if(sub_addr.sub_addr_len > 4){ + retval = -EPERM; + break; + } + + MSG2("Sub Address = %02x, length = %d\n", + sub_addr.sub_addr, sub_addr.sub_addr_len); + + dev->subaddr = sub_addr.sub_addr; + dev->subaddr_len = sub_addr.sub_addr_len; + + break; + + default: + retval = -ENOTTY; + break; + } + + return retval; + +} + + +struct file_operations i2c_fops = +{ + owner: THIS_MODULE, + open: i2c_open, + release: i2c_release, + ioctl: i2c_ioctl, + read: i2c_read, + write: i2c_write, +}; + +static void i2c_module_exit(void) +{ + unregister_chrdev(I2C_MAJOR, "i2c"); +} + +static int __init i2c_module_init(void) +{ + int i, retval; + + retval = register_chrdev(I2C_MAJOR, "i2c", &i2c_fops); + if(retval < 0) + goto failed; + + printk("I2C Bus Driver has been installed successfully.\n"); + + return 0; + +failed: + + i2c_module_exit(); + + printk("Init I2C Bus Driver failed!\n"); + + return retval; +} + +module_init(i2c_module_init); +module_exit(i2c_module_exit); + |