浏览代码

add more SPI device driver.

aozima 10 年之前
父节点
当前提交
0fc1ac6189

+ 22 - 2
components/drivers/spi/SConscript

@@ -1,8 +1,28 @@
 from building import *
 from building import *
 
 
-cwd     = GetCurrentDir()
-src	= Glob('*.c')
+cwd = GetCurrentDir()
+src = ['spi_core.c', 'spi_dev.c']
 CPPPATH = [cwd + '/../include']
 CPPPATH = [cwd + '/../include']
+
+src_device = []
+
+if GetDepend('RT_USING_SPI_WIFI'):
+    src_device += ['spi_wifi_rw009.c']
+
+if GetDepend('RT_USING_W25QXX'):
+    src_device += ['spi_flash_w25qxx.c']
+
+if GetDepend('RT_USING_ENC28J60'):
+    src_device += ['enc28j60.c']
+
+if GetDepend('RT_USING_AT45DBXX'):
+    src_device += ['spi_flash_at45dbxx.c']
+
+if GetDepend('RT_USING_SST25VFXX'):
+    src_device += ['spi_flash_sst25vfxx.c']
+
+src += src_device
+
 group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)
 group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)
 
 
 Return('group')
 Return('group')

+ 15 - 0
components/drivers/spi/device_driver_list.txt

@@ -0,0 +1,15 @@
+spi_wifi_rw009.c/spi_wifi_rw009.h
+RW009
+http://www.rt-thread.com/
+
+enc28j60.c/enc28j60.h
+http://www.microchip.com/
+
+spi_flash_at45dbxx.c/spi_flash_at45dbxx.h
+http://www.atmel.com/
+
+spi_flash_sst25vfxx.c/spi_flash_sst25vfxx.h
+http://www.microchip.com/
+
+spi_flash_w25qxx.c/spi_flash_w25qxx.h
+http://www.winbond.com/

+ 876 - 0
components/drivers/spi/enc28j60.c

