]> rtime.felk.cvut.cz Git - lincan.git/commitdiff
Support for asynchronous SPI messages and callbacks
authorIng. Jan Kriz <devel@jojen.net>
Mon, 18 Apr 2011 08:37:32 +0000 (10:37 +0200)
committerIng. Jan Kriz <devel@jojen.net>
Mon, 18 Apr 2011 08:37:32 +0000 (10:37 +0200)
lincan/include/main.h
lincan/include/mcp2515.h
lincan/include/omap2_spican.h
lincan/src/main.c
lincan/src/mcp2515.c
lincan/src/omap2_spican.c
lincan/src/setup.c

index 23accfb31ac56882fccd9f2eeaa6c83af06a14a1..2c146ff1f6bcebfdc915eacddd1a6c9ddcbb84cd 100644 (file)
@@ -32,6 +32,8 @@
 /* Publication of enhanced or derived LinCAN files is required although.  */
 /**************************************************************************/
 
+// #define CAN_DEBUG
+
 #include "./can.h"
 #include "./constants.h"
 #include "./can_sysdep.h"
@@ -197,6 +199,7 @@ struct canchip_t {
        int  (*spi_acquire_bus)(struct candevice_t *candev, short channel, int block);
        void (*spi_release_bus)(struct candevice_t *candev, short channel);
        int  (*spi_transfer)(struct candevice_t *candev, void *tx, void *rx, uint16_t len);
+       int  (*spi_async_transfer)(struct candevice_t *candev, void (*callback)(void *data, uint8_t count), void *data, uint8_t count, uint8_t fasthandler);
        short spi_channel;
 
 
@@ -338,14 +341,15 @@ struct hwspecops_t {
        int (*program_irq)(struct candevice_t *candev);
        void (*write_register)(unsigned data, can_ioptr_t address);
        unsigned (*read_register)(can_ioptr_t address);
-       int (*spi_acquire_bus)(struct candevice_t *candev, short channel, int block);
-       void (*spi_release_bus)(struct candevice_t *candev, short channel);
-       int (*spi_transfer)(struct candevice_t *candev, void *tx, void *rx, uint16_t len);
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10))
        void (*release_device)(struct kref *refcount);
 #endif
        
+       int (*spi_acquire_bus)(struct candevice_t *candev, short channel, int block);
+       void (*spi_release_bus)(struct candevice_t *candev, short channel);
+       int (*spi_transfer)(struct candevice_t *candev, void *tx, void *rx, uint16_t len);
+       int (*spi_async_transfer)(struct candevice_t *candev, void (*callback)(void *data, uint8_t count), void *data, uint8_t count, uint8_t fasthandler);
 };
 
 /**
@@ -486,6 +490,28 @@ extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struc
 #define CONFIG_OC_LINCAN_DYNAMICIO
 #endif
 
+#define SPI_MESSAGE_LENGTH (32)
+
+/**
+ * struct can_spi_async_t - SPI asynchronous communication supplemental data
+ * @chip: pointer to the chip structure
+ * @opcode: Operation code to be identified by spi_async callback function
+ * @tx_buf: a read-only copy of the transfer buffer
+ * @rx_buf: a read-only copy of the transfer buffer
+ * @len: length of the transmitted buffer
+ * @obj: lincan message for data transmission
+ */
+struct can_spi_async_t{
+       struct canchip_t *chip;
+       uint8_t opcode;
+       uint8_t tx_buf[SPI_MESSAGE_LENGTH];
+       uint8_t rx_buf[SPI_MESSAGE_LENGTH];
+       size_t len;
+       struct msgobj_t *obj;
+       canmsg_tstamp_t timestamp;
+};
+
+
 /* Inline function to write to the hardware registers. The argument reg_offs is
  * relative to the memory map of the chip and not the absolute memory reg_offs.
  */
@@ -508,6 +534,11 @@ extern inline int can_spi_transfer(struct canchip_t *chip, void *tx, void *rx, u
        return chip->spi_transfer(chip->hostdevice, tx, rx, len);
 }
 
+extern inline int can_spi_async_transfer(struct canchip_t *chip, void (*callback)(void *data, uint8_t count), struct can_spi_async_t *data, uint8_t count, uint8_t fasthandler)
+{
+       return chip->spi_async_transfer(chip->hostdevice, callback, data, count, fasthandler);
+}
+
 extern inline int can_spi_acquire_bus(struct canchip_t *chip, int block)
 {
        return chip->spi_acquire_bus(chip->hostdevice, chip->spi_channel, block);
@@ -519,7 +550,6 @@ extern inline void can_spi_release_bus(struct canchip_t *chip)
 }
 
 
