diff options
Diffstat (limited to 'drivers/net/can/sja1000')
-rw-r--r-- | drivers/net/can/sja1000/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/ems_pci.c | 39 | ||||
-rw-r--r-- | drivers/net/can/sja1000/kvaser_pci.c | 21 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000.c | 110 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000.h | 9 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_of_platform.c | 235 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_platform.c | 19 |
7 files changed, 332 insertions, 102 deletions
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index d6c631f9e665..9d0c08da273c 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o +obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 3cd2ff9165e3..121b64101d72 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -99,25 +99,21 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl); */ static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) { - return readb((void __iomem *)card->base_addr - + (port * EMS_PCI_PORT_BYTES)); + return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES)); } -static u8 ems_pci_read_reg(const struct net_device *dev, int port) +static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port) { - return readb((void __iomem *)dev->base_addr - + (port * EMS_PCI_PORT_BYTES)); + return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES)); } -static void ems_pci_write_reg(const struct net_device *dev, int port, u8 val) +static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) { - writeb(val, (void __iomem *)dev->base_addr - + (port * EMS_PCI_PORT_BYTES)); + writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES)); } -static void ems_pci_post_irq(const struct net_device *dev) +static void ems_pci_post_irq(const struct sja1000_priv *priv) { - struct sja1000_priv *priv = netdev_priv(dev); struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; /* reset int flag of pita */ @@ -129,17 +125,17 @@ static void ems_pci_post_irq(const struct net_device *dev) * Check if a CAN controller is present at the specified location * by trying to set 'em into the PeliCAN mode */ -static inline int ems_pci_check_chan(struct net_device *dev) +static inline int ems_pci_check_chan(const struct sja1000_priv *priv) { unsigned char res; /* Make sure SJA1000 is in reset mode */ - ems_pci_write_reg(dev, REG_MOD, 1); + ems_pci_write_reg(priv, REG_MOD, 1); - ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN); + ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN); /* read reset-values */ - res = ems_pci_read_reg(dev, REG_CDR); + res = ems_pci_read_reg(priv, REG_CDR); if (res == CDR_PELICAN) return 1; @@ -218,14 +214,12 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); if (card->conf_addr == NULL) { err = -ENOMEM; - goto failure_cleanup; } card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); if (card->base_addr == NULL) { err = -ENOMEM; - goto failure_cleanup; } @@ -239,7 +233,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, ems_pci_readb(card, 3) != 0xCB || ems_pci_readb(card, 4) != 0x11) { dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); - err = -ENODEV; goto failure_cleanup; } @@ -260,12 +253,11 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, priv->irq_flags = IRQF_SHARED; dev->irq = pdev->irq; - dev->base_addr = (unsigned long)(card->base_addr - + EMS_PCI_CAN_BASE_OFFSET - + (i * EMS_PCI_CAN_CTRL_SIZE)); + priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET + + (i * EMS_PCI_CAN_CTRL_SIZE); /* Check if channel is present */ - if (ems_pci_check_chan(dev)) { + if (ems_pci_check_chan(priv)) { priv->read_reg = ems_pci_read_reg; priv->write_reg = ems_pci_write_reg; priv->post_irq = ems_pci_post_irq; @@ -289,9 +281,8 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->channels++; - dev_info(&pdev->dev, "Channel #%d at %#lX, irq %d\n", - i + 1, dev->base_addr, - dev->irq); + dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n", + i + 1, priv->reg_base, dev->irq); } else { free_sja1000dev(dev); } diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index 00830b358c4f..7dd7769b9713 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -117,14 +117,15 @@ static struct pci_device_id kvaser_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl); -static u8 kvaser_pci_read_reg(const struct net_device *dev, int port) +static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port) { - return ioread8((void __iomem *)(dev->base_addr + port)); + return ioread8(priv->reg_base + port); } -static void kvaser_pci_write_reg(const struct net_device *dev, int port, u8 val) +static void kvaser_pci_write_reg(const struct sja1000_priv *priv, + int port, u8 val) { - iowrite8(val, (void __iomem *)(dev->base_addr + port)); + iowrite8(val, priv->reg_base + port); } static void kvaser_pci_disable_irq(struct net_device *dev) @@ -199,7 +200,7 @@ static void kvaser_pci_del_chan(struct net_device *dev) } unregister_sja1000dev(dev); - pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr); + pci_iounmap(board->pci_dev, priv->reg_base); pci_iounmap(board->pci_dev, board->conf_addr); pci_iounmap(board->pci_dev, board->res_addr); @@ -210,7 +211,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, struct net_device **master_dev, void __iomem *conf_addr, void __iomem *res_addr, - unsigned long base_addr) + void __iomem *base_addr) { struct net_device *dev; struct sja1000_priv *priv; @@ -252,7 +253,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, board->xilinx_ver = master_board->xilinx_ver; } - dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES; + priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES; priv->read_reg = kvaser_pci_read_reg; priv->write_reg = kvaser_pci_write_reg; @@ -267,8 +268,8 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, init_step = 4; - dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n", - dev->base_addr, board->conf_addr, dev->irq); + dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n", + priv->reg_base, board->conf_addr, dev->irq); SET_NETDEV_DEV(dev, &pdev->dev); @@ -343,7 +344,7 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev, for (i = 0; i < no_channels; i++) { err = kvaser_pci_add_chan(pdev, i, &master_dev, conf_addr, res_addr, - (unsigned long)base_addr); + base_addr); if (err) goto failure_cleanup; } diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 05b38dde648e..571f133a8fec 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -89,7 +89,7 @@ static int sja1000_probe_chip(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) { + if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) { printk(KERN_INFO "%s: probing @0x%lX failed\n", DRV_NAME, dev->base_addr); return 0; @@ -100,11 +100,11 @@ static int sja1000_probe_chip(struct net_device *dev) static void set_reset_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(dev, REG_MOD); + unsigned char status = priv->read_reg(priv, REG_MOD); int i; /* disable interrupts */ - priv->write_reg(dev, REG_IER, IRQ_OFF); + priv->write_reg(priv, REG_IER, IRQ_OFF); for (i = 0; i < 100; i++) { /* check reset bit */ @@ -113,9 +113,9 @@ static void set_reset_mode(struct net_device *dev) return; } - priv->write_reg(dev, REG_MOD, MOD_RM); /* reset chip */ + priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */ udelay(10); - status = priv->read_reg(dev, REG_MOD); + status = priv->read_reg(priv, REG_MOD); } dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n"); @@ -124,7 +124,7 @@ static void set_reset_mode(struct net_device *dev) static void set_normal_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(dev, REG_MOD); + unsigned char status = priv->read_reg(priv, REG_MOD); int i; for (i = 0; i < 100; i++) { @@ -132,14 +132,14 @@ static void set_normal_mode(struct net_device *dev) if ((status & MOD_RM) == 0) { priv->can.state = CAN_STATE_ERROR_ACTIVE; /* enable all interrupts */ - priv->write_reg(dev, REG_IER, IRQ_ALL); + priv->write_reg(priv, REG_IER, IRQ_ALL); return; } /* set chip to normal mode */ - priv->write_reg(dev, REG_MOD, 0x00); + priv->write_reg(priv, REG_MOD, 0x00); udelay(10); - status = priv->read_reg(dev, REG_MOD); + status = priv->read_reg(priv, REG_MOD); } dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n"); @@ -154,9 +154,9 @@ static void sja1000_start(struct net_device *dev) set_reset_mode(dev); /* Clear error counters and error code capture */ - priv->write_reg(dev, REG_TXERR, 0x0); - priv->write_reg(dev, REG_RXERR, 0x0); - priv->read_reg(dev, REG_ECC); + priv->write_reg(priv, REG_TXERR, 0x0); + priv->write_reg(priv, REG_RXERR, 0x0); + priv->read_reg(priv, REG_ECC); /* leave reset mode */ set_normal_mode(dev); @@ -198,8 +198,8 @@ static int sja1000_set_bittiming(struct net_device *dev) dev_info(dev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); - priv->write_reg(dev, REG_BTR0, btr0); - priv->write_reg(dev, REG_BTR1, btr1); + priv->write_reg(priv, REG_BTR0, btr0); + priv->write_reg(priv, REG_BTR1, btr1); return 0; } @@ -217,20 +217,20 @@ static void chipset_init(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); /* set clock divider and output control register */ - priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN); + priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN); /* set acceptance filter (accept all) */ - priv->write_reg(dev, REG_ACCC0, 0x00); - priv->write_reg(dev, REG_ACCC1, 0x00); - priv->write_reg(dev, REG_ACCC2, 0x00); - priv->write_reg(dev, REG_ACCC3, 0x00); + priv->write_reg(priv, REG_ACCC0, 0x00); + priv->write_reg(priv, REG_ACCC1, 0x00); + priv->write_reg(priv, REG_ACCC2, 0x00); + priv->write_reg(priv, REG_ACCC3, 0x00); - priv->write_reg(dev, REG_ACCM0, 0xFF); - priv->write_reg(dev, REG_ACCM1, 0xFF); - priv->write_reg(dev, REG_ACCM2, 0xFF); - priv->write_reg(dev, REG_ACCM3, 0xFF); + priv->write_reg(priv, REG_ACCM0, 0xFF); + priv->write_reg(priv, REG_ACCM1, 0xFF); + priv->write_reg(priv, REG_ACCM2, 0xFF); + priv->write_reg(priv, REG_ACCM3, 0xFF); - priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL); + priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL); } /* @@ -261,27 +261,27 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) if (id & CAN_EFF_FLAG) { fi |= FI_FF; dreg = EFF_BUF; - priv->write_reg(dev, REG_FI, fi); - priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); - priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8)); - priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5); - priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3); + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); + priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8)); + priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5); + priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3); } else { dreg = SFF_BUF; - priv->write_reg(dev, REG_FI, fi); - priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3); - priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5); + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3); + priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5); } for (i = 0; i < dlc; i++) - priv->write_reg(dev, dreg++, cf->data[i]); + priv->write_reg(priv, dreg++, cf->data[i]); stats->tx_bytes += dlc; dev->trans_start = jiffies; can_put_echo_skb(skb, dev, 0); - priv->write_reg(dev, REG_CMR, CMD_TR); + priv->write_reg(priv, REG_CMR, CMD_TR); return 0; } @@ -304,22 +304,22 @@ static void sja1000_rx(struct net_device *dev) skb->dev = dev; skb->protocol = htons(ETH_P_CAN); - fi = priv->read_reg(dev, REG_FI); + fi = priv->read_reg(priv, REG_FI); dlc = fi & 0x0F; if (fi & FI_FF) { /* extended frame format (EFF) */ dreg = EFF_BUF; - id = (priv->read_reg(dev, REG_ID1) << (5 + 16)) - | (priv->read_reg(dev, REG_ID2) << (5 + 8)) - | (priv->read_reg(dev, REG_ID3) << 5) - | (priv->read_reg(dev, REG_ID4) >> 3); + id = (priv->read_reg(priv, REG_ID1) << (5 + 16)) + | (priv->read_reg(priv, REG_ID2) << (5 + 8)) + | (priv->read_reg(priv, REG_ID3) << 5) + | (priv->read_reg(priv, REG_ID4) >> 3); id |= CAN_EFF_FLAG; } else { /* standard frame format (SFF) */ dreg = SFF_BUF; - id = (priv->read_reg(dev, REG_ID1) << 3) - | (priv->read_reg(dev, REG_ID2) >> 5); + id = (priv->read_reg(priv, REG_ID1) << 3) + | (priv->read_reg(priv, REG_ID2) >> 5); } if (fi & FI_RTR) @@ -330,13 +330,13 @@ static void sja1000_rx(struct net_device *dev) cf->can_id = id; cf->can_dlc = dlc; for (i = 0; i < dlc; i++) - cf->data[i] = priv->read_reg(dev, dreg++); + cf->data[i] = priv->read_reg(priv, dreg++); while (i < 8) cf->data[i++] = 0; /* release receive buffer */ - priv->write_reg(dev, REG_CMR, CMD_RRB); + priv->write_reg(priv, REG_CMR, CMD_RRB); netif_rx(skb); @@ -371,7 +371,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */ + priv->write_reg(priv, REG_CMR, CMD_CDO); /* clear bit */ } if (isrc & IRQ_EI) { @@ -392,7 +392,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) priv->can.can_stats.bus_error++; stats->rx_errors++; - ecc = priv->read_reg(dev, REG_ECC); + ecc = priv->read_reg(priv, REG_ECC); cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; @@ -426,7 +426,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (isrc & IRQ_ALI) { /* arbitration lost interrupt */ dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); - alc = priv->read_reg(dev, REG_ALC); + alc = priv->read_reg(priv, REG_ALC); priv->can.can_stats.arbitration_lost++; stats->rx_errors++; cf->can_id |= CAN_ERR_LOSTARB; @@ -435,8 +435,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE)) { - uint8_t rxerr = priv->read_reg(dev, REG_RXERR); - uint8_t txerr = priv->read_reg(dev, REG_TXERR); + uint8_t rxerr = priv->read_reg(priv, REG_RXERR); + uint8_t txerr = priv->read_reg(priv, REG_TXERR); cf->can_id |= CAN_ERR_CRTL; if (state == CAN_STATE_ERROR_WARNING) { priv->can.can_stats.error_warning++; @@ -471,15 +471,15 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) int n = 0; /* Shared interrupts and IRQ off? */ - if (priv->read_reg(dev, REG_IER) == IRQ_OFF) + if (priv->read_reg(priv, REG_IER) == IRQ_OFF) return IRQ_NONE; if (priv->pre_irq) - priv->pre_irq(dev); + priv->pre_irq(priv); - while ((isrc = priv->read_reg(dev, REG_IR)) && (n < SJA1000_MAX_IRQ)) { + while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) { n++; - status = priv->read_reg(dev, REG_SR); + status = priv->read_reg(priv, REG_SR); if (isrc & IRQ_WUI) dev_warn(dev->dev.parent, "wakeup interrupt\n"); @@ -494,7 +494,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) /* receive interrupt */ while (status & SR_RBS) { sja1000_rx(dev); - status = priv->read_reg(dev, REG_SR); + status = priv->read_reg(priv, REG_SR); } } if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { @@ -505,7 +505,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) } if (priv->post_irq) - priv->post_irq(dev); + priv->post_irq(priv); if (n >= SJA1000_MAX_IRQ) dev_dbg(dev->dev.parent, "%d messages handled in ISR", n); @@ -532,8 +532,8 @@ static int sja1000_open(struct net_device *dev) err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags, dev->name, (void *)dev); if (err) { - return -EAGAIN; close_candev(dev); + return -EAGAIN; } } diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index ccd302887964..302d2c763ad7 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -155,14 +155,15 @@ struct sja1000_priv { struct sk_buff *echo_skb; /* the lower-layer is responsible for appropriate locking */ - u8 (*read_reg) (const struct net_device *dev, int reg); - void (*write_reg) (const struct net_device *dev, int reg, u8 val); - void (*pre_irq) (const struct net_device *dev); - void (*post_irq) (const struct net_device *dev); + u8 (*read_reg) (const struct sja1000_priv *priv, int reg); + void (*write_reg) (const struct sja1000_priv *priv, int reg, u8 val); + void (*pre_irq) (const struct sja1000_priv *priv); + void (*post_irq) (const struct sja1000_priv *priv); void *priv; /* for board-specific data */ struct net_device *dev; + void __iomem *reg_base; /* ioremap'ed address to registers */ unsigned long irq_flags; /* for request_irq() */ u16 flags; /* custom mode flags */ diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c new file mode 100644 index 000000000000..3373560405ba --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -0,0 +1,235 @@ +/* + * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus + * + * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This is a generic driver for SJA1000 chips on the OpenFirmware platform + * bus found on embedded PowerPC systems. You need a SJA1000 CAN node + * definition in your flattened device tree source (DTS) file similar to: + * + * can@3,100 { + * compatible = "nxp,sja1000"; + * reg = <3 0x100 0x80>; + * interrupts = <2 0>; + * interrupt-parent = <&mpic>; + * nxp,external-clock-frequency = <16000000>; + * }; + * + * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further + * information. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/can.h> +#include <linux/can/dev.h> + +#include <linux/of_platform.h> +#include <asm/prom.h> + +#include "sja1000.h" + +#define DRV_NAME "sja1000_of_platform" + +MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); +MODULE_LICENSE("GPL v2"); + +#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) + +#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN +#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) + +static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) +{ + return in_8(priv->reg_base + reg); +} + +static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + out_8(priv->reg_base + reg, val); +} + +static int __devexit sja1000_ofp_remove(struct of_device *ofdev) +{ + struct net_device *dev = dev_get_drvdata(&ofdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); + struct device_node *np = ofdev->node; + struct resource res; + + dev_set_drvdata(&ofdev->dev, NULL); + + unregister_sja1000dev(dev); + free_sja1000dev(dev); + iounmap(priv->reg_base); + irq_dispose_mapping(dev->irq); + + of_address_to_resource(np, 0, &res); + release_mem_region(res.start, resource_size(&res)); + + return 0; +} + +static int __devinit sja1000_ofp_probe(struct of_device *ofdev, + const struct of_device_id *id) +{ + struct device_node *np = ofdev->node; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource res; + const u32 *prop; + int err, irq, res_size, prop_size; + void __iomem *base; + + err = of_address_to_resource(np, 0, &res); + if (err) { + dev_err(&ofdev->dev, "invalid address\n"); + return err; + } + + res_size = resource_size(&res); + + if (!request_mem_region(res.start, res_size, DRV_NAME)) { + dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + return -EBUSY; + } + + base = ioremap_nocache(res.start, res_size); + if (!base) { + dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + err = -ENOMEM; + goto exit_release_mem; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + dev_err(&ofdev->dev, "no irq found\n"); + err = -ENODEV; + goto exit_unmap_mem; + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_dispose_irq; + } + + priv = netdev_priv(dev); + + priv->read_reg = sja1000_ofp_read_reg; + priv->write_reg = sja1000_ofp_write_reg; + + prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->can.clock.freq = *prop / 2; + else + priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ + + prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= *prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + prop = of_get_property(np, "nxp,tx-output-config", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32)) && *prop) { + u32 divider = priv->can.clock.freq * 2 / *prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); + if (!prop) + priv->cdr |= CDR_CBP; /* default */ + + priv->irq_flags = IRQF_SHARED; + priv->reg_base = base; + + dev->irq = irq; + + dev_info(&ofdev->dev, + "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", + priv->reg_base, dev->irq, priv->can.clock.freq, + priv->ocr, priv->cdr); + + dev_set_drvdata(&ofdev->dev, dev); + SET_NETDEV_DEV(dev, &ofdev->dev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free_sja1000; + } + + return 0; + +exit_free_sja1000: + free_sja1000dev(dev); +exit_dispose_irq: + irq_dispose_mapping(irq); +exit_unmap_mem: + iounmap(base); +exit_release_mem: + release_mem_region(res.start, res_size); + + return err; +} + +static struct of_device_id __devinitdata sja1000_ofp_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; + +static struct of_platform_driver sja1000_ofp_driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .probe = sja1000_ofp_probe, + .remove = __devexit_p(sja1000_ofp_remove), + .match_table = sja1000_ofp_table, +}; + +static int __init sja1000_ofp_init(void) +{ + return of_register_platform_driver(&sja1000_ofp_driver); +} +module_init(sja1000_ofp_init); + +static void __exit sja1000_ofp_exit(void) +{ + return of_unregister_platform_driver(&sja1000_ofp_driver); +}; +module_exit(sja1000_ofp_exit); diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 8017229d6fd6..628374c2a05f 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -37,14 +37,14 @@ MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); MODULE_LICENSE("GPL v2"); -static u8 sp_read_reg(const struct net_device *dev, int reg) +static u8 sp_read_reg(const struct sja1000_priv *priv, int reg) { - return ioread8((void __iomem *)(dev->base_addr + reg)); + return ioread8(priv->reg_base + reg); } -static void sp_write_reg(const struct net_device *dev, int reg, u8 val) +static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val) { - iowrite8(val, (void __iomem *)(dev->base_addr + reg)); + iowrite8(val, priv->reg_base + reg); } static int sp_probe(struct platform_device *pdev) @@ -89,9 +89,9 @@ static int sp_probe(struct platform_device *pdev) } priv = netdev_priv(dev); - dev->base_addr = (unsigned long)addr; dev->irq = res_irq->start; priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + priv->reg_base = addr; priv->read_reg = sp_read_reg; priv->write_reg = sp_write_reg; priv->can.clock.freq = pdata->clock; @@ -108,8 +108,8 @@ static int sp_probe(struct platform_device *pdev) goto exit_free; } - dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n", - DRV_NAME, dev->base_addr, dev->irq); + dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n", + DRV_NAME, priv->reg_base, dev->irq); return 0; exit_free: @@ -125,13 +125,14 @@ static int sp_probe(struct platform_device *pdev) static int sp_remove(struct platform_device *pdev) { struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); struct resource *res; unregister_sja1000dev(dev); dev_set_drvdata(&pdev->dev, NULL); - if (dev->base_addr) - iounmap((void __iomem *)dev->base_addr); + if (priv->reg_base) + iounmap(priv->reg_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); |