Add DM320 I²C driver, although not (yet) enabled in the sources.
[Rockbox.git] / firmware / target / arm / tms320dm320 / i2c-dm320.c
blobcb6411e41274072fb30254b1e74aa666fd554f9b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Maurus Cuelenaere
12 * DM320 I²C driver
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "system.h"
22 #include "thread.h"
23 #include "i2c-dm320.h"
25 #define I2C_SCS_COND_START 0x0001
26 #define I2C_SCS_COND_STOP 0x0002
27 #define I2C_SCS_XMIT 0x0004
29 #define I2C_TX_ACK (1 << 20)
31 static struct mutex i2c_mtx;
33 static inline void i2c_begin(void)
35 mutex_lock(&i2c_mtx);
38 static inline void i2c_end(void)
40 mutex_unlock(&i2c_mtx);
43 static inline bool i2c_getack(void)
45 return (IO_I2C_RXDATA & 0x100)>>8;
48 #define WAIT_FOR_I2C if(IO_I2C_SCS & 0x4){ \
49 while(IO_I2C_SCS & 0x4) { \
50 asm volatile("nop"); \
51 } \
52 } \
54 static inline void i2c_start(void)
56 IO_I2C_SCS |= I2C_SCS_XMIT;
57 return;
60 int i2c_write(unsigned short address, const unsigned char *buf, int count)
62 int i;
63 int ret=0;
64 i2c_begin();
65 IO_I2C_TXDATA = ( (address << 1) & 0xFF ) | (address>0x7F ? 0 : 1 ) | I2C_TX_ACK;
66 IO_I2C_SCS &= ~0x3; //clear conditions
67 IO_I2C_SCS |= I2C_SCS_COND_START; // write 'start condition'
68 i2c_start();
69 WAIT_FOR_I2C;
70 /* experimental */
71 if(address>0x7F){ // check if it is 10-bit instead of 7-bit
72 IO_I2C_TXDATA = ( (address >> 7) & 0xFF) | I2C_TX_ACK;
73 IO_I2C_SCS &= ~0x3; //normal transfer
74 i2c_start();
75 WAIT_FOR_I2C;
76 IO_I2C_TXDATA = ( (address << 1) & 0xFF) | 1 | I2C_TX_ACK;
77 IO_I2C_SCS &= ~0x3; //clear conditions
78 IO_I2C_SCS |= I2C_SCS_COND_START; //write 'start condition'
79 i2c_start();
80 WAIT_FOR_I2C;
83 for(i=0; i<count; i++){
84 IO_I2C_TXDATA = buf[i] | I2C_TX_ACK;
85 IO_I2C_SCS &= ~0x3; //normal transfer
86 i2c_start();
87 WAIT_FOR_I2C;
88 if(!i2c_getack())
89 ret = -1;
91 IO_I2C_SCS &= ~0x3; //clear conditions
92 IO_I2C_SCS |= I2C_SCS_COND_STOP; //write 'stop condition'
93 i2c_start();
94 WAIT_FOR_I2C;
95 i2c_end();
96 return ret;
99 int i2c_read(unsigned short address, unsigned char* buf, int count)
101 int i;
102 int ack=0;
103 i2c_begin();
104 IO_I2C_TXDATA = ( (address << 1) & 0xFF ) | (address>0x7F ? 0 : 1 ) | I2C_TX_ACK;
105 IO_I2C_SCS &= ~0x3; //clear conditions
106 IO_I2C_SCS |= I2C_SCS_COND_START; // write 'start condition'
107 i2c_start();
108 WAIT_FOR_I2C;
109 /* experimental */
110 if(address>0x7F){ // check if it is 10-bit instead of 7-bit
111 IO_I2C_TXDATA = ( (address >> 7) & 0xFF ) | I2C_TX_ACK;
112 IO_I2C_SCS &= ~0x3; //normal transfer
113 i2c_start();
114 WAIT_FOR_I2C;
115 IO_I2C_TXDATA = ( (address << 1) & 0xFF ) | 1 | I2C_TX_ACK;
116 IO_I2C_SCS &= ~0x3; //clear conditions
117 IO_I2C_SCS |= I2C_SCS_COND_START; //write 'start condition'
118 i2c_start();
119 WAIT_FOR_I2C;
122 for(i=0; i<count; i++){
123 unsigned short temp;
124 IO_I2C_TXDATA = 0xFF | ( (count-1)==i ? I2C_TX_ACK : 0);
125 IO_I2C_SCS &= ~0x3; //normal transfer
126 i2c_start();
127 WAIT_FOR_I2C;
128 temp = IO_I2C_RXDATA;
129 buf[i] = temp & 0xFF;
130 ack = (temp & 0x100) >> 8;
132 IO_I2C_SCS &= ~0x3; //clear conditions
133 IO_I2C_SCS |= I2C_SCS_COND_STOP; //write 'stop condition'
134 i2c_start();
135 WAIT_FOR_I2C;
136 i2c_end();
137 return ack;
140 void i2c_init(void)
142 #if 0 //TODO: mimic OF I2C clock settings; currently this is done by the bootloader
143 IO_CLK_MOD2 &= ~CLK_MOD2_I2C; // turn I²C clock off (just to be sure)
144 IO_CLK_LPCTL1 &= ~1; // set Powerdown mode to off
145 IO_CLK_SEL0 &= ~0x800; // set I²C clock to PLLA
146 IO_CLK_DIV4 &= ~0x1F; // I²C clock division = 1
147 IO_CLK_MOD2 |= CLK_MOD2_I2C; // enable I²C clock
148 #endif
149 IO_I2C_SCS &= ~0x8; //set clock to 100 kHz
150 IO_INTC_EINT2 &= ~INTR_EINT2_I2C; // disable I²C interrupt