diff options
Diffstat (limited to 'drivers/net/can/sja1000/plx_pci.c')
| -rw-r--r-- | drivers/net/can/sja1000/plx_pci.c | 155 | 
1 files changed, 143 insertions, 12 deletions
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index 6b46a6395f8..437b5c716a2 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:  |