From 3cec91e940ca501534d28d6893bb80996ecd3206 Mon Sep 17 00:00:00 2001 From: "Ing. Jan Kriz" Date: Mon, 18 Apr 2011 10:37:32 +0200 Subject: [PATCH] Support for asynchronous SPI messages and callbacks --- lincan/include/main.h | 38 +++- lincan/include/mcp2515.h | 5 + lincan/include/omap2_spican.h | 42 +++- lincan/src/main.c | 5 +- lincan/src/mcp2515.c | 418 +++++++++++++++++++++++++++++----- lincan/src/omap2_spican.c | 287 ++++++++++++++++++----- lincan/src/setup.c | 1 + 7 files changed, 669 insertions(+), 127 deletions(-) diff --git a/lincan/include/main.h b/lincan/include/main.h index 23accfb..2c146ff 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -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) { diff --git a/lincan/include/mcp2515.h b/lincan/include/mcp2515.h index 00add4e..bad1cae 100644 --- a/lincan/include/mcp2515.h +++ b/lincan/include/mcp2515.h @@ -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; diff --git a/lincan/include/omap2_spican.h b/lincan/include/omap2_spican.h index c165a28..6fae401 100644 --- a/lincan/include/omap2_spican.h +++ b/lincan/include/omap2_spican.h @@ -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); diff --git a/lincan/src/main.c b/lincan/src/main.c index c5547af..34661f1 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -101,6 +101,7 @@ #include "../include/usbcan.h" #endif #if defined(CONFIG_OC_LINCAN_CARD_omap2_spican) + #include #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; } diff --git a/lincan/src/mcp2515.c b/lincan/src/mcp2515.c index 10e4c5f..51ff64b 100644 --- a/lincan/src/mcp2515.c +++ b/lincan/src/mcp2515.c @@ -15,8 +15,24 @@ #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 (ntxfree); + 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;isidl & 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; } diff --git a/lincan/src/omap2_spican.c b/lincan/src/omap2_spican.c index 132d3ca..e6fb0d2 100644 --- a/lincan/src/omap2_spican.c +++ b/lincan/src/omap2_spican.c @@ -30,6 +30,10 @@ #include #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 @@ -37,15 +41,22 @@ */ 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;ispeed_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;icount;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 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;idata[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 diff --git a/lincan/src/setup.c b/lincan/src/setup.c index d378617..d20bac9 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -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; -- 2.39.2