diff options
Diffstat (limited to 'drivers/net/can/sja1000')
-rw-r--r-- | drivers/net/can/sja1000/Kconfig | 4 | ||||
-rw-r--r-- | drivers/net/can/sja1000/ems_pci.c | 2 | ||||
-rw-r--r-- | drivers/net/can/sja1000/kvaser_pci.c | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/plx_pci.c | 155 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000.c | 23 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000.h | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_isa.c | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_of_platform.c | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_platform.c | 48 |
9 files changed, 206 insertions, 30 deletions
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index 9e277d64a318..ae3505afd682 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -53,7 +53,9 @@ config CAN_PLX_PCI Driver supports now: - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/) - Adlink PCI-7841/cPCI-7841 SE card + - esd CAN-PCI/CPCI/PCI104/200 (http://www.esd.eu/) + - esd CAN-PCI/PMC/266 + - esd CAN-PCIe/2000 - Marathon CAN-bus-PCI card (http://www.marathon.ru/) - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/) - endif diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 87300606abb9..36f4f9780c30 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -22,8 +22,8 @@ #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/delay.h> +#include <linux/slab.h> #include <linux/pci.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/io.h> diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index 441e776a7f59..ed004cebd31f 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -36,7 +36,6 @@ #include <linux/netdevice.h> #include <linux/delay.h> #include <linux/pci.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/io.h> diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index 6b46a6395f80..437b5c716a24 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -25,8 +25,8 @@ #include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/delay.h> +#include <linux/slab.h> #include <linux/pci.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/io.h> @@ -40,7 +40,10 @@ MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with " MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " "Adlink PCI-7841/cPCI-7841 SE, " "Marathon CAN-bus-PCI, " - "TEWS TECHNOLOGIES TPMC810"); + "TEWS TECHNOLOGIES TPMC810, " + "esd CAN-PCI/CPCI/PCI104/200, " + "esd CAN-PCI/PMC/266, " + "esd CAN-PCIe/2000") MODULE_LICENSE("GPL v2"); #define PLX_PCI_MAX_CHAN 2 @@ -49,11 +52,14 @@ struct plx_pci_card { int channels; /* detected channels count */ struct net_device *net_dev[PLX_PCI_MAX_CHAN]; void __iomem *conf_addr; + + /* Pointer to device-dependent reset function */ + void (*reset_func)(struct pci_dev *pdev); }; #define PLX_PCI_CAN_CLOCK (16000000 / 2) -/* PLX90xx registers */ +/* PLX9030/9050/9052 registers */ #define PLX_INTCSR 0x4c /* Interrupt Control/Status */ #define PLX_CNTRL 0x50 /* User I/O, Direct Slave Response, * Serial EEPROM, and Initialization @@ -65,6 +71,14 @@ struct plx_pci_card { #define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */ #define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */ +/* PLX9056 registers */ +#define PLX9056_INTCSR 0x68 /* Interrupt Control/Status */ +#define PLX9056_CNTRL 0x6c /* Control / Software Reset */ + +#define PLX9056_LINTI (1 << 11) +#define PLX9056_PCI_INT_EN (1 << 8) +#define PLX9056_PCI_RCR (1 << 29) /* Read Configuration Registers */ + /* * The board configuration is probably following: * RX1 is connected to ground. @@ -100,6 +114,13 @@ struct plx_pci_card { #define ADLINK_PCI_VENDOR_ID 0x144A #define ADLINK_PCI_DEVICE_ID 0x7841 +#define ESD_PCI_SUB_SYS_ID_PCI200 0x0004 +#define ESD_PCI_SUB_SYS_ID_PCI266 0x0009 +#define ESD_PCI_SUB_SYS_ID_PMC266 0x000e +#define ESD_PCI_SUB_SYS_ID_CPCI200 0x010b +#define ESD_PCI_SUB_SYS_ID_PCIE2000 0x0200 +#define ESD_PCI_SUB_SYS_ID_PCI104200 0x0501 + #define MARATHON_PCI_DEVICE_ID 0x2715 #define TEWS_PCI_VENDOR_ID 0x1498 @@ -107,6 +128,7 @@ struct plx_pci_card { static void plx_pci_reset_common(struct pci_dev *pdev); static void plx_pci_reset_marathon(struct pci_dev *pdev); +static void plx9056_pci_reset_common(struct pci_dev *pdev); struct plx_pci_channel_map { u32 bar; @@ -147,6 +169,30 @@ static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = { /* based on PLX9052 */ }; +static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = { + "esd CAN-PCI/CPCI/PCI104/200", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, + &plx_pci_reset_common + /* based on PLX9030/9050 */ +}; + +static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = { + "esd CAN-PCI/PMC/266", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, + &plx9056_pci_reset_common + /* based on PLX9056 */ +}; + +static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = { + "esd CAN-PCIe/2000", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, + &plx9056_pci_reset_common + /* based on PEX8311 */ +}; + static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = { "Marathon CAN-bus-PCI", 2, PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, @@ -179,6 +225,48 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = { (kernel_ulong_t)&plx_pci_card_info_adlink_se }, { + /* esd CAN-PCI/200 */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI200, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_esd200 + }, + { + /* esd CAN-CPCI/200 */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_CPCI200, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_esd200 + }, + { + /* esd CAN-PCI104/200 */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI104200, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_esd200 + }, + { + /* esd CAN-PCI/266 */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, + PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI266, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_esd266 + }, + { + /* esd CAN-PMC/266 */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, + PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PMC266, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_esd266 + }, + { + /* esd CAN-PCIE/2000 */ + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, + PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCIE2000, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_esd2000 + }, + { /* Marathon CAN-bus-PCI card */ PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -241,7 +329,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv) } /* - * PLX90xx software reset + * PLX9030/50/52 software reset * Also LRESET# asserts and brings to reset device on the Local Bus (if wired). * For most cards it's enough for reset the SJA1000 chips. */ @@ -258,6 +346,38 @@ static void plx_pci_reset_common(struct pci_dev *pdev) iowrite32(cntrl, card->conf_addr + PLX_CNTRL); }; +/* + * PLX9056 software reset + * Assert LRESET# and reset device(s) on the Local Bus (if wired). + */ +static void plx9056_pci_reset_common(struct pci_dev *pdev) +{ + struct plx_pci_card *card = pci_get_drvdata(pdev); + u32 cntrl; + + /* issue a local bus reset */ + cntrl = ioread32(card->conf_addr + PLX9056_CNTRL); + cntrl |= PLX_PCI_RESET; + iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); + udelay(100); + cntrl ^= PLX_PCI_RESET; + iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); + + /* reload local configuration from EEPROM */ + cntrl |= PLX9056_PCI_RCR; + iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); + + /* + * There is no safe way to poll for the end + * of reconfiguration process. Waiting for 10ms + * is safe. + */ + mdelay(10); + + cntrl ^= PLX9056_PCI_RCR; + iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); +}; + /* Special reset function for Marathon card */ static void plx_pci_reset_marathon(struct pci_dev *pdev) { @@ -301,13 +421,16 @@ static void plx_pci_del_card(struct pci_dev *pdev) free_sja1000dev(dev); } - plx_pci_reset_common(pdev); + card->reset_func(pdev); /* - * Disable interrupts from PCI-card (PLX90xx) and disable Local_1, - * Local_2 interrupts + * Disable interrupts from PCI-card and disable local + * interrupts */ - iowrite32(0x0, card->conf_addr + PLX_INTCSR); + if (pdev->device != PCI_DEVICE_ID_PLX_9056) + iowrite32(0x0, card->conf_addr + PLX_INTCSR); + else + iowrite32(0x0, card->conf_addr + PLX9056_INTCSR); if (card->conf_addr) pci_iounmap(pdev, card->conf_addr); @@ -366,6 +489,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev, card->conf_addr = addr + ci->conf_map.offset; ci->reset_func(pdev); + card->reset_func = ci->reset_func; /* Detect available channels */ for (i = 0; i < ci->channel_count; i++) { @@ -437,10 +561,17 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev, * Enable interrupts from PCI-card (PLX90xx) and enable Local_1, * Local_2 interrupts from the SJA1000 chips */ - val = ioread32(card->conf_addr + PLX_INTCSR); - val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN; - iowrite32(val, card->conf_addr + PLX_INTCSR); - + if (pdev->device != PCI_DEVICE_ID_PLX_9056) { + val = ioread32(card->conf_addr + PLX_INTCSR); + if (pdev->subsystem_vendor == PCI_VENDOR_ID_ESDGMBH) + val |= PLX_LINT1_EN | PLX_PCI_INT_EN; + else + val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN; + iowrite32(val, card->conf_addr + PLX_INTCSR); + } else { + iowrite32(PLX9056_LINTI | PLX9056_PCI_INT_EN, + card->conf_addr + PLX9056_INTCSR); + } return 0; failure_cleanup: diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 145b1a731a53..85f7cbfe8e5f 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -60,7 +60,6 @@ #include <linux/skbuff.h> #include <linux/delay.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> @@ -84,6 +83,20 @@ static struct can_bittiming_const sja1000_bittiming_const = { .brp_inc = 1, }; +static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val) +{ + unsigned long flags; + + /* + * The command register needs some locking and time to settle + * the write_reg() operation - especially on SMP systems. + */ + spin_lock_irqsave(&priv->cmdreg_lock, flags); + priv->write_reg(priv, REG_CMR, val); + priv->read_reg(priv, REG_SR); + spin_unlock_irqrestore(&priv->cmdreg_lock, flags); +} + static int sja1000_probe_chip(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); @@ -293,11 +306,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, for (i = 0; i < dlc; i++) priv->write_reg(priv, dreg++, cf->data[i]); - dev->trans_start = jiffies; - can_put_echo_skb(skb, dev, 0); - priv->write_reg(priv, REG_CMR, CMD_TR); + sja1000_write_cmdreg(priv, CMD_TR); return NETDEV_TX_OK; } @@ -346,7 +357,7 @@ static void sja1000_rx(struct net_device *dev) cf->can_id = id; /* release receive buffer */ - priv->write_reg(priv, REG_CMR, CMD_RRB); + sja1000_write_cmdreg(priv, CMD_RRB); netif_rx(skb); @@ -374,7 +385,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(priv, REG_CMR, CMD_CDO); /* clear bit */ + sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */ } if (isrc & IRQ_EI) { diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index 97a622b9302f..de8e778f6832 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -167,6 +167,7 @@ struct sja1000_priv { void __iomem *reg_base; /* ioremap'ed address to registers */ unsigned long irq_flags; /* for request_irq() */ + spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */ u16 flags; /* custom mode flags */ u8 ocr; /* output control register */ diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c index a6a51f155962..496223e9e2fc 100644 --- a/drivers/net/can/sja1000/sja1000_isa.c +++ b/drivers/net/can/sja1000/sja1000_isa.c @@ -23,7 +23,6 @@ #include <linux/delay.h> #include <linux/irq.h> #include <linux/io.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/platform/sja1000.h> diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c index 9dd076a626a5..34e79efbd2fc 100644 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -38,7 +38,6 @@ #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> diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 628374c2a05f..d9fadc489b32 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -24,7 +24,6 @@ #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/irq.h> -#include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/platform/sja1000.h> #include <linux/io.h> @@ -37,16 +36,36 @@ 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 sja1000_priv *priv, int reg) +static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) { return ioread8(priv->reg_base + reg); } -static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val) +static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val) { iowrite8(val, priv->reg_base + reg); } +static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg) +{ + return ioread8(priv->reg_base + reg * 2); +} + +static void sp_write_reg16(const struct sja1000_priv *priv, int reg, u8 val) +{ + iowrite8(val, priv->reg_base + reg * 2); +} + +static u8 sp_read_reg32(const struct sja1000_priv *priv, int reg) +{ + return ioread8(priv->reg_base + reg * 4); +} + +static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val) +{ + iowrite8(val, priv->reg_base + reg * 4); +} + static int sp_probe(struct platform_device *pdev) { int err; @@ -90,14 +109,29 @@ static int sp_probe(struct platform_device *pdev) priv = netdev_priv(dev); dev->irq = res_irq->start; - priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED); priv->reg_base = addr; - priv->read_reg = sp_read_reg; - priv->write_reg = sp_write_reg; - priv->can.clock.freq = pdata->clock; + /* The CAN clock frequency is half the oscillator clock frequency */ + priv->can.clock.freq = pdata->osc_freq / 2; priv->ocr = pdata->ocr; priv->cdr = pdata->cdr; + switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) { + case IORESOURCE_MEM_32BIT: + priv->read_reg = sp_read_reg32; + priv->write_reg = sp_write_reg32; + break; + case IORESOURCE_MEM_16BIT: + priv->read_reg = sp_read_reg16; + priv->write_reg = sp_write_reg16; + break; + case IORESOURCE_MEM_8BIT: + default: + priv->read_reg = sp_read_reg8; + priv->write_reg = sp_write_reg8; + break; + } + dev_set_drvdata(&pdev->dev, dev); SET_NETDEV_DEV(dev, &pdev->dev); |