/* * * i2c-avalanche.c * Description: * IIC driver for TI IIC adaptors implementation * * Copyright (C) 2008 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** \file i2c-avalanche.c \brief IIC driver for TI IIC adaptors FOR DOCUMENTATION OF FUNCTIONS: Refer file i2c-avalanche.h \author PSP TII \version 0.1 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "i2c-avalanche.h" #include "../algos/i2c-algo-avalanche.h" #if defined(CONFIG_I2C_DEBUG_BUS) #define DEBUG_IIC_BUS(fmt,arg...) printk(fmt , ##arg) #else #define DEBUG_IIC_BUS(fmt,arg...) #endif /* global defines */ extern unsigned int avalanche_get_vbus_freq(void); static int clock = CONFIG_I2C_AVALANCHE_CLOCK; static int polling_mode = CONFIG_I2C_AVALANCHE_FORCE_POLLED_MODE; static int spike_filter = CONFIG_I2C_AVALANCHE_SPIKE_FILTER; static unsigned int iic_base = AVALANCHE_IIC_REGS_BASE; static struct iic_avalanche iic_avalanche_priv_data = { AVALANCHE_IIC_REGS_BASE, /* Base address */ LNXINTNUM(AVALANCHE_I2C_INT), /* Interrupt*/ 0, /* Our address on the i2c bus */ CONFIG_I2C_AVALANCHE_FORCE_POLLED_MODE, CONFIG_I2C_AVALANCHE_CLOCK, CONFIG_I2C_AVALANCHE_SPIKE_FILTER, NULL, 0, 0, }; static void iic_avalanche_setiic( unsigned long reg_addr,unsigned int val ) { *(volatile unsigned long *)reg_addr = val; } static unsigned int iic_avalanche_getiic( unsigned long reg_addr ) { volatile unsigned int val = 0; val = *(volatile unsigned long *)reg_addr; return( val ); } static int iic_avalanche_getown(void *data ) { struct iic_avalanche *avalanche_priv_data =(struct iic_avalanche *)data; return( avalanche_priv_data->iic_own ); } static int iic_avalanche_getclock(void *data ) { struct iic_avalanche *avalanche_priv_data = (struct iic_avalanche *)data; return( avalanche_priv_data->clock); } static inline int iic_avalanche_cmd_complete(void) { volatile unsigned int status; status = iic_avalanche_getiic((unsigned long ) (iic_avalanche_priv_data.iic_base + 0xc )); return !(status & 0x4000); } static irqreturn_t iic_avalanche_handler( int this_irq, void *dev_id) { if (iic_avalanche_cmd_complete()) wake_up_interruptible(&iic_avalanche_priv_data.iic_wait); return IRQ_HANDLED; } static void iic_avalanche_waitforpin( void *data ) { long timeout = 0; /* If interrupts are enabled (which they are), then put the process to * sleep. This process will be awakened by two events -- either the * the I2C peripheral interrupts or the timeout expires. (timeout is set to 50msec) */ timeout = wait_event_interruptible_timeout(iic_avalanche_priv_data.iic_wait, iic_avalanche_cmd_complete(), (5 * HZ) /100); if(timeout == 0) { DEBUG_IIC_BUS("No I2C interrupt for a long period (timeout \ = %d jiffies)\n", (int)timeout); } *(int*)data = (timeout)?0:(AVALANCHE_I2C_ERROR); } /* Request our interrupt line and register its associated handler. */ static int iic_hw_resrc_init(void) { unsigned long flags =0; if(! iic_avalanche_priv_data.polling_mode ) { if( iic_avalanche_priv_data.iic_irq > 0 ) { if( request_irq( iic_avalanche_priv_data.iic_irq, iic_avalanche_handler, flags, "TI IIC", NULL ) < 0 ) { printk(KERN_ERR "request_irq failed in iic_hw_resrc_init\n" ); return AVALANCHE_I2C_ERROR; } else { DEBUG_IIC_BUS("Enabled IIC IRQ %d\n", \ iic_avalanche_priv_data.iic_irq); } } } return 0; } void iic_avalanche_release(void) { if(!iic_avalanche_priv_data.polling_mode) { if( iic_avalanche_priv_data.iic_irq > 0 ) { free_irq( iic_avalanche_priv_data.iic_irq, 0 ); } } } static struct i2c_algo_iic_data iic_avalanche_data = { NULL, iic_avalanche_setiic, iic_avalanche_getiic, iic_avalanche_getown, iic_avalanche_getclock, iic_avalanche_waitforpin, 80, /* udelay waits */ 80, /* mdelay waits */ 100, /* timeout */ }; static struct i2c_adapter iic_avalanche_adapter = { .owner = THIS_MODULE, .id = I2C_HW_AVALANCHE_ID, .class = I2C_CLASS_ALL, .algo = NULL, .algo_data = &iic_avalanche_data, .name = "TI IIC adapter", }; /* Called when the module is loaded. This function starts the * cascade of calls up through the heirarchy of i2c modules * (i.e. up to the algorithm layer and into to the core layer) */ static int iic_avalanche_init( void ) { int ret = 0; printk(KERN_INFO "Initialize Avalanche IIC-over-VLYNQ adapter module\n"); iic_avalanche_priv_data.clock = clock; iic_avalanche_priv_data.polling_mode = polling_mode; iic_avalanche_priv_data.spike_filter = spike_filter; iic_avalanche_priv_data.iic_base = iic_base; DEBUG_IIC_BUS("values of the parameters is \n clock = %d\n polling_mode = %d\n spike_filter = %d\n iic_base = 0x%x\n", iic_avalanche_priv_data.clock, iic_avalanche_priv_data.polling_mode, iic_avalanche_priv_data.spike_filter,(unsigned int)iic_avalanche_priv_data.iic_base ); /* Valodate mode of the Driver */ if( iic_avalanche_priv_data. polling_mode != 0 && iic_avalanche_priv_data.polling_mode != 1 ) { printk(KERN_ERR "Invalid mode defaulting to Interrupt mode\n"); iic_avalanche_priv_data.polling_mode = 0; } /* Validate clock frequency */ if( iic_avalanche_priv_data.clock < AVALANCHE_I2C_MIN_CLOCK || iic_avalanche_priv_data.clock > AVALANCHE_I2C_MAX_CLOCK ) { printk(KERN_ERR "Invalid clock defaulting to 400KHz\n"); iic_avalanche_priv_data.clock = AVALANCHE_I2C_MAX_CLOCK; } /* Validate spike_filter */ if( iic_avalanche_priv_data.spike_filter < 0 || iic_avalanche_priv_data.spike_filter > 7 ) { printk(KERN_ERR "Invalid spike filter defaulting to 0\n"); iic_avalanche_priv_data.spike_filter = 0; } init_waitqueue_head(&iic_avalanche_priv_data.iic_wait); /*initilise the data lock */ mutex_init(&(iic_avalanche_priv_data.avalanche_i2c_lock)); iic_avalanche_data.data = (void *)&iic_avalanche_priv_data; if( iic_hw_resrc_init() == 0 ) { DEBUG_IIC_BUS("calling add bus\n"); if( iov_avalanche_add_bus(&iic_avalanche_adapter) < 0) { ret = -ENODEV; goto i2c_avalanche_bus_fail; } } else { ret = -ENODEV; goto i2c_avalanche_bus_fail; } DEBUG_IIC_BUS("Found device at %#x irq %d.\n", (unsigned int)iic_avalanche_priv_data.iic_base, (unsigned int)iic_avalanche_priv_data.iic_irq); return ret; i2c_avalanche_bus_fail: printk(KERN_ERR "TI I2C Bus :i2c_avalanche_bus_fail\n"); iic_avalanche_release(); return ret; } static void iic_avalanche_exit( void ) { i2c_del_adapter(&iic_avalanche_adapter); iic_avalanche_release(); } module_init(iic_avalanche_init); module_exit(iic_avalanche_exit); MODULE_AUTHOR("Texas Instruments India"); MODULE_DESCRIPTION("TI I2C bus adapter"); MODULE_LICENSE("GPL"); module_param(spike_filter,int,S_IRUSR | S_IRGRP | S_IROTH); MODULE_PARM_DESC(spike_filter, " \n\t\tFor noisy environments, selectable spike filtering is available for I2C data and clock signals.The spike filter evaluates the incoming signal for a selected number of chip clocks Signal stability can be evaluated for up to eight chip clock cycles "); module_param(polling_mode,int,S_IRUSR | S_IRGRP | S_IROTH); MODULE_PARM_DESC(clock, "\n\t\tSet I2C Clock frequency in Hz: 100KHz (Standard Mode) or 400KHz(Fast Mode) "); module_param(clock,int,S_IRUSR | S_IRGRP | S_IROTH); MODULE_PARM_DESC(polling_mode, "\n\t\tSet Polling_mode=1 for polling mode, for interrupt mode set polling_mode=0 "); module_param(iic_base,uint,S_IRUSR | S_IRGRP | S_IROTH); MODULE_PARM_DESC(iic_base, "\n\t\tSet remote I2C base address ");