OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [i2c/] [cortexm/] [a2fxxx/] [current/] [src/] [i2c_a2fxxx.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      i2c_a2fxxx.c
4
//
5
//      I2C driver for Smartfusion Cortex M3 microcontroller
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2011 Free Software Foundation, Inc.
12
//
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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     ccoutand
43
// Contributors:
44
// Date:          2011-01-18
45
// Original:      Uwe Kindler, Bart Veer
46
//                I2C driver for motorola coldfire processor
47
// Description:   I2C driver for Smartfusion Cortex M3 microcontroller
48
//                The RX part of the driver has not been tested.
49
//
50
//####DESCRIPTIONEND####
51
//==========================================================================
52
 
53
#include <pkgconf/system.h>
54
 
55
#include <cyg/infra/cyg_type.h>
56
#include <cyg/infra/cyg_ass.h>
57
#include <cyg/infra/diag.h>
58
#include <cyg/io/i2c.h>
59
#include <cyg/io/i2c_a2fxxx.h>
60
#include <cyg/hal/hal_arch.h>
61
#include <cyg/hal/hal_io.h>
62
#include <cyg/hal/hal_intr.h>
63
#include <cyg/hal/drv_api.h>
64
 
65
#ifdef CYGDBG_DEVS_I2C_CORTEXM_A2FXXX_TRACE
66
# define I2C_TRACE(args...) diag_printf(args)
67
#else
68
# define I2C_TRACE(args...)
69
#endif
70
 
71
#define I2C_DAT(_base_)       (_base_ + CYGHWR_HAL_A2FXXX_I2C_DATA)
72
#define I2C_ADR(_base_)       (_base_ + CYGHWR_HAL_A2FXXX_I2C_ADDR)
73
#define I2C_SR(_base_)        (_base_ + CYGHWR_HAL_A2FXXX_I2C_STATUS)
74
#define I2C_CR(_base_)        (_base_ + CYGHWR_HAL_A2FXXX_I2C_CTRL)
75
#define I2C_FREQ(_base_)      (_base_ + CYGHWR_HAL_A2FXXX_I2C_FREQ)
76
#define I2C_SMBUS(_base_)     (_base_ + CYGHWR_HAL_A2FXXX_I2C_SMBUS)
77
#define I2C_GLITCH(_base_)    (_base_ + CYGHWR_HAL_A2FXXX_I2C_GLITCH)
78
 
79
// Bit-band definition
80
#define I2C_CR_CR0(_base_)    (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
81
                               ( 0*sizeof(cyg_uint32) ) )
82
#define I2C_CR_CR1(_base_)    (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
83
                               ( 1*sizeof(cyg_uint32) ) )
84
#define I2C_CR_AA(_base_)     (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
85
                               ( 2*sizeof(cyg_uint32) ) )
86
#define I2C_CR_SI(_base_)     (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
87
                               ( 3*sizeof(cyg_uint32) ) )
88
#define I2C_CR_STO(_base_)    (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
89
                               ( 4*sizeof(cyg_uint32) ) )
90
#define I2C_CR_STA(_base_)    (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
91
                               ( 5*sizeof(cyg_uint32) ) )
92
#define I2C_CR_ENS1(_base_)   (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
93
                               ( 6*sizeof(cyg_uint32) ) )
94
#define I2C_CR_CR2(_base_)    (_base_ + ( CYGHWR_HAL_A2FXXX_I2C_CTRL << 5 ) +  \
95
                               ( 7*sizeof(cyg_uint32) ) )
96
 
97
#define I2C_MTX_STATE(x)      CYGHWR_HAL_A2FXXX_I2C_STATUS_MTX_##x
98
#define I2C_MRX_STATE(x)      CYGHWR_HAL_A2FXXX_I2C_STATUS_MRX_##x
99
 
100
// Divider coefficient
101
static const unsigned int i2c_div[] = {
102
    256,
103
    224,
104
    192,
105
    160,
106
    960,
107
    120,
108
    60,
109
    8,
110
 
111
};
112
 
113
static cyg_uint32
114
a2fxxx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data)
115
{
116
    a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) data;
117
    cyg_uint32      result = CYG_ISR_HANDLED;
118
    cyg_uint32      sr,
119
                    dr;
120
    cyg_uint8       tx_data = *extra->i2c_data.i2c_tx_data;
121
    cyg_uint32      cr = 0;
122
 
123
    // Read the current status of the I2C
124
    HAL_READ_UINT32(I2C_SR(extra->i2c_base), sr);
125
    HAL_READ_UINT32(I2C_CR(extra->i2c_base), cr);
126
 
127
    // What to do next depends on the current transfer mode.
