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

5
Last change on this file since f3b29236 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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