adding new spi flash driver

This commit is contained in:
Thomas Doerfler
2007-10-26 06:07:06 +00:00
parent 78c7192903
commit 83374f3b27
2 changed files with 382 additions and 0 deletions

View File

@@ -0,0 +1,338 @@
/*===============================================================*\
| Project: SPI driver for M25P40 like spi flash device |
+-----------------------------------------------------------------+
| Copyright (c) 2007 |
| Embedded Brains GmbH |
| Obere Lagerstr. 30 |
| D-82178 Puchheim |
| Germany |
| rtems@embedded-brains.de |
+-----------------------------------------------------------------+
| The license and distribution terms for this file may be |
| found in the file LICENSE in this distribution or at |
| |
| http://www.rtems.com/license/LICENSE. |
| |
+-----------------------------------------------------------------+
\*===============================================================*/
/*
* FIXME: currently, this driver only supports read accesses
* write/erase accesses are to be completed
*/
#include <rtems.h>
#include <rtems/libi2c.h>
#include <libchip/spi-flash-m25p40.h>
#include <rtems/libio.h>
#define FLASH_M25P40_CMD_WREN 0x06
#define FLASH_M25P40_CMD_WRDIS 0x04
#define FLASH_M25P40_CMD_RDID 0x9F
#define FLASH_M25P40_CMD_RDSR 0x05
#define FLASH_M25P40_CMD_WRSR 0x01
#define FLASH_M25P40_CMD_READ 0x03
#define FLASH_M25P40_CMD_PP 0x02 /* page program */
#define FLASH_M25P40_CMD_SE 0xD8 /* sector erase */
#define FLASH_M25P40_CMD_BE 0xC7 /* bulk erase */
#define FLASH_M25P40_CMD_DP 0xB9 /* deep power down */
#define FLASH_M25P40_CMD_RES 0xAB /* release from deep power down */
#define M25P40_PAGE_SIZE 256
#define M25P40_TOTAL_SIZE (512*1024)
const rtems_libi2c_tfr_mode_t spi_flash_m25p40_tfr_mode = {
baudrate: 20000000, /* maximum bits per second */
bits_per_char: 8, /* how many bits per byte/word/longword? */
lsb_first: FALSE, /* FALSE: send MSB first */
clock_inv: FALSE, /* FALSE: non-inverted clock (high active) */
clock_phs: FALSE /* FALSE: clock starts in middle of data tfr */
} ;
/*=========================================================================*\
| Function: |
\*-------------------------------------------------------------------------*/
rtems_status_code spi_flash_m25p40_wait_ms
(
/*-------------------------------------------------------------------------*\
| Purpose: |
| wait a certain interval given in ms |
+---------------------------------------------------------------------------+
| Input Parameters: |
\*-------------------------------------------------------------------------*/
int ms /* time to wait in milliseconds */
)
/*-------------------------------------------------------------------------*\
| Return Value: |
| o = ok or error code |
\*=========================================================================*/
{
rtems_status_code rc = RTEMS_SUCCESSFUL;
rtems_interval ticks_per_second;
rc = rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND,&ticks_per_second);
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_task_wake_after(ticks_per_second * ms / 1000);
}
return rc;
}
/*=========================================================================*\
| Function: |
\*-------------------------------------------------------------------------*/
rtems_status_code spi_flash_m25p40_write
(
/*-------------------------------------------------------------------------*\
| Purpose: |
| write a block of data to flash |
+---------------------------------------------------------------------------+
| Input Parameters: |
\*-------------------------------------------------------------------------*/
rtems_device_major_number major, /* major device number */
rtems_device_major_number minor, /* minor device number */
void *arg /* ptr to write argument struct */
)
/*-------------------------------------------------------------------------*\
| Return Value: |
| o = ok or error code |
\*=========================================================================*/
{
rtems_status_code rc = RTEMS_SUCCESSFUL;
rtems_libio_rw_args_t *rwargs = arg;
unsigned off = rwargs->offset;
int cnt = rwargs->count;
unsigned char *buf = (unsigned char *)rwargs->buffer;
int bytes_sent = 0;
int curr_cnt;
unsigned char cmdbuf[4];
int ret_cnt = 0;
/*
* FIXME: check arguments
*/
if (rc == RTEMS_SUCCESSFUL) {
}
/*
* select device, set transfer mode, address device
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_start(minor);
}
/*
* set transfer mode
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = -rtems_libi2c_ioctl(minor,
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
&spi_flash_m25p40_tfr_mode);
}
/*
* send write_enable command
*/
if (rc == RTEMS_SUCCESSFUL) {
cmdbuf[0] = FLASH_M25P40_CMD_WREN;
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
if (ret_cnt < 0) {
rc = -ret_cnt;
}
}
/*
* terminate transfer
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_stop(minor);
}
while ((rc == RTEMS_SUCCESSFUL) &&
(cnt > bytes_sent)) {
curr_cnt = cnt;
if ((off / M25P40_PAGE_SIZE) !=
((off+curr_cnt+1) / M25P40_PAGE_SIZE)) {
curr_cnt = M25P40_PAGE_SIZE - (off % M25P40_PAGE_SIZE);
}
/*
* select device, set transfer mode, address device
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_start(minor);
}
/*
* set transfer mode
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = -rtems_libi2c_ioctl(minor,
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
&spi_flash_m25p40_tfr_mode);
}
/*
* send "page program" command and address
*/
if (rc == RTEMS_SUCCESSFUL) {
cmdbuf[0] = FLASH_M25P40_CMD_PP;
cmdbuf[1] = (off >> 16) & 0xff;
cmdbuf[2] = (off >> 8) & 0xff;
cmdbuf[3] = (off >> 0) & 0xff;
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,4);
if (ret_cnt < 0) {
rc = -ret_cnt;
}
}
/*
* send write data
*/
if (rc == RTEMS_SUCCESSFUL) {
ret_cnt = rtems_libi2c_write_bytes(minor,buf,curr_cnt);
if (ret_cnt < 0) {
rc = -ret_cnt;
}
}
/*
* terminate transfer
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_stop(minor);
}
/*
* wait proper time for data to store: 5ms
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = spi_flash_m25p40_wait_ms(5);
}
/*
* adjust bytecount to be sent and pointers
*/
bytes_sent += curr_cnt;
off += curr_cnt;
buf += curr_cnt;
}
rwargs->bytes_moved = bytes_sent;
return rc;
}
/*=========================================================================*\
| Function: |
\*-------------------------------------------------------------------------*/
rtems_status_code spi_flash_m25p40_read
(
/*-------------------------------------------------------------------------*\
| Purpose: |
| read a block of data from flash |
+---------------------------------------------------------------------------+
| Input Parameters: |
\*-------------------------------------------------------------------------*/
rtems_device_major_number major, /* major device number */
rtems_device_major_number minor, /* minor device number */
void *arg /* ptr to read argument struct */
)
/*-------------------------------------------------------------------------*\
| Return Value: |
| o = ok or error code |
\*=========================================================================*/
{
rtems_status_code rc = RTEMS_SUCCESSFUL;
rtems_libio_rw_args_t *rwargs = arg;
unsigned off = rwargs->offset;
int cnt = rwargs->count;
unsigned char *buf = (unsigned char *)rwargs->buffer;
unsigned char cmdbuf[4];
int ret_cnt = 0;
/*
* FIXME: check arguments
*/
if (rc == RTEMS_SUCCESSFUL) {
}
/*
* select device, set transfer mode, address device
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_start(minor);
}
/*
* set transfer mode
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = -rtems_libi2c_ioctl(minor,
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
&spi_flash_m25p40_tfr_mode);
}
/*
* address device
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_addr(minor,TRUE);
}
if (off >= M25P40_TOTAL_SIZE) {
/*
* HACK: beyond size of Flash array? then read status register instead
*/
/*
* send read status register command
*/
if (rc == RTEMS_SUCCESSFUL) {
cmdbuf[0] = FLASH_M25P40_CMD_RDSR;
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,1);
if (ret_cnt < 0) {
rc = -ret_cnt;
}
}
}
else {
/*
* send read command and address
*/
if (rc == RTEMS_SUCCESSFUL) {
cmdbuf[0] = FLASH_M25P40_CMD_READ;
cmdbuf[1] = (off >> 16) & 0xff;
cmdbuf[2] = (off >> 8) & 0xff;
cmdbuf[3] = (off >> 0) & 0xff;
ret_cnt = rtems_libi2c_write_bytes(minor,cmdbuf,4);
if (ret_cnt < 0) {
rc = -ret_cnt;
}
}
}
/*
* fetch read data
*/
if (rc == RTEMS_SUCCESSFUL) {
ret_cnt = rtems_libi2c_read_bytes (minor,buf,cnt);
if (ret_cnt < 0) {
rc = -ret_cnt;
}
}
/*
* terminate transfer
*/
if (rc == RTEMS_SUCCESSFUL) {
rc = rtems_libi2c_send_stop(minor);
}
rwargs->bytes_moved = (rc == RTEMS_SUCCESSFUL) ? ret_cnt : 0;
return rc;
}
static rtems_driver_address_table spi_flash_m25p40_rw_ops = {
read_entry: spi_flash_m25p40_read,
write_entry: spi_flash_m25p40_write
};
static rtems_libi2c_drv_t spi_flash_m25p40_rw_drv_tbl = {
ops: &spi_flash_m25p40_rw_ops,
size: sizeof (spi_flash_m25p40_rw_drv_tbl),
};
rtems_libi2c_drv_t *spi_flash_m25p40_rw_driver_descriptor =
&spi_flash_m25p40_rw_drv_tbl;
static rtems_driver_address_table spi_flash_m25p40_ro_ops = {
read_entry: spi_flash_m25p40_read,
};
static rtems_libi2c_drv_t spi_flash_m25p40_ro_drv_tbl = {
ops: &spi_flash_m25p40_ro_ops,
size: sizeof (spi_flash_m25p40_ro_drv_tbl),
};
rtems_libi2c_drv_t *spi_flash_m25p40_ro_driver_descriptor =
&spi_flash_m25p40_ro_drv_tbl;

