Changeset fe83cef6 in rtems


Ignore:
Timestamp:
01/11/10 16:14:47 (14 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 5, master
Children:
29a3d72c
Parents:
04a82e9c
Message:

2010-01-11 Allan Hessenflow <allanh@…>

  • serial/spi.c, serial/spi.h: Fill in skeleton with functional SPI master code.
  • include/spiRegs.h: Correct spi shadow register declaration.
Location:
c/src/lib/libcpu/bfin
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libcpu/bfin/ChangeLog

    r04a82e9c rfe83cef6  
     12010-01-11      Allan Hessenflow <allanh@kallisti.com>
     2
     3        * serial/spi.c, serial/spi.h:
     4        Fill in skeleton with functional SPI master code.
     5        * include/spiRegs.h:
     6        Correct spi shadow register declaration.
     7
    182009-12-11      Ralf Corsépius <ralf.corsepius@rtems.org>
    29
  • c/src/lib/libcpu/bfin/README

    r04a82e9c rfe83cef6  
    1010processor variant they're being built for.
    1111
    12 serial/spi* and serial/sport* are currently just placeholders.
    13 serial/twi* does not contain enough code to do anything useful;
    14 it is however a start at an I2C driver.
     12serial/sport* is currently just a placeholders.  serial/twi* does not
     13contain enough code to do anything useful; it is however a start at an
     14I2C driver.
    1515
  • c/src/lib/libcpu/bfin/include/spiRegs.h

    r04a82e9c rfe83cef6  
    11/*  Blackfin SPI Registers
    22 *
    3  *  Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
     3 *  Copyright (c) 2010 Kallisti Labs, Los Gatos, CA, USA
    44 *             written by Allan Hessenflow <allanh@kallisti.com>
    55 *
     
    2323#define SPI_RDBR_OFFSET                               0x0010
    2424#define SPI_BAUD_OFFSET                               0x0014
    25 #define SPI_SHADOW                                    0x0018
     25#define SPI_SHADOW_OFFSET                             0x0018
    2626
    2727
  • c/src/lib/libcpu/bfin/serial/spi.c

    r04a82e9c rfe83cef6  
    1 /* placeholder (just a shell) */
    2 
    31/*  SPI driver for Blackfin
    42 *
    5  *  Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
     3 *  Copyright (c) 2010 Kallisti Labs, Los Gatos, CA, USA
    64 *             written by Allan Hessenflow <allanh@kallisti.com>
    75 *
     
    1311 */
    1412
    15 
    1613#include <stdlib.h>
    17 #include <rtems.h>
     14#include <bsp.h>
     15#include <rtems/error.h>
     16#include <rtems/bspIo.h>
     17#include <errno.h>
    1818#include <rtems/libi2c.h>
    19 
    2019#include <libcpu/spiRegs.h>
    2120#include "spi.h"
    2221
    2322
    24 static rtems_status_code spiInit(rtems_libi2c_bus_t *bus) {
    25   bfin_spi_softc_t *softc;
    26   rtems_status_code status;
    27 
    28   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    29 
    30   status = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
     23#ifndef BFIN_REG16
     24#define BFIN_REG16(base, offset) \
     25        (*((uint16_t volatile *) ((uint8_t *)(base) + (offset))))
     26#endif
     27
     28
     29static bfin_spi_state_t *bfin_spi;
     30
     31
     32void bfin_spi_isr(int v) {
     33  bfin_spi_state_t *state;
     34  uint16_t r;
     35
     36  state = bfin_spi;
     37  if (state->len > state->bytes_per_word) {
     38    if (state->wr_ptr) {
     39      if (state->bytes_per_word == 2)
     40        r = *(uint16_t *) state->wr_ptr;
     41      else
     42        r = (uint16_t) *state->wr_ptr;
     43      state->wr_ptr += state->bytes_per_word;
     44    } else
     45      r = state->idle_pattern;
     46    BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r;
     47  }
     48  state->len -= state->bytes_per_word;
     49  if (state->len <= 0) {
     50    /*
     51       The transfers are done, so I don't want to kick off another
     52       transfer or get any more interrupts.  Reading the last word from
     53       SPI_SHADOW instead of SPI_RDBR should prevent it from triggering
     54       another transfer, but that doesn't clear the interrupt flag.  I
     55       could mask the interrupt in the SIC, but that would preclude ever
     56       using the DMA channel that shares the interrupt independently (and
     57       they might just share it with something more important in some other
     58       member of the Blackfin family).  And who knows what problems it
     59       might cause in this code potentially dealing with that still pended
     60       interrupt at the beginning of the next transfer.
     61
     62       So instead I disable the SPI interface, read the data from RDBR
     63       (thus clearing the interrupt but not triggering another transfer
     64       since the interface is disabled), then re-eanble the interface.
     65       This has the problem that the bf537 tri-states the SPI signals
     66       while the interface is disabled.  Either adding pull-ups on at
     67       least the chip select signals, or using GPIOs for them so they're
     68       not controlled by the SPI module, would be correct fixes for that
     69       (really pull-ups/downs should be added to the SPI CLK and MOSI
     70       signals as well to insure they cannot float into some region that
     71       causes input structures to consume excessive power).  Or they can
     72       all be left alone, assuming that there's enough capacitance on the
     73       lines to prevent any problems for the short time they're being left
     74       disabled.
     75
     76       An alternative approach I attempted involved switching TIMOD
     77       between RDBR and TDBR when starting and finishing a transfer, but
     78       I didn't get anywhere with that.  In my limited testing TIMOD TDBR
     79       wasn't behaving as I expected it to, but maybe with more
     80       experimentation I'd find some solution there.  However I'm out
     81       of time for this project, at least for now.
     82    */
     83
     84    BFIN_REG16(state->base, SPI_CTL_OFFSET) &= ~SPI_CTL_SPE;
     85    r = BFIN_REG16(state->base, SPI_RDBR_OFFSET);
     86    BFIN_REG16(state->base, SPI_CTL_OFFSET) |= SPI_CTL_SPE;
     87    rtems_semaphore_release(state->sem);
     88  } else
     89    r = BFIN_REG16(state->base, SPI_RDBR_OFFSET);
     90
     91  if (state->rd_ptr) {
     92    if (state->bytes_per_word == 2)
     93      *(uint16_t *) state->rd_ptr = r;
     94    else
     95      *state->rd_ptr = (uint8_t) r;
     96    state->rd_ptr += state->bytes_per_word;
     97  }
     98}
     99
     100static rtems_status_code setTFRMode(rtems_libi2c_bus_t *bus,
     101                                    const rtems_libi2c_tfr_mode_t *tfrMode) {
     102  rtems_status_code result;
     103  bfin_spi_state_t *state;
     104  uint32_t divisor;
     105  uint16_t ctrl;
     106
     107  result = RTEMS_SUCCESSFUL;
     108  state = &((bfin_spi_bus_t *) bus)->p;
     109
     110  if (result == RTEMS_SUCCESSFUL) {
     111    if (tfrMode->bits_per_char != 8 &&
     112        tfrMode->bits_per_char != 16)
     113      result = RTEMS_INVALID_NUMBER;
     114    if (tfrMode->baudrate <= 0)
     115      result = RTEMS_INVALID_NUMBER;
     116  }
     117  if (result == RTEMS_SUCCESSFUL) {
     118    divisor = (SCLK / 2 + tfrMode->baudrate - 1) /
     119              tfrMode->baudrate;
     120    if (divisor < 2)
     121      divisor = 2;
     122    else if (divisor > 65535)
     123      result = RTEMS_INVALID_NUMBER;
     124  }
     125  if (result == RTEMS_SUCCESSFUL) {
     126    state->idle_pattern = (uint16_t) tfrMode->idle_char;
     127    state->bytes_per_word = (tfrMode->bits_per_char > 8) ? 2 : 1;
     128    BFIN_REG16(state->base, SPI_BAUD_OFFSET) = divisor;
     129    ctrl = BFIN_REG16(state->base, SPI_CTL_OFFSET);
     130    if (tfrMode->lsb_first)
     131      ctrl |= SPI_CTL_LSBF;
     132    else
     133      ctrl &= ~SPI_CTL_LSBF;
     134    if (tfrMode->bits_per_char > 8)
     135      ctrl |= SPI_CTL_SIZE;
     136    else
     137      ctrl &= ~SPI_CTL_SIZE;
     138    if (tfrMode->clock_inv)
     139      ctrl |= SPI_CTL_CPOL;
     140    else
     141      ctrl &= ~SPI_CTL_CPOL;
     142    if (tfrMode->clock_phs)
     143      ctrl |= SPI_CTL_CPHA;
     144    else
     145      ctrl &= ~SPI_CTL_CPHA;
     146    BFIN_REG16(state->base, SPI_CTL_OFFSET) = ctrl;
     147  }
     148
     149  return result;
     150}
     151
     152static int readWrite(rtems_libi2c_bus_t *bus, uint8_t *rdBuf,
     153                     const uint8_t *wrBuf, int len) {
     154  rtems_status_code result;
     155  bfin_spi_state_t *state;
     156  uint16_t r;
     157
     158  result = RTEMS_SUCCESSFUL;
     159  state = &((bfin_spi_bus_t *) bus)->p;
     160
     161  if (len) {
     162    state->rd_ptr = rdBuf;
     163    state->wr_ptr = wrBuf;
     164    state->len = len;
     165    if (state->wr_ptr) {
     166      if (state->bytes_per_word == 2)
     167        r = *(uint16_t *) state->wr_ptr;
     168      else
     169        r = (uint16_t) *state->wr_ptr;
     170      state->wr_ptr += state->bytes_per_word;
     171    } else
     172      r = state->idle_pattern;
     173    BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r;
     174    BFIN_REG16(state->base, SPI_RDBR_OFFSET); /* trigger */
     175    /* wait until done */
     176    do {
     177      result = rtems_semaphore_obtain(state->sem, RTEMS_WAIT, 100);
     178    } while (result == RTEMS_SUCCESSFUL && state->len > 0);
     179  }
     180
     181  return (result == RTEMS_SUCCESSFUL) ? len : -result;
     182}
     183
     184
     185rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus) {
     186  rtems_status_code result;
     187  bfin_spi_state_t *state;
     188
     189  state = &((bfin_spi_bus_t *) bus)->p;
     190
     191  BFIN_REG16(state->base, SPI_CTL_OFFSET) = SPI_CTL_SPE |
     192                                            SPI_CTL_MSTR |
     193                                            SPI_CTL_CPHA |
     194                                            SPI_CTL_TIMOD_RDBR;
     195
     196  result = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
    31197                                  0,
    32198                                  RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
    33199                                  0,
    34                                   &softc->irq_sema_id);
    35 
    36   return status;
    37 }
    38 
    39 static rtems_status_code spiSendStart(rtems_libi2c_bus_t *bus) {
    40   bfin_spi_softc_t *softc;
    41   rtems_status_code status;
    42 
    43   status = RTEMS_SUCCESSFUL;
    44   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    45 
    46   return status;
    47 }
    48 
    49 static rtems_status_code spiSendStop(rtems_libi2c_bus_t *bus) {
    50   bfin_spi_softc_t *softc;
    51   rtems_status_code status;
    52 
    53   status = RTEMS_SUCCESSFUL;
    54   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    55 
    56   return status;
    57 }
    58 
    59 static rtems_status_code spiSendAddr(rtems_libi2c_bus_t *bus,
    60                                      uint32_t addr, int rw) {
    61   bfin_spi_softc_t *softc;
    62   rtems_status_code status;
    63 
    64   status = RTEMS_SUCCESSFUL;
    65   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    66 
    67   return status;
    68 }
    69 
    70 static int spiReadBytes(rtems_libi2c_bus_t *bus,
    71                         unsigned char *buf, int len) {
    72   bfin_spi_softc_t *softc;
    73 
    74   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    75 
    76   return 0;
    77 }
    78 
    79 static int spiWriteBytes(rtems_libi2c_bus_t *bus,
    80                          unsigned char *buf, int len) {
    81   bfin_spi_softc_t *softc;
    82 
    83   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    84 
    85   return 0;
    86 }
    87 
    88 static int spiIoctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) {
    89   bfin_spi_softc_t *softc;
    90 
    91   softc = &(((bfin_spi_desc_t *)(bus))->softc);
    92 
    93 
    94   return 0;
    95 }
    96 
    97 void bfin_spi_isr(int source) {
    98 }
    99 
    100 rtems_libi2c_bus_ops_t bfin_spi_libi2c_bus_ops = {
    101   init: spiInit,
    102   send_start: spiSendStart,
    103   send_stop: spiSendStop,
    104   send_addr: spiSendAddr,
    105   read_bytes: spiReadBytes,
    106   write_bytes: spiWriteBytes,
    107   ioctl: spiIoctl
    108 };
    109 
     200                                  &state->sem);
     201  if (result == RTEMS_SUCCESSFUL)
     202    bfin_spi = state; /* for isr */
     203
     204  return result;
     205}
     206
     207rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus) {
     208
     209  return RTEMS_SUCCESSFUL;
     210}
     211
     212int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) {
     213
     214  return readWrite(bus, buf, NULL, len);
     215}
     216
     217int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) {
     218
     219  return readWrite(bus, NULL, buf, len);
     220}
     221
     222int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) {
     223  int result;
     224
     225  result = -RTEMS_NOT_DEFINED;
     226  switch(cmd) {
     227  case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
     228    result = -setTFRMode(bus, (const rtems_libi2c_tfr_mode_t *) arg);
     229    break;
     230  case RTEMS_LIBI2C_IOCTL_READ_WRITE:
     231    result = readWrite(bus,
     232                       ((rtems_libi2c_read_write_t *) arg)->rd_buf,
     233                       ((rtems_libi2c_read_write_t *) arg)->wr_buf,
     234                       ((rtems_libi2c_read_write_t *) arg)->byte_cnt);
     235    break;
     236  default:
     237    break;
     238  }
     239
     240  return result;
     241}
     242
  • c/src/lib/libcpu/bfin/serial/spi.h

    r04a82e9c rfe83cef6  
    1 /* placeholder (just a shell) */
    2 
    31/*
    42 *  RTEMS driver for Blackfin SPI
    53 *
    6  *  COPYRIGHT (c) 2008 Kallisti Labs, Los Gatos, CA, USA
     4 *  COPYRIGHT (c) 2010 Kallisti Labs, Los Gatos, CA, USA
    75 *            written by Allan Hessenflow <allanh@kallisti.com>
    86 *
     
    1412 */
    1513
    16 
    17 #ifndef _spi_h_
    18 #define _spi_h_
    19 
     14#ifndef _spi_h
     15#define _spi_h
    2016
    2117#ifdef __cplusplus
     
    2319#endif
    2420
    25 
    2621typedef struct {
    27   /* parameters provided by bsp */
    28   uint32_t freq;
    29   void    *base;
    30   bool     fast;
    31   /* internal use */
    32   rtems_id irq_sema_id;
    33 } bfin_spi_softc_t;
     22  void *base;
     23  /* remaining entries are for internal use */
     24  rtems_id sem;
     25  int bytes_per_word;
     26  uint16_t idle_pattern;
     27  uint8_t *rd_ptr;
     28  const uint8_t *wr_ptr;
     29  int len;
     30} bfin_spi_state_t;
    3431
    3532typedef struct {
    3633  rtems_libi2c_bus_t bus;
    37   bfin_spi_softc_t softc;
    38 } bfin_spi_desc_t;
     34  bfin_spi_state_t p;
     35} bfin_spi_bus_t;
    3936
    4037
    41 extern rtems_libi2c_bus_ops_t bfin_spi_libi2c_bus_ops;
     38void bfin_spi_isr(int v);
    4239
     40rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus);
    4341
    44 void bfin_spi_isr(int source);
     42rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus);
    4543
     44int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len);
     45
     46int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len);
     47
     48int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg);
    4649
    4750#ifdef __cplusplus
     
    4952#endif
    5053
    51 #endif /* _spi_h_ */
    5254
     55#endif /* _spi_h */
Note: See TracChangeset for help on using the changeset viewer.