M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices"
depends on CAN_DEV && HAS_IOMEM
if CAN_SJA1000
config CAN_SJA1000_ISA
tristate "ISA Bus based legacy SJA1000 driver"
---help---
This driver adds legacy support for SJA1000 chips connected to
the ISA bus using I/O port, memory mapped or indirect access.
config CAN_SJA1000_PLATFORM
tristate "Generic Platform Bus based SJA1000 driver"
---help---
This driver adds support for the SJA1000 chips connected to
the "platform bus" (Linux abstraction for directly to the
processor attached devices). Which can be found on various
boards from Phytec (http://www.phytec.de) like the PCM027,
PCM038.
config CAN_SJA1000_OF_PLATFORM
tristate "Generic OF Platform Bus based SJA1000 driver"
depends on PPC_OF
---help---
This driver adds support for the SJA1000 chips connected to
the OpenFirmware "platform bus" found on embedded systems with
OpenFirmware bindings, e.g. if you have a PowerPC based system
you may want to enable this option.
config CAN_EMS_PCMCIA
tristate "EMS CPC-CARD Card"
depends on PCMCIA
---help---
This driver is for the one or two channel CPC-CARD cards from
EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
config CAN_EMS_PCI
tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
depends on PCI
---help---
This driver is for the one, two or four channel CPC-PCI,
CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
(http://www.ems-wuensche.de).
config CAN_PEAK_PCMCIA
tristate "PEAK PCAN-PC Card"
depends on PCMCIA
---help---
This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)
from PEAK-System (http://www.peak-system.com). To compile this
driver as a module, choose M here: the module will be called
peak_pcmcia.
config CAN_PEAK_PCI
tristate "PEAK PCAN-PCI/PCIe/miniPCI Cards"
depends on PCI
---help---
This driver is for the PCAN-PCI/PCIe/miniPCI cards
(1, 2, 3 or 4 channels) from PEAK-System Technik
(http://www.peak-system.com).
config CAN_PEAK_PCIEC
bool "PEAK PCAN-ExpressCard Cards"
depends on CAN_PEAK_PCI
select I2C
select I2C_ALGOBIT
default y
---help---
Say Y here if you want to use a PCAN-ExpressCard from PEAK-System
Technik. This will also automatically select I2C and I2C_ALGO
configuration options.
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
depends on PCI
---help---
This driver is for the the PCIcanx and PCIcan cards (1, 2 or
4 channel) from Kvaser (http://www.kvaser.com).
config CAN_PLX_PCI
tristate "PLX90xx PCI-bridge based Cards"
depends on PCI
---help---
This driver is for CAN interface cards based on
the PLX90xx PCI bridge.
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/)
- IXXAT Automation PC-I 04/PCI card (http://www.ixxat.com/)
config CAN_TSCAN1
tristate "TS-CAN1 PC104 boards"
depends on ISA
help
This driver is for Technologic Systems' TSCAN-1 PC104 boards.
http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
The driver supports multiple boards and automatically configures them:
PLD IO base addresses are read from jumpers JP1 and JP2,
IRQ numbers are read from jumpers JP4 and JP5,
SJA1000 IO base addresses are chosen heuristically (first that works).
endif

View File

@@ -0,0 +1,17 @@
#
# Makefile for the SJA1000 CAN controller drivers.
#
obj-$(CONFIG_CAN_SJA1000) += sja1000.o
obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
obj-$(CONFIG_CAN_PEAK_PCMCIA) += peak_pcmcia.o
obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG

View File

@@ -0,0 +1,386 @@
/*
* Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
* Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/can/dev.h>
#include <linux/io.h>
#include "sja1000.h"
#define DRV_NAME "ems_pci"
MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
MODULE_LICENSE("GPL v2");
#define EMS_PCI_V1_MAX_CHAN 2
#define EMS_PCI_V2_MAX_CHAN 4
#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN
struct ems_pci_card {
int version;
int channels;
struct pci_dev *pci_dev;
struct net_device *net_dev[EMS_PCI_MAX_CHAN];
void __iomem *conf_addr;
void __iomem *base_addr;
};
#define EMS_PCI_CAN_CLOCK (16000000 / 2)
/*
* Register definitions and descriptions are from LinCAN 0.3.3.
*
* PSB4610 PITA-2 bridge control registers
*/
#define PITA2_ICR 0x00 /* Interrupt Control Register */
#define PITA2_ICR_INT0 0x00000002 /* [RC] INT0 Active/Clear */
#define PITA2_ICR_INT0_EN 0x00020000 /* [RW] Enable INT0 */
#define PITA2_MISC 0x1c /* Miscellaneous Register */
#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */
/*
* Register definitions for the PLX 9030
*/
#define PLX_ICSR 0x4c /* Interrupt Control/Status register */
#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
PLX_ICSR_LINTI1_CLR)
/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
* This means normal output mode, push-pull and the correct polarity.
*/
#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
/*
* In the CDR register, you should set CBP to 1.
* You will probably also want to set the clock divider value to 7
* (meaning direct oscillator output) because the second SJA1000 chip
* is driven by the first one CLKOUT output.
*/
#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
#define EMS_PCI_V1_BASE_BAR 1
#define EMS_PCI_V1_CONF_SIZE 4096 /* size of PITA control area */
#define EMS_PCI_V2_BASE_BAR 2
#define EMS_PCI_V2_CONF_SIZE 128 /* size of PLX control area */
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
#define EMS_PCI_BASE_SIZE 4096 /* size of controller area */
static DEFINE_PCI_DEVICE_TABLE(ems_pci_tbl) = {
/* CPC-PCI v1 */
{PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
/* CPC-PCI v2 */
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
/* CPC-104P v2 */
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
{0,}
};
MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
/*
* Helper to read internal registers from card logic (not CAN)
*/
static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
{
return readb(card->base_addr + (port * 4));
}
static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
{
return readb(priv->reg_base + (port * 4));
}
static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
int port, u8 val)
{
writeb(val, priv->reg_base + (port * 4));
}
static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
{
struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
/* reset int flag of pita */
writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
card->conf_addr + PITA2_ICR);
}
static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
{
return readb(priv->reg_base + port);
}
static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
int port, u8 val)
{
writeb(val, priv->reg_base + port);
}
static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
{
struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
}
/*
* 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(const struct sja1000_priv *priv)
{
unsigned char res;
/* Make sure SJA1000 is in reset mode */
priv->write_reg(priv, REG_MOD, 1);
priv->write_reg(priv, REG_CDR, CDR_PELICAN);
/* read reset-values */
res = priv->read_reg(priv, REG_CDR);
if (res == CDR_PELICAN)
return 1;
return 0;
}
static void ems_pci_del_card(struct pci_dev *pdev)
{
struct ems_pci_card *card = pci_get_drvdata(pdev);
struct net_device *dev;
int i = 0;
for (i = 0; i < card->channels; i++) {
dev = card->net_dev[i];
if (!dev)
continue;
dev_info(&pdev->dev, "Removing %s.\n", dev->name);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
}
if (card->base_addr != NULL)
pci_iounmap(card->pci_dev, card->base_addr);
if (card->conf_addr != NULL)
pci_iounmap(card->pci_dev, card->conf_addr);
kfree(card);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
static void ems_pci_card_reset(struct ems_pci_card *card)
{
/* Request board reset */
writeb(0, card->base_addr);
}
/*
* Probe PCI device for EMS CAN signature and register each available
* CAN channel to SJA1000 Socket-CAN subsystem.
*/
static int __devinit ems_pci_add_card(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct net_device *dev;
struct ems_pci_card *card;
int max_chan, conf_size, base_bar;
int err, i;
/* Enabling PCI device */
if (pci_enable_device(pdev) < 0) {
dev_err(&pdev->dev, "Enabling PCI device failed\n");
return -ENODEV;
}
/* Allocating card structures to hold addresses, ... */
card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
if (card == NULL) {
dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
pci_set_drvdata(pdev, card);
card->pci_dev = pdev;
card->channels = 0;
if (pdev->vendor == PCI_VENDOR_ID_PLX) {
card->version = 2; /* CPC-PCI v2 */
max_chan = EMS_PCI_V2_MAX_CHAN;
base_bar = EMS_PCI_V2_BASE_BAR;
conf_size = EMS_PCI_V2_CONF_SIZE;
} else {
card->version = 1; /* CPC-PCI v1 */
max_chan = EMS_PCI_V1_MAX_CHAN;
base_bar = EMS_PCI_V1_BASE_BAR;
conf_size = EMS_PCI_V1_CONF_SIZE;
}
/* Remap configuration space and controller memory area */
card->conf_addr = pci_iomap(pdev, 0, conf_size);
if (card->conf_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
card->base_addr = pci_iomap(pdev, base_bar, EMS_PCI_BASE_SIZE);
if (card->base_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
if (card->version == 1) {
/* Configure PITA-2 parallel interface (enable MUX) */
writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
/* Check for unique EMS CAN signature */
if (ems_pci_v1_readb(card, 0) != 0x55 ||
ems_pci_v1_readb(card, 1) != 0xAA ||
ems_pci_v1_readb(card, 2) != 0x01 ||
ems_pci_v1_readb(card, 3) != 0xCB ||
ems_pci_v1_readb(card, 4) != 0x11) {
dev_err(&pdev->dev,
"Not EMS Dr. Thomas Wuensche interface\n");
err = -ENODEV;
goto failure_cleanup;
}
}
ems_pci_card_reset(card);
/* Detect available channels */
for (i = 0; i < max_chan; i++) {
dev = alloc_sja1000dev(0);
if (dev == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
card->net_dev[i] = dev;
priv = netdev_priv(dev);
priv->priv = card;
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
+ (i * EMS_PCI_CAN_CTRL_SIZE);
if (card->version == 1) {
priv->read_reg = ems_pci_v1_read_reg;
priv->write_reg = ems_pci_v1_write_reg;
priv->post_irq = ems_pci_v1_post_irq;
} else {
priv->read_reg = ems_pci_v2_read_reg;
priv->write_reg = ems_pci_v2_write_reg;
priv->post_irq = ems_pci_v2_post_irq;
}
/* Check if channel is present */
if (ems_pci_check_chan(priv)) {
priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
priv->ocr = EMS_PCI_OCR;
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
if (card->version == 1)
/* reset int flag of pita */
writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
card->conf_addr + PITA2_ICR);
else
/* enable IRQ in PLX 9030 */
writel(PLX_ICSR_ENA_CLR,
card->conf_addr + PLX_ICSR);
/* Register SJA1000 device */
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "Registering device failed "
"(err=%d)\n", err);
free_sja1000dev(dev);
goto failure_cleanup;
}
card->channels++;
dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n",
i + 1, priv->reg_base, dev->irq);
} else {
free_sja1000dev(dev);
}
}
return 0;
failure_cleanup:
dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
ems_pci_del_card(pdev);
return err;
}
static struct pci_driver ems_pci_driver = {
.name = DRV_NAME,
.id_table = ems_pci_tbl,
.probe = ems_pci_add_card,
.remove = ems_pci_del_card,
};
static int __init ems_pci_init(void)
{
return pci_register_driver(&ems_pci_driver);
}
static void __exit ems_pci_exit(void)
{
pci_unregister_driver(&ems_pci_driver);
}
module_init(ems_pci_init);
module_exit(ems_pci_exit);

View File

@@ -0,0 +1,331 @@
/*
* Copyright (C) 2008 Sebastian Haas (initial chardev implementation)
* Copyright (C) 2010 Markus Plessing <plessing@ems-wuensche.com>
* Rework for mainline by Oliver Hartkopp <socketcan@hartkopp.net>
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include "sja1000.h"
#define DRV_NAME "ems_pcmcia"
MODULE_AUTHOR("Markus Plessing <plessing@ems-wuensche.com>");
MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-CARD cards");
MODULE_SUPPORTED_DEVICE("EMS CPC-CARD CAN card");
MODULE_LICENSE("GPL v2");
#define EMS_PCMCIA_MAX_CHAN 2
struct ems_pcmcia_card {
int channels;
struct pcmcia_device *pcmcia_dev;
struct net_device *net_dev[EMS_PCMCIA_MAX_CHAN];
void __iomem *base_addr;
};
#define EMS_PCMCIA_CAN_CLOCK (16000000 / 2)
/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
* This means normal output mode , push-pull and the correct polarity.
*/
#define EMS_PCMCIA_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
/*
* In the CDR register, you should set CBP to 1.
* You will probably also want to set the clock divider value to 7
* (meaning direct oscillator output) because the second SJA1000 chip
* is driven by the first one CLKOUT output.
*/
#define EMS_PCMCIA_CDR (CDR_CBP | CDR_CLKOUT_MASK)
#define EMS_PCMCIA_MEM_SIZE 4096 /* Size of the remapped io-memory */
#define EMS_PCMCIA_CAN_BASE_OFFSET 0x100 /* Offset where controllers starts */
#define EMS_PCMCIA_CAN_CTRL_SIZE 0x80 /* Memory size for each controller */
#define EMS_CMD_RESET 0x00 /* Perform a reset of the card */
#define EMS_CMD_MAP 0x03 /* Map CAN controllers into card' memory */
#define EMS_CMD_UMAP 0x02 /* Unmap CAN controllers from card' memory */
static struct pcmcia_device_id ems_pcmcia_tbl[] = {
PCMCIA_DEVICE_PROD_ID123("EMS_T_W", "CPC-Card", "V2.0", 0xeab1ea23,
0xa338573f, 0xe4575800),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, ems_pcmcia_tbl);
static u8 ems_pcmcia_read_reg(const struct sja1000_priv *priv, int port)
{
return readb(priv->reg_base + port);
}
static void ems_pcmcia_write_reg(const struct sja1000_priv *priv, int port,
u8 val)
{
writeb(val, priv->reg_base + port);
}
static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
{
struct ems_pcmcia_card *card = dev_id;
struct net_device *dev;
irqreturn_t retval = IRQ_NONE;
int i, again;
/* Card not present */
if (readw(card->base_addr) != 0xAA55)
return IRQ_HANDLED;
do {
again = 0;
/* Check interrupt for each channel */
for (i = 0; i < card->channels; i++) {
dev = card->net_dev[i];
if (!dev)
continue;
if (sja1000_interrupt(irq, dev) == IRQ_HANDLED)
again = 1;
}
/* At least one channel handled the interrupt */
if (again)
retval = IRQ_HANDLED;
} while (again);
return retval;
}
/*
* Check if a CAN controller is present at the specified location
* by trying to set 'em into the PeliCAN mode
*/
static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)
{
/* Make sure SJA1000 is in reset mode */
ems_pcmcia_write_reg(priv, REG_MOD, 1);
ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN);
/* read reset-values */
if (ems_pcmcia_read_reg(priv, REG_CDR) == CDR_PELICAN)
return 1;
return 0;
}
static void ems_pcmcia_del_card(struct pcmcia_device *pdev)
{
struct ems_pcmcia_card *card = pdev->priv;
struct net_device *dev;
int i;
free_irq(pdev->irq, card);
for (i = 0; i < card->channels; i++) {
dev = card->net_dev[i];
if (!dev)
continue;
printk(KERN_INFO "%s: removing %s on channel #%d\n",
DRV_NAME, dev->name, i);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
}
writeb(EMS_CMD_UMAP, card->base_addr);
iounmap(card->base_addr);
kfree(card);
pdev->priv = NULL;
}
/*
* Probe PCI device for EMS CAN signature and register each available
* CAN channel to SJA1000 Socket-CAN subsystem.
*/
static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
unsigned long base)
{
struct sja1000_priv *priv;
struct net_device *dev;
struct ems_pcmcia_card *card;
int err, i;
/* Allocating card structures to hold addresses, ... */
card = kzalloc(sizeof(struct ems_pcmcia_card), GFP_KERNEL);
if (!card)
return -ENOMEM;
pdev->priv = card;
card->channels = 0;
card->base_addr = ioremap(base, EMS_PCMCIA_MEM_SIZE);
if (!card->base_addr) {
err = -ENOMEM;
goto failure_cleanup;
}
/* Check for unique EMS CAN signature */
if (readw(card->base_addr) != 0xAA55) {
err = -ENODEV;
goto failure_cleanup;
}
/* Request board reset */
writeb(EMS_CMD_RESET, card->base_addr);
/* Make sure CAN controllers are mapped into card's memory space */
writeb(EMS_CMD_MAP, card->base_addr);
/* Detect available channels */
for (i = 0; i < EMS_PCMCIA_MAX_CHAN; i++) {
dev = alloc_sja1000dev(0);
if (!dev) {
err = -ENOMEM;
goto failure_cleanup;
}
card->net_dev[i] = dev;
priv = netdev_priv(dev);
priv->priv = card;
SET_NETDEV_DEV(dev, &pdev->dev);
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
priv->reg_base = card->base_addr + EMS_PCMCIA_CAN_BASE_OFFSET +
(i * EMS_PCMCIA_CAN_CTRL_SIZE);
/* Check if channel is present */
if (ems_pcmcia_check_chan(priv)) {
priv->read_reg = ems_pcmcia_read_reg;
priv->write_reg = ems_pcmcia_write_reg;
priv->can.clock.freq = EMS_PCMCIA_CAN_CLOCK;
priv->ocr = EMS_PCMCIA_OCR;
priv->cdr = EMS_PCMCIA_CDR;
priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
/* Register SJA1000 device */
err = register_sja1000dev(dev);
if (err) {
free_sja1000dev(dev);
goto failure_cleanup;
}
card->channels++;
printk(KERN_INFO "%s: registered %s on channel "
"#%d at 0x%p, irq %d\n", DRV_NAME, dev->name,
i, priv->reg_base, dev->irq);
} else
free_sja1000dev(dev);
}
err = request_irq(dev->irq, &ems_pcmcia_interrupt, IRQF_SHARED,
DRV_NAME, card);
if (!err)
return 0;
failure_cleanup:
ems_pcmcia_del_card(pdev);
return err;
}
/*
* Setup PCMCIA socket and probe for EMS CPC-CARD
*/
static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev)
{
int csval;
/* General socket configuration */
dev->config_flags |= CONF_ENABLE_IRQ;
dev->config_index = 1;
dev->config_regs = PRESENT_OPTION;
/* The io structure describes IO port mapping */
dev->resource[0]->end = 16;
dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
dev->resource[1]->end = 16;
dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
dev->io_lines = 5;
/* Allocate a memory window */
dev->resource[2]->flags =
(WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE);
dev->resource[2]->start = dev->resource[2]->end = 0;
csval = pcmcia_request_window(dev, dev->resource[2], 0);
if (csval) {
dev_err(&dev->dev, "pcmcia_request_window failed (err=%d)\n",
csval);
return 0;
}
csval = pcmcia_map_mem_page(dev, dev->resource[2], dev->config_base);
if (csval) {
dev_err(&dev->dev, "pcmcia_map_mem_page failed (err=%d)\n",
csval);
return 0;
}
csval = pcmcia_enable_device(dev);
if (csval) {
dev_err(&dev->dev, "pcmcia_enable_device failed (err=%d)\n",
csval);
return 0;
}
ems_pcmcia_add_card(dev, dev->resource[2]->start);
return 0;
}
/*
* Release claimed resources
*/
static void ems_pcmcia_remove(struct pcmcia_device *dev)
{
ems_pcmcia_del_card(dev);
pcmcia_disable_device(dev);
}
static struct pcmcia_driver ems_pcmcia_driver = {
.name = DRV_NAME,
.probe = ems_pcmcia_probe,
.remove = ems_pcmcia_remove,
.id_table = ems_pcmcia_tbl,
};
static int __init ems_pcmcia_init(void)
{
return pcmcia_register_driver(&ems_pcmcia_driver);
}
module_init(ems_pcmcia_init);
static void __exit ems_pcmcia_exit(void)
{
pcmcia_unregister_driver(&ems_pcmcia_driver);
}
module_exit(ems_pcmcia_exit);

