/* vxbFtcan.c - CAN driver */ /* * * This program is OPEN SOURCE software: you can redistribute it and/or modify it; * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <../src/hwif/h/vxbus/vxbAccess.h> #include "vxbFtcan.h" #undef FTCAN_DEBUG #ifdef FTCAN_DEBUG #define FTCAN_LOGMSG(fmt,p1,p2,p3,p4,p5,p6) logMsg(fmt,p1,p2,p3,p4,p5,p6) #else #define FTCAN_LOGMSG(fmt,p1,p2,p3,p4,p5,p6) #endif /* VxBus methods */ LOCAL void ftCanInstInit (VXB_DEVICE_ID); LOCAL void ftCanInstInit2 (VXB_DEVICE_ID); LOCAL void ftCanInstConnect (VXB_DEVICE_ID); LOCAL void ftCanInt (FTCAN_DRV_CTRL *pDrvCtrl); LOCAL void ftCanRecvTask(FTCAN_DRV_CTRL * pDrvCtrl); LOCAL int ftcan_set_bittiming(VXB_DEVICE_ID pDev,struct can_bittiming *bt); LOCAL int can_calc_bittiming( struct can_bittiming *bt,const struct can_bittiming_const *btc); /* END functions */ LOCAL struct drvBusFuncs ftCanFuncs = { ftCanInstInit, /* devInstanceInit */ ftCanInstInit2, /* devInstanceInit2 */ ftCanInstConnect /* devConnect */ }; LOCAL device_method_t ftCan_methods[] = { { 0, 0} }; LOCAL struct vxbDevRegInfo ftCanDevPlbRegistration = { NULL, /* pNext */ VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_PLB, /* busID = PLB */ VXB_VER_4_0_0, /* vxbVersion */ "ftCan", /* drvName */ &ftCanFuncs, /* pDrvBusFuncs */ NULL, /* pMethods */ NULL, /* devProbe */ NULL /* pParamDefaults */ }; LOCAL VXB_DEVICE_ID glftCanDev[CAN_MAX_CTL]; #ifdef __DCC__ LOCAL const struct can_bittiming_const ftcan_bittiming_const = { "vxbftCan", 1, 16, 1, 8, 4, 1, 512, 2 }; #else LOCAL const struct can_bittiming_const ftcan_bittiming_const = { .name = "vxbftCan", .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 512, .brp_inc = 2, }; #endif /***************************************************************************** * *vxbFtCanRegister - register with the VxBus subsystem * * This routine registers the Template driver with VxBus as a * child of the PCI bus type. * * RETURNS: N/A * * ERRNO: N/A */ void vxbFtCanRegister(void) { vxbDevRegister((struct vxbDevRegInfo *)&ftCanDevPlbRegistration); return; } /***************************************************************************** * * ftCanInstInit - VxBus instInit handler * * This function implements the VxBus instInit handler for an template * device instance. The only thing done here is to select a unit * number for the device. * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftCanInstInit ( VXB_DEVICE_ID pDev ) { FTCAN_DRV_CTRL * pDrvCtrl; HCF_DEVICE * pHcf; /* get the HCF device from the instance ID */ pHcf = hcfDeviceGet (pDev); /* if pHcf is NULL, no device is present in hwconf.c */ if (pHcf == NULL) return; /* allocate memory for the data */ pDrvCtrl = (FTCAN_DRV_CTRL *)hwMemAlloc (sizeof(FTCAN_DRV_CTRL)); if (pDrvCtrl == NULL) return; bzero((char *)pDrvCtrl, sizeof(FTCAN_DRV_CTRL)); pDrvCtrl->ftCanDev = pDev; if (devResourceGet (pHcf, "regBase", HCF_RES_INT, (void *)&pDrvCtrl->ftCanRegbase) != OK) { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif return; } if (devResourceGet (pHcf, "irq", HCF_RES_INT, (void *)&pDrvCtrl->irq) != OK) { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif return; } if (devResourceGet (pHcf, "bitrate", HCF_RES_INT, (void *)&pDrvCtrl->ftcan_bittiming.bitrate) != OK) { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif return; } pDev->pDrvCtrl = pDrvCtrl; vxbRegMap(pDev, 0, &pDrvCtrl->ftCanHandle); glftCanDev[pDev->unitNumber]= pDev; return; } /***************************************************************************** * * ftCanInstInit2 - VxBus instInit2 handler * * This function implements the VxBus instInit2 handler for an template * device instance. Once we reach this stage of initialization, it's * safe for us to allocate memory, so we can create our pDrvCtrl * structure and do some initial hardware setup. The important * steps we do here are to create a child miiBus instance, connect * our ISR to our assigned interrupt vector, read the station * address from the EEPROM, and set up our vxbDma tags and memory * regions. We need to allocate a 64K region for the RX DMA window * here. * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftCanInstInit2 ( VXB_DEVICE_ID pDev ) { FTCAN_DRV_CTRL *pDrvCtrl; UINT is_config_mode=0; struct can_bittiming bt; int ret; pDrvCtrl = (FTCAN_DRV_CTRL *)pDev->pDrvCtrl;; if ((pDrvCtrl->ftcanQueue = msgQCreate(FTCAN_QUEUE_SIZE, VXB_FTCAN_MSG_SIZE, MSG_Q_FIFO)) == NULL) { FTCAN_LOGMSG(" Unable to create FT CAN message queue\n", 0,0,0,0,0,0); return; } if ((pDrvCtrl->canTxSem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY)) == NULL) { FTCAN_LOGMSG(" Unable to create FT CAN Tx Sem\n", 0,0,0,0,0,0); return; } is_config_mode = CSR_READ_4(pDev,FTCAN_CTRL_OFFSET); if (is_config_mode&FTCAN_CTRL_XFER_MASK) { FTCAN_LOGMSG("FT can is not in configration mode\n",1,2,3,4,5,6); return; } CSR_WRITE_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6));/*bit 6 is internal reset**/ CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_AIME_MASK); CSR_WRITE_4(pDev, FTCAN_ACC_ID0_MASK_OFFSET, FTCAN_ACC_IDN_MASK); CSR_WRITE_4(pDev, FTCAN_ACC_ID1_MASK_OFFSET, FTCAN_ACC_IDN_MASK); CSR_WRITE_4(pDev, FTCAN_ACC_ID2_MASK_OFFSET, FTCAN_ACC_IDN_MASK); CSR_WRITE_4(pDev, FTCAN_ACC_ID3_MASK_OFFSET, FTCAN_ACC_IDN_MASK); CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6)); bt.bitrate = pDrvCtrl->ftcan_bittiming.bitrate; bt.sjw = 0; bt.sample_point = 0; ret = can_calc_bittiming(&bt,&ftcan_bittiming_const); if(ret<0){ FTCAN_LOGMSG("can_calc_bittiming error\n",1,2,3,4,5,6); return ; } if (ftcan_set_bittiming(pDev,&bt)) { FTCAN_LOGMSG("ftcan_set_bittiming error\n",1,2,3,4,5,6); return ; } pDrvCtrl->ftcan_bittiming.brp=bt.brp; pDrvCtrl->ftcan_bittiming.sjw=bt.sjw; pDrvCtrl->ftcan_bittiming.tq =bt.tq; pDrvCtrl->ftcan_bittiming.phase_seg1= bt.phase_seg1; pDrvCtrl->ftcan_bittiming.phase_seg2= bt.phase_seg2; pDrvCtrl->ftcan_bittiming.sample_point=bt.sample_point; pDrvCtrl->txCfMax = FTCAN_TX_FIFO_MAX/FTCAN_FIFOFRAME_SIZE; pDrvCtrl->txCfCnt = 0; } LOCAL unsigned int div64_32(unsigned long long *n, unsigned int base) { unsigned long long rem = *n; unsigned long long b = base; unsigned long long res, d = 1; unsigned int high = rem >> 32; /* Reduce the thing a bit first */ res = 0; if (high >= base) { high /= base; res = (unsigned long long) high << 32; rem -= (unsigned long long) (high*base) << 32; } while ((unsigned long long)b > 0 && b < rem) { b = b+b; d = d+d; } do { if (rem >= b) { rem -= b; res += d; } b >>= 1; d >>= 1; } while (d); *n = res; return rem; } /***************************************************************************** * * can_update_sample_point - Bit-timing calculation * * Calculates proper bit-timing parameters for a specified bit-rate * and sample-point, which can then be used to set the bit-timing * registers of the CAN controller. * * RETURNS: sample point * * ERRNO: N/A */ LOCAL int can_update_sample_point( const struct can_bittiming_const *btc, unsigned int sample_point_nominal, unsigned int tseg, unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, unsigned int *sample_point_error_ptr) { unsigned int sample_point_error, best_sample_point_error = UINT_MAX; unsigned int sample_point, best_sample_point = 0; unsigned int tseg1, tseg2; int i; for (i = 0; i <= 1; i++) { tseg2 = tseg + CAN_CALC_SYNC_SEG - (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i; tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); tseg1 = tseg - tseg2; if (tseg1 > btc->tseg1_max) { tseg1 = btc->tseg1_max; tseg2 = tseg - tseg1; } sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG); sample_point_error = abs(sample_point_nominal - sample_point); if ((sample_point <= sample_point_nominal) && (sample_point_error < best_sample_point_error)) { best_sample_point = sample_point; best_sample_point_error = sample_point_error; *tseg1_ptr = tseg1; *tseg2_ptr = tseg2; } } if (sample_point_error_ptr) *sample_point_error_ptr = best_sample_point_error; return best_sample_point; } /***************************************************************************** * * can_calc_bittiming - Bit-timing calculation * * Calculates proper bit-timing parameters for a specified bit-rate * and sample-point, which can then be used to set the bit-timing * registers of the CAN controller. * * RETURNS: 0 on success and failure value on error * * ERRNO: N/A */ LOCAL int can_calc_bittiming( struct can_bittiming *bt, const struct can_bittiming_const *btc) { unsigned int bitrate; /* current bitrate */ unsigned int bitrate_error; /* difference between current and nominal value */ unsigned int best_bitrate_error = UINT_MAX; unsigned int sample_point_error; /* difference between current and nominal value */ unsigned int best_sample_point_error = UINT_MAX; unsigned int sample_point_nominal; /* nominal sample point */ unsigned int best_tseg = 0; /* current best value for tseg */ unsigned int best_brp = 0; /* current best value for brp */ unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; unsigned long long v64; /* Use CiA recommended sample points */ if (bt->sample_point) { sample_point_nominal = bt->sample_point; } else { if (bt->bitrate > 800000) sample_point_nominal = 750; else if (bt->bitrate > 500000) sample_point_nominal = 800; else sample_point_nominal = 875; } /* tseg even = round down, odd = round up */ for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { tsegall = CAN_CALC_SYNC_SEG + tseg / 2; /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ brp = CAN_CLK_FREQ / (tsegall * bt->bitrate) + tseg % 2; /* choose brp step which is possible in system */ brp = (brp / btc->brp_inc) * btc->brp_inc; if ((brp < btc->brp_min) || (brp > btc->brp_max)) continue; bitrate = CAN_CLK_FREQ / (brp * tsegall); bitrate_error = abs(bt->bitrate - bitrate); /* tseg brp biterror */ if (bitrate_error > best_bitrate_error) continue; /* reset sample point error if we have a better bitrate */ if (bitrate_error < best_bitrate_error) best_sample_point_error = UINT_MAX; can_update_sample_point(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error); if (sample_point_error > best_sample_point_error) continue; best_sample_point_error = sample_point_error; best_bitrate_error = bitrate_error; best_tseg = tseg / 2; best_brp = brp; if (bitrate_error == 0 && sample_point_error == 0) break; } if (best_bitrate_error) { /* Error in one-tenth of a percent */ v64 = (unsigned long long)best_bitrate_error * 1000; div64_32(&v64, bt->bitrate); bitrate_error = (unsigned int)v64; if (bitrate_error > CAN_CALC_MAX_ERROR) { FTCAN_LOGMSG("bitrate error %d.%d%% too high\n", bitrate_error / 10, bitrate_error % 10,3,4,5,6); return -EDOM; } FTCAN_LOGMSG( "bitrate error %d.%d%%\n", bitrate_error / 10, bitrate_error % 10,3,4,5,6); } /* real sample point */ bt->sample_point = can_update_sample_point(btc, sample_point_nominal, best_tseg, &tseg1, &tseg2, NULL); v64 = (unsigned long long)best_brp * 1000 * 1000 * 1000; div64_32(&v64, CAN_CLK_FREQ); bt->tq = (unsigned long long)v64; bt->prop_seg = tseg1 / 2; bt->phase_seg1 = tseg1 - bt->prop_seg; bt->phase_seg2 = tseg2; /* check for sjw user settings */ if (!bt->sjw || !btc->sjw_max) { bt->sjw = 1; } else { /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ if (bt->sjw > btc->sjw_max) bt->sjw = btc->sjw_max; /* bt->sjw must not be higher than tseg2 */ if (tseg2 < bt->sjw) bt->sjw = tseg2; } bt->brp = best_brp; /* real bitrate */ bt->bitrate = CAN_CLK_FREQ / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2)); return 0; } /***************************************************************************** * * ftcan_set_bittiming - CAN set bit timing routine * * This is the driver set bittiming routine. * * RETURNS: 0 on success and failure value on error * * ERRNO: N/A */ LOCAL int ftcan_set_bittiming(VXB_DEVICE_ID pDev,struct can_bittiming *bt) { UINT btr; UINT is_config_mode; /* Setting Baud Rate prescalar value in BRPR Register */ btr = (bt->brp - 1) << 16; /* Setting Time Segment 1 in BTR Register */ btr |= (bt->prop_seg - 1) << 2; btr |= (bt->phase_seg1 - 1) << 5; /* Setting Time Segment 2 in BTR Register */ btr |= (bt->phase_seg2 - 1) << 8; /* Setting Synchronous jump width in BTR Register */ btr |= (bt->sjw - 1); FTCAN_LOGMSG("%s:Update Can btr:0x%x \n", __func__, btr,3,4,5,6); /* Check whether FT2000/4 CAN is in configuration mode. * It cannot set bit timing if FT2000/4 CAN is not in configuration mode. */ is_config_mode = (CSR_READ_4(pDev, FTCAN_CTRL_OFFSET) & FTCAN_CTRL_XFER_MASK); if (is_config_mode) { /*Disable Transfer*/ CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); } CSR_WRITE_4(pDev, FTCAN_DAT_RATE_CTRL_OFFSET, btr); CSR_WRITE_4(pDev, FTCAN_ARB_RATE_CTRL_OFFSET, btr); /*Enable Transfer*/ CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); FTCAN_LOGMSG( "DAT=0x%08x, ARB=0x%08x\n", CSR_READ_4(pDev, FTCAN_DAT_RATE_CTRL_OFFSET), CSR_READ_4(pDev, FTCAN_ARB_RATE_CTRL_OFFSET),3,4,5,6); return 0; } /***************************************************************************** * * ftcan_err_interrupt - error frame Isr * * This is the CAN error interrupt and it will * check the the type of error * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftcan_err_interrupt(VXB_DEVICE_ID pDev, UINT isr) { UINT txerr = 0, rxerr = 0; rxerr = CSR_READ_4(pDev, FTCAN_ERR_CNT_OFFSET) & FTCAN_ERR_CNT_RFN_MASK; txerr = ((CSR_READ_4(pDev, FTCAN_ERR_CNT_OFFSET) & FTCAN_ERR_CNT_TFN_MASK) >> FTCAN_ERR_CNT_TFN_SHIFT); FTCAN_LOGMSG("%s: rx error count %d, tx error count %d\n", __func__, rxerr,txerr,4,5,6); FTCAN_LOGMSG("%s: error status register:0x%x\n", __func__, (CSR_READ_4(pDev,FTCAN_INTR_OFFSET) & FTCAN_INTR_STATUS_MASK),3,4,5,6); } /***************************************************************************** * * ftcan_tx_interrupt - Tx Done Isr * * This is the CAN Tx Done interrupt * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftcan_tx_interrupt(VXB_DEVICE_ID pDev, UINT isr) { FTCAN_DRV_CTRL * pFtCanCtrl; pFtCanCtrl = pDev->pDrvCtrl; CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_TEIC_MASK | FTCAN_INTR_REIC_MASK); pFtCanCtrl->txCfCnt--; if(pFtCanCtrl->txCfCnt != 0){ CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK); CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); } else{ if (semGive (pFtCanCtrl->canTxSem) == ERROR) { FTCAN_LOGMSG ("semGive error\n", 0, 0, 0, 0, 0, 0); } } } /***************************************************************************** * * ftcan_rx_interrupt - Rx Done Isr * * This is the CAN Rx Done interrupt * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftcan_rx_interrupt(FTCAN_DRV_CTRL* pDrvCtrl, UINT isr) { UINT id_ftcan,data[2] = {0, 0}; UINT dlc = 0; FTCAN_FRAME ftCanFrame; VXB_DEVICE_ID pDev; pDev= pDrvCtrl->ftCanDev; while((CSR_READ_4(pDev, FTCAN_FIFO_CNT_OFFSET)&0x3f) > 0) { /* Read a frame from FT2000/4 CAN */ id_ftcan = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET); id_ftcan = be32_to_cpup(id_ftcan); /* Change FT2000/4 CAN ID format to socketCAN ID format */ if (id_ftcan & FTCAN_IDR_IDE_MASK) { /* The received frame is an Extended format frame */ dlc = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET); dlc = be32_to_cpup(dlc); dlc = ((dlc & FTCAN_IDR_EDLC_MASK ) >> FTCAN_IDR_EDLC_SHIFT); ftCanFrame.can_id = (id_ftcan & FTCAN_IDR_ID1_MASK) >> 3; ftCanFrame.can_id |= (id_ftcan & FTCAN_IDR_ID2_MASK) >> FTCAN_IDR_ID2_SHIFT; ftCanFrame.can_id |= CAN_EFF_FLAG; if (id_ftcan & FTCAN_IDR_RTR_MASK) ftCanFrame.can_id |= CAN_RTR_FLAG; } else { dlc = ((id_ftcan & FTCAN_IDR_DLC_MASK ) >> FTCAN_IDR_SDLC_SHIFT); /* The received frame is a standard format frame */ ftCanFrame.can_id = (id_ftcan & FTCAN_IDR_ID1_MASK) >> FTCAN_IDR_ID1_SHIFT; if (id_ftcan & FTCAN_IDR_SRR_MASK) ftCanFrame.can_id |= CAN_RTR_FLAG; } /* Change FT2000/4 CAN data length format to socketCAN data format */ ftCanFrame.can_dlc = get_can_dlc(dlc); if (!(ftCanFrame.can_id & CAN_RTR_FLAG)) { /* Change FT2000/4 CAN data format to socketCAN data format */ if (ftCanFrame.can_dlc > 0){ data[0] = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET); *(UINT *)(ftCanFrame.data) = (data[0]); } if (ftCanFrame.can_dlc > 4){ data[1] = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET); *(UINT *)(ftCanFrame.data + 4) = (data[1]); } } FTCAN_LOGMSG("recevied canid %x can_dlc %d data 0x%2x 0x%2x 0x%2x 0x%2x ", ftCanFrame.can_id & CAN_EFF_MASK,ftCanFrame.can_dlc, ftCanFrame.data[0],ftCanFrame.data[1],ftCanFrame.data[2], ftCanFrame.data[3]); FTCAN_LOGMSG("0x%2x 0x%2x 0x%2x 0x%2x\r\n",ftCanFrame.data[4], ftCanFrame.data[5],ftCanFrame.data[6],ftCanFrame.data[7],5,6); msgQSend(pDrvCtrl->ftcanQueue,(char * )&ftCanFrame,sizeof(ftCanFrame),NO_WAIT,MSG_PRI_NORMAL); } } /***************************************************************************** * * ftCanInt - VxBus interrupt handler * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftCanInt (FTCAN_DRV_CTRL* pDrvCtrl) { VXB_DEVICE_ID pDev; UINT isr; pDev = pDrvCtrl->ftCanDev; /* Get the interrupt status from FT2000/4 CAN */ isr = (CSR_READ_4(pDev, FTCAN_INTR_OFFSET) & FTCAN_INTR_STATUS_MASK); if (!isr) return; /*Check for Tx interrupt and Processing it */ if ((isr & FTCAN_INTR_TEIS_MASK)){ isr &= (~FTCAN_INTR_REIS_MASK); ftcan_tx_interrupt(pDev, isr); } /* Check for the type of error interrupt and Processing it */ if (isr & (FTCAN_INTR_EIS_MASK | FTCAN_INTR_RFIS_MASK | FTCAN_INTR_BOIS_MASK | FTCAN_INTR_PEIS_MASK | FTCAN_INTR_PWIS_MASK)) { CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, (FTCAN_INTR_EIC_MASK | FTCAN_INTR_RFIC_MASK | FTCAN_INTR_BOIC_MASK | FTCAN_INTR_PEIC_MASK | FTCAN_INTR_PWIC_MASK)); ftcan_err_interrupt(pDev, isr); } /* Check for the type of receive interrupt and Processing it */ if (isr & (FTCAN_INTR_REIS_MASK)) { CSR_CLRBIT_4(pDev, FTCAN_INTR_OFFSET,FTCAN_INTR_REIE_MASK); ftcan_rx_interrupt(pDrvCtrl,isr); CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_REIC_MASK); CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_REIE_MASK); } return; } /***************************************************************************** * * ftCanInstConnect - VxBus instConnect handler * * This function implements the VxBus instConnect handler for an template * device instance. * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftCanInstConnect ( VXB_DEVICE_ID pDev ) { int st; FTCAN_DRV_CTRL * pFtCanCtrl; char task_name[32]; TASK_ID tid; pFtCanCtrl = pDev->pDrvCtrl; bzero(task_name, sizeof(task_name)); sprintf(task_name, "tCanRx%d", pDev->unitNumber); tid = taskSpawn(task_name, 100, 0, 0x20000, (FUNCPTR) ftCanRecvTask,(_Vx_usr_arg_t) pFtCanCtrl, 2,3,4,5,6,7,8,9,10); if(TASK_ID_ERROR == tid) { FTCAN_LOGMSG("failed to spawn can recv task!\n",1,2,3,4,5,6); return; } /* * Attach our ISR. For PCI, the index value is always * 0, since the PCI bus controller dynamically sets * up interrupts for us. */ st = vxbIntConnect (pDev, 0, ftCanInt, pFtCanCtrl); st |= vxbIntEnable (pDev, 0, ftCanInt, pFtCanCtrl); if(st != OK) { FTCAN_LOGMSG("interrupt cn/en failed!\n",1,2,3,4,5,6); return; } /* Enable interrupts */ CSR_WRITE_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_EN); /*Enable Transfer*/ CSR_WRITE_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); FTCAN_LOGMSG("status:#x%08x\n",CSR_READ_4(pDev,FTCAN_XFER_STS_OFFSET),2,3,4,5,6); return; } /***************************************************************************** * * ftcan_send_txfifo - Write the Frame to CAN TX FIFO * * Write the Frame to CAN TX FIFO * * RETURNS: Sent frame number * * ERRNO: N/A */ LOCAL unsigned int ftcan_send_txfifo(VXB_DEVICE_ID pDev, struct can_frame *df) { struct can_frame *cf = df; UINT id, dlc, frame_head[2] = {0, 0}, data[8] = {0, 0}; /* Watch carefully on the bit sequence */ if (cf->can_id & CAN_EFF_FLAG) { /* Extended CAN ID format */ id = ((cf->can_id & CAN_EFF_MASK) << FTCAN_IDR_ID2_SHIFT) & FTCAN_IDR_ID2_MASK; id |= (((cf->can_id & CAN_EFF_MASK) >> (CAN_EFF_ID_BITS-CAN_SFF_ID_BITS)) << FTCAN_IDR_ID1_SHIFT) & FTCAN_IDR_ID1_MASK; id |= FTCAN_IDR_IDE_MASK | FTCAN_IDR_SRR_MASK; if (cf->can_id & CAN_RTR_FLAG) /* Extended frames remote TX request */ id |= FTCAN_IDR_RTR_MASK; dlc = cf->can_dlc << FTCAN_IDR_EDLC_SHIFT; frame_head[0] = cpu_to_be32p(id); frame_head[1] = cpu_to_be32p(dlc); /* Write the Frame to FT2000/4 CAN TX FIFO */ CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, frame_head[0]); CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, frame_head[1]); } else { /* Standard CAN ID format */ id = ((cf->can_id & CAN_SFF_MASK) << FTCAN_IDR_ID1_SHIFT) & FTCAN_IDR_ID1_MASK; if (cf->can_id & CAN_RTR_FLAG) /* Standard frames remote TX request */ id |= FTCAN_IDR_SRR_MASK; dlc = ((cf->can_dlc << FTCAN_IDR_SDLC_SHIFT) | FTCAN_IDR_PAD_MASK); id |= dlc; frame_head[0] = cpu_to_be32p(id); /* Write the Frame to CAN TX FIFO */ CSR_WRITE_4(pDev,FTCAN_TX_FIFO_OFFSET, frame_head[0]); } if (!(cf->can_id & CAN_RTR_FLAG)) { if (cf->can_dlc > 0){ data[0] = (*(UINT*)(cf->data + 0)); CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, data[0]); } if (cf->can_dlc > 4){ data[1] = (*(UINT*)(cf->data + 4)); CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, data[1]); } } return 1; } /***************************************************************************** * * ftcan_write - Sending the CAN data * * RETURNS: Sent frame number * * ERRNO: N/A */ LOCAL UINT ftcan_write(VXB_DEVICE_ID pDev, char *buf, size_t len) { FTCAN_DRV_CTRL * pFtCanCtrl; struct can_frame *ftCanFrame; UINT frameNum,frameLeft,sendNumOnce,i; pFtCanCtrl = pDev->pDrvCtrl; if(buf == NULL) { FTCAN_LOGMSG("Send Buff is NULL.\r\n", 1,2,3,4,5,6); return 0; } if(len%sizeof(struct can_frame)) { FTCAN_LOGMSG("Lenth is invalid\n",1,2,3,4,5,6); return 0; } frameNum = len/sizeof(struct can_frame); for(frameLeft = frameNum; frameLeft > 0; ) { if(frameLeft/pFtCanCtrl->txCfMax >= 1) { sendNumOnce = pFtCanCtrl->txCfMax; frameLeft -= pFtCanCtrl->txCfMax; } else { sendNumOnce = frameLeft; frameLeft = 0; } /*shut down tranmission*/ CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK); CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); for(i=0;itxCfCnt = sendNumOnce; /* triggers tranmission */ CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK); CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK); CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK|FTCAN_CTRL_XFER_MASK); if (semTake (pFtCanCtrl->canTxSem, WAIT_FOREVER) == ERROR) { FTCAN_LOGMSG ("SemTake Error\n",1 ,2, 3, 4, 5, 6); } } return frameNum; } /***************************************************************************** * * ftCanSend - send can msg. API function. * * This function is used to send data * * RETURNS: OK/ERROR * * ERRNO: N/A */ STATUS ftCanSend ( unsigned char ctlNo, char * sendbuff, int lenth ) { VXB_DEVICE_ID pDev; UINT sentLenth; if(ctlNo >= CAN_MAX_CTL) { printf("ctlNo %d is invalid.\r\n", ctlNo); return ERROR; } pDev= glftCanDev[ctlNo]; if(pDev == NULL) { printf("pDev is NULL!\r\n"); return ERROR; } sentLenth = ftcan_write(pDev,sendbuff,lenth); if (sentLenth > 0) { return OK; } else { return ERROR; } } /***************************************************************************** * * ftCanRecvCallback - receive callback * * Registers the receive processing function for the specified CAN controller * ftCanRecvRtn:The pointer function of the receiving process * * RETURNS: OK/ERROR * * ERRNO: N/A */ STATUS ftCanRecvCallback ( unsigned char ctlNo, void (*ftCanRecvRtn)(FTCAN_FRAME* pFtCanFrame) ) { VXB_DEVICE_ID pDev; FTCAN_DRV_CTRL * pDrvCtrl; if(ctlNo >= CAN_MAX_CTL) { FTCAN_LOGMSG("ctlNo %d is invalid.\r\n", ctlNo,2,3,4,5,6); return ERROR; } pDev= glftCanDev[ctlNo]; if(pDev == NULL) { FTCAN_LOGMSG("pDev is NULL!\r\n",1,2,3,4,5,6); return ERROR; } pDrvCtrl = (FTCAN_DRV_CTRL * )pDev->pDrvCtrl; if(pDrvCtrl == NULL) { FTCAN_LOGMSG("pDrvCtrl is NULL for %d!\r\n", pDev->unitNumber,2,3,4,5,6); return ERROR; } pDrvCtrl->ftCanRecvRtn = ftCanRecvRtn; return OK; } /***************************************************************************** * * ftCanSetBitrate - set bitrate * * This function Set Bitrate for can * * RETURNS: OK/ERROR * * ERRNO: N/A */ STATUS ftCanSetBitrate ( unsigned char ctlNo, UINT bitrate ) { VXB_DEVICE_ID pDev; struct can_bittiming bt; int ret; FTCAN_DRV_CTRL * pDrvCtrl; pDev= glftCanDev[ctlNo]; pDrvCtrl= pDev->pDrvCtrl; bt.bitrate = bitrate; bt.sjw = 0; bt.sample_point = 0; ret = can_calc_bittiming(&bt,&ftcan_bittiming_const); if(ret<0){ return -ret; } if (ftcan_set_bittiming(pDev,&bt)) { return -EFAULT; } pDrvCtrl->ftcan_bittiming.bitrate = bitrate; pDrvCtrl->ftcan_bittiming.brp=bt.brp; pDrvCtrl->ftcan_bittiming.sjw=bt.sjw; pDrvCtrl->ftcan_bittiming.tq =bt.tq; pDrvCtrl->ftcan_bittiming.phase_seg1= bt.phase_seg1; pDrvCtrl->ftcan_bittiming.phase_seg2= bt.phase_seg2; pDrvCtrl->ftcan_bittiming.sample_point=bt.sample_point; return OK; } /***************************************************************************** * * ftCanSetIDFilter - set id filter * * This function Set set id filter for can * * RETURNS: OK/ERROR * * ERRNO: N/A */ STATUS ftCanSetIDFilter ( unsigned char ctlNo, UINT filterNo, UINT id, UINT mask, UINT type ) { VXB_DEVICE_ID pDev; UINT32 idRegOffset[4] = {FTCAN_ACC_ID0_OFFSET, FTCAN_ACC_ID1_OFFSET, FTCAN_ACC_ID2_OFFSET, FTCAN_ACC_ID3_OFFSET}; UINT32 maskRegOffset[4] = {FTCAN_ACC_ID0_MASK_OFFSET, FTCAN_ACC_ID1_MASK_OFFSET, FTCAN_ACC_ID2_MASK_OFFSET, FTCAN_ACC_ID3_MASK_OFFSET} ; pDev= glftCanDev[ctlNo]; CSR_WRITE_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6));/*bit 6 is internal reset**/ if(type == STANDARD_FRAME) { id = id << FTCAN_ACC_IDN_SHIFT; mask = mask << FTCAN_ACC_IDN_SHIFT; } CSR_WRITE_4(pDev, idRegOffset[filterNo], id); CSR_WRITE_4(pDev, maskRegOffset[filterNo], mask); CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6)); CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK | FTCAN_CTRL_AIME_MASK); return OK; } /***************************************************************************** * * ftCanRecvTask - Receiving work * * This function receives data * printf : canid,can_dlc,data. * RETURNS: N/A * * ERRNO: N/A */ LOCAL void ftCanRecvTask ( FTCAN_DRV_CTRL * pDrvCtrl ) { FTCAN_FRAME ftCanFrame; UINT maxNBytes = sizeof(ftCanFrame); ULONG cnt = 1; for(;;) { bzero((char *)&ftCanFrame, sizeof(ftCanFrame)); msgQReceive(pDrvCtrl->ftcanQueue,(char *)&ftCanFrame,maxNBytes,WAIT_FOREVER); if(pDrvCtrl->ftCanRecvRtn != NULL) { pDrvCtrl->ftCanRecvRtn(&ftCanFrame); } else { printf("%s count:%d \r\n" " recevied canid:%x can_dlc:%d. data:%02x %02x %02x %02x %02x %02x %02x %02x\r\n", __FUNCTION__,cnt, ftCanFrame.can_id & CAN_EFF_MASK,ftCanFrame.can_dlc, ftCanFrame.data[0],ftCanFrame.data[1], ftCanFrame.data[2],ftCanFrame.data[3], ftCanFrame.data[4],ftCanFrame.data[5], ftCanFrame.data[6],ftCanFrame.data[7]); cnt++; } } return ; } #define FTCAN_DEBUG #ifdef FTCAN_DEBUG /***************************************************************************** * * testCanRecvCallback - Test Receive Callback * * This function is used to test the Receive Callback * * RETURNS: N/A * * ERRNO: N/A */ void testCanRecvCallback(struct can_frame* ftCanFrame) { ULONG cnt = 1; if(NULL == ftCanFrame) { printf("%s,%d NULL can frame, no recv\r\n", __FUNCTION__, __LINE__); return; } printf("%s count:%d \r\n" " recevied canid:%x can_dlc:%d. data:%02x %02x %02x %02x %02x %02x %02x %02x\r\n", __FUNCTION__, cnt, ftCanFrame->can_id & CAN_EFF_MASK,ftCanFrame->can_dlc, ftCanFrame->data[0],ftCanFrame->data[1], ftCanFrame->data[2],ftCanFrame->data[3], ftCanFrame->data[4],ftCanFrame->data[5], ftCanFrame->data[6],ftCanFrame->data[7]); cnt++; } /***************************************************************************** * * testCanRecv - Test Receive Callback * * This function is used to test the Receive Callback * * RETURNS: N/A * * ERRNO: N/A */ void testCanRecv(void) { ftCanRecvCallback(0, testCanRecvCallback); } /***************************************************************************** * * testCanSend - TEST CAN0 * * This function is used to test the transmitted data * * RETURNS: N/A * * ERRNO: N/A */ void testCanSend(int channel, int cnt) { struct can_frame canFrame[10]; int i = 0; if(0 == cnt) cnt=1; for(i=0;i<10;i++) { canFrame[i].can_id = (i) | CAN_EFF_FLAG; canFrame[i].can_dlc = 8; canFrame[i].data[0]=0; canFrame[i].data[1]=1; canFrame[i].data[2]=2; canFrame[i].data[3]=3; canFrame[i].data[4]=4; canFrame[i].data[5]=5; canFrame[i].data[6]=6; canFrame[i].data[7]=7; } for(i=0;ipDrvCtrl; for ( i=0; i<0x40;) { printf("addr 0x%x value 0x%x\r\n",i,CSR_READ_4(pDev,i)); i=i+4; } } #endif /* FTCAN_DEBUG */