Commit 8c8463cce44d849e37744749b32d38e1dfb12e50
Committed by
Peter Pearse
1 parent
c98b47ad24
Exists in
master
and in
54 other branches
add an i2c driver for mx31
This patch adds an i2c driver for Freescale i.MX processors Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
Showing 2 changed files with 208 additions and 0 deletions Side-by-side Diff
drivers/i2c/Makefile
drivers/i2c/mxc_i2c.c
1 | +/* | |
2 | + * i2c driver for Freescale mx31 | |
3 | + * | |
4 | + * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | |
5 | + * | |
6 | + * See file CREDITS for list of people who contributed to this | |
7 | + * project. | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or | |
10 | + * modify it under the terms of the GNU General Public License as | |
11 | + * published by the Free Software Foundation; either version 2 of | |
12 | + * the License, or (at your option) any later version. | |
13 | + * | |
14 | + * This program is distributed in the hope that it will be useful, | |
15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | + * GNU General Public License for more details. | |
18 | + * | |
19 | + * You should have received a copy of the GNU General Public License | |
20 | + * along with this program; if not, write to the Free Software | |
21 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
22 | + * MA 02111-1307 USA | |
23 | + */ | |
24 | + | |
25 | +#include <common.h> | |
26 | + | |
27 | +#if defined(CONFIG_HARD_I2C) && defined(CONFIG_I2C_MXC) | |
28 | + | |
29 | +#include <asm/arch/mx31.h> | |
30 | +#include <asm/arch/mx31-regs.h> | |
31 | + | |
32 | +#define IADR 0x00 | |
33 | +#define IFDR 0x04 | |
34 | +#define I2CR 0x08 | |
35 | +#define I2SR 0x0c | |
36 | +#define I2DR 0x10 | |
37 | + | |
38 | +#define I2CR_IEN (1 << 7) | |
39 | +#define I2CR_IIEN (1 << 6) | |
40 | +#define I2CR_MSTA (1 << 5) | |
41 | +#define I2CR_MTX (1 << 4) | |
42 | +#define I2CR_TX_NO_AK (1 << 3) | |
43 | +#define I2CR_RSTA (1 << 2) | |
44 | + | |
45 | +#define I2SR_ICF (1 << 7) | |
46 | +#define I2SR_IBB (1 << 5) | |
47 | +#define I2SR_IIF (1 << 1) | |
48 | +#define I2SR_RX_NO_AK (1 << 0) | |
49 | + | |
50 | +#ifdef CFG_I2C_MX31_PORT1 | |
51 | +#define I2C_BASE 0x43f80000 | |
52 | +#elif defined(CFG_I2C_MX31_PORT2) | |
53 | +#define I2C_BASE 0x43f98000 | |
54 | +#elif defined(CFG_I2C_MX31_PORT3) | |
55 | +#define I2C_BASE 0x43f84000 | |
56 | +#else | |
57 | +#error "define CFG_I2C_MX31_PORTx to use the mx31 I2C driver" | |
58 | +#endif | |
59 | + | |
60 | +#ifdef DEBUG | |
61 | +#define DPRINTF(args...) printf(args) | |
62 | +#else | |
63 | +#define DPRINTF(args...) | |
64 | +#endif | |
65 | + | |
66 | +static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144, | |
67 | + 160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960, | |
68 | + 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840}; | |
69 | + | |
70 | +void i2c_init(int speed, int unused) | |
71 | +{ | |
72 | + int freq = mx31_get_ipg_clk(); | |
73 | + int i; | |
74 | + | |
75 | + for (i = 0; i < 0x1f; i++) | |
76 | + if (freq / div[i] <= speed) | |
77 | + break; | |
78 | + | |
79 | + DPRINTF("%s: speed: %d\n", __FUNCTION__, speed); | |
80 | + | |
81 | + __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ | |
82 | + __REG16(I2C_BASE + IFDR) = i; | |
83 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN; | |
84 | + __REG16(I2C_BASE + I2SR) = 0; | |
85 | +} | |
86 | + | |
87 | +static int wait_busy(void) | |
88 | +{ | |
89 | + int timeout = 10000; | |
90 | + | |
91 | + while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) | |
92 | + udelay(1); | |
93 | + __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ | |
94 | + | |
95 | + return timeout; | |
96 | +} | |
97 | + | |
98 | +static int tx_byte(u8 byte) | |
99 | +{ | |
100 | + __REG16(I2C_BASE + I2DR) = byte; | |
101 | + | |
102 | + if (!wait_busy() || __REG16(I2C_BASE + I2SR) & I2SR_RX_NO_AK) | |
103 | + return -1; | |
104 | + return 0; | |
105 | +} | |
106 | + | |
107 | +static int rx_byte(void) | |
108 | +{ | |
109 | + if (!wait_busy()) | |
110 | + return -1; | |
111 | + | |
112 | + return __REG16(I2C_BASE + I2DR); | |
113 | +} | |
114 | + | |
115 | +int i2c_probe(uchar chip) | |
116 | +{ | |
117 | + int ret; | |
118 | + | |
119 | + __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ | |
120 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN; | |
121 | + | |
122 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; | |
123 | + ret = tx_byte(chip << 1); | |
124 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MTX; | |
125 | + | |
126 | + return ret; | |
127 | +} | |
128 | + | |
129 | +static int i2c_addr(uchar chip, uint addr, int alen) | |
130 | +{ | |
131 | + __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ | |
132 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; | |
133 | + | |
134 | + if (tx_byte(chip << 1)) | |
135 | + return -1; | |
136 | + | |
137 | + while (alen--) | |
138 | + if (tx_byte((addr >> (alen * 8)) & 0xff)) | |
139 | + return -1; | |
140 | + return 0; | |
141 | +} | |
142 | + | |
143 | +int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) | |
144 | +{ | |
145 | + int timeout = 10000; | |
146 | + int ret; | |
147 | + | |
148 | + DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: +%d\n", \ | |
149 | + __FUNCTION__, chip, addr, alen, len); | |
150 | + | |
151 | + if (i2c_addr(chip, addr, alen)) { | |
152 | + printf("i2c_addr failed\n"); | |
153 | + return -1; | |
154 | + } | |
155 | + | |
156 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | \ | |
157 | + I2CR_MTX | I2CR_RSTA; | |
158 | + | |
159 | + if (tx_byte(chip << 1 | 1)) | |
160 | + return -1; | |
161 | + | |
162 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | ((len == 1) \ | |
163 | + ? I2CR_TX_NO_AK : 0); | |
164 | + | |
165 | + ret = __REG16(I2C_BASE + I2DR); | |
166 | + | |
167 | + while (len--) { | |
168 | + if ((ret = rx_byte()) < 0) | |
169 | + return -1; | |
170 | + *buf++ = ret; | |
171 | + if (len <= 1) | |
172 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN | \ | |
173 | + I2CR_MSTA | I2CR_TX_NO_AK; | |
174 | + } | |
175 | + | |
176 | + wait_busy(); | |
177 | + | |
178 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN; | |
179 | + | |
180 | + while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) | |
181 | + udelay(1); | |
182 | + | |
183 | + return 0; | |
184 | +} | |
185 | + | |
186 | +int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) | |
187 | +{ | |
188 | + int timeout = 10000; | |
189 | + DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", \ | |
190 | + __FUNCTION__, chip, addr, alen, len); | |
191 | + | |
192 | + if (i2c_addr(chip, addr, alen)) | |
193 | + return -1; | |
194 | + | |
195 | + while (len--) | |
196 | + if (tx_byte(*buf++)) | |
197 | + return -1; | |
198 | + | |
199 | + __REG16(I2C_BASE + I2CR) = I2CR_IEN; | |
200 | + | |
201 | + while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) | |
202 | + udelay(1); | |
203 | + | |
204 | + return 0; | |
205 | +} | |
206 | + | |
207 | +#endif /* CONFIG_HARD_I2C */ |