@@ -0,0 +1,876 @@
+#include "enc28j60.h"
+
+#define NET_TRACE
+#define ETH_RX_DUMP
+#define ETH_TX_DUMP
+
+#ifdef NET_TRACE
+#define NET_DEBUG         rt_kprintf
+#else
+#define NET_DEBUG(...)
+#endif /* #ifdef NET_TRACE */
+
+struct enc28j60_tx_list_typedef
+{
+    struct enc28j60_tx_list_typedef * prev;
+    struct enc28j60_tx_list_typedef * next;
+    rt_uint32_t addr; /* pkt addr in buffer */
+    rt_uint32_t len;  /* pkt len */
+    volatile rt_bool_t free; /* 0:busy, 1:free */
+};
+static struct enc28j60_tx_list_typedef enc28j60_tx_list[2];
+static volatile struct enc28j60_tx_list_typedef * tx_current;
+static volatile struct enc28j60_tx_list_typedef * tx_ack;
+static struct rt_event tx_event;
+
+/* private enc28j60 define */
+/* enc28j60 spi interface function */
+static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address);
+static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data);
+
+static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address);
+static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data);
+
+static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk);
+static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address);
+static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device);
+static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level);
+
+static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address);
+static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data);
+static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device);
+
+#define enc28j60_lock(dev)      rt_mutex_take(&((struct net_device*)dev)->lock, RT_WAITING_FOREVER);
+#define enc28j60_unlock(dev)    rt_mutex_release(&((struct net_device*)dev)->lock);
+
+static struct net_device  enc28j60_dev;
+static uint8_t  Enc28j60Bank;
+//struct rt_spi_device * spi_device;
+static uint16_t NextPacketPtr;
+
+static void _delay_us(uint32_t us)
+{
+    volatile uint32_t len;
+    for (; us > 0; us --)
+        for (len = 0; len < 20; len++ );
+}
+
+/* enc28j60 spi interface function */
+static uint8_t spi_read_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address)
+{
+    uint8_t send_buffer[2];
+    uint8_t recv_buffer[1];
+    uint32_t send_size = 1;
+
+    send_buffer[0] = op | (address & ADDR_MASK);
+    send_buffer[1] = 0xFF;
+
+    /* do dummy read if needed (for mac and mii, see datasheet page 29). */
+    if(address & 0x80)
+    {
+        send_size = 2;
+    }
+
+    rt_spi_send_then_recv(spi_device, send_buffer, send_size, recv_buffer, 1);
+    return (recv_buffer[0]);
+}
+
+static void spi_write_op(struct rt_spi_device * spi_device, uint8_t op, uint8_t address, uint8_t data)
+{
+    uint32_t level;
+    uint8_t buffer[2];
+
+    level = rt_hw_interrupt_disable();
+
+    buffer[0] = op | (address & ADDR_MASK);
+    buffer[1] = data;
+    rt_spi_send(spi_device, buffer, 2);
+
+    rt_hw_interrupt_enable(level);
+}
+
+/* enc28j60 function */
+static void enc28j60_clkout(struct rt_spi_device * spi_device, rt_uint8_t clk)
+{
+    /* setup clkout: 2 is 12.5MHz: */
+    spi_write(spi_device, ECOCON, clk & 0x7);
+}
+
+static void enc28j60_set_bank(struct rt_spi_device * spi_device, uint8_t address)
+{
+    /* set the bank (if needed) .*/
+    if((address & BANK_MASK) != Enc28j60Bank)
+    {
+        /* set the bank. */
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
+        Enc28j60Bank = (address & BANK_MASK);
+    }
+}
+
+static uint8_t spi_read(struct rt_spi_device * spi_device, uint8_t address)
+{
+    /* set the bank. */
+    enc28j60_set_bank(spi_device, address);
+    /* do the read. */
+    return spi_read_op(spi_device, ENC28J60_READ_CTRL_REG, address);
+}
+
+static void spi_write(struct rt_spi_device * spi_device, rt_uint8_t address, rt_uint8_t data)
+{
+    /* set the bank. */
+    enc28j60_set_bank(spi_device, address);
+    /* do the write. */
+    spi_write_op(spi_device, ENC28J60_WRITE_CTRL_REG, address, data);
+}
+
+static uint16_t enc28j60_phy_read(struct rt_spi_device * spi_device, rt_uint8_t address)
+{
+    uint16_t value;
+
+    /* Set the right address and start the register read operation. */
+    spi_write(spi_device, MIREGADR, address);
+    spi_write(spi_device, MICMD, MICMD_MIIRD);
+
+    _delay_us(15);
+
+    /* wait until the PHY read completes. */
+    while(spi_read(spi_device, MISTAT) & MISTAT_BUSY);
+
+    /* reset reading bit */
+    spi_write(spi_device, MICMD, 0x00);
+
+    value = spi_read(spi_device, MIRDL) | spi_read(spi_device, MIRDH)<<8;
+
+    return (value);
+}
+
+static void enc28j60_phy_write(struct rt_spi_device * spi_device, rt_uint8_t address, uint16_t data)
+{
+    /* set the PHY register address. */
+    spi_write(spi_device, MIREGADR, address);
+
+    /* write the PHY data. */
+    spi_write(spi_device, MIWRL, data);
+    spi_write(spi_device, MIWRH, data>>8);
+
+    /* wait until the PHY write completes. */
+    while(spi_read(spi_device, MISTAT) & MISTAT_BUSY)
+    {
+        _delay_us(15);
+    }
+}
+
+static uint32_t enc28j60_interrupt_disable(struct rt_spi_device * spi_device)
+{
+    uint32_t level;
+
+    /* switch to bank 0 */
+    enc28j60_set_bank(spi_device, EIE);
+
+    /* get last interrupt level */
+    level = spi_read(spi_device, EIE);
+    /* disable interrutps */
+    spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, level);
+
+    return level;
+}
+
+static void enc28j60_interrupt_enable(struct rt_spi_device * spi_device, uint32_t level)
+{
+    /* switch to bank 0 */
+    enc28j60_set_bank(spi_device, EIE);
+    spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, level);
+}
+
+/*
+ * Access the PHY to determine link status
+ */
+static rt_bool_t enc28j60_check_link_status(struct rt_spi_device * spi_device)
+{
+    uint16_t reg;
+    int duplex;
+
+    reg = enc28j60_phy_read(spi_device, PHSTAT2);
+    duplex = reg & PHSTAT2_DPXSTAT;
+
+    if (reg & PHSTAT2_LSTAT)
+    {
+        /* on */
+        return RT_TRUE;
+    }
+    else
+    {
+        /* off */
+        return RT_FALSE;
+    }
+}
+
+
+/************************* RT-Thread Device Interface *************************/
+void enc28j60_isr(void)
+{
+    eth_device_ready(&enc28j60_dev.parent);
+    NET_DEBUG("enc28j60_isr\r\n");
+}
+
+static void _tx_chain_init(void)
+{
+    enc28j60_tx_list[0].next = &enc28j60_tx_list[1];
+    enc28j60_tx_list[1].next = &enc28j60_tx_list[0];
+
+    enc28j60_tx_list[0].prev = &enc28j60_tx_list[1];
+    enc28j60_tx_list[1].prev = &enc28j60_tx_list[0];
+
+    enc28j60_tx_list[0].addr = TXSTART_INIT;
+    enc28j60_tx_list[1].addr = TXSTART_INIT + MAX_TX_PACKAGE_SIZE;
+
+    enc28j60_tx_list[0].free = RT_TRUE;
+    enc28j60_tx_list[1].free = RT_TRUE;
+
+    tx_current = &enc28j60_tx_list[0];
+    tx_ack = tx_current;
+}
+
+/* initialize the interface */
+static rt_err_t enc28j60_init(rt_device_t dev)
+{
+    struct net_device * enc28j60 = (struct net_device *)dev;
+    struct rt_spi_device * spi_device = enc28j60->spi_device;
+
+    enc28j60_lock(dev);
+
+    _tx_chain_init();
+
+    // perform system reset
+    spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+    rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */
+
+    NextPacketPtr = RXSTART_INIT;
+
+    // Rx start
+    spi_write(spi_device, ERXSTL, RXSTART_INIT&0xFF);
+    spi_write(spi_device, ERXSTH, RXSTART_INIT>>8);
+    // set receive pointer address
+    spi_write(spi_device, ERXRDPTL, RXSTOP_INIT&0xFF);
+    spi_write(spi_device, ERXRDPTH, RXSTOP_INIT>>8);
+    // RX end
+    spi_write(spi_device, ERXNDL, RXSTOP_INIT&0xFF);
+    spi_write(spi_device, ERXNDH, RXSTOP_INIT>>8);
+
+    // TX start
+    spi_write(spi_device, ETXSTL, TXSTART_INIT&0xFF);
+    spi_write(spi_device, ETXSTH, TXSTART_INIT>>8);
+    // set transmission pointer address
+    spi_write(spi_device, EWRPTL, TXSTART_INIT&0xFF);
+    spi_write(spi_device, EWRPTH, TXSTART_INIT>>8);
+    // TX end
+    spi_write(spi_device, ETXNDL, TXSTOP_INIT&0xFF);
+    spi_write(spi_device, ETXNDH, TXSTOP_INIT>>8);
+
+    // do bank 1 stuff, packet filter:
+    // For broadcast packets we allow only ARP packtets
+    // All other packets should be unicast only for our mac (MAADR)
+    //
+    // The pattern to match on is therefore
+    // Type     ETH.DST
+    // ARP      BROADCAST
+    // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
+    // in binary these poitions are:11 0000 0011 1111
+    // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
+    spi_write(spi_device, ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_BCEN);
+
+    // do bank 2 stuff
+    // enable MAC receive
+    spi_write(spi_device, MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
+    // enable automatic padding to 60bytes and CRC operations
+    // spi_write_op(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
+    spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
+    // bring MAC out of reset
+
+    // set inter-frame gap (back-to-back)
+    // spi_write(MABBIPG, 0x12);
+    spi_write(spi_device, MABBIPG, 0x15);
+
+    spi_write(spi_device, MACON4, MACON4_DEFER);
+    spi_write(spi_device, MACLCON2, 63);
+
+    // set inter-frame gap (non-back-to-back)
+    spi_write(spi_device, MAIPGL, 0x12);
+    spi_write(spi_device, MAIPGH, 0x0C);
+
+    // Set the maximum packet size which the controller will accept
+    // Do not send packets longer than MAX_FRAMELEN:
+    spi_write(spi_device, MAMXFLL, MAX_FRAMELEN&0xFF);
+    spi_write(spi_device, MAMXFLH, MAX_FRAMELEN>>8);
+
+    // do bank 3 stuff
+    // write MAC address
+    // NOTE: MAC address in ENC28J60 is byte-backward
+    spi_write(spi_device, MAADR0, enc28j60->dev_addr[5]);
+    spi_write(spi_device, MAADR1, enc28j60->dev_addr[4]);
+    spi_write(spi_device, MAADR2, enc28j60->dev_addr[3]);
+    spi_write(spi_device, MAADR3, enc28j60->dev_addr[2]);
+    spi_write(spi_device, MAADR4, enc28j60->dev_addr[1]);
+    spi_write(spi_device, MAADR5, enc28j60->dev_addr[0]);
+
+    /* output off */
+    spi_write(spi_device, ECOCON, 0x00);
+
+    // enc28j60_phy_write(PHCON1, 0x00);
+    enc28j60_phy_write(spi_device, PHCON1, PHCON1_PDPXMD); // full duplex
+    // no loopback of transmitted frames
+    enc28j60_phy_write(spi_device, PHCON2, PHCON2_HDLDIS);
+
+    enc28j60_set_bank(spi_device, ECON2);
+    spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_AUTOINC);
+
+    // switch to bank 0
+    enc28j60_set_bank(spi_device, ECON1);
+    // enable all interrutps
+    spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, EIE, 0xFF);
+    // enable packet reception
+    spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+    /* clock out */
+    enc28j60_clkout(spi_device, 2);
+
+    enc28j60_phy_write(spi_device, PHLCON, 0xD76);	//0x476
+    rt_thread_delay(RT_TICK_PER_SECOND/50); /* delay 20ms */
+
+    enc28j60_unlock(dev);
+    return RT_EOK;
+}
+
+/* control the interface */
+static rt_err_t enc28j60_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+    struct net_device * enc28j60 = (struct net_device *)dev;
+    switch(cmd)
+    {
+    case NIOCTL_GADDR:
+        /* get mac address */
+        if(args) rt_memcpy(args, enc28j60->dev_addr, 6);
+        else return -RT_ERROR;
+        break;
+
+    default :
+        break;
+    }
+
+    return RT_EOK;
+}
+
+/* Open the ethernet interface */
+static rt_err_t enc28j60_open(rt_device_t dev, uint16_t oflag)
+{
+    return RT_EOK;
+}
+
+/* Close the interface */
+static rt_err_t enc28j60_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+/* Read */
+static rt_size_t enc28j60_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return RT_EOK;
+}
+
+/* Write */
+static rt_size_t enc28j60_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+/* ethernet device interface */
+/* Transmit packet. */
+static rt_err_t enc28j60_tx( rt_device_t dev, struct pbuf* p)
+{
+    struct net_device * enc28j60 = (struct net_device *)dev;
+    struct rt_spi_device * spi_device = enc28j60->spi_device;
+    struct pbuf* q;
+    rt_uint32_t level;
+#ifdef ETH_TX_DUMP
+    rt_size_t dump_count = 0;
+    rt_uint8_t * dump_ptr;
+    rt_size_t dump_i;
+#endif
+
+    if(tx_current->free == RT_FALSE)
+    {
+        NET_DEBUG("[Tx] no empty buffer!\r\n");
+        while(tx_current->free == RT_FALSE)
+        {
+            rt_err_t result;
+            rt_uint32_t recved;
+
+            /* there is no block yet, wait a flag */
+            result = rt_event_recv(&tx_event, 0x01,
+                                   RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved);
+
+            RT_ASSERT(result == RT_EOK);
+        }
+        NET_DEBUG("[Tx] wait empty buffer done!\r\n");
+    }
+
+    enc28j60_lock(dev);
+
+    /* disable enc28j60 interrupt */
+    level = enc28j60_interrupt_disable(spi_device);
+
+    // Set the write pointer to start of transmit buffer area
+//    spi_write(EWRPTL, TXSTART_INIT&0xFF);
+//    spi_write(EWRPTH, TXSTART_INIT>>8);
+    spi_write(spi_device, EWRPTL, (tx_current->addr)&0xFF);
+    spi_write(spi_device, EWRPTH, (tx_current->addr)>>8);
+    // Set the TXND pointer to correspond to the packet size given
+    tx_current->len = p->tot_len;
+//    spi_write(ETXNDL, (TXSTART_INIT+ p->tot_len + 1)&0xFF);
+//    spi_write(ETXNDH, (TXSTART_INIT+ p->tot_len + 1)>>8);
+
+    // write per-packet control byte (0x00 means use macon3 settings)
+    spi_write_op(spi_device, ENC28J60_WRITE_BUF_MEM, 0, 0x00);
+
+#ifdef ETH_TX_DUMP
+    NET_DEBUG("tx_dump, size:%d\r\n", p->tot_len);
+#endif
+    for (q = p; q != NULL; q = q->next)
+    {
+        uint8_t cmd = ENC28J60_WRITE_BUF_MEM;
+        rt_spi_send_then_send(enc28j60->spi_device, &cmd, 1, q->payload, q->len);
+#ifdef ETH_RX_DUMP
+        dump_ptr = q->payload;
+        for(dump_i=0; dump_i<q->len; dump_i++)
+        {
+            NET_DEBUG("%02x ", *dump_ptr);
+            if( ((dump_count+1)%8) == 0 )
+            {
+                NET_DEBUG("  ");
+            }
+            if( ((dump_count+1)%16) == 0 )
+            {
+                NET_DEBUG("\r\n");
+            }
+            dump_count++;
+            dump_ptr++;
+        }
+#endif
+    }
+#ifdef ETH_RX_DUMP
+    NET_DEBUG("\r\n");
+#endif
+
+    // send the contents of the transmit buffer onto the network
+    if(tx_current == tx_ack)
+    {
+        NET_DEBUG("[Tx] stop, restart!\r\n");
+        // TX start
+        spi_write(spi_device, ETXSTL, (tx_current->addr)&0xFF);
+        spi_write(spi_device, ETXSTH, (tx_current->addr)>>8);
+        // TX end
+        spi_write(spi_device, ETXNDL, (tx_current->addr + tx_current->len)&0xFF);
+        spi_write(spi_device, ETXNDH, (tx_current->addr + tx_current->len)>>8);
+
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+    }
+    else
+    {
+        NET_DEBUG("[Tx] busy, add to chain!\r\n");
+    }
+
+    tx_current->free = RT_FALSE;
+    tx_current = tx_current->next;
+
+    /* Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. */
+    if( (spi_read(spi_device, EIR) & EIR_TXERIF) )
+    {
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
+    }
+
+    /* enable enc28j60 interrupt */
+    enc28j60_interrupt_enable(spi_device, level);
+
+    enc28j60_unlock(dev);
+
+    return RT_EOK;
+}
+
+/* recv packet. */
+static struct pbuf *enc28j60_rx(rt_device_t dev)
+{
+    struct net_device * enc28j60 = (struct net_device *)dev;
+    struct rt_spi_device * spi_device = enc28j60->spi_device;
+    struct pbuf* p = RT_NULL;
+
+    uint8_t eir, eir_clr;
+    uint32_t pk_counter;
+    rt_uint32_t level;
+    rt_uint32_t len;
+    rt_uint16_t rxstat;
+
+    enc28j60_lock(dev);
+
+    /* disable enc28j60 interrupt */
+    level = enc28j60_interrupt_disable(spi_device);
+
+    /* get EIR */
+    eir = spi_read(spi_device, EIR);
+
+    while(eir & ~EIR_PKTIF)
+    {
+        eir_clr = 0;
+
+        /* clear PKTIF */
+        if (eir & EIR_PKTIF)
+        {
+            NET_DEBUG("EIR_PKTIF\r\n");
+
+            /* switch to bank 0. */
+            enc28j60_set_bank(spi_device, EIE);
+            /* disable rx interrutps. */
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIE, EIE_PKTIE);
+            eir_clr |= EIR_PKTIF;
+//            enc28j60_set_bank(spi_device, EIR);
+//            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_PKTIF);
+        }
+
+        /* clear DMAIF */
+        if (eir & EIR_DMAIF)
+        {
+            NET_DEBUG("EIR_DMAIF\r\n");
+            eir_clr |= EIR_DMAIF;
+//            enc28j60_set_bank(spi_device, EIR);
+//            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_DMAIF);
+        }
+
+        /* LINK changed handler */
+        if ( eir & EIR_LINKIF)
+        {
+            rt_bool_t link_status;
+
+            NET_DEBUG("EIR_LINKIF\r\n");
+            link_status = enc28j60_check_link_status(spi_device);
+
+            /* read PHIR to clear the flag */
+            enc28j60_phy_read(spi_device, PHIR);
+            eir_clr |= EIR_LINKIF;
+//            enc28j60_set_bank(spi_device, EIR);
+//            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_LINKIF);
+
+            eth_device_linkchange(&(enc28j60->parent), link_status);
+        }
+
+        if (eir & EIR_TXIF)
+        {
+            /* A frame has been transmitted. */
+            enc28j60_set_bank(spi_device, EIR);
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXIF);
+
+            tx_ack->free = RT_TRUE;
+            tx_ack = tx_ack->next;
+            if(tx_ack->free == RT_FALSE)
+            {
+                NET_DEBUG("[tx isr] Tx chain not empty, continue send the next pkt!\r\n");
+                // TX start
+                spi_write(spi_device, ETXSTL, (tx_ack->addr)&0xFF);
+                spi_write(spi_device, ETXSTH, (tx_ack->addr)>>8);
+                // TX end
+                spi_write(spi_device, ETXNDL, (tx_ack->addr + tx_ack->len)&0xFF);
+                spi_write(spi_device, ETXNDH, (tx_ack->addr + tx_ack->len)>>8);
+
+                spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+            }
+            else
+            {
+                NET_DEBUG("[tx isr] Tx chain empty, stop!\r\n");
+            }
+
+            /* set event */
+            rt_event_send(&tx_event, 0x01);
+        }
+
+        /* wake up handler */
+        if ( eir & EIR_WOLIF)
+        {
+            NET_DEBUG("EIR_WOLIF\r\n");
+            eir_clr |= EIR_WOLIF;
+//            enc28j60_set_bank(spi_device, EIR);
+//            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_WOLIF);
+        }
+
+        /* TX Error handler */
+        if ((eir & EIR_TXERIF) != 0)
+        {
+            NET_DEBUG("EIR_TXERIF re-start tx chain!\r\n");
+            enc28j60_set_bank(spi_device, ECON1);
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
+            eir_clr |= EIR_TXERIF;
+//            enc28j60_set_bank(spi_device, EIR);
+//            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
+
+            /* re-init tx chain */
+            _tx_chain_init();
+        }
+
+        /* RX Error handler */
+        if ((eir & EIR_RXERIF) != 0)
+        {
+            NET_DEBUG("EIR_RXERIF re-start rx!\r\n");
+
+            NextPacketPtr = RXSTART_INIT;
+            enc28j60_set_bank(spi_device, ECON1);
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXRST);
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXRST);
+            /* switch to bank 0. */
+            enc28j60_set_bank(spi_device, ECON1);
+            /* enable packet reception. */
+            spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+            eir_clr |= EIR_RXERIF;
+//            enc28j60_set_bank(spi_device, EIR);
+//            spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, EIR_RXERIF);
+        }
+
+        enc28j60_set_bank(spi_device, EIR);
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_CLR, EIR, eir_clr);
+
+        eir = spi_read(spi_device, EIR);
+    }
+
+    /* read pkt */
+    pk_counter = spi_read(spi_device, EPKTCNT);
+    if(pk_counter)
+    {
+        /* Set the read pointer to the start of the received packet. */
+        spi_write(spi_device, ERDPTL, (NextPacketPtr));
+        spi_write(spi_device, ERDPTH, (NextPacketPtr)>>8);
+
+        /* read the next packet pointer. */
+        NextPacketPtr  = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);
+        NextPacketPtr |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8;
+
+        /* read the packet length (see datasheet page 43). */
+        len  = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);	    //0x54
+        len |= spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0)<<8;	//5554
+
+        len-=4; //remove the CRC count
+
+        // read the receive status (see datasheet page 43)
+        rxstat  = spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0);
+        rxstat |= ((rt_uint16_t)spi_read_op(spi_device, ENC28J60_READ_BUF_MEM, 0))<<8;
+
+        // check CRC and symbol errors (see datasheet page 44, table 7-3):
+        // The ERXFCON.CRCEN is set by default. Normally we should not
+        // need to check this.
+        if ((rxstat & 0x80)==0)
+        {
+            // invalid
+            len=0;
+        }
+        else
+        {
+            /* allocation pbuf */
+            p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
+            if (p != RT_NULL)
+            {
+                struct pbuf* q;
+#ifdef ETH_RX_DUMP
+                rt_size_t dump_count = 0;
+                rt_uint8_t * dump_ptr;
+                rt_size_t dump_i;
+                NET_DEBUG("rx_dump, size:%d\r\n", len);
+#endif
+                for (q = p; q != RT_NULL; q= q->next)
+                {
+                    uint8_t cmd = ENC28J60_READ_BUF_MEM;
+                    rt_spi_send_then_recv(spi_device, &cmd, 1, q->payload, q->len);
+#ifdef ETH_RX_DUMP
+                    dump_ptr = q->payload;
+                    for(dump_i=0; dump_i<q->len; dump_i++)
+                    {
+                        NET_DEBUG("%02x ", *dump_ptr);
+                        if( ((dump_count+1)%8) == 0 )
+                        {
+                            NET_DEBUG("  ");
+                        }
+                        if( ((dump_count+1)%16) == 0 )
+                        {
+                            NET_DEBUG("\r\n");
+                        }
+                        dump_count++;
+                        dump_ptr++;
+                    }
+#endif
+                }
+#ifdef ETH_RX_DUMP
+                NET_DEBUG("\r\n");
+#endif
+            }
+        }
+
+        /* Move the RX read pointer to the start of the next received packet. */
+        /* This frees the memory we just read out. */
+        spi_write(spi_device, ERXRDPTL, (NextPacketPtr));
+        spi_write(spi_device, ERXRDPTH, (NextPacketPtr)>>8);
+
+        /* decrement the packet counter indicate we are done with this packet. */
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
+    }
+    else
+    {
+        /* switch to bank 0. */
+        enc28j60_set_bank(spi_device, ECON1);
+        /* enable packet reception. */
+        spi_write_op(spi_device, ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+        level |= EIE_PKTIE;
+    }
+
+    /* enable enc28j60 interrupt */
+    enc28j60_interrupt_enable(spi_device, level);
+
+    enc28j60_unlock(dev);
+
+    return p;
+}
+
+rt_err_t enc28j60_attach(const char * spi_device_name)
+{
+    struct rt_spi_device * spi_device;
+
+    spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+    if(spi_device == RT_NULL)
+    {
+        NET_DEBUG("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */
+        cfg.max_hz = 20 * 1000 * 1000; /* SPI Interface with Clock Speeds Up to 20 MHz */
+        rt_spi_configure(spi_device, &cfg);
+    } /* config spi */
+
+    memset(&enc28j60_dev, 0, sizeof(enc28j60_dev));
+
+    rt_event_init(&tx_event, "eth_tx", RT_IPC_FLAG_FIFO);
+    enc28j60_dev.spi_device = spi_device;
+
+    /* detect device */
+    {
+        uint16_t value;
+
+        /* perform system reset. */
+        spi_write_op(spi_device, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+        rt_thread_delay(1); /* delay 20ms */
+
+        enc28j60_dev.emac_rev = spi_read(spi_device, EREVID);
+        value = enc28j60_phy_read(spi_device, PHHID2);
+        enc28j60_dev.phy_rev = value&0x0F;
+        enc28j60_dev.phy_pn = (value>>4)&0x3F;
+        enc28j60_dev.phy_id = (enc28j60_phy_read(spi_device, PHHID1) | ((value>>10)<<16))<<3;
+
+        if(enc28j60_dev.phy_id != 0x00280418)
+        {
+            NET_DEBUG("ENC28J60 PHY ID not correct!\r\n");
+            NET_DEBUG("emac_rev:%d\r\n", enc28j60_dev.emac_rev);
+            NET_DEBUG("phy_rev:%02X\r\n", enc28j60_dev.phy_rev);
+            NET_DEBUG("phy_pn:%02X\r\n", enc28j60_dev.phy_pn);
+            NET_DEBUG("phy_id:%08X\r\n", enc28j60_dev.phy_id);
+            return RT_EIO;
+        }
+    }
+
+    /* OUI 00-04-A3 (hex): Microchip Technology, Inc. */
+    enc28j60_dev.dev_addr[0] = 0x00;
+    enc28j60_dev.dev_addr[1] = 0x04;
+    enc28j60_dev.dev_addr[2] = 0xA3;
+    /* set MAC address, only for test */
+    enc28j60_dev.dev_addr[3] = 0x12;
+    enc28j60_dev.dev_addr[4] = 0x34;
+    enc28j60_dev.dev_addr[5] = 0x56;
+
+    /* init rt-thread device struct */
+    enc28j60_dev.parent.parent.type    = RT_Device_Class_NetIf;
+    enc28j60_dev.parent.parent.init    = enc28j60_init;
+    enc28j60_dev.parent.parent.open    = enc28j60_open;
+    enc28j60_dev.parent.parent.close   = enc28j60_close;
+    enc28j60_dev.parent.parent.read    = enc28j60_read;
+    enc28j60_dev.parent.parent.write   = enc28j60_write;
+    enc28j60_dev.parent.parent.control = enc28j60_control;
+
+    /* init rt-thread ethernet device struct */
+    enc28j60_dev.parent.eth_rx  = enc28j60_rx;
+    enc28j60_dev.parent.eth_tx  = enc28j60_tx;
+
+    rt_mutex_init(&enc28j60_dev.lock, "enc28j60", RT_IPC_FLAG_FIFO);
+
+    eth_device_init(&(enc28j60_dev.parent), "e0");
+
+    return RT_EOK;
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+/*
+ * Debug routine to dump useful register contents
+ */
+static void enc28j60(void)
+{
+    struct rt_spi_device * spi_device = enc28j60_dev.spi_device;
+    enc28j60_lock(&enc28j60_dev);
+
+    rt_kprintf("-- enc28j60 registers:\n");
+    rt_kprintf("HwRevID: 0x%02X\n", spi_read(spi_device, EREVID));
+
+    rt_kprintf("Cntrl: ECON1 ECON2 ESTAT  EIR  EIE\n");
+    rt_kprintf("       0x%02X  0x%02X  0x%02X  0x%02X  0x%02X\n",
+               spi_read(spi_device, ECON1),
+               spi_read(spi_device, ECON2),
+               spi_read(spi_device, ESTAT),
+               spi_read(spi_device, EIR),
+               spi_read(spi_device, EIE));
+
+    rt_kprintf("MAC  : MACON1 MACON3 MACON4\n");
+    rt_kprintf("       0x%02X   0x%02X   0x%02X\n",
+               spi_read(spi_device, MACON1),
+               spi_read(spi_device, MACON3),
+               spi_read(spi_device, MACON4));
+
+    rt_kprintf("Rx   : ERXST  ERXND  ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n");
+    rt_kprintf("       0x%04X 0x%04X 0x%04X  0x%04X  ",
+               (spi_read(spi_device, ERXSTH) << 8) | spi_read(spi_device, ERXSTL),
+               (spi_read(spi_device, ERXNDH) << 8) | spi_read(spi_device, ERXNDL),
+               (spi_read(spi_device, ERXWRPTH) << 8) | spi_read(spi_device, ERXWRPTL),
+               (spi_read(spi_device, ERXRDPTH) << 8) | spi_read(spi_device, ERXRDPTL));
+
+    rt_kprintf("0x%02X    0x%02X    0x%04X\n",
+               spi_read(spi_device, ERXFCON),
+               spi_read(spi_device, EPKTCNT),
+               (spi_read(spi_device, MAMXFLH) << 8) | spi_read(spi_device, MAMXFLL));
+
+    rt_kprintf("Tx   : ETXST  ETXND  MACLCON1 MACLCON2 MAPHSUP\n");
+    rt_kprintf("       0x%04X 0x%04X 0x%02X     0x%02X     0x%02X\n",
+               (spi_read(spi_device, ETXSTH) << 8) | spi_read(spi_device, ETXSTL),
+               (spi_read(spi_device, ETXNDH) << 8) | spi_read(spi_device, ETXNDL),
+               spi_read(spi_device, MACLCON1),
+               spi_read(spi_device, MACLCON2),
+               spi_read(spi_device, MAPHSUP));
+
+    rt_kprintf("PHY   : PHCON1 PHSTAT1\r\n");
+    rt_kprintf("        0x%04X 0x%04X\r\n",
+               enc28j60_phy_read(spi_device, PHCON1),
+               enc28j60_phy_read(spi_device, PHSTAT1));
+
+    enc28j60_unlock(&enc28j60_dev);
+}
+FINSH_FUNCTION_EXPORT(enc28j60, dump enc28j60 registers);
+#endif

+ 329 - 0
components/drivers/spi/enc28j60.h

@@ -0,0 +1,329 @@
+#ifndef EN28J60_H_INCLUDED
+#define EN28J60_H_INCLUDED
+
+#include <stdint.h>
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+#include <netif/ethernetif.h>
+
+// ENC28J60 Control Registers
+// Control register definitions are a combination of address,
+// bank number, and Ethernet/MAC/PHY indicator bits.
+// - Register address        (bits 0-4)
+// - Bank number        (bits 5-6)
+// - MAC/PHY indicator        (bit 7)
+#define ADDR_MASK        0x1F
+#define BANK_MASK        0x60
+#define SPRD_MASK        0x80
+// All-bank registers
+#define EIE              0x1B
+#define EIR              0x1C
+#define ESTAT            0x1D
+#define ECON2            0x1E
+#define ECON1            0x1F
+// Bank 0 registers
+#define ERDPTL           (0x00|0x00)
+#define ERDPTH           (0x01|0x00)
+#define EWRPTL           (0x02|0x00)
+#define EWRPTH           (0x03|0x00)
+#define ETXSTL           (0x04|0x00)
+#define ETXSTH           (0x05|0x00)
+#define ETXNDL           (0x06|0x00)
+#define ETXNDH           (0x07|0x00)
+#define ERXSTL           (0x08|0x00)
+#define ERXSTH           (0x09|0x00)
+#define ERXNDL           (0x0A|0x00)
+#define ERXNDH           (0x0B|0x00)
+#define ERXRDPTL         (0x0C|0x00)
+#define ERXRDPTH         (0x0D|0x00)
+#define ERXWRPTL         (0x0E|0x00)
+#define ERXWRPTH         (0x0F|0x00)
+#define EDMASTL          (0x10|0x00)
+#define EDMASTH          (0x11|0x00)
+#define EDMANDL          (0x12|0x00)
+#define EDMANDH          (0x13|0x00)
+#define EDMADSTL         (0x14|0x00)
+#define EDMADSTH         (0x15|0x00)
+#define EDMACSL          (0x16|0x00)
+#define EDMACSH          (0x17|0x00)
+// Bank 1 registers
+#define EHT0             (0x00|0x20)
+#define EHT1             (0x01|0x20)
+#define EHT2             (0x02|0x20)
+#define EHT3             (0x03|0x20)
+#define EHT4             (0x04|0x20)
+#define EHT5             (0x05|0x20)
+#define EHT6             (0x06|0x20)
+#define EHT7             (0x07|0x20)
+#define EPMM0            (0x08|0x20)
+#define EPMM1            (0x09|0x20)
+#define EPMM2            (0x0A|0x20)
+#define EPMM3            (0x0B|0x20)
+#define EPMM4            (0x0C|0x20)
+#define EPMM5            (0x0D|0x20)
+#define EPMM6            (0x0E|0x20)
+#define EPMM7            (0x0F|0x20)
+#define EPMCSL           (0x10|0x20)
+#define EPMCSH           (0x11|0x20)
+#define EPMOL            (0x14|0x20)
+#define EPMOH            (0x15|0x20)
+#define EWOLIE           (0x16|0x20)
+#define EWOLIR           (0x17|0x20)
+#define ERXFCON          (0x18|0x20)
+#define EPKTCNT          (0x19|0x20)
+// Bank 2 registers
+#define MACON1           (0x00|0x40|0x80)
+#define MACON2           (0x01|0x40|0x80)
+#define MACON3           (0x02|0x40|0x80)
+#define MACON4           (0x03|0x40|0x80)
+#define MABBIPG          (0x04|0x40|0x80)
+#define MAIPGL           (0x06|0x40|0x80)
+#define MAIPGH           (0x07|0x40|0x80)
+#define MACLCON1         (0x08|0x40|0x80)
+#define MACLCON2         (0x09|0x40|0x80)
+#define MAMXFLL          (0x0A|0x40|0x80)
+#define MAMXFLH          (0x0B|0x40|0x80)
+#define MAPHSUP          (0x0D|0x40|0x80)
+#define MICON            (0x11|0x40|0x80)
+#define MICMD            (0x12|0x40|0x80)
+#define MIREGADR         (0x14|0x40|0x80)
+#define MIWRL            (0x16|0x40|0x80)
+#define MIWRH            (0x17|0x40|0x80)
+#define MIRDL            (0x18|0x40|0x80)
+#define MIRDH            (0x19|0x40|0x80)
+// Bank 3 registers
+#define MAADR1           (0x00|0x60|0x80)
+#define MAADR0           (0x01|0x60|0x80)
+#define MAADR3           (0x02|0x60|0x80)
+#define MAADR2           (0x03|0x60|0x80)
+#define MAADR5           (0x04|0x60|0x80)
+#define MAADR4           (0x05|0x60|0x80)
+#define EBSTSD           (0x06|0x60)
+#define EBSTCON          (0x07|0x60)
+#define EBSTCSL          (0x08|0x60)
+#define EBSTCSH          (0x09|0x60)
+#define MISTAT           (0x0A|0x60|0x80)
+#define EREVID           (0x12|0x60)
+#define ECOCON           (0x15|0x60)
+#define EFLOCON          (0x17|0x60)
+#define EPAUSL           (0x18|0x60)
+#define EPAUSH           (0x19|0x60)
+// PHY registers
+#define PHCON1           0x00
+#define PHSTAT1          0x01
+#define PHHID1           0x02
+#define PHHID2           0x03
+#define PHCON2           0x10
+#define PHSTAT2          0x11
+#define PHIE             0x12
+#define PHIR             0x13
+#define PHLCON           0x14
+
+// ENC28J60 ERXFCON Register Bit Definitions
+#define ERXFCON_UCEN     0x80
+#define ERXFCON_ANDOR    0x40
+#define ERXFCON_CRCEN    0x20
+#define ERXFCON_PMEN     0x10
+#define ERXFCON_MPEN     0x08
+#define ERXFCON_HTEN     0x04
+#define ERXFCON_MCEN     0x02
+#define ERXFCON_BCEN     0x01
+// ENC28J60 EIE Register Bit Definitions
+#define EIE_INTIE        0x80
+#define EIE_PKTIE        0x40
+#define EIE_DMAIE        0x20
+#define EIE_LINKIE       0x10
+#define EIE_TXIE         0x08
+#define EIE_WOLIE        0x04
+#define EIE_TXERIE       0x02
+#define EIE_RXERIE       0x01
+// ENC28J60 EIR Register Bit Definitions
+#define EIR_PKTIF        0x40
+#define EIR_DMAIF        0x20
+#define EIR_LINKIF       0x10
+#define EIR_TXIF         0x08
+#define EIR_WOLIF        0x04
+#define EIR_TXERIF       0x02
+#define EIR_RXERIF       0x01
+// ENC28J60 ESTAT Register Bit Definitions
+#define ESTAT_INT        0x80
+#define ESTAT_LATECOL    0x10
+#define ESTAT_RXBUSY     0x04
+#define ESTAT_TXABRT     0x02
+#define ESTAT_CLKRDY     0x01
+// ENC28J60 ECON2 Register Bit Definitions
+#define ECON2_AUTOINC    0x80
+#define ECON2_PKTDEC     0x40
+#define ECON2_PWRSV      0x20
+#define ECON2_VRPS       0x08
+// ENC28J60 ECON1 Register Bit Definitions
+#define ECON1_TXRST      0x80
+#define ECON1_RXRST      0x40
+#define ECON1_DMAST      0x20
+#define ECON1_CSUMEN     0x10
+#define ECON1_TXRTS      0x08
+#define ECON1_RXEN       0x04
+#define ECON1_BSEL1      0x02
+#define ECON1_BSEL0      0x01
+// ENC28J60 MACON1 Register Bit Definitions
+#define MACON1_LOOPBK    0x10
+#define MACON1_TXPAUS    0x08
+#define MACON1_RXPAUS    0x04
+#define MACON1_PASSALL   0x02
+#define MACON1_MARXEN    0x01
+// ENC28J60 MACON2 Register Bit Definitions
+#define MACON2_MARST     0x80
+#define MACON2_RNDRST    0x40
+#define MACON2_MARXRST   0x08
+#define MACON2_RFUNRST   0x04
+#define MACON2_MATXRST   0x02
+#define MACON2_TFUNRST   0x01
+// ENC28J60 MACON3 Register Bit Definitions
+#define MACON3_PADCFG2   0x80
+#define MACON3_PADCFG1   0x40
+#define MACON3_PADCFG0   0x20
+#define MACON3_TXCRCEN   0x10
+#define MACON3_PHDRLEN   0x08
+#define MACON3_HFRMLEN   0x04
+#define MACON3_FRMLNEN   0x02
+#define MACON3_FULDPX    0x01
+// ENC28J60 MACON4 Register Bit Definitions
+#define	MACON4_DEFER	(1<<6)
+#define	MACON4_BPEN		(1<<5)
+#define	MACON4_NOBKOFF	(1<<4)
+// ENC28J60 MICMD Register Bit Definitions
+#define MICMD_MIISCAN    0x02
+#define MICMD_MIIRD      0x01
+// ENC28J60 MISTAT Register Bit Definitions
+#define MISTAT_NVALID    0x04
+#define MISTAT_SCAN      0x02
+#define MISTAT_BUSY      0x01
+// ENC28J60 PHY PHCON1 Register Bit Definitions
+#define PHCON1_PRST      0x8000
+#define PHCON1_PLOOPBK   0x4000
+#define PHCON1_PPWRSV    0x0800
+#define PHCON1_PDPXMD    0x0100
+// ENC28J60 PHY PHSTAT1 Register Bit Definitions
+#define PHSTAT1_PFDPX    0x1000
+#define PHSTAT1_PHDPX    0x0800
+#define PHSTAT1_LLSTAT   0x0004
+#define PHSTAT1_JBSTAT   0x0002
+/* ENC28J60 PHY PHSTAT2 Register Bit Definitions */
+#define PHSTAT2_TXSTAT	(1 << 13)
+#define PHSTAT2_RXSTAT	(1 << 12)
+#define PHSTAT2_COLSTAT	(1 << 11)
+#define PHSTAT2_LSTAT	(1 << 10)
+#define PHSTAT2_DPXSTAT	(1 << 9)
+#define PHSTAT2_PLRITY	(1 << 5)
+// ENC28J60 PHY PHCON2 Register Bit Definitions
+#define PHCON2_FRCLINK   0x4000
+#define PHCON2_TXDIS     0x2000
+#define PHCON2_JABBER    0x0400
+#define PHCON2_HDLDIS    0x0100
+
+// ENC28J60 Packet Control Byte Bit Definitions
+#define PKTCTRL_PHUGEEN  0x08
+#define PKTCTRL_PPADEN   0x04
+#define PKTCTRL_PCRCEN   0x02
+#define PKTCTRL_POVERRIDE 0x01
+
+/* ENC28J60 Transmit Status Vector */
+#define TSV_TXBYTECNT           0
+#define TSV_TXCOLLISIONCNT      16
+#define TSV_TXCRCERROR          20
+#define TSV_TXLENCHKERROR       21
+#define TSV_TXLENOUTOFRANGE     22
+#define TSV_TXDONE              23
+#define TSV_TXMULTICAST         24
+#define TSV_TXBROADCAST         25
+#define TSV_TXPACKETDEFER       26
+#define TSV_TXEXDEFER           27
+#define TSV_TXEXCOLLISION       28
+#define TSV_TXLATECOLLISION     29
+#define TSV_TXGIANT             30
+#define TSV_TXUNDERRUN          31
+#define TSV_TOTBYTETXONWIRE     32
+#define TSV_TXCONTROLFRAME      48
+#define TSV_TXPAUSEFRAME        49
+#define TSV_BACKPRESSUREAPP     50
+#define TSV_TXVLANTAGFRAME      51
+
+#define TSV_SIZE                7
+#define TSV_BYTEOF(x)           ((x) / 8)
+#define TSV_BITMASK(x)          (1 << ((x) % 8))
+#define TSV_GETBIT(x, y)        (((x)[TSV_BYTEOF(y)] & TSV_BITMASK(y)) ? 1 : 0)
+
+/* ENC28J60 Receive Status Vector */
+#define RSV_RXLONGEVDROPEV      16
+#define RSV_CARRIEREV           18
+#define RSV_CRCERROR            20
+#define RSV_LENCHECKERR         21
+#define RSV_LENOUTOFRANGE       22
+#define RSV_RXOK                23
+#define RSV_RXMULTICAST         24
+#define RSV_RXBROADCAST         25
+#define RSV_DRIBBLENIBBLE       26
+#define RSV_RXCONTROLFRAME      27
+#define RSV_RXPAUSEFRAME        28
+#define RSV_RXUNKNOWNOPCODE     29
+#define RSV_RXTYPEVLAN          30
+
+#define RSV_SIZE                6
+#define RSV_BITMASK(x)          (1 << ((x) - 16))
+#define RSV_GETBIT(x, y)        (((x) & RSV_BITMASK(y)) ? 1 : 0)
+
+// SPI operation codes
+#define ENC28J60_READ_CTRL_REG       0x00
+#define ENC28J60_READ_BUF_MEM        0x3A
+#define ENC28J60_WRITE_CTRL_REG      0x40
+#define ENC28J60_WRITE_BUF_MEM       0x7A
+#define ENC28J60_BIT_FIELD_SET       0x80
+#define ENC28J60_BIT_FIELD_CLR       0xA0
+#define ENC28J60_SOFT_RESET          0xFF
+
+// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
+// buffer boundaries applied to internal 8K ram
+// the entire available packet buffer space is allocated
+//
+
+#define MAX_TX_PACKAGE_SIZE    (1536)
+
+// start with recbuf at 0/
+#define RXSTART_INIT	0x0
+// receive buffer end
+#define RXSTOP_INIT		(0x1FFF - MAX_TX_PACKAGE_SIZE*2) - 1
+// start TX buffer at 0x1FFF-0x0600, pace for one full ethernet frame (~1500 bytes)
+
+#define TXSTART_INIT	(0x1FFF - MAX_TX_PACKAGE_SIZE*2)
+// stp TX buffer at end of mem
+#define TXSTOP_INIT		0x1FFF
+
+// max frame length which the conroller will accept:
+#define MAX_FRAMELEN	1518
+
+#define MAX_ADDR_LEN    6
+
+struct net_device
+{
+	/* inherit from ethernet device */
+	struct eth_device parent;
+
+	/* interface address info. */
+	rt_uint8_t  dev_addr[MAX_ADDR_LEN]; /* hw address	*/
+
+	rt_uint8_t emac_rev;
+	rt_uint8_t phy_rev;
+	rt_uint8_t phy_pn;
+	rt_uint32_t phy_id;
+
+	/* spi device */
+	struct rt_spi_device * spi_device;
+	struct rt_mutex lock;
+};
+
+/* export function */
+extern rt_err_t enc28j60_attach(const char * spi_device_name);
+extern void enc28j60_isr(void);
+
+#endif // EN28J60_H_INCLUDED

+ 437 - 0
components/drivers/spi/spi_flash_at45dbxx.c

@@ -0,0 +1,437 @@
+/*
+ * File      : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-12-16     aozima       the first version
+ */
+
+#include <stdint.h>
+#include "spi_flash_at45dbxx.h"
+
+#define FLASH_DEBUG
+#define DMA_BUFFER_SIZE                         512
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE         rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /**< #ifdef FLASH_DEBUG */
+
+/* JEDEC Manufacturer¡¯s ID */
+#define MF_ID                (0x1F) /* atmel */
+#define DENSITY_CODE_011D    (0x02) /* AT45DB011D Density Code : 00010 = 1-Mbit */
+#define DENSITY_CODE_021D    (0x03) /* AT45DB021D Density Code : 00011 = 2-Mbit */
+#define DENSITY_CODE_041D    (0x04) /* AT45DB041D Density Code : 00100 = 4-Mbit */
+#define DENSITY_CODE_081D    (0x05) /* AT45DB081D Density Code : 00101 = 8-Mbit */
+#define DENSITY_CODE_161D    (0x06) /* AT45DB161D Density Code : 00110 = 16-Mbit */
+#define DENSITY_CODE_321D    (0x07) /* AT45DB321D Density Code : 00111 = 32-Mbit */
+#define DENSITY_CODE_642D    (0x08) /* AT45DB642D Density Code : 01000 = 64-Mbit */
+
+struct JEDEC_ID
+{
+    uint8_t manufacturer_id;          /* Manufacturer ID */
+    uint8_t density_code:5; /* Density Code */
+    uint8_t family_code:3;  /* Family Code */
+    uint8_t version_code:5; /* Product Version Code */
+    uint8_t mlc_code:3;     /* MLC Code */
+    uint8_t byte_count;     /* Byte Count */
+};
+
+#define AT45DB_BUFFER_1_WRITE                 0x84
+#define AT45DB_BUFFER_2_WRITE                 0x87
+#define AT45DB_BUFFER_1_READ                  0xD4
+#define AT45DB_BUFFER_2_READ                  0xD6
+#define AT45DB_B1_TO_MM_PAGE_PROG_WITH_ERASE  0x83
+#define AT45DB_B2_TO_MM_PAGE_PROG_WITH_ERASE  0x86
+#define AT45DB_MM_PAGE_TO_B1_XFER             0x53
+#define AT45DB_MM_PAGE_TO_B2_XFER             0x55
+#define AT45DB_PAGE_ERASE                     0x81
+#define AT45DB_SECTOR_ERASE                   0x7C
+#define AT45DB_READ_STATE_REGISTER            0xD7
+#define AT45DB_MM_PAGE_READ                   0xD2
+#define AT45DB_MM_PAGE_PROG_THRU_BUFFER1      0x82
+#define AT45DB_CMD_JEDEC_ID                   0x9F
+
+static struct spi_flash_at45dbxx  spi_flash_at45dbxx;
+
+/*****************************************************************************/
+/*Status Register Format:                                   */
+/* ------------------------------------------------------------------------- */
+/* | bit7   | bit6   | bit5   | bit4   | bit3   | bit2   | bit1   | bit0   | */
+/* |--------|--------|--------|--------|--------|--------|--------|--------| */
+/* |RDY/BUSY| COMP   |         device density            |   X    |   X    | */
+/* ------------------------------------------------------------------------- */
+/* 0:busy   |        |        AT45DB041:0111             | protect|page size */
+/* 1:ready  |        |        AT45DB161:1011             |                   */
+/* --------------------------------------------------------------------------*/
+/*****************************************************************************/
+static uint8_t AT45DB_StatusRegisterRead(void)
+{
+    return rt_spi_sendrecv8(spi_flash_at45dbxx.rt_spi_device, AT45DB_READ_STATE_REGISTER);
+}
+
+static void wait_busy(void)
+{
+    uint16_t i = 0;
+    while (i++ < 10000)
+    {
+        if (AT45DB_StatusRegisterRead() & 0x80)
+        {
+            return;
+        }
+    }
+    FLASH_TRACE("\r\nSPI_FLASH timeout!!!\r\n");
+}
+
+/* RT-Thread Device Driver Interface */
+static rt_err_t AT45DB_flash_init(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+
+    return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t AT45DB_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+    {
+        struct rt_device_blk_geometry *geometry;
+
+        geometry = (struct rt_device_blk_geometry *)args;
+        if (geometry == RT_NULL) return -RT_ERROR;
+
+        geometry->bytes_per_sector = 512;
+        geometry->sector_count = 4096;
+        geometry->block_size = 4096; /* block erase: 4k */
+    }
+
+    return RT_EOK;
+}
+
+static rt_size_t AT45DB_flash_read_page_256(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    uint32_t index, nr;
+    uint8_t * read_buffer = buffer;
+
+    nr = size;
+
+    for (index = 0; index < nr; index++)
+    {
+        uint32_t  page = pos;
+        uint8_t send_buffer[8];
+        uint32_t i;
+
+        for(i=0; i<sizeof(send_buffer); i++)
+        {
+            send_buffer[i] = 0;
+        }
+
+        send_buffer[0] = AT45DB_MM_PAGE_READ;
+        send_buffer[1] = (uint8_t)(page >> 7);
+        send_buffer[2] = (uint8_t)(page << 1);
+
+        rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 256);
+        read_buffer += 256;
+        page++;
+    }
+
+    return size;
+}
+
+static rt_size_t AT45DB_flash_read_page_512(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    uint32_t index, nr;
+    uint8_t * read_buffer = buffer;
+
+    nr = size;
+
+    for (index = 0; index < nr; index++)
+    {
+        uint32_t  page = pos;
+        uint8_t send_buffer[8];
+        uint32_t i;
+
+        for(i=0; i<sizeof(send_buffer); i++)
+        {
+            send_buffer[i] = 0;
+        }
+
+        send_buffer[0] = AT45DB_MM_PAGE_READ;
+        send_buffer[1] = (uint8_t)(page >> 6);
+        send_buffer[2] = (uint8_t)(page << 2);
+
+        rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 512);
+        read_buffer += 512;
+        page++;
+    }
+
+    return size;
+}
+
+static rt_size_t AT45DB_flash_read_page_1024(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    uint32_t index, nr;
+    uint8_t * read_buffer = buffer;
+
+    nr = size;
+
+    for (index = 0; index < nr; index++)
+    {
+        uint32_t  page = pos;
+        uint8_t send_buffer[8];
+        uint32_t i;
+
+        for(i=0; i<sizeof(send_buffer); i++)
+        {
+            send_buffer[i] = 0;
+        }
+
+        send_buffer[0] = AT45DB_MM_PAGE_READ;
+        send_buffer[1] = (uint8_t)(page >> 5);
+        send_buffer[2] = (uint8_t)(page << 3);
+
+        rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, send_buffer, 8, read_buffer, 1024);
+        read_buffer += 1024;
+        page++;
+    }
+
+    return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_256(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    rt_uint32_t index, nr;
+    const uint8_t * write_buffer = buffer;
+
+    nr = size;
+
+    for (index = 0; index < nr; index++)
+    {
+        uint32_t  page = pos;
+        uint8_t send_buffer[4];
+
+        send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+        send_buffer[1] = (uint8_t) (page >> 7);
+        send_buffer[2] = (uint8_t) (page << 1);
+        send_buffer[3] = 0;
+
+        rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 256);
+
+        write_buffer += 256;
+        page++;
+
+        wait_busy();
+    }
+
+    return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_512(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    rt_uint32_t index, nr;
+    const uint8_t * write_buffer = buffer;
+
+    nr = size;
+
+    for (index = 0; index < nr; index++)
+    {
+        uint32_t  page = pos;
+        uint8_t send_buffer[4];
+
+        send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+        send_buffer[1] = (uint8_t) (page >> 6);
+        send_buffer[2] = (uint8_t) (page << 2);
+        send_buffer[3] = 0;
+
+        rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 512);
+
+        write_buffer += 512;
+        page++;
+
+        wait_busy();
+    }
+
+    return size;
+}
+
+static rt_size_t AT45DB_flash_write_page_1024(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    rt_uint32_t index, nr;
+    const uint8_t * write_buffer = buffer;
+
+    nr = size;
+
+    for (index = 0; index < nr; index++)
+    {
+        uint32_t  page = pos;
+        uint8_t send_buffer[4];
+
+        send_buffer[0] = AT45DB_MM_PAGE_PROG_THRU_BUFFER1;
+        send_buffer[1] = (uint8_t) (page >> 5);
+        send_buffer[2] = (uint8_t) (page << 3);
+        send_buffer[3] = 0;
+
+        rt_spi_send_then_send(spi_flash_at45dbxx.rt_spi_device, send_buffer, 4, write_buffer, 1024);
+
+        write_buffer += 1024;
+        page++;
+
+        wait_busy();
+    }
+
+    return size;
+}
+
+rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+    struct rt_spi_device * rt_spi_device;
+    struct JEDEC_ID * JEDEC_ID;
+
+    rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+    if(rt_spi_device == RT_NULL)
+    {
+        FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+    spi_flash_at45dbxx.rt_spi_device = rt_spi_device;
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 and 3 */
+        cfg.max_hz = 66000000; /* Atmel RapidS Serial Interface: 66MHz Maximum Clock Frequency */
+        rt_spi_configure(spi_flash_at45dbxx.rt_spi_device, &cfg);
+    }
+
+    /* read JEDEC ID */
+    {
+        uint8_t cmd;
+        uint8_t id_recv[6];
+        JEDEC_ID = (struct JEDEC_ID *)id_recv;
+
+        cmd = AT45DB_CMD_JEDEC_ID;
+        rt_spi_send_then_recv(spi_flash_at45dbxx.rt_spi_device, &cmd, 1, id_recv, 6);
+
+        /**< 1FH = Atmel */
+        /**< 001 = Atmel DataFlash */
+        if(JEDEC_ID->manufacturer_id != 0x1F || JEDEC_ID->family_code != 0x01)
+        {
+            FLASH_TRACE("Manufacturer¡¯s ID or Memory Type error!\r\n");
+            FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+            return -RT_ENOSYS;
+        }
+
+        if(JEDEC_ID->density_code == DENSITY_CODE_011D)
+        {
+            /**< AT45DB011D Density Code : 00010 = 1-Mbit */
+            FLASH_TRACE("AT45DB011D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+            spi_flash_at45dbxx.geometry.sector_count = 512;     /* 1-Mbit / 8 / 256 = 512 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*2;    /* Block Erase (2-Kbytes) */
+        }
+        else if(JEDEC_ID->density_code == DENSITY_CODE_021D)
+        {
+            /**< AT45DB021D Density Code : 00011 = 2-Mbit */
+            FLASH_TRACE("AT45DB021D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+            spi_flash_at45dbxx.geometry.sector_count = 512*2;   /* 2-Mbit / 8 / 256 = 1024 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*2;    /* Block Erase (2-Kbytes) */
+        }
+        else if(JEDEC_ID->density_code == DENSITY_CODE_041D)
+        {
+            /**< AT45DB041D Density Code : 00100 = 4-Mbit */
+            FLASH_TRACE("AT45DB041D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+            spi_flash_at45dbxx.geometry.sector_count = 512*4;   /* 4-Mbit / 8 / 256 = 2048 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*2;    /* Block Erase (2-Kbytes) */
+        }
+        else if(JEDEC_ID->density_code == DENSITY_CODE_081D)
+        {
+            /**< AT45DB081D Density Code : 00101 = 8-Mbit */
+            FLASH_TRACE("AT45DB081D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 256; /* Page Erase (256 Bytes) */
+            spi_flash_at45dbxx.geometry.sector_count = 512*8;   /* 8-Mbit / 8 / 256 = 4096 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*2;    /* Block Erase (2-Kbytes) */
+        }
+        else if(JEDEC_ID->density_code == DENSITY_CODE_161D)
+        {
+            /**< AT45DB161D Density Code : 00110 = 16-Mbit */
+            FLASH_TRACE("AT45DB161D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */
+            spi_flash_at45dbxx.geometry.sector_count = 256*16;  /* 16-Mbit / 8 / 512 = 4096 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*4;    /* Block Erase (4-Kbytes) */
+        }
+        else if(JEDEC_ID->density_code == DENSITY_CODE_321D)
+        {
+            /**< AT45DB321D Density Code : 00111 = 32-Mbit */
+            FLASH_TRACE("AT45DB321D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 512; /* Page Erase (512 Bytes) */
+            spi_flash_at45dbxx.geometry.sector_count = 256*32;  /* 32-Mbit / 8 / 512 = 8192 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*4;    /* Block Erase (4-Kbytes) */
+        }
+        else if(JEDEC_ID->density_code == DENSITY_CODE_642D)
+        {
+            /**< AT45DB642D Density Code : 01000 = 64-Mbit */
+            FLASH_TRACE("AT45DB642D detection\r\n");
+            spi_flash_at45dbxx.geometry.bytes_per_sector = 1024; /* Page Erase (1 Kbyte) */
+            spi_flash_at45dbxx.geometry.sector_count = 128*64;   /* 64-Mbit / 8 / 1024 = 8192 */
+            spi_flash_at45dbxx.geometry.block_size = 1024*8;     /* Block Erase (8 Kbytes) */
+        }
+        else
+        {
+            FLASH_TRACE("Memory Capacity error!\r\n");
+            return -RT_ENOSYS;
+        }
+    }
+
+    /* register device */
+    spi_flash_at45dbxx.flash_device.type    = RT_Device_Class_Block;
+    spi_flash_at45dbxx.flash_device.init    = AT45DB_flash_init;
+    spi_flash_at45dbxx.flash_device.open    = AT45DB_flash_open;
+    spi_flash_at45dbxx.flash_device.close   = AT45DB_flash_close;
+    spi_flash_at45dbxx.flash_device.control = AT45DB_flash_control;
+
+    if(JEDEC_ID->density_code == DENSITY_CODE_642D)
+    {
+        spi_flash_at45dbxx.flash_device.read 	  = AT45DB_flash_read_page_1024;
+        spi_flash_at45dbxx.flash_device.write   = AT45DB_flash_write_page_1024;
+    }
+    else if(JEDEC_ID->density_code == DENSITY_CODE_161D
+            || JEDEC_ID->density_code == DENSITY_CODE_321D )
+    {
+        spi_flash_at45dbxx.flash_device.read 	  = AT45DB_flash_read_page_512;
+        spi_flash_at45dbxx.flash_device.write   = AT45DB_flash_write_page_512;
+    }
+    else
+    {
+        spi_flash_at45dbxx.flash_device.read 	  = AT45DB_flash_read_page_256;
+        spi_flash_at45dbxx.flash_device.write   = AT45DB_flash_write_page_256;
+    }
+
+    /* no private */
+    spi_flash_at45dbxx.flash_device.user_data = RT_NULL;
+
+    rt_device_register(&spi_flash_at45dbxx.flash_device, flash_device_name,
+                       RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+    return RT_EOK;
+}

+ 17 - 0
components/drivers/spi/spi_flash_at45dbxx.h

@@ -0,0 +1,17 @@
+#ifndef SPI_FLASH_AT45DBXX_H_INCLUDED
+#define SPI_FLASH_AT45DBXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_at45dbxx
+{
+    struct rt_device                flash_device;
+    struct rt_device_blk_geometry   geometry;
+    struct rt_spi_device *          rt_spi_device;
+};
+
+extern rt_err_t at45dbxx_init(const char * flash_device_name, const char * spi_device_name);
+
+
+#endif // SPI_FLASH_AT45DBXX_H_INCLUDED

+ 346 - 0
components/drivers/spi/spi_flash_sst25vfxx.c

@@ -0,0 +1,346 @@
+/*
+ * File      : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-12-16     aozima       the first version
+ */
+
+#include <stdint.h>
+#include "spi_flash_sst25vfxx.h"
+
+#define FLASH_DEBUG
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE         rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /* #ifdef FLASH_DEBUG */
+
+/* JEDEC Manufacturer¡¯s ID */
+#define MF_ID                       (0xBF)
+/* JEDEC Device ID : Memory Type */
+#define MT_ID                       (0x25)
+/* JEDEC Device ID: Memory Capacity */
+#define MC_ID_SST25VF020B            (0x8C) /* 2Mbit  */
+#define MC_ID_SST25VF040B            (0x8D) /* 4Mbit  */
+#define MC_ID_SST25VF080B            (0x8E) /* 8Mbit  */
+#define MC_ID_SST25VF016B            (0x41) /* 16Mbit */
+#define MC_ID_SST25VF032B            (0x4A) /* 32Mbit */
+#define MC_ID_SST25VF064C            (0x4B) /* 64Mbit */
+
+/* command list */
+#define CMD_RDSR                    (0x05)
+#define CMD_WRSR                    (0x01)
+#define CMD_EWSR                    (0x50)
+#define CMD_WRDI                    (0x04)
+#define CMD_WREN                    (0x06)
+#define CMD_READ                    (0x03)
+#define CMD_FAST_READ               (0x0B)
+#define CMD_BP                      (0x02)
+#define CMD_AAIP                    (0xAD)
+#define CMD_ERASE_4K                (0x20)
+#define CMD_ERASE_32K               (0x52)
+#define CMD_ERASE_64K               (0xD8)
+#define CMD_ERASE_full              (0xC7)
+#define CMD_JEDEC_ID                (0x9F)
+#define CMD_EBSY                    (0x70)
+#define CMD_DBSY                    (0x80)
+
+#define DUMMY                       (0xFF)
+
+static struct spi_flash_sst25vfxx  spi_flash_sst25vfxx;
+
+static uint8_t sst25vfxx_read_status(struct spi_flash_sst25vfxx * spi_flash)
+{
+    return rt_spi_sendrecv8(spi_flash->rt_spi_device, CMD_RDSR);
+}
+
+static void sst25vfxx_wait_busy(struct spi_flash_sst25vfxx * spi_flash)
+{
+    while( sst25vfxx_read_status(spi_flash) & (0x01));
+}
+
+/** \brief write N page on [page]
+ *
+ * \param page uint32_t unit : byte (4096 * N,1 page = 4096byte)
+ * \param buffer const uint8_t*
+ * \param size uint32_t unit : byte ( 4096*N )
+ * \return uint32_t
+ *
+ */
+static uint32_t sst25vfxx_page_write(struct spi_flash_sst25vfxx * spi_flash, uint32_t page, const uint8_t * buffer, uint32_t size)
+{
+    uint32_t index;
+    uint32_t need_wirte = size;
+    uint8_t send_buffer[6];
+
+    page &= ~0xFFF; // page size = 4096byte
+
+    send_buffer[0] = CMD_WREN;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_ERASE_4K;
+    send_buffer[1] = (page >> 16);
+    send_buffer[2] = (page >> 8);
+    send_buffer[3] = (page);
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 4);
+
+    sst25vfxx_wait_busy(spi_flash); // wait erase done.
+
+    send_buffer[0] = CMD_WREN;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_AAIP;
+    send_buffer[1] = (uint8_t)(page >> 16);
+    send_buffer[2] = (uint8_t)(page >> 8);
+    send_buffer[3] = (uint8_t)(page);
+    send_buffer[4] = *buffer++;
+    send_buffer[5] = *buffer++;
+    need_wirte -= 2;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 6);
+
+    sst25vfxx_wait_busy(spi_flash);
+
+    for(index=0; index < need_wirte/2; index++)
+    {
+        send_buffer[0] = CMD_AAIP;
+        send_buffer[1] = *buffer++;
+        send_buffer[2] = *buffer++;
+        rt_spi_send(spi_flash->rt_spi_device, send_buffer, 3);
+        sst25vfxx_wait_busy(spi_flash);
+    }
+
+    send_buffer[0] = CMD_WRDI;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+    return size;
+}
+
+/* RT-Thread device interface */
+static rt_err_t sst25vfxx_flash_init(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    rt_err_t result;
+    uint8_t send_buffer[2];
+    struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+    /* lock spi flash */
+    result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+    if(result != RT_EOK)
+    {
+        return result;
+    }
+
+    send_buffer[0] = CMD_DBSY;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_EWSR;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_WRSR;
+    send_buffer[1] = 0;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 2);
+
+    /* release lock */
+    rt_mutex_release(&(spi_flash->lock));
+
+    return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t sst25vfxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+    struct spi_flash_sst25vfxx * spi_flash;
+
+    spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+    RT_ASSERT(dev != RT_NULL);
+
+    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+    {
+        struct rt_device_blk_geometry *geometry;
+
+        geometry = (struct rt_device_blk_geometry *)args;
+        if (geometry == RT_NULL) return -RT_ERROR;
+
+        geometry->bytes_per_sector = spi_flash->geometry.bytes_per_sector;
+        geometry->sector_count = spi_flash->geometry.sector_count;
+        geometry->block_size = spi_flash->geometry.block_size;
+    }
+
+    return RT_EOK;
+}
+
+static rt_size_t sst25vfxx_flash_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    rt_err_t result;
+    uint8_t send_buffer[4];
+    struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+    uint32_t offset = pos * spi_flash->geometry.bytes_per_sector;
+
+    /* lock spi flash */
+    result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+    if(result != RT_EOK)
+    {
+        return 0;
+    }
+
+    send_buffer[0] = CMD_WRDI;
+    rt_spi_send(spi_flash->rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_READ;
+    send_buffer[1] = (uint8_t)(offset>>16);
+    send_buffer[2] = (uint8_t)(offset>>8);
+    send_buffer[3] = (uint8_t)(offset);
+    rt_spi_send_then_recv(spi_flash->rt_spi_device, send_buffer, 4, buffer, size * spi_flash->geometry.bytes_per_sector);
+
+    /* release lock */
+    rt_mutex_release(&(spi_flash->lock));
+
+    return size;
+}
+
+static rt_size_t sst25vfxx_flash_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    uint32_t i;
+    rt_err_t result;
+    const uint8_t * write_buffer = buffer;
+    struct spi_flash_sst25vfxx * spi_flash = (struct spi_flash_sst25vfxx *)dev;
+
+    /* lock spi flash */
+    result = rt_mutex_take(&(spi_flash->lock), RT_WAITING_FOREVER);
+    if(result != RT_EOK)
+    {
+        return 0;
+    }
+
+    for(i=0; i<size; i++)
+    {
+        sst25vfxx_page_write(spi_flash,
+                             (pos + i) * spi_flash->geometry.bytes_per_sector,
+                             write_buffer,
+                             spi_flash->geometry.bytes_per_sector);
+        write_buffer += spi_flash->geometry.bytes_per_sector;
+    }
+
+    /* release lock */
+    rt_mutex_release(&(spi_flash->lock));
+
+    return size;
+}
+
+rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+    struct rt_spi_device * rt_spi_device;
+    struct spi_flash_sst25vfxx * spi_flash = &spi_flash_sst25vfxx;
+
+    rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+    if(rt_spi_device == RT_NULL)
+    {
+        FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+    spi_flash->rt_spi_device = rt_spi_device;
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+        cfg.max_hz = 50000000; /* 50M */
+        rt_spi_configure(spi_flash->rt_spi_device, &cfg);
+    }
+
+    /* init flash */
+    {
+        rt_uint8_t cmd;
+        rt_uint8_t id_recv[3];
+
+        cmd = CMD_WRDI;
+        rt_spi_send(spi_flash->rt_spi_device, &cmd, 1);
+
+        /* read flash id */
+        cmd = CMD_JEDEC_ID;
+        rt_spi_send_then_recv(spi_flash->rt_spi_device, &cmd, 1, id_recv, 3);
+
+        if(id_recv[0] != MF_ID || id_recv[1] != MT_ID)
+        {
+            FLASH_TRACE("Manufacturer¡¯s ID or Memory Type error!\r\n");
+            FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+            return -RT_ENOSYS;
+        }
+
+        spi_flash->geometry.bytes_per_sector = 4096;
+        spi_flash->geometry.block_size = 4096; /* block erase: 4k */
+
+        if(id_recv[2] == MC_ID_SST25VF020B)
+        {
+            FLASH_TRACE("SST25VF020B detection\r\n");
+            spi_flash->geometry.sector_count = 64;
+        }
+        else if(id_recv[2] == MC_ID_SST25VF040B)
+        {
+            FLASH_TRACE("SST25VF040B detection\r\n");
+            spi_flash->geometry.sector_count = 128;
+        }
+        else if(id_recv[2] == MC_ID_SST25VF080B)
+        {
+            FLASH_TRACE("SST25VF080B detection\r\n");
+            spi_flash->geometry.sector_count = 256;
+        }
+        else if(id_recv[2] == MC_ID_SST25VF016B)
+        {
+            FLASH_TRACE("SST25VF016B detection\r\n");
+            spi_flash->geometry.sector_count = 512;
+        }
+        else if(id_recv[2] == MC_ID_SST25VF032B)
+        {
+            FLASH_TRACE("SST25VF032B detection\r\n");
+            spi_flash->geometry.sector_count = 1024;
+        }
+        else if(id_recv[2] == MC_ID_SST25VF064C)
+        {
+            FLASH_TRACE("SST25VF064C detection\r\n");
+            spi_flash->geometry.sector_count = 2048;
+        }
+        else
+        {
+            FLASH_TRACE("Memory Capacity error!\r\n");
+            return -RT_ENOSYS;
+        }
+    }
+
+    /* initialize mutex lock */
+    rt_mutex_init(&spi_flash->lock, flash_device_name, RT_IPC_FLAG_PRIO);
+
+    /* register device */
+    spi_flash->flash_device.type    = RT_Device_Class_Block;
+    spi_flash->flash_device.init    = sst25vfxx_flash_init;
+    spi_flash->flash_device.open    = sst25vfxx_flash_open;
+    spi_flash->flash_device.close   = sst25vfxx_flash_close;
+    spi_flash->flash_device.read    = sst25vfxx_flash_read;
+    spi_flash->flash_device.write   = sst25vfxx_flash_write;
+    spi_flash->flash_device.control = sst25vfxx_flash_control;
+    /* no private */
+    spi_flash->flash_device.user_data = RT_NULL;
+
+    rt_device_register(&spi_flash->flash_device, flash_device_name,
+                       RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+    return RT_EOK;
+}

+ 32 - 0
components/drivers/spi/spi_flash_sst25vfxx.h

@@ -0,0 +1,32 @@
+/*
+ * File      : rtdef.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-12-16     aozima      the first version
+ */
+
+#ifndef SPI_FLASH_SST25VFXX_H_INCLUDED
+#define SPI_FLASH_SST25VFXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_sst25vfxx
+{
+    struct rt_device                flash_device;
+    struct rt_device_blk_geometry   geometry;
+    struct rt_spi_device *          rt_spi_device;
+    struct rt_mutex                 lock;
+};
+
+extern rt_err_t sst25vfxx_init(const char * flash_device_name, const char * spi_device_name);
+
+
+#endif // SPI_FLASH_SST25VFXX_H_INCLUDED

+ 371 - 0
components/drivers/spi/spi_flash_w25qxx.c

@@ -0,0 +1,371 @@
+/*
+ * File      : spi_flash_w25qxx.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-12-16     aozima       the first version
+ * 2012-05-06     aozima       can page write.
+ * 2012-08-23     aozima       add flash lock.
+ * 2012-08-24     aozima       fixed write status register BUG.
+ */
+
+#include <stdint.h>
+#include "spi_flash_w25qxx.h"
+
+#define FLASH_DEBUG
+
+#ifdef FLASH_DEBUG
+#define FLASH_TRACE         rt_kprintf
+#else
+#define FLASH_TRACE(...)
+#endif /* #ifdef FLASH_DEBUG */
+
+#define PAGE_SIZE           4096
+
+/* JEDEC Manufacturer¡¯s ID */
+#define MF_ID           (0xEF)
+/* JEDEC Device ID: Memory type and Capacity */
+#define MTC_W25Q16_BV_CL_CV   (0x4015) /* W25Q16BV W25Q16CL W25Q16CV  */
+#define MTC_W25Q16_DW         (0x6015) /* W25Q16DW  */
+#define MTC_W25Q32_BV         (0x4016) /* W25Q32BV */
+#define MTC_W25Q32_DW         (0x6016) /* W25Q32DW */
+#define MTC_W25Q64_BV_CV      (0x4017) /* W25Q64BV W25Q64CV */
+#define MTC_W25Q64_DW         (0x4017) /* W25Q64DW */
+#define MTC_W25Q128_BV        (0x4018) /* W25Q128BV */
+#define MTC_W25Q256_FV        (TBD)    /* W25Q256FV */
+
+/* command list */
+#define CMD_WRSR                    (0x01)  /* Write Status Register */
+#define CMD_PP                      (0x02)  /* Page Program */
+#define CMD_READ                    (0x03)  /* Read Data */
+#define CMD_WRDI                    (0x04)  /* Write Disable */
+#define CMD_RDSR1                   (0x05)  /* Read Status Register-1 */
+#define CMD_WREN                    (0x06)  /* Write Enable */
+#define CMD_FAST_READ               (0x0B)  /* Fast Read */
+#define CMD_ERASE_4K                (0x20)  /* Sector Erase:4K */
+#define CMD_RDSR2                   (0x35)  /* Read Status Register-2 */
+#define CMD_ERASE_32K               (0x52)  /* 32KB Block Erase */
+#define CMD_JEDEC_ID                (0x9F)  /* Read JEDEC ID */
+#define CMD_ERASE_full              (0xC7)  /* Chip Erase */
+#define CMD_ERASE_64K               (0xD8)  /* 64KB Block Erase */
+
+#define DUMMY                       (0xFF)
+
+static struct spi_flash_device  spi_flash_device;
+
+static void flash_lock(struct spi_flash_device * flash_device)
+{
+    rt_mutex_take(&flash_device->lock, RT_WAITING_FOREVER);
+}
+
+static void flash_unlock(struct spi_flash_device * flash_device)
+{
+    rt_mutex_release(&flash_device->lock);
+}
+
+static uint8_t w25qxx_read_status(void)
+{
+    return rt_spi_sendrecv8(spi_flash_device.rt_spi_device, CMD_RDSR1);
+}
+
+static void w25qxx_wait_busy(void)
+{
+    while( w25qxx_read_status() & (0x01));
+}
+
+/** \brief read [size] byte from [offset] to [buffer]
+ *
+ * \param offset uint32_t unit : byte
+ * \param buffer uint8_t*
+ * \param size uint32_t   unit : byte
+ * \return uint32_t byte for read
+ *
+ */
+static uint32_t w25qxx_read(uint32_t offset, uint8_t * buffer, uint32_t size)
+{
+    uint8_t send_buffer[4];
+
+    send_buffer[0] = CMD_WRDI;
+    rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_READ;
+    send_buffer[1] = (uint8_t)(offset>>16);
+    send_buffer[2] = (uint8_t)(offset>>8);
+    send_buffer[3] = (uint8_t)(offset);
+
+    rt_spi_send_then_recv(spi_flash_device.rt_spi_device,
+                          send_buffer, 4,
+                          buffer, size);
+
+    return size;
+}
+
+/** \brief write N page on [page]
+ *
+ * \param page_addr uint32_t unit : byte (4096 * N,1 page = 4096byte)
+ * \param buffer const uint8_t*
+ * \return uint32_t
+ *
+ */
+uint32_t w25qxx_page_write(uint32_t page_addr, const uint8_t* buffer)
+{
+    uint32_t index;
+    uint8_t send_buffer[4];
+
+    RT_ASSERT((page_addr&0xFF) == 0); /* page addr must align to 256byte. */
+
+    send_buffer[0] = CMD_WREN;
+    rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_ERASE_4K;
+    send_buffer[1] = (page_addr >> 16);
+    send_buffer[2] = (page_addr >> 8);
+    send_buffer[3] = (page_addr);
+    rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 4);
+
+    w25qxx_wait_busy(); // wait erase done.
+
+    for(index=0; index < (PAGE_SIZE / 256); index++)
+    {
+        send_buffer[0] = CMD_WREN;
+        rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+        send_buffer[0] = CMD_PP;
+        send_buffer[1] = (uint8_t)(page_addr >> 16);
+        send_buffer[2] = (uint8_t)(page_addr >> 8);
+        send_buffer[3] = (uint8_t)(page_addr);
+
+        rt_spi_send_then_send(spi_flash_device.rt_spi_device,
+                              send_buffer,
+                              4,
+                              buffer,
+                              256);
+
+        buffer += 256;
+        page_addr += 256;
+        w25qxx_wait_busy();
+    }
+
+    send_buffer[0] = CMD_WRDI;
+    rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+    return PAGE_SIZE;
+}
+
+/* RT-Thread device interface */
+static rt_err_t w25qxx_flash_init(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    uint8_t send_buffer[3];
+
+    flash_lock((struct spi_flash_device *)dev);
+
+    send_buffer[0] = CMD_WREN;
+    rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
+
+    send_buffer[0] = CMD_WRSR;
+    send_buffer[1] = 0;
+    send_buffer[2] = 0;
+    rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 3);
+
+    w25qxx_wait_busy();
+
+    flash_unlock((struct spi_flash_device *)dev);
+
+    return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t w25qxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+    {
+        struct rt_device_blk_geometry *geometry;
+
+        geometry = (struct rt_device_blk_geometry *)args;
+        if (geometry == RT_NULL) return -RT_ERROR;
+
+        geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector;
+        geometry->sector_count = spi_flash_device.geometry.sector_count;
+        geometry->block_size = spi_flash_device.geometry.block_size;
+    }
+
+    return RT_EOK;
+}
+
+static rt_size_t w25qxx_flash_read(rt_device_t dev,
+                                   rt_off_t pos,
+                                   void* buffer,
+                                   rt_size_t size)
+{
+    flash_lock((struct spi_flash_device *)dev);
+
+    w25qxx_read(pos*spi_flash_device.geometry.bytes_per_sector,
+                buffer,
+                size*spi_flash_device.geometry.bytes_per_sector);
+
+    flash_unlock((struct spi_flash_device *)dev);
+
+    return size;
+}
+
+static rt_size_t w25qxx_flash_write(rt_device_t dev,
+                                    rt_off_t pos,
+                                    const void* buffer,
+                                    rt_size_t size)
+{
+    rt_size_t i = 0;
+    rt_size_t block = size;
+    const uint8_t * ptr = buffer;
+
+    flash_lock((struct spi_flash_device *)dev);
+
+    while(block--)
+    {
+        w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector,
+                          ptr);
+        ptr += PAGE_SIZE;
+        i++;
+    }
+
+    flash_unlock((struct spi_flash_device *)dev);
+
+    return size;
+}
+
+rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_name)
+{
+    struct rt_spi_device * rt_spi_device;
+
+    /* initialize mutex */
+    if (rt_mutex_init(&spi_flash_device.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK)
+    {
+        rt_kprintf("init sd lock mutex failed\n");
+        return -RT_ENOSYS;
+    }
+
+    rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+    if(rt_spi_device == RT_NULL)
+    {
+        FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+    spi_flash_device.rt_spi_device = rt_spi_device;
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+        cfg.max_hz = 50 * 1000 * 1000; /* 50M */
+        rt_spi_configure(spi_flash_device.rt_spi_device, &cfg);
+    }
+
+    /* init flash */
+    {
+        rt_uint8_t cmd;
+        rt_uint8_t id_recv[3];
+        uint16_t memory_type_capacity;
+
+        flash_lock(&spi_flash_device);
+
+        cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
+        rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
+
+        cmd = CMD_WRDI;
+        rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
+
+        /* read flash id */
+        cmd = CMD_JEDEC_ID;
+        rt_spi_send_then_recv(spi_flash_device.rt_spi_device, &cmd, 1, id_recv, 3);
+
+        flash_unlock(&spi_flash_device);
+
+        if(id_recv[0] != MF_ID)
+        {
+            FLASH_TRACE("Manufacturers ID error!\r\n");
+            FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
+            return -RT_ENOSYS;
+        }
+
+        spi_flash_device.geometry.bytes_per_sector = 4096;
+        spi_flash_device.geometry.block_size = 4096; /* block erase: 4k */
+
+        /* get memory type and capacity */
+        memory_type_capacity = id_recv[1];
+        memory_type_capacity = (memory_type_capacity << 8) | id_recv[2];
+
+        if(memory_type_capacity == MTC_W25Q128_BV)
+        {
+            FLASH_TRACE("W25Q128BV detection\r\n");
+            spi_flash_device.geometry.sector_count = 4096;
+        }
+        else if(memory_type_capacity == MTC_W25Q64_BV_CV)
+        {
+            FLASH_TRACE("W25Q64BV or W25Q64CV detection\r\n");
+            spi_flash_device.geometry.sector_count = 2048;
+        }
+        else if(memory_type_capacity == MTC_W25Q64_DW)
+        {
+            FLASH_TRACE("W25Q64DW detection\r\n");
+            spi_flash_device.geometry.sector_count = 2048;
+        }
+        else if(memory_type_capacity == MTC_W25Q32_BV)
+        {
+            FLASH_TRACE("W25Q32BV detection\r\n");
+            spi_flash_device.geometry.sector_count = 1024;
+        }
+        else if(memory_type_capacity == MTC_W25Q32_DW)
+        {
+            FLASH_TRACE("W25Q32DW detection\r\n");
+            spi_flash_device.geometry.sector_count = 1024;
+        }
+        else if(memory_type_capacity == MTC_W25Q16_BV_CL_CV)
+        {
+            FLASH_TRACE("W25Q16BV or W25Q16CL or W25Q16CV detection\r\n");
+            spi_flash_device.geometry.sector_count = 512;
+        }
+        else if(memory_type_capacity == MTC_W25Q16_DW)
+        {
+            FLASH_TRACE("W25Q16DW detection\r\n");
+            spi_flash_device.geometry.sector_count = 512;
+        }
+        else
+        {
+            FLASH_TRACE("Memory Capacity error!\r\n");
+            return -RT_ENOSYS;
+        }
+    }
+
+    /* register device */
+    spi_flash_device.flash_device.type    = RT_Device_Class_Block;
+    spi_flash_device.flash_device.init    = w25qxx_flash_init;
+    spi_flash_device.flash_device.open    = w25qxx_flash_open;
+    spi_flash_device.flash_device.close   = w25qxx_flash_close;
+    spi_flash_device.flash_device.read    = w25qxx_flash_read;
+    spi_flash_device.flash_device.write   = w25qxx_flash_write;
+    spi_flash_device.flash_device.control = w25qxx_flash_control;
+    /* no private */
+    spi_flash_device.flash_device.user_data = RT_NULL;
+
+    rt_device_register(&spi_flash_device.flash_device, flash_device_name,
+                       RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+    return RT_EOK;
+}

+ 34 - 0
components/drivers/spi/spi_flash_w25qxx.h

@@ -0,0 +1,34 @@
+/*
+ * File      : spi_flash_w25qxx.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2011-12-16     aozima      the first version
+ * 2012-08-23     aozima       add flash lock.
+ */
+
+#ifndef SPI_FLASH_W25QXX_H_INCLUDED
+#define SPI_FLASH_W25QXX_H_INCLUDED
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+struct spi_flash_device
+{
+    struct rt_device                flash_device;
+    struct rt_device_blk_geometry   geometry;
+    struct rt_spi_device *          rt_spi_device;
+    struct rt_mutex                 lock;
+};
+
+extern rt_err_t w25qxx_init(const char * flash_device_name,
+                            const char * spi_device_name);
+
+
+#endif // SPI_FLASH_W25QXX_H_INCLUDED

+ 590 - 0
components/drivers/spi/spi_wifi_rw009.c

@@ -0,0 +1,590 @@
+/*
+ * File      : spi_wifi_rw009.c
+ * This file is part of RT-Thread RTOS
+ * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ *  This program 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-07-31     aozima       the first version
+ */
+
+#include <rtthread.h>
+#include <drivers/spi.h>
+
+#include <netif/ethernetif.h>
+#include <netif/etharp.h>
+#include <lwip/icmp.h>
+#include "lwipopts.h"
+
+#include "spi_wifi_rw009.h"
+
+#define SSID_NAME      "AP_SSID"
+#define SSID_PASSWORD  "AP_passwd"
+
+//#define WIFI_DEBUG_ON
+// #define ETH_RX_DUMP
+// #define ETH_TX_DUMP
+
+#ifdef WIFI_DEBUG_ON
+#define WIFI_DEBUG         rt_kprintf("[WIFI] ");rt_kprintf
+#else
+#define WIFI_DEBUG(...)
+#endif /* #ifdef WIFI_DEBUG_ON */
+
+#define MAX_BUFFER_SIZE     (sizeof(struct response) + MAX_DATA_LEN)
+#define MAX_ADDR_LEN 6
+struct spi_wifi_eth
+{
+    /* inherit from ethernet device */
+    struct eth_device parent;
+
+    struct rt_spi_device *rt_spi_device;
+
+    /* interface address info. */
+    rt_uint8_t  dev_addr[MAX_ADDR_LEN];         /* hw address   */
+    rt_uint8_t  active;
+
+    struct rt_mempool spi_tx_mp;
+    struct rt_mempool spi_rx_mp;
+
+    struct rt_mailbox spi_tx_mb;
+    struct rt_mailbox eth_rx_mb;
+
+    int spi_tx_mb_pool[SPI_TX_POOL_SIZE];
+    int eth_rx_mb_pool[SPI_TX_POOL_SIZE];
+
+    int spi_wifi_cmd_mb_pool[3];
+    struct rt_mailbox spi_wifi_cmd_mb;
+
+    ALIGN(4)
+    rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
+    ALIGN(4)
+    rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
+
+    ALIGN(4)
+    uint8_t spi_hw_rx_buffer[MAX_BUFFER_SIZE];
+};
+static struct spi_wifi_eth spi_wifi_device;
+static struct rt_event spi_wifi_data_event;
+
+static void resp_handler(struct spi_wifi_eth *wifi_device, struct spi_wifi_resp *resp)
+{
+    struct spi_wifi_resp *resp_return;
+
+    switch (resp->cmd)
+    {
+    case SPI_WIFI_CMD_INIT:
+        WIFI_DEBUG("resp_handler SPI_WIFI_CMD_INIT\n");
+        resp_return = (struct spi_wifi_resp *)rt_malloc(sizeof(struct spi_wifi_resp)); //TODO:
+        memcpy(resp_return, resp, 10);
+        rt_mb_send(&wifi_device->spi_wifi_cmd_mb, (rt_uint32_t)resp_return);
+        break;
+
+    case SPI_WIFI_CMD_SCAN:
+        WIFI_DEBUG("resp_handler SPI_WIFI_CMD_SCAN\n");
+        break;
+
+    case SPI_WIFI_CMD_JOIN:
+        WIFI_DEBUG("resp_handler SPI_WIFI_CMD_JOIN\n");
+        wifi_device->active = 1;
+        eth_device_linkchange(&wifi_device->parent, RT_TRUE);
+        break;
+
+    default:
+        WIFI_DEBUG("resp_handler %d\n", resp->cmd);
+        break;
+    }
+
+}
+
+static rt_err_t spi_wifi_transfer(struct spi_wifi_eth *dev)
+{
+    struct pbuf *p = RT_NULL;
+    struct cmd_request cmd;
+    struct response resp;
+
+    rt_err_t result;
+    const struct spi_data_packet *data_packet = RT_NULL;
+
+    struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+    struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
+
+    spi_wifi_int_cmd(0);
+    while (spi_wifi_is_busy());
+    WIFI_DEBUG("sequence start!\n");
+
+    memset(&cmd, 0, sizeof(struct cmd_request));
+    cmd.magic1 = CMD_MAGIC1;
+    cmd.magic2 = CMD_MAGIC2;
+
+    cmd.flag |= CMD_FLAG_MRDY;
+
+    result = rt_mb_recv(&wifi_device->spi_tx_mb,
+                        (rt_uint32_t *)&data_packet,
+                        0);
+    if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
+    {
+        cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
+        //WIFI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len);
+    }
+
+    rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
+    while (spi_wifi_is_busy());
+
+    {
+        struct rt_spi_message message;
+        uint32_t max_data_len = 0;
+
+        /* setup message */
+        message.send_buf = RT_NULL;
+        message.recv_buf = &resp;
+        message.length = sizeof(resp);
+        message.cs_take = 1;
+        message.cs_release = 0;
+
+        rt_spi_take_bus(rt_spi_device);
+
+        /* transfer message */
+        rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+        if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
+        {
+            WIFI_DEBUG("bad resp magic, abort!\n");
+            goto _bad_resp_magic;
+        }
+
+        if (resp.flag & RESP_FLAG_SRDY)
+        {
+            WIFI_DEBUG("RESP_FLAG_SRDY\n");
+            max_data_len = cmd.M2S_len;
+        }
+
+        if (resp.S2M_len)
+        {
+            WIFI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len);
+            if (resp.S2M_len > sizeof(struct spi_data_packet))
+            {
+                WIFI_DEBUG("resp.S2M_len > sizeof(struct spi_data_packet), drop!\n");
+                resp.S2M_len = 0;//drop
+            }
+
+            if (resp.S2M_len > max_data_len)
+                max_data_len = resp.S2M_len;
+        }
+
+        if (max_data_len == 0)
+        {
+            WIFI_DEBUG("no rx or tx data!\n");
+        }
+
+        //WIFI_DEBUG("max_data_len = %d\n", max_data_len);
+
+_bad_resp_magic:
+        /* setup message */
+        message.send_buf = data_packet;//&tx_buffer;
+        message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer;
+        message.length = max_data_len;
+        message.cs_take = 0;
+        message.cs_release = 1;
+
+        /* transfer message */
+        rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+        rt_spi_release_bus(rt_spi_device);
+
+        if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY))
+        {
+            rt_mp_free((void *)data_packet);
+        }
+
+        if ((resp.S2M_len) && (resp.S2M_len <= MAX_DATA_LEN))
+        {
+            data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
+            if (data_packet->data_type == data_type_eth_data)
+            {
+
+                if (wifi_device->active)
+                {
+                    p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
+                    pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
+
+                    rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
+                    eth_device_ready((struct eth_device *)dev);
+                }
+                else
+                {
+                    WIFI_DEBUG("!active, RX drop.\n");
+                }
+            }
+            else if (data_packet->data_type == data_type_resp)
+            {
+                WIFI_DEBUG("data_type_resp\n");
+                resp_handler(dev, (struct spi_wifi_resp *)data_packet->buffer);
+            }
+            else
+            {
+                WIFI_DEBUG("data_type: %d, %dbyte\n",
+                           data_packet->data_type,
+                           data_packet->data_len);
+            }
+        }
+    }
+    spi_wifi_int_cmd(1);
+
+    WIFI_DEBUG("sequence finish!\n\n");
+
+    if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
+    {
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+#if defined(ETH_RX_DUMP) ||  defined(ETH_TX_DUMP)
+static void packet_dump(const char *msg, const struct pbuf *p)
+{
+    rt_uint32_t i;
+    rt_uint8_t *ptr = p->payload;
+
+    rt_kprintf("%s %d byte\n", msg, p->tot_len);
+
+    for (i = 0; i < p->tot_len; i++)
+    {
+        if ((i % 8) == 0)
+        {
+            rt_kprintf("  ");
+        }
+        if ((i % 16) == 0)
+        {
+            rt_kprintf("\r\n");
+        }
+        rt_kprintf("%02x ", *ptr);
+        ptr++;
+    }
+    rt_kprintf("\n\n");
+}
+#endif /* dump */
+
+/* initialize the interface */
+static rt_err_t spi_wifi_eth_init(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t spi_wifi_eth_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    return RT_EOK;
+}
+
+static rt_err_t spi_wifi_eth_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_size_t spi_wifi_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+static rt_size_t spi_wifi_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+
+static rt_err_t spi_wifi_eth_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+    struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+    struct spi_data_packet *data_packet;
+    struct spi_wifi_cmd *wifi_cmd;
+    struct spi_wifi_resp *resp;
+
+    switch (cmd)
+    {
+    case NIOCTL_GADDR:
+        memcpy(args, wifi_device->dev_addr, 6);
+        break;
+
+    case SPI_WIFI_CMD_INIT:
+        /* get mac address */
+        if (args)
+        {
+            rt_err_t result;
+
+            data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+            // TODO: check result.
+
+            wifi_cmd = (struct spi_wifi_cmd *)data_packet->buffer;
+            wifi_cmd->cmd = SPI_WIFI_CMD_INIT;
+
+            data_packet->data_type = data_type_cmd;
+            data_packet->data_len = member_offset(struct spi_wifi_cmd, buffer) + 0;
+
+            rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+            rt_event_send(&spi_wifi_data_event, 1);
+
+            result = rt_mb_recv(&wifi_device->spi_wifi_cmd_mb,
+                                (rt_uint32_t *)&resp,
+                                RT_WAITING_FOREVER);
+
+            if ((result == RT_EOK) && (resp != RT_NULL))
+            {
+                WIFI_DEBUG("resp cmd: %d\n", resp->cmd);
+
+                rt_memcpy(args, resp->buffer, 6);
+            }
+        }
+        else return -RT_ERROR;
+        break;
+
+
+    case SPI_WIFI_CMD_SCAN:
+
+    case SPI_WIFI_CMD_JOIN:
+        if (args)
+        {
+            struct cmd_join *cmd_join;
+
+            data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+
+            wifi_cmd = (struct spi_wifi_cmd *)data_packet->buffer;
+            wifi_cmd->cmd = SPI_WIFI_CMD_JOIN;
+            cmd_join = (struct cmd_join *)wifi_cmd->buffer;
+
+#define WPA_SECURITY    0x00200000
+#define WPA2_SECURITY   0x00400000
+
+#define TKIP_ENABLED    0x0002
+#define AES_ENABLED     0x0004
+
+
+            strncpy(cmd_join->ssid, SSID_NAME, SSID_NAME_LENGTH_MAX);
+            strncpy(cmd_join->passwd, SSID_PASSWORD, PASSWORD_LENGTH_MAX);
+            cmd_join->security = WPA2_SECURITY | TKIP_ENABLED | AES_ENABLED;
+            // cmd_join->security = WPA_SECURITY | TKIP_ENABLED;
+            data_packet->data_type = data_type_cmd;
+            data_packet->data_len = sizeof(struct cmd_join) + member_offset(struct spi_wifi_cmd, buffer);
+
+            rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+            rt_event_send(&spi_wifi_data_event, 1);
+        }
+        else return -RT_ERROR;
+        break;
+
+    default :
+        break;
+    }
+
+    return RT_EOK;
+}
+
+/* transmit packet. */
+rt_err_t spi_wifi_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+    rt_err_t result = RT_EOK;
+    struct spi_data_packet *data_packet;
+    struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+
+    if (!wifi_device->active)
+    {
+        WIFI_DEBUG("!active, TX drop!\n");
+        return RT_EOK;
+    }
+
+    /* get free tx buffer */
+    data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+    if (data_packet != RT_NULL)
+    {
+        data_packet->data_type = data_type_eth_data;
+        data_packet->data_len = p->tot_len;
+
+        pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
+
+        rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+        eth_device_ready((struct eth_device *)dev);
+    }
+    else
+        return -RT_ERROR;
+
+#ifdef ETH_TX_DUMP
+    packet_dump("TX dump", p);
+#endif /* ETH_TX_DUMP */
+
+    /* Return SUCCESS */
+    return result;
+}
+
+/* reception packet. */
+struct pbuf *spi_wifi_eth_rx(rt_device_t dev)
+{
+    struct pbuf *p = RT_NULL;
+    struct spi_wifi_eth *wifi_device = (struct spi_wifi_eth *)dev;
+
+    if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK)
+    {
+        return RT_NULL;
+    }
+
+
+
+    return p;
+}
+
+static void spi_wifi_data_thread_entry(void *parameter)
+{
+    rt_uint32_t e;
+    rt_err_t result;
+
+    while (1)
+    {
+        /* receive first event */
+        if (rt_event_recv(&spi_wifi_data_event,
+                          1,
+                          RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                          RT_WAITING_FOREVER,
+                          &e) != RT_EOK)
+        {
+            continue;
+        }
+
+        result = spi_wifi_transfer(&spi_wifi_device);
+
+        if (result == RT_EOK)
+        {
+            rt_event_send(&spi_wifi_data_event, 1);
+        }
+    }
+}
+
+rt_err_t rt_hw_wifi_init(const char *spi_device_name)
+{
+    memset(&spi_wifi_device, 0, sizeof(struct spi_wifi_eth));
+
+    spi_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+
+    if (spi_wifi_device.rt_spi_device == RT_NULL)
+    {
+        WIFI_DEBUG("spi device %s not found!\r\n", spi_device_name);
+        return -RT_ENOSYS;
+    }
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
+        cfg.max_hz = 1000000; /* 50M */
+        rt_spi_configure(spi_wifi_device.rt_spi_device, &cfg);
+    }
+
+    spi_wifi_device.parent.parent.init       = spi_wifi_eth_init;
+    spi_wifi_device.parent.parent.open       = spi_wifi_eth_open;
+    spi_wifi_device.parent.parent.close      = spi_wifi_eth_close;
+    spi_wifi_device.parent.parent.read       = spi_wifi_eth_read;
+    spi_wifi_device.parent.parent.write      = spi_wifi_eth_write;
+    spi_wifi_device.parent.parent.control    = spi_wifi_eth_control;
+    spi_wifi_device.parent.parent.user_data  = RT_NULL;
+
+    spi_wifi_device.parent.eth_rx     = spi_wifi_eth_rx;
+    spi_wifi_device.parent.eth_tx     = spi_wifi_eth_tx;
+
+    rt_mp_init(&spi_wifi_device.spi_tx_mp,
+               "spi_tx",
+               &spi_wifi_device.spi_tx_mempool[0],
+               sizeof(spi_wifi_device.spi_tx_mempool),
+               sizeof(struct spi_data_packet));
+
+    rt_mp_init(&spi_wifi_device.spi_rx_mp,
+               "spi_rx",
+               &spi_wifi_device.spi_rx_mempool[0],
+               sizeof(spi_wifi_device.spi_rx_mempool),
+               sizeof(struct spi_data_packet));
+
+    rt_mb_init(&spi_wifi_device.spi_tx_mb,
+               "spi_tx",
+               &spi_wifi_device.spi_tx_mb_pool[0],
+               SPI_TX_POOL_SIZE,
+               RT_IPC_FLAG_PRIO);
+
+    rt_mb_init(&spi_wifi_device.eth_rx_mb,
+               "eth_rx",
+               &spi_wifi_device.eth_rx_mb_pool[0],
+               SPI_TX_POOL_SIZE,
+               RT_IPC_FLAG_PRIO);
+
+    rt_mb_init(&spi_wifi_device.spi_wifi_cmd_mb,
+               "wifi_cmd",
+               &spi_wifi_device.spi_wifi_cmd_mb_pool[0],
+               sizeof(spi_wifi_device.spi_wifi_cmd_mb_pool) / 4,
+               RT_IPC_FLAG_PRIO);
+    rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
+
+    spi_wifi_hw_init();
+
+    {
+        rt_thread_t tid;
+
+
+        tid = rt_thread_create("wifi",
+                               spi_wifi_data_thread_entry,
+                               RT_NULL,
+                               2048,
+                               RT_THREAD_PRIORITY_MAX - 2,
+                               20);
+
+        if (tid != RT_NULL)
+            rt_thread_startup(tid);
+    }
+
+    /* init: get mac address */
+    {
+        WIFI_DEBUG("wifi_control SPI_WIFI_CMD_INIT\n");
+        spi_wifi_eth_control((rt_device_t)&spi_wifi_device,
+                             SPI_WIFI_CMD_INIT,
+                             (void *)&spi_wifi_device.dev_addr[0]);
+
+    }
+    /* register eth device */
+    eth_device_init(&(spi_wifi_device.parent), "w0");
+    eth_device_linkchange(&spi_wifi_device.parent, RT_FALSE);
+
+    {
+        WIFI_DEBUG("wifi_control SPI_WIFI_CMD_JOIN\n");
+        spi_wifi_eth_control((rt_device_t)&spi_wifi_device,
+                             SPI_WIFI_CMD_JOIN,
+                             (void *)&spi_wifi_device.dev_addr[0]);
+
+        WIFI_DEBUG("wifi_control exit\n");
+    }
+
+    return RT_EOK;
+}
+
+void spi_wifi_isr(int vector)
+{
+	/* enter interrupt */
+	rt_interrupt_enter();
+
+    WIFI_DEBUG("spi_wifi_isr\n");
+    rt_event_send(&spi_wifi_data_event, 1);
+
+	/* leave interrupt */
+	rt_interrupt_leave();
+}

