summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-12-29 05:15:36 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-12-29 05:15:36 +0000
commit20d81d979a22403c16c1f1c576de63af07b2ea99 (patch)
tree5d673b6185330c5b3d41aac301b0439a7a3bd71a /firmware/target
parentad9a0588dbbcb91cd10ab6465d7c9405d5c032fc (diff)
downloadrockbox-20d81d979a22403c16c1f1c576de63af07b2ea99.tar.gz
rockbox-20d81d979a22403c16c1f1c576de63af07b2ea99.zip
i.MX31: Implement asynchronous version of I2C driver.
Scheme is more flexible and should help to enable threadless RDS. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31461 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/imx31/i2c-imx31.c373
-rw-r--r--firmware/target/arm/imx31/i2c-imx31.h47
2 files changed, 262 insertions, 158 deletions
diff --git a/firmware/target/arm/imx31/i2c-imx31.c b/firmware/target/arm/imx31/i2c-imx31.c
index 975f951fdc..972c7d465b 100644
--- a/firmware/target/arm/imx31/i2c-imx31.c
+++ b/firmware/target/arm/imx31/i2c-imx31.c
@@ -46,14 +46,11 @@ static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void);
46static struct i2c_module_descriptor 46static struct i2c_module_descriptor
47{ 47{
48 volatile unsigned short * const base; /* Module base address */ 48 volatile unsigned short * const base; /* Module base address */
49 struct i2c_transfer_desc *head; /* Running job */
50 struct i2c_transfer_desc *tail; /* Most recent job added */
49 void (* const handler)(void); /* Module interrupt handler */ 51 void (* const handler)(void); /* Module interrupt handler */
50 struct mutex m; /* Node mutual-exclusion */ 52 unsigned char addr; /* Composite address value */
51 struct semaphore complete; /* I2C completion signal */ 53 unsigned char busy; /* Have buffers been modified? */
52 unsigned char *addr_data; /* Additional addressing data */
53 int addr_count; /* Addressing byte count */
54 unsigned char *data; /* TX/RX buffer (actual data) */
55 int data_count; /* TX/RX byte count */
56 unsigned char addr; /* Address + r/w bit */
57 uint8_t enable; /* Enable count */ 54 uint8_t enable; /* Enable count */
58 const uint8_t cg; /* Clock gating index */ 55 const uint8_t cg; /* Clock gating index */
59 const uint8_t ints; /* Module interrupt number */ 56 const uint8_t ints; /* Module interrupt number */
@@ -85,226 +82,308 @@ static struct i2c_module_descriptor
85#endif 82#endif
86}; 83};
87 84
88static void i2c_interrupt(enum i2c_module_number i2c) 85
86/* Actually begin the session at the queue head */
87static bool start_transfer(struct i2c_module_descriptor * const desc,
88 struct i2c_transfer_desc * const xfer)
89{ 89{
90 struct i2c_module_descriptor * const desc = &i2c_descs[i2c];
91 volatile unsigned short * const base = desc->base; 90 volatile unsigned short * const base = desc->base;
92 unsigned short i2sr = base[I2SR];
93 91
94 base[I2SR] = 0; /* Clear IIF */ 92 /* If interface isn't enabled or buffers have been used, the transfer
93 cannot be started/restarted. */
94 if (desc->enable == 0 || desc->busy != 0)
95 return false;
96
97 /* Set speed */
98 base[IFDR] = xfer->node->ifdr;
99
100 /* Clear status */
101 base[I2SR] = 0;
102
103 /* Enable module, enable Interrupt, master transmitter */
104 unsigned short i2cr = I2C_I2CR_IEN | I2C_I2CR_IIEN | I2C_I2CR_MTX;
105
106 unsigned char addr = xfer->node->addr & 0xfe;
95 107
96 if (desc->addr_count >= 0) 108 if (xfer->rxcount > 0)
97 { 109 {
98 /* ADDR cycle - either done or more to send */ 110 addr |= 0x01; /* Slave address/rd */
99 if ((i2sr & I2C_I2SR_RXAK) != 0) 111
112 if (xfer->rxcount < 2)
100 { 113 {
101 goto i2c_stop; /* problem */ 114 /* Receiving less than two bytes - disable ACK generation */
115 i2cr |= I2C_I2CR_TXAK;
102 } 116 }
117 }
118
119 /* Remember composite address - contains info concerning RX or TX */
120 desc->addr = addr;
121
122 /* Set config, generate START. */
123 base[I2CR] = i2cr | I2C_I2CR_MSTA;
124
125 /* Address slave (first byte sent) and begin session. */
126 base[I2DR] = addr;
127
128 return true;
129}
130
131static void i2c_interrupt(struct i2c_module_descriptor * const desc)
132{
133 volatile unsigned short * const base = desc->base;
134 unsigned short const i2sr = base[I2SR];
135 struct i2c_transfer_desc *xfer = desc->head;
136
137 base[I2SR] = 0; /* Clear IIF */
138
139 if (i2sr & I2C_I2SR_IAL)
140 {
141 /* Bus arbitration was lost - retry current transfer until it succeeds */
142 /* Best guess as to why: at high CPU speeds, voltage hasn't had time to
143 * stabilize to register STOP if a new transfer is started very soon
144 * after a previous one has completed. AFAICT, this might happen once at
145 * most on a transfer. Switching to repeated START could be a better way
146 * to handle the cases where multiple transfers are already queued. */
147 if (start_transfer(desc, xfer))
148 return;
103 149
104 if (--desc->addr_count < 0) 150 /* Restart failed - STOP */
151 base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
152 }
153 else if (xfer->txcount >= 0 && (base[I2CR] & I2C_I2CR_MTX))
154 {
155 /* ADDR cycle or TX */
156 if ((i2sr & I2C_I2SR_RXAK) != 0)
105 { 157 {
106 /* Switching to data cycle */ 158 /* NACK */
107 if (desc->addr & 0x1)
108 {
109 base[I2CR] &= ~I2C_I2CR_MTX; /* Switch to RX mode */
110 base[I2DR]; /* Dummy read */
111 return;
112 }
113 /* else remaining data is TX - handle below */
114 goto i2c_transmit;
115 } 159 }
116 else 160 else if (xfer->txcount > 0)
117 { 161 {
118 base[I2DR] = *desc->addr_data++; /* Send next addressing byte */ 162 desc->busy = 1;
163 base[I2DR] = *xfer->txdata++; /* Send next TX byte */
164 xfer->txcount--;
119 return; 165 return;
120 } 166 }
121 } 167 else if (desc->addr & 0x01)
122
123 if (base[I2CR] & I2C_I2CR_MTX)
124 {
125 /* Transmitting data */
126 if ((i2sr & I2C_I2SR_RXAK) == 0)
127 { 168 {
128i2c_transmit: 169 /* ADDR cycle is complete */
129 if (desc->data_count > 0) 170 base[I2CR] &= ~I2C_I2CR_MTX; /* Switch to RX mode */
130 { 171 base[I2DR]; /* Dummy read */
131 /* More bytes to send, got ACK from previous byte */ 172 return;
132 base[I2DR] = *desc->data++;
133 desc->data_count--;
134 return;
135 }
136 } 173 }
137 /* else done or no ACK received */ 174
175 /* Transfer complete or NACK - STOP */
176 base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
138 } 177 }
139 else 178 else if (xfer->rxcount > 0)
140 { 179 {
141 /* Receiving data */ 180 /* RX */
142 if (--desc->data_count > 0) 181 desc->busy = 1;
182
183 if (--xfer->rxcount > 0)
143 { 184 {
144 if (desc->data_count == 1) 185 if (xfer->rxcount == 1)
145 { 186 {
146 /* 2nd to Last byte - NACK */ 187 /* 2nd to Last byte - NACK */
147 base[I2CR] |= I2C_I2CR_TXAK; 188 base[I2CR] |= I2C_I2CR_TXAK;
148 } 189 }
149 190
150 *desc->data++ = base[I2DR]; /* Read data from I2DR and store */ 191 *xfer->rxdata++ = base[I2DR]; /* Read data from I2DR and store */
151 return; 192 return;
152 } 193 }
194
195 /* Generate STOP signal before reading final byte */
196 base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
197 *xfer->rxdata++ = base[I2DR]; /* Read data from I2DR and store */
198 }
199
200 /* Start next transfer, if any */
201 for (;;)
202 {
203 struct i2c_transfer_desc *next = xfer->next;
204 i2c_transfer_cb_fn_type callback = xfer->callback;
205 xfer->next = NULL;
206
207 if (next == xfer)
208 {
209 /* Last job on queue */
210 desc->head = NULL;
211
212 if (callback != NULL)
213 callback(xfer);
214
215 /* Callback may have restarted transfers. */
216 }
153 else 217 else
154 { 218 {
155 /* Generate STOP signal before reading data */ 219 /* Queue next job */
156 base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN); 220 desc->head = next;
157 *desc->data++ = base[I2DR]; /* Read data from I2DR and store */ 221
158 goto i2c_done; 222 if (callback != NULL)
223 callback(xfer);
224
225 desc->busy = 0;
226 if (!start_transfer(desc, next))
227 {
228 xfer = next;
229 continue;
230 }
159 } 231 }
160 }
161 232
162i2c_stop: 233 break;
163 /* Generate STOP signal */ 234 }
164 base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
165i2c_done:
166 /* Signal thread we're done */
167 semaphore_release(&desc->complete);
168} 235}
169 236
170#if (I2C_MODULE_MASK & USE_I2C1_MODULE) 237#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
171static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void) 238static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void)
172{ 239{
173 i2c_interrupt(I2C1_NUM); 240 i2c_interrupt(&i2c_descs[I2C1_NUM]);
174} 241}
175#endif 242#endif
176#if (I2C_MODULE_MASK & USE_I2C2_MODULE) 243#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
177static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void) 244static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void)
178{ 245{
179 i2c_interrupt(I2C2_NUM); 246 i2c_interrupt(&i2c_descs[I2C2_NUM]);
180} 247}
181#endif 248#endif
182#if (I2C_MODULE_MASK & USE_I2C3_MODULE) 249#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
183static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void) 250static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void)
184{ 251{
185 i2c_interrupt(I2C3_NUM); 252 i2c_interrupt(&i2c_descs[I2C3_NUM]);
186} 253}
187#endif 254#endif
188 255
189static int i2c_transfer(struct i2c_node * const node, 256/* Send and/or receive data on the specified node asynchronously */
190 struct i2c_module_descriptor *const desc) 257bool i2c_transfer(struct i2c_transfer_desc *xfer)
191{ 258{
192 volatile unsigned short * const base = desc->base; 259 if (xfer == NULL || xfer->next != NULL || xfer->node == NULL ||
193 int count = desc->data_count; 260 xfer->rxcount < 0 || xfer->txcount < 0 ||
194 uint16_t i2cr; 261 (xfer->rxcount <= 0 && xfer->txcount <= 0))
195
196 /* Make sure bus is idle. */
197 while (base[I2SR] & I2C_I2SR_IBB);
198
199 /* Set speed */
200 base[IFDR] = node->ifdr;
201
202 /* Enable module */
203 base[I2CR] = I2C_I2CR_IEN;
204
205 /* Enable Interrupt, Master */
206 i2cr = I2C_I2CR_IEN | I2C_I2CR_IIEN | I2C_I2CR_MTX;
207
208 if ((desc->addr & 0x1) && desc->data_count < 2)
209 { 262 {
210 /* Receiving less than two bytes - disable ACK generation */ 263 /* Can't pass a busy descriptor, requires a node, < 0 sizes
211 i2cr |= I2C_I2CR_TXAK; 264 or all-0 sizes not permitted. */
265 return false;
212 } 266 }
213 267
214 /* Set config */ 268 bool retval = true;
215 base[I2CR] = i2cr; 269 struct i2c_module_descriptor * const desc = &i2c_descs[xfer->node->num];
216 270 unsigned long cpsr = disable_irq_save();
217 /* Generate START */
218 base[I2CR] = i2cr | I2C_I2CR_MSTA;
219
220 /* Address slave (first byte sent) and begin session. */
221 base[I2DR] = desc->addr;
222 271
223 /* Wait for transfer to complete */ 272 if (desc->head == NULL)
224 if (semaphore_wait(&desc->complete, HZ) == OBJ_WAIT_SUCCEEDED)
225 { 273 {
226 count -= desc->data_count; 274 /* No transfers in progress; start interface. */
275 desc->busy = 0;
276 retval = start_transfer(desc, xfer);
277
278 if (retval)
279 {
280 /* Start ok: actually put it in the queue. */
281 desc->head = xfer;
282 desc->tail = xfer;
283 xfer->next = xfer; /* First, self-reference terminate */
284 }
227 } 285 }
228 else 286 else
229 { 287 {
230 /* Generate STOP if timeout */ 288 /* Already running: simply add to end and the final INT on the
231 base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN); 289 * running transfer will pick it up. */
232 count = -1; 290 desc->tail->next = xfer; /* Add to tail */
291 desc->tail = xfer; /* New tail */
292 xfer->next = xfer; /* Self-reference terminate */
233 } 293 }
234 294
235 desc->addr_count = 0; 295 restore_irq(cpsr);
236 296
237 return count; 297 return retval;
238} 298}
239 299
240int i2c_read(struct i2c_node *node, int reg, 300/** Synchronous transfers support **/
241 unsigned char *data, int data_count) 301static void i2c_sync_xfer_complete_cb(struct i2c_transfer_desc *xfer)
242{ 302{
243 struct i2c_module_descriptor *const desc = &i2c_descs[node->num]; 303 semaphore_release(&((struct i2c_sync_transfer_desc *)xfer)->sema);
244 unsigned char ad[1]; 304}
245 305
246 mutex_lock(&desc->m); 306static inline bool i2c_sync_wait_for_xfer_complete(struct i2c_sync_transfer_desc *xfer)
307{
308 return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK) == OBJ_WAIT_SUCCEEDED;
309}
310
311int i2c_read(struct i2c_node *node, int addr, unsigned char *data,
312 int data_count)
313{
314 struct i2c_sync_transfer_desc xfer;
247 315
248 desc->addr = (node->addr & 0xfe) | 0x1; /* Slave address/rd */ 316 xfer.xfer.node = node;
249 317
250 if (reg >= 0) 318 unsigned char ad;
319
320 if (addr >= 0)
251 { 321 {
252 /* Sub-address */ 322 /* Sub-address */
253 desc->addr_count = 1; 323 ad = addr;
254 desc->addr_data = ad; 324 xfer.xfer.txdata = &ad;
255 ad[0] = reg; 325 xfer.xfer.txcount = 1;
326 }
327 else
328 {
329 /* Raw read from slave */
330 xfer.xfer.txcount = 0;
256 } 331 }
257 /* else raw read from slave */
258 332
259 desc->data = data; 333 xfer.xfer.rxdata = data;
260 desc->data_count = data_count; 334 xfer.xfer.rxcount = data_count;
335 xfer.xfer.callback = i2c_sync_xfer_complete_cb;
336 xfer.xfer.next = NULL;
261 337
262 data_count = i2c_transfer(node, desc); 338 semaphore_init(&xfer.sema, 1, 0);
263 339
264 mutex_unlock(&desc->m); 340 if (i2c_transfer(&xfer.xfer) && i2c_sync_wait_for_xfer_complete(&xfer))
341 {
342 return data_count - xfer.xfer.rxcount;
343 }
265 344
266 return data_count; 345 return -1;
267} 346}
268 347
269int i2c_write(struct i2c_node *node, const unsigned char *data, int data_count) 348int i2c_write(struct i2c_node *node, const unsigned char *data,
349 int data_count)
270{ 350{
271 struct i2c_module_descriptor *const desc = &i2c_descs[node->num]; 351 struct i2c_sync_transfer_desc xfer;
272 352
273 mutex_lock(&desc->m); 353 xfer.xfer.node = node;
354 xfer.xfer.txdata = data;
355 xfer.xfer.txcount = data_count;
356 xfer.xfer.rxcount = 0;
357 xfer.xfer.callback = i2c_sync_xfer_complete_cb;
358 xfer.xfer.next = NULL;
274 359
275 desc->addr = node->addr & 0xfe; /* Slave address/wr */ 360 semaphore_init(&xfer.sema, 1, 0);
276 desc->data = (unsigned char *)data;
277 desc->data_count = data_count;
278 361
279 data_count = i2c_transfer(node, desc); 362 if (i2c_transfer(&xfer.xfer) && i2c_sync_wait_for_xfer_complete(&xfer))
280 363 {
281 mutex_unlock(&desc->m); 364 return data_count - xfer.xfer.txcount;
365 }
282 366
283 return data_count; 367 return -1;
284} 368}
285 369
286void i2c_init(void) 370void INIT_ATTR i2c_init(void)
287{ 371{
288 int i;
289
290 /* Do one-time inits for each module that will be used - leave 372 /* Do one-time inits for each module that will be used - leave
291 * module disabled and unclocked until something wants it */ 373 * module disabled and unclocked until something wants it. */
292 for (i = 0; i < I2C_NUM_I2C; i++) 374 for (int i = 0; i < I2C_NUM_I2C; i++)
293 { 375 {
294 struct i2c_module_descriptor *const desc = &i2c_descs[i]; 376 struct i2c_module_descriptor * const desc = &i2c_descs[i];
295 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT); 377 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT);
296 mutex_init(&desc->m);
297 semaphore_init(&desc->complete, 1, 0);
298 desc->base[I2CR] = 0; 378 desc->base[I2CR] = 0;
299 ccm_module_clock_gating(desc->cg, CGM_OFF); 379 ccm_module_clock_gating(desc->cg, CGM_OFF);
300 } 380 }
301} 381}
302 382
383/* Enable or disable the node - modules will be switched on/off accordingly. */
303void i2c_enable_node(struct i2c_node *node, bool enable) 384void i2c_enable_node(struct i2c_node *node, bool enable)
304{ 385{
305 struct i2c_module_descriptor *const desc = &i2c_descs[node->num]; 386 struct i2c_module_descriptor * const desc = &i2c_descs[node->num];
306
307 mutex_lock(&desc->m);
308 387
309 if (enable) 388 if (enable)
310 { 389 {
@@ -312,6 +391,8 @@ void i2c_enable_node(struct i2c_node *node, bool enable)
312 { 391 {
313 /* First enable */ 392 /* First enable */
314 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT); 393 ccm_module_clock_gating(desc->cg, CGM_ON_RUN_WAIT);
394 desc->base[I2CR] = I2C_I2CR_IEN;
395 desc->base[I2SR] = 0;
315 avic_enable_int(desc->ints, INT_TYPE_IRQ, INT_PRIO_DEFAULT, 396 avic_enable_int(desc->ints, INT_TYPE_IRQ, INT_PRIO_DEFAULT,
316 desc->handler); 397 desc->handler);
317 } 398 }
@@ -321,24 +402,16 @@ void i2c_enable_node(struct i2c_node *node, bool enable)
321 if (desc->enable > 0 && --desc->enable == 0) 402 if (desc->enable > 0 && --desc->enable == 0)
322 { 403 {
323 /* Last enable */ 404 /* Last enable */
324 while (desc->base[I2SR] & I2C_I2SR_IBB); /* Wait for STOP */ 405
406 /* Wait for last tranfer */
407 while (*(void ** volatile)&desc->head != NULL);
408
409 /* Wait for STOP */
410 while (desc->base[I2SR] & I2C_I2SR_IBB);
411
325 desc->base[I2CR] &= ~I2C_I2CR_IEN; 412 desc->base[I2CR] &= ~I2C_I2CR_IEN;
326 avic_disable_int(desc->ints); 413 avic_disable_int(desc->ints);
327 ccm_module_clock_gating(desc->cg, CGM_OFF); 414 ccm_module_clock_gating(desc->cg, CGM_OFF);
328 } 415 }
329 } 416 }
330
331 mutex_unlock(&desc->m);
332}
333
334void i2c_lock_node(struct i2c_node *node)
335{
336 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
337 mutex_lock(&desc->m);
338}
339
340void i2c_unlock_node(struct i2c_node *node)
341{
342 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
343 mutex_unlock(&desc->m);
344} 417}
diff --git a/firmware/target/arm/imx31/i2c-imx31.h b/firmware/target/arm/imx31/i2c-imx31.h
index a29c7ce96b..f73a8e6320 100644
--- a/firmware/target/arm/imx31/i2c-imx31.h
+++ b/firmware/target/arm/imx31/i2c-imx31.h
@@ -50,15 +50,46 @@ struct i2c_node
50 unsigned char addr; /* Slave address on module */ 50 unsigned char addr; /* Slave address on module */
51}; 51};
52 52
53struct i2c_transfer_desc;
54
55typedef void (*i2c_transfer_cb_fn_type)(struct i2c_transfer_desc *);
56
57/* Basic transfer descriptor for normal asynchronous read/write */
58struct i2c_transfer_desc
59{
60 struct i2c_node *node;
61 const unsigned char *txdata;
62 int txcount;
63 unsigned char *rxdata;
64 int rxcount;
65 i2c_transfer_cb_fn_type callback;
66 struct i2c_transfer_desc *next;
67};
68
69/* Extended transfer descriptor for synchronous read/write that handles
70 thread wait and wakeup */
71struct i2c_sync_transfer_desc
72{
73 struct i2c_transfer_desc xfer;
74 struct semaphore sema;
75};
76
77/* One-time init of i2c driver */
53void i2c_init(void); 78void i2c_init(void);
54/* Enable or disable the node - modules will be switch on/off accordingly. */ 79
80/* Enable or disable the node - modules will be switched on/off accordingly. */
55void i2c_enable_node(struct i2c_node *node, bool enable); 81void i2c_enable_node(struct i2c_node *node, bool enable);
56/* If addr < 0, then raw read */ 82
57int i2c_read(struct i2c_node *node, int addr, unsigned char *data, int count); 83/* Send and/or receive data on the specified node asynchronously */
58int i2c_write(struct i2c_node *node, const unsigned char *data, int count); 84bool i2c_transfer(struct i2c_transfer_desc *xfer);
59/* Gain mutually-exclusive access to the node and module to perform multiple 85
60 * operations atomically */ 86/* Read bytes from a device on the I2C bus, with optional sub-addressing
61void i2c_lock_node(struct i2c_node *node); 87 * If addr < 0, then raw read without sub-addressing */
62void i2c_unlock_node(struct i2c_node *node); 88int i2c_read(struct i2c_node *node, int addr, unsigned char *data,
89 int data_count);
90
91/* Write bytes to a device on the I2C bus */
92int i2c_write(struct i2c_node *node, const unsigned char *data,
93 int data_count);
63 94
64#endif /* I2C_IMX31_H */ 95#endif /* I2C_IMX31_H */