128
    if (A2FXXX_I2C_XFER_MODE_TX == extra->i2c_mode) {
129
        I2C_TRACE("I2C: TX IRQ handling -> 0x%x\n", sr);
130
        switch (sr) {
131
        // Start/Repeated start, write the slave address and clear the
132
        // START and SI bits
133
        case I2C_MTX_STATE(START):
134
        case I2C_MTX_STATE(REPEAT_START):
135
            HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), extra->slave_addr);
136
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_STA;
137
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
138
            break;
139
        // ACK is received for the address or data, keep sending
140
        // START and SI bits
141
        case I2C_MTX_STATE(ADDR_ACK):
142
        case I2C_MTX_STATE(DATA_ACK):
143
            if (0 == extra->i2c_count) {
144
                if (extra->send_stop) {
145
                    cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO;
146
                    cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
147
                } else {
148
                    // For repeated start, we must disable interrupt
149
                    extra->i2c_isr_mask = true;
150
                }
151
                // No more bytes to send.
152
                result |= CYG_ISR_CALL_DSR;
153
            } else {
154
                // Send byte
155
                HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base),
156
                                 (cyg_uint32)tx_data);
157
                extra->i2c_data.i2c_tx_data += 1;
158
                extra->i2c_count -= 1;
159
                cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
160
            }
161
            break;
162
        case I2C_MTX_STATE(ARBLOST):
163
        case I2C_MTX_STATE(DATA_NACK):
164
            // Lost the bus, abort the transfer. count has already been
165
            // decremented. Assume the byte did not actually arrive.
166
            extra->i2c_count += 1;
167
        case I2C_MTX_STATE(ADDR_NACK):
168
            // For all error type, clear interrupt and send stop bit
169
            cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO;
170
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
171
            extra->i2c_got_nack = 1;
172
            result |= CYG_ISR_CALL_DSR;
173
            break;
174
        default:
175
            HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id);
176
            return result;
177
        }
178
    } else if (A2FXXX_I2C_XFER_MODE_RX == extra->i2c_mode) {
179
        I2C_TRACE("I2C: RX IRQ handling -> 0x%x\n", sr);
180
        cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_AA;
181
        switch (sr) {
182
        // Start/Repeated start, write the slave address and clear the
183
        // START and SI bits
184
        case I2C_MRX_STATE(START):
185
        case I2C_MRX_STATE(REPEAT_START):
186
            HAL_WRITE_UINT32(I2C_DAT(extra->i2c_base), extra->slave_addr);
187
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_STA;
188
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
189
            break;
190
        // ACK is received for the address
191
        case I2C_MRX_STATE(ADDR_ACK):
192
            if (extra->i2c_count > 1) {
193
                cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_AA;
194
            }
195
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
196
            break;
197
        // Receive data
198
        case I2C_MRX_STATE(DATA_ACK):
199
        case I2C_MRX_STATE(DATA_NACK):
200
            cr &= ~CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
201
            if (extra->i2c_count > 2) {
202
                cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_AA;
203
            }
204
            if (1 == extra->i2c_count) {
205
                if (extra->send_stop) {
206
                    cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO;
207
                } else {
208
                    // For repeated start, we must disable interrupt
209
                    cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_SI;
210
                    extra->i2c_isr_mask = true;
211
                }
212
                // Received the last byte.
213
                result |= CYG_ISR_CALL_DSR;
214
            }
215
            HAL_READ_UINT32(I2C_DAT(extra->i2c_base), dr);
216
            *(extra->i2c_data.i2c_rx_data) = (cyg_uint8)dr;
217
            extra->i2c_data.i2c_rx_data += 1;
218
            extra->i2c_count -= 1;
219
            break;
220
        case I2C_MRX_STATE(ARBLOST):
221
        case I2C_MRX_STATE(ADDR_NACK):
222
            // Lost the bus? Maybe a spurious stop
223
            cr |= CYGHWR_HAL_A2FXXX_I2C_CTRL_STO;
224
            result |= CYG_ISR_CALL_DSR;
225
            break;
226
        default:
227
            HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id);
228
            return result;
229
        }
230
    } else {
231
        // Invalid state? Some kind of spurious interrupt?
232
        // Just ignore it.
233
        I2C_TRACE("I2C spurious interrupt\n");
234
    }
235
 
236
    HAL_WRITE_UINT32(I2C_CR(extra->i2c_base), cr);
237
 
238
    HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id);
239
 
240
    if (extra->i2c_isr_mask)
241
        HAL_INTERRUPT_MASK(extra->i2c_isr_id);
242
 
243
    return result;
244
}
245
 
246
 
247
static void
248
a2fxxx_i2c_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
249
{
250
    a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) data;
251
    extra->i2c_completed = 1;
252
    cyg_drv_cond_signal(&(extra->i2c_wait));
253
}
254
 
255
 