View File

@@ -0,0 +1,411 @@
/*
* Copyright (C) 2008 Per Dalen <per.dalen@cnw.se>
*
* Parts of this software are based on (derived) the following:
*
* - Kvaser linux driver, version 4.72 BETA
* Copyright (C) 2002-2007 KVASER AB
*
* - Lincan driver, version 0.3.3, OCERA project
* Copyright (C) 2004 Pavel Pisa
* Copyright (C) 2001 Arnaud Westenberg
*
* - Socketcan SJA1000 drivers
* Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
* 38106 Braunschweig, GERMANY
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/can/dev.h>
#include <linux/io.h>
#include "sja1000.h"
#define DRV_NAME "kvaser_pci"
MODULE_AUTHOR("Per Dalen <per.dalen@cnw.se>");
MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards");
MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card");
MODULE_LICENSE("GPL v2");
#define MAX_NO_OF_CHANNELS 4 /* max no of channels on a single card */
struct kvaser_pci {
int channel;
struct pci_dev *pci_dev;
struct net_device *slave_dev[MAX_NO_OF_CHANNELS-1];
void __iomem *conf_addr;
void __iomem *res_addr;
int no_channels;
u8 xilinx_ver;
};
#define KVASER_PCI_CAN_CLOCK (16000000 / 2)
/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
* This means normal output mode , push-pull and the correct polarity.
*/
#define KVASER_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
/*
* In the CDR register, you should set CBP to 1.
* You will probably also want to set the clock divider value to 0
* (meaning divide-by-2), the Pelican bit, and the clock-off bit
* (you will have no need for CLKOUT anyway).
*/
#define KVASER_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
/*
* These register values are valid for revision 14 of the Xilinx logic.
*/
#define XILINX_VERINT 7 /* Lower nibble simulate interrupts,
high nibble version number. */
#define XILINX_PRESUMED_VERSION 14
/*
* Important S5920 registers
*/
#define S5920_INTCSR 0x38
#define S5920_PTCR 0x60
#define INTCSR_ADDON_INTENABLE_M 0x2000
#define KVASER_PCI_PORT_BYTES 0x20
#define PCI_CONFIG_PORT_SIZE 0x80 /* size of the config io-memory */
#define PCI_PORT_SIZE 0x80 /* size of a channel io-memory */
#define PCI_PORT_XILINX_SIZE 0x08 /* size of a xilinx io-memory */
#define KVASER_PCI_VENDOR_ID1 0x10e8 /* the PCI device and vendor IDs */
#define KVASER_PCI_DEVICE_ID1 0x8406
#define KVASER_PCI_VENDOR_ID2 0x1a07 /* the PCI device and vendor IDs */
#define KVASER_PCI_DEVICE_ID2 0x0008
static DEFINE_PCI_DEVICE_TABLE(kvaser_pci_tbl) = {
{KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,},
{KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl);
static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port)
{
return ioread8(priv->reg_base + port);
}
static void kvaser_pci_write_reg(const struct sja1000_priv *priv,
int port, u8 val)
{
iowrite8(val, priv->reg_base + port);
}
static void kvaser_pci_disable_irq(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct kvaser_pci *board = priv->priv;
u32 intcsr;
/* Disable interrupts from card */
intcsr = ioread32(board->conf_addr + S5920_INTCSR);
intcsr &= ~INTCSR_ADDON_INTENABLE_M;
iowrite32(intcsr, board->conf_addr + S5920_INTCSR);
}
static void kvaser_pci_enable_irq(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct kvaser_pci *board = priv->priv;
u32 tmp_en_io;
/* Enable interrupts from card */
tmp_en_io = ioread32(board->conf_addr + S5920_INTCSR);
tmp_en_io |= INTCSR_ADDON_INTENABLE_M;
iowrite32(tmp_en_io, board->conf_addr + S5920_INTCSR);
}
static int number_of_sja1000_chip(void __iomem *base_addr)
{
u8 status;
int i;
for (i = 0; i < MAX_NO_OF_CHANNELS; i++) {
/* reset chip */
iowrite8(MOD_RM, base_addr +
(i * KVASER_PCI_PORT_BYTES) + REG_MOD);
status = ioread8(base_addr +
(i * KVASER_PCI_PORT_BYTES) + REG_MOD);
/* check reset bit */
if (!(status & MOD_RM))
break;
}
return i;
}
static void kvaser_pci_del_chan(struct net_device *dev)
{
struct sja1000_priv *priv;
struct kvaser_pci *board;
int i;
if (!dev)
return;
priv = netdev_priv(dev);
board = priv->priv;
if (!board)
return;
dev_info(&board->pci_dev->dev, "Removing device %s\n",
dev->name);
/* Disable PCI interrupts */
kvaser_pci_disable_irq(dev);
for (i = 0; i < board->no_channels - 1; i++) {
if (board->slave_dev[i]) {
dev_info(&board->pci_dev->dev, "Removing device %s\n",
board->slave_dev[i]->name);
unregister_sja1000dev(board->slave_dev[i]);
free_sja1000dev(board->slave_dev[i]);
}
}
unregister_sja1000dev(dev);
pci_iounmap(board->pci_dev, priv->reg_base);
pci_iounmap(board->pci_dev, board->conf_addr);
pci_iounmap(board->pci_dev, board->res_addr);
free_sja1000dev(dev);
}
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,
void __iomem *base_addr)
{
struct net_device *dev;
struct sja1000_priv *priv;
struct kvaser_pci *board;
int err, init_step;
dev = alloc_sja1000dev(sizeof(struct kvaser_pci));
if (dev == NULL)
return -ENOMEM;
priv = netdev_priv(dev);
board = priv->priv;
board->pci_dev = pdev;
board->channel = channel;
/* S5920 */
board->conf_addr = conf_addr;
/* XILINX board wide address */
board->res_addr = res_addr;
if (channel == 0) {
board->xilinx_ver =
ioread8(board->res_addr + XILINX_VERINT) >> 4;
init_step = 2;
/* Assert PTADR# - we're in passive mode so the other bits are
not important */
iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR);
/* Enable interrupts from card */
kvaser_pci_enable_irq(dev);
} else {
struct sja1000_priv *master_priv = netdev_priv(*master_dev);
struct kvaser_pci *master_board = master_priv->priv;
master_board->slave_dev[channel - 1] = dev;
master_board->no_channels = channel + 1;
board->xilinx_ver = master_board->xilinx_ver;
}
priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES;
priv->read_reg = kvaser_pci_read_reg;
priv->write_reg = kvaser_pci_write_reg;
priv->can.clock.freq = KVASER_PCI_CAN_CLOCK;
priv->ocr = KVASER_PCI_OCR;
priv->cdr = KVASER_PCI_CDR;
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
init_step = 4;
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);
/* Register SJA1000 device */
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "Registering device failed (err=%d)\n",
err);
goto failure;
}
if (channel == 0)
*master_dev = dev;
return 0;
failure:
kvaser_pci_del_chan(dev);
return err;
}
static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err;
struct net_device *master_dev = NULL;
struct sja1000_priv *priv;
struct kvaser_pci *board;
int no_channels;
void __iomem *base_addr = NULL;
void __iomem *conf_addr = NULL;
void __iomem *res_addr = NULL;
int i;
dev_info(&pdev->dev, "initializing device %04x:%04x\n",
pdev->vendor, pdev->device);
err = pci_enable_device(pdev);
if (err)
goto failure;
err = pci_request_regions(pdev, DRV_NAME);
if (err)
goto failure_release_pci;
/* S5920 */
conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE);
if (conf_addr == NULL) {
err = -ENODEV;
goto failure_release_regions;
}
/* XILINX board wide address */
res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE);
if (res_addr == NULL) {
err = -ENOMEM;
goto failure_iounmap;
}
base_addr = pci_iomap(pdev, 1, PCI_PORT_SIZE);
if (base_addr == NULL) {
err = -ENOMEM;
goto failure_iounmap;
}
no_channels = number_of_sja1000_chip(base_addr);
if (no_channels == 0) {
err = -ENOMEM;
goto failure_iounmap;
}
for (i = 0; i < no_channels; i++) {
err = kvaser_pci_add_chan(pdev, i, &master_dev,
conf_addr, res_addr,
base_addr);
if (err)
goto failure_cleanup;
}
priv = netdev_priv(master_dev);
board = priv->priv;
dev_info(&pdev->dev, "xilinx version=%d number of channels=%d\n",
board->xilinx_ver, board->no_channels);
pci_set_drvdata(pdev, master_dev);
return 0;
failure_cleanup:
kvaser_pci_del_chan(master_dev);
failure_iounmap:
if (conf_addr != NULL)
pci_iounmap(pdev, conf_addr);
if (res_addr != NULL)
pci_iounmap(pdev, res_addr);
if (base_addr != NULL)
pci_iounmap(pdev, base_addr);
failure_release_regions:
pci_release_regions(pdev);
failure_release_pci:
pci_disable_device(pdev);
failure:
return err;
}
static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
kvaser_pci_del_chan(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
static struct pci_driver kvaser_pci_driver = {
.name = DRV_NAME,
.id_table = kvaser_pci_tbl,
.probe = kvaser_pci_init_one,
.remove = __devexit_p(kvaser_pci_remove_one),
};
static int __init kvaser_pci_init(void)
{
return pci_register_driver(&kvaser_pci_driver);
}
static void __exit kvaser_pci_exit(void)
{
pci_unregister_driver(&kvaser_pci_driver);
}
module_init(kvaser_pci_init);
module_exit(kvaser_pci_exit);

View File

@@ -0,0 +1,762 @@
/*
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
* Copyright (C) 2001-2006 PEAK System-Technik GmbH
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include "sja1000.h"
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
MODULE_LICENSE("GPL v2");
#define DRV_NAME "peak_pci"
struct peak_pciec_card;
struct peak_pci_chan {
void __iomem *cfg_base; /* Common for all channels */
struct net_device *prev_dev; /* Chain of network devices */
u16 icr_mask; /* Interrupt mask for fast ack */
struct peak_pciec_card *pciec_card; /* only for PCIeC LEDs */
};
#define PEAK_PCI_CAN_CLOCK (16000000 / 2)
#define PEAK_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
#define PEAK_PCI_OCR OCR_TX0_PUSHPULL
/*
* Important PITA registers
*/
#define PITA_ICR 0x00 /* Interrupt control register */
#define PITA_GPIOICR 0x18 /* GPIO interface control register */
#define PITA_MISC 0x1C /* Miscellaneous register */
#define PEAK_PCI_CFG_SIZE 0x1000 /* Size of the config PCI bar */
#define PEAK_PCI_CHAN_SIZE 0x0400 /* Size used by the channel */
#define PEAK_PCI_VENDOR_ID 0x001C /* The PCI device and vendor IDs */
#define PEAK_PCI_DEVICE_ID 0x0001 /* for PCI/PCIe slot cards */
#define PEAK_PCIEC_DEVICE_ID 0x0002 /* for ExpressCard slot cards */
#define PEAK_PCIE_DEVICE_ID 0x0003 /* for nextgen PCIe slot cards */
#define PEAK_MPCI_DEVICE_ID 0x0008 /* The miniPCI slot cards */
#define PEAK_PCI_CHAN_MAX 4
static const u16 peak_pci_icr_masks[PEAK_PCI_CHAN_MAX] = {
0x02, 0x01, 0x40, 0x80
};
static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = {
{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
#ifdef CONFIG_CAN_PEAK_PCIEC
{PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
#endif
{0,}
};
MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
#ifdef CONFIG_CAN_PEAK_PCIEC
/*
* PCAN-ExpressCard needs I2C bit-banging configuration option.
*/
/* GPIOICR byte access offsets */
#define PITA_GPOUT 0x18 /* GPx output value */
#define PITA_GPIN 0x19 /* GPx input value */
#define PITA_GPOEN 0x1A /* configure GPx as ouput pin */
/* I2C GP bits */
#define PITA_GPIN_SCL 0x01 /* Serial Clock Line */
#define PITA_GPIN_SDA 0x04 /* Serial DAta line */
#define PCA9553_1_SLAVEADDR (0xC4 >> 1)
/* PCA9553 LS0 fields values */
enum {
PCA9553_LOW,
PCA9553_HIGHZ,
PCA9553_PWM0,
PCA9553_PWM1
};
/* LEDs control */
#define PCA9553_ON PCA9553_LOW
#define PCA9553_OFF PCA9553_HIGHZ
#define PCA9553_SLOW PCA9553_PWM0
#define PCA9553_FAST PCA9553_PWM1
#define PCA9553_LED(c) (1 << (c))
#define PCA9553_LED_STATE(s, c) ((s) << ((c) << 1))
#define PCA9553_LED_ON(c) PCA9553_LED_STATE(PCA9553_ON, c)
#define PCA9553_LED_OFF(c) PCA9553_LED_STATE(PCA9553_OFF, c)
#define PCA9553_LED_SLOW(c) PCA9553_LED_STATE(PCA9553_SLOW, c)
#define PCA9553_LED_FAST(c) PCA9553_LED_STATE(PCA9553_FAST, c)
#define PCA9553_LED_MASK(c) PCA9553_LED_STATE(0x03, c)
#define PCA9553_LED_OFF_ALL (PCA9553_LED_OFF(0) | PCA9553_LED_OFF(1))
#define PCA9553_LS0_INIT 0x40 /* initial value (!= from 0x00) */
struct peak_pciec_chan {
struct net_device *netdev;
unsigned long prev_rx_bytes;
unsigned long prev_tx_bytes;
};
struct peak_pciec_card {
void __iomem *cfg_base; /* Common for all channels */
void __iomem *reg_base; /* first channel base address */
u8 led_cache; /* leds state cache */
/* PCIExpressCard i2c data */
struct i2c_algo_bit_data i2c_bit;
struct i2c_adapter led_chip;
struct delayed_work led_work; /* led delayed work */
int chan_count;
struct peak_pciec_chan channel[PEAK_PCI_CHAN_MAX];
};
/* "normal" pci register write callback is overloaded for leds control */
static void peak_pci_write_reg(const struct sja1000_priv *priv,
int port, u8 val);
static inline void pita_set_scl_highz(struct peak_pciec_card *card)
{
u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SCL;
writeb(gp_outen, card->cfg_base + PITA_GPOEN);
}
static inline void pita_set_sda_highz(struct peak_pciec_card *card)
{
u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SDA;
writeb(gp_outen, card->cfg_base + PITA_GPOEN);
}
static void peak_pciec_init_pita_gpio(struct peak_pciec_card *card)
{
/* raise SCL & SDA GPIOs to high-Z */
pita_set_scl_highz(card);
pita_set_sda_highz(card);
}
static void pita_setsda(void *data, int state)
{
struct peak_pciec_card *card = (struct peak_pciec_card *)data;
u8 gp_out, gp_outen;
/* set output sda always to 0 */
gp_out = readb(card->cfg_base + PITA_GPOUT) & ~PITA_GPIN_SDA;
writeb(gp_out, card->cfg_base + PITA_GPOUT);
/* control output sda with GPOEN */
gp_outen = readb(card->cfg_base + PITA_GPOEN);
if (state)
gp_outen &= ~PITA_GPIN_SDA;
else
gp_outen |= PITA_GPIN_SDA;
writeb(gp_outen, card->cfg_base + PITA_GPOEN);
}
static void pita_setscl(void *data, int state)
{
struct peak_pciec_card *card = (struct peak_pciec_card *)data;
u8 gp_out, gp_outen;
/* set output scl always to 0 */
gp_out = readb(card->cfg_base + PITA_GPOUT) & ~PITA_GPIN_SCL;
writeb(gp_out, card->cfg_base + PITA_GPOUT);
/* control output scl with GPOEN */
gp_outen = readb(card->cfg_base + PITA_GPOEN);
if (state)
gp_outen &= ~PITA_GPIN_SCL;
else
gp_outen |= PITA_GPIN_SCL;
writeb(gp_outen, card->cfg_base + PITA_GPOEN);
}
static int pita_getsda(void *data)
{
struct peak_pciec_card *card = (struct peak_pciec_card *)data;
/* set tristate */
pita_set_sda_highz(card);
return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SDA) ? 1 : 0;
}
static int pita_getscl(void *data)
{
struct peak_pciec_card *card = (struct peak_pciec_card *)data;
/* set tristate */
pita_set_scl_highz(card);
return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SCL) ? 1 : 0;
}
/*
* write commands to the LED chip though the I2C-bus of the PCAN-PCIeC
*/
static int peak_pciec_write_pca9553(struct peak_pciec_card *card,
u8 offset, u8 data)
{
u8 buffer[2] = {
offset,
data
};
struct i2c_msg msg = {
.addr = PCA9553_1_SLAVEADDR,
.len = 2,
.buf = buffer,
};
int ret;
/* cache led mask */
if ((offset == 5) && (data == card->led_cache))
return 0;
ret = i2c_transfer(&card->led_chip, &msg, 1);
if (ret < 0)
return ret;
if (offset == 5)
card->led_cache = data;
return 0;
}
/*
* delayed work callback used to control the LEDs
*/
static void peak_pciec_led_work(struct work_struct *work)
{
struct peak_pciec_card *card =
container_of(work, struct peak_pciec_card, led_work.work);
struct net_device *netdev;
u8 new_led = card->led_cache;
int i, up_count = 0;
/* first check what is to do */
for (i = 0; i < card->chan_count; i++) {
/* default is: not configured */
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_ON(i);
netdev = card->channel[i].netdev;
if (!netdev || !(netdev->flags & IFF_UP))
continue;
up_count++;
/* no activity (but configured) */
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_SLOW(i);
/* if bytes counters changed, set fast blinking led */
if (netdev->stats.rx_bytes != card->channel[i].prev_rx_bytes) {
card->channel[i].prev_rx_bytes = netdev->stats.rx_bytes;
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_FAST(i);
}
if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_FAST(i);
}
}
/* check if LS0 settings changed, only update i2c if so */
peak_pciec_write_pca9553(card, 5, new_led);
/* restart timer (except if no more configured channels) */
if (up_count)
schedule_delayed_work(&card->led_work, HZ);
}
/*
* set LEDs blinking state
*/
static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
{
u8 new_led = card->led_cache;
int i;
/* first check what is to do */
for (i = 0; i < card->chan_count; i++)
if (led_mask & PCA9553_LED(i)) {
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_STATE(s, i);
}
/* check if LS0 settings changed, only update i2c if so */
peak_pciec_write_pca9553(card, 5, new_led);
}
/*
* start one second delayed work to control LEDs
*/
static void peak_pciec_start_led_work(struct peak_pciec_card *card)
{
if (!delayed_work_pending(&card->led_work))
schedule_delayed_work(&card->led_work, HZ);
}
/*
* stop LEDs delayed work
*/
static void peak_pciec_stop_led_work(struct peak_pciec_card *card)
{
cancel_delayed_work_sync(&card->led_work);
}
/*
* initialize the PCA9553 4-bit I2C-bus LED chip
*/
static int peak_pciec_init_leds(struct peak_pciec_card *card)
{
int err;
/* prescaler for frequency 0: "SLOW" = 1 Hz = "44" */
err = peak_pciec_write_pca9553(card, 1, 44 / 1);
if (err)
return err;
/* duty cycle 0: 50% */
err = peak_pciec_write_pca9553(card, 2, 0x80);
if (err)
return err;
/* prescaler for frequency 1: "FAST" = 5 Hz */
err = peak_pciec_write_pca9553(card, 3, 44 / 5);
if (err)
return err;
/* duty cycle 1: 50% */
err = peak_pciec_write_pca9553(card, 4, 0x80);
if (err)
return err;
/* switch LEDs to initial state */
return peak_pciec_write_pca9553(card, 5, PCA9553_LS0_INIT);
}
/*
* restore LEDs state to off peak_pciec_leds_exit
*/
static void peak_pciec_leds_exit(struct peak_pciec_card *card)
{
/* switch LEDs to off */
peak_pciec_write_pca9553(card, 5, PCA9553_LED_OFF_ALL);
}
/*
* normal write sja1000 register method overloaded to catch when controller
* is started or stopped, to control leds
*/
static void peak_pciec_write_reg(const struct sja1000_priv *priv,
int port, u8 val)
{
struct peak_pci_chan *chan = priv->priv;
struct peak_pciec_card *card = chan->pciec_card;
int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE;
/* sja1000 register changes control the leds state */
if (port == REG_MOD)
switch (val) {
case MOD_RM:
/* Reset Mode: set led on */
peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_ON);
break;
case 0x00:
/* Normal Mode: led slow blinking and start led timer */
peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_SLOW);
peak_pciec_start_led_work(card);
break;
default:
break;
}
/* call base function */
peak_pci_write_reg(priv, port, val);
}
static struct i2c_algo_bit_data peak_pciec_i2c_bit_ops = {
.setsda = pita_setsda,
.setscl = pita_setscl,
.getsda = pita_getsda,
.getscl = pita_getscl,
.udelay = 10,
.timeout = HZ,
};
static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct peak_pci_chan *chan = priv->priv;
struct peak_pciec_card *card;
int err;
/* copy i2c object address from 1st channel */
if (chan->prev_dev) {
struct sja1000_priv *prev_priv = netdev_priv(chan->prev_dev);
struct peak_pci_chan *prev_chan = prev_priv->priv;
card = prev_chan->pciec_card;
if (!card)
return -ENODEV;
/* channel is the first one: do the init part */
} else {
/* create the bit banging I2C adapter structure */
card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
if (!card) {
dev_err(&pdev->dev,
"failed allocating memory for i2c chip\n");
return -ENOMEM;
}
card->cfg_base = chan->cfg_base;
card->reg_base = priv->reg_base;
card->led_chip.owner = THIS_MODULE;
card->led_chip.dev.parent = &pdev->dev;
card->led_chip.algo_data = &card->i2c_bit;
strncpy(card->led_chip.name, "peak_i2c",
sizeof(card->led_chip.name));
card->i2c_bit = peak_pciec_i2c_bit_ops;
card->i2c_bit.udelay = 10;
card->i2c_bit.timeout = HZ;
card->i2c_bit.data = card;
peak_pciec_init_pita_gpio(card);
err = i2c_bit_add_bus(&card->led_chip);
if (err) {
dev_err(&pdev->dev, "i2c init failed\n");
goto pciec_init_err_1;
}
err = peak_pciec_init_leds(card);
if (err) {
dev_err(&pdev->dev, "leds hardware init failed\n");
goto pciec_init_err_2;
}
INIT_DELAYED_WORK(&card->led_work, peak_pciec_led_work);
/* PCAN-ExpressCard needs its own callback for leds */
priv->write_reg = peak_pciec_write_reg;
}
chan->pciec_card = card;
card->channel[card->chan_count++].netdev = dev;
return 0;
pciec_init_err_2:
i2c_del_adapter(&card->led_chip);
pciec_init_err_1:
peak_pciec_init_pita_gpio(card);
kfree(card);
return err;
}
static void peak_pciec_remove(struct peak_pciec_card *card)
{
peak_pciec_stop_led_work(card);
peak_pciec_leds_exit(card);
i2c_del_adapter(&card->led_chip);
peak_pciec_init_pita_gpio(card);
kfree(card);
}
#else /* CONFIG_CAN_PEAK_PCIEC */
/*
* Placebo functions when PCAN-ExpressCard support is not selected
*/
static inline int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
{
return -ENODEV;
}
static inline void peak_pciec_remove(struct peak_pciec_card *card)
{
}
#endif /* CONFIG_CAN_PEAK_PCIEC */
static u8 peak_pci_read_reg(const struct sja1000_priv *priv, int port)
{
return readb(priv->reg_base + (port << 2));
}
static void peak_pci_write_reg(const struct sja1000_priv *priv,
int port, u8 val)
{
writeb(val, priv->reg_base + (port << 2));
}
static void peak_pci_post_irq(const struct sja1000_priv *priv)
{
struct peak_pci_chan *chan = priv->priv;
u16 icr;
/* Select and clear in PITA stored interrupt */
icr = readw(chan->cfg_base + PITA_ICR);
if (icr & chan->icr_mask)
writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
}
static int __devinit peak_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct peak_pci_chan *chan;
struct net_device *dev;
void __iomem *cfg_base, *reg_base;
u16 sub_sys_id, icr;
int i, err, channels;
err = pci_enable_device(pdev);
if (err)
return err;
err = pci_request_regions(pdev, DRV_NAME);
if (err)
goto failure_disable_pci;
err = pci_read_config_word(pdev, 0x2e, &sub_sys_id);
if (err)
goto failure_release_regions;
dev_dbg(&pdev->dev, "probing device %04x:%04x:%04x\n",
pdev->vendor, pdev->device, sub_sys_id);
err = pci_write_config_word(pdev, 0x44, 0);
if (err)
goto failure_release_regions;
if (sub_sys_id >= 12)
channels = 4;
else if (sub_sys_id >= 10)
channels = 3;
else if (sub_sys_id >= 4)
channels = 2;
else
channels = 1;
cfg_base = pci_iomap(pdev, 0, PEAK_PCI_CFG_SIZE);
if (!cfg_base) {
dev_err(&pdev->dev, "failed to map PCI resource #0\n");
goto failure_release_regions;
}
reg_base = pci_iomap(pdev, 1, PEAK_PCI_CHAN_SIZE * channels);
if (!reg_base) {
dev_err(&pdev->dev, "failed to map PCI resource #1\n");
goto failure_unmap_cfg_base;
}
/* Set GPIO control register */
writew(0x0005, cfg_base + PITA_GPIOICR + 2);
/* Enable all channels of this card */
writeb(0x00, cfg_base + PITA_GPIOICR);
/* Toggle reset */
writeb(0x05, cfg_base + PITA_MISC + 3);
mdelay(5);
/* Leave parport mux mode */
writeb(0x04, cfg_base + PITA_MISC + 3);
icr = readw(cfg_base + PITA_ICR + 2);
for (i = 0; i < channels; i++) {
dev = alloc_sja1000dev(sizeof(struct peak_pci_chan));
if (!dev) {
err = -ENOMEM;
goto failure_remove_channels;
}
priv = netdev_priv(dev);
chan = priv->priv;
chan->cfg_base = cfg_base;
priv->reg_base = reg_base + i * PEAK_PCI_CHAN_SIZE;
priv->read_reg = peak_pci_read_reg;
priv->write_reg = peak_pci_write_reg;
priv->post_irq = peak_pci_post_irq;
priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
priv->ocr = PEAK_PCI_OCR;
priv->cdr = PEAK_PCI_CDR;
/* Neither a slave nor a single device distributes the clock */
if (channels == 1 || i > 0)
priv->cdr |= CDR_CLK_OFF;
/* Setup interrupt handling */
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
chan->icr_mask = peak_pci_icr_masks[i];
icr |= chan->icr_mask;
SET_NETDEV_DEV(dev, &pdev->dev);
/* Create chain of SJA1000 devices */
chan->prev_dev = pci_get_drvdata(pdev);
pci_set_drvdata(pdev, dev);
/*
* PCAN-ExpressCard needs some additional i2c init.
* This must be done *before* register_sja1000dev() but
* *after* devices linkage
*/
if (pdev->device == PEAK_PCIEC_DEVICE_ID) {
err = peak_pciec_probe(pdev, dev);
if (err) {
dev_err(&pdev->dev,
"failed to probe device (err %d)\n",
err);
goto failure_free_dev;
}
}
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "failed to register device\n");
goto failure_free_dev;
}
dev_info(&pdev->dev,
"%s at reg_base=0x%p cfg_base=0x%p irq=%d\n",
dev->name, priv->reg_base, chan->cfg_base, dev->irq);
}
/* Enable interrupts */
writew(icr, cfg_base + PITA_ICR + 2);
return 0;
failure_free_dev:
pci_set_drvdata(pdev, chan->prev_dev);
free_sja1000dev(dev);
failure_remove_channels:
/* Disable interrupts */
writew(0x0, cfg_base + PITA_ICR + 2);
chan = NULL;
for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
unregister_sja1000dev(dev);
free_sja1000dev(dev);
priv = netdev_priv(dev);
chan = priv->priv;
}
/* free any PCIeC resources too */
if (chan && chan->pciec_card)
peak_pciec_remove(chan->pciec_card);
pci_iounmap(pdev, reg_base);
failure_unmap_cfg_base:
pci_iounmap(pdev, cfg_base);
failure_release_regions:
pci_release_regions(pdev);
failure_disable_pci:
pci_disable_device(pdev);
return err;
}
static void __devexit peak_pci_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev); /* Last device */
struct sja1000_priv *priv = netdev_priv(dev);
struct peak_pci_chan *chan = priv->priv;
void __iomem *cfg_base = chan->cfg_base;
void __iomem *reg_base = priv->reg_base;
/* Disable interrupts */
writew(0x0, cfg_base + PITA_ICR + 2);
/* Loop over all registered devices */
while (1) {
dev_info(&pdev->dev, "removing device %s\n", dev->name);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
dev = chan->prev_dev;
if (!dev) {
/* do that only for first channel */
if (chan->pciec_card)
peak_pciec_remove(chan->pciec_card);
break;
}
priv = netdev_priv(dev);
chan = priv->priv;
}
pci_iounmap(pdev, reg_base);
pci_iounmap(pdev, cfg_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
static struct pci_driver peak_pci_driver = {
.name = DRV_NAME,
.id_table = peak_pci_tbl,
.probe = peak_pci_probe,
.remove = __devexit_p(peak_pci_remove),
};
static int __init peak_pci_init(void)
{
return pci_register_driver(&peak_pci_driver);
}
module_init(peak_pci_init);
static void __exit peak_pci_exit(void)
{
pci_unregister_driver(&peak_pci_driver);
}
module_exit(peak_pci_exit);

View File

@@ -0,0 +1,753 @@
/*
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* CAN driver for PEAK-System PCAN-PC Card
* Derived from the PCAN project file driver/src/pcan_pccard.c
* Copyright (C) 2006-2010 PEAK System-Technik GmbH
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include "sja1000.h"
MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
MODULE_DESCRIPTION("CAN driver for PEAK-System PCAN-PC Cards");
MODULE_LICENSE("GPL v2");
MODULE_SUPPORTED_DEVICE("PEAK PCAN-PC Card");
/* PEAK-System PCMCIA driver name */
#define PCC_NAME "peak_pcmcia"
#define PCC_CHAN_MAX 2
#define PCC_CAN_CLOCK (16000000 / 2)
#define PCC_MANF_ID 0x0377
#define PCC_CARD_ID 0x0001
#define PCC_CHAN_SIZE 0x20
#define PCC_CHAN_OFF(c) ((c) * PCC_CHAN_SIZE)
#define PCC_COMN_OFF (PCC_CHAN_OFF(PCC_CHAN_MAX))
#define PCC_COMN_SIZE 0x40
/* common area registers */
#define PCC_CCR 0x00
#define PCC_CSR 0x02
#define PCC_CPR 0x04
#define PCC_SPI_DIR 0x06
#define PCC_SPI_DOR 0x08
#define PCC_SPI_ADR 0x0a
#define PCC_SPI_IR 0x0c
#define PCC_FW_MAJOR 0x10
#define PCC_FW_MINOR 0x12
/* CCR bits */
#define PCC_CCR_CLK_16 0x00
#define PCC_CCR_CLK_10 0x01
#define PCC_CCR_CLK_21 0x02
#define PCC_CCR_CLK_8 0x03
#define PCC_CCR_CLK_MASK PCC_CCR_CLK_8
#define PCC_CCR_RST_CHAN(c) (0x01 << ((c) + 2))
#define PCC_CCR_RST_ALL (PCC_CCR_RST_CHAN(0) | PCC_CCR_RST_CHAN(1))
#define PCC_CCR_RST_MASK PCC_CCR_RST_ALL
/* led selection bits */
#define PCC_LED(c) (1 << (c))
#define PCC_LED_ALL (PCC_LED(0) | PCC_LED(1))
/* led state value */
#define PCC_LED_ON 0x00
#define PCC_LED_FAST 0x01
#define PCC_LED_SLOW 0x02
#define PCC_LED_OFF 0x03
#define PCC_CCR_LED_CHAN(s, c) ((s) << (((c) + 2) << 1))
#define PCC_CCR_LED_ON_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_ON, c)
#define PCC_CCR_LED_FAST_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_FAST, c)
#define PCC_CCR_LED_SLOW_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_SLOW, c)
#define PCC_CCR_LED_OFF_CHAN(c) PCC_CCR_LED_CHAN(PCC_LED_OFF, c)
#define PCC_CCR_LED_MASK_CHAN(c) PCC_CCR_LED_OFF_CHAN(c)
#define PCC_CCR_LED_OFF_ALL (PCC_CCR_LED_OFF_CHAN(0) | \
PCC_CCR_LED_OFF_CHAN(1))
#define PCC_CCR_LED_MASK PCC_CCR_LED_OFF_ALL
#define PCC_CCR_INIT (PCC_CCR_CLK_16 | PCC_CCR_RST_ALL | PCC_CCR_LED_OFF_ALL)
/* CSR bits */
#define PCC_CSR_SPI_BUSY 0x04
/* time waiting for SPI busy (prevent from infinite loop) */
#define PCC_SPI_MAX_BUSY_WAIT_MS 3
/* max count of reading the SPI status register waiting for a change */
/* (prevent from infinite loop) */
#define PCC_WRITE_MAX_LOOP 1000
/* max nb of int handled by that isr in one shot (prevent from infinite loop) */
#define PCC_ISR_MAX_LOOP 10
/* EEPROM chip instruction set */
/* note: EEPROM Read/Write instructions include A8 bit */
#define PCC_EEP_WRITE(a) (0x02 | (((a) & 0x100) >> 5))
#define PCC_EEP_READ(a) (0x03 | (((a) & 0x100) >> 5))
#define PCC_EEP_WRDI 0x04 /* EEPROM Write Disable */
#define PCC_EEP_RDSR 0x05 /* EEPROM Read Status Register */
#define PCC_EEP_WREN 0x06 /* EEPROM Write Enable */
/* EEPROM Status Register bits */
#define PCC_EEP_SR_WEN 0x02 /* EEPROM SR Write Enable bit */
#define PCC_EEP_SR_WIP 0x01 /* EEPROM SR Write In Progress bit */
/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
* This means normal output mode, push-pull and the correct polarity.
*/
#define PCC_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
/*
* In the CDR register, you should set CBP to 1.
* You will probably also want to set the clock divider value to 7
* (meaning direct oscillator output) because the second SJA1000 chip
* is driven by the first one CLKOUT output.
*/
#define PCC_CDR (CDR_CBP | CDR_CLKOUT_MASK)
struct pcan_channel {
struct net_device *netdev;
unsigned long prev_rx_bytes;
unsigned long prev_tx_bytes;
};
/* PCAN-PC Card private structure */
struct pcan_pccard {
struct pcmcia_device *pdev;
int chan_count;
struct pcan_channel channel[PCC_CHAN_MAX];
u8 ccr;
u8 fw_major;
u8 fw_minor;
void __iomem *ioport_addr;
struct timer_list led_timer;
};
static struct pcmcia_device_id pcan_table[] = {
PCMCIA_DEVICE_MANF_CARD(PCC_MANF_ID, PCC_CARD_ID),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, pcan_table);
static void pcan_set_leds(struct pcan_pccard *card, u8 mask, u8 state);
/*
* start timer which controls leds state
*/
static void pcan_start_led_timer(struct pcan_pccard *card)
{
if (!timer_pending(&card->led_timer))
mod_timer(&card->led_timer, jiffies + HZ);
}
/*
* stop the timer which controls leds state
*/
static void pcan_stop_led_timer(struct pcan_pccard *card)
{
del_timer_sync(&card->led_timer);
}
/*
* read a sja1000 register
*/
static u8 pcan_read_canreg(const struct sja1000_priv *priv, int port)
{
return ioread8(priv->reg_base + port);
}
/*
* write a sja1000 register
*/
static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v)
{
struct pcan_pccard *card = priv->priv;
int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;
/* sja1000 register changes control the leds state */
if (port == REG_MOD)
switch (v) {
case MOD_RM:
/* Reset Mode: set led on */
pcan_set_leds(card, PCC_LED(c), PCC_LED_ON);
break;
case 0x00:
/* Normal Mode: led slow blinking and start led timer */
pcan_set_leds(card, PCC_LED(c), PCC_LED_SLOW);
pcan_start_led_timer(card);
break;
default:
break;
}
iowrite8(v, priv->reg_base + port);
}
/*
* read a register from the common area
*/
static u8 pcan_read_reg(struct pcan_pccard *card, int port)
{
return ioread8(card->ioport_addr + PCC_COMN_OFF + port);
}
/*
* write a register into the common area
*/
static void pcan_write_reg(struct pcan_pccard *card, int port, u8 v)
{
/* cache ccr value */
if (port == PCC_CCR) {
if (card->ccr == v)
return;
card->ccr = v;
}
iowrite8(v, card->ioport_addr + PCC_COMN_OFF + port);
}
/*
* check whether the card is present by checking its fw version numbers
* against values read at probing time.
*/
static inline int pcan_pccard_present(struct pcan_pccard *card)
{
return ((pcan_read_reg(card, PCC_FW_MAJOR) == card->fw_major) &&
(pcan_read_reg(card, PCC_FW_MINOR) == card->fw_minor));
}
/*
* wait for SPI engine while it is busy
*/
static int pcan_wait_spi_busy(struct pcan_pccard *card)
{
unsigned long timeout = jiffies +
msecs_to_jiffies(PCC_SPI_MAX_BUSY_WAIT_MS) + 1;
/* be sure to read status at least once after sleeping */
while (pcan_read_reg(card, PCC_CSR) & PCC_CSR_SPI_BUSY) {
if (time_after(jiffies, timeout))
return -EBUSY;
schedule();
}
return 0;
}
/*
* write data in device eeprom
*/
static int pcan_write_eeprom(struct pcan_pccard *card, u16 addr, u8 v)
{
u8 status;
int err, i;
/* write instruction enabling write */
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WREN);
err = pcan_wait_spi_busy(card);
if (err)
goto we_spi_err;
/* wait until write enabled */
for (i = 0; i < PCC_WRITE_MAX_LOOP; i++) {
/* write instruction reading the status register */
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_RDSR);
err = pcan_wait_spi_busy(card);
if (err)
goto we_spi_err;
/* get status register value and check write enable bit */
status = pcan_read_reg(card, PCC_SPI_DIR);
if (status & PCC_EEP_SR_WEN)
break;
}
if (i >= PCC_WRITE_MAX_LOOP) {
dev_err(&card->pdev->dev,
"stop waiting to be allowed to write in eeprom\n");
return -EIO;
}
/* set address and data */
pcan_write_reg(card, PCC_SPI_ADR, addr & 0xff);
pcan_write_reg(card, PCC_SPI_DOR, v);
/*
* write instruction with bit[3] set according to address value:
* if addr refers to upper half of the memory array: bit[3] = 1
*/
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WRITE(addr));
err = pcan_wait_spi_busy(card);
if (err)
goto we_spi_err;
/* wait while write in progress */
for (i = 0; i < PCC_WRITE_MAX_LOOP; i++) {
/* write instruction reading the status register */
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_RDSR);
err = pcan_wait_spi_busy(card);
if (err)
goto we_spi_err;
/* get status register value and check write in progress bit */
status = pcan_read_reg(card, PCC_SPI_DIR);
if (!(status & PCC_EEP_SR_WIP))
break;
}
if (i >= PCC_WRITE_MAX_LOOP) {
dev_err(&card->pdev->dev,
"stop waiting for write in eeprom to complete\n");
return -EIO;
}
/* write instruction disabling write */
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WRDI);
err = pcan_wait_spi_busy(card);
if (err)
goto we_spi_err;
return 0;
we_spi_err:
dev_err(&card->pdev->dev,
"stop waiting (spi engine always busy) err %d\n", err);
return err;
}
static void pcan_set_leds(struct pcan_pccard *card, u8 led_mask, u8 state)
{
u8 ccr = card->ccr;
int i;
for (i = 0; i < card->chan_count; i++)
if (led_mask & PCC_LED(i)) {
/* clear corresponding led bits in ccr */
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
/* then set new bits */
ccr |= PCC_CCR_LED_CHAN(state, i);
}
/* real write only if something has changed in ccr */
pcan_write_reg(card, PCC_CCR, ccr);
}
/*
* enable/disable CAN connectors power
*/
static inline void pcan_set_can_power(struct pcan_pccard *card, int onoff)
{
int err;
err = pcan_write_eeprom(card, 0, !!onoff);
if (err)
dev_err(&card->pdev->dev,
"failed setting power %s to can connectors (err %d)\n",
(onoff) ? "on" : "off", err);
}
/*
* set leds state according to channel activity
*/
static void pcan_led_timer(unsigned long arg)
{
struct pcan_pccard *card = (struct pcan_pccard *)arg;
struct net_device *netdev;
int i, up_count = 0;
u8 ccr;
ccr = card->ccr;
for (i = 0; i < card->chan_count; i++) {
/* default is: not configured */
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_ON_CHAN(i);
netdev = card->channel[i].netdev;
if (!netdev || !(netdev->flags & IFF_UP))
continue;
up_count++;
/* no activity (but configured) */
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_SLOW_CHAN(i);
/* if bytes counters changed, set fast blinking led */
if (netdev->stats.rx_bytes != card->channel[i].prev_rx_bytes) {
card->channel[i].prev_rx_bytes = netdev->stats.rx_bytes;
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_FAST_CHAN(i);
}
if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_FAST_CHAN(i);
}
}
/* write the new leds state */
pcan_write_reg(card, PCC_CCR, ccr);
/* restart timer (except if no more configured channels) */
if (up_count)
mod_timer(&card->led_timer, jiffies + HZ);
}
/*
* interrupt service routine
*/
static irqreturn_t pcan_isr(int irq, void *dev_id)
{
struct pcan_pccard *card = dev_id;
int irq_handled;
/* prevent from infinite loop */
for (irq_handled = 0; irq_handled < PCC_ISR_MAX_LOOP; irq_handled++) {
/* handle shared interrupt and next loop */
int nothing_to_handle = 1;
int i;
/* check interrupt for each channel */
for (i = 0; i < card->chan_count; i++) {
struct net_device *netdev;
/*
* check whether the card is present before calling
* sja1000_interrupt() to speed up hotplug detection
*/
if (!pcan_pccard_present(card)) {
/* card unplugged during isr */
return IRQ_NONE;
}
/*
* should check whether all or SJA1000_MAX_IRQ
* interrupts have been handled: loop again to be sure.
*/
netdev = card->channel[i].netdev;
if (netdev &&
sja1000_interrupt(irq, netdev) == IRQ_HANDLED)
nothing_to_handle = 0;
}
if (nothing_to_handle)
break;
}
return (irq_handled) ? IRQ_HANDLED : IRQ_NONE;
}
/*
* free all resources used by the channels and switch off leds and can power
*/
static void pcan_free_channels(struct pcan_pccard *card)
{
int i;
u8 led_mask = 0;
for (i = 0; i < card->chan_count; i++) {
struct net_device *netdev;
char name[IFNAMSIZ];
led_mask |= PCC_LED(i);
netdev = card->channel[i].netdev;
if (!netdev)
continue;
strncpy(name, netdev->name, IFNAMSIZ);
unregister_sja1000dev(netdev);
free_sja1000dev(netdev);
dev_info(&card->pdev->dev, "%s removed\n", name);
}
/* do it only if device not removed */
if (pcan_pccard_present(card)) {
pcan_set_leds(card, led_mask, PCC_LED_OFF);
pcan_set_can_power(card, 0);
}
}
/*
* check if a CAN controller is present at the specified location
*/
static inline int pcan_channel_present(struct sja1000_priv *priv)
{
/* make sure SJA1000 is in reset mode */
pcan_write_canreg(priv, REG_MOD, 1);
pcan_write_canreg(priv, REG_CDR, CDR_PELICAN);
/* read reset-values */
if (pcan_read_canreg(priv, REG_CDR) == CDR_PELICAN)
return 1;
return 0;
}
static int pcan_add_channels(struct pcan_pccard *card)
{
struct pcmcia_device *pdev = card->pdev;
int i, err = 0;
u8 ccr = PCC_CCR_INIT;
/* init common registers (reset channels and leds off) */
card->ccr = ~ccr;
pcan_write_reg(card, PCC_CCR, ccr);
/* wait 2ms before unresetting channels */
mdelay(2);
ccr &= ~PCC_CCR_RST_ALL;
pcan_write_reg(card, PCC_CCR, ccr);
/* create one network device per channel detected */
for (i = 0; i < ARRAY_SIZE(card->channel); i++) {
struct net_device *netdev;
struct sja1000_priv *priv;
netdev = alloc_sja1000dev(0);
if (!netdev) {
err = -ENOMEM;
break;
}
/* update linkages */
priv = netdev_priv(netdev);
priv->priv = card;
SET_NETDEV_DEV(netdev, &pdev->dev);
priv->irq_flags = IRQF_SHARED;
netdev->irq = pdev->irq;
priv->reg_base = card->ioport_addr + PCC_CHAN_OFF(i);
/* check if channel is present */
if (!pcan_channel_present(priv)) {
dev_err(&pdev->dev, "channel %d not present\n", i);
free_sja1000dev(netdev);
continue;
}
priv->read_reg = pcan_read_canreg;
priv->write_reg = pcan_write_canreg;
priv->can.clock.freq = PCC_CAN_CLOCK;
priv->ocr = PCC_OCR;
priv->cdr = PCC_CDR;
/* Neither a slave device distributes the clock */
if (i > 0)
priv->cdr |= CDR_CLK_OFF;
priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
/* register SJA1000 device */
err = register_sja1000dev(netdev);
if (err) {
free_sja1000dev(netdev);
continue;
}
card->channel[i].netdev = netdev;
card->chan_count++;
/* set corresponding led on in the new ccr */
ccr &= ~PCC_CCR_LED_OFF_CHAN(i);
dev_info(&pdev->dev,
"%s on channel %d at 0x%p irq %d\n",
netdev->name, i, priv->reg_base, pdev->irq);
}
/* write new ccr (change leds state) */
pcan_write_reg(card, PCC_CCR, ccr);
return err;
}
static int pcan_conf_check(struct pcmcia_device *pdev, void *priv_data)
{
pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; /* only */
pdev->io_lines = 10;
/* This reserves IO space but doesn't actually enable it */
return pcmcia_request_io(pdev);
}
/*
* free all resources used by the device
*/
static void pcan_free(struct pcmcia_device *pdev)
{
struct pcan_pccard *card = pdev->priv;
if (!card)
return;
free_irq(pdev->irq, card);
pcan_stop_led_timer(card);
pcan_free_channels(card);
ioport_unmap(card->ioport_addr);
kfree(card);
pdev->priv = NULL;
}
/*
* setup PCMCIA socket and probe for PEAK-System PC-CARD
*/
static int __devinit pcan_probe(struct pcmcia_device *pdev)
{
struct pcan_pccard *card;
int err;
pdev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
err = pcmcia_loop_config(pdev, pcan_conf_check, NULL);
if (err) {
dev_err(&pdev->dev, "pcmcia_loop_config() error %d\n", err);
goto probe_err_1;
}
if (!pdev->irq) {
dev_err(&pdev->dev, "no irq assigned\n");
err = -ENODEV;
goto probe_err_1;
}
err = pcmcia_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "pcmcia_enable_device failed err=%d\n",
err);
goto probe_err_1;
}
card = kzalloc(sizeof(struct pcan_pccard), GFP_KERNEL);
if (!card) {
dev_err(&pdev->dev, "couldn't allocate card memory\n");
err = -ENOMEM;
goto probe_err_2;
}
card->pdev = pdev;
pdev->priv = card;
/* sja1000 api uses iomem */
card->ioport_addr = ioport_map(pdev->resource[0]->start,
resource_size(pdev->resource[0]));
if (!card->ioport_addr) {
dev_err(&pdev->dev, "couldn't map io port into io memory\n");
err = -ENOMEM;
goto probe_err_3;
}
card->fw_major = pcan_read_reg(card, PCC_FW_MAJOR);
card->fw_minor = pcan_read_reg(card, PCC_FW_MINOR);
/* display board name and firware version */
dev_info(&pdev->dev, "PEAK-System pcmcia card %s fw %d.%d\n",
pdev->prod_id[1] ? pdev->prod_id[1] : "PCAN-PC Card",
card->fw_major, card->fw_minor);
/* detect available channels */
pcan_add_channels(card);
if (!card->chan_count)
goto probe_err_4;
/* init the timer which controls the leds */
init_timer(&card->led_timer);
card->led_timer.function = pcan_led_timer;
card->led_timer.data = (unsigned long)card;
/* request the given irq */
err = request_irq(pdev->irq, &pcan_isr, IRQF_SHARED, PCC_NAME, card);
if (err) {
dev_err(&pdev->dev, "couldn't request irq%d\n", pdev->irq);
goto probe_err_5;
}
/* power on the connectors */
pcan_set_can_power(card, 1);
return 0;
probe_err_5:
/* unregister can devices from network */
pcan_free_channels(card);
probe_err_4:
ioport_unmap(card->ioport_addr);
probe_err_3:
kfree(card);
pdev->priv = NULL;
probe_err_2:
pcmcia_disable_device(pdev);
probe_err_1:
return err;
}
/*
* release claimed resources
*/
static void pcan_remove(struct pcmcia_device *pdev)
{
pcan_free(pdev);
pcmcia_disable_device(pdev);
}
static struct pcmcia_driver pcan_driver = {
.name = PCC_NAME,
.probe = pcan_probe,
.remove = pcan_remove,
.id_table = pcan_table,
};
static int __init pcan_init(void)
{
return pcmcia_register_driver(&pcan_driver);
}
module_init(pcan_init);
static void __exit pcan_exit(void)
{
pcmcia_unregister_driver(&pcan_driver);
}
module_exit(pcan_exit);

