add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
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"
depends on ISA
---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_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_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).
endif

View File

@@ -0,0 +1,12 @@
#
# 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_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.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/pci.h>
#include <linux/can.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 struct pci_device_id 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,412 @@
/*
* 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.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 struct pci_device_id 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,648 @@
/*
* 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.
*
* Send feedback to <socketcan-users@lists.berlios.de>
*
*/
#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.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_probe_chip(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) {
printk(KERN_INFO "%s: probing @0x%lX failed\n",
DRV_NAME, dev->base_addr);
return 0;
}
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);
}
dev_err(dev->dev.parent, "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 all interrupts */
priv->write_reg(priv, REG_IER, IRQ_ALL);
return;
}
/* set chip to normal mode */
priv->write_reg(priv, REG_MOD, 0x00);
udelay(10);
status = priv->read_reg(priv, REG_MOD);
}
dev_err(dev->dev.parent, "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;
dev_info(dev->dev.parent,
"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;
}
/*
* 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;
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]);
dev->trans_start = jiffies;
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;
uint8_t dlc;
int i;
skb = dev_alloc_skb(sizeof(struct can_frame));
if (skb == NULL)
return;
skb->dev = dev;
skb->protocol = htons(ETH_P_CAN);
fi = priv->read_reg(priv, REG_FI);
dlc = fi & 0x0F;
if (fi & FI_FF) {
/* extended frame format (EFF) */
dreg = EFF_BUF;
id = (priv->read_reg(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);
}
if (fi & FI_RTR)
id |= CAN_RTR_FLAG;
cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(cf, 0, sizeof(struct can_frame));
cf->can_id = id;
cf->can_dlc = dlc;
for (i = 0; i < dlc; i++)
cf->data[i] = priv->read_reg(priv, dreg++);
while (i < 8)
cf->data[i++] = 0;
/* release receive buffer */
sja1000_write_cmdreg(priv, CMD_RRB);
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += 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 = dev_alloc_skb(sizeof(struct can_frame));
if (skb == NULL)
return -ENOMEM;
skb->dev = dev;
skb->protocol = htons(ETH_P_CAN);
cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(cf, 0, sizeof(struct can_frame));
cf->can_id = CAN_ERR_FLAG;
cf->can_dlc = CAN_ERR_DLC;
if (isrc & IRQ_DOI) {
/* data overrun interrupt */
dev_dbg(dev->dev.parent, "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 */
dev_dbg(dev->dev.parent, "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 occured during transmission? */
if ((ecc & ECC_DIR) == 0)
cf->data[2] |= CAN_ERR_PROT_TX;
}
if (isrc & IRQ_EPI) {
/* error passive interrupt */
dev_dbg(dev->dev.parent, "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 */
dev_dbg(dev->dev.parent, "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;
}
}
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);
if (isrc & IRQ_WUI)
dev_warn(dev->dev.parent, "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);
}
}
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)
dev_dbg(dev->dev.parent, "%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);
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;
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,182 @@
/*
* 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.
*
* Send feedback to <socketcan-users@lists.berlios.de>
*
*/
#ifndef SJA1000_DEV_H
#define SJA1000_DEV_H
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#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,281 @@
/*
* 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/isa.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#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 char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
static char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
static char __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, byte, 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 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_match(struct device *pdev, unsigned int idx)
{
if (port[idx] || mem[idx]) {
if (irq[idx])
return 1;
} else if (idx)
return 0;
dev_err(pdev, "insufficient parameters supplied\n");
return 0;
}
static int __devinit sja1000_isa_probe(struct device *pdev, unsigned int idx)
{
struct net_device *dev;
struct sja1000_priv *priv;
void __iomem *base = NULL;
int iosize = SJA1000_IOSIZE;
int err;
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] != -1)
priv->ocr = ocr[idx] & 0xff;
else if (ocr[0] != -1)
priv->ocr = ocr[0] & 0xff;
else
priv->ocr = OCR_DEFAULT;
if (cdr[idx] != -1)
priv->cdr = cdr[idx] & 0xff;
else if (cdr[0] != -1)
priv->cdr = cdr[0] & 0xff;
else
priv->cdr = CDR_DEFAULT;
dev_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, pdev);
err = register_sja1000dev(dev);
if (err) {
dev_err(pdev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
goto exit_unmap;
}
dev_info(pdev, "%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 device *pdev, unsigned int idx)
{
struct net_device *dev = dev_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
unregister_sja1000dev(dev);
dev_set_drvdata(pdev, 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 isa_driver sja1000_isa_driver = {
.match = sja1000_isa_match,
.probe = sja1000_isa_probe,
.remove = __devexit_p(sja1000_isa_remove),
.driver = {
.name = DRV_NAME,
},
};
static int __init sja1000_isa_init(void)
{
int err = isa_register_driver(&sja1000_isa_driver, MAXDEV);
if (!err)
printk(KERN_INFO
"Legacy %s driver for max. %d devices registered\n",
DRV_NAME, MAXDEV);
return err;
}
static void __exit sja1000_isa_exit(void)
{
isa_unregister_driver(&sja1000_isa_driver);
}
module_init(sja1000_isa_init);
module_exit(sja1000_isa_exit);

View File

@@ -0,0 +1,236 @@
/*
* Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
*
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the version 2 of the GNU General Public License
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
* bus found on embedded PowerPC systems. You need a SJA1000 CAN node
* definition in your flattened device tree source (DTS) file similar to:
*
* can@3,100 {
* compatible = "nxp,sja1000";
* reg = <3 0x100 0x80>;
* interrupts = <2 0>;
* interrupt-parent = <&mpic>;
* nxp,external-clock-frequency = <16000000>;
* };
*
* See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further
* information.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/of_platform.h>
#include <asm/prom.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_of_platform"
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
MODULE_LICENSE("GPL v2");
#define SJA1000_OFP_CAN_CLOCK (16000000 / 2)
#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN
#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF)
static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
{
return in_8(priv->reg_base + reg);
}
static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
int reg, u8 val)
{
out_8(priv->reg_base + reg, val);
}
static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
{
struct net_device *dev = dev_get_drvdata(&ofdev->dev);
struct sja1000_priv *priv = netdev_priv(dev);
struct device_node *np = ofdev->node;
struct resource res;
dev_set_drvdata(&ofdev->dev, NULL);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
iounmap(priv->reg_base);
irq_dispose_mapping(dev->irq);
of_address_to_resource(np, 0, &res);
release_mem_region(res.start, resource_size(&res));
return 0;
}
static int __devinit sja1000_ofp_probe(struct of_device *ofdev,
const struct of_device_id *id)
{
struct device_node *np = ofdev->node;
struct net_device *dev;
struct sja1000_priv *priv;
struct resource res;
const u32 *prop;
int err, irq, res_size, prop_size;
void __iomem *base;
err = of_address_to_resource(np, 0, &res);
if (err) {
dev_err(&ofdev->dev, "invalid address\n");
return err;
}
res_size = resource_size(&res);
if (!request_mem_region(res.start, res_size, DRV_NAME)) {
dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n",
(unsigned long long)res.start,
(unsigned long long)res.end);
return -EBUSY;
}
base = ioremap_nocache(res.start, res_size);
if (!base) {
dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n",
(unsigned long long)res.start,
(unsigned long long)res.end);
err = -ENOMEM;
goto exit_release_mem;
}
irq = irq_of_parse_and_map(np, 0);
if (irq == NO_IRQ) {
dev_err(&ofdev->dev, "no irq found\n");
err = -ENODEV;
goto exit_unmap_mem;
}
dev = alloc_sja1000dev(0);
if (!dev) {
err = -ENOMEM;
goto exit_dispose_irq;
}
priv = netdev_priv(dev);
priv->read_reg = sja1000_ofp_read_reg;
priv->write_reg = sja1000_ofp_write_reg;
prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
if (prop && (prop_size == sizeof(u32)))
priv->can.clock.freq = *prop / 2;
else
priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
if (prop && (prop_size == sizeof(u32)))
priv->ocr |= *prop & OCR_MODE_MASK;
else
priv->ocr |= OCR_MODE_NORMAL; /* default */
prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
if (prop && (prop_size == sizeof(u32)))
priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
else
priv->ocr |= OCR_TX0_PULLDOWN; /* default */
prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
if (prop && (prop_size == sizeof(u32)) && *prop) {
u32 divider = priv->can.clock.freq * 2 / *prop;
if (divider > 1)
priv->cdr |= divider / 2 - 1;
else
priv->cdr |= CDR_CLKOUT_MASK;
} else {
priv->cdr |= CDR_CLK_OFF; /* default */
}
prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
if (!prop)
priv->cdr |= CDR_CBP; /* default */
priv->irq_flags = IRQF_SHARED;
priv->reg_base = base;
dev->irq = irq;
dev_info(&ofdev->dev,
"reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
priv->reg_base, dev->irq, priv->can.clock.freq,
priv->ocr, priv->cdr);
dev_set_drvdata(&ofdev->dev, dev);
SET_NETDEV_DEV(dev, &ofdev->dev);
err = register_sja1000dev(dev);
if (err) {
dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
goto exit_free_sja1000;
}
return 0;
exit_free_sja1000:
free_sja1000dev(dev);
exit_dispose_irq:
irq_dispose_mapping(irq);
exit_unmap_mem:
iounmap(base);
exit_release_mem:
release_mem_region(res.start, res_size);
return err;
}
static struct of_device_id __devinitdata sja1000_ofp_table[] = {
{.compatible = "nxp,sja1000"},
{},
};
MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
static struct of_platform_driver sja1000_ofp_driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
.probe = sja1000_ofp_probe,
.remove = __devexit_p(sja1000_ofp_remove),
.match_table = sja1000_ofp_table,
};
static int __init sja1000_ofp_init(void)
{
return of_register_platform_driver(&sja1000_ofp_driver);
}
module_init(sja1000_ofp_init);
static void __exit sja1000_ofp_exit(void)
{
return of_unregister_platform_driver(&sja1000_ofp_driver);
};
module_exit(sja1000_ofp_exit);

View File

@@ -0,0 +1,165 @@
/*
* 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.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_reg(const struct sja1000_priv *priv, int reg)
{
return ioread8(priv->reg_base + reg);
}
static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val)
{
iowrite8(val, priv->reg_base + reg);
}
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;
priv->reg_base = addr;
priv->read_reg = sp_read_reg;
priv->write_reg = sp_write_reg;
priv->can.clock.freq = pdata->clock;
priv->ocr = pdata->ocr;
priv->cdr = pdata->cdr;
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,
},
};
static int __init sp_init(void)
{
return platform_driver_register(&sp_driver);
}
static void __exit sp_exit(void)
{
platform_driver_unregister(&sp_driver);
}
module_init(sp_init);
module_exit(sp_exit);