256
// A transfer has been started. Wait for completion
257
static inline void
258
a2fxxx_i2c_doit(a2fxxx_i2c_extra * extra)
259
{
260
    cyg_drv_mutex_lock(&(extra->i2c_lock));
261
    cyg_drv_dsr_lock();
262
    while (!extra->i2c_completed) {
263
        cyg_drv_cond_wait(&(extra->i2c_wait));
264
    }
265
    cyg_drv_dsr_unlock();
266
    cyg_drv_mutex_unlock(&(extra->i2c_lock));
267
}
268
 
269
 
270
static inline void
271
a2fxxx_i2c_stopit(a2fxxx_i2c_extra * extra)
272
{
273
    extra->i2c_lost_arb = 0;
274
    extra->i2c_owner = 0;
275
    extra->i2c_mode = A2FXXX_I2C_XFER_MODE_INVALID;
276
}
277
 
278
 
279
void
280
a2fxxx_i2c_stop(const cyg_i2c_device * dev)
281
{
282
    a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) dev->i2c_bus->i2c_extra;
283
    a2fxxx_i2c_stopit(extra);
284
}
285
 
286
 
287
cyg_uint32
288
a2fxxx_i2c_tx(const cyg_i2c_device * dev, cyg_bool send_start,
289
              const cyg_uint8 *tx_data, cyg_uint32 count, cyg_bool send_stop)
290
{
291
    a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) dev->i2c_bus->i2c_extra;
292
    extra->send_stop = send_stop;
293
    extra->send_start = send_start;
294
    extra->i2c_count = count;
295
    extra->slave_addr = ((dev->i2c_address << 1) | 0x00);
296
    cyg_uint32      si = 0;
297
 
298
    if (!extra->i2c_lost_arb) {
299
        extra->i2c_completed = 0;
300
        extra->i2c_mode = A2FXXX_I2C_XFER_MODE_TX;
301
 
302
        if (send_start || !extra->i2c_got_nack) {
303
            I2C_TRACE
304
                ("I2C: TX to %2x, data %2x, count: %4d, START flag: %s, STOP flag: %s\n",
305
                 dev->i2c_address, *tx_data, count,
306
                 (send_start == true) ? "true" : "false",
307
                 (send_stop == true) ? "true" : "false");
308
            extra->i2c_data.i2c_tx_data = tx_data;
309
            HAL_READ_UINT32(I2C_CR_SI(extra->i2c_base_bb), si);
310
            // Set start bit
311
            HAL_WRITE_UINT32(I2C_CR_STA(extra->i2c_base_bb),
312
                             CYGHWR_HAL_A2FXXX_BITSET);
313
            // For repeated start, we need to clear the interrupt
314
            if (si != 0) {
315
                HAL_WRITE_UINT32(I2C_CR_SI(extra->i2c_base_bb),
316
                                 CYGHWR_HAL_A2FXXX_BITCLEAR);
317
                HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id);
318
            }
319
            // For repeated start, we need to un-mask the interrupt
320
            if (extra->i2c_isr_mask) {
321
                extra->i2c_isr_mask = false;
322
                HAL_INTERRUPT_UNMASK(extra->i2c_isr_id);
323
            }
324
            a2fxxx_i2c_doit(extra);
325
        }
326
 
327
    }
328
    if (send_stop) {
329
        I2C_TRACE("I2C: TX send stop\n");
330
        a2fxxx_i2c_stopit(extra);
331
    }
332
 
333
    I2C_TRACE("I2C: TX count %d\n", extra->i2c_count);
334
 
335
    // tx() should return the number of bytes actually transmitted.
336
    // ISR() increments extra->count after a failure, which leads to
337
    // an edge condition when send_start and there is no acknowledgment
338
    // of the address byte.
339
    if (extra->i2c_count > count) {
340
        return 0;
341
    }
342
 
343
    return count - extra->i2c_count;
344
}
345
 
346
 
347
cyg_uint32
348
a2fxxx_i2c_rx(const cyg_i2c_device * dev, cyg_bool send_start,
349
              cyg_uint8 *rx_data, cyg_uint32 count, cyg_bool send_nack,
350
              cyg_bool send_stop)
351
{
352
    a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) dev->i2c_bus->i2c_extra;
353
    extra->i2c_send_nack = send_nack;
354
    extra->i2c_count = count;
355
    extra->send_stop = send_stop;
356
    extra->send_start = send_start;
357
    extra->slave_addr = ((dev->i2c_address << 1) | 0x01);
358
    cyg_uint32      si = 0;
359
 