View File

@@ -0,0 +1,623 @@
/*
* Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
*
* Derived from the ems_pci.c driver:
* Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
* Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/can/dev.h>
#include <linux/io.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_plx_pci"
MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>");
MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
"the SJA1000 chips");
MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
"Adlink PCI-7841/cPCI-7841 SE, "
"Marathon CAN-bus-PCI, "
"TEWS TECHNOLOGIES TPMC810, "
"esd CAN-PCI/CPCI/PCI104/200, "
"esd CAN-PCI/PMC/266, "
"esd CAN-PCIe/2000, "
"IXXAT PC-I 04/PCI")
MODULE_LICENSE("GPL v2");
#define PLX_PCI_MAX_CHAN 2
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)
/* 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
* Control register
*/
#define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */
#define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */
#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.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
* This means normal output mode, push-pull and the correct polarity.
*/
#define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
/*
* In the CDR register, you should set CBP to 1.
* You will probably also want to set the clock divider value to 7
* (meaning direct oscillator output) because the second SJA1000 chip
* is driven by the first one CLKOUT output.
*/
#define PLX_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
/* SJA1000 Control Register in the BasicCAN Mode */
#define REG_CR 0x00
/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
#define REG_CR_BASICCAN_INITIAL 0x21
#define REG_CR_BASICCAN_INITIAL_MASK 0xa1
#define REG_SR_BASICCAN_INITIAL 0x0c
#define REG_IR_BASICCAN_INITIAL 0xe0
/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
#define REG_MOD_PELICAN_INITIAL 0x01
#define REG_SR_PELICAN_INITIAL 0x3c
#define REG_IR_PELICAN_INITIAL 0x00
#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 IXXAT_PCI_VENDOR_ID 0x10b5
#define IXXAT_PCI_DEVICE_ID 0x9050
#define IXXAT_PCI_SUB_SYS_ID 0x2540
#define MARATHON_PCI_DEVICE_ID 0x2715
#define TEWS_PCI_VENDOR_ID 0x1498
#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A
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;
u32 offset;
u32 size; /* 0x00 - auto, e.g. length of entire bar */
};
struct plx_pci_card_info {
const char *name;
int channel_count;
u32 can_clock;
u8 ocr; /* output control register */
u8 cdr; /* clock divider register */
/* Parameters for mapping local configuration space */
struct plx_pci_channel_map conf_map;
/* Parameters for mapping the SJA1000 chips */
struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
/* Pointer to device-dependent reset function */
void (*reset_func)(struct pci_dev *pdev);
};
static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
"Adlink PCI-7841/cPCI-7841", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
&plx_pci_reset_common
/* based on PLX9052 */
};
static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
"Adlink PCI-7841/cPCI-7841 SE", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
&plx_pci_reset_common
/* 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_ixxat __devinitdata = {
"IXXAT PC-I 04/PCI", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x200, 0x80} },
&plx_pci_reset_common
/* based on PLX9050 */
};
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,
{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
&plx_pci_reset_marathon
/* based on PLX9052 */
};
static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
"TEWS TECHNOLOGIES TPMC810", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
&plx_pci_reset_common
/* based on PLX9030 */
};
static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
{
/* Adlink PCI-7841/cPCI-7841 */
ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_NETWORK_OTHER << 8, ~0,
(kernel_ulong_t)&plx_pci_card_info_adlink
},
{
/* Adlink PCI-7841/cPCI-7841 SE */
ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
(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
},
{
/* IXXAT PC-I 04/PCI card */
IXXAT_PCI_VENDOR_ID, IXXAT_PCI_DEVICE_ID,
PCI_ANY_ID, IXXAT_PCI_SUB_SYS_ID,
0, 0,
(kernel_ulong_t)&plx_pci_card_info_ixxat
},
{
/* Marathon CAN-bus-PCI card */
PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
(kernel_ulong_t)&plx_pci_card_info_marathon
},
{
/* TEWS TECHNOLOGIES TPMC810 card */
TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
(kernel_ulong_t)&plx_pci_card_info_tews
},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
{
return ioread8(priv->reg_base + port);
}
static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
{
iowrite8(val, priv->reg_base + port);
}
/*
* Check if a CAN controller is present at the specified location
* by trying to switch 'em from the Basic mode into the PeliCAN mode.
* Also check states of some registers in reset mode.
*/
static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
{
int flag = 0;
/*
* Check registers after hardware reset (the Basic mode)
* See states on p. 10 of the Datasheet.
*/
if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
REG_CR_BASICCAN_INITIAL &&
(priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
(priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
flag = 1;
/* Bring the SJA1000 into the PeliCAN mode*/
priv->write_reg(priv, REG_CDR, CDR_PELICAN);
/*
* Check registers after reset in the PeliCAN mode.
* See states on p. 23 of the Datasheet.
*/
if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
return flag;
return 0;
}
/*
* 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.
*/
static void plx_pci_reset_common(struct pci_dev *pdev)
{
struct plx_pci_card *card = pci_get_drvdata(pdev);
u32 cntrl;
cntrl = ioread32(card->conf_addr + PLX_CNTRL);
cntrl |= PLX_PCI_RESET;
iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
udelay(100);
cntrl ^= PLX_PCI_RESET;
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)
{
void __iomem *reset_addr;
int i;
static const int reset_bar[2] = {3, 5};
plx_pci_reset_common(pdev);
for (i = 0; i < 2; i++) {
reset_addr = pci_iomap(pdev, reset_bar[i], 0);
if (!reset_addr) {
dev_err(&pdev->dev, "Failed to remap reset "
"space %d (BAR%d)\n", i, reset_bar[i]);
} else {
/* reset the SJA1000 chip */
iowrite8(0x1, reset_addr);
udelay(100);
pci_iounmap(pdev, reset_addr);
}
}
}
static void plx_pci_del_card(struct pci_dev *pdev)
{
struct plx_pci_card *card = pci_get_drvdata(pdev);
struct net_device *dev;
struct sja1000_priv *priv;
int i = 0;
for (i = 0; i < PLX_PCI_MAX_CHAN; i++) {
dev = card->net_dev[i];
if (!dev)
continue;
dev_info(&pdev->dev, "Removing %s\n", dev->name);
unregister_sja1000dev(dev);
priv = netdev_priv(dev);
if (priv->reg_base)
pci_iounmap(pdev, priv->reg_base);
free_sja1000dev(dev);
}
card->reset_func(pdev);
/*
* Disable interrupts from PCI-card and disable local
* interrupts
*/
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);
kfree(card);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
/*
* Probe PLX90xx based device for the SJA1000 chips and register each
* available CAN channel to SJA1000 Socket-CAN subsystem.
*/
static int __devinit plx_pci_add_card(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct net_device *dev;
struct plx_pci_card *card;
struct plx_pci_card_info *ci;
int err, i;
u32 val;
void __iomem *addr;
ci = (struct plx_pci_card_info *)ent->driver_data;
if (pci_enable_device(pdev) < 0) {
dev_err(&pdev->dev, "Failed to enable PCI device\n");
return -ENODEV;
}
dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
ci->name, PCI_SLOT(pdev->devfn));
/* Allocate card structures to hold addresses, ... */
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card) {
dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
pci_set_drvdata(pdev, card);
card->channels = 0;
/* Remap PLX90xx configuration space */
addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
if (!addr) {
err = -ENOMEM;
dev_err(&pdev->dev, "Failed to remap configuration space "
"(BAR%d)\n", ci->conf_map.bar);
goto failure_cleanup;
}
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++) {
struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
dev = alloc_sja1000dev(0);
if (!dev) {
err = -ENOMEM;
goto failure_cleanup;
}
card->net_dev[i] = dev;
priv = netdev_priv(dev);
priv->priv = card;
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
/*
* Remap IO space of the SJA1000 chips
* This is device-dependent mapping
*/
addr = pci_iomap(pdev, cm->bar, cm->size);
if (!addr) {
err = -ENOMEM;
dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
goto failure_cleanup;
}
priv->reg_base = addr + cm->offset;
priv->read_reg = plx_pci_read_reg;
priv->write_reg = plx_pci_write_reg;
/* Check if channel is present */
if (plx_pci_check_sja1000(priv)) {
priv->can.clock.freq = ci->can_clock;
priv->ocr = ci->ocr;
priv->cdr = ci->cdr;
SET_NETDEV_DEV(dev, &pdev->dev);
/* Register SJA1000 device */
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "Registering device failed "
"(err=%d)\n", err);
goto failure_cleanup;
}
card->channels++;
dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
"registered as %s\n", i + 1, priv->reg_base,
dev->irq, dev->name);
} else {
dev_err(&pdev->dev, "Channel #%d not detected\n",
i + 1);
free_sja1000dev(dev);
card->net_dev[i] = NULL;
}
}
if (!card->channels) {
err = -ENODEV;
goto failure_cleanup;
}
/*
* Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
* Local_2 interrupts from the SJA1000 chips
*/
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:
dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
plx_pci_del_card(pdev);
return err;
}
static struct pci_driver plx_pci_driver = {
.name = DRV_NAME,
.id_table = plx_pci_tbl,
.probe = plx_pci_add_card,
.remove = plx_pci_del_card,
};
static int __init plx_pci_init(void)
{
return pci_register_driver(&plx_pci_driver);
}
static void __exit plx_pci_exit(void)
{
pci_unregister_driver(&plx_pci_driver);
}
module_init(plx_pci_init);
module_exit(plx_pci_exit);

