diff options
Diffstat (limited to 'drivers/net/can/bfin_can.c')
| -rw-r--r-- | drivers/net/can/bfin_can.c | 309 |
1 files changed, 109 insertions, 200 deletions
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 0ec1524523c..543ecceb33e 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -9,7 +9,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/bitops.h> #include <linux/interrupt.h> @@ -18,98 +17,15 @@ #include <linux/skbuff.h> #include <linux/platform_device.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> +#include <asm/bfin_can.h> #include <asm/portmux.h> #define DRV_NAME "bfin_can" #define BFIN_CAN_TIMEOUT 100 - -/* - * transmit and receive channels - */ -#define TRANSMIT_CHL 24 -#define RECEIVE_STD_CHL 0 -#define RECEIVE_EXT_CHL 4 -#define RECEIVE_RTR_CHL 8 -#define RECEIVE_EXT_RTR_CHL 12 -#define MAX_CHL_NUMBER 32 - -/* - * bfin can registers layout - */ -struct bfin_can_mask_regs { - u16 aml; - u16 dummy1; - u16 amh; - u16 dummy2; -}; - -struct bfin_can_channel_regs { - u16 data[8]; - u16 dlc; - u16 dummy1; - u16 tsv; - u16 dummy2; - u16 id0; - u16 dummy3; - u16 id1; - u16 dummy4; -}; - -struct bfin_can_regs { - /* - * global control and status registers - */ - u16 mc1; /* offset 0 */ - u16 dummy1; - u16 md1; /* offset 4 */ - u16 rsv1[13]; - u16 mbtif1; /* offset 0x20 */ - u16 dummy2; - u16 mbrif1; /* offset 0x24 */ - u16 dummy3; - u16 mbim1; /* offset 0x28 */ - u16 rsv2[11]; - u16 mc2; /* offset 0x40 */ - u16 dummy4; - u16 md2; /* offset 0x44 */ - u16 dummy5; - u16 trs2; /* offset 0x48 */ - u16 rsv3[11]; - u16 mbtif2; /* offset 0x60 */ - u16 dummy6; - u16 mbrif2; /* offset 0x64 */ - u16 dummy7; - u16 mbim2; /* offset 0x68 */ - u16 rsv4[11]; - u16 clk; /* offset 0x80 */ - u16 dummy8; - u16 timing; /* offset 0x84 */ - u16 rsv5[3]; - u16 status; /* offset 0x8c */ - u16 dummy9; - u16 cec; /* offset 0x90 */ - u16 dummy10; - u16 gis; /* offset 0x94 */ - u16 dummy11; - u16 gim; /* offset 0x98 */ - u16 rsv6[3]; - u16 ctrl; /* offset 0xa0 */ - u16 dummy12; - u16 intr; /* offset 0xa4 */ - u16 rsv7[7]; - u16 esr; /* offset 0xb4 */ - u16 rsv8[37]; - - /* - * channel(mailbox) mask and message registers - */ - struct bfin_can_mask_regs msk[MAX_CHL_NUMBER]; /* offset 0x100 */ - struct bfin_can_channel_regs chl[MAX_CHL_NUMBER]; /* offset 0x200 */ -}; +#define TX_ECHO_SKB_MAX 1 /* * bfin can private data @@ -127,7 +43,7 @@ struct bfin_can_priv { /* * bfin can timing parameters */ -static struct can_bittiming_const bfin_can_bittiming_const = { +static const struct can_bittiming_const bfin_can_bittiming_const = { .name = DRV_NAME, .tseg1_min = 1, .tseg1_max = 16, @@ -162,11 +78,10 @@ static int bfin_can_set_bittiming(struct net_device *dev) if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) timing |= SAM; - bfin_write16(®->clk, clk); - bfin_write16(®->timing, timing); + bfin_write(®->clock, clk); + bfin_write(®->timing, timing); - dev_info(dev->dev.parent, "setting CLOCK=0x%04x TIMING=0x%04x\n", - clk, timing); + netdev_info(dev, "setting CLOCK=0x%04x TIMING=0x%04x\n", clk, timing); return 0; } @@ -179,20 +94,19 @@ static void bfin_can_set_reset_mode(struct net_device *dev) int i; /* disable interrupts */ - bfin_write16(®->mbim1, 0); - bfin_write16(®->mbim2, 0); - bfin_write16(®->gim, 0); + bfin_write(®->mbim1, 0); + bfin_write(®->mbim2, 0); + bfin_write(®->gim, 0); /* reset can and enter configuration mode */ - bfin_write16(®->ctrl, SRS | CCR); + bfin_write(®->control, SRS | CCR); SSYNC(); - bfin_write16(®->ctrl, CCR); + bfin_write(®->control, CCR); SSYNC(); - while (!(bfin_read16(®->ctrl) & CCA)) { + while (!(bfin_read(®->control) & CCA)) { udelay(10); if (--timeout == 0) { - dev_err(dev->dev.parent, - "fail to enter configuration mode\n"); + netdev_err(dev, "fail to enter configuration mode\n"); BUG(); } } @@ -202,33 +116,33 @@ static void bfin_can_set_reset_mode(struct net_device *dev) * by writing to CAN Mailbox Configuration Registers 1 and 2 * For all bits: 0 - Mailbox disabled, 1 - Mailbox enabled */ - bfin_write16(®->mc1, 0); - bfin_write16(®->mc2, 0); + bfin_write(®->mc1, 0); + bfin_write(®->mc2, 0); /* Set Mailbox Direction */ - bfin_write16(®->md1, 0xFFFF); /* mailbox 1-16 are RX */ - bfin_write16(®->md2, 0); /* mailbox 17-32 are TX */ + bfin_write(®->md1, 0xFFFF); /* mailbox 1-16 are RX */ + bfin_write(®->md2, 0); /* mailbox 17-32 are TX */ /* RECEIVE_STD_CHL */ for (i = 0; i < 2; i++) { - bfin_write16(®->chl[RECEIVE_STD_CHL + i].id0, 0); - bfin_write16(®->chl[RECEIVE_STD_CHL + i].id1, AME); - bfin_write16(®->chl[RECEIVE_STD_CHL + i].dlc, 0); - bfin_write16(®->msk[RECEIVE_STD_CHL + i].amh, 0x1FFF); - bfin_write16(®->msk[RECEIVE_STD_CHL + i].aml, 0xFFFF); + bfin_write(®->chl[RECEIVE_STD_CHL + i].id0, 0); + bfin_write(®->chl[RECEIVE_STD_CHL + i].id1, AME); + bfin_write(®->chl[RECEIVE_STD_CHL + i].dlc, 0); + bfin_write(®->msk[RECEIVE_STD_CHL + i].amh, 0x1FFF); + bfin_write(®->msk[RECEIVE_STD_CHL + i].aml, 0xFFFF); } /* RECEIVE_EXT_CHL */ for (i = 0; i < 2; i++) { - bfin_write16(®->chl[RECEIVE_EXT_CHL + i].id0, 0); - bfin_write16(®->chl[RECEIVE_EXT_CHL + i].id1, AME | IDE); - bfin_write16(®->chl[RECEIVE_EXT_CHL + i].dlc, 0); - bfin_write16(®->msk[RECEIVE_EXT_CHL + i].amh, 0x1FFF); - bfin_write16(®->msk[RECEIVE_EXT_CHL + i].aml, 0xFFFF); + bfin_write(®->chl[RECEIVE_EXT_CHL + i].id0, 0); + bfin_write(®->chl[RECEIVE_EXT_CHL + i].id1, AME | IDE); + bfin_write(®->chl[RECEIVE_EXT_CHL + i].dlc, 0); + bfin_write(®->msk[RECEIVE_EXT_CHL + i].amh, 0x1FFF); + bfin_write(®->msk[RECEIVE_EXT_CHL + i].aml, 0xFFFF); } - bfin_write16(®->mc2, BIT(TRANSMIT_CHL - 16)); - bfin_write16(®->mc1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL)); + bfin_write(®->mc2, BIT(TRANSMIT_CHL - 16)); + bfin_write(®->mc1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL)); SSYNC(); priv->can.state = CAN_STATE_STOPPED; @@ -243,13 +157,12 @@ static void bfin_can_set_normal_mode(struct net_device *dev) /* * leave configuration mode */ - bfin_write16(®->ctrl, bfin_read16(®->ctrl) & ~CCR); + bfin_write(®->control, bfin_read(®->control) & ~CCR); - while (bfin_read16(®->status) & CCA) { + while (bfin_read(®->status) & CCA) { udelay(10); if (--timeout == 0) { - dev_err(dev->dev.parent, - "fail to leave configuration mode\n"); + netdev_err(dev, "fail to leave configuration mode\n"); BUG(); } } @@ -257,25 +170,25 @@ static void bfin_can_set_normal_mode(struct net_device *dev) /* * clear _All_ tx and rx interrupts */ - bfin_write16(®->mbtif1, 0xFFFF); - bfin_write16(®->mbtif2, 0xFFFF); - bfin_write16(®->mbrif1, 0xFFFF); - bfin_write16(®->mbrif2, 0xFFFF); + bfin_write(®->mbtif1, 0xFFFF); + bfin_write(®->mbtif2, 0xFFFF); + bfin_write(®->mbrif1, 0xFFFF); + bfin_write(®->mbrif2, 0xFFFF); /* * clear global interrupt status register */ - bfin_write16(®->gis, 0x7FF); /* overwrites with '1' */ + bfin_write(®->gis, 0x7FF); /* overwrites with '1' */ /* * Initialize Interrupts * - set bits in the mailbox interrupt mask register * - global interrupt mask */ - bfin_write16(®->mbim1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL)); - bfin_write16(®->mbim2, BIT(TRANSMIT_CHL - 16)); + bfin_write(®->mbim1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL)); + bfin_write(®->mbim2, BIT(TRANSMIT_CHL - 16)); - bfin_write16(®->gim, EPIM | BOIM | RMLIM); + bfin_write(®->gim, EPIM | BOIM | RMLIM); SSYNC(); } @@ -307,6 +220,20 @@ static int bfin_can_set_mode(struct net_device *dev, enum can_mode mode) return 0; } +static int bfin_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct bfin_can_priv *priv = netdev_priv(dev); + struct bfin_can_regs __iomem *reg = priv->membase; + + u16 cec = bfin_read(®->cec); + + bec->txerr = cec >> 8; + bec->rxerr = cec; + + return 0; +} + static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bfin_can_priv *priv = netdev_priv(dev); @@ -318,43 +245,35 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev) u16 val; int i; + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + netif_stop_queue(dev); /* fill id */ if (id & CAN_EFF_FLAG) { - bfin_write16(®->chl[TRANSMIT_CHL].id0, id); - if (id & CAN_RTR_FLAG) - writew(((id & 0x1FFF0000) >> 16) | IDE | AME | RTR, - ®->chl[TRANSMIT_CHL].id1); - else - writew(((id & 0x1FFF0000) >> 16) | IDE | AME, - ®->chl[TRANSMIT_CHL].id1); - - } else { - if (id & CAN_RTR_FLAG) - writew((id << 2) | AME | RTR, - ®->chl[TRANSMIT_CHL].id1); - else - bfin_write16(®->chl[TRANSMIT_CHL].id1, - (id << 2) | AME); - } + bfin_write(®->chl[TRANSMIT_CHL].id0, id); + val = ((id & 0x1FFF0000) >> 16) | IDE; + } else + val = (id << 2); + if (id & CAN_RTR_FLAG) + val |= RTR; + bfin_write(®->chl[TRANSMIT_CHL].id1, val | AME); /* fill payload */ for (i = 0; i < 8; i += 2) { val = ((7 - i) < dlc ? (data[7 - i]) : 0) + ((6 - i) < dlc ? (data[6 - i] << 8) : 0); - bfin_write16(®->chl[TRANSMIT_CHL].data[i], val); + bfin_write(®->chl[TRANSMIT_CHL].data[i], val); } /* fill data length code */ - bfin_write16(®->chl[TRANSMIT_CHL].dlc, dlc); - - dev->trans_start = jiffies; + bfin_write(®->chl[TRANSMIT_CHL].dlc, dlc); can_put_echo_skb(skb, dev, 0); /* set transmit request */ - bfin_write16(®->trs2, BIT(TRANSMIT_CHL - 16)); + bfin_write(®->trs2, BIT(TRANSMIT_CHL - 16)); return 0; } @@ -377,26 +296,26 @@ static void bfin_can_rx(struct net_device *dev, u16 isrc) /* get id */ if (isrc & BIT(RECEIVE_EXT_CHL)) { /* extended frame format (EFF) */ - cf->can_id = ((bfin_read16(®->chl[RECEIVE_EXT_CHL].id1) + cf->can_id = ((bfin_read(®->chl[RECEIVE_EXT_CHL].id1) & 0x1FFF) << 16) - + bfin_read16(®->chl[RECEIVE_EXT_CHL].id0); + + bfin_read(®->chl[RECEIVE_EXT_CHL].id0); cf->can_id |= CAN_EFF_FLAG; obj = RECEIVE_EXT_CHL; } else { /* standard frame format (SFF) */ - cf->can_id = (bfin_read16(®->chl[RECEIVE_STD_CHL].id1) + cf->can_id = (bfin_read(®->chl[RECEIVE_STD_CHL].id1) & 0x1ffc) >> 2; obj = RECEIVE_STD_CHL; } - if (bfin_read16(®->chl[obj].id1) & RTR) + if (bfin_read(®->chl[obj].id1) & RTR) cf->can_id |= CAN_RTR_FLAG; /* get data length code */ - cf->can_dlc = get_can_dlc(bfin_read16(®->chl[obj].dlc) & 0xF); + cf->can_dlc = get_can_dlc(bfin_read(®->chl[obj].dlc) & 0xF); /* get payload */ for (i = 0; i < 8; i += 2) { - val = bfin_read16(®->chl[obj].data[i]); + val = bfin_read(®->chl[obj].data[i]); cf->data[7 - i] = (7 - i) < cf->can_dlc ? val : 0; cf->data[6 - i] = (6 - i) < cf->can_dlc ? (val >> 8) : 0; } @@ -422,7 +341,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) if (isrc & RMLIS) { /* data overrun interrupt */ - dev_dbg(dev->dev.parent, "data overrun interrupt\n"); + netdev_dbg(dev, "data overrun interrupt\n"); cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; @@ -430,7 +349,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) } if (isrc & BOIS) { - dev_dbg(dev->dev.parent, "bus-off mode interrupt\n"); + netdev_dbg(dev, "bus-off mode interrupt\n"); state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; can_bus_off(dev); @@ -438,19 +357,18 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) if (isrc & EPIS) { /* error passive interrupt */ - dev_dbg(dev->dev.parent, "error passive interrupt\n"); + netdev_dbg(dev, "error passive interrupt\n"); state = CAN_STATE_ERROR_PASSIVE; } if ((isrc & EWTIS) || (isrc & EWRIS)) { - dev_dbg(dev->dev.parent, - "Error Warning Transmit/Receive Interrupt\n"); + netdev_dbg(dev, "Error Warning Transmit/Receive Interrupt\n"); state = CAN_STATE_ERROR_WARNING; } if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE)) { - u16 cec = bfin_read16(®->cec); + u16 cec = bfin_read(®->cec); u8 rxerr = cec; u8 txerr = cec >> 8; @@ -493,7 +411,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) return 0; } -irqreturn_t bfin_can_interrupt(int irq, void *dev_id) +static irqreturn_t bfin_can_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct bfin_can_priv *priv = netdev_priv(dev); @@ -501,23 +419,23 @@ irqreturn_t bfin_can_interrupt(int irq, void *dev_id) struct net_device_stats *stats = &dev->stats; u16 status, isrc; - if ((irq == priv->tx_irq) && bfin_read16(®->mbtif2)) { + if ((irq == priv->tx_irq) && bfin_read(®->mbtif2)) { /* transmission complete interrupt */ - bfin_write16(®->mbtif2, 0xFFFF); + bfin_write(®->mbtif2, 0xFFFF); stats->tx_packets++; - stats->tx_bytes += bfin_read16(®->chl[TRANSMIT_CHL].dlc); + stats->tx_bytes += bfin_read(®->chl[TRANSMIT_CHL].dlc); can_get_echo_skb(dev, 0); netif_wake_queue(dev); - } else if ((irq == priv->rx_irq) && bfin_read16(®->mbrif1)) { + } else if ((irq == priv->rx_irq) && bfin_read(®->mbrif1)) { /* receive interrupt */ - isrc = bfin_read16(®->mbrif1); - bfin_write16(®->mbrif1, 0xFFFF); + isrc = bfin_read(®->mbrif1); + bfin_write(®->mbrif1, 0xFFFF); bfin_can_rx(dev, isrc); - } else if ((irq == priv->err_irq) && bfin_read16(®->gis)) { + } else if ((irq == priv->err_irq) && bfin_read(®->gis)) { /* error interrupt */ - isrc = bfin_read16(®->gis); - status = bfin_read16(®->esr); - bfin_write16(®->gis, 0x7FF); + isrc = bfin_read(®->gis); + status = bfin_read(®->esr); + bfin_write(®->gis, 0x7FF); bfin_can_err(dev, isrc, status); } else { return IRQ_NONE; @@ -585,12 +503,12 @@ static int bfin_can_close(struct net_device *dev) return 0; } -struct net_device *alloc_bfin_candev(void) +static struct net_device *alloc_bfin_candev(void) { struct net_device *dev; struct bfin_can_priv *priv; - dev = alloc_candev(sizeof(*priv)); + dev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX); if (!dev) return NULL; @@ -600,6 +518,8 @@ struct net_device *alloc_bfin_candev(void) priv->can.bittiming_const = &bfin_can_bittiming_const; priv->can.do_set_bittiming = bfin_can_set_bittiming; priv->can.do_set_mode = bfin_can_set_mode; + priv->can.do_get_berr_counter = bfin_can_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; return dev; } @@ -608,9 +528,10 @@ static const struct net_device_ops bfin_can_netdev_ops = { .ndo_open = bfin_can_open, .ndo_stop = bfin_can_close, .ndo_start_xmit = bfin_can_start_xmit, + .ndo_change_mtu = can_change_mtu, }; -static int __devinit bfin_can_probe(struct platform_device *pdev) +static int bfin_can_probe(struct platform_device *pdev) { int err; struct net_device *dev; @@ -618,7 +539,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev) struct resource *res_mem, *rx_irq, *tx_irq, *err_irq; unsigned short *pdata; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data provided!\n"); err = -EINVAL; @@ -659,7 +580,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev) priv->pin_list = pdata; priv->can.clock.freq = get_sclk(); - dev_set_drvdata(&pdev->dev, dev); + platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->flags |= IFF_ECHO; /* we support local echo */ @@ -676,7 +597,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s device registered" "(®_base=%p, rx_irq=%d, tx_irq=%d, err_irq=%d, sclk=%d)\n", - DRV_NAME, (void *)priv->membase, priv->rx_irq, + DRV_NAME, priv->membase, priv->rx_irq, priv->tx_irq, priv->err_irq, priv->can.clock.freq); return 0; @@ -690,9 +611,9 @@ exit: return err; } -static int __devexit bfin_can_remove(struct platform_device *pdev) +static int bfin_can_remove(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct bfin_can_priv *priv = netdev_priv(dev); struct resource *res; @@ -700,8 +621,6 @@ static int __devexit bfin_can_remove(struct platform_device *pdev) 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)); @@ -714,20 +633,19 @@ static int __devexit bfin_can_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct bfin_can_priv *priv = netdev_priv(dev); struct bfin_can_regs __iomem *reg = priv->membase; int timeout = BFIN_CAN_TIMEOUT; if (netif_running(dev)) { /* enter sleep mode */ - bfin_write16(®->ctrl, bfin_read16(®->ctrl) | SMR); + bfin_write(®->control, bfin_read(®->control) | SMR); SSYNC(); - while (!(bfin_read16(®->intr) & SMACK)) { + while (!(bfin_read(®->intr) & SMACK)) { udelay(10); if (--timeout == 0) { - dev_err(dev->dev.parent, - "fail to enter sleep mode\n"); + netdev_err(dev, "fail to enter sleep mode\n"); BUG(); } } @@ -738,13 +656,13 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) static int bfin_can_resume(struct platform_device *pdev) { - struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct net_device *dev = platform_get_drvdata(pdev); struct bfin_can_priv *priv = netdev_priv(dev); struct bfin_can_regs __iomem *reg = priv->membase; if (netif_running(dev)) { /* leave sleep mode */ - bfin_write16(®->intr, 0); + bfin_write(®->intr, 0); SSYNC(); } @@ -757,7 +675,7 @@ static int bfin_can_resume(struct platform_device *pdev) static struct platform_driver bfin_can_driver = { .probe = bfin_can_probe, - .remove = __devexit_p(bfin_can_remove), + .remove = bfin_can_remove, .suspend = bfin_can_suspend, .resume = bfin_can_resume, .driver = { @@ -766,18 +684,9 @@ static struct platform_driver bfin_can_driver = { }, }; -static int __init bfin_can_init(void) -{ - return platform_driver_register(&bfin_can_driver); -} -module_init(bfin_can_init); - -static void __exit bfin_can_exit(void) -{ - platform_driver_unregister(&bfin_can_driver); -} -module_exit(bfin_can_exit); +module_platform_driver(bfin_can_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Blackfin on-chip CAN netdevice driver"); +MODULE_ALIAS("platform:" DRV_NAME); |
