/* MPC8xx CPM I2C interface. Copyright (c) 1999 Dan Malek (dmalek@jlc.net). * This driver only support I2C master mode. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "commproc.h" /* Print debug messages */ #define DEBUG /* This is the I2C device number. */ #define CPM_I2C_CDEV_MAJOR 89 /* Defines to make I2C clock run at 100kHz (101kHz) @ 50MHz CPU clock */ #define I2BRG_100KHZ 0x1A #define I2MOD_100KHZ 0x0C /* Defines to make I2C clock run at 400kHz (391kHz) @ 50MHz CPU clock */ #define I2BRG_400KHZ 0x0B #define I2MOD_400KHZ 0x0E /* Maximum number of bytes we can xmit/receive at once (hardware). */ #define MAX_I2C_DATALEN 128 void cpm_iic_init(void); static int cpm_iic_open(struct inode *, struct file *); static int cpm_iic_close(struct inode *, struct file *); static ssize_t cpm_iic_read(struct file *, char *, size_t, loff_t *); static ssize_t cpm_iic_write(struct file *, const char *, size_t, loff_t *); static int cpm_iic_ioctl(struct inode *, struct file *, uint, ulong); static void cpm_iic_interrupt(void *); static struct file_operations cpm_iic_fops = { NULL, /* lseek */ cpm_iic_read, /* read */ cpm_iic_write, /* write */ NULL, /* readdir */ NULL, /* select */ cpm_iic_ioctl, /* ioctl */ NULL, /* mmap */ cpm_iic_open, /* open */ cpm_iic_close, /* close */ NULL /* fsync */ }; /* File pointer specific setup */ typedef struct i2c_setup_struct_def { u_char device_address; /* The device we want to talk to */ u_char internal_address_len; /* The length of internal address */ uint clock_freq; /* The i2c clock frequency */ } i2c_setup_struct; /* Mutex used to make sure only one uses the i2c bus at time. */ struct semaphore bus_busy_mutex = MUTEX; /* Wait queue used while waiting for interrupt */ static struct wait_queue *i2c_interrupt_wait; volatile i2c8xx_t *i2c; volatile cbd_t *tbdf, *rbdf; /*************************************************************************** * Setup the interface for r/w. * * @param reloc Returns relocation offset for microcode. 0 = original. * If pass in NULL, nothing returned. * @param cp Pointer to the communications processor address space. * @param init TRUE to force init of the registers for startup. If * FALSE, may init but depends on patching of ucode. * @return Pointer to memory space for control registers. ***************************************************************************/ volatile iic_t *setupChip(int* reloc,volatile cpm8xx_t *cp, int init) { volatile iic_t *iip; // Parameter ram section for i2c int r; // Relocation. /* Load up base pointers. Note that cpmp is set in kernal initialization. */ iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; /* Check for and use a microcode relocation patch. If so, we also move the location of the parameters. */ if (reloc = iip->iic_rpbase) { printk("Microcode relocation patch used\n"); ipp = (iic_t *)&cp->cp_dpmem[reloc] } return iip; } void cpm_iic_init() { uint mem_addr, dp_addr; volatile cpm8xx_t *cp; volatile iic_t *iip; volatile immap_t *immap; int* reloc; /* print version string */ printk("CPM I2C driver version 1.0 %s\n", __DATE__); /* Get pointer to Communication Processor * and to internal registers */ cp = cpmp; immap = (immap_t *)IMAP_ADDR; iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; i2c = (i2c8xx_t *)&(immap->im_i2c); /* Initialize Port B I2C pins. */ cp->cp_pbpar |= 0x00000030; cp->cp_pbdir |= 0x00000030; cp->cp_pbodr |= 0x00000030; /* Disable interrupts. */ i2c->i2c_i2cmr = 0; i2c->i2c_i2cer = 0xff; /* Set I2C controller in master mode */ i2c->i2c_i2com = 0x01; /* Allocate space for two transmit and one receive buffer * descriptor in the DP ram. */ dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 3); /* Allocate space for two transmit and one receive buffer in the host memory. * The most you can read or write at once from I2C is 128 bytes. */ mem_addr = m8xx_cpm_hostalloc(128 * 3); /* Load up base pointers. */ iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; /* Check for and use a microcode relocation patch. If so, we also move the location of the parameters. */ if (reloc = iip->iic_rpbase) { printk("Microcode relocation patch used\n"); ipp = (iic_t *)&cp->cp_dpmem[reloc] } /* Set up the I2C parameters in the parameter ram. */ iip->iic_rbase = dp_addr; iip->iic_tbase = dp_addr + sizeof(cbd_t); /* Set the buffer address. */ rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; rbdf[0].cbd_bufaddr = __pa(mem_addr); tbdf[0].cbd_bufaddr = __pa(mem_addr+128); tbdf[1].cbd_bufaddr = __pa(mem_addr+256); if(!relocated) { /* Initialize Tx/Rx parameters. */ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); } else { /* * Initialize required parameters if using microcode patch * * NOTE: These are the parameters required as stated in the * Relocation spec which can be found at * http://www.mot.com/SPS/ADC/pps/subpgs/etoolbox/8XX/i2c_spi.html */ iip->iic_rbptr = iip->iic_rbase; iip->iic_tbptr = iip->iic_tbase; iip->iic_rstate = 0; iip->iic_tstate = 0; } /* Set byte order to big endian. Also, setup address type to 5.*/ iip->iic_tfcr = SMC_EB; iip->iic_rfcr = SMC_EB; /* Set maximum receive size. */ iip->iic_mrblr = MAX_I2C_DATALEN; /* Install interrupt handler. */ cpm_install_handler(CPMVEC_I2C, cpm_iic_interrupt, (void *)iip); /* Register the I2C driver */ if(register_chrdev(CPM_I2C_CDEV_MAJOR,"i2c",&cpm_iic_fops)) { printk("unable to get major %d for I2C devs\n", CPM_I2C_CDEV_MAJOR); } printk("IIC Drivers Loaded (Major %d)!\n", CPM_I2C_CDEV_MAJOR); } static int cpm_iic_open(struct inode *ip, struct file *fp) { i2c_setup_struct *i2c_setup; printk("Opening iic device\n"); /* Check minor number. */ if( MINOR(ip->i_rdev) > 0) return -ENODEV; /* Alloc some memory for I2C setup struct */ fp->private_data = kmalloc(sizeof(i2c_setup_struct), GFP_KERNEL); i2c_setup = (i2c_setup_struct *)(fp->private_data); if(!i2c_setup) return -ENOMEM; /* Set device address and internal address length to 0 * and i2c clock freq. to 100kHz */ i2c_setup->device_address = 0; i2c_setup->internal_address_len = 0; i2c_setup->clock_freq = 100000; /* Set pointer to file operations struct */ fp->f_op = &cpm_iic_fops; return 0; } static int cpm_iic_close(struct inode *ip, struct file *fp) { /* Free space used by i2c setup struct */ kfree(fp->private_data); return 0; } /* Read from I2C. * This is a two step process if internal addresses is used. First, we send * the "dummy" write to set the internal address for the read. Second, we * perform the read operation. */ static ssize_t cpm_iic_read(struct file *fp, char *buf, size_t count, loff_t *ppos) { i2c_setup_struct *i2c_setup; loff_t offset; u_char *tb, *tb2, *rb, len, tmp_off[4]; /* Get pointer to i2c setup data */ i2c_setup = (i2c_setup_struct *)(fp->private_data); /* Get pointer to transmit and receive buffer */ tb = __va(tbdf[0].cbd_bufaddr); tb2 = __va(tbdf[1].cbd_bufaddr); rb = __va(rbdf[0].cbd_bufaddr); /* Get file offset (internal address) */ offset = *ppos; tmp_off[0] = (char)(offset >> 24); tmp_off[1] = (char)((offset >> 16) % 0x100); tmp_off[2] = (char)((offset >> 8) % 0x100); tmp_off[3] = (char)(offset % 0x100); /* Enter critical section */ down(&bus_busy_mutex); if (signal_pending(current)) { up(&bus_busy_mutex); return -ERESTARTSYS; } if(i2c_setup->internal_address_len) /* Use internal address */ { *tb = i2c_setup->device_address & 0xfe; /* Device address, write request */ tbdf[0].cbd_datlen = i2c_setup->internal_address_len + 1 ; /* Length */ /* copy offset into transmit buffer */ for(len=0; len < i2c_setup->internal_address_len; len++) tb[1+len] = tmp_off[(4 - i2c_setup->internal_address_len) + len]; *tb2 = i2c_setup->device_address | 0x01; /* Device address, read request */ tbdf[1].cbd_datlen = count + 1; /* Length */ tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START; tbdf[1].cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; } else /* No internal address */ { *tb = i2c_setup->device_address | 0x01; /* Device address, read request */ tbdf[0].cbd_datlen = count + 1; /* Length */ tbdf[0].cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; } rbdf[0].cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP; i2c->i2c_i2cmr = 0x15; /* Enable receive interrupt */ i2c->i2c_i2cer = 0xff; /* Clear event register */ if(i2c_setup->clock_freq == 400000) /* Make clock run at 400kHz */ { i2c->i2c_i2brg = I2BRG_400KHZ; i2c->i2c_i2mod = I2MOD_400KHZ; } else /* Make clock run at 100kHz */ { i2c->i2c_i2brg = I2BRG_100KHZ; i2c->i2c_i2mod = I2MOD_100KHZ; } i2c->i2c_i2mod |= 0x01; /* Chip errata, set enable here */ i2c->i2c_i2com |= 0x80; /* Start transmit */ /* Wait for I2C receive interrupt or time out (1 second). */ if(interruptible_sleep_on_timeout(&i2c_interrupt_wait, 1*HZ)<=0) { #ifdef DEBUG printk("I2C read: Time out!\n"); #endif } i2c->i2c_i2mod &= ~0x01; /* Chip errata, clear enable */ if(signal_pending(current)) { up(&bus_busy_mutex); return -ERESTARTSYS; } /* check for errors in first tx buffer */ if(tbdf[0].cbd_sc & (BD_SC_READY | BD_SC_NAK | BD_SC_UN | BD_SC_CL)) { #ifdef DEBUG switch(tbdf[0].cbd_sc & (BD_SC_READY | BD_SC_NAK | BD_SC_UN | BD_SC_CL)) { case BD_SC_READY: printk("I2C read complete but tx_buf ready!\n"); break; case BD_SC_NAK: printk("I2C read: no acknowledge!\n"); break; case BD_SC_UN: printk("I2C read: underrun!\n"); break; case BD_SC_CL: printk("I2C read: collision!\n"); break; } #endif up(&bus_busy_mutex); return -EFAULT; } if(i2c_setup->internal_address_len) { /* check for errors in second tx buffer */ if(tbdf[1].cbd_sc & (BD_SC_READY | BD_SC_NAK | BD_SC_UN | BD_SC_CL)) { #ifdef DEBUG switch(tbdf[1].cbd_sc & (BD_SC_READY | BD_SC_NAK | BD_SC_UN | BD_SC_CL)) { case BD_SC_READY: printk("I2C read complete but tx_buf ready!\n"); break; case BD_SC_NAK: printk("I2C read: no acknowledge!\n"); break; case BD_SC_UN: printk("I2C read: underrun!\n"); break; case BD_SC_CL: printk("I2C read: collision!\n"); break; } #endif up(&bus_busy_mutex); return -EFAULT; } } /* check for errors in rx buffer */ if (rbdf[0].cbd_sc & BD_SC_EMPTY) { up(&bus_busy_mutex); #ifdef DEBUG printk("I2C read complete but rx_buf empty!"); #endif return -EFAULT; } if (copy_to_user(buf, rb, count)) { up(&bus_busy_mutex); return -EFAULT; } /* Leave critical section */ up(&bus_busy_mutex); *ppos += count; return count; } /* I2C write funktion. */ static ssize_t cpm_iic_write(struct file *fp, const char *buf, size_t count, loff_t *ppos) { i2c_setup_struct *i2c_setup; loff_t offset; u_char *tb, len, tmp_off[4]; /* Get pointer to i2c setup data */ i2c_setup = (i2c_setup_struct *)(fp->private_data); /* Get file offset (internal address) */ offset = *ppos; tmp_off[0] = (char)(offset >> 24); tmp_off[1] = (char)((offset >> 16) % 0x100); tmp_off[2] = (char)((offset >> 8) % 0x100); tmp_off[3] = (char)(offset % 0x100); /* Enter critical section */ down(&bus_busy_mutex); if(signal_pending(current)) { up(&bus_busy_mutex); return -ERESTARTSYS; } /* Get pointer to transmit buffer */ tb = __va(tbdf[0].cbd_bufaddr); *tb = i2c_setup->device_address & 0xfe; /* Set device address, write request */ if(i2c_setup->internal_address_len) /* Use internal address */ { /* copy offset into transmit buffer */ for(len=0; len < i2c_setup->internal_address_len; len++) tb[1+len] = tmp_off[(4 - i2c_setup->internal_address_len) + len]; } /* copy data into transmit buffer */ if(copy_from_user(tb+i2c_setup->internal_address_len+1, buf, count)) { up(&bus_busy_mutex); return -EFAULT; } tbdf[0].cbd_datlen = count + i2c_setup->internal_address_len + 1; /* Data length */ tbdf[0].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; i2c->i2c_i2cmr = 0x16; /* Enable transmit interrupt */ i2c->i2c_i2cer = 0xff; /* Clear event register */ if(i2c_setup->clock_freq == 400000) /* Make clock run at 400kHz */ { i2c->i2c_i2brg = I2BRG_400KHZ; i2c->i2c_i2mod = I2MOD_400KHZ; } else /* Make clock run at 100kHz */ { i2c->i2c_i2brg = I2BRG_100KHZ; i2c->i2c_i2mod = I2MOD_100KHZ; } i2c->i2c_i2mod |= 0x01; /* Chip errata, set enable here */ i2c->i2c_i2com |= 0x80; /* Start transmit */ /* Wait for I2C transmit interrupt or time out (1 second). */ if(interruptible_sleep_on_timeout(&i2c_interrupt_wait, 1*HZ)<=0) { #ifdef DEBUG printk("I2C write: Time out!\n"); #endif } i2c->i2c_i2mod &= ~0x01; /* Chip errata, clear enable */ if (signal_pending(current)) { up(&bus_busy_mutex); return -ERESTARTSYS; } /* check for errors in tx buffer */ if(tbdf[0].cbd_sc & (BD_SC_READY | BD_SC_NAK | BD_SC_UN | BD_SC_CL)) { #ifdef DEBUG switch(tbdf[0].cbd_sc & (BD_SC_READY | BD_SC_NAK | BD_SC_UN | BD_SC_CL)) { case BD_SC_READY: printk("I2C write complete but tx_buf ready!\n"); break; case BD_SC_NAK: printk("I2C write: no acknowledge!\n"); break; case BD_SC_UN: printk("I2C write: underrun!\n"); break; case BD_SC_CL: printk("I2C write: collision!\n"); break; } #endif up(&bus_busy_mutex); return -EFAULT; } /* Leave critical section */ up(&bus_busy_mutex); *ppos += count; return count; } static int cpm_iic_ioctl(struct inode *ip, struct file *fp, u_int cmd, ulong arg) { int retval = 0; i2c_setup_struct *i2c_setup; i2c_setup = (i2c_setup_struct *)(fp->private_data); switch(cmd) { /* Set device address. */ case 1: i2c_setup->device_address = (u_char)arg & 0xfe; /* Set device address, ignore LSB */ break; /* Set internal address length. */ case 2: if((u_char)arg > 4) retval = -EINVAL; else i2c_setup->internal_address_len = (u_char)arg; break; /* Set the bus clock frequency. */ case 3: if(((uint)arg != 100000) && ((uint)arg != 400000)) retval = -EINVAL; else i2c_setup->clock_freq = (uint)arg; break; default: retval = -ENOIOCTLCMD; } return retval; } static void cpm_iic_interrupt(void *dev_id) { /* Clear interrupt. */ i2c->i2c_i2cer = 0xff; /* Wake up process in wait queue */ wake_up_interruptible(&i2c_interrupt_wait); }