i2c-algo-pxa.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  i2c-algo-pxa.c
  3.  *
  4.  *  I2C algorithm for the PXA I2C bus access.
  5.  *  Byte driven algorithm similar to pcf.
  6.  *
  7.  *  Copyright (C) 2002 Intrinsyc Software Inc.
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License version 2 as
  11.  *  published by the Free Software Foundation.
  12.  *
  13.  *  History:
  14.  *    Apr 2002: Initial version [CS]
  15.  *    Jun 2002: Properly seperated algo/adap [FB]
  16.  * 
  17.  */
  18. #include <linux/kernel.h>
  19. #include <linux/module.h>
  20. #include <linux/init.h>
  21. #include <linux/delay.h>
  22. #include <linux/i2c.h>          /* struct i2c_msg and others */
  23. #include <linux/i2c-id.h>
  24. #include "i2c-pxa.h"
  25. /*
  26.  * Set this to zero to remove all the debug statements via dead code elimination.
  27.  */
  28. //#define DEBUG       1
  29. #if DEBUG
  30. static unsigned int i2c_debug = DEBUG;
  31. #else
  32. #define i2c_debug 0
  33. #endif
  34. static int pxa_scan = 1;
  35. static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num)
  36. {
  37. int i;
  38. if (num < 1 || num > MAX_MESSAGES){
  39. if( i2c_debug) 
  40. printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)n", 
  41. MAX_MESSAGES, num);
  42. return -EINVAL;
  43. }
  44. /* check consistency of our messages */
  45. for (i=0;i<num;i++){
  46. if (&msgs[i]==NULL){
  47. if( i2c_debug) printk(KERN_INFO "Msgs is NULLn");
  48. return -EINVAL;
  49. } else {
  50. if (msgs[i].len < 0 || msgs[i].buf == NULL){
  51. if( i2c_debug)printk(KERN_INFO "Length is less than zero");
  52. return -EINVAL;
  53. }
  54. if (msgs[0].len == 0){  /* this is SMBUS_QUICK */
  55. if( i2c_debug)printk(KERN_INFO "Message length is zeron");
  56. return 0;
  57. }
  58. }
  59. }
  60. return 1;
  61. }
  62. static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf, 
  63. int count, int last)
  64. {
  65.         int i, timeout=0;
  66.         struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
  67.         /* increment number of bytes to read by one -- read dummy byte */
  68.         for (i = 0; i <= count; i++) {
  69.                 if (i!=0){
  70.                         /* set ACK to NAK for last received byte ICR[ACKNAK] = 1
  71.                                 only if not a repeated start */
  72.                         if ((i == count) && last) {
  73. adap->transfer( last, I2C_RECEIVE, 0);
  74. }else{
  75. adap->transfer( 0, I2C_RECEIVE, 1);
  76.                         }
  77. timeout = adap->wait_for_interrupt(I2C_RECEIVE);
  78. #ifdef DEBUG
  79.                         if (timeout==BUS_ERROR){
  80. printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing resetn");
  81.                                 adap->reset();
  82.                                 return I2C_RETRY;
  83.                         }
  84. #endif
  85.                         if (timeout){
  86.                                 adap->reset();
  87.                                 return I2C_RETRY;
  88.                         }
  89.                 }
  90.                 if (i) {
  91.                         buf[i - 1] = adap->read_byte();
  92.                 } else {
  93.                         adap->read_byte(); /* dummy read */
  94.                 }
  95.         }
  96.         return (i - 1);
  97. }
  98. static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
  99.                          int count, int last)
  100. {
  101.         struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
  102.         int wrcount, timeout;
  103.         for (wrcount=0; wrcount<count; ++wrcount) {
  104.                 adap->write_byte(buf[wrcount]);
  105.                 if ((wrcount==(count-1)) && last) {
  106. adap->transfer( last, I2C_TRANSMIT, 0);
  107. }else{
  108. adap->transfer( 0, I2C_TRANSMIT, 1);
  109.                 }
  110. timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
  111. #ifdef DEBUG
  112.                 if (timeout==BUS_ERROR) {
  113. printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.n");
  114.                         adap->reset();
  115.                         return I2C_RETRY;
  116.                 }
  117. #endif
  118.                 if (timeout) {
  119.                         adap->reset();
  120.                         return I2C_RETRY;
  121.                 }
  122.         }
  123.         return (wrcount);
  124. }
  125. static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg)
  126. {
  127. u16 flags = msg->flags; 
  128. u8 addr;                            
  129. addr = (u8) ( (0x7f & msg->addr) << 1 );
  130. if (flags & I2C_M_RD ) 
  131. addr |= 1;      
  132. if (flags & I2C_M_REV_DIR_ADDR )
  133. addr ^= 1;
  134. adap->write_byte(addr);
  135. return 0;
  136. }       
  137. static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
  138. {
  139. struct i2c_algo_pxa_data * adap;
  140. struct i2c_msg *pmsg=NULL;
  141. int i;
  142. int ret=0, timeout;
  143. adap = i2c_adap->algo_data;
  144. timeout = adap->wait_bus_not_busy();
  145. if (timeout) {
  146. return I2C_RETRY;
  147. }
  148. for (i = 0;ret >= 0 && i < num; i++) {
  149. int last = i + 1 == num;
  150. pmsg = &msgs[i];
  151. ret = i2c_pxa_set_ctrl_byte(adap,pmsg);
  152. /* Send START */
  153. if (i == 0) {
  154. adap->start();
  155. }else{
  156. adap->repeat_start();
  157. }
  158. adap->transfer(0, I2C_TRANSMIT, 0);
  159. /* Wait for ITE (transmit empty) */
  160. timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
  161. #ifdef DEBUG
  162. /* Check for ACK (bus error) */
  163. if (timeout==BUS_ERROR){
  164. printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing resetn");
  165. adap->reset();
  166. return I2C_RETRY;
  167. }
  168. #endif
  169. if (timeout) {
  170. adap->abort();
  171. adap->reset();
  172. return I2C_RETRY;
  173. }
  174. /* FIXME: handle arbitration... */
  175. #if 0
  176. /* Check for bus arbitration loss */
  177. if (adap->arbitration_loss()){
  178. printk("Arbitration loss detected n");
  179. adap->reset();
  180. return I2C_RETRY;
  181. }
  182. #endif
  183. /* Read */
  184. if (pmsg->flags & I2C_M_RD) {
  185. /* read bytes into buffer*/
  186. ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last);
  187. #if DEBUG > 2
  188. if (ret != pmsg->len) {
  189. printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.n",
  190. ret, pmsg->len);
  191. } else {
  192. printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.n",ret);
  193. }
  194. #endif
  195. } else { /* Write */
  196. ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last);
  197. #if DEBUG > 2
  198. if (ret != pmsg->len) {
  199. printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.n",
  200. ret, pmsg->len);
  201. } else {
  202. printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.n",ret);
  203. }
  204. #endif
  205. }
  206. }
  207. if (ret<0){
  208. return ret;
  209. }else{
  210. return i;
  211. }
  212. }
  213. static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
  214. {
  215. int retval = i2c_pxa_valid_messages( msgs, num);
  216. if( retval > 0)
  217. {
  218. int i;
  219. for (i=i2c_adap->retries; i>=0; i--){
  220. int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num);
  221. if (retval!=I2C_RETRY){
  222. return retval;
  223. }
  224. if( i2c_debug)printk(KERN_INFO"Retrying transmission n");
  225. udelay(100);
  226. }   
  227. if( i2c_debug)printk(KERN_INFO"Retried %i timesn",i2c_adap->retries);
  228. return -EREMOTEIO;
  229. }
  230. return retval;
  231. }
  232. struct i2c_algorithm i2c_pxa_algorithm  = {
  233.         name:                   "PXA-I2C-Algorithm",
  234.         id:                     I2C_ALGO_PXA,
  235.         master_xfer:            i2c_pxa_xfer,
  236.         smbus_xfer:             NULL,
  237.         slave_send:             NULL,
  238.         slave_recv:             NULL,
  239.         algo_control:           NULL,
  240. };
  241. /* 
  242.  * registering functions to load algorithms at runtime 
  243.  */
  244. int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap)
  245. {
  246.         struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
  247.         printk(KERN_INFO"I2C: Adding %s.n", i2c_adap->name);
  248.         i2c_adap->algo = &i2c_pxa_algorithm;
  249.         MOD_INC_USE_COUNT;
  250.         /* register new adapter to i2c module... */
  251.         i2c_add_adapter(i2c_adap);
  252. adap->reset();
  253. /* scan bus */
  254. if (pxa_scan) {
  255. int i;
  256. printk(KERN_INFO "I2C: Scanning bus ");
  257. for (i = 0x02; i < 0xff; i+=2) {
  258. if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue;
  259. if (adap->wait_bus_not_busy()) {
  260. printk(KERN_INFO "I2C: scanning bus %s - TIMEOUTed.n",
  261. i2c_adap->name);
  262.                                 return -EIO;
  263. }
  264. adap->write_byte(i);
  265. adap->start();
  266. adap->transfer(0, I2C_TRANSMIT, 0);
  267. if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) {
  268. printk("(%02x)",i>>1);
  269. adap->abort();
  270. } else {
  271. // printk(".");
  272. }
  273. adap->stop();
  274. udelay(adap->udelay);
  275. }
  276. printk("n");
  277. }
  278.         return 0;
  279. }
  280. int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap)
  281. {
  282.         int res;
  283.         if ((res = i2c_del_adapter(i2c_adap)) < 0)
  284.                 return res;
  285.         MOD_DEC_USE_COUNT;
  286.         printk(KERN_INFO "I2C: Removing %s.n", i2c_adap->name);
  287.         return 0;
  288. }
  289. static int __init i2c_algo_pxa_init (void)
  290. {
  291.         printk(KERN_INFO "I2C: PXA algorithm module loaded.n");
  292.         return 0;
  293. }
  294. EXPORT_SYMBOL(i2c_pxa_add_bus);
  295. EXPORT_SYMBOL(i2c_pxa_del_bus);
  296. MODULE_PARM(pxa_scan, "i");
  297. MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus");
  298. MODULE_AUTHOR("Intrinsyc Software Inc.");
  299. MODULE_LICENSE("GPL");
  300. module_init(i2c_algo_pxa_init);