summaryrefslogtreecommitdiffstats
path: root/c/src/libchip
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2007-10-26 06:07:06 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2007-10-26 06:07:06 +0000
commit83374f3b273e9b3a7ff101e8f306fe396d19a5ba (patch)
tree3551dff8cc629576a3bc3c8a6b880d13e9558659 /c/src/libchip
parent2007-10-25 Joel Sherrill <joel.sherrill@oarcorp.com> (diff)
downloadrtems-83374f3b273e9b3a7ff101e8f306fe396d19a5ba.tar.bz2
adding new spi flash driver
Diffstat (limited to 'c/src/libchip')
-rw-r--r--c/src/libchip/i2c/spi-flash-m25p40.c338
-rw-r--r--c/src/libchip/i2c/spi-flash-m25p40.h44
2 files changed, 382 insertions, 0 deletions
diff --git a/c/src/libchip/i2c/spi-flash-m25p40.c b/c/src/libchip/i2c/spi-flash-m25p40.c
new file mode 100644
index 0000000000..310f9c80cc
--- /dev/null
+++ b/c/src/libchip/i2c/spi-flash-m25p40.c
@@ -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;
diff --git a/c/src/libchip/i2c/spi-flash-m25p40.h b/c/src/libchip/i2c/spi-flash-m25p40.h
new file mode 100644
index 0000000000..786ba55792
--- /dev/null
+++ b/c/src/libchip/i2c/spi-flash-m25p40.h
@@ -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 */