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

4.104.114.95
Last change on this file since 35a968c was 30abd24, checked in by Joel Sherrill <joel.sherrill@…>, on 08/15/08 at 20:18:41

2008-08-15 Allan Hessenflow <allanh@…>

  • ChangeLog?, Makefile.am, README, configure.ac, preinstall.am, cache/cache.c, cache/cache_.h, clock/clock.c, clock/rtc.c, clock/tod.h, include/bf533.h, include/bf537.h, include/cecRegs.h, include/coreTimerRegs.h, include/dmaRegs.h, include/ebiuRegs.h, include/ethernetRegs.h, include/gpioRegs.h, include/memoryRegs.h, include/mmuRegs.h, include/ppiRegs.h, include/rtcRegs.h, include/sicRegs.h, include/spiRegs.h, include/sportRegs.h, include/timerRegs.h, include/twiRegs.h, include/uartRegs.h, include/wdogRegs.h, interrupt/interrupt.c, interrupt/interrupt.h, mmu/mmu.c, mmu/mmu.h, network/ethernet.c, network/ethernet.h, serial/spi.c, serial/spi.h, serial/sport.c, serial/sport.h, serial/twi.c, serial/twi.h, serial/uart.c, serial/uart.h, timer/timer.c: New files.
  • Property mode set to 100644
File size: 8.7 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  boolean volatile masterActive;
41  rtems_status_code volatile masterResult;
42  boolean 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  uint8_t data;
140
141  for (i = 0; i < N_BFIN_TWI; i++) {
142    base = twi[i].base;
143    if (base) {
144      stat = BFIN_REG16(base, TWI_INT_STAT_OFFSET);
145      if (stat) {
146        BFIN_REG16(base, TWI_INT_STAT_OFFSET) = stat;
147        if ((stat & TWI_INT_STAT_SINIT) && !twi[i].slaveActive) {
148          twi[i].slaveActive = TRUE;
149          r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
150          BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
151          BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
152          r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
153          BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r | TWI_SLAVE_CTL_STDVAL;
154        }
155        if (twi[i].slaveActive) {
156
157
158          if (stat & (TWI_INT_STAT_SCOMP | TWI_INT_STAT_SERR)) {
159
160
161            r = BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET);
162            BFIN_REG16(base, TWI_SLAVE_CTL_OFFSET) = r & ~TWI_SLAVE_CTL_STDVAL;
163            twi[i].slaveActive = FALSE;
164
165
166          }
167        }
168        if (twi[i].masterActive && !twi[i].slaveActive) {
169
170
171          if (stat & (TWI_INT_STAT_MCOMP | TWI_INT_STAT_MERR)) {
172            if (!(stat & TWI_INT_STAT_MERR)) {
173
174
175              rtems_semaphore_release(twi[i].irqSem);
176
177
178            } else
179              rtems_semaphore_release(twi[i].irqSem);
180          }
181        }
182      }
183    }
184  }
185}
186
187rtems_status_code bfin_twi_request(int channel, uint8_t address,
188                                   bfin_twi_request_t *request,
189                                   rtems_interval timeout) {
190  rtems_status_code result;
191  void *base;
192  rtems_interrupt_level level;
193  uint16_t r;
194  uint16_t masterMode;
195
196  if (channel < 0 || channel >= N_BFIN_TWI)
197    return RTEMS_INVALID_NUMBER;
198  result = rtems_semaphore_obtain(twi[channel].mutex,
199                                  RTEMS_WAIT, RTEMS_NO_TIMEOUT);
200  if (result == RTEMS_SUCCESSFUL) {
201    base = twi[channel].base;
202    twi[channel].req = request;
203
204    if (request->write) {
205      twi[channel].dataPtr = request->data;
206      twi[channel].count = request->count;
207    } else
208      twi[channel].count = 0;
209
210    BFIN_REG16(base, TWI_MASTER_ADDR_OFFSET) = (uint16_t) address <<
211                                               TWI_MASTER_ADDR_MADDR_SHIFT;
212    masterMode = BFIN_REG16(base, TWI_MASTER_CTL_OFFSET);
213    masterMode |= (request->count << TWI_MASTER_CTL_DCNT_SHIFT);
214    if (request->next)
215      masterMode |= TWI_MASTER_CTL_RSTART;
216    if (!request->write)
217      masterMode |= TWI_MASTER_CTL_MDIR;
218    masterMode |= TWI_MASTER_CTL_MEN;
219    rtems_interrupt_disable(level);
220    if (!twi[channel].slaveActive) {
221      r = BFIN_REG16(base, TWI_FIFO_CTL_OFFSET);
222      BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r | TWI_FIFO_CTL_XMTFLUSH;
223      BFIN_REG16(base, TWI_FIFO_CTL_OFFSET) = r;
224      if (request->write) {
225        while (twi[channel].count &&
226               (BFIN_REG16(base, TWI_FIFO_STAT_OFFSET) &
227                TWI_FIFO_STAT_XMTSTAT_MASK) !=
228               TWI_FIFO_STAT_XMTSTAT_FULL) {
229          BFIN_REG16(base, TWI_XMT_DATA8_OFFSET) =
230              (uint16_t) *twi[channel].dataPtr++;
231          twi[channel].count--;
232        }
233      }
234      twi[channel].masterActive = TRUE;
235      BFIN_REG16(base, TWI_MASTER_CTL_OFFSET) = masterMode;
236    } else {
237      twi[channel].masterActive = FALSE;
238      twi[channel].masterResult = -1; /* BISON (code should be equiv to lost arbitration) */
239    }
240    rtems_interrupt_enable(level);
241    while (result == RTEMS_SUCCESSFUL && twi[channel].masterActive)
242      result = rtems_semaphore_obtain(twi[channel].irqSem,
243                                      RTEMS_WAIT, timeout);
244    if (result == RTEMS_SUCCESSFUL)
245      result = twi[channel].masterResult;
246    else {
247      /* BISON abort */
248
249
250
251    }
252    rtems_semaphore_release(twi[channel].mutex);
253  }
254  return result;
255}
256
Note: See TracBrowser for help on using the repository browser.