View File

@@ -0,0 +1,44 @@
/*===============================================================*\
| Project: SPI driver for M25P40 like spi flash device |
+-----------------------------------------------------------------+
| Copyright (c) 2007 |
| Embedded Brains GmbH |
| Obere Lagerstr. 30 |
| D-82178 Puchheim |
| Germany |
| rtems@embedded-brains.de |
+-----------------------------------------------------------------+
| The license and distribution terms for this file may be |
| found in the file LICENSE in this distribution or at |
| |
| http://www.rtems.com/license/LICENSE. |
| |
+-----------------------------------------------------------------+
\*===============================================================*/
/*
* FIXME: currently, this driver only supports read accesses
* write/erase accesses are to be completed
*/
#ifndef _LIBCHIP_SPI_FLASH_M25P40_H
#define _LIBCHIP_SPI_FLASH_M25P40_H
#include <rtems/libi2c.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* pass one of these descriptor pointers to rtems_libi2c_register_drv
*/
extern rtems_libi2c_drv_t *spi_flash_m25p40_rw_driver_descriptor;
extern rtems_libi2c_drv_t *spi_flash_m25p40_ro_driver_descriptor;
#ifdef __cplusplus
}
#endif
#endif /* _LIBCHIP_SPI_FLASH_M25P40_H */