+ 123 - 0
components/drivers/spi/spi_wifi_rw009.h

@@ -0,0 +1,123 @@
+/*
+ * File      : spi_wifi_rw009.h
+ * This file is part of RT-Thread RTOS
+ * Copyright by Shanghai Real-Thread Electronic Technology Co.,Ltd
+ *
+ *  This program 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-07-31     aozima       the first version
+ */
+
+#ifndef SPI_WIFI_H_INCLUDED
+#define SPI_WIFI_H_INCLUDED
+
+#include <stdint.h>
+
+// little-endian
+struct cmd_request
+{
+    uint32_t flag;
+    uint32_t M2S_len; // master to slave data len.
+    uint32_t magic1;
+    uint32_t magic2;
+};
+
+#define CMD_MAGIC1          (0x67452301)
+#define CMD_MAGIC2          (0xEFCDAB89)
+
+#define CMD_FLAG_MRDY       (0x01)
+
+// little-endian
+struct response
+{
+    uint32_t flag;
+    uint32_t S2M_len; // slave to master data len.
+    uint32_t magic1;
+    uint32_t magic2;
+};
+
+#define RESP_FLAG_SRDY      (0x01)
+#define RESP_MAGIC1         (0x98BADCFE)
+#define RESP_MAGIC2         (0x10325476)
+
+/* spi slave configure. */
+#define MAX_DATA_LEN        1520
+#define SPI_TX_POOL_SIZE    2
+
+// align check
+#if (MAX_DATA_LEN & 0x03) != 0
+#error MAX_DATA_LEN must ALIGN to 4byte!
+#endif
+
+typedef enum
+{
+    data_type_eth_data = 0,
+    data_type_cmd,
+    data_type_resp,
+}
+app_data_type_typedef;
+
+struct spi_data_packet
+{
+    uint32_t data_len;
+    uint32_t data_type;
+    char buffer[MAX_DATA_LEN];
+};
+
+struct spi_wifi_cmd
+{
+    uint32_t cmd;
+    char buffer[128];
+};
+
+struct spi_wifi_resp
+{
+    uint32_t cmd;
+    char buffer[128];
+};
+
+#define SPI_WIFI_CMD_INIT         128  //wait
+#define SPI_WIFI_CMD_SCAN         129  //no wait
+#define SPI_WIFI_CMD_JOIN         130  //no wait
+
+/* porting */
+extern void spi_wifi_hw_init(void);
+extern void spi_wifi_int_cmd(rt_bool_t cmd);
+extern rt_bool_t spi_wifi_is_busy(void);
+
+/* tools */
+#define node_entry(node, type, member) \
+    ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
+#define member_offset(type, member) \
+    ((unsigned long)(&((type *)0)->member))
+
+#define SSID_NAME_LENGTH_MAX        (32)
+#define PASSWORD_LENGTH_MAX         (32)
+
+struct cmd_join
+{
+    char ssid[SSID_NAME_LENGTH_MAX];
+    char passwd[PASSWORD_LENGTH_MAX];
+
+    uint8_t bssid[8]; // 6byte + 2byte PAD.
+
+    uint32_t channel;
+    uint32_t security;
+};
+
+
+#endif // SPI_WIFI_H_INCLUDED