/*++ drivers/i2c/algos/wmt_i2c_algo.c Copyright (c) 2008 WonderMedia Technologies, Inc. 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . WonderMedia Technologies, Inc. 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. --*/ #define WMT_I2C_ALGO_C #include #include #include #include #include #include /* #include */ #include #include #ifdef __KERNEL__ #ifdef DEBUG #define DPRINTK printk #else #define DPRINTK(x...) #endif #else #define DPRINTK printf #endif static struct i2c_adapter *wmt_i2c_adap[5]; /*!************************************************************************* * wmt_i2c_valid_messages() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief verify the input message * * \retval 1 if success */ static int wmt_i2c_valid_messages( struct i2c_msg msgs[], /*!<; //[IN] transfer data */ int num /*!<; //[IN] transfer data length */ ) { int i; if (num < 1 || num > MAX_MESSAGES) { DPRINTK(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n", MAX_MESSAGES, num); return -EINVAL; } /* check consistency of our messages */ for (i = 0; i < num; i++) { if (&msgs[i] == NULL) { DPRINTK(KERN_INFO "Msgs is NULL\n"); return -EINVAL; } else { if (msgs[i].buf == NULL) { DPRINTK(KERN_INFO "Length is less than zero\n"); return -EINVAL; } } } return 1; } /*!************************************************************************* * wmt_i2c_do_xfer() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief * * \retval 0 if success */ static int wmt_i2c_do_xfer( struct i2c_adapter *i2c_adap, /*!<; //[IN] a pointer point to struct inode */ struct i2c_msg msgs[], /*!<; //[IN] transfer data */ int num /*!<; //[IN] transfer data length */ ) { int i; struct i2c_algo_wmt_data *adap; int ret = 0 ; adap = i2c_adap->algo_data; /*ret = adap->wait_bus_not_busy();*/ for (i = 0 ; i < 10; ++i) ; if (ret < 0) return ret ; ret = adap->send_request(msgs, num, 0, 0, 0); return ret; } /*!************************************************************************* * wmt_i2c_xfer() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief Transfer (read/write) data to i2c bus, wmt_i2c_do_xfer will be called to transfer * * \retval 0 if success */ static int wmt_i2c_xfer( struct i2c_adapter *i2c_adap, /*!<; //[IN] a pointer point to struct inode */ struct i2c_msg msgs[], /*!<; //[IN] transfer data */ int num /*!<; //[IN] transfer data length */ ) { int ret ; int i ; ret = wmt_i2c_valid_messages(msgs, num); if (ret < 0) return ret ; for (i = i2c_adap->retries ; i >= 0; i--) { ret = wmt_i2c_do_xfer(i2c_adap, msgs, num); if (ret > 0) return ret ; DPRINTK(KERN_INFO"Retrying transmission \n"); udelay(100); } DPRINTK(KERN_INFO"Retried %i times\n", i2c_adap->retries); return ret; } /*!************************************************************************* * wmt_i2c_functionality() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief * * \retval smbus functionality */ static u32 wmt_i2c_functionality( struct i2c_adapter *adapter /*!<; //[IN] a pointer point to struct inode */ ) { /* Emulate the SMBUS functions*/ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } /* * send i2c_msg into fifo of i2c bus * msg: transfer data content * msg_num:number of transferring msg * bus_id :used to indicate which bus do device want to access */ int wmt_i2c_transfer(struct i2c_msg* msgs, int msg_num, int bus_id, void (*callback)(void *data), void *data) { struct i2c_algo_wmt_data *adap; int ret = 0 ; adap = wmt_i2c_adap[bus_id]->algo_data; ret = adap->send_request(msgs, msg_num, 1, callback, data); return ret; } #if 0 /*!************************************************************************* * wmt_i2c_control() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief To set i2c transfer mode * * \retval 0 if success */ static int wmt_i2c_control( struct i2c_adapter *i2c_adap, /*!<; //[IN] a pointer point to struct inode */ unsigned int cmd, /*!<; //[IN] standard or fast mode */ unsigned long arg /*!<; //Not in used, but can't delete */ ) { int ret ; struct i2c_algo_wmt_data *adap = i2c_adap->algo_data; ret = 0 ; DPRINTK("wmt_i2c_control: cmd = 0x%8.8x \n", cmd); switch (cmd) { case I2C_SET_STANDARD_MODE: adap->set_mode(I2C_STANDARD_MODE); break ; case I2C_SET_FAST_MODE: adap->set_mode(I2C_FAST_MODE); break ; default: ret = -EINVAL; break; } return ret; } #endif struct i2c_algorithm wmt_i2c_algorithm = { .master_xfer = wmt_i2c_xfer, .functionality = wmt_i2c_functionality, }; /*!************************************************************************* * wmt_i2c_add_bus() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief * * \retval NULL */ int wmt_i2c_add_bus(struct i2c_adapter *i2c_adap) { printk(KERN_INFO"i2c: adding %s.\n", i2c_adap->name); i2c_adap->algo = &wmt_i2c_algorithm; wmt_i2c_adap[i2c_adap->nr] = i2c_adap; /* register new adapter to i2c module... */ /* i2c_add_adapter(i2c_adap); */ i2c_add_numbered_adapter(i2c_adap); /* adap->reset();*/ return 0; } /*!************************************************************************* * wmt_i2c_del_bus() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief * * \retval NULL */ int wmt_i2c_del_bus(struct i2c_adapter *i2c_adap) { int res; res = i2c_del_adapter(i2c_adap); if (res < 0) return res; printk(KERN_INFO "i2c: removing %s.\n", i2c_adap->name); return 0; } /*!************************************************************************* * wmt_i2c_algo_init() * * Private Function by Paul Kwong, 2007/1/12 */ /*! * \brief * * \retval NULL */ static int __init wmt_i2c_algo_init(void) { printk(KERN_INFO "i2c: wmt algorithm module loaded.\n"); return 0; } EXPORT_SYMBOL(wmt_i2c_add_bus); EXPORT_SYMBOL(wmt_i2c_del_bus); MODULE_AUTHOR("WonderMedia Technologies, Inc."); MODULE_DESCRIPTION("WMT I2C ALGO Driver"); MODULE_LICENSE("GPL"); module_init(wmt_i2c_algo_init); #undef WMT_I2C_ALGO_C