Commit 06a3f31a authored by Flavio Suligoi's avatar Flavio Suligoi Committed by Marc Kleine-Budde
Browse files

can: sja1000: plx_pci: add support for ASEM CAN raw device

This patch adds support for ASEM opto-isolated dual channels
CAN raw device (http://www.asem.it

)

Signed-off-by: default avatarFlavio Suligoi <f.suligoi@asem.it>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 0db90713
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ config CAN_PLX_PCI
	   - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
	   - IXXAT Automation PC-I 04/PCI card (http://www.ixxat.com/)
	   - Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card (http://www.connecttech.com)
	   - ASEM CAN raw - 2 isolated CAN channels (www.asem.it)

config CAN_TSCAN1
	tristate "TS-CAN1 PC104 boards"
+64 −1
Original line number Diff line number Diff line
@@ -46,7 +46,8 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
			"esd CAN-PCIe/2000, "
			"Connect Tech Inc. CANpro/104-Plus Opto (CRG001), "
			"IXXAT PC-I 04/PCI, "
			"ELCUS CAN-200-PCI")
			"ELCUS CAN-200-PCI, "
			"ASEM DUAL CAN-RAW")
MODULE_LICENSE("GPL v2");

#define PLX_PCI_MAX_CHAN 2
@@ -70,7 +71,9 @@ struct plx_pci_card {
					 */

#define PLX_LINT1_EN	0x1		/* Local interrupt 1 enable */
#define PLX_LINT1_POL	(1 << 1)	/* Local interrupt 1 polarity */
#define PLX_LINT2_EN	(1 << 3)	/* Local interrupt 2 enable */
#define PLX_LINT2_POL	(1 << 4)	/* Local interrupt 2 polarity */
#define PLX_PCI_INT_EN	(1 << 6)	/* PCI Interrupt Enable */
#define PLX_PCI_RESET	(1 << 30)	/* PCI Adapter Software Reset */

@@ -92,6 +95,9 @@ struct plx_pci_card {
 */
#define PLX_PCI_OCR	(OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)

/* OCR setting for ASEM Dual CAN raw */
#define ASEM_PCI_OCR	0xfe

/*
 * In the CDR register, you should set CBP to 1.
 * You will probably also want to set the clock divider value to 7
@@ -145,10 +151,20 @@ struct plx_pci_card {
#define MOXA_PCI_VENDOR_ID		0x1393
#define MOXA_PCI_DEVICE_ID		0x0100

#define ASEM_RAW_CAN_VENDOR_ID		0x10b5
#define ASEM_RAW_CAN_DEVICE_ID		0x9030
#define ASEM_RAW_CAN_SUB_VENDOR_ID	0x3000
#define ASEM_RAW_CAN_SUB_DEVICE_ID	0x1001
#define ASEM_RAW_CAN_SUB_DEVICE_ID_BIS	0x1002
#define ASEM_RAW_CAN_RST_REGISTER	0x54
#define ASEM_RAW_CAN_RST_MASK_CAN1	0x20
#define ASEM_RAW_CAN_RST_MASK_CAN2	0x04

static void plx_pci_reset_common(struct pci_dev *pdev);
static void plx9056_pci_reset_common(struct pci_dev *pdev);
static void plx_pci_reset_marathon_pci(struct pci_dev *pdev);
static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev);
static void plx_pci_reset_asem_dual_can_raw(struct pci_dev *pdev);

struct plx_pci_channel_map {
	u32 bar;
@@ -269,6 +285,14 @@ static struct plx_pci_card_info plx_pci_card_info_moxa = {
	 /* based on PLX9052 */
};

static struct plx_pci_card_info plx_pci_card_info_asem_dual_can = {
	"ASEM Dual CAN raw PCI", 2,
	PLX_PCI_CAN_CLOCK, ASEM_PCI_OCR, PLX_PCI_CDR,
	{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
	&plx_pci_reset_asem_dual_can_raw
	/* based on PLX9030 */
};

static const struct pci_device_id plx_pci_tbl[] = {
	{
		/* Adlink PCI-7841/cPCI-7841 */
@@ -375,6 +399,20 @@ static const struct pci_device_id plx_pci_tbl[] = {
		0, 0,
		(kernel_ulong_t)&plx_pci_card_info_moxa
	},
	{
		/* ASEM Dual CAN raw */
		ASEM_RAW_CAN_VENDOR_ID, ASEM_RAW_CAN_DEVICE_ID,
		ASEM_RAW_CAN_SUB_VENDOR_ID, ASEM_RAW_CAN_SUB_DEVICE_ID,
		0, 0,
		(kernel_ulong_t)&plx_pci_card_info_asem_dual_can
	},
	{
		/* ASEM Dual CAN raw -new model */
		ASEM_RAW_CAN_VENDOR_ID, ASEM_RAW_CAN_DEVICE_ID,
		ASEM_RAW_CAN_SUB_VENDOR_ID, ASEM_RAW_CAN_SUB_DEVICE_ID_BIS,
		0, 0,
		(kernel_ulong_t)&plx_pci_card_info_asem_dual_can
	},
	{ 0,}
};
MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
@@ -524,6 +562,31 @@ static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev)
	}
}

/* Special reset function for ASEM Dual CAN raw card */
static void plx_pci_reset_asem_dual_can_raw(struct pci_dev *pdev)
{
	void __iomem *bar0_addr;
	u8 tmpval;

	plx_pci_reset_common(pdev);

	bar0_addr = pci_iomap(pdev, 0, 0);
	if (!bar0_addr) {
		dev_err(&pdev->dev, "Failed to remap reset space 0 (BAR0)\n");
		return;
	}

	/* reset the two SJA1000 chips */
	tmpval = ioread8(bar0_addr + ASEM_RAW_CAN_RST_REGISTER);
	tmpval &= ~(ASEM_RAW_CAN_RST_MASK_CAN1 | ASEM_RAW_CAN_RST_MASK_CAN2);
	iowrite8(tmpval, bar0_addr + ASEM_RAW_CAN_RST_REGISTER);
	usleep_range(300, 400);
	tmpval |= ASEM_RAW_CAN_RST_MASK_CAN1 | ASEM_RAW_CAN_RST_MASK_CAN2;
	iowrite8(tmpval, bar0_addr + ASEM_RAW_CAN_RST_REGISTER);
	usleep_range(300, 400);
	pci_iounmap(pdev, bar0_addr);
}

static void plx_pci_del_card(struct pci_dev *pdev)
{
	struct plx_pci_card *card = pci_get_drvdata(pdev);