View File

@@ -0,0 +1,667 @@
/*
* sja1000.c - Philips SJA1000 network device driver
*
* Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
* 38106 Braunschweig, GERMANY
*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Volkswagen nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Alternatively, provided that this notice is retained in full, this
* software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2, in which case the provisions of the
* GPL apply INSTEAD OF those given above.
*
* The provided data structures and external interfaces from this code
* are not restricted to be used by modules with a GPL compatible license.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "sja1000.h"
#define DRV_NAME "sja1000"
MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver");
static struct can_bittiming_const sja1000_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.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_is_absent(struct sja1000_priv *priv)
{
return (priv->read_reg(priv, REG_MOD) == 0xFF);
}
static int sja1000_probe_chip(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
if (priv->reg_base && sja1000_is_absent(priv)) {
printk(KERN_INFO "%s: probing @0x%lX failed\n",
DRV_NAME, dev->base_addr);
return 0;
}
return -1;
}
static void set_reset_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
unsigned char status = priv->read_reg(priv, REG_MOD);
int i;
/* disable interrupts */
priv->write_reg(priv, REG_IER, IRQ_OFF);
for (i = 0; i < 100; i++) {
/* check reset bit */
if (status & MOD_RM) {
priv->can.state = CAN_STATE_STOPPED;
return;
}
priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */
udelay(10);
status = priv->read_reg(priv, REG_MOD);
}
netdev_err(dev, "setting SJA1000 into reset mode failed!\n");
}
static void set_normal_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
unsigned char status = priv->read_reg(priv, REG_MOD);
int i;
for (i = 0; i < 100; i++) {
/* check reset bit */
if ((status & MOD_RM) == 0) {
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
priv->write_reg(priv, REG_IER, IRQ_ALL);
else
priv->write_reg(priv, REG_IER,
IRQ_ALL & ~IRQ_BEI);
return;
}
/* set chip to normal mode */
priv->write_reg(priv, REG_MOD, 0x00);
udelay(10);
status = priv->read_reg(priv, REG_MOD);
}
netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
}
static void sja1000_start(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
/* leave reset mode */
if (priv->can.state != CAN_STATE_STOPPED)
set_reset_mode(dev);
/* Clear error counters and error code capture */
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);
}
static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
{
struct sja1000_priv *priv = netdev_priv(dev);
if (!priv->open_time)
return -EINVAL;
switch (mode) {
case CAN_MODE_START:
sja1000_start(dev);
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int sja1000_set_bittiming(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct can_bittiming *bt = &priv->can.bittiming;
u8 btr0, btr1;
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
(((bt->phase_seg2 - 1) & 0x7) << 4);
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
priv->write_reg(priv, REG_BTR0, btr0);
priv->write_reg(priv, REG_BTR1, btr1);
return 0;
}
static int sja1000_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct sja1000_priv *priv = netdev_priv(dev);
bec->txerr = priv->read_reg(priv, REG_TXERR);
bec->rxerr = priv->read_reg(priv, REG_RXERR);
return 0;
}
/*
* initialize SJA1000 chip:
* - reset chip
* - set output mode
* - set baudrate
* - enable interrupts
* - start operating mode
*/
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(priv, REG_CDR, priv->cdr | CDR_PELICAN);
/* set acceptance filter (accept all) */
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(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(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
}
/*
* transmit a CAN message
* message layout in the sk_buff should be like this:
* xx xx xx xx ff ll 00 11 22 33 44 55 66 77
* [ can-id ] [flags] [len] [can data (up to 8 bytes]
*/
static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;
uint8_t fi;
uint8_t dlc;
canid_t id;
uint8_t dreg;
int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
fi = dlc = cf->can_dlc;
id = cf->can_id;
if (id & CAN_RTR_FLAG)
fi |= FI_RTR;
if (id & CAN_EFF_FLAG) {
fi |= FI_FF;
dreg = EFF_BUF;
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(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(priv, dreg++, cf->data[i]);
can_put_echo_skb(skb, dev, 0);
sja1000_write_cmdreg(priv, CMD_TR);
return NETDEV_TX_OK;
}
static void sja1000_rx(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
uint8_t fi;
uint8_t dreg;
canid_t id;
int i;
/* create zero'ed CAN frame buffer */
skb = alloc_can_skb(dev, &cf);
if (skb == NULL)
return;
fi = priv->read_reg(priv, REG_FI);
if (fi & FI_FF) {
/* extended frame format (EFF) */
dreg = EFF_BUF;
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(priv, REG_ID1) << 3)
| (priv->read_reg(priv, REG_ID2) >> 5);
}
cf->can_dlc = get_can_dlc(fi & 0x0F);
if (fi & FI_RTR) {
id |= CAN_RTR_FLAG;
} else {
for (i = 0; i < cf->can_dlc; i++)
cf->data[i] = priv->read_reg(priv, dreg++);
}
cf->can_id = id;
/* release receive buffer */
sja1000_write_cmdreg(priv, CMD_RRB);
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
}
static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
{
struct sja1000_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
enum can_state state = priv->can.state;
uint8_t ecc, alc;
skb = alloc_can_err_skb(dev, &cf);
if (skb == NULL)
return -ENOMEM;
if (isrc & IRQ_DOI) {
/* data overrun interrupt */
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++;
stats->rx_errors++;
sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */
}
if (isrc & IRQ_EI) {
/* error warning interrupt */
netdev_dbg(dev, "error warning interrupt\n");
if (status & SR_BS) {
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
can_bus_off(dev);
} else if (status & SR_ES) {
state = CAN_STATE_ERROR_WARNING;
} else
state = CAN_STATE_ERROR_ACTIVE;
}
if (isrc & IRQ_BEI) {
/* bus error interrupt */
priv->can.can_stats.bus_error++;
stats->rx_errors++;
ecc = priv->read_reg(priv, REG_ECC);
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
switch (ecc & ECC_MASK) {
case ECC_BIT:
cf->data[2] |= CAN_ERR_PROT_BIT;
break;
case ECC_FORM:
cf->data[2] |= CAN_ERR_PROT_FORM;
break;
case ECC_STUFF:
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = ecc & ECC_SEG;
break;
}
/* Error occurred during transmission? */
if ((ecc & ECC_DIR) == 0)
cf->data[2] |= CAN_ERR_PROT_TX;
}
if (isrc & IRQ_EPI) {
/* error passive interrupt */
netdev_dbg(dev, "error passive interrupt\n");
if (status & SR_ES)
state = CAN_STATE_ERROR_PASSIVE;
else
state = CAN_STATE_ERROR_ACTIVE;
}
if (isrc & IRQ_ALI) {
/* arbitration lost interrupt */
netdev_dbg(dev, "arbitration lost interrupt\n");
alc = priv->read_reg(priv, REG_ALC);
priv->can.can_stats.arbitration_lost++;
stats->tx_errors++;
cf->can_id |= CAN_ERR_LOSTARB;
cf->data[0] = alc & 0x1f;
}
if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
state == CAN_STATE_ERROR_PASSIVE)) {
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++;
cf->data[1] = (txerr > rxerr) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
} else {
priv->can.can_stats.error_passive++;
cf->data[1] = (txerr > rxerr) ?
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
}
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
priv->can.state = state;
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
return 0;
}
irqreturn_t sja1000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct sja1000_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
uint8_t isrc, status;
int n = 0;
/* Shared interrupts and IRQ off? */
if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
return IRQ_NONE;
if (priv->pre_irq)
priv->pre_irq(priv);
while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
n++;
status = priv->read_reg(priv, REG_SR);
/* check for absent controller due to hw unplug */
if (status == 0xFF && sja1000_is_absent(priv))
return IRQ_NONE;
if (isrc & IRQ_WUI)
netdev_warn(dev, "wakeup interrupt\n");
if (isrc & IRQ_TI) {
/* transmission complete interrupt */
stats->tx_bytes += priv->read_reg(priv, REG_FI) & 0xf;
stats->tx_packets++;
can_get_echo_skb(dev, 0);
netif_wake_queue(dev);
}
if (isrc & IRQ_RI) {
/* receive interrupt */
while (status & SR_RBS) {
sja1000_rx(dev);
status = priv->read_reg(priv, REG_SR);
/* check for absent controller */
if (status == 0xFF && sja1000_is_absent(priv))
return IRQ_NONE;
}
}
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
/* error interrupt */
if (sja1000_err(dev, isrc, status))
break;
}
}
if (priv->post_irq)
priv->post_irq(priv);
if (n >= SJA1000_MAX_IRQ)
netdev_dbg(dev, "%d messages handled in ISR", n);
return (n) ? IRQ_HANDLED : IRQ_NONE;
}
EXPORT_SYMBOL_GPL(sja1000_interrupt);
static int sja1000_open(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
int err;
/* set chip into reset mode */
set_reset_mode(dev);
/* common open */
err = open_candev(dev);
if (err)
return err;
/* register interrupt handler, if not done by the device driver */
if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) {
err = request_irq(dev->irq, sja1000_interrupt, priv->irq_flags,
dev->name, (void *)dev);
if (err) {
close_candev(dev);
return -EAGAIN;
}
}
/* init and start chi */
sja1000_start(dev);
priv->open_time = jiffies;
netif_start_queue(dev);
return 0;
}
static int sja1000_close(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
set_reset_mode(dev);
if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER))
free_irq(dev->irq, (void *)dev);
close_candev(dev);
priv->open_time = 0;
return 0;
}
struct net_device *alloc_sja1000dev(int sizeof_priv)
{
struct net_device *dev;
struct sja1000_priv *priv;
dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv,
SJA1000_ECHO_SKB_MAX);
if (!dev)
return NULL;
priv = netdev_priv(dev);
priv->dev = dev;
priv->can.bittiming_const = &sja1000_bittiming_const;
priv->can.do_set_bittiming = sja1000_set_bittiming;
priv->can.do_set_mode = sja1000_set_mode;
priv->can.do_get_berr_counter = sja1000_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING;
spin_lock_init(&priv->cmdreg_lock);
if (sizeof_priv)
priv->priv = (void *)priv + sizeof(struct sja1000_priv);
return dev;
}
EXPORT_SYMBOL_GPL(alloc_sja1000dev);
void free_sja1000dev(struct net_device *dev)
{
free_candev(dev);
}
EXPORT_SYMBOL_GPL(free_sja1000dev);
static const struct net_device_ops sja1000_netdev_ops = {
.ndo_open = sja1000_open,
.ndo_stop = sja1000_close,
.ndo_start_xmit = sja1000_start_xmit,
};
int register_sja1000dev(struct net_device *dev)
{
if (!sja1000_probe_chip(dev))
return -ENODEV;
dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &sja1000_netdev_ops;
set_reset_mode(dev);
chipset_init(dev);
return register_candev(dev);
}
EXPORT_SYMBOL_GPL(register_sja1000dev);
void unregister_sja1000dev(struct net_device *dev)
{
set_reset_mode(dev);
unregister_candev(dev);
}
EXPORT_SYMBOL_GPL(unregister_sja1000dev);
static __init int sja1000_init(void)
{
printk(KERN_INFO "%s CAN netdevice driver\n", DRV_NAME);
return 0;
}
module_init(sja1000_init);
static __exit void sja1000_exit(void)
{
printk(KERN_INFO "%s: driver removed\n", DRV_NAME);
}
module_exit(sja1000_exit);