360
    if (!extra->i2c_lost_arb) {
361
        extra->i2c_completed = 0;
362
        extra->i2c_data.i2c_rx_data = rx_data;
363
        extra->i2c_mode = A2FXXX_I2C_XFER_MODE_RX;
364
        I2C_TRACE
365
            ("I2C: RX to %2x, count: %4d, START flag: %s, STOP flag: %s\n",
366
             dev->i2c_address, count, (send_start == true) ? "true" : "false",
367
             (send_stop == true) ? "true" : "false");
368
        HAL_READ_UINT32(I2C_CR_SI(extra->i2c_base_bb), si);
369
        // Set start bit
370
        HAL_WRITE_UINT32(I2C_CR_STA(extra->i2c_base_bb),
371
                         CYGHWR_HAL_A2FXXX_BITSET);
372
        // For repeated start, we need to clear the interrupt
373
        if (si != 0) {
374
            HAL_WRITE_UINT32(I2C_CR_SI(extra->i2c_base_bb),
375
                             CYGHWR_HAL_A2FXXX_BITCLEAR);
376
            HAL_INTERRUPT_ACKNOWLEDGE(extra->i2c_isr_id);
377
        }
378
        // For repeated start, we need to un-mask the interrupt
379
        if (extra->i2c_isr_mask) {
380
            extra->i2c_isr_mask = false;
381
            HAL_INTERRUPT_UNMASK(extra->i2c_isr_id);
382
        }
383
        a2fxxx_i2c_doit(extra);
384
    }
385
 
386
    if (send_stop) {
387
        I2C_TRACE("I2C: RX send stop\n");
388
        a2fxxx_i2c_stopit(extra);
389
    }
390
 
391
    return count - extra->i2c_count;
392
}
393
 
394
 
395
// ----------------------------------------------------------------------------
396
// The functions needed for all I2C devices.
397
 
398
void
399
a2fxxx_i2c_init(struct cyg_i2c_bus *bus)
400
{
401
    a2fxxx_i2c_extra *extra = (a2fxxx_i2c_extra *) bus->i2c_extra;
402
    cyg_uint8       div = 0;
403
#ifdef CYGDBG_DEVS_I2C_CORTEXM_A2FXXX_TRACE
404
    cyg_uint32      i2c_freq =
405
        ((hal_a2fxxx_i2c_clock(extra->i2c_base) /
406
          CYGNUM_HAL_CORTEXM_A2FXXX_I2C_CLK_DIV));
407
#endif
408
 
409
    while ((i2c_div[div] != CYGNUM_HAL_CORTEXM_A2FXXX_I2C_CLK_DIV) &&
410
           i2c_div[div] != 0) {
411
        div++;
412
    }
413
 
414
    I2C_TRACE("\nI2C INIT, divider: %d(%d), frequency: %d\n", i2c_div[div],
415
              div, i2c_freq);
416
 
417
    cyg_drv_mutex_init(&extra->i2c_lock);
418
    cyg_drv_cond_init(&extra->i2c_wait, &extra->i2c_lock);
419
    cyg_drv_interrupt_create(extra->i2c_isr_id,
420
                             extra->i2c_isr_pri,
421
                             (cyg_addrword_t)extra,
422
                             &a2fxxx_i2c_isr,
423
                             &a2fxxx_i2c_dsr,
424
                             &(extra->i2c_interrupt_handle),
425
                             &(extra->i2c_interrupt_data));
426
    cyg_drv_interrupt_attach(extra->i2c_interrupt_handle);
427
 
428
    // Enable I2C peripheral
429
    CYGHWR_HAL_A2FXXX_PERIPH_RELEASE(extra->i2c_periph);
430
 
431
    // Set I2C bus speed
432
    HAL_WRITE_UINT32(I2C_CR_ENS1(extra->i2c_base_bb),
433
                     CYGHWR_HAL_A2FXXX_BITSET);
434
 
435
    HAL_WRITE_UINT32(I2C_CR_CR0(extra->i2c_base_bb),
436
                     ((div & 0x1) ? CYGHWR_HAL_A2FXXX_BITSET :
437
                      CYGHWR_HAL_A2FXXX_BITCLEAR));
438
    HAL_WRITE_UINT32(I2C_CR_CR1(extra->i2c_base_bb),
439
                     ((div & 0x2) ? CYGHWR_HAL_A2FXXX_BITSET :
440
                      CYGHWR_HAL_A2FXXX_BITCLEAR));
441
    HAL_WRITE_UINT32(I2C_CR_CR2(extra->i2c_base_bb),
442
                     ((div & 0x4) ? CYGHWR_HAL_A2FXXX_BITSET :
443
                      CYGHWR_HAL_A2FXXX_BITCLEAR));
444
 
445
    // Interrupts can now be safely unmasked
446
    HAL_INTERRUPT_UNMASK(extra->i2c_isr_id);
447
}
448
 
449
//---------------------------------------------------------------------------
450
// EOF i2c_a2fxxx.c

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.