1 //==========================================================================
3 // devs/i2c/m68k/mcf52xx/current/src/i2c_mcf52xx.c
5 // I2C driver for Motorola coldfire processors
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2005, 2006 eCosCentric Ltd.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 // -------------------------------------------
36 //####ECOSGPLCOPYRIGHTEND####
37 //==========================================================================
38 //#####DESCRIPTIONBEGIN####
40 // Author(s): Uwe Kindler, Bart Veer
43 // Description: I2C driver for motorola coldfire processor
44 //####DESCRIPTIONEND####
45 //==========================================================================
47 #include <pkgconf/system.h>
48 #include <pkgconf/devs_i2c_mcf52xx.h>
50 #include <cyg/infra/cyg_type.h>
51 #include <cyg/infra/cyg_ass.h>
52 #include <cyg/infra/diag.h>
53 #include <cyg/io/i2c.h>
54 #include <cyg/io/i2c_mcf52xx.h>
55 #include <cyg/hal/hal_arch.h>
56 #include <cyg/hal/hal_io.h>
57 #include <cyg/hal/hal_intr.h>
58 #include <cyg/hal/drv_api.h>
60 // Optimize for the case of a single bus device, while still allowing
62 #ifndef CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES
63 # define I2C_BASE(_extra_) (cyg_uint8*)HAL_MCF52xx_I2C_SINGLETON_BASE
64 # define I2C_ISRVEC(_extra_) HAL_MCF52xx_I2C_SINGLETON_ISRVEC
65 # define I2C_ISRPRI(_extra_) HAL_MCF52xx_I2C_SINGLETON_ISRPRI
66 # define I2C_FDR(_extra_) HAL_MCF52xx_I2C_SINGLETON_FDR
68 # define I2C_BASE(_extra_) ((_extra_)->i2c_base)
69 # define I2C_ISRVEC(_extra_) ((_extra_)->i2c_isrvec)
70 # define I2C_ISRPRI(_extra_) ((_extra_)->i2c_isrpri)
71 # define I2C_FDR(_extra_) ((_extra_)->i2c_fdr)
74 // If building for a singleton but the macros are no defined, assume
75 // the I2C support is conditional on a disabled platform HAL
76 // configuration option. This handles the common case of an I2C bus
77 // accessed only via an expansion connector.
78 #if defined(CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES) || defined(HAL_MCF52xx_I2C_SINGLETON_BASE)
80 // ----------------------------------------------------------------------------
81 // Interrupt handling and polling
83 // The MCF52xx I2C bus device does not have a fifo or any kind of DMA
84 // capability, so can generate interrupts at a very high rate: ~10K
85 // interrupts per second if the bus is running at the standard 100KHz,
86 // or 50K for a high-speed 400KHz bus. To keep the cpu load down to
87 // something vaguely reasonable as much work as possible has to be
88 // done in the ISR, with the DSR used only for completion.
90 mcf52xx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data)
92 cyg_mcf52xx_i2c_extra* extra = (cyg_mcf52xx_i2c_extra*)data;
94 cyg_uint8* base = I2C_BASE(extra);
95 cyg_uint32 result = CYG_ISR_HANDLED;
97 // Read the current status, then clear the interrupt and
98 // arbitration-lost flags. No later code will look at the
100 HAL_READ_UINT8( base + HAL_MCF52xx_I2C_SR_OFF, sr);
101 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, 0x00);
103 // What to do next depends on the current transfer mode.
104 if (CYG_MCF52xx_I2C_XFER_MODE_TX == extra->i2c_mode) {
105 // We are in a transmit, or sending the address byte just
106 // before a transmit.
107 if (sr & HAL_MCF52xx_I2C_SR_IAL) {
108 // Lost the bus, abort the transfer. count has already been
109 // decremented. Assume the byte did not actually arrive.
110 extra->i2c_count += 1;
111 result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
112 } else if (sr & HAL_MCF52xx_I2C_SR_RXAK) {
113 // This byte has been sent but the device cannot accept
114 // any more. The nack must be remembered. Otherwise if
115 // we got a nack for the last byte in a tx then the
116 // calling code will think the entire tx succeeded,
117 // and there will be problems if the next call is
118 // another tx without a repeated start.
119 extra->i2c_got_nack = 1;
120 result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
121 } else if (0 == extra->i2c_count) {
122 // No more bytes to send.
123 result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
125 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, *(extra->i2c_data.i2c_tx_data));
126 extra->i2c_data.i2c_tx_data += 1;
127 extra->i2c_count -= 1;
129 } else if (CYG_MCF52xx_I2C_XFER_MODE_RX == extra->i2c_mode) {
130 if (sr & HAL_MCF52xx_I2C_SR_IAL) {
131 // Lost the bus? Maybe a spurious stop
132 result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
134 if (extra->i2c_send_nack && (2 == extra->i2c_count)) {
135 // Received one, one more to go, and that one should be nacked.
136 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
137 HAL_MCF52xx_I2C_CR_IEN |
138 HAL_MCF52xx_I2C_CR_IIEN |
139 HAL_MCF52xx_I2C_CR_MSTA |
140 HAL_MCF52xx_I2C_CR_TXAK);
141 } else if (1 == extra->i2c_count) {
142 // Received the last byte. The docs say to send a stop,
143 // but there may be another transaction_rx() call. We
144 // cannot just read DR again, that would trigger another
145 // read. So instead switch to transmit mode for now,
146 // which should cause the h/w to wait until a byte is
148 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
149 HAL_MCF52xx_I2C_CR_IEN |
150 HAL_MCF52xx_I2C_CR_IIEN |
151 HAL_MCF52xx_I2C_CR_MSTA |
152 HAL_MCF52xx_I2C_CR_MTX);
153 result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
156 HAL_READ_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, dr);
157 *(extra->i2c_data.i2c_rx_data) = dr;
158 extra->i2c_data.i2c_rx_data += 1;
159 extra->i2c_count -= 1;
161 } else if (CYG_MCF52xx_I2C_XFER_MODE_STARTRX == extra->i2c_mode) {
162 // Start followed by RX. The address byte has been sent, we
163 // need to switch to receiving.
164 if (sr & HAL_MCF52xx_I2C_SR_IAL) {
165 // Looks like no device acknowledged the address.
166 result = CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
168 extra->i2c_mode = CYG_MCF52xx_I2C_XFER_MODE_RX;
169 if (extra->i2c_send_nack && (1 == extra->i2c_count)) {
170 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
171 HAL_MCF52xx_I2C_CR_IEN |
172 HAL_MCF52xx_I2C_CR_IIEN |
173 HAL_MCF52xx_I2C_CR_MSTA |
174 HAL_MCF52xx_I2C_CR_TXAK);
176 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
177 HAL_MCF52xx_I2C_CR_IEN |
178 HAL_MCF52xx_I2C_CR_IIEN |
179 HAL_MCF52xx_I2C_CR_MSTA);
181 // This dummy read causes the next rx to start
182 HAL_READ_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, dr);
185 // Invalid state? Some kind of spurious interrupt? Just ignore
187 CYG_FAIL("I2C spurious interrupt");
190 // NOTE: this will acknowledge the interrupt even in polled mode.
191 // Probably harmless. Using I2C_ISRVEC rather than the vec arg
192 // means a constant number for the singleton case, which may
193 // allow the HAL to optimize the acknowledge away completely.
194 HAL_INTERRUPT_ACKNOWLEDGE(I2C_ISRVEC(extra));
199 mcf52xx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
201 cyg_mcf52xx_i2c_extra* extra = (cyg_mcf52xx_i2c_extra*)data;
202 extra->i2c_completed = 1;
203 cyg_drv_cond_signal(&(extra->i2c_wait));
206 // A transfer has been started. Wait for completion, allowing for both
207 // polled and interrupt-driven mode.
209 mcf52xx_i2c_doit(cyg_mcf52xx_i2c_extra* extra)
211 cyg_uint8* base = I2C_BASE(extra);
215 HAL_QUERY_INTERRUPTS(ints_state);
216 if (((ints_state >> 8) & 0x07) > CYGNUM_HAL_INTERRUPT_DEFAULT_IPL_LEVEL) {
217 // Interrupts are currently disabled. We'll have to poll.
219 HAL_READ_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, sr);
220 if (sr & HAL_MCF52xx_I2C_SR_IIF) {
221 if (CYG_ISR_CALL_DSR & mcf52xx_i2c_isr(I2C_ISRVEC(extra), (cyg_addrword_t)extra)) {
227 cyg_drv_mutex_lock(&(extra->i2c_lock));
229 while (! extra->i2c_completed) {
230 cyg_drv_cond_wait(&(extra->i2c_wait));
232 cyg_drv_dsr_unlock();
233 cyg_drv_mutex_unlock(&(extra->i2c_lock));
238 mcf52xx_i2c_send_start(cyg_mcf52xx_i2c_extra* extra, int address)
240 cyg_uint8* base = I2C_BASE(extra);
243 // This may be a repeated start or the beginning of a transaction.
244 // If the former then we still own the bus.
245 if (!extra->i2c_owner) {
246 // The bus is currently in slave mode. See if another master
247 // currently owns the bus and if so fail immediately. It is up
248 // to higher level code to decide when to retry. Alternatively
249 // if the bus has somehow got stuck in busy mode it is again
250 // up to higher level code to sort things out.
251 HAL_READ_UINT8(I2C_BASE(extra) + HAL_MCF52xx_I2C_SR_OFF, sr);
252 if (sr & HAL_MCF52xx_I2C_SR_IBB) {
256 // Now we can put the bus into master mode
257 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
258 HAL_MCF52xx_I2C_CR_IEN |
259 HAL_MCF52xx_I2C_CR_IIEN |
260 HAL_MCF52xx_I2C_CR_MSTA | // This implicitly generates the start
261 HAL_MCF52xx_I2C_CR_MTX); // The address byte needs to be transmitted.
262 extra->i2c_owner = 1;
264 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
265 HAL_MCF52xx_I2C_CR_IEN |
266 HAL_MCF52xx_I2C_CR_IIEN |
267 HAL_MCF52xx_I2C_CR_MSTA | // Already set so no start generated by this
268 HAL_MCF52xx_I2C_CR_MTX |
269 HAL_MCF52xx_I2C_CR_RSTA); // Repeated start
272 // Any previous nack is no longer relevant. If the device cannot accept
273 // more data it will nack the address.
274 extra->i2c_got_nack = 0;
275 // Now send the address. The rest of the transfer is handled by the
276 // interrupt/polling code.
277 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, address);
282 mcf52xx_i2c_stopit(cyg_mcf52xx_i2c_extra* extra)
284 // If we still own the bus this releases it (by clearing MSTA) and
285 // generating a stop. If we have lost arbitration then this write
286 // has no effect (other than disabling interrupts). Either way the
287 // bus should end up in a consistent state.
288 HAL_WRITE_UINT8(I2C_BASE(extra) + HAL_MCF52xx_I2C_CR_OFF, HAL_MCF52xx_I2C_CR_IEN);
289 extra->i2c_lost_arb = 0;
290 extra->i2c_owner = 0;
291 extra->i2c_mode = CYG_MCF52xx_I2C_XFER_MODE_INVALID;
294 // ----------------------------------------------------------------------------
295 // The functions needed for all I2C devices.
298 cyg_mcf52xx_i2c_init(struct cyg_i2c_bus* bus)
300 cyg_mcf52xx_i2c_extra* extra = (cyg_mcf52xx_i2c_extra*)bus->i2c_extra;
302 cyg_uint8* base = I2C_BASE(extra);
304 cyg_drv_mutex_init(&extra->i2c_lock);
305 cyg_drv_cond_init(&extra->i2c_wait, &extra->i2c_lock);
306 cyg_drv_interrupt_create(I2C_ISRVEC(extra),
308 (cyg_addrword_t) extra,
311 &(extra->i2c_interrupt_handle),
312 &(extra->i2c_interrupt_data));
313 cyg_drv_interrupt_attach(extra->i2c_interrupt_handle);
315 // Before unmasking the interrupt sort out the hardware.
317 // The bus frequency is set by the platform HAL or user, since
318 // it depends on what mixture of devices are present on the bus.
319 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_FDR_OFF, I2C_FDR(extra));
320 // The device will operate in slave mode when idle. If there is
321 // another bus master then the coldfire might accidentally accept
322 // requests intended for another device. Address 0 is installed
323 // as the slave address. This is the General Call address, used
324 // for broadcasting. It might be better to use another address
325 // like an Hs-mode one, but conflicts are still possible.
326 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_ADR_OFF, 0x0);
327 // Enable the I2C device but do not start any transfers and
328 // leave interrupts disabled.
329 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, HAL_MCF52xx_I2C_CR_IEN);
331 // As per the documentation, if IBB is set then issue a stop. It
332 // is not really clear this is the right thing to do in
333 // multimaster setups, if another master happens to start a
334 // transfer at this exact time. Presumably it solves more problems
335 // than it might cause.
336 HAL_READ_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, reg);
337 if (reg & HAL_MCF52xx_I2C_SR_IBB) {
338 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, 0x0000);
339 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, 0x00A0);
340 HAL_READ_UINT8( base + HAL_MCF52xx_I2C_DR_OFF, reg);
341 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, 0x0000);
342 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, 0x0000);
344 // Don't forget to reenable the device.
345 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF, HAL_MCF52xx_I2C_CR_IEN);
348 // Clear any pending conditions including interrupts.
349 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_SR_OFF, 0);
351 // Interrupts can now be safely unmasked
352 HAL_INTERRUPT_UNMASK(I2C_ISRVEC(extra));
356 cyg_mcf52xx_i2c_tx(const cyg_i2c_device* dev, cyg_bool send_start, const cyg_uint8* tx_data, cyg_uint32 count, cyg_bool send_stop)
358 cyg_mcf52xx_i2c_extra* extra = (cyg_mcf52xx_i2c_extra*)dev->i2c_bus->i2c_extra;
360 extra->i2c_count = count;
361 if (! extra->i2c_lost_arb) {
362 extra->i2c_completed = 0;
363 extra->i2c_mode = CYG_MCF52xx_I2C_XFER_MODE_TX;
366 extra->i2c_data.i2c_tx_data = tx_data;
367 if (! mcf52xx_i2c_send_start(extra, (dev->i2c_address << 1) | 0x00)) {
368 diag_printf("send_start failed\n");
371 mcf52xx_i2c_doit(extra);
372 } else if ( !extra->i2c_got_nack) {
373 // We are in the middle of a transaction and not
374 // generating a repeated start, so the device must already
375 // be set up for writes.
376 extra->i2c_data.i2c_tx_data = &(tx_data[1]);
377 extra->i2c_count = count - 1;
378 HAL_WRITE_UINT8(I2C_BASE(extra) + HAL_MCF52xx_I2C_DR_OFF, *tx_data);
379 mcf52xx_i2c_doit(extra);
383 mcf52xx_i2c_stopit(extra);
386 // tx() should return the number of bytes actually transmitted.
387 // ISR() increments extra->count after a failure, which leads to
388 // an edge condition when send_start and there is no acknowledgment
389 // of the address byte.
390 if (extra->i2c_count > count) {
393 return count - extra->i2c_count;
397 cyg_mcf52xx_i2c_rx(const cyg_i2c_device* dev, cyg_bool send_start, cyg_uint8* rx_data, cyg_uint32 count, cyg_bool send_nack, cyg_bool send_stop)
399 cyg_mcf52xx_i2c_extra* extra = (cyg_mcf52xx_i2c_extra*)dev->i2c_bus->i2c_extra;
400 cyg_uint8* base = I2C_BASE(extra);
403 extra->i2c_count = count;
404 extra->i2c_send_nack = send_nack;
406 if (! extra->i2c_lost_arb) {
407 extra->i2c_completed = 0;
408 extra->i2c_data.i2c_rx_data = rx_data;
410 extra->i2c_mode = CYG_MCF52xx_I2C_XFER_MODE_STARTRX;
411 if (! mcf52xx_i2c_send_start(extra, (dev->i2c_address << 1) | 0x01) ) {
415 // In the middle of a transaction. The previous transfer
416 // will have left the device in tx mode.
417 extra->i2c_mode = CYG_MCF52xx_I2C_XFER_MODE_RX;
418 if (send_nack && (1 == count)) {
419 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
420 HAL_MCF52xx_I2C_CR_IEN |
421 HAL_MCF52xx_I2C_CR_IIEN |
422 HAL_MCF52xx_I2C_CR_MSTA |
423 HAL_MCF52xx_I2C_CR_TXAK);
425 HAL_WRITE_UINT8(base + HAL_MCF52xx_I2C_CR_OFF,
426 HAL_MCF52xx_I2C_CR_IEN |
427 HAL_MCF52xx_I2C_CR_IIEN |
428 HAL_MCF52xx_I2C_CR_MSTA);
430 // So reading the data register here should get the device
431 // reading the next byte.
432 HAL_READ_UINT8(base + HAL_MCF52xx_I2C_DR_OFF, discard);
434 mcf52xx_i2c_doit(extra);
437 mcf52xx_i2c_stopit(extra);
439 return count - extra->i2c_count;
443 cyg_mcf52xx_i2c_stop(const cyg_i2c_device* dev)
445 cyg_mcf52xx_i2c_extra* extra = (cyg_mcf52xx_i2c_extra*)dev->i2c_bus->i2c_extra;
446 mcf52xx_i2c_stopit(extra);
449 #endif // defined(CYGHWR_DEVS_I2C_MCF52xx_MULTIPLE_BUSES) || defined(HAL_MCF52xx_I2C_SINGLETON_BASE)
450 //---------------------------------------------------------------------------