summaryrefslogtreecommitdiff
path: root/firmware/drivers/i2c-coldfire.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/i2c-coldfire.c')
-rw-r--r--firmware/drivers/i2c-coldfire.c229
1 files changed, 145 insertions, 84 deletions
diff --git a/firmware/drivers/i2c-coldfire.c b/firmware/drivers/i2c-coldfire.c
index 47aeba757f..a628ce5f0e 100644
--- a/firmware/drivers/i2c-coldfire.c
+++ b/firmware/drivers/i2c-coldfire.c
@@ -5,6 +5,7 @@
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 *
8 * $Id$ 9 * $Id$
9 * 10 *
10 * Copyright (C) 2005 by Andy Young 11 * Copyright (C) 2005 by Andy Young
@@ -23,17 +24,16 @@
23#include "system.h" 24#include "system.h"
24#include "i2c-coldfire.h" 25#include "i2c-coldfire.h"
25 26
26#define I2C_DEVICE_1 ((volatile unsigned char *)&MADR)
27#define I2C_DEVICE_2 ((volatile unsigned char *)&MADR2)
28 27
29/* Local functions definitions */ 28/* --- Local functions - declarations --- */
29
30static int i2c_start(volatile unsigned char *iface);
31static int i2c_wait_for_slave(volatile unsigned char *iface);
32static int i2c_outb(volatile unsigned char *iface, unsigned char byte);
33inline void i2c_stop(volatile unsigned char *iface);
30 34
31static int i2c_write_byte(int device, unsigned char data);
32static int i2c_gen_start(int device);
33static void i2c_gen_stop(int device);
34static volatile unsigned char *i2c_get_addr(int device);
35 35
36/* Public functions */ 36/* --- Public functions - implementation --- */
37 37
38void i2c_init(void) 38void i2c_init(void)
39{ 39{
@@ -55,14 +55,15 @@ void i2c_init(void)
55#endif 55#endif
56 56
57 /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */ 57 /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */
58 MFDR = 0x0d; 58 MFDR = 0x0d;
59 MFDR2 = 0x0d; 59 MFDR2 = 0x0d;
60 60
61#ifdef IAUDIO_X5 61#ifdef IAUDIO_X5
62 MBCR = IEN; /* Enable interface */ 62 MBCR = IEN; /* Enable interface */
63 MBCR2 = IEN;
63#endif 64#endif
64 65
65#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) 66#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
66 /* Audio Codec */ 67 /* Audio Codec */
67 MBDR = 0; /* iRiver firmware does this */ 68 MBDR = 0; /* iRiver firmware does this */
68 MBCR = IEN; /* Enable interface */ 69 MBCR = IEN; /* Enable interface */
@@ -72,109 +73,169 @@ void i2c_init(void)
72void i2c_close(void) 73void i2c_close(void)
73{ 74{
74 MBCR = 0; 75 MBCR = 0;
76 MBCR2 = 0;
75} 77}
76 78
77/** 79/*
78 * Writes bytes to the selected device. 80 * Writes bytes to a I2C device.
79 * 81 *
80 * Use device=1 for bus 1 at 0x40000280 82 * Returns number of bytes successfully sent or a negative value on error.
81 * Use device=2 for bus 2 at 0x80000440
82 *
83 * Returns number of bytes successfully send or -1 if START failed
84 */ 83 */
85int i2c_write(int device, unsigned char *buf, int count) 84int i2c_write(volatile unsigned char *iface, unsigned char addr,
85 const unsigned char *buf, int count)
86{ 86{
87 int i; 87 int i, rc;
88 int rc;
89 88
90 rc = i2c_gen_start(device); 89 if ( ! count)
90 return 0;
91
92 rc = i2c_start(iface);
91 if (rc < 0) 93 if (rc < 0)
94 return rc;
95
96 rc = i2c_outb(iface, addr & 0xfe);
97 if (rc < 0)
98 return rc;
99
100 for (i = 0; i < count; i++)
92 { 101 {
93 logf("i2c: gen_start failed (d=%d)", device); 102 rc = i2c_outb(iface, *buf++);
94 return rc*10 - 1;
95 }
96
97 for (i=0; i<count; i++)
98 {
99 rc = i2c_write_byte(device, buf[i]);
100 if (rc < 0) 103 if (rc < 0)
101 { 104 return rc;
102 logf("i2c: write failed at (d=%d,i=%d)", device, i);
103 return rc*10 - 2;
104 }
105 } 105 }
106 106 i2c_stop(iface);
107 i2c_gen_stop(device); 107
108
109 return count; 108 return count;
110} 109}
111 110
112/* Write a byte to the interface, returns 0 on success, -1 otherwise. */ 111/*
113int i2c_write_byte(int device, unsigned char data) 112 * Reads bytes from a I2C device.
113 *
114 * Returns number of bytes successfully received or a negative value on error.
115 */
116int i2c_read(volatile unsigned char *iface, unsigned char addr,
117 unsigned char *buf, int count)
114{ 118{
115 volatile unsigned char *regs = i2c_get_addr(device); 119 int i, rc;
116 120
117 long count = 0; 121 if ( ! count)
122 return 0;
123
124 rc = i2c_start(iface);
125 if (rc < 0)
126 return rc;
118 127
119 regs[O_MBDR] = data; /* Write data byte */ 128 rc = i2c_outb(iface, addr | 1);
129 if (rc < 0)
130 return rc;
131
132 /* Switch to Rx mode */
133 iface[O_MBCR] &= ~MTX;
134 iface[O_MBCR] &= ~TXAK;
135
136 /* Dummy read */
137 rc = (int) iface[O_MBDR];
138
139 for (i = 0; i < count; i++)
140 {
141 rc = i2c_wait_for_slave(iface);
142 if (rc < 0)
143 return rc;
120 144
121 /* Wait for bus busy */ 145 if (i == count-2)
122 while (!(regs[O_MBSR] & IBB) && count < MAX_LOOP) 146 /* Don't ACK the next-to-last byte */
123 count++; 147 iface[O_MBCR] |= TXAK;
148
149 if (i == count-1)
150 /* Generate STOP before reading last byte */
151 i2c_stop(iface);
124 152
125 if (count >= MAX_LOOP) 153 *buf++ = iface[O_MBDR];
126 return -1; 154 }
155 return count;
156}
127 157
128 count = 0; 158/* --- Local functions - implementation --- */
129 159
130 /* Wait for interrupt flag */ 160/* Begin I2C session on the given interface.
131 while (!(regs[O_MBSR] & IFF) && count < MAX_LOOP) 161 *
132 count++; 162 * Returns 0 on success, negative value on error.
163 */
164int i2c_start(volatile unsigned char *iface)
165{
166 /* Wait for bus to become free */
167 int j = MAX_LOOP;
168 while (--j && (iface[O_MBSR] & IBB))
169 ;
170 if (!j)
171 {
172 logf("i2c: bus is busy (iface=%08x)", iface);
173 return -1;
174 }
175
176 /* Generate START and prepare for write */
177 iface[O_MBCR] |= (MSTA | TXAK | MTX);
178
179 return 0;
180}
133 181
134 if (count >= MAX_LOOP) 182/* Wait for slave to act on given I2C interface.
183 *
184 * Returns 0 on success, negative value on error.
185 */
186int i2c_wait_for_slave(volatile unsigned char *iface)
187{
188 int j = MAX_LOOP;
189 while (--j && ! (iface[O_MBSR] & IFF))
190 ;
191 if (!j)
192 {
193 logf("i2c: IFF not set (iface=%08x)", iface);
194 i2c_stop(iface);
135 return -2; 195 return -2;
136 196 }
137 regs[O_MBSR] &= ~IFF; /* Clear interrupt flag */ 197
138 198 /* Clear interrupt flag */
139 if (!(regs[O_MBSR] & ICF)) /* Check that transfer is complete */ 199 iface[O_MBSR] &= ~IFF;
140 return -3; 200
141
142 if (regs[O_MBSR] & RXAK) /* Check that the byte has been ACKed */
143 return -4;
144
145 return 0; 201 return 0;
146} 202}
147 203
148 204/* Write the given byte to the given I2C interface.
149/* Returns 0 on success, -1 on failure */ 205 *
150int i2c_gen_start(int device) 206 * Returns 0 on success, negative value on error.
207 */
208int i2c_outb(volatile unsigned char *iface, unsigned char byte)
151{ 209{
152 volatile unsigned char *regs = i2c_get_addr(device); 210 int rc;
153 long count = 0;
154
155 /* Wait for bus to become free */
156 while ((regs[O_MBSR] & IBB) && (count < MAX_LOOP))
157 count++;
158
159 if (count >= MAX_LOOP)
160 return -1;
161 211
162 regs[O_MBCR] |= MSTA | MTX; /* Generate START */ 212 iface[O_MBDR] = byte;
163 213
214 rc = i2c_wait_for_slave(iface);
215 if (rc < 0)
216 return rc;
217
218 /* Check that transfer is complete */
219 if ( !(iface[O_MBSR] & ICF))
220 {
221 logf("i2c: transfer error (iface=%08x)", iface);
222 i2c_stop(iface);
223 return -3;
224 }
225
226 /* Check that the byte has been ACKed */
227 if (iface[O_MBSR] & RXAK)
228 {
229 logf("i2c: no ACK (iface=%08x)", iface);
230 i2c_stop(iface);
231 return -4;
232 }
233
164 return 0; 234 return 0;
165}
166
167void i2c_gen_stop(int device)
168{
169 volatile unsigned char *regs = i2c_get_addr(device);
170 regs[O_MBCR] &= ~MSTA; /* Clear MSTA to generate STOP */
171} 235}
172 236
173 237/* End I2C session on the given interface. */
174volatile unsigned char *i2c_get_addr(int device) 238inline void i2c_stop(volatile unsigned char *iface)
175{ 239{
176 if (device == 1) 240 iface[O_MBCR] &= ~MSTA;
177 return I2C_DEVICE_1;
178
179 return I2C_DEVICE_2;
180} 241}