-
 extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
                                unsigned char data, unsigned reg_offs)
 {
index 00add4ef01b055de4bf95a8ecd5d8ad70007e6b2..bad1caea70deb49a9178dc6bfd7c85e2de796387 100644 (file)
@@ -57,6 +57,7 @@ typedef struct {
 } MCP2515_ERRCNT;      
 
 #define MCP2515_STATUS_SHUTDOWN (1)
+#define MCP2515_TXBUF_NUM (3)
 
 typedef struct {
        struct canchip_t *chip;
@@ -64,6 +65,10 @@ typedef struct {
        uint8_t spi_buf[SPI_BUF_LEN];
        struct work_struct workqueue_handler;
        struct tasklet_struct tasklet_handler;
+
+       struct work_struct txwq_handler;
+       DECLARE_BITMAP(txfree, MCP2515_TXBUF_NUM);
+
        MCP2515_ERRCNT errcnt;
        uint32_t wakeint_cnt;
 } MCP2515_PRIV;
index c165a284fa90083d7b326d06a1735f50e9eb9c1e..6fae401ccc2c5c3f71f1c743a37f4e6f89fae8d0 100644 (file)
@@ -6,7 +6,7 @@
  * Adapted for spican by Jan Kriz
  * email:devel@jojen.net
  * This software is released under the GPL-License.
- * Version lincan-0.3.4-r1  20 Aug 2010
+ * Version lincan-0.3.4-r2  14 Sep 2010
  */
 
 #define OMAP2_SPICAN_NCHIPS 1 // Since the device is initiated from SPI, it's applies to 1 chip (and 1 irq) at a time
@@ -32,16 +32,39 @@ int spican_program_irq(struct candevice_t *candev);
 #define OMAP2_SPICAN_DELAY_USECS (0)
 #define OMAP2_SPICAN_SPEED_HZ (10000000)
 
-struct omap2_spican_platform_data {
-       uint32_t mcp2515_clk; /* Clock frequency of MCP2515 */
-       uint32_t baudrate; /* Requested can communication speed */
+#define OMAP2_SPICAN_PRE_ASYNC (256)
+#define OMAP2_SPICAN_MAX_TRANSFERS (2)
+
+struct omap2_spican_async_t {
+       void (*complete)(void *arg, uint8_t count);
+       struct can_spi_async_t data[OMAP2_SPICAN_MAX_TRANSFERS];
+       uint8_t count;
+       uint8_t bitmap_bit;
+       struct spi_transfer t[OMAP2_SPICAN_MAX_TRANSFERS];
+       struct spi_message m;
+       uint8_t fasthandler;
+};
+
+struct lincan_spican_platform_data {
+       u32 clk; /* Clock frequency of the chip */
+       u32 baudrate; /* Requested can communication speed */
+       u32 speed_hz; /* Speed of SPI communication */
+       const char *chiptype;
        
-       unsigned cs_change; /* Cycle ~CS between transmissions? */
        u16 delay_usecs; /* Time gap between transmissions */
-       u32 speed_hz; /* Speed of SPI communication */
+       u8 cs_change; /* Cycle ~CS between transmissions? */
+};
 
+struct omap2_spican_platform_data {
+       /** This part must be kept the same as in struct lincan_spican_platform_data */
+       u32 clk; /* Clock frequency of the chip */
+       u32 baudrate; /* Requested can communication speed */
+       u32 speed_hz; /* Speed of SPI communication */
        const char *chiptype;
        
+       u16 delay_usecs; /* Time gap between transmissions */
+       u8 cs_change; /* Cycle ~CS between transmissions? */
+
        /* Following options are set at runtime */
        struct spi_device *spi; /* SPI device */
        u8      trigger;
@@ -51,6 +74,13 @@ struct omap2_spican_platform_data {
        int32_t timer_irq; // the IRQ # for our gp timer
 #endif /* CONFIG_OMAP_DM_TIMER */
        spinlock_t spi_lock;
+       struct omap2_spican_async_t async[OMAP2_SPICAN_PRE_ASYNC];
+       DECLARE_BITMAP(async_req_map, OMAP2_SPICAN_PRE_ASYNC);
+       DECLARE_BITMAP(lo_async_done_map, OMAP2_SPICAN_PRE_ASYNC);
+       struct tasklet_struct lo_async_tasklet;
+       struct work_struct lo_async_workqueue;
+       DECLARE_BITMAP(hi_async_done_map, OMAP2_SPICAN_PRE_ASYNC);
+       struct tasklet_struct hi_async_tasklet;
 };
 
 int omap2_spican_init(void);
index c5547af9e2e535021426e94c7707db77b562168f..34661f19453a7885d6f6639579222fde86ee42e9 100644 (file)
        #include "../include/usbcan.h"
 #endif
 #if defined(CONFIG_OC_LINCAN_CARD_omap2_spican)
+       #include <linux/spi/spi.h>
        #include "../include/omap2_spican.h"
 #endif
 
@@ -603,8 +604,8 @@ struct candevice_t* register_hotplug_dev(const char *hwname,int (*chipdataregfnc
                #endif /*CAN_WITH_RTL*/
 
 //     register_error:
-//             if ( can_del_mem_list() )
-//                     CANMSG("Error deallocating memory\n");
+//             if ( can_del_mem_list() )
+//                     CANMSG("Error deallocating memory\n");
 
                return NULL;
 }
index 10e4c5f05c5f183f777e103389f98d0d4252ef82..51ff64b32a3ceade98b3baacc53a6ac0ad78b74d 100644 (file)
 #define RESET_CMD  0xc0
 #define READ_CMD   0x03
 #define WRITE_CMD  0x02
+#define READ_RX0_CMD 0x90
+#define READ_RX1_CMD 0x94
 #define BITMOD_CMD 0x05
 
+#define MCP2515_SPI_ASYNC
+
+enum MCP2515_OPS {
+       NOOP,
+       READ_RX0,
+       READ_RX1,
+       READ_CANINTF,
+       READ_ERR
+};
+
+static struct workqueue_struct *mcp2515_wq;
+
+static void mcp2515_async_callback(void *data, uint8_t count);
+static void tx_handler(struct canchip_t *chip,  struct msgobj_t *obj);
 
 /*****************************************************************************/
 /*                       SPI ACCESS FUNCTIONS                                */
@@ -122,6 +138,241 @@ static void bitmod_reg(struct canchip_t *chip, unsigned addr,
 }
 
 
+/*****************************************************************************/
+static void bitmod_reg_async(struct canchip_t *chip, unsigned addr, 
+                      unsigned char mask, unsigned char data, uint8_t opcode)
+{
+       struct can_spi_async_t async;
+
+       async.chip = chip;
+       async.opcode = opcode;
+       async.tx_buf[0] = BITMOD_CMD;
+       async.tx_buf[1] = addr;
+       async.tx_buf[2] = mask;
+       async.tx_buf[3] = data;
+       async.len = 4;
+       can_spi_async_transfer(chip, mcp2515_async_callback, &async, 1, 0);
+
+#if DEBUG
+       DEBUGMSG("reg[0x%02x]<=0x%02x mask=0x%02x\n",addr,(unsigned)data,(unsigned)mask);
+#endif
+}
+
+/*****************************************************************************/
+static void read_async(struct canchip_t *chip, unsigned startAddr, size_t len, uint8_t opcode)
+{
+       struct can_spi_async_t async[2];
+
+       async[0].chip = chip;
+       async[0].opcode = opcode;
+       async[0].tx_buf[0] = READ_CMD;
+       async[0].tx_buf[1] = startAddr;
+       async[0].len = len+2;
+       
+       if (opcode == READ_CANINTF){
+               async[1].chip = chip;
+               async[1].opcode = opcode;
+               async[1].tx_buf[0] = READ_CMD;
+               async[1].tx_buf[1] = startAddr;
+               async[1].len = len+2;
+               can_spi_async_transfer(chip, mcp2515_async_callback, async, 2, 1);
+       }
+       else
+               can_spi_async_transfer(chip, mcp2515_async_callback, async, 1, 0);
+}
+
+/*****************************************************************************/
+inline void read_rx_async(struct canchip_t *chip, unsigned rxbuf,struct msgobj_t *obj)
+{
+       struct can_spi_async_t async = {
+               .chip = chip,
+               .opcode = rxbuf?READ_RX1:READ_RX0,
+               .tx_buf[0] = rxbuf?READ_RX1_CMD:READ_RX0_CMD,
+               .len = sizeof(MCP2515_FRAME)+1,
+               .obj = obj,
+       };
+
+       can_spi_async_transfer(chip, mcp2515_async_callback, &async, 1, 0);
+}
+
+/*****************************************************************************/
+inline void read_err_async(struct canchip_t *chip)
+{
+       struct can_spi_async_t async;
+
+       async.chip = chip;
+       async.opcode = READ_ERR;
+       async.tx_buf[0] = READ_CMD;
+       async.tx_buf[1] = MCP2515_EFLG;
+       async.len = 3;
+
+       can_spi_async_transfer(chip, mcp2515_async_callback, &async, 1, 0);
+}
+
+/*****************************************************************************/
+static void txwq_handler(struct work_struct *work)
+{
+       MCP2515_PRIV *priv = container_of(work,MCP2515_PRIV,txwq_handler);
+       struct canchip_t *chip = priv->chip;
+       int n;
+       if (chip == NULL)
+               return;
+       n = find_first_bit(priv->txfree, MCP2515_TXBUF_NUM);
+       while (n<MCP2515_TXBUF_NUM){
+               clear_bit(n,priv->txfree);
+               tx_handler(chip,chip->msgobj[n]);
+               n = find_first_bit(priv->txfree, MCP2515_TXBUF_NUM);
+       }
+}
+       
+
+static int mcp2515_async_canintf_reread = 0;
+/*****************************************************************************/
+static void mcp2515_async_callback(void *data,uint8_t count){
+       struct can_spi_async_t *async = (struct can_spi_async_t *)data;
+       struct canchip_t *chip;
+       struct msgobj_t *obj;
+       int i;
+       if (async == NULL)
+               return;
+       
+       for (i=0;i<count;i++){
+               switch (async[i].opcode){
+                       case NOOP : break;
+                       case READ_RX0 : 
+                       case READ_RX1 : {
+                               uint8_t len;
+                               MCP2515_FRAME *frame = NULL;
+                               
+                               chip = async[i].chip;
+                               if (chip == NULL) return;
+                               obj = async[i].obj;
+                               if (obj == NULL) return;
+
+                               if (async[i].rx_buf == NULL)
+                                       panic("async[%d].rx_buf is null",i);
+                               frame = (MCP2515_FRAME *)(async[i].rx_buf+1); //The received data is 1 byte late
+
+                               if(frame->sidl & mcpIDE) {
+                                       DEBUGMSG("extended frame\n");
+                                       obj->rx_msg.id = 
+                                               ((uint32_t)frame->eid0)              | 
+                                               ((uint32_t)frame->eid8)        <<  8 |
+                                               ((uint32_t)frame->sidl & 0x03) << 16 |
+                                               ((uint32_t)frame->sidl & 0xe0) << 13 |
+                                               ((uint32_t)frame->sidh)        << 21;                           
+                                       obj->rx_msg.flags = MSG_EXT | ((frame->dlc & mcpRTR) ? MSG_RTR : 0);
+                               } 
+                               else {
+                                       DEBUGMSG("standard frame\n");
+                                       obj->rx_msg.id =
+                                               ((uint32_t)frame->sidl) >> 5 |
+                                               ((uint32_t)frame->sidh) << 3;
+                                       obj->rx_msg.flags = ((frame->sidl & mcpSRR) ? MSG_RTR : 0);
+                               }
+                                       
+                               len = frame->dlc & mcpDLC_MASK;
+                               if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+                               obj->rx_msg.length = len;               
+                                       
+                               memcpy(obj->rx_msg.data,frame->data,len);
+                                       
+                               /* fill CAN message timestamp */
+//                             can_filltimestamp(&obj->rx_msg.timestamp);              
+                               memcpy(&obj->rx_msg.timestamp, &async->timestamp, sizeof(canmsg_tstamp_t));
+                               canque_filter_msg2edges(obj->qends, &obj->rx_msg);
+                               break;
+                       }
+                       case READ_CANINTF : {
+                               uint8_t flags = async[i].rx_buf[2];
+                               MCP2515_PRIV *priv;
+
+                               chip = async[i].chip;
+                               if (chip == NULL) break;
+                               priv=(MCP2515_PRIV *)(chip->chip_data);
+                               if (priv == NULL) break;
+                               
+                               if ((count > i+1) && (async[i+1].opcode == READ_CANINTF) && (async[++i].rx_buf[2] ^ flags)){
+                                       DEBUGMSG("Found differences in two consequent interrupt flag readings. Reading again...\n");
+                                       read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+                                       break;
+                               }
+                               
+                               if((flags == 0) && (mcp2515_async_canintf_reread)){
+                                       mcp2515_async_canintf_reread = 0;
+                                       enable_irq(chip->chip_irq);
+                                       break;
+                               }
+                               else if((flags == 0)){
+                                       mcp2515_async_canintf_reread++;
+                                       read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+                                       break;
+                               }
+                               mcp2515_async_canintf_reread = 0;
+                               
+                               DEBUGMSG("mcp251x_irq_work_handler:%s%s%s%s%s%s%s%s\n",
+                                      (flags & mcpRX0INT) ? " RX0":"",
+                                      (flags & mcpRX1INT) ? " RX1":"",
+                                      (flags & mcpTX0INT) ? " TX0":"",
+                                      (flags & mcpTX1INT) ? " TX1":"",
+                                      (flags & mcpTX2INT) ? " TX2":"",
+                                      (flags & mcpERRINT) ? " ERR":"",         
+                                      (flags & mcpWAKINT) ? " WAK":"",
+                                      (flags & mcpMERREINT) ? " MERRE":"");
+
+
+                               if(flags & mcpRX0INT) read_rx_async(chip,0,chip->msgobj[0]);
+                               if(flags & mcpRX1INT) read_rx_async(chip,1,chip->msgobj[0]);
+                               if(flags & mcpTX0INT) {
+                                       set_bit(0,priv->txfree);
+                                       queue_work(mcp2515_wq,&priv->txwq_handler);
+                               }
+                               if(flags & mcpTX1INT) {
+                                       set_bit(1,priv->txfree);
+                                       queue_work(mcp2515_wq,&priv->txwq_handler);
+                               }
+                               if(flags & mcpTX2INT) {
+                                       set_bit(2,priv->txfree);
+                                       queue_work(mcp2515_wq,&priv->txwq_handler);
+                               }
+
+                               if(flags & mcpERRINT) read_err_async(chip);
+                               if(flags & mcpMERREINT) (priv->errcnt.merre)++;
+                               if(flags & mcpWAKINT) (priv->wakeint_cnt)++;
+                               
+                               bitmod_reg_async(chip, MCP2515_CANINTF, flags & ~(mcpRX0INT|mcpRX1INT), 0, NOOP);
+
+                               read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+                               break;
+                       }
+                       case READ_ERR : {
+                               uint8_t error = async[i].rx_buf[2];
+                               MCP2515_PRIV *priv;
+
+                               chip = async[i].chip;
+                               if (chip == NULL) break;
+                               priv=(MCP2515_PRIV *)(chip->chip_data);
+                               if (priv == NULL) break;
+                               
+                               if(error & mcpRX0OVR) {
+                                       (priv->errcnt.rx0ovr)++;
+                                       CANMSG("can: RX0OVR\n");
+                               }
+                               if(error & mcpRX1OVR) (priv->errcnt.rx1ovr)++;
+                               if(error & mcpTXBO)   (priv->errcnt.txbo)++;
+                               if(error & mcpTXEP)   (priv->errcnt.txep)++;
+                               if(error & mcpRXEP)   (priv->errcnt.rxep)++;
+                               if(error & mcpTXWAR)  (priv->errcnt.txwar)++;
+                               if(error & mcpRXWAR)  (priv->errcnt.rxwar)++;
+                               if(error & mcpEWARN)  (priv->errcnt.ewarn)++;
+
+                               break;
+                       }
+                       default : CANMSG("OMAP2_SPICAN got unknown asynchronous response");
+               }
+       }
+}
+
 /*****************************************************************************/
 /*                              PROC INTERFACE                               */
 /*****************************************************************************/
@@ -168,7 +419,6 @@ static void rx_handler(struct canchip_t *chip, int bufNo, struct msgobj_t *obj)
        if(chip == NULL) panic("rx_handler: chip==NULL");
        if(obj == NULL) panic("rx_handler: obj==NULL");
 
-
        /* get all frame data */
        if(bufNo == 0){
                read_block(chip,MCP2515_RXB0SIDH,sizeof(MCP2515_FRAME),&frame);
@@ -182,18 +432,18 @@ static void rx_handler(struct canchip_t *chip, int bufNo, struct msgobj_t *obj)
        if(frame.sidl & mcpIDE) {
                DEBUGMSG("extended frame\n");
                obj->rx_msg.id = 
-                       ((uint32_t)frame.eid0)              | 
-                       ((uint32_t)frame.eid8)        <<  8 |
-                       ((uint32_t)frame.sidl & 0x03) << 16 |
-                       ((uint32_t)frame.sidl & 0xe0) << 13 |
-                       ((uint32_t)frame.sidh)        << 21;                            
+                       ((uint32_t)frame.sidl & 0xe0) >>  5 |
+                       ((uint32_t)frame.sidh)        <<  3 |
+                       ((uint32_t)frame.eid0)        << 11 | 
+                       ((uint32_t)frame.eid8)        << 19 |
+                       ((uint32_t)frame.sidl & 0x03) << 27;
                obj->rx_msg.flags = MSG_EXT | ((frame.dlc & mcpRTR) ? MSG_RTR : 0);
        } 
        else {
                DEBUGMSG("standard frame\n");
                obj->rx_msg.id =
-                       ((uint32_t)frame.sidl) >> 5 |
-                       ((uint32_t)frame.sidh) << 3;
+                       ((uint32_t)frame.sidl & 0xe0) >>  5 |
+                       ((uint32_t)frame.sidh)        <<  3;
                obj->rx_msg.flags = ((frame.sidl & mcpSRR) ? MSG_RTR : 0);
        }
                
@@ -214,10 +464,10 @@ static void tx_handler(struct canchip_t *chip,  struct msgobj_t *obj)
        int cmd;
 
        if(chip == NULL) panic("tx_handler: chip==NULL");
-       if(obj == NULL) panic("tx_handler: obj==NULL");
-       
+       if(obj == NULL) panic("tx_handler: obj==NULL");
+#ifndef MCP2515_SPI_ASYNC
        bitmod_reg(chip,MCP2515_CANINTF, mcpTX0INT, ~mcpTX0INT);
-
+#endif
        
        if(obj->tx_slot) {
                /* Do local transmitted message distribution if enabled */
@@ -291,6 +541,10 @@ static void irq_work(void *data)
        priv=(MCP2515_PRIV *)(chip->chip_data);
        if (priv == NULL)
                return;
+       
+#ifdef MCP2515_SPI_ASYNC
+               read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+#else
        while(1) {
 
                flags = read_reg(chip, MCP2515_CANINTF);
@@ -320,8 +574,8 @@ static void irq_work(void *data)
 
 //             bitmod_reg(chip, MCP2515_CANINTF, flags, 0);
        }
-       
        enable_irq(chip->chip_irq);
+#endif /* MCP2515_SPI_ASYNC */
 }
 
 /*****************************************************************************/
@@ -476,21 +730,12 @@ int mcp2515_chip_config(struct canchip_t *chip)
        write_block(chip,MCP2515_TXB0DATA,8,pat0);
        for (i=0;i<10;i++){
                read_block(chip,MCP2515_TXB0DATA,8,pat1);
-//             *(pat1) = read_reg(chip,MCP2515_TXB0DATA);
-//             *(pat1+1) = read_reg(chip,MCP2515_TXB0DATA+1);
-//             *(pat1+2) = read_reg(chip,MCP2515_TXB0DATA+2);
-//             *(pat1+3) = read_reg(chip,MCP2515_TXB0DATA+3);
-//             *(pat1+4) = read_reg(chip,MCP2515_TXB0DATA+4);
-//             *(pat1+5) = read_reg(chip,MCP2515_TXB0DATA+5);
-//             *(pat1+6) = read_reg(chip,MCP2515_TXB0DATA+6);
-//             *(pat1+7) = read_reg(chip,MCP2515_TXB0DATA+7);
 
                if(memcmp(pat0,pat1,8)) {
                        CANMSG("mcp2515_chip_config: chip #%d not found\n",
                               chip->chip_idx);
                        CANMSG("Requested: Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X\n",pat0[0],pat0[1],pat0[2],pat0[3],pat0[4],pat0[5],pat0[6],pat0[7]);
                        CANMSG("Obtained : Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X\n",pat1[0],pat1[1],pat1[2],pat1[3],pat1[4],pat1[5],pat1[6],pat1[7]);
-//                     return -ENODEV;
                }
                else 
                        break;
@@ -503,8 +748,12 @@ int mcp2515_chip_config(struct canchip_t *chip)
        CANMSG("Found mcp2515:%d\n",chip->chip_idx);
        
 
-       if (mcp2515_extended_mask(chip,0x00000000, 0xffffffff))
+       // Accept only most the dominant message
+       if (mcp2515_extended_mask(chip,0xffffffff, 0xffffffff))
                return -ENODEV;
+/*     // Accept only most the dominant message
+       if (mcp2515_extended_mask(chip,0xffffffff, 0x00000000))
+               return -ENODEV;*/
        
        if (!chip->baudrate) chip->baudrate=1000000;
        if (mcp2515_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
@@ -530,25 +779,38 @@ int mcp2515_chip_config(struct canchip_t *chip)
  */
 int mcp2515_extended_mask(struct canchip_t *chip, unsigned long code, unsigned  long mask)
 {
+       char c_filter[4],c_mask[4];
        DEBUGMSG("mcp2515_extended_mask\n");
 
-#if 0
+// #if 0
        if (mcp2515_enable_configuration(chip))
                return -ENODEV;
 
-// LSB to +3, MSB to +0        
-       for(i=SJA_PeliCAN_AC_LEN; --i>=0;) {
-               can_write_reg(chip,code&0xff,SJAACR0+i);
-               can_write_reg(chip,mask&0xff,SJAAMR0+i);
-               code >>= 8;
-               mask >>= 8;
-       }
-
-       DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
-       DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
+       c_filter[0] = (code >> 3) & 0xFF;
+       c_filter[1] = ((code << 5) & 0xE0 ) | 1<<3 | ((code >> 16) & 0x03);
+       c_filter[2] = (code >> 8) & 0xFF;
+       c_filter[3] = (code) & 0xFF;
+       write_block(chip, MCP2515_RXF0SIDH, 4, c_filter);
+       write_block(chip, MCP2515_RXF2SIDH, 4, c_filter);
+       write_block(chip, MCP2515_RXF3SIDH, 4, c_filter);
+       write_block(chip, MCP2515_RXF4SIDH, 4, c_filter);
+       write_block(chip, MCP2515_RXF5SIDH, 4, c_filter);
+       c_filter[1] = ((code << 5) & 0xE0 ) | 0<<3 | ((code >> 16) & 0x03);
+       write_block(chip, MCP2515_RXF1SIDH, 4, c_filter);
+       c_mask[0] = (mask >> 3) & 0xFF;
+       c_mask[1] = ((mask << 5) & 0xE0 ) | ((mask >> 16) & 0x03);
+       c_mask[2] = (mask >> 8) & 0xFF;
+       c_mask[3] = (mask) & 0xFF;
+       write_block(chip, MCP2515_RXM0SIDH, 4, c_mask);
+       write_block(chip, MCP2515_RXM1SIDH, 4, c_mask);
+
+       CANMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
+       CANMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
+//     DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
+//     DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
 
        mcp2515_disable_configuration(chip);
-#endif
+// #endif
        return 0;
 }
 
@@ -632,7 +894,7 @@ int mcp2515_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw_in,
                        continue;
                }
                readreg = read_reg(chip, MCP2515_CNF3);
-               if (readreg & CNF3_PHSEG2_MASK != (u8)((ps2-1))){
+               if ((readreg & CNF3_PHSEG2_MASK) != (u8)((ps2-1))){
                        CANMSG("Wrong value in CNF3 - sent: 0x%X, received: 0x%X\n",(ps2-1) | brp,readreg & CNF3_PHSEG2_MASK);
                        continue;
                }
@@ -671,7 +933,7 @@ int mcp2515_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
        return 0;
 }
 
-#define MAX_TRANSMIT_WAIT_LOOPS 10
+#define MAX_TRANSMIT_WAIT_LOOPS 20
 /**
  * mcp2515_pre_write_config: - prepares message object for message transmission
  * @chip: pointer to chip state structure
@@ -716,32 +978,32 @@ int mcp2515_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
                return -EIO;
        }
 
-
-       frame.sidl = (msg->id << 5) || 
-               ((msg->flags & MSG_EXT) ? mcpEXIDE : 0) ||
-               ((msg->id >> 16) & mcpEID_MASK);
-       
        len = msg->length;
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
 
        if(msg->flags & MSG_EXT) {
-               frame.sidh = msg->id >> 21;
-               frame.sidl = (msg->id << 5) | ((msg->id >> 27) & 0x3) | mcpEXIDE;
-               frame.eid8 = msg->id >> 19;
-               frame.eid0 = 13;
+               frame.sidh = (msg->id >> 3) & 0xFF;
+               frame.sidl = ((msg->id << 5) | ((msg->id >> 27) & mcpEID_MASK) | mcpEXIDE) & 0xFF;
+               frame.eid8 = (msg->id >> 19) & 0xFF;
+               frame.eid0 = (msg->id >> 11) & 0xFF;
                frame.dlc = len | ((msg->flags & MSG_RTR) ? mcpRTR : 0);
                memcpy(frame.data, msg->data, len);
        }
        else {
-               frame.sidh = msg->id >> 21;
-               frame.sidl = (msg->id << 5) | ((msg->id >> 27) & 0x3);
-               frame.eid8 = msg->id >> 19;
-               frame.eid0 = 13;
+               frame.sidh = (msg->id >> 3) & 0xFF;
+               frame.sidl = ((msg->id << 5) | ((msg->id >> 27) & mcpEID_MASK)) & 0xFF;
+               frame.eid8 = (msg->id >> 19) & 0xFF;
+               frame.eid0 = (msg->id >> 11) & 0xFF;
                frame.dlc = len | ((msg->flags & MSG_RTR) ? mcpRTR : 0);
                memcpy(frame.data, msg->data, len);
        }
 
-       write_block(chip, MCP2515_TXB0SIDH, len+5, &frame);
+       if (obj == chip->msgobj[0])
+               write_block(chip, MCP2515_TXB0SIDH, len+5, &frame);
+       if (obj == chip->msgobj[1])
+               write_block(chip, MCP2515_TXB1SIDH, len+5, &frame);
+       if (obj == chip->msgobj[2])
+               write_block(chip, MCP2515_TXB2SIDH, len+5, &frame);
 
        can_spi_release_bus(chip);
 
@@ -765,7 +1027,21 @@ int mcp2515_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
        DEBUGMSG("mcp2515_send_msg\n");
 
        can_spi_acquire_bus(chip,1);    
-       bitmod_reg(chip, MCP2515_TXB0CTRL, mcpTXREQ, mcpTXREQ);
+#ifdef MCP2515_SPI_ASYNC
+       if (obj == chip->msgobj[0])
+               bitmod_reg_async(chip, MCP2515_TXB0CTRL, mcpTXREQ, mcpTXREQ, NOOP);
+       if (obj == chip->msgobj[1])
+               bitmod_reg_async(chip, MCP2515_TXB1CTRL, mcpTXREQ, mcpTXREQ, NOOP);
+       if (obj == chip->msgobj[2])
+               bitmod_reg_async(chip, MCP2515_TXB2CTRL, mcpTXREQ, mcpTXREQ, NOOP);
+#else
+       if (obj == chip->msgobj[0])
+               bitmod_reg(chip, MCP2515_TXB0CTRL, mcpTXREQ, mcpTXREQ);
+       if (obj == chip->msgobj[1])
+               bitmod_reg(chip, MCP2515_TXB1CTRL, mcpTXREQ, mcpTXREQ);
+       if (obj == chip->msgobj[2])
+               bitmod_reg(chip, MCP2515_TXB2CTRL, mcpTXREQ, mcpTXREQ);
+#endif
        can_spi_release_bus(chip);
 
        return 0;
@@ -869,13 +1145,22 @@ int mcp2515_attach_to_chip(struct canchip_t *chip)
 {
        DEBUGMSG("mcp2515_attach_to_chip\n");
        /* Initialize delayed interrupt processing */
+       mcp2515_wq = create_singlethread_workqueue("lincan_mcp2515");
+       if (mcp2515_wq == NULL)
+               return -1;
+       
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
        INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler), 
                  workqueue_handler, 
-                 NULL);
+                 &(((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
+       INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->txwq_handler), 
+                 txwq_handler, 
+                 &(((MCP2515_PRIV *)(chip->chip_data))->txwq_handler);
  #else
        INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler), 
                  workqueue_handler);
+       INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->txwq_handler), 
+                 txwq_handler);
  #endif
 
        tasklet_init(&(((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler),
@@ -902,8 +1187,9 @@ int mcp2515_release_chip(struct canchip_t *chip)
        
        chip->flags &= ~CHIP_ATTACHED;
        DEBUGMSG("Flush workqueue.\n");
+       cancel_delayed_work(&((MCP2515_PRIV *)(chip->chip_data))->txwq_handler);
        cancel_delayed_work(&((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
-       flush_scheduled_work();
+       flush_workqueue(mcp2515_wq);
 
        DEBUGMSG("Kill tasklets.\n");
        tasklet_kill(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
@@ -911,6 +1197,8 @@ int mcp2515_release_chip(struct canchip_t *chip)
        mcp2515_stop_chip(chip);
        can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
 #endif
+       destroy_workqueue(mcp2515_wq);
+
        return 0;
 }
 
@@ -994,11 +1282,17 @@ int mcp2515_irq_handler(int irq, struct canchip_t *chip)
        if (~chip->flags & CHIP_ATTACHED)
                return CANCHIP_IRQ_ACCEPTED;
        
+       if(can_spi_acquire_bus(chip, 0)){
+#ifdef MCP2515_SPI_ASYNC
+       /* let the SPI subsystem read interrupt status immediately - the response runs in callbacks */
+               read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+#else
        /* do work in tasklet if bus is immediately available */
-       if(can_spi_acquire_bus(chip, 0))
-               tasklet_schedule(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
+               tasklet_hi_schedule(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
+#endif /* MCP2515_SPI_ASYNC */
+       }
        else /* do work in workqueue */
-               schedule_work(&((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
+               queue_work(mcp2515_wq,&((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
 
        disable_irq(chip->chip_irq);
        return CANCHIP_IRQ_HANDLED;
@@ -1035,6 +1329,16 @@ int mcp2515_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
                        obj->tx_retry_cnt=0;
                        tx_handler(chip, obj);
                }
+               else{
+#ifdef MCP2515_SPI_ASYNC
+               /* let the SPI subsystem read interrupt status immediately - the response runs in callbacks */
+                       read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+#else
+               /* do work in tasklet if bus is immediately available */
+                       tasklet_hi_schedule(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
+#endif /* MCP2515_SPI_ASYNC */
+               }
+                       
                can_spi_release_bus(chip);      
 
                can_msgobj_clear_fl(obj,TX_LOCK);
@@ -1088,7 +1392,7 @@ int mcp2515_fill_chipspecops(struct canchip_t *chip)
 {
        DEBUGMSG("mcp2515_fill_chipspecops\n");
        chip->chip_type="mcp2515";
-       chip->max_objects=2;
+       chip->max_objects=3;
        mcp2515_register(chip->chipspecops);
        return 0;
 }
index 132d3cae9aff7b572b8ec12e09319aab48c8b56a..e6fb0d287b8d99bb730c8356906b15a1055eb2ac 100644 (file)
        #include <plat/dmtimer.h>       
 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
 
+static const char* omap2_spican_defaulttype = "mcp2515";
+
+static struct workqueue_struct *omap2_spican_wq;
+
 /*******************************************************************/
 /*
  * We can't use the standard synchronous wrappers for file I/O; we
  */
 static void omap2_spican_spi_complete(void *arg)
 {
+       DEBUGMSG("SPICAN sync: complete\n");
        complete(arg);
 }
 
-static ssize_t omap2_spican_spi_sync(struct candevice_t *candev, struct spi_message *message)
+ssize_t omap2_spican_spi_sync(struct candevice_t *candev, struct spi_message *message)
 {
        DECLARE_COMPLETION_ONSTACK(done);
-       struct omap2_spican_platform_data *pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
+       struct omap2_spican_platform_data *pdata;
        int status;
+       
+       if (candev == NULL)
+               return -ESHUTDOWN;
+       if (message == NULL)
+               panic("SPICAN: trying to send null pointered message");
 
+       pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
        if (pdata == NULL)
                return -ESHUTDOWN;
 
@@ -54,12 +65,17 @@ static ssize_t omap2_spican_spi_sync(struct candevice_t *candev, struct spi_mess
        spin_lock_irq(&pdata->spi_lock);
        if (pdata->spi == NULL)
                status = -ESHUTDOWN;
-       else
+       else{
+               DEBUGMSG("SPICAN sync: transfer\n");
                status = spi_async(pdata->spi, message);
+       }
        spin_unlock_irq(&pdata->spi_lock);
 
        if (status == 0) {
-               wait_for_completion(&done);
+               while (!wait_for_completion_interruptible_timeout(&done, msecs_to_jiffies(10))) { 
+                       DEBUGMSG("SPICAN sync: timeout 10 msecs\n");
+               }
+//             do { ;} while (wait_for_completion_interruptible(&done));
                status = message->status;
                if (status == 0)
                        status = message->actual_length;
@@ -89,34 +105,157 @@ static ssize_t omap2_spican_spi_transfer(struct candevice_t *candev,void *tx, vo
 
        spi_message_add_tail(&t, &m);
        status = omap2_spican_spi_sync(candev, &m);
-/*     struct spi_transfer     *t;
-       struct spi_message      m;
-       int i,status;
+       return status;
+}
 
+static void hi_async_tasklet_handler(unsigned long data)
+{
+       struct omap2_spican_platform_data *pdata=(struct omap2_spican_platform_data *)data;
+       int n;
+       
        if (pdata == NULL)
-               return -1;
-       if(len > SPI_BUF_LEN) panic("long CAN spi transfer: %u",len);
+               return;
 
-       spi_message_init(&m);
+       
+       do {
+               n = find_first_bit(pdata->hi_async_done_map,OMAP2_SPICAN_PRE_ASYNC);
+               if (n == OMAP2_SPICAN_PRE_ASYNC)
+                       break;
+
+               DEBUGMSG("SPICAN async %d: high priority tasklet\n",n);
+               if (pdata->async[n].complete)
+                       pdata->async[n].complete(pdata->async[n].data,pdata->async[n].count);
+               
+               clear_bit(n,pdata->hi_async_done_map);
+               clear_bit(n,pdata->async_req_map);
+       } while (n < OMAP2_SPICAN_PRE_ASYNC);
+}
+
+static void lo_async_workqueue_handler(struct work_struct *work)
+{
+       struct omap2_spican_platform_data *pdata = container_of(work,struct omap2_spican_platform_data,lo_async_workqueue);
+       struct omap2_spican_async_t *async;
+       int n;
+
+       if (pdata == NULL)
+               return;
+
+       do {
+               n = find_first_bit(pdata->lo_async_done_map,OMAP2_SPICAN_PRE_ASYNC);
+               if (n >= OMAP2_SPICAN_PRE_ASYNC)
+                       break;
+
+               DEBUGMSG("SPICAN async %d: low priority workqueue\n",n);
+               async = pdata->async + n;
+
+               if (async->complete)
+                       async->complete(async->data,async->count);
+               
+               clear_bit(n,pdata->lo_async_done_map);
+               clear_bit(n,pdata->async_req_map);
+       } while (n < OMAP2_SPICAN_PRE_ASYNC);
+}
 
-       t = can_checked_malloc(len * sizeof(struct spi_transfer));
-       for (i=0;i<len;i++){
-               (*(t+i)).tx_buf         = tx+i;
-               (*(t+i)).rx_buf         = rx+i;
-               (*(t+i)).len            = 1;
-               (*(t+i)).cs_change = 0;
-               (*(t+i)).delay_usecs = 0;
-               (*(t+i)).speed_hz = pdata->speed_hz;
-               (*(t+i)).bits_per_word = 8;
-               spi_message_add_tail(t+i, &m);
+static void omap2_spican_spi_async_complete(void *arg)
+{
+       struct omap2_spican_async_t *as = (struct omap2_spican_async_t *)arg;
+       struct omap2_spican_platform_data *pdata = container_of(as,struct omap2_spican_platform_data,async[as->bitmap_bit]);
+       int i;
+
+//     DEBUGMSG("SPICAN async: complete\n");
+       for (i=1;i<as->count;i++)
+               can_filltimestamp(&as->data[i].timestamp);              
+       // Serve the fast handlers ASAP
+       if ((as->fasthandler) && (as->complete)){
+//             DEBUGMSG("SPICAN async: fasthandler\n");
+/*             set_bit(as->bitmap_bit,pdata->hi_async_done_map);
+               tasklet_hi_schedule(&pdata->hi_async_tasklet);*/
+               if (as->complete){
+                       as->complete(as->data,as->count);
+               }
+               clear_bit(as->bitmap_bit,pdata->lo_async_done_map);
+               clear_bit(as->bitmap_bit,pdata->async_req_map);
+//             DEBUGMSG("SPICAN async: fasthandler done\n");
+               return;
        }
-       status = omap2_spican_spi_sync(candev, &m);
-       can_checked_free(t);*/
-       return status;
+       
+       DEBUGMSG("SPICAN async %d: slowhandler register\n",as->bitmap_bit);
+       set_bit(as->bitmap_bit,pdata->lo_async_done_map);
+       queue_work(omap2_spican_wq,&pdata->lo_async_workqueue);
 }
 
+ssize_t omap2_spican_spi_async_transfer(struct candevice_t *candev, void (*callback)(void *data), struct can_spi_async_t *data, uint8_t count, uint8_t fasthandler)
+{
+       struct omap2_spican_platform_data *pdata;
+       struct omap2_spican_async_t *async;
+       int status,i;
+       int n;
+       
+       if (candev == NULL)
+               return -ESHUTDOWN;
+
+       pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
+       if (pdata == NULL)
+               return -ESHUTDOWN;
+       
+       if (count > OMAP2_SPICAN_MAX_TRANSFERS)
+               return -ENOBUFS;
+
+       do {
+               n = find_first_zero_bit(pdata->async_req_map, OMAP2_SPICAN_PRE_ASYNC);
+               // There's no free transfer slot
+               if (n == OMAP2_SPICAN_PRE_ASYNC)
+                       return -ENOBUFS;
+       } while (test_and_set_bit(n,pdata->async_req_map));
+       
+       async = pdata->async+n;
+
+       memset(async,0,sizeof(struct omap2_spican_async_t));
+
+       for (i=0;i<count;i++){
+               if(data[i].len > SPI_MESSAGE_LENGTH)
+                       panic("too long CAN spi transfer: %u",data[i].len);
+       }
+
+       memcpy(async->data,data,count*sizeof(struct can_spi_async_t));
+       async->count = count;
+       async->bitmap_bit = n;
+       async->complete = callback;
+       async->fasthandler = fasthandler;
+
+       spi_message_init(&async->m);
+       
+       for (i=0;i<count;i++){
+               if ((async->data[i].tx_buf == NULL) && (async->data[i].rx_buf == NULL) && async->data[i].len != 0)
+                       panic("Trying to send NULL pointered buffers");
+               
+               async->t[i].tx_buf = async->data[i].tx_buf;
+               async->t[i].rx_buf = async->data[i].rx_buf;
+               async->t[i].len = async->data[i].len;
+               async->t[i].cs_change = 1;
+               async->t[i].speed_hz = pdata->speed_hz;
+               async->t[i].bits_per_word = 8;
+
+               spi_message_add_tail(&async->t[i], &async->m);
+       }
+       
+       async->m.complete = omap2_spican_spi_async_complete;
+       async->m.context = async;
+       spin_lock_irq(&pdata->spi_lock);
+       if (pdata->spi == NULL)
+               status = -ESHUTDOWN;
+       else{
+               DEBUGMSG("SPICAN async %d: transfer\n",n);
+               status = spi_async(pdata->spi, &async->m);
+       }
+       spin_unlock_irq(&pdata->spi_lock);
+       
+       if (status){
+               clear_bit(n,pdata->async_req_map);
+       }
 
-/// ---------------------- EVERYTHING'S DONE AFTER THIS POINT -----------------------------------------------
+       return status;
+}
 
 /**
  * omap2_spican_irq_handler: - GPT (general purpose timer) and waiting
@@ -135,14 +274,23 @@ static irqreturn_t omap2_spican_irq_handler(int irq, void *dev_id)
        int i;
        
        if (!dev_id)
-               return IRQ_HANDLED;
-
+               return IRQ_NONE;
+       
        pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
        if (!pdata)
-               return IRQ_HANDLED;
+               return IRQ_NONE;
        
+/*     if (((pdata->trigger == OMAP2_SPICAN_TRIG_GPT) && (irq != pdata->timer_irq))
+               || ((pdata->trigger == OMAP2_SPICAN_TRIG_IRQ) && (irq != pdata->irq))
+       )
+               return IRQ_NONE;*/
+       if ((irq != pdata->timer_irq) && (irq != pdata->irq))
+               return IRQ_NONE;
+       
+       DEBUGMSG("SPICAN: Got interrupt");
        #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
-       if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
+//     if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
+       if (irq == pdata->timer_irq){
                // reset the timer interrupt status
                omap_dm_timer_write_status(pdata->timer_ptr, OMAP_TIMER_INT_OVERFLOW);
                omap_dm_timer_read_status(pdata->timer_ptr); // YES, you really need to do this 'wasteful' read
@@ -293,7 +441,7 @@ int omap2_spican_init_chip_data(struct candevice_t *candev, int chipnr)
 
 int omap2_spican_register_chip_data(struct canchip_t *ch,void *data){
        struct omap2_spican_platform_data *pdata = (struct omap2_spican_platform_data *)data;
-       ch->clock = pdata->mcp2515_clk;
+       ch->clock = pdata->clk;
        ch->baudrate = pdata->baudrate;
        int ret = 0;
        
@@ -387,6 +535,7 @@ int omap2_spican_program_irq(struct candevice_t *candev)
 
 /*******************************************************************/
 int omap2_spican_spi_acquire_bus(struct candevice_t *candev, short channel, int block){
+       /* Subsystem is always ready to accept messages */
        return 1;
 }
 
@@ -409,6 +558,7 @@ int omap2_spican_register(struct hwspecops_t *hwspecops)
 
        // SPI specific functions
        hwspecops->spi_transfer = omap2_spican_spi_transfer;
+       hwspecops->spi_async_transfer = omap2_spican_spi_async_transfer;
        hwspecops->spi_acquire_bus = omap2_spican_spi_acquire_bus;
        hwspecops->spi_release_bus = omap2_spican_spi_release_bus;
 
@@ -419,37 +569,47 @@ int omap2_spican_register(struct hwspecops_t *hwspecops)
 
 static int omap2_spican_probe(struct spi_device *spi)
 {
-       struct omap2_spican_platform_data       *pdata = spi->dev.platform_data;
+       struct lincan_spican_platform_data      *spidata = spi->dev.platform_data;
+       struct omap2_spican_platform_data *pdata;
        struct candevice_t *dev;
        int allocated = 0;
-
-       static struct omap2_spican_platform_data mypdata;
-       static const char* omap2_spican_defaulttype = "mcp2515";
        
        DEBUGMSG("Starting probe for omap2_spican...\n");
        
        // Structure checks and initialization
-       if (pdata == NULL){
-/*             pdata = (struct omap2_spican_platform_data *)can_checked_malloc(sizeof(struct omap2_spican_platform_data));
-               if (pdata)
-                       memset(pdata,0,sizeof(struct omap2_spican_platform_data));
-               else
-                       return -ENOMEM;
-               allocated = 1;*/
-               pdata = &mypdata; // No need to free up
-               
+       pdata = (struct omap2_spican_platform_data *)can_checked_malloc(sizeof(struct omap2_spican_platform_data));
+       if (pdata)
+               memset(pdata,0,sizeof(struct omap2_spican_platform_data));
+       else
+               return -ENOMEM;
+       
+       if (spidata)
+               memcpy(pdata,spidata,sizeof(struct lincan_spican_platform_data));
+       else{
                if (!pdata->cs_change) pdata->cs_change = OMAP2_SPICAN_CS_CHANGE;
                if (!pdata->delay_usecs) pdata->delay_usecs = OMAP2_SPICAN_DELAY_USECS;
        }
-       if (!pdata->mcp2515_clk) pdata->mcp2515_clk = OMAP2_SPICAN_MCP_CLK;
+       if (!pdata->clk) pdata->clk = OMAP2_SPICAN_MCP_CLK;
        if (!pdata->baudrate) pdata->baudrate = OMAP2_SPICAN_BAUDRATE;
        if (!pdata->speed_hz) pdata->speed_hz = OMAP2_SPICAN_SPEED_HZ;
        if (!pdata->chiptype) pdata->chiptype = omap2_spican_defaulttype;
 
-       
        spin_lock_init(&pdata->spi_lock);
        pdata->spi = spi;
        pdata->trigger = 0;
+
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+       INIT_WORK(&pdata->lo_async_workqueue, 
+                 lo_async_workqueue_handler, 
+                 &pdata->lo_async_workqueue);
+ #else
+       INIT_WORK(&pdata->lo_async_workqueue, 
+                 lo_async_workqueue_handler);
+ #endif
+       tasklet_init(&pdata->hi_async_tasklet,
+                    hi_async_tasklet_handler, 
+                    (unsigned long)pdata);
+       
        if (spi->irq) {
                DEBUGMSG("Interrupt line number %d provided.\n",spi->irq);
                pdata->trigger = OMAP2_SPICAN_TRIG_IRQ;
@@ -466,9 +626,9 @@ static int omap2_spican_probe(struct spi_device *spi)
        if (pdata->trigger == OMAP2_SPICAN_TRIG_IRQ) {
                int status = 0;
                DEBUGMSG("Requesting interrupt line %d.\n",spi->irq);
-               status = set_irq_type(pdata->irq,IRQ_TYPE_EDGE_BOTH);
+               status = set_irq_type(pdata->irq,IRQ_TYPE_EDGE_FALLING);
                if(status){
-                       CANMSG("Setting low level trigger on irq %d failed.\n", spi->irq);
+                       CANMSG("Setting falling edge trigger on irq %d failed.\n", spi->irq);
                        goto release;
                }
                status = request_irq(pdata->irq, omap2_spican_irq_handler, IRQF_DISABLED , "omap2_spican", dev);
@@ -478,7 +638,8 @@ static int omap2_spican_probe(struct spi_device *spi)
                }
        }
 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
-       if (pdata->trigger == 0){
+//     if (pdata->trigger == 0){
+       {
                struct clk *gt_fclk;
                uint32_t gt_rate;
                int status = 0;
@@ -502,8 +663,8 @@ static int omap2_spican_probe(struct spi_device *spi)
                gt_rate = clk_get_rate(gt_fclk)/(1<<(prescaler+1));
         
                // set preload, and autoreload
-               // we set it to the clock rate in order to get 1 overflow every 10 usecs
-               omap_dm_timer_set_load(pdata->timer_ptr, 1, 0xFFFFFFFF - (uint32_t)(gt_rate / 100));
+               // we set it to the clock rate in order to get 1 overflow every 1 msec
+               omap_dm_timer_set_load(pdata->timer_ptr, 1, 0xFFFFFFFF - (uint32_t)(gt_rate / 1000));
 
                // Request for the irq
                pdata->timer_irq = omap_dm_timer_get_irq(pdata->timer_ptr);
@@ -517,25 +678,25 @@ static int omap2_spican_probe(struct spi_device *spi)
 
                // setup timer to trigger our IRQ on the overflow event
                omap_dm_timer_set_int_enable(pdata->timer_ptr, OMAP_TIMER_INT_OVERFLOW);
-               pdata->trigger = OMAP2_SPICAN_TRIG_GPT;
+//             pdata->trigger = OMAP2_SPICAN_TRIG_GPT;
        }
 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
 
        spi_set_drvdata(spi, dev);
 
 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
-                       if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
-                               // Everything's ready, let's roll!
-                               DEBUGMSG("Starting OMAP GPT\n");
-                               omap_dm_timer_start(pdata->timer_ptr);
-                       }
+//                     if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
+       {
+               // Everything's ready, let's roll!
+               DEBUGMSG("Starting OMAP GPT\n");
+               omap_dm_timer_start(pdata->timer_ptr);
+       }
 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
        DEBUGMSG("Device omap2_spican successfully configured. Have fun!\n");
        return 0;
        
 release:
-       if (allocated)
-               can_checked_free(pdata);
+       can_checked_free(pdata);
        return -ENODEV;
 }
 
@@ -549,7 +710,8 @@ static int omap2_spican_remove(struct spi_device *spi)
                free_irq(pdata->irq, candev);
        }
 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
-       if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
+//     if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
+       {
                DEBUGMSG("Stopping OMAP GPT\n");
                omap_dm_timer_stop(pdata->timer_ptr);
                // release the IRQ handler
@@ -561,6 +723,7 @@ static int omap2_spican_remove(struct spi_device *spi)
 
        DEBUGMSG("Removing omap2_spican from device structure...");
        //      make sure ops on existing fds can abort cleanly
+       deregister_hotplug_dev(candev);
        cleanup_hotplug_dev(candev);
 
        spin_lock_irq(&pdata->spi_lock);
@@ -569,6 +732,10 @@ static int omap2_spican_remove(struct spi_device *spi)
 //     candev->sysdevptr.anydev = NULL;
        spin_unlock_irq(&pdata->spi_lock);
 
+       DEBUGMSG("Kill tasklets.\n");
+       tasklet_kill(&pdata->hi_async_tasklet);
+
+       can_checked_free(pdata);
        DEBUGMSG(" done.\n");
 
        return 0;
@@ -586,11 +753,15 @@ static struct spi_driver omap2_spican_driver = {
 };
 
 int omap2_spican_init(void){
+       omap2_spican_wq = create_singlethread_workqueue("omap2_spican");
+       if (omap2_spican_wq == NULL)
+               return -1;
        return spi_register_driver(&omap2_spican_driver);
 }
 
 void omap2_spican_exit(void){
        spi_unregister_driver(&omap2_spican_driver);
+       destroy_workqueue(omap2_spican_wq);
 }
 
 #ifdef MODULE_ALIAS
index d378617b55359fdbe8f86caf3e7ebe85c6a5dc19..d20bac94ed99c7626459278efc0f1d637529ce89 100644 (file)
@@ -350,6 +350,7 @@ int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudr
        chip->write_register=candev->hwspecops->write_register;
        chip->read_register=candev->hwspecops->read_register;
        chip->spi_transfer=candev->hwspecops->spi_transfer;
+       chip->spi_async_transfer=candev->hwspecops->spi_async_transfer;
        chip->spi_acquire_bus=candev->hwspecops->spi_acquire_bus;
        chip->spi_release_bus=candev->hwspecops->spi_release_bus;