diff options
-rw-r--r-- | firmware/target/arm/imx31/i2c-imx31.c | 373 | ||||
-rw-r--r-- | firmware/target/arm/imx31/i2c-imx31.h | 47 |
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); | |||
46 | static struct i2c_module_descriptor | 46 | static 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 | ||
88 | static void i2c_interrupt(enum i2c_module_number i2c) | 85 | |
86 | /* Actually begin the session at the queue head */ | ||
87 | static 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 | |||
131 | static 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 | { |
128 | i2c_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 | ||
162 | i2c_stop: | 233 | break; |
163 | /* Generate STOP signal */ | 234 | } |
164 | base[I2CR] &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN); | ||
165 | i2c_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) |
171 | static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void) | 238 | static __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) |
177 | static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void) | 244 | static __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) |
183 | static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void) | 250 | static __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 | ||
189 | static 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) | 257 | bool 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 | ||
240 | int i2c_read(struct i2c_node *node, int reg, | 300 | /** Synchronous transfers support **/ |
241 | unsigned char *data, int data_count) | 301 | static 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); | 306 | static 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 | |||
311 | int 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 | ||
269 | int i2c_write(struct i2c_node *node, const unsigned char *data, int data_count) | 348 | int 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 | ||
286 | void i2c_init(void) | 370 | void 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. */ | ||
303 | void i2c_enable_node(struct i2c_node *node, bool enable) | 384 | void 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 | |||
334 | void 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 | |||
340 | void 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 | ||
53 | struct i2c_transfer_desc; | ||
54 | |||
55 | typedef void (*i2c_transfer_cb_fn_type)(struct i2c_transfer_desc *); | ||
56 | |||
57 | /* Basic transfer descriptor for normal asynchronous read/write */ | ||
58 | struct 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 */ | ||
71 | struct i2c_sync_transfer_desc | ||
72 | { | ||
73 | struct i2c_transfer_desc xfer; | ||
74 | struct semaphore sema; | ||
75 | }; | ||
76 | |||
77 | /* One-time init of i2c driver */ | ||
53 | void i2c_init(void); | 78 | void 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. */ | ||
55 | void i2c_enable_node(struct i2c_node *node, bool enable); | 81 | void i2c_enable_node(struct i2c_node *node, bool enable); |
56 | /* If addr < 0, then raw read */ | 82 | |
57 | int i2c_read(struct i2c_node *node, int addr, unsigned char *data, int count); | 83 | /* Send and/or receive data on the specified node asynchronously */ |
58 | int i2c_write(struct i2c_node *node, const unsigned char *data, int count); | 84 | bool 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 |
61 | void i2c_lock_node(struct i2c_node *node); | 87 | * If addr < 0, then raw read without sub-addressing */ |
62 | void i2c_unlock_node(struct i2c_node *node); | 88 | int 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 */ | ||
92 | int 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 */ |