/* * gsc3280_can.c - CAN network driver for GSC3280 SoC CAN controller * * (C) 2013 by Clive Chen, chenguangyu@china-cpu.com * (C) 2016 by Merlin Song, songxingjia@china-cpu.com * * This software may be distributed under the terms of the GNU General * Public License ("GPL") version 2 as distributed in the 'COPYING' * file from the main directory of the linux kernel source. * * * Your platform definition file should specify something like: * * static struct resource gsc3280_can_resources[] = { * { * .start = GSC3280_CAN_BASEADDR & 0x1fffffff, * .end = ( GSC3280_CAN_BASEADDR & 0x1fffffff ) + 0x100, * .flags = IORESOURCE_MEM, * }, * { * .start = EXT_GSC3280_CAN_IRQ, * .end = EXT_GSC3280_CAN_IRQ, * .flags = IORESOURCE_IRQ, * }, * }; * * unsigned short can_data; * static struct platform_device gsc3280_device_can = { * .name = "gsc3280_can_driver", * .id = 0, * .num_resources = ARRAY_SIZE(gsc3280_can_resources), * .resource = gsc3280_can_resources, * .dev = { * .platform_data = &can_data, * }, * }; * * static struct platform_device *gsc3280_devices[] __initdata = { * ... * &gsc3280_device_can, * ... * } * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gsc3280_can.h" #define DRV_NAME "gsc3280-can" #define TX_ECHO_SKB_MAX 1 //#define CONFIG_GSC3280_CAN_DEBUG 1 #ifdef CONFIG_GSC3280_CAN_DEBUG #define DBG(msg...) do { \ printk(KERN_INFO msg); \ } while (0) #else #define DBG(msg...) do { } while(0) #endif /****************gsc3280 can module register enum************************/ enum gsc3280_reg { CAN_MOD = 0x00, CAN_CMR = 0x04, CAN_SR = 0x08, CAN_IR = 0x0C, CAN_IER = 0x10, CAN_BTR = 0x14, CAN_ALC = 0x18, CAN_ECC = 0x1C, CAN_EWLR = 0x20, CAN_RXERR = 0x24, CAN_TXERR = 0x28, CAN_RMC = 0x2C, CAN_ACR = 0x80, CAN_AMR = 0x84, CAN_TXB0 = 0x80, CAN_TXB1 = 0x84, CAN_TXB2 = 0x88, CAN_TXB3 = 0x8C, CAN_RXB0 = 0x80, CAN_RXB1 = 0x84, CAN_RXB2 = 0x88, CAN_RXB3 = 0x8C, }; enum BLX_devtype { BLX_DEVTYPE_GSC3280, }; struct gsc3280_priv{ struct can_priv can; /*must be the first member!*/ struct net_device *dev; void __iomem *reg_base; int open_time; struct work_struct can_wq; u32 reg_sr; int irq; unsigned short *pin_list; spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */ }; static inline u32 gsc3280_read(const struct gsc3280_priv *priv, enum gsc3280_reg reg) { return __raw_readl((priv->reg_base + reg) + 0xa0000000); } static inline void gsc3280_write(const struct gsc3280_priv *priv, enum gsc3280_reg reg, u32 value ) { __raw_writel(value, (priv->reg_base + reg + 0xa0000000)); } static struct can_bittiming_const gsc3280_can_bittiming_const = { .name = DRV_NAME, .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, .tseg2_max = 8, .sjw_max = 4, .brp_min = 2, .brp_max = 128, .brp_inc = 1, }; /* * gsc3280_can_set_reset_mode - gsc3280 can set reset mode routine * @dev net device structure */ static void gsc3280_can_set_reset_mode (struct net_device *dev) { struct gsc3280_priv *priv = netdev_priv(dev); int i; unsigned char status = gsc3280_read(priv, CAN_MOD) & 0xff; DBG("status is 0x%x, GSC3280_IER 0x%2x,IRQ_OFF 0x%2x\n", status, CAN_IER, IRQ_OFF); /* disable interrupts */ gsc3280_write(priv, CAN_IER, IRQ_OFF); for (i = 0; i < 100; i++) { /* check reset bit */ if (status & MOD_RM) { priv->can.state = CAN_STATE_STOPPED; return ; } /* reset chip */ gsc3280_write(priv, CAN_MOD, MOD_RM); udelay(10); __raw_writel( 0x4, 0xbc04a010); udelay(200); __raw_writel( 0x0 , 0xbc04a010); udelay(200); printk(KERN_INFO "CAN TEST1 CAN_SR= 0x%x \n", gsc3280_read(priv, CAN_SR)); status = gsc3280_read(priv, CAN_MOD) & 0xff; } DBG("setting GSC3280 CAN into reset mode failed!\n"); } /* * gsc3280_can_set_normal_mode - gsc3280 can set normal mode routine * @dev net device structure */ static void gsc3280_can_set_normal_mode(struct net_device *dev) { struct gsc3280_priv *priv = netdev_priv(dev); int i; u32 status = gsc3280_read ( priv, CAN_MOD ); /*printk("Enter gsc3280_can_set_normal_mod, reg_base is %x\n", priv->reg_base);*/ for ( i = 0; i < 100; i++){ /* check reset bit */ if (( status & MOD_RM) == 0) { /* enable interrupts */ priv->can.state = CAN_STATE_ERROR_ACTIVE; gsc3280_write(priv, CAN_IER, IRQ_ALL); if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) gsc3280_write(priv, CAN_IER, IRQ_ALL); else gsc3280_write(priv, CAN_IER, IRQ_ALL & ~IRQ_BEI); return; } /* set chip to normal mode */ gsc3280_write (priv, CAN_MOD, 0x00); udelay(10); status = gsc3280_read ( priv, CAN_MOD); DBG("normal_mod status is 0x%x\n", status); printk(KERN_INFO "CAN TEST2 CAN_SR= 0x%x \n", gsc3280_read(priv, CAN_SR)); } DBG("setting GSC3280 CAN into normal mode failed!\n"); } /* * gsc3280_can_start - gsc3280 can start routine * @dev net device structure */ static void gsc3280_can_start(struct net_device *dev) { struct gsc3280_priv *priv = netdev_priv(dev); /* leave reset mode */ if (priv->can.state != CAN_STATE_STOPPED) gsc3280_can_set_reset_mode(dev); /* Clear error counters and error code capture */ gsc3280_write (priv, CAN_TXERR, 0x0 ); gsc3280_write (priv, CAN_RXERR, 0x0 ); gsc3280_read(priv, CAN_ECC); /* leave reset mode */ gsc3280_can_set_normal_mode(dev); } /* * gsc3280_can_set_bittiming - get can controller bittimg parameters from app * @dev: netdevice structure */ static int gsc3280_can_set_bittiming(struct net_device *dev) { struct gsc3280_priv *priv = netdev_priv(dev); struct can_bittiming *bt = &priv->can.bittiming; unsigned int btr; uint8_t tseg1, tseg2, sjw, brp, sam; tseg1 = (bt->prop_seg + bt->phase_seg1 - 1) & 0xf; tseg2 = (bt->phase_seg2 - 1) & 0x7; sjw = (bt->sjw - 1) & 0x3; brp = (bt->brp - 1) & 0x3f ; btr = (tseg2<<12) | (tseg1<<8) | (sjw<<6) | brp; if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) { sam = 0x1; btr = btr| (sam<<15); } gsc3280_write ( priv, CAN_BTR, btr ); btr = gsc3280_read ( priv, CAN_BTR); DBG("Setting CAN BTR=0x%04x\n",btr); return 0; } static int gsc3280_can_get_berr_counter(const struct net_device *dev, struct can_berr_counter *bec) { struct gsc3280_priv *priv = netdev_priv(dev); bec->txerr = gsc3280_read(priv, CAN_TXERR); bec->rxerr = gsc3280_read(priv, CAN_RXERR); return 0; } /* * gsc3280_can_start_xmit - can controller transmiter function * @dev: netdevice structure * @skb: socket buffer structure */ static int gsc3280_can_start_xmit ( struct sk_buff * skb , struct net_device *dev ) { struct gsc3280_priv *priv = netdev_priv(dev); struct can_frame *cf = ( struct can_frame *)skb->data; uint8_t fi; uint8_t dlc; canid_t id; unsigned long flags; u32 buf1,buf2; int count=0; DBG("Enter gsc3280_can_start_xmit\n"); if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; netif_stop_queue(dev); fi = dlc = cf->can_dlc; id = cf->can_id; DBG(" can_dlc 0x%x \n", cf->can_dlc); DBG(" can_id 0x%x \n", cf->can_id); if((id>>24) & FI_RTR) { fi |= FI_RTR; DBG("remote frame |"); gsc3280_write(priv, CAN_TXB0, fi); }else{ DBG("data frame |"); } if((id>>24) & FI_FF) { DBG("extend"); fi |= FI_FF; gsc3280_write (priv, CAN_TXB0, fi); DBG("id=0x%x, \n", id<<3); gsc3280_write (priv, CAN_TXB1, id<<3); }else{ DBG("standard"); gsc3280_write (priv, CAN_TXB0, fi); DBG("id=0x%x, \n",id); gsc3280_write (priv, CAN_TXB1, id<<21); } DBG ("ID: %x |", id); if (dlc){ DBG("dlc = %d \n", dlc); DBG("DATA:%x %x %x %x %x %x %x %x", cf->data[0], cf->data[1],cf->data[2],cf->data[3],cf->data[4],cf->data[5],cf->data[6],cf->data[7]); buf1= ((cf->data[3]&0xff)<<24) | ((cf->data[2]&0xff)<<16) | ((cf->data[1]&0xff)<<8) | (cf->data[0]); DBG("GSC3280_TXB3 data %x \n",buf1); buf2= ((cf->data[7]&0xff)<<24) | ((cf->data[6]&0xff)<<16) | ((cf->data[5]&0xff)<<8) | (cf->data[4]); DBG("GSC3280_TXB4 data %x \n",buf2); gsc3280_write ( priv, CAN_TXB2, buf1); gsc3280_write ( priv, CAN_TXB3, buf2); } can_put_echo_skb ( skb, dev, 0 ); while (!(gsc3280_read(priv, CAN_SR) & 0x4)); /*tx fifo ok*/ spin_lock_irqsave(&priv->cmdreg_lock, flags); gsc3280_write(priv, CAN_CMR, CMD_TR); spin_unlock_irqrestore(&priv->cmdreg_lock, flags); while (!(gsc3280_read(priv, CAN_SR) & 0x8) && (0!=count)) { /*tx fifo ok*/ count--; } #if 0 printk("REG info: \n"); printk("REG CAN_ALC: 0x%08x \n", gsc3280_read(priv, CAN_ALC)); printk("REG CAN_ECC: 0x%08x \n", gsc3280_read(priv, CAN_ECC)); printk("REG CAN_EWLR: 0x%08x \n", gsc3280_read(priv, CAN_EWLR)); printk("REG CAN_RXERR: 0x%08x \n", gsc3280_read(priv, CAN_RXERR)); printk("REG CAN_TXERR: 0x%08x \n", gsc3280_read(priv, CAN_TXERR)); printk("T over \n"); #endif return NETDEV_TX_OK; } /* * gsc3280_can_rx - gsc3280 can receive routine * @dev net device structure */ static void gsc3280_can_rx ( struct net_device *dev ) { struct gsc3280_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; struct can_frame *cf; struct sk_buff *skb; unsigned long flags; uint8_t ff; uint8_t fi; canid_t id; uint8_t dlc; skb = alloc_can_skb(dev, &cf); if ( skb == NULL ) return; ff = gsc3280_read ( priv, CAN_RXB0); fi = ff & 0xc0; dlc = ff & 0x0F; cf->can_dlc = get_can_dlc(dlc); DBG( "rx: ff is 0x%x,fi is 0x%x,dlc is 0x%x\n", ff, fi, dlc ); if ( fi & FI_FF ){ /* extended frame format (EFF) */ DBG("extend "); id = (gsc3280_read (priv, CAN_RXB1)) >> 3; id |= CAN_EFF_FLAG; }else { /* standard frame format (SFF) */ DBG("standard "); id = (gsc3280_read (priv, CAN_RXB1)) >> 21; } if ( fi & FI_RTR ){ DBG("remote frame |"); id |= CAN_RTR_FLAG; }else{ DBG("data frame |"); } cf->can_id = id; DBG("ID: %x |", id); if (dlc){ cf->data[0] = gsc3280_read ( priv, CAN_RXB2); cf->data[1] = (gsc3280_read ( priv, CAN_RXB2))>>8; cf->data[2] = (gsc3280_read ( priv, CAN_RXB2))>>16; cf->data[3] = (gsc3280_read ( priv, CAN_RXB2))>>24; cf->data[4] = gsc3280_read ( priv, CAN_RXB3); cf->data[5] = (gsc3280_read ( priv, CAN_RXB3))>>8; cf->data[6] = (gsc3280_read ( priv, CAN_RXB3))>>16; cf->data[7] = (gsc3280_read ( priv, CAN_RXB3))>>24; DBG("DATA: "); DBG("%x", gsc3280_read(priv, CAN_RXB3)); DBG("%x", gsc3280_read(priv, CAN_RXB2)); } netif_rx (skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; spin_lock_irqsave(&priv->cmdreg_lock, flags); gsc3280_write(priv, CAN_CMR, CMD_RRB); spin_unlock_irqrestore(&priv->cmdreg_lock, flags); #if 0 printk("REG info: \n"); printk("REG CAN_ALC: 0x%08x \n", gsc3280_read(priv, CAN_ALC)); printk("REG CAN_ECC: 0x%08x \n", gsc3280_read(priv, CAN_ECC)); printk("REG CAN_EWLR: 0x%08x \n", gsc3280_read(priv, CAN_EWLR)); printk("REG CAN_RXERR: 0x%08x \n", gsc3280_read(priv, CAN_RXERR)); printk("REG CAN_TXERR: 0x%08x \n", gsc3280_read(priv, CAN_TXERR)); printk("R over!\n"); #endif } static void gsc3280_poll_rx ( struct net_device *dev ) { struct gsc3280_priv *priv = netdev_priv(dev); uint8_t status; status = gsc3280_read(priv, CAN_RMC); while(status) { gsc3280_can_rx ( dev ); status = gsc3280_read(priv, CAN_RMC); } gsc3280_write(priv, CAN_IER, IRQ_RI); } static int gsc3280_can_err ( struct net_device * dev, u8 isrc, u8 status ) { struct gsc3280_priv *priv = netdev_priv (dev); struct net_device_stats *stats = &dev->stats; struct can_frame *cf; struct sk_buff *skb; uint8_t ecc, alc; enum can_state state = priv->can.state; DBG("Enter gsc3280_can_err\n"); skb = alloc_can_err_skb ( dev, &cf ); if ( skb == NULL ) return -ENOMEM; if ( isrc & IRQ_DOI ) { /* data overrun interrupt */ DBG("data overflow interrupt\n" ); cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; /* gsc3280 can controllor used read reg clear bit */ /* read CAN_IR or set reset mode can clear it */ } if ( isrc & IRQ_EI ) { /* error warning interrupt */ DBG("error warning interrupt\n"); if (status & SR_BS) { state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; can_bus_off(dev); } else if (status & SR_ES) { state = CAN_STATE_ERROR_WARNING; } else state = CAN_STATE_ERROR_ACTIVE; } if (isrc & IRQ_BEI) { /* bus error interrupt */ priv->can.can_stats.bus_error++; stats->rx_errors++; ecc = gsc3280_read(priv, CAN_ECC); cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; switch (ecc & ECC_MASK) { case ECC_BIT: cf->data[2] |= CAN_ERR_PROT_BIT; break; case ECC_FORM: cf->data[2] |= CAN_ERR_PROT_FORM; break; case ECC_STUFF: cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] = ecc & ECC_SEG; break; } /* Error occurred during transmission? */ if ((ecc & ECC_DIR) == 0) cf->data[2] |= CAN_ERR_PROT_TX; } if ( isrc & IRQ_EPI ) { /* error passive interrupt */ DBG( "error passive interrupt\n"); if (status & SR_ES) state = CAN_STATE_ERROR_PASSIVE; else state = CAN_STATE_ERROR_ACTIVE; } if (isrc & IRQ_ALI) { /* arbitration lost interrupt */ DBG("arbitration lost interrupt\n"); alc = gsc3280_read(priv, CAN_ALC); priv->can.can_stats.arbitration_lost++; stats->tx_errors++; cf->can_id |= CAN_ERR_LOSTARB; cf->data[0] = alc & 0x1f; } if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE)) { uint8_t rxerr = gsc3280_read(priv, CAN_RXERR); uint8_t txerr = gsc3280_read(priv, CAN_TXERR); cf->can_id |= CAN_ERR_CRTL; if (state == CAN_STATE_ERROR_WARNING) { priv->can.can_stats.error_warning++; cf->data[1] = (txerr > rxerr) ? CAN_ERR_CRTL_TX_WARNING : CAN_ERR_CRTL_RX_WARNING; } else { priv->can.can_stats.error_passive++; cf->data[1] = (txerr > rxerr) ? CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; } cf->data[6] = txerr; cf->data[7] = rxerr; } priv->can.state = state; netif_rx ( skb ); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; return 0; } irqreturn_t gsc3280_can_interrupt ( int irq, void * dev_id ) { struct net_device *dev = dev_id; struct gsc3280_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; uint8_t status, isrc; isrc = gsc3280_read( priv, CAN_IR); if(isrc & IRQ_TI ){ /*trammiter interrupt*/ stats->tx_packets++; stats->tx_bytes += gsc3280_read (priv, CAN_TXB0)&0xf; can_get_echo_skb ( dev, 0 ); netif_wake_queue ( dev ); }else if( isrc & IRQ_RI ){ /*receive interrupt*/ status = gsc3280_read(priv, CAN_RMC); while (status) { gsc3280_can_rx ( dev ); status = gsc3280_read(priv, CAN_RMC); } // gsc3280_write(priv, CAN_IER, ~IRQ_RI); // gsc3280_poll_rx( dev ); }else if(( isrc & ~(IRQ_TI | IRQ_RI) )){ gsc3280_can_err ( dev, isrc, status ); }else{ return IRQ_NONE; } return IRQ_HANDLED; } /* * gsc3280_can_open - gsc3280 can open routine * @dev net device structure */ static int gsc3280_can_open ( struct net_device *dev ) { struct gsc3280_priv *priv = netdev_priv(dev); int err; DBG(" gsc3280_can_open \n"); gsc3280_can_set_reset_mode(dev); err = open_candev(dev); if(err) goto exit_open; err = request_irq(priv->irq, &gsc3280_can_interrupt, IRQF_SHARED, "gsc3280-can-irq" , dev); if(err) goto exit_err_irq; /*this must set in reset mode*/ gsc3280_write(priv, CAN_ACR, 0xffffffff); gsc3280_write(priv, CAN_AMR, 0xffffffff); gsc3280_can_start(dev); priv->open_time = jiffies; netif_start_queue (dev); return 0; exit_err_irq: close_candev(dev); free_irq(priv->irq,dev); exit_open: return err; } static int gsc3280_can_close ( struct net_device *dev ) { struct gsc3280_priv *priv = netdev_priv(dev); DBG("Enter gsc3280_can_close\n"); netif_stop_queue (dev); gsc3280_can_set_reset_mode(dev); close_candev(dev); free_irq(priv->irq,dev); priv->open_time = 0; return 0; } static int gsc3280_can_set_mode(struct net_device *dev, enum can_mode mode) { struct gsc3280_priv *priv = netdev_priv(dev); if (!priv->open_time) return -EINVAL; switch (mode) { case CAN_MODE_START: gsc3280_can_start(dev); if (netif_queue_stopped(dev)) netif_wake_queue(dev); break; default: return -EOPNOTSUPP; } return 0; } struct net_device *alloc_gsc3280_candev(void) { struct net_device *dev; struct gsc3280_priv *priv; dev = alloc_candev ( sizeof(*priv), TX_ECHO_SKB_MAX); DBG("alloc_gsc3280_candev,dev is 0x%x, dev->dev is 0x%x\n", dev, dev->dev); if ( !dev) return NULL; priv = netdev_priv (dev); priv->dev = dev; priv->can.bittiming_const = &gsc3280_can_bittiming_const; priv->can.do_set_bittiming = gsc3280_can_set_bittiming; //priv->can.do_set_mode = gsc3280_can_set_mode; priv->can.do_set_mode = gsc3280_can_set_reset_mode; //priv->can.do_get_berr_counter = gsc3280_can_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; spin_lock_init(&priv->cmdreg_lock); return dev; } static const struct net_device_ops gsc3280_can_netdev_ops = { .ndo_open = gsc3280_can_open, .ndo_stop = gsc3280_can_close, .ndo_start_xmit = gsc3280_can_start_xmit, }; static int __devinit gsc3280_can_probe (struct platform_device *pdev) { struct net_device *dev; struct gsc3280_priv *priv; struct resource *res_mem, *irq; struct clk *clk; unsigned long rate; unsigned short *pdata; int err; void __iomem *addr; //SYSCTL_CLK_DIV_CAN; //*(volatile unsigned int *)0xbc04a030 = 0x1; // rate=55.6M/2 __raw_writel( 0x1 , 0xbc04a030); // rate=55.6M/4 clk = clk_get ( &pdev->dev , "can" ); rate = clk_get_rate ( clk ); clk_set_rate(clk, rate); if ( IS_ERR(clk)){ DBG("no clock defined\n"); err = -ENODEV; goto exit; } pdata = pdev->dev.platform_data; if(!pdata){ DBG("No platform data provided!\n"); err = -EINVAL; goto exit; } res_mem = platform_get_resource (pdev, IORESOURCE_MEM, 0); irq = platform_get_resource (pdev, IORESOURCE_IRQ, 0); DBG("res_mem is 0x%x, irq is %d\n", res_mem->start, irq->start); /* if ( !res_mem || irq<0 || !tx_irq || !rx_irq ){ err = -ENODEV; goto exit; } */ if (!request_mem_region( res_mem->start , resource_size(res_mem), dev_name(&pdev->dev) )){ printk("request_mem_region is null\n"); err = -ENOMEM; goto exit_release; } dev = alloc_gsc3280_candev(); if (!dev){ err = -ENOMEM; goto exit_iounmap; } priv = netdev_priv (dev); priv->can.clock.freq = rate; priv->can.bittiming_const = &gsc3280_can_bittiming_const; priv->can.do_set_bittiming = gsc3280_can_set_bittiming; priv->can.do_set_mode = gsc3280_can_set_mode; priv->can.do_get_berr_counter = gsc3280_can_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; priv->dev = dev; priv->reg_base = (void __iomem*) (res_mem->start); /* DBG("priv->reg_base is 0x%x\n", priv->reg_base);*/ priv->irq = irq->start; priv->pin_list = pdata; DBG("priv_irq is %d\n", priv->irq); dev_set_drvdata(&pdev->dev, dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->netdev_ops = &gsc3280_can_netdev_ops; dev->flags |= IFF_ECHO; __raw_writel(( __raw_readl(0xbc04a008)| 0x4) , 0xbc04a008); gsc3280_can_set_reset_mode(dev); gsc3280_can_set_bittiming(dev); err = register_candev(dev); if(err){ DBG("registering netdev failed\n"); goto exit_free; } DBG("device registered (reg_base=0x%x,irq=%d)\n", priv->reg_base, priv->irq); return 0; exit_free: free_candev(dev); exit_iounmap: iounmap(addr); exit_release: release_mem_region ( res_mem->start, resource_size(res_mem)); exit: return err; } static int __devexit gsc3280_can_remove ( struct platform_device *pdev ) { struct net_device *dev = dev_get_drvdata ( &pdev->dev ); /* struct gsc3280_priv *priv = netdev_priv (dev);*/ struct resource *res; gsc3280_can_set_reset_mode(dev); unregister_candev(dev); dev_set_drvdata(&pdev->dev, NULL); res = platform_get_resource ( pdev, IORESOURCE_MEM, 0 ); release_mem_region (res->start, resource_size(res)); free_candev(dev); return 0; } static const struct platform_device_id gsc3280_can_id_table[] = { { .name = "gsc3280_can_driver", .driver_data = BLX_DEVTYPE_GSC3280, },{ } }; static struct platform_driver gsc3280_can_driver = { .probe = gsc3280_can_probe, .remove = __devexit_p ( gsc3280_can_remove ), .driver = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, }, .id_table = gsc3280_can_id_table, }; static int __init gsc3280_can_module_init (void) { printk("gsc3280_can_init\n"); return platform_driver_register (&gsc3280_can_driver); } static void __exit gsc3280_can_module_exit (void) { platform_driver_unregister(&gsc3280_can_driver); } module_init(gsc3280_can_module_init); module_exit(gsc3280_can_module_exit); MODULE_AUTHOR("Merlin Song "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION(KBUILD_MODNAME " CAN netdevice driver");