View File

@@ -0,0 +1,183 @@
/*
* sja1000.h - Philips SJA1000 network device driver
*
* Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
* 38106 Braunschweig, GERMANY
*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Volkswagen nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Alternatively, provided that this notice is retained in full, this
* software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2, in which case the provisions of the
* GPL apply INSTEAD OF those given above.
*
* The provided data structures and external interfaces from this code
* are not restricted to be used by modules with a GPL compatible license.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
#ifndef SJA1000_DEV_H
#define SJA1000_DEV_H
#include <linux/irqreturn.h>
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#define SJA1000_ECHO_SKB_MAX 1 /* the SJA1000 has one TX buffer object */
#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
#define REG_MOD 0x00
#define REG_CMR 0x01
#define REG_SR 0x02
#define REG_IR 0x03
#define REG_IER 0x04
#define REG_ALC 0x0B
#define REG_ECC 0x0C
#define REG_EWL 0x0D
#define REG_RXERR 0x0E
#define REG_TXERR 0x0F
#define REG_ACCC0 0x10
#define REG_ACCC1 0x11
#define REG_ACCC2 0x12
#define REG_ACCC3 0x13
#define REG_ACCM0 0x14
#define REG_ACCM1 0x15
#define REG_ACCM2 0x16
#define REG_ACCM3 0x17
#define REG_RMC 0x1D
#define REG_RBSA 0x1E
/* Common registers - manual section 6.5 */
#define REG_BTR0 0x06
#define REG_BTR1 0x07
#define REG_OCR 0x08
#define REG_CDR 0x1F
#define REG_FI 0x10
#define SFF_BUF 0x13
#define EFF_BUF 0x15
#define FI_FF 0x80
#define FI_RTR 0x40
#define REG_ID1 0x11
#define REG_ID2 0x12
#define REG_ID3 0x13
#define REG_ID4 0x14
#define CAN_RAM 0x20
/* mode register */
#define MOD_RM 0x01
#define MOD_LOM 0x02
#define MOD_STM 0x04
#define MOD_AFM 0x08
#define MOD_SM 0x10
/* commands */
#define CMD_SRR 0x10
#define CMD_CDO 0x08
#define CMD_RRB 0x04
#define CMD_AT 0x02
#define CMD_TR 0x01
/* interrupt sources */
#define IRQ_BEI 0x80
#define IRQ_ALI 0x40
#define IRQ_EPI 0x20
#define IRQ_WUI 0x10
#define IRQ_DOI 0x08
#define IRQ_EI 0x04
#define IRQ_TI 0x02
#define IRQ_RI 0x01
#define IRQ_ALL 0xFF
#define IRQ_OFF 0x00
/* status register content */
#define SR_BS 0x80
#define SR_ES 0x40
#define SR_TS 0x20
#define SR_RS 0x10
#define SR_TCS 0x08
#define SR_TBS 0x04
#define SR_DOS 0x02
#define SR_RBS 0x01
#define SR_CRIT (SR_BS|SR_ES)
/* ECC register */
#define ECC_SEG 0x1F
#define ECC_DIR 0x20
#define ECC_ERR 6
#define ECC_BIT 0x00
#define ECC_FORM 0x40
#define ECC_STUFF 0x80
#define ECC_MASK 0xc0
/*
* Flags for sja1000priv.flags
*/
#define SJA1000_CUSTOM_IRQ_HANDLER 0x1
/*
* SJA1000 private data structure
*/
struct sja1000_priv {
struct can_priv can; /* must be the first member */
int open_time;
struct sk_buff *echo_skb;
/* the lower-layer is responsible for appropriate locking */
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() */
spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
u16 flags; /* custom mode flags */
u8 ocr; /* output control register */
u8 cdr; /* clock divider register */
};
struct net_device *alloc_sja1000dev(int sizeof_priv);
void free_sja1000dev(struct net_device *dev);
int register_sja1000dev(struct net_device *dev);
void unregister_sja1000dev(struct net_device *dev);
irqreturn_t sja1000_interrupt(int irq, void *dev_id);
#endif /* SJA1000_DEV_H */

