source: rtems/c/src/lib/libcpu/bfin/serial/twi.c @ 3551166d

4.104.114.95
Last change on this file since 3551166d was 3551166d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 09/05/08 at 11:55:58

Convert to "bool".

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/* this is not much more than a shell; it does not do anything useful yet */
2
3/*  TWI (I2C) driver for Blackfin
4 *
5 *  Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
6 *             written by Allan Hessenflow <allanh@kallisti.com>
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *  $Id$
13 */
14 
15
16#include <stdlib.h>
17#include <rtems.h>
18
19#include <libcpu/twiRegs.h>
20#include "twi.h"
21
22
23#ifndef N_BFIN_TWI
24#define N_BFIN_TWI 1
25#endif
26
27#define BFIN_REG16(base, offset) \
28        (*((uint16_t volatile *) ((char *)(base) + (offset))))
29
30
31static struct {
32  void *base;
33  rtems_id irqSem;
34  rtems_id mutex;
35  bfin_twi_callback_t callback;
36  void *callbackArg;
37  bfin_twi_request_t volatile *req;
38  uint8_t volatile *dataPtr;
39  int volatile count;
40  bool volatile masterActive;
41  rtems_status_code volatile masterResult;
42  bool volatile slaveActive;
43} twi[N_BFIN_TWI];
44
45
46rtems_status_code bfin_twi_init(int channel, bfin_twi_config_t *config) {
47  rtems_status_code result;
48  void *base;
49
50  if (channel < 0 || channel >= N_BFIN_TWI)
51    return RTEMS_INVALID_NUMBER;
52   
53  base = config->base;
54  twi[channel].base = base;   
55
56  result = rtems_semaphore_create(rtems_build_name('t','w','i','s'),
57                                  0,
58                                  RTEMS_FIFO |
59                                  RTEMS_SIMPLE_BINARY_SEMAPHORE |
60                                  RTEMS_NO_INHERIT_PRIORITY |
61                                  RTEMS_NO_PRIORITY_CEILING |
62                                  RTEMS_LOCAL,
63                                  0,
64                                  &twi[channel].irqSem);
65  result = rtems_semaphore_create(rtems_build_name('t','w','i','m'),
66                                  1,
67                                  RTEMS_PRIORITY |
68                                  RTEMS_SIMPLE_BINARY_SEMAPHORE |
69                                  RTEMS_INHERIT_PRIORITY |
70                                  RTEMS_NO_PRIORITY_CEILING |
71                                  RTEMS_LOCAL,
72                                  0,
73                                  &twi[channel].mutex);
74  BFIN_REG16(base, TWI_CONTROL_OFFSET) =
75      (uint16_t) (((config->sclk +9999999) / 10000000) <<
76                  TWI_CONTROL_PRESCALE_SHIFT) |
77      TWI_CONTROL_TWI_ENA;
78  BFIN_REG16(base, TWI_CLKDIV_OFFSET) = config->fast ?
79                                        ((8 << TWI_CLKDIV_CLKHI_SHIFT) |
80                                         (17 << TWI_CLKDIV_CLKLOW_SHIFT)) :
81                                        ((33 << TWI_CLKDIV_CLKHI_SHIFT) |
82                                         (67 << TWI_CLKDIV_CLKLOW_SHIFT));
83  BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = 0;
84  BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = config->fast ?
85                                            TWI_MASTER_CTL_FAST :
86                                            0;
87  BFIN_REG16(base, TWI_SLAVE_ADDR_OFFSET) = (uint16_t) config->slave_address <<
88                                            TWI_SLAVE_ADDR_SADDR_SHIFT;
89  BFIN_REG16(base, TWI_MASTER_STAT_OFFSET) = TWI_MASTER_STAT_BUFWRERR |
90                                             TWI_MASTER_STAT_BUFRDERR |
91                                             TWI_MASTER_STAT_DNAK |
92                                             TWI_MASTER_STAT_ANAK |
93                                             TWI_MASTER_STAT_LOSTARB;
94  BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = TWI_FIFO_CTL_XMTFLUSH |
95                                          TWI_FIFO_CTL_RCVFLUSH;
96  BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = 0;
97  BFIN_REG16(base, TWI_INT_STAT_OFFSET) = TWI_INT_STAT_RCVSERV |
98                                          TWI_INT_STAT_XMTSERV |
99                                          TWI_INT_STAT_MERR |
100                                          TWI_INT_STAT_MCOMP |
101                                          TWI_INT_STAT_SOVF |
102                                          TWI_INT_STAT_SERR |
103                                          TWI_INT_STAT_SCOMP |
104                                          TWI_INT_STAT_SINIT;
105  BFIN_REG16(base, TWI_INT_MASK_OFFSET) = TWI_INT_MASK_RCVSERVM |
106                                          TWI_INT_MASK_XMTSERVM;
107
108  return result;
109}
110
111rtems_status_code bfin_twi_register_callback(int channel,
112                                             bfin_twi_callback_t callback,
113                                             void *arg) {
114  void *base;
115  int level;
116
117  if (channel < 0 || channel >= N_BFIN_TWI)
118    return RTEMS_INVALID_NUMBER;
119
120  base = twi[channel].base;
121  if (callback == NULL)
122    BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = 0;
123  rtems_interrupt_disable(level);
124  twi[channel].callback = callback;
125  twi[channel].callbackArg = arg;
126  rtems_interrupt_enable(level);
127  if (callback != NULL)
128    BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = TWI_SLAVE_CTL_GEN |
129                                             TWI_SLAVE_CTL_SEN;
130
131  return RTEMS_SUCCESSFUL;
132}
133
134void bfin_twi_isr(int source) {
135  void *base;
136  int i;
137  uint16_t r;
138  uint16_t stat;
139
140  for (i = 0; i < N_BFIN_TWI; i++) {
141    base = twi[i].base;
142    if (base) {
143      stat = BFIN_REG16(base, TWI_INT_STAT_OFFSET);
144      if (stat) {
145        BFIN_REG16(base, TWI_INT_STAT_OFFSET) = stat;
146        if ((stat & TWI_INT_STAT_SINIT) && !twi[i].slaveActive) {
147          twi[i].slaveActive = true;
148          r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
149          BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
150          BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
151          r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
152          BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r | TWI_SLAVE_CTL_STDVAL;
153        }
154        if (twi[i].slaveActive) {
155
156
157          if (stat & (TWI_INT_STAT_SCOMP | TWI_INT_STAT_SERR)) {
158
159
160            r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
161            BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r & ~TWI_SLAVE_CTL_STDVAL;
162            twi[i].slaveActive = false;
163
164
165          }
166        }
167        if (twi[i].masterActive && !twi[i].slaveActive) {
168
169
170          if (stat & (TWI_INT_STAT_MCOMP | TWI_INT_STAT_MERR)) {
171            if (!(stat & TWI_INT_STAT_MERR)) {
172
173
174              rtems_semaphore_release(twi[i].irqSem);
175
176
177            } else
178              rtems_semaphore_release(twi[i].irqSem);
179          }
180        }
181      }
182    }
183  }
184}
185
186rtems_status_code bfin_twi_request(int channel, uint8_t address,
187                                   bfin_twi_request_t *request,
188                                   rtems_interval timeout) {
189  rtems_status_code result;
190  void *base;
191  rtems_interrupt_level level;
192  uint16_t r;
193  uint16_t masterMode;
194
195  if (channel < 0 || channel >= N_BFIN_TWI)
196    return RTEMS_INVALID_NUMBER;
197  result = rtems_semaphore_obtain(twi[channel].mutex,
198                                  RTEMS_WAIT, RTEMS_NO_TIMEOUT);
199  if (result == RTEMS_SUCCESSFUL) {
200    base = twi[channel].base;
201    twi[channel].req = request;
202
203    if (request->write) {
204      twi[channel].dataPtr = request->data;
205      twi[channel].count = request->count;
206    } else
207      twi[channel].count = 0;
208
209    BFIN_REG16(base, TWI_MASTER_ADDR_OFFSET) = (uint16_t) address <<
210                                               TWI_MASTER_ADDR_MADDR_SHIFT;
211    masterMode = BFIN_REG16(base, TWI_MASTER_CTL_OFFSET);
212    masterMode |= (request->count << TWI_MASTER_CTL_DCNT_SHIFT);
213    if (request->next)
214      masterMode |= TWI_MASTER_CTL_RSTART;
215    if (!request->write)
216      masterMode |= TWI_MASTER_CTL_MDIR;
217    masterMode |= TWI_MASTER_CTL_MEN;
218    rtems_interrupt_disable(level);
219    if (!twi[channel].slaveActive) {
220      r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
221      BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
222      BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
223      if (request->write) {
224        while (twi[channel].count &&
225               (BFIN_REG16(base, TWI_FIFO_STAT_OFFSET) &
226                TWI_FIFO_STAT_XMTSTAT_MASK) !=
227               TWI_FIFO_STAT_XMTSTAT_FULL) {
228          BFIN_REG16(base, TWI_XMT_DATA8_OFFSET) =
229              (uint16_t) *twi[channel].dataPtr++;
230          twi[channel].count--;
231        }
232      }
233      twi[channel].masterActive = true;
234      BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = masterMode;
235    } else {
236      twi[channel].masterActive = false;
237      twi[channel].masterResult = -1; /* BISON (code should be equiv to lost arbitration) */
238    }
239    rtems_interrupt_enable(level);
240    while (result == RTEMS_SUCCESSFUL && twi[channel].masterActive)
241      result = rtems_semaphore_obtain(twi[channel].irqSem,
242                                      RTEMS_WAIT, timeout);
243    if (result == RTEMS_SUCCESSFUL)
244      result = twi[channel].masterResult;
245    else {
246      /* BISON abort */
247
248
249
250    }
251    rtems_semaphore_release(twi[channel].mutex);
252  }
253  return result;
254}
255
Note: See TracBrowser for help on using the repository browser.