URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [spi/] [arm/] [lpc2xxx/] [current/] [src/] [spi_lpc2xxx.cxx] - Rev 817
Go to most recent revision | Compare with Previous | Blame | View Log
//========================================================================== // // spi_lpc2xxx.cxx // // SPI driver for LPC2xxx // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later // version. // // eCos is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> // Contributors: // Date: 2007-07-12 // Purpose: // Description: // //####DESCRIPTIONEND#### // //========================================================================== #include <pkgconf/hal.h> #include <pkgconf/io_spi.h> #include <pkgconf/devs_spi_arm_lpc2xxx.h> #include <cyg/infra/cyg_type.h> #include <cyg/infra/cyg_ass.h> #include <cyg/hal/hal_io.h> #include <cyg/hal/hal_if.h> #include <cyg/hal/hal_intr.h> #include <cyg/io/spi.h> #include <cyg/io/spi_lpc2xxx.h> #include <cyg/error/codes.h> #define SPI_SPCR_SPIE 0x80 #define SPI_SPCR_LSBF 0x40 #define SPI_SPCR_MSTR 0x20 #define SPI_SPCR_CPOL 0x10 #define SPI_SPCR_CPHA 0x08 #define SPI_SPSR_SPIF 0x80 #define SPI_SPSR_WCOL 0x40 #define SPI_SPSR_ROVR 0x20 #define SPI_SPSR_MODF 0x10 #define SPI_SPSR_ABRT 0x08 #define SPI_SPINT 0x01 #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus0; CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 0); #endif #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus1; CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 1); #endif /* * Interrupt routine * read & write the next byte until count reaches zero */ static cyg_uint32 spi_lpc2xxx_isr(cyg_vector_t vec, cyg_addrword_t data) { cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) data; cyg_uint8 tmp; tmp = bus->spi_dev->spsr; if(tmp & SPI_SPSR_MODF) bus->spi_dev->spcr = bus->spi_dev->spcr | SPI_SPCR_MSTR; tmp = bus->spi_dev->spdr; if(bus->count) { if(bus->rx) *bus->rx++ = tmp; if(--bus->count) { bus->spi_dev->spint = SPI_SPINT; bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0; cyg_drv_interrupt_acknowledge(bus->spi_vect); return CYG_ISR_HANDLED; } } bus->count = 0; bus->tx = NULL; bus->rx = NULL; bus->spi_dev->spint = SPI_SPINT; cyg_drv_interrupt_acknowledge(bus->spi_vect); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } static void spi_lpc2xxx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data) { cyg_drv_cond_signal(&((cyg_spi_lpc2xxx_bus_t *) data)->spi_wait); } /* * Configure bus for a specific baud rate */ static void spi_lpc2xxx_baud(cyg_spi_lpc2xxx_bus_t *bus, cyg_uint32 baud) { cyg_uint32 ccr = 8; if(baud) { ccr = (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / baud; if(((CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / ccr) > baud) ccr++; ccr++; ccr &= 0xfe; } bus->spi_dev->spccr = ccr < 8 ? 8 : ccr; } /* * get/set configuration */ static int spi_lpc2xxx_get_config(cyg_spi_device *device, cyg_uint32 key, void *buf, cyg_uint32 *len) { cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; switch(key) { case CYG_IO_GET_CONFIG_SPI_CLOCKRATE: if(*len == sizeof(cyg_uint32)) { cyg_uint32 *b = (cyg_uint32 *) buf; *b = dev->spi_baud; } else return -EINVAL; break; default: return -EINVAL; } return ENOERR; } static int spi_lpc2xxx_set_config(cyg_spi_device *device, cyg_uint32 key, const void *buf, cyg_uint32 *len) { cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; switch(key) { case CYG_IO_SET_CONFIG_SPI_CLOCKRATE: if(*len == sizeof(cyg_uint32)) { dev->spi_baud = * (cyg_uint32 *) buf; spi_lpc2xxx_baud((cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus, dev->spi_baud); } else return -EINVAL; break; default: return -EINVAL; } return ENOERR; } /* * Begin transaction * configure bus for device and drive CS by calling device cs() function */ static void spi_lpc2xxx_begin(cyg_spi_device *device) { cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; cyg_uint8 cr = (dev->spi_cpha ? SPI_SPCR_CPHA : 0) | (dev->spi_cpol ? SPI_SPCR_CPOL : 0) | (dev->spi_lsbf ? SPI_SPCR_LSBF : 0); bus->spi_dev->spcr = SPI_SPCR_MSTR | cr; spi_lpc2xxx_baud(bus, dev->spi_baud); dev->spi_cs(1); } /* * Transfer a buffer to a device, * fill another buffer with data from the device */ static void spi_lpc2xxx_transfer(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count, const cyg_uint8 *tx_data, cyg_uint8 *rx_data, cyg_bool drop_cs) { cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; cyg_uint8 tmp; if(!count) return; if(!polled) { bus->count = count; bus->tx = tx_data; bus->rx = rx_data; bus->spi_dev->spcr |= SPI_SPCR_SPIE; bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0; cyg_drv_mutex_lock(&bus->spi_lock); cyg_drv_dsr_lock(); cyg_drv_interrupt_unmask(bus->spi_vect); while(bus->count) cyg_drv_cond_wait(&bus->spi_wait); cyg_drv_interrupt_mask(bus->spi_vect); cyg_drv_dsr_unlock(); cyg_drv_mutex_unlock(&bus->spi_lock); } else do { bus->spi_dev->spdr = tx_data ? *tx_data++ : 0; while(!(bus->spi_dev->spsr & SPI_SPSR_SPIF)); tmp = bus->spi_dev->spdr; if(rx_data) *rx_data++ = tmp; count--; } while(count); if(drop_cs) dev->spi_cs(0); return; } /* * Tick */ static void spi_lpc2xxx_tick(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count) { spi_lpc2xxx_transfer(device, polled, count, NULL, NULL, false); } /* * End transaction * disable SPI bus, drop CS, reset transfer variables */ static void spi_lpc2xxx_end(cyg_spi_device *device) { cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; bus->spi_dev->spcr = 0; dev->spi_cs(0); bus->count = 0; bus->tx = NULL; bus->rx = NULL; } /* * Driver & bus initialization */ static void spi_lpc2xxx_init_bus(cyg_spi_lpc2xxx_bus_t *bus, cyg_addrword_t dev, cyg_vector_t vec, cyg_priority_t prio) { bus->spi_bus.spi_transaction_begin = spi_lpc2xxx_begin; bus->spi_bus.spi_transaction_transfer = spi_lpc2xxx_transfer; bus->spi_bus.spi_transaction_tick = spi_lpc2xxx_tick; bus->spi_bus.spi_transaction_end = spi_lpc2xxx_end; bus->spi_bus.spi_get_config = spi_lpc2xxx_get_config; bus->spi_bus.spi_set_config = spi_lpc2xxx_set_config; CYG_SPI_BUS_COMMON_INIT(&bus->spi_bus); cyg_drv_mutex_init(&bus->spi_lock); cyg_drv_cond_init(&bus->spi_wait, &bus->spi_lock); bus->spi_dev = (struct spi_dev *) dev; bus->spi_vect = vec; bus->spi_prio = prio; cyg_drv_interrupt_create( vec, prio, (cyg_addrword_t) bus, &spi_lpc2xxx_isr, &spi_lpc2xxx_dsr, &bus->spi_hand, &bus->spi_intr); cyg_drv_interrupt_attach(bus->spi_hand); } /* * initialization class */ class cyg_spi_lpc2xxx_init_class { public: cyg_spi_lpc2xxx_init_class(void) { cyg_uint32 addr, tmp; #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0); HAL_READ_UINT32(addr, tmp); tmp |= 0x5500; HAL_WRITE_UINT32(addr, tmp); spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus0, CYGARC_HAL_LPC2XXX_REG_SPI0_BASE, CYGNUM_HAL_INTERRUPT_SPI0, CYGNUM_IO_SPI_ARM_LPC2XXX_BUS0_INTPRIO); #endif #ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1); HAL_READ_UINT32(addr, tmp); tmp |= 0x2a8; HAL_WRITE_UINT32(addr, tmp); spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus1, CYGARC_HAL_LPC2XXX_REG_SPI1_BASE, CYGNUM_HAL_INTERRUPT_SPI1, CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO); #endif } }; static cyg_spi_lpc2xxx_init_class spi_lpc2xxx_init CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_BUS_SPI);
Go to most recent revision | Compare with Previous | Blame | View Log