Index: linux-2.6.25-rc/drivers/net/can/at91_can.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.25-rc/drivers/net/can/at91_can.c 2008-02-15 21:55:36.000000000 +0100 @@ -0,0 +1,954 @@ +/* + * at91_can.c - CAN network driver for AT91 SoC CAN controller + * + * (C) 2007 by Hans J. Koch + * + * 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. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "at91_can.h" + +MODULE_AUTHOR("Hans J. Koch "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("LLCF/socketcan '" CHIP_NAME "' network device driver"); + +static char drv_name[DRV_NAME_LEN] = "undefined"; + +/* driver and version information */ +static const char *drv_version = "0.0.1"; +static const char *drv_reldate = "2007-10-26"; + +/* We can never have more than one CAN controller */ +static struct net_device *can_dev; + +/* module parameters */ +static unsigned int speed = DEFAULT_SPEED; +static int clk = DEFAULT_HW_CLK; +static int debug; +static int restart_ms = 100; +static int loopback; + +module_param(speed, int, 0); +module_param(clk, int, 0); +module_param(debug, int, 0); +module_param(restart_ms, int, 0); +module_param(loopback, int, S_IRUGO); + +MODULE_PARM_DESC(speed, "CAN bus bitrate"); +MODULE_PARM_DESC(clk, "CAN controller chip clock (default: 100MHz)"); +MODULE_PARM_DESC(debug, "set debug level 0..3 (default: 0)"); +MODULE_PARM_DESC(restart_ms, "restart chip on heavy bus errors / bus off " + "after x ms (default 100ms)"); +MODULE_PARM_DESC(loopback, "Loop back sent frames. default: 1 (On)"); + +#ifdef CONFIG_CAN_DEBUG_DEVICES +#define can_dbg(netdev, level, fmt, arg...) \ + if (debug >= level) dev_info(&netdev->dev, fmt, ## arg) +#else +static void can_dbg(struct net_device *dev, int level, const char *fmt, ...) {} +#endif + +static u32 at91_can_read(struct net_device *dev, unsigned long reg) +{ + return _at91_can_read(dev->base_addr + reg); +} + +static void at91_can_write(struct net_device *dev, unsigned long reg, u32 value) +{ + _at91_can_write(dev->base_addr + reg, value); +} + +static void enable_can_transceiver(struct can_priv *priv, int enable) +{ + /* Enable or disable transceiver */ + if ((priv->data) && (priv->data->transceiver_enable)) + priv->data->transceiver_enable(enable); +} + +/* + * calculate baud rate register values + * @baud: Desired baud rate in Hz + * @clock: MCK clock in Hz + */ +static int set_baud(struct net_device *dev, int baud, int clock) +{ + u32 brp, propag, phase1, phase2, sjw, can_mr; + u32 can_br = 0, time_quanta = 16; + int n; + + if (baud <= 0) { + can_dbg(dev, 0, "Stupid baud value (%d)!\n", baud); + return -EINVAL; + } + + can_dbg(dev, 1, "set_baud, baud=%d, clock=%d\n", baud, clock); + + while (1) { + brp = (u32)clock/(time_quanta * (u32)baud) - 1; + if (brp < 50) + break; + time_quanta++; + if (time_quanta > 25) { + can_dbg(dev, 1, "Baud problem: Max. 25 time quanta.\n"); + goto err_impossible; + } + } + + if (brp == 0) { + can_dbg(dev, 1, "Baud problem: brp is 0.\n"); + goto err_impossible; + } + + propag = time_quanta * baud * 38 / 100000000; + if (propag < 3) + propag = 3; + + /* Ensure phase1+phase2 <= 16 by increasing propag if needed */ + if ((time_quanta > 17) && (time_quanta - propag > 17)) + propag = time_quanta - 17; + + n = time_quanta - propag - 1; + if (n < 2) { + can_dbg(dev, 1, "Baud problem: phase1+phase2 too short.\n"); + goto err_impossible; + } + phase2 = n/2; + phase1 = time_quanta - propag - phase2 - 1; + sjw = phase1 - 1; + if (sjw > 3) + sjw = 3; + can_dbg(dev, 2, "%d time quanta, brp=%d, sjw=%d, propag=%d, phase1=%d, " + "phase2=%d\n", time_quanta, brp, sjw, propag, phase1, phase2); + + can_br = (brp << 16) | + (sjw << 12) | + ((propag - 1) << 8) | + ((phase1 - 1) << 4) | + (phase2 - 1); + can_dbg(dev, 2, "Setting CAN_BR to 0x%08X\n", can_br); + + can_mr = at91_can_read(dev, CAN_MR); + at91_can_write(dev, CAN_MR, can_mr & ~CAN_MR_CANEN); + at91_can_write(dev, CAN_BR, can_br); + at91_can_write(dev, CAN_MR, can_mr | CAN_MR_CANEN); + + return 0; + +err_impossible: + can_dbg(dev, 0, "Impossible baud/clock combination (%d/%d)!\n", + baud, clock); + return -EINVAL; +} + +static void set_mailbox_mode(struct net_device *dev, int mb, int mode) +{ + at91_can_write(dev, CAN_MMR(mb), mode << 24); +} + +static void setup_mailboxes(struct net_device *dev) +{ + int mb; + + /* The first 8 mailboxes are used as a reception FIFO. The eighth + * mailbox is configured with overwrite option. The overwrite flag + * indicates a FIFO overflow. + */ + for (mb = 0; mb < LAST_RX_MB; mb++) + set_mailbox_mode(dev, mb, MB_MODE_RX); + set_mailbox_mode(dev, LAST_RX_MB, MB_MODE_RX_OVRWR); + + /* The last 8 mailboxes are used for transmitting. */ + for (mb = FIRST_TX_MB; mb < 16; mb++) + set_mailbox_mode(dev, mb, MB_MODE_TX); +} + +static int find_free_tx_mailbox(struct net_device *dev, int *is_last_mb) +{ + int mb, ret_mb = -1; + unsigned long flags; + struct can_priv *priv = netdev_priv(dev); + + *is_last_mb = 1; + + spin_lock_irqsave(&priv->lock, flags); + for (mb = FIRST_TX_MB; mb < 16; mb++) { + if (at91_can_read(dev, CAN_MSR(mb)) & CAN_MSR_MRDY) { + if (ret_mb >= 0) { + *is_last_mb = 0; + goto out; + } + ret_mb = mb; + } + } + +out: + spin_unlock_irqrestore(&priv->lock, flags); + return ret_mb; +} + +static int find_full_rx_mailbox(struct net_device *dev) +{ + int mb; + u32 msr; + struct can_priv *priv = netdev_priv(dev); + + spin_lock(&priv->lock); + + for (mb = 0; mb <= LAST_RX_MB; mb++) { + msr = at91_can_read(dev, CAN_MSR(mb)); + if (msr & CAN_MSR_MRDY) { + spin_unlock(&priv->lock); + if ((mb == LAST_RX_MB) && (msr & CAN_MSR_MMI)) { + priv->can_stats.data_overrun++; + can_dbg(dev, 2, "RX overrun.\n"); + } + return mb; + } + } + + spin_unlock(&priv->lock); + return -1; +} + +static int can_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + struct can_frame *cf = (struct can_frame *)skb->data; + int loop; + int is_last_mb; + u32 can_mid, can_mcr, can_mdl = 0, can_mdh = 0; + unsigned long flags; + int mb = find_free_tx_mailbox(dev, &is_last_mb); + + if (is_last_mb) + netif_stop_queue(dev); + + if (mb < 0) { + /* This should never happen, queue should be stopped when + * the last mailbox was used. + */ + can_dbg(dev, 0, "Huh?? can_start_xmit without free mailbox?\n"); + return 0; + } + + can_dbg(dev, 2, "TX start for mb #%d\n", mb); + + spin_lock_irqsave(&priv->lock, flags); + set_mailbox_mode(dev, mb, MB_MODE_DISABLED); + + if (cf->can_id & CAN_EFF_FLAG) + can_mid = CAN_MID_MIDE | (cf->can_id & 0x0003FFFF); + else + can_mid = (cf->can_id & 0x000007FF) << 18; + + at91_can_write(dev, CAN_MID(mb), can_mid); + set_mailbox_mode(dev, mb, MB_MODE_TX); + + can_mdl = cf->data[0] | + (cf->data[1] << 8) | + (cf->data[2] << 16) | + (cf->data[3] << 24); + can_mdh = cf->data[4] | + (cf->data[5] << 8) | + (cf->data[6] << 16) | + (cf->data[7] << 24); + + at91_can_write(dev, CAN_MDL(mb), can_mdl); + at91_can_write(dev, CAN_MDH(mb), can_mdh); + + can_mcr = (cf->can_id & CAN_RTR_FLAG) ? CAN_MCR_MRTR : 0; + can_mcr |= ((cf->can_dlc & 0x0F) << 16); + can_mcr |= CAN_MCR_MTCR; + + /* This triggers transmission */ + at91_can_write(dev, CAN_MCR(mb), can_mcr); + + priv->stats.tx_bytes += cf->can_dlc; + dev->trans_start = jiffies; + + /* Enable interrupt for this mailbox */ + at91_can_write(dev, CAN_IER, 1 << mb); + + spin_unlock_irqrestore(&priv->lock, flags); + + /* set flag whether this packet has to be looped back */ + loop = (skb->pkt_type == PACKET_LOOPBACK); + + if (!loopback || !loop) { + kfree_skb(skb); + return 0; + } + + if (!priv->loop_skb[mb - FIRST_TX_MB]) { + struct sock *srcsk = skb->sk; + + if (atomic_read(&skb->users) != 1) { + struct sk_buff *old_skb = skb; + + skb = skb_clone(old_skb, GFP_ATOMIC); + can_dbg(dev, 2, "freeing old skbuff %p, " + "using new skbuff %p\n", old_skb, skb); + kfree_skb(old_skb); + if (!skb) + return 0; + } else + skb_orphan(skb); + + skb->sk = srcsk; + + skb->protocol = htons(ETH_P_CAN); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->dev = dev; + + /* save this skb for tx interrupt loopback handling */ + priv->loop_skb[mb - FIRST_TX_MB] = skb; + + } else { + /* locking problem with netif_stop_queue() ?? */ + printk(KERN_ERR "%s: %s: occupied loop_skb!\n", + dev->name, __FUNCTION__); + kfree_skb(skb); + } + + return 0; +} + +static void read_mailbox(struct net_device *dev, int mb, struct can_frame *cf) +{ + u32 can_msr, can_mid, can_mdl, can_mdh; + int i; + struct can_priv *priv = netdev_priv(dev); + + spin_lock(&priv->lock); + can_mid = at91_can_read(dev, CAN_MID(mb)); + if (can_mid & CAN_MID_MIDE) + cf->can_id = (can_mid & 0x0003FFFF) | CAN_EFF_FLAG; + else + cf->can_id = ((can_mid & 0x1FFC0000) >> 18); + + can_msr = at91_can_read(dev, CAN_MSR(mb)); + cf->can_dlc = ((can_msr & 0x000F0000) >> 16); + if (can_msr & CAN_MSR_MRTR) + cf->can_id |= CAN_RTR_FLAG; + + can_mdl = at91_can_read(dev, CAN_MDL(mb)); + can_mdh = at91_can_read(dev, CAN_MDH(mb)); + + for (i = 0; i < 4; i++) { + cf->data[i] = can_mdl & 0x000000FF; + cf->data[i+4] = can_mdh & 0x000000FF; + can_mdl = can_mdl >> 8; + can_mdh = can_mdh >> 8; + } + + /* reenable mailbox */ + set_mailbox_mode(dev, mb, + (mb == LAST_RX_MB) ? MB_MODE_RX_OVRWR : MB_MODE_RX); + + spin_unlock(&priv->lock); + return; +} + +static void can_rx(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + struct can_frame *cf; + struct sk_buff *skb; + u32 mcr; + + int mb = find_full_rx_mailbox(dev); + + while (mb >= 0) { + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) + return; + + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + read_mailbox(dev, mb, cf); + spin_lock(&priv->lock); + netif_rx(skb); + dev->last_rx = jiffies; + priv->stats.rx_packets++; + priv->stats.rx_bytes += cf->can_dlc; + mcr = at91_can_read(dev, CAN_MCR(mb)); + /* Finished, allow new reception */ + at91_can_write(dev, CAN_MCR(mb), mcr | CAN_MCR_MTCR); + spin_unlock(&priv->lock); + mb = find_full_rx_mailbox(dev); + } +} + +static void can_tx_irq(struct net_device *dev, u32 mask) +{ + int mb; + u32 imr; + struct can_priv *priv = netdev_priv(dev); + + spin_lock(&priv->lock); + imr = at91_can_read(dev, CAN_IMR); + + for (mb = FIRST_TX_MB; mb < 16; mb++) { + if (mask & imr & (1 << mb)) { + /* Disable irq for this TX mailbox */ + at91_can_write(dev, CAN_IDR, 1 << mb); + + /* Reenable mailbox */ + at91_can_write(dev, CAN_MCR(mb), 0); + + priv->stats.tx_packets++; + + if (loopback && priv->loop_skb[mb - FIRST_TX_MB]) { + netif_rx(priv->loop_skb[mb - FIRST_TX_MB]); + priv->loop_skb[mb - FIRST_TX_MB] = NULL; + } + } + } + + spin_unlock(&priv->lock); + netif_wake_queue(dev); +} + +static int at91_can_init_regs(struct net_device *dev) +{ + u32 reg; + int ret; + unsigned long flags; + struct can_priv *priv = netdev_priv(dev); + + spin_lock_irqsave(&priv->lock, flags); + /* Disable all interrupts */ + at91_can_write(dev, CAN_IDR, 0x1FFFFFFF); + + if (priv->speed == 0) + priv->speed = DEFAULT_SPEED; + + ret = set_baud(dev, priv->speed, priv->clock); + if (ret) + return ret; + + setup_mailboxes(dev); + + /* Enable interrupts, TODO: CAN_IRQ_ERRP */ + reg = CAN_IRQ_MB_RX | + CAN_IRQ_BOFF | + CAN_IRQ_CERR | + CAN_IRQ_SERR | + CAN_IRQ_AERR | + CAN_IRQ_FERR | + CAN_IRQ_BERR; + + at91_can_write(dev, CAN_IER, reg); + + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static void chipset_init(struct net_device *dev, int wake) +{ + struct can_priv *priv = netdev_priv(dev); + int i; + + at91_can_init_regs(dev); + + if (priv->rx_probe) { + /* TODO: automatic bit rate detection */ + priv->state = STATE_PROBE; + printk(KERN_ERR "CAN: No autobaud yet!!!\n"); + } else + priv->state = STATE_ACTIVE; + + if ((wake) && netif_queue_stopped(dev)) { + /* Check for pending loopback */ + for (i = 8; i < 16; i++) { + if (priv->loop_skb[i]) { + kfree_skb(priv->loop_skb[i]); + priv->loop_skb[i] = NULL; + } + } + netif_wake_queue(dev); + } +} + +static void can_tx_timeout(struct net_device *dev) +{ + int i; + struct can_priv *priv = netdev_priv(dev); + + priv->stats.tx_errors++; + can_dbg(dev, 0, "TX timeout!\n"); + + /* do not conflict with e.g. bus error handling */ + if (!(priv->timer.expires)) { + chipset_init(dev, 0); + for (i = 8; i < 16; i++) { + if (priv->loop_skb[i]) { + kfree_skb(priv->loop_skb[i]); + priv->loop_skb[i] = NULL; + } + } + netif_wake_queue(dev); + } else + can_dbg(dev, 1, "can_restart_dev already active.\n"); +} + +static void can_restart_dev(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct can_priv *priv = netdev_priv(dev); + + can_dbg(dev, 1, "can_restart_dev (%ld)\n", jiffies); + + /* mark inactive timer */ + priv->timer.expires = 0; + + if (priv->state != STATE_UNINITIALIZED) { + /* count number of restarts */ + priv->can_stats.restarts++; + chipset_init(dev, 1); + } +} + +static void can_restart_on(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (!(priv->timer.expires)) { + /* no restart in progress */ + priv->timer.function = can_restart_dev; + priv->timer.data = (unsigned long) dev; + + /* restart chip on persistent error in ms */ + priv->timer.expires = jiffies + (priv->restart_ms * HZ) / 1000; + add_timer(&priv->timer); + + can_dbg(dev, 1, "can_restart_on (%ld)\n", jiffies); + } else + can_dbg(dev, 1, "can_restart_on already active (%ld)\n", + jiffies); +} + +static struct net_device_stats *can_get_stats(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + /* TODO: read statistics from chip */ + return &priv->stats; +} + +static int can_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + if (!netif_running(dev)) + return -EINVAL; + + /* TODO: Add baudrate ioctls ? */ +#if 0 + switch (cmd) { + case SIOCSCANBAUDRATE: + ; + return 0; + case SIOCGCANBAUDRATE: + ; + return 0; + } +#endif + return 0; +} + +/* + * interrupt handler + */ +static irqreturn_t can_interrupt(int irq, void *dev_id) +{ + u32 sr, imr; + struct net_device *dev = (struct net_device *)dev_id; + struct can_priv *priv = netdev_priv(dev); + + sr = at91_can_read(dev, CAN_SR); + imr = at91_can_read(dev, CAN_IMR); + can_dbg(dev, 2, "irq: SR=0x%08x IMR=0x%08x [0x%08x]\n", + sr, imr, sr & imr); + /* Ignore masked interrupts */ + sr &= imr; + + if (sr & CAN_IRQ_MB_RX) { + can_rx(dev); + + if (priv->state == STATE_PROBE) { + /* TODO: Handle autobaud detection */ + printk(KERN_ERR "CAN: irq: no autobaud yet!!!\n"); + } + } + + if (sr & CAN_IRQ_MB_TX) + can_tx_irq(dev, sr); + + if (sr & CAN_IRQ_WAKEUP) { + priv->can_stats.wakeup++; + can_dbg(dev, 1, "WAKEUP irq\n"); + } + + if (sr & CAN_IRQ_CERR) + can_dbg(dev, 1, "CERR irq\n"); + + if (sr & CAN_IRQ_SERR) + can_dbg(dev, 1, "SERR irq\n"); + + if (sr & CAN_IRQ_AERR) + can_dbg(dev, 1, "AERR irq\n"); + + if (sr & CAN_IRQ_FERR) + can_dbg(dev, 1, "FERR irq\n"); + + if (sr & CAN_IRQ_ERRP) { + can_dbg(dev, 1, "ERRP irq\n"); + priv->can_stats.error_passive++; + can_restart_on(dev); + return IRQ_HANDLED; + } + + if (sr & CAN_IRQ_WARN) { + can_dbg(dev, 1, "WARN irq\n"); + priv->can_stats.error_warning++; + } + + if (sr & CAN_IRQ_BOFF) { + can_dbg(dev, 1, "BOFF irq\n"); + priv->state = STATE_BUS_OFF; + can_restart_on(dev); + return IRQ_HANDLED; + } + + if (sr & CAN_IRQ_BERR) { + can_dbg(dev, 1, "BERR irq\n"); + priv->can_stats.bus_error++; + /* TODO: Bus error == Bit error? Restart? */ + } + + /* TODO: Howto detect lost arbitration??? + * priv->can_stats.arbitration_lost++; + */ + + return IRQ_HANDLED; +} + +/* + * initialize CAN bus driver + */ +static int can_open(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + can_dbg(dev, 1, "can_open called\n"); + priv->state = STATE_UNINITIALIZED; + clk_enable(priv->can_clk); + /* init chip */ + chipset_init(dev, 0); + enable_can_transceiver(priv, 1); + /* clear statistics */ + memset(&priv->stats, 0, sizeof(priv->stats)); + + priv->open_time = jiffies; + + /* register interrupt handler */ + if (request_irq(dev->irq, &can_interrupt, IRQF_SHARED, + dev->name, (void *)dev)) { + can_dbg(dev, 0, "request_irq failed.\n"); + return -EAGAIN; + } + netif_start_queue(dev); + + return 0; +} + +/* + * stop CAN bus activity + */ +static int can_close(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + can_dbg(dev, 1, "can_close called\n"); + priv->open_time = 0; + + if (priv->timer.expires) { + del_timer(&priv->timer); + priv->timer.expires = 0; + } + + netif_stop_queue(dev); + clk_disable(priv->can_clk); + + free_irq(dev->irq, (void *)dev); + priv->state = STATE_UNINITIALIZED; + + enable_can_transceiver(priv, 0); + + return 0; +} + +void can_netdev_setup(struct net_device *dev) +{ + /* Fill in the the fields of the device structure + * with CAN netdev generic values + */ + + dev->change_mtu = NULL; + dev->set_mac_address = NULL; + + dev->type = ARPHRD_CAN; + dev->hard_header_len = 0; + dev->mtu = sizeof(struct can_frame); + dev->addr_len = 0; + dev->tx_queue_len = 10; + + dev->flags = IFF_NOARP; + + /* set flags according to driver capabilities */ + if (loopback) + dev->flags |= IFF_LOOPBACK; + + dev->features = NETIF_F_NO_CSUM; + + dev->open = can_open; + dev->stop = can_close; + dev->hard_start_xmit = can_start_xmit; + dev->get_stats = can_get_stats; + dev->do_ioctl = can_ioctl; + + dev->tx_timeout = can_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +} + +static struct net_device *can_create_netdev(struct platform_device *pdev, + struct clk *can_clk) +{ + struct net_device *dev; + struct can_priv *priv; + struct resource *res; + + dev = alloc_netdev(sizeof(struct can_priv), CAN_NETDEV_NAME, + can_netdev_setup); + if (!dev) { + can_dbg(dev, 0, "alloc_netdev failed!\n"); + return NULL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + goto err_out0; + + if (!request_mem_region(res->start, res->end - res->start + 1, + "at91_can")) + goto err_out0; + + dev->base_addr = (unsigned long)ioremap(res->start, + res->end - res->start + 1); + if (!dev->base_addr) { + can_dbg(dev, 0, "ioremap failed!\n"); + goto err_out1; + } + + dev->irq = AT91SAM9263_ID_CAN; + + priv = netdev_priv(dev); + + spin_lock_init(&priv->lock); + priv->can_clk = can_clk; + priv->data = pdev->dev.platform_data; + priv->speed = speed; + priv->clock = clk; + priv->restart_ms = restart_ms; + priv->debug = debug; + + init_timer(&priv->timer); + priv->timer.expires = 0; + + if (register_netdev(dev)) { + can_dbg(dev, 0, "register netdev failed\n"); + goto err_out2; + } + + return dev; + +err_out2: + iounmap((void *)dev->base_addr); +err_out1: + release_mem_region(res->start, res->end - res->start + 1); +err_out0: + free_netdev(dev); + return NULL; +} + +static int can_set_drv_name(void) +{ + char *hname = "AT91_CAN"; + + if (strlen(CHIP_NAME) + strlen(hname) >= DRV_NAME_LEN-1) { + printk(KERN_ERR "%s: driver name too long!\n", CHIP_NAME); + return -EINVAL; + } + sprintf(drv_name, "%s-%s", CHIP_NAME, hname); + return 0; +} + +static int __init at91_can_probe(struct platform_device *pdev) +{ + int ret; + struct clk *can_clk; + + ret = can_set_drv_name(); + if (ret) + return ret; + + /* MHz clock value */ + if (clk < 1000) + clk *= 1000000; + /* kHz clock value */ + if (clk < 1000000) + clk *= 1000; + /* kHz baud value */ + if (speed <= 1000) + speed *= 1000; + + printk(KERN_ERR "%s driver v%s (%s)\n", + drv_name, drv_version, drv_reldate); + printk(KERN_ERR "%s - options [clk %d.%06d MHz] [restart_ms %dms]" + " [debug %d]\n", + drv_name, clk/1000000, clk%1000000, restart_ms, debug); + + can_clk = clk_get(&pdev->dev, "can_clk"); + if (IS_ERR(can_clk)) { + printk(KERN_ERR "at91_can: no clock defined\n"); + return -ENODEV; + } + + can_dev = can_create_netdev(pdev, can_clk); + platform_set_drvdata(pdev, can_dev); + + if (!can_dev) { + printk(KERN_ERR "at91_can: Could not create netdev.\n"); + return -ENODEV; + } + + return 0; +} + +static int __devexit at91_can_remove(struct platform_device *pdev) +{ + struct net_device *net_dev = platform_get_drvdata(pdev); + struct can_priv *priv; + struct resource *res; + unsigned long can_base; + + if (!net_dev) + return -ENODEV; + + can_base = net_dev->base_addr; + + priv = netdev_priv(net_dev); + + unregister_netdev(net_dev); + free_irq(net_dev->irq, net_dev); + del_timer(&priv->timer); + clk_put(priv->can_clk); + enable_can_transceiver(priv, 0); + + platform_set_drvdata(pdev, NULL); + free_netdev(net_dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap((void *)can_base); + release_mem_region(res->start, res->end - res->start + 1); + + return 0; +} + +#ifdef CONFIG_PM + +static int at91_can_suspend(struct platform_device *pdev, + pm_message_t mesg) +{ + struct net_device *net_dev = platform_get_drvdata(pdev); + struct can_priv *priv = netdev_priv(net_dev); + + if (netif_running(net_dev)) { + /* TODO Disable IRQ? */ + netif_stop_queue(net_dev); + netif_device_detach(net_dev); + enable_can_transceiver(priv, 0); + clk_disable(priv->can_clk); + } + return 0; +} + +static int at91_can_resume(struct platform_device *pdev) +{ + struct net_device *net_dev = platform_get_drvdata(pdev); + struct can_priv *priv = netdev_priv(net_dev); + + if (netif_running(net_dev)) { + clk_enable(priv->can_clk); + enable_can_transceiver(priv, 1); + netif_device_attach(net_dev); + netif_start_queue(net_dev); + /* TODO Enable IRQ? */ + } + return 0; +} + +#else +#define at91_can_suspend NULL +#define at91_can_resume NULL +#endif + +static struct platform_driver at91_can_driver = { + .probe = at91_can_probe, + .remove = __devexit_p(at91_can_remove), + .suspend = at91_can_suspend, + .resume = at91_can_resume, + .driver = { + .name = "at91_can", + .owner = THIS_MODULE, + }, +}; + +static int __init at91_can_init_module(void) +{ + return platform_driver_register(&at91_can_driver); +} + +static void __exit at91_can_exit_module(void) +{ + platform_driver_unregister(&at91_can_driver); +} + +module_init(at91_can_init_module); +module_exit(at91_can_exit_module); + Index: linux-2.6.25-rc/drivers/net/can/at91_can.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.25-rc/drivers/net/can/at91_can.h 2008-02-15 21:55:36.000000000 +0100 @@ -0,0 +1,169 @@ +/* + * at91_can.h - CAN related definitions for AT91 SoC CAN controller + * + * (C) 2007 by Hans J. Koch + * + * 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. + * + * Send feedback to + * + */ + +#ifndef AT91_CAN_H +#define AT91_CAN_H + +#define CHIP_NAME "AT91" + +#define DRV_NAME_LEN 30 /* for "-" */ + +#define DEFAULT_HW_CLK 100000000 +#define DEFAULT_SPEED 250 /* kBit/s */ + +#define CAN_NETDEV_NAME "can%d" + +#define TX_TIMEOUT (50*HZ/1000) /* 50ms */ +#define RESTART_MS 100 /* restart chip on persistent errors in 100ms */ +#define MAX_BUS_ERRORS 200 /* prevent from flooding bus error interrupts */ + +#define TX_MAILBOX_COUNT 8 +#define LAST_RX_MB 7 +#define FIRST_TX_MB (LAST_RX_MB + 1) + +/* Common registers */ +#define CAN_MR 0x000 +#define CAN_IER 0x004 +#define CAN_IDR 0x008 +#define CAN_IMR 0x00C +#define CAN_SR 0x010 +#define CAN_BR 0x014 +#define CAN_TIM 0x018 +#define CAN_TIMESTP 0x01C +#define CAN_ECR 0x020 +#define CAN_TCR 0x024 +#define CAN_ACR 0x028 + +/* Mailbox registers (0 <= i <= 15) */ +#define CAN_MMR(i) (0x200 + ((i) * 0x20)) +#define CAN_MAM(i) (0x204 + ((i) * 0x20)) +#define CAN_MID(i) (0x208 + ((i) * 0x20)) +#define CAN_MFID(i) (0x20C + ((i) * 0x20)) +#define CAN_MSR(i) (0x210 + ((i) * 0x20)) +#define CAN_MDL(i) (0x214 + ((i) * 0x20)) +#define CAN_MDH(i) (0x218 + ((i) * 0x20)) +#define CAN_MCR(i) (0x21C + ((i) * 0x20)) + +/* Register bits */ +#define CAN_MR_CANEN (1 << 0) +#define CAN_MR_LPM (1 << 1) +#define CAN_MR_ABM (1 << 2) +#define CAN_MR_OVL (1 << 3) +#define CAN_MR_TEOF (1 << 4) +#define CAN_MR_TTM (1 << 5) +#define CAN_MR_TIMFRZ (1 << 6) +#define CAN_MR_DRPT (1 << 7) + +#define CAN_MID_MIDE (1 << 29) + +#define CAN_MSR_MRTR (1 << 20) +#define CAN_MSR_MRDY (1 << 23) +#define CAN_MSR_MMI (1 << 24) + +#define CAN_MCR_MRTR (1 << 20) +#define CAN_MCR_MTCR (1 << 23) + +/* Mailbox Modes */ +#define MB_MODE_DISABLED 0 +#define MB_MODE_RX 1 +#define MB_MODE_RX_OVRWR 2 +#define MB_MODE_TX 3 +#define MB_MODE_CONSUMER 4 +#define MB_MODE_PRODUCER 5 + +/* Interrupt mask bits */ + +#define CAN_IRQ_MB0 (1 << 0) +#define CAN_IRQ_MB1 (1 << 1) +#define CAN_IRQ_MB2 (1 << 2) +#define CAN_IRQ_MB3 (1 << 3) +#define CAN_IRQ_MB4 (1 << 4) +#define CAN_IRQ_MB5 (1 << 5) +#define CAN_IRQ_MB6 (1 << 6) +#define CAN_IRQ_MB7 (1 << 7) +#define CAN_IRQ_MB8 (1 << 8) +#define CAN_IRQ_MB9 (1 << 9) +#define CAN_IRQ_MB10 (1 << 10) +#define CAN_IRQ_MB11 (1 << 11) +#define CAN_IRQ_MB12 (1 << 12) +#define CAN_IRQ_MB13 (1 << 13) +#define CAN_IRQ_MB14 (1 << 14) +#define CAN_IRQ_MB15 (1 << 15) + +#define CAN_IRQ_MB_TX 0x0000FF00 +#define CAN_IRQ_MB_RX 0x000000FF +#define CAN_IRQ_MB_ALL 0x0000FFFF + +#define CAN_IRQ_ERRA (1 << 16) +#define CAN_IRQ_WARN (1 << 17) +#define CAN_IRQ_ERRP (1 << 18) +#define CAN_IRQ_BOFF (1 << 19) +#define CAN_IRQ_SLEEP (1 << 20) +#define CAN_IRQ_WAKEUP (1 << 21) +#define CAN_IRQ_TOVF (1 << 22) +#define CAN_IRQ_TSTP (1 << 23) +#define CAN_IRQ_CERR (1 << 24) +#define CAN_IRQ_SERR (1 << 25) +#define CAN_IRQ_AERR (1 << 26) +#define CAN_IRQ_FERR (1 << 27) +#define CAN_IRQ_BERR (1 << 28) + + +/* CAN private data structure */ + +enum can_state { + STATE_UNINITIALIZED = 0, + STATE_PROBE, + STATE_ACTIVE, + STATE_ERROR_ACTIVE, + STATE_ERROR_PASSIVE, + STATE_BUS_OFF, + STATE_RESET_MODE, +}; + +struct can_device_stats { + int error_warning; + int data_overrun; + int wakeup; + int bus_error; + int error_passive; + int arbitration_lost; + int restarts; + int bus_error_at_init; +}; + +struct can_priv { + struct net_device_stats stats; + struct can_device_stats can_stats; + struct clk *can_clk; + struct at91_can_data *data; + long open_time; + int clock; + int hw_regs; + int restart_ms; + int debug; + int speed; + int btr; + int rx_probe; + struct timer_list timer; + enum can_state state; + struct sk_buff *loop_skb[TX_MAILBOX_COUNT]; + spinlock_t lock; +}; + +/* Register access macros */ + +#define _at91_can_read(a) ((unsigned long) __raw_readl(a)) +#define _at91_can_write(a, v) __raw_writel((v), (a)) + +#endif /* AT91_CAN_H */ Index: linux-2.6.25-rc/drivers/net/can/Kconfig =================================================================== --- linux-2.6.25-rc.orig/drivers/net/can/Kconfig 2008-02-15 21:56:20.000000000 +0100 +++ linux-2.6.25-rc/drivers/net/can/Kconfig 2008-02-15 21:58:30.000000000 +0100 @@ -22,4 +22,11 @@ a problem with CAN support and want to see more of what is going on. +config CAN_AT91 + tristate "Atmel AT91 onchip CAN controller" + depends on CAN && ARCH_AT91SAM9263 + default N + ---help--- + This is a driver for the SoC CAN controller in Atmel's AT91SAM9263. + endmenu Index: linux-2.6.25-rc/drivers/net/can/Makefile =================================================================== --- linux-2.6.25-rc.orig/drivers/net/can/Makefile 2008-02-15 21:59:50.000000000 +0100 +++ linux-2.6.25-rc/drivers/net/can/Makefile 2008-02-15 22:00:02.000000000 +0100 @@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_VCAN) += vcan.o +obj-$(CONFIG_CAN_AT91) += at91_can.o