View File

@@ -0,0 +1,316 @@
/*
* Copyright (C) 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
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_isa"
#define MAXDEV 8
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the ISA bus");
MODULE_LICENSE("GPL v2");
#define CLK_DEFAULT 16000000 /* 16 MHz */
#define CDR_DEFAULT (CDR_CBP | CDR_CLK_OFF)
#define OCR_DEFAULT OCR_TX0_PUSHPULL
static unsigned long port[MAXDEV];
static unsigned long mem[MAXDEV];
static int __devinitdata irq[MAXDEV];
static int __devinitdata clk[MAXDEV];
static unsigned char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static unsigned char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
module_param_array(port, ulong, NULL, S_IRUGO);
MODULE_PARM_DESC(port, "I/O port number");
module_param_array(mem, ulong, NULL, S_IRUGO);
MODULE_PARM_DESC(mem, "I/O memory address");
module_param_array(indirect, int, NULL, S_IRUGO);
MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
module_param_array(irq, int, NULL, S_IRUGO);
MODULE_PARM_DESC(irq, "IRQ number");
module_param_array(clk, int, NULL, S_IRUGO);
MODULE_PARM_DESC(clk, "External oscillator clock frequency "
"(default=16000000 [16 MHz])");
module_param_array(cdr, byte, NULL, S_IRUGO);
MODULE_PARM_DESC(cdr, "Clock divider register "
"(default=0x48 [CDR_CBP | CDR_CLK_OFF])");
module_param_array(ocr, byte, NULL, S_IRUGO);
MODULE_PARM_DESC(ocr, "Output control register "
"(default=0x18 [OCR_TX0_PUSHPULL])");
#define SJA1000_IOSIZE 0x20
#define SJA1000_IOSIZE_INDIRECT 0x02
static struct platform_device *sja1000_isa_devs[MAXDEV];
static u8 sja1000_isa_mem_read_reg(const struct sja1000_priv *priv, int reg)
{
return readb(priv->reg_base + reg);
}
static void sja1000_isa_mem_write_reg(const struct sja1000_priv *priv,
int reg, u8 val)
{
writeb(val, priv->reg_base + reg);
}
static u8 sja1000_isa_port_read_reg(const struct sja1000_priv *priv, int reg)
{
return inb((unsigned long)priv->reg_base + reg);
}
static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
int reg, u8 val)
{
outb(val, (unsigned long)priv->reg_base + reg);
}
static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
int reg)
{
unsigned long base = (unsigned long)priv->reg_base;
outb(reg, base);
return inb(base + 1);
}
static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
int reg, u8 val)
{
unsigned long base = (unsigned long)priv->reg_base;
outb(reg, base);
outb(val, base + 1);
}
static int __devinit sja1000_isa_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sja1000_priv *priv;
void __iomem *base = NULL;
int iosize = SJA1000_IOSIZE;
int idx = pdev->id;
int err;
dev_dbg(&pdev->dev, "probing idx=%d: port=%#lx, mem=%#lx, irq=%d\n",
idx, port[idx], mem[idx], irq[idx]);
if (mem[idx]) {
if (!request_mem_region(mem[idx], iosize, DRV_NAME)) {
err = -EBUSY;
goto exit;
}
base = ioremap_nocache(mem[idx], iosize);
if (!base) {
err = -ENOMEM;
goto exit_release;
}
} else {
if (indirect[idx] > 0 ||
(indirect[idx] == -1 && indirect[0] > 0))
iosize = SJA1000_IOSIZE_INDIRECT;
if (!request_region(port[idx], iosize, DRV_NAME)) {
err = -EBUSY;
goto exit;
}
}
dev = alloc_sja1000dev(0);
if (!dev) {
err = -ENOMEM;
goto exit_unmap;
}
priv = netdev_priv(dev);
dev->irq = irq[idx];
priv->irq_flags = IRQF_SHARED;
if (mem[idx]) {
priv->reg_base = base;
dev->base_addr = mem[idx];
priv->read_reg = sja1000_isa_mem_read_reg;
priv->write_reg = sja1000_isa_mem_write_reg;
} else {
priv->reg_base = (void __iomem *)port[idx];
dev->base_addr = port[idx];
if (iosize == SJA1000_IOSIZE_INDIRECT) {
priv->read_reg = sja1000_isa_port_read_reg_indirect;
priv->write_reg = sja1000_isa_port_write_reg_indirect;
} else {
priv->read_reg = sja1000_isa_port_read_reg;
priv->write_reg = sja1000_isa_port_write_reg;
}
}
if (clk[idx])
priv->can.clock.freq = clk[idx] / 2;
else if (clk[0])
priv->can.clock.freq = clk[0] / 2;
else
priv->can.clock.freq = CLK_DEFAULT / 2;
if (ocr[idx] != 0xff)
priv->ocr = ocr[idx];
else if (ocr[0] != 0xff)
priv->ocr = ocr[0];
else
priv->ocr = OCR_DEFAULT;
if (cdr[idx] != 0xff)
priv->cdr = cdr[idx];
else if (cdr[0] != 0xff)
priv->cdr = cdr[0];
else
priv->cdr = CDR_DEFAULT;
dev_set_drvdata(&pdev->dev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
goto exit_unmap;
}
dev_info(&pdev->dev, "%s device registered (reg_base=0x%p, irq=%d)\n",
DRV_NAME, priv->reg_base, dev->irq);
return 0;
exit_unmap:
if (mem[idx])
iounmap(base);
exit_release:
if (mem[idx])
release_mem_region(mem[idx], iosize);
else
release_region(port[idx], iosize);
exit:
return err;
}
static int __devexit sja1000_isa_remove(struct platform_device *pdev)
{
struct net_device *dev = dev_get_drvdata(&pdev->dev);
struct sja1000_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_sja1000dev(dev);
dev_set_drvdata(&pdev->dev, NULL);
if (mem[idx]) {
iounmap(priv->reg_base);
release_mem_region(mem[idx], SJA1000_IOSIZE);
} else {
if (priv->read_reg == sja1000_isa_port_read_reg_indirect)
release_region(port[idx], SJA1000_IOSIZE_INDIRECT);
else
release_region(port[idx], SJA1000_IOSIZE);
}
free_sja1000dev(dev);
return 0;
}
static struct platform_driver sja1000_isa_driver = {
.probe = sja1000_isa_probe,
.remove = __devexit_p(sja1000_isa_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init sja1000_isa_init(void)
{
int idx, err;
for (idx = 0; idx < MAXDEV; idx++) {
if ((port[idx] || mem[idx]) && irq[idx]) {
sja1000_isa_devs[idx] =
platform_device_alloc(DRV_NAME, idx);
if (!sja1000_isa_devs[idx]) {
err = -ENOMEM;
goto exit_free_devices;
}
err = platform_device_add(sja1000_isa_devs[idx]);
if (err) {
platform_device_put(sja1000_isa_devs[idx]);
goto exit_free_devices;
}
pr_debug("%s: platform device %d: port=%#lx, mem=%#lx, "
"irq=%d\n",
DRV_NAME, idx, port[idx], mem[idx], irq[idx]);
} else if (idx == 0 || port[idx] || mem[idx]) {
pr_err("%s: insufficient parameters supplied\n",
DRV_NAME);
err = -EINVAL;
goto exit_free_devices;
}
}
err = platform_driver_register(&sja1000_isa_driver);
if (err)
goto exit_free_devices;
pr_info("Legacy %s driver for max. %d devices registered\n",
DRV_NAME, MAXDEV);
return 0;
exit_free_devices:
while (--idx >= 0) {
if (sja1000_isa_devs[idx])
platform_device_unregister(sja1000_isa_devs[idx]);
}
return err;
}
static void __exit sja1000_isa_exit(void)
{
int idx;
platform_driver_unregister(&sja1000_isa_driver);
for (idx = 0; idx < MAXDEV; idx++) {
if (sja1000_isa_devs[idx])
platform_device_unregister(sja1000_isa_devs[idx]);
}
}
module_init(sja1000_isa_init);
module_exit(sja1000_isa_exit);

View File

@@ -0,0 +1,223 @@
/*
* 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/devicetree/bindings/net/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/io.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 platform_device *ofdev)
{
struct net_device *dev = dev_get_drvdata(&ofdev->dev);
struct sja1000_priv *priv = netdev_priv(dev);
struct device_node *np = ofdev->dev.of_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 platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_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 %pR\n", &res);
return -EBUSY;
}
base = ioremap_nocache(res.start, res_size);
if (!base) {
dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
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"},
{},
};
MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
static struct platform_driver sja1000_ofp_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
.of_match_table = sja1000_ofp_table,
},
.probe = sja1000_ofp_probe,
.remove = __devexit_p(sja1000_ofp_remove),
};
module_platform_driver(sja1000_ofp_driver);

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2005 Sascha Hauer, Pengutronix
* Copyright (C) 2007 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
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#include <linux/io.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_platform"
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_reg8(const struct sja1000_priv *priv, int reg)
{
return ioread8(priv->reg_base + reg);
}
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;
void __iomem *addr;
struct net_device *dev;
struct sja1000_priv *priv;
struct resource *res_mem, *res_irq;
struct sja1000_platform_data *pdata;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "No platform data provided!\n");
err = -ENODEV;
goto exit;
}
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res_mem || !res_irq) {
err = -ENODEV;
goto exit;
}
if (!request_mem_region(res_mem->start, resource_size(res_mem),
DRV_NAME)) {
err = -EBUSY;
goto exit;
}
addr = ioremap_nocache(res_mem->start, resource_size(res_mem));
if (!addr) {
err = -ENOMEM;
goto exit_release;
}
dev = alloc_sja1000dev(0);
if (!dev) {
err = -ENOMEM;
goto exit_iounmap;
}
priv = netdev_priv(dev);
dev->irq = res_irq->start;
priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED);
priv->reg_base = addr;
/* 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);
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
goto exit_free;
}
dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
DRV_NAME, priv->reg_base, dev->irq);
return 0;
exit_free:
free_sja1000dev(dev);
exit_iounmap:
iounmap(addr);
exit_release:
release_mem_region(res_mem->start, resource_size(res_mem));
exit:
return err;
}
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 (priv->reg_base)
iounmap(priv->reg_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
free_sja1000dev(dev);
return 0;
}
static struct platform_driver sp_driver = {
.probe = sp_probe,
.remove = sp_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
module_platform_driver(sp_driver);

View File

@@ -0,0 +1,216 @@
/*
* tscan1.c: driver for Technologic Systems TS-CAN1 PC104 boards
*
* Copyright 2010 Andre B. Oliveira
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/*
* References:
* - Getting started with TS-CAN1, Technologic Systems, Jun 2009
* http://www.embeddedarm.com/documentation/ts-can1-manual.pdf
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include "sja1000.h"
MODULE_DESCRIPTION("Driver for Technologic Systems TS-CAN1 PC104 boards");
MODULE_AUTHOR("Andre B. Oliveira <anbadeol@gmail.com>");
MODULE_LICENSE("GPL");
/* Maximum number of boards (one in each JP1:JP2 setting of IO address) */
#define TSCAN1_MAXDEV 4
/* PLD registers address offsets */
#define TSCAN1_ID1 0
#define TSCAN1_ID2 1
#define TSCAN1_VERSION 2
#define TSCAN1_LED 3
#define TSCAN1_PAGE 4
#define TSCAN1_MODE 5
#define TSCAN1_JUMPERS 6
/* PLD board identifier registers magic values */
#define TSCAN1_ID1_VALUE 0xf6
#define TSCAN1_ID2_VALUE 0xb9
/* PLD mode register SJA1000 IO enable bit */
#define TSCAN1_MODE_ENABLE 0x40
/* PLD jumpers register bits */
#define TSCAN1_JP4 0x10
#define TSCAN1_JP5 0x20
/* PLD IO base addresses start */
#define TSCAN1_PLD_ADDRESS 0x150
/* PLD register space size */
#define TSCAN1_PLD_SIZE 8
/* SJA1000 register space size */
#define TSCAN1_SJA1000_SIZE 32
/* SJA1000 crystal frequency (16MHz) */
#define TSCAN1_SJA1000_XTAL 16000000
/* SJA1000 IO base addresses */
static const unsigned short tscan1_sja1000_addresses[] __devinitconst = {
0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320
};
/* Read SJA1000 register */
static u8 tscan1_read(const struct sja1000_priv *priv, int reg)
{
return inb((unsigned long)priv->reg_base + reg);
}
/* Write SJA1000 register */
static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
{
outb(val, (unsigned long)priv->reg_base + reg);
}
/* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */
static int __devinit tscan1_probe(struct device *dev, unsigned id)
{
struct net_device *netdev;
struct sja1000_priv *priv;
unsigned long pld_base, sja1000_base;
int irq, i;
pld_base = TSCAN1_PLD_ADDRESS + id * TSCAN1_PLD_SIZE;
if (!request_region(pld_base, TSCAN1_PLD_SIZE, dev_name(dev)))
return -EBUSY;
if (inb(pld_base + TSCAN1_ID1) != TSCAN1_ID1_VALUE ||
inb(pld_base + TSCAN1_ID2) != TSCAN1_ID2_VALUE) {
release_region(pld_base, TSCAN1_PLD_SIZE);
return -ENODEV;
}
switch (inb(pld_base + TSCAN1_JUMPERS) & (TSCAN1_JP4 | TSCAN1_JP5)) {
case TSCAN1_JP4:
irq = 6;
break;
case TSCAN1_JP5:
irq = 7;
break;
case TSCAN1_JP4 | TSCAN1_JP5:
irq = 5;
break;
default:
dev_err(dev, "invalid JP4:JP5 setting (no IRQ)\n");
release_region(pld_base, TSCAN1_PLD_SIZE);
return -EINVAL;
}
netdev = alloc_sja1000dev(0);
if (!netdev) {
release_region(pld_base, TSCAN1_PLD_SIZE);
return -ENOMEM;
}
dev_set_drvdata(dev, netdev);
SET_NETDEV_DEV(netdev, dev);
netdev->base_addr = pld_base;
netdev->irq = irq;
priv = netdev_priv(netdev);
priv->read_reg = tscan1_read;
priv->write_reg = tscan1_write;
priv->can.clock.freq = TSCAN1_SJA1000_XTAL / 2;
priv->cdr = CDR_CBP | CDR_CLK_OFF;
priv->ocr = OCR_TX0_PUSHPULL;
/* Select the first SJA1000 IO address that is free and that works */
for (i = 0; i < ARRAY_SIZE(tscan1_sja1000_addresses); i++) {
sja1000_base = tscan1_sja1000_addresses[i];
if (!request_region(sja1000_base, TSCAN1_SJA1000_SIZE,
dev_name(dev)))
continue;
/* Set SJA1000 IO base address and enable it */
outb(TSCAN1_MODE_ENABLE | i, pld_base + TSCAN1_MODE);
priv->reg_base = (void __iomem *)sja1000_base;
if (!register_sja1000dev(netdev)) {
/* SJA1000 probe succeeded; turn LED off and return */
outb(0, pld_base + TSCAN1_LED);
netdev_info(netdev, "TS-CAN1 at 0x%lx 0x%lx irq %d\n",
pld_base, sja1000_base, irq);
return 0;
}
/* SJA1000 probe failed; release and try next address */
outb(0, pld_base + TSCAN1_MODE);
release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
}
dev_err(dev, "failed to assign SJA1000 IO address\n");
dev_set_drvdata(dev, NULL);
free_sja1000dev(netdev);
release_region(pld_base, TSCAN1_PLD_SIZE);
return -ENXIO;
}
static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/)
{
struct net_device *netdev;
struct sja1000_priv *priv;
unsigned long pld_base, sja1000_base;
netdev = dev_get_drvdata(dev);
unregister_sja1000dev(netdev);
dev_set_drvdata(dev, NULL);
priv = netdev_priv(netdev);
pld_base = netdev->base_addr;
sja1000_base = (unsigned long)priv->reg_base;
outb(0, pld_base + TSCAN1_MODE); /* disable SJA1000 IO space */
release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
release_region(pld_base, TSCAN1_PLD_SIZE);
free_sja1000dev(netdev);
return 0;
}
static struct isa_driver tscan1_isa_driver = {
.probe = tscan1_probe,
.remove = __devexit_p(tscan1_remove),
.driver = {
.name = "tscan1",
},
};
static int __init tscan1_init(void)
{
return isa_register_driver(&tscan1_isa_driver, TSCAN1_MAXDEV);
}
module_init(tscan1_init);
static void __exit tscan1_exit(void)
{
isa_unregister_driver(&tscan1_isa_driver);
}
module_exit(tscan1_exit);