Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

166
drivers/net/can/Kconfig Normal file
View file

@ -0,0 +1,166 @@
menu "CAN Device Drivers"
config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)"
---help---
Similar to the network loopback devices, vcan offers a
virtual local CAN interface.
This driver can also be built as a module. If so, the module
will be called vcan.
config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on TTY
---help---
CAN driver for several 'low cost' CAN interfaces that are attached
via serial lines or via USB-to-serial adapters using the LAWICEL
ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
As only the sending and receiving of CAN frames is implemented, this
driver should work with the (serial/USB) CAN hardware from:
www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
Userspace tools to attach the SLCAN line discipline (slcan_attach,
slcand) can be found in the can-utils at the SocketCAN SVN, see
http://developer.berlios.de/projects/socketcan for details.
The slcan driver supports up to 10 CAN netdevices by default which
can be changed by the 'maxdev=xx' module option. This driver can
also be built as a module. If so, the module will be called slcan.
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
default y
---help---
Enables the common framework for platform CAN drivers with Netlink
support. This is the standard library for CAN drivers.
If unsure, say Y.
if CAN_DEV
config CAN_CALC_BITTIMING
bool "CAN bit-timing calculation"
default y
---help---
If enabled, CAN bit-timing parameters will be calculated for the
bit-rate specified via Netlink argument "bitrate" when the device
get started. This works fine for the most common CAN controllers
with standard bit-rates but may fail for exotic bit-rates or CAN
source clock frequencies. Disabling saves some space, but then the
bit-timing parameters must be specified directly using the Netlink
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
If unsure, say Y.
config CAN_LEDS
bool "Enable LED triggers for Netlink based drivers"
depends on LEDS_CLASS
select LEDS_TRIGGERS
---help---
This option adds two LED triggers for packet receive and transmit
events on each supported CAN device.
Say Y here if you are working on a system with led-class supported
LEDs and you want to use them as canbus activity indicators.
config CAN_AT91
tristate "Atmel AT91 onchip CAN controller"
depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors.
config CAN_TI_HECC
depends on ARM
tristate "TI High End CAN Controller"
---help---
Driver for TI HECC (High End CAN Controller) module found on many
TI devices. The device specifications are available from www.ti.com
config CAN_BFIN
depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
tristate "Analog Devices Blackfin on-chip CAN"
---help---
Driver for the Analog Devices Blackfin on-chip CAN controllers
To compile this driver as a module, choose M here: the
module will be called bfin_can.
config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
depends on MFD_JANZ_CMODIO
---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board.
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
depends on ARM || PPC
---help---
Say Y here if you want to support for Freescale FlexCAN.
config PCH_CAN
tristate "Intel EG20T PCH CAN controller"
depends on PCI && (X86_32 || COMPILE_TEST)
---help---
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
is an IOH for x86 embedded processor (Intel Atom E6xx series).
This driver can access CAN bus.
config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on OF
---help---
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little
endian syntheses of the cores would need some modifications on
the hardware level to work.
config CAN_RCAR
tristate "Renesas R-Car CAN controller"
depends on ARM
---help---
Say Y here if you want to use CAN controller found on Renesas R-Car
SoCs.
To compile this driver as a module, choose M here: the module will
be called rcar_can.
config CAN_XILINXCAN
tristate "Xilinx CAN"
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
depends on COMMON_CLK && HAS_IOMEM
---help---
Xilinx CAN driver. This driver supports both soft AXI CAN IP and
Zynq CANPS IP.
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/cc770/Kconfig"
source "drivers/net/can/spi/Kconfig"
source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"
endif
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
---help---
Say Y here if you want the CAN device drivers to produce a bunch of
debug messages to the system log. Select this if you are having
a problem with CAN support and want to see more of what is going
on.
endmenu

32
drivers/net/can/Makefile Normal file
View file

@ -0,0 +1,32 @@
#
# Makefile for the Linux Controller Area Network drivers.
#
obj-$(CONFIG_CAN_VCAN) += vcan.o
obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += spi/
obj-y += usb/
obj-y += softing/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_M_CAN) += m_can/
obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_PCH_CAN) += pch_can.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
obj-$(CONFIG_CAN_RCAR) += rcar_can.o
obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o
subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG

1441
drivers/net/can/at91_can.c Normal file

File diff suppressed because it is too large Load diff

692
drivers/net/can/bfin_can.c Normal file
View file

@ -0,0 +1,692 @@
/*
* Blackfin On-Chip CAN Driver
*
* Copyright 2004-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <asm/bfin_can.h>
#include <asm/portmux.h>
#define DRV_NAME "bfin_can"
#define BFIN_CAN_TIMEOUT 100
#define TX_ECHO_SKB_MAX 1
/*
* bfin can private data
*/
struct bfin_can_priv {
struct can_priv can; /* must be the first member */
struct net_device *dev;
void __iomem *membase;
int rx_irq;
int tx_irq;
int err_irq;
unsigned short *pin_list;
};
/*
* bfin can timing parameters
*/
static const struct can_bittiming_const bfin_can_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
/*
* Although the BRP field can be set to any value, it is recommended
* that the value be greater than or equal to 4, as restrictions
* apply to the bit timing configuration when BRP is less than 4.
*/
.brp_min = 4,
.brp_max = 1024,
.brp_inc = 1,
};
static int bfin_can_set_bittiming(struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
struct can_bittiming *bt = &priv->can.bittiming;
u16 clk, timing;
clk = bt->brp - 1;
timing = ((bt->sjw - 1) << 8) | (bt->prop_seg + bt->phase_seg1 - 1) |
((bt->phase_seg2 - 1) << 4);
/*
* If the SAM bit is set, the input signal is oversampled three times
* at the SCLK rate.
*/
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
timing |= SAM;
bfin_write(&reg->clock, clk);
bfin_write(&reg->timing, timing);
netdev_info(dev, "setting CLOCK=0x%04x TIMING=0x%04x\n", clk, timing);
return 0;
}
static void bfin_can_set_reset_mode(struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
int timeout = BFIN_CAN_TIMEOUT;
int i;
/* disable interrupts */
bfin_write(&reg->mbim1, 0);
bfin_write(&reg->mbim2, 0);
bfin_write(&reg->gim, 0);
/* reset can and enter configuration mode */
bfin_write(&reg->control, SRS | CCR);
SSYNC();
bfin_write(&reg->control, CCR);
SSYNC();
while (!(bfin_read(&reg->control) & CCA)) {
udelay(10);
if (--timeout == 0) {
netdev_err(dev, "fail to enter configuration mode\n");
BUG();
}
}
/*
* All mailbox configurations are marked as inactive
* by writing to CAN Mailbox Configuration Registers 1 and 2
* For all bits: 0 - Mailbox disabled, 1 - Mailbox enabled
*/
bfin_write(&reg->mc1, 0);
bfin_write(&reg->mc2, 0);
/* Set Mailbox Direction */
bfin_write(&reg->md1, 0xFFFF); /* mailbox 1-16 are RX */
bfin_write(&reg->md2, 0); /* mailbox 17-32 are TX */
/* RECEIVE_STD_CHL */
for (i = 0; i < 2; i++) {
bfin_write(&reg->chl[RECEIVE_STD_CHL + i].id0, 0);
bfin_write(&reg->chl[RECEIVE_STD_CHL + i].id1, AME);
bfin_write(&reg->chl[RECEIVE_STD_CHL + i].dlc, 0);
bfin_write(&reg->msk[RECEIVE_STD_CHL + i].amh, 0x1FFF);
bfin_write(&reg->msk[RECEIVE_STD_CHL + i].aml, 0xFFFF);
}
/* RECEIVE_EXT_CHL */
for (i = 0; i < 2; i++) {
bfin_write(&reg->chl[RECEIVE_EXT_CHL + i].id0, 0);
bfin_write(&reg->chl[RECEIVE_EXT_CHL + i].id1, AME | IDE);
bfin_write(&reg->chl[RECEIVE_EXT_CHL + i].dlc, 0);
bfin_write(&reg->msk[RECEIVE_EXT_CHL + i].amh, 0x1FFF);
bfin_write(&reg->msk[RECEIVE_EXT_CHL + i].aml, 0xFFFF);
}
bfin_write(&reg->mc2, BIT(TRANSMIT_CHL - 16));
bfin_write(&reg->mc1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL));
SSYNC();
priv->can.state = CAN_STATE_STOPPED;
}
static void bfin_can_set_normal_mode(struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
int timeout = BFIN_CAN_TIMEOUT;
/*
* leave configuration mode
*/
bfin_write(&reg->control, bfin_read(&reg->control) & ~CCR);
while (bfin_read(&reg->status) & CCA) {
udelay(10);
if (--timeout == 0) {
netdev_err(dev, "fail to leave configuration mode\n");
BUG();
}
}
/*
* clear _All_ tx and rx interrupts
*/
bfin_write(&reg->mbtif1, 0xFFFF);
bfin_write(&reg->mbtif2, 0xFFFF);
bfin_write(&reg->mbrif1, 0xFFFF);
bfin_write(&reg->mbrif2, 0xFFFF);
/*
* clear global interrupt status register
*/
bfin_write(&reg->gis, 0x7FF); /* overwrites with '1' */
/*
* Initialize Interrupts
* - set bits in the mailbox interrupt mask register
* - global interrupt mask
*/
bfin_write(&reg->mbim1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL));
bfin_write(&reg->mbim2, BIT(TRANSMIT_CHL - 16));
bfin_write(&reg->gim, EPIM | BOIM | RMLIM);
SSYNC();
}
static void bfin_can_start(struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
/* enter reset mode */
if (priv->can.state != CAN_STATE_STOPPED)
bfin_can_set_reset_mode(dev);
/* leave reset mode */
bfin_can_set_normal_mode(dev);
}
static int bfin_can_set_mode(struct net_device *dev, enum can_mode mode)
{
switch (mode) {
case CAN_MODE_START:
bfin_can_start(dev);
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int bfin_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
u16 cec = bfin_read(&reg->cec);
bec->txerr = cec >> 8;
bec->rxerr = cec;
return 0;
}
static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc = cf->can_dlc;
canid_t id = cf->can_id;
u8 *data = cf->data;
u16 val;
int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
netif_stop_queue(dev);
/* fill id */
if (id & CAN_EFF_FLAG) {
bfin_write(&reg->chl[TRANSMIT_CHL].id0, id);
val = ((id & 0x1FFF0000) >> 16) | IDE;
} else
val = (id << 2);
if (id & CAN_RTR_FLAG)
val |= RTR;
bfin_write(&reg->chl[TRANSMIT_CHL].id1, val | AME);
/* fill payload */
for (i = 0; i < 8; i += 2) {
val = ((7 - i) < dlc ? (data[7 - i]) : 0) +
((6 - i) < dlc ? (data[6 - i] << 8) : 0);
bfin_write(&reg->chl[TRANSMIT_CHL].data[i], val);
}
/* fill data length code */
bfin_write(&reg->chl[TRANSMIT_CHL].dlc, dlc);
can_put_echo_skb(skb, dev, 0);
/* set transmit request */
bfin_write(&reg->trs2, BIT(TRANSMIT_CHL - 16));
return 0;
}
static void bfin_can_rx(struct net_device *dev, u16 isrc)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct bfin_can_regs __iomem *reg = priv->membase;
struct can_frame *cf;
struct sk_buff *skb;
int obj;
int i;
u16 val;
skb = alloc_can_skb(dev, &cf);
if (skb == NULL)
return;
/* get id */
if (isrc & BIT(RECEIVE_EXT_CHL)) {
/* extended frame format (EFF) */
cf->can_id = ((bfin_read(&reg->chl[RECEIVE_EXT_CHL].id1)
& 0x1FFF) << 16)
+ bfin_read(&reg->chl[RECEIVE_EXT_CHL].id0);
cf->can_id |= CAN_EFF_FLAG;
obj = RECEIVE_EXT_CHL;
} else {
/* standard frame format (SFF) */
cf->can_id = (bfin_read(&reg->chl[RECEIVE_STD_CHL].id1)
& 0x1ffc) >> 2;
obj = RECEIVE_STD_CHL;
}
if (bfin_read(&reg->chl[obj].id1) & RTR)
cf->can_id |= CAN_RTR_FLAG;
/* get data length code */
cf->can_dlc = get_can_dlc(bfin_read(&reg->chl[obj].dlc) & 0xF);
/* get payload */
for (i = 0; i < 8; i += 2) {
val = bfin_read(&reg->chl[obj].data[i]);
cf->data[7 - i] = (7 - i) < cf->can_dlc ? val : 0;
cf->data[6 - i] = (6 - i) < cf->can_dlc ? (val >> 8) : 0;
}
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
}
static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
{
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
enum can_state state = priv->can.state;
skb = alloc_can_err_skb(dev, &cf);
if (skb == NULL)
return -ENOMEM;
if (isrc & RMLIS) {
/* 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++;
}
if (isrc & BOIS) {
netdev_dbg(dev, "bus-off mode interrupt\n");
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
can_bus_off(dev);
}
if (isrc & EPIS) {
/* error passive interrupt */
netdev_dbg(dev, "error passive interrupt\n");
state = CAN_STATE_ERROR_PASSIVE;
}
if ((isrc & EWTIS) || (isrc & EWRIS)) {
netdev_dbg(dev, "Error Warning Transmit/Receive Interrupt\n");
state = CAN_STATE_ERROR_WARNING;
}
if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
state == CAN_STATE_ERROR_PASSIVE)) {
u16 cec = bfin_read(&reg->cec);
u8 rxerr = cec;
u8 txerr = cec >> 8;
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;
}
}
if (status) {
priv->can.can_stats.bus_error++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
if (status & BEF)
cf->data[2] |= CAN_ERR_PROT_BIT;
else if (status & FER)
cf->data[2] |= CAN_ERR_PROT_FORM;
else if (status & SER)
cf->data[2] |= CAN_ERR_PROT_STUFF;
else
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
}
priv->can.state = state;
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
return 0;
}
static irqreturn_t bfin_can_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
struct net_device_stats *stats = &dev->stats;
u16 status, isrc;
if ((irq == priv->tx_irq) && bfin_read(&reg->mbtif2)) {
/* transmission complete interrupt */
bfin_write(&reg->mbtif2, 0xFFFF);
stats->tx_packets++;
stats->tx_bytes += bfin_read(&reg->chl[TRANSMIT_CHL].dlc);
can_get_echo_skb(dev, 0);
netif_wake_queue(dev);
} else if ((irq == priv->rx_irq) && bfin_read(&reg->mbrif1)) {
/* receive interrupt */
isrc = bfin_read(&reg->mbrif1);
bfin_write(&reg->mbrif1, 0xFFFF);
bfin_can_rx(dev, isrc);
} else if ((irq == priv->err_irq) && bfin_read(&reg->gis)) {
/* error interrupt */
isrc = bfin_read(&reg->gis);
status = bfin_read(&reg->esr);
bfin_write(&reg->gis, 0x7FF);
bfin_can_err(dev, isrc, status);
} else {
return IRQ_NONE;
}
return IRQ_HANDLED;
}
static int bfin_can_open(struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
int err;
/* set chip into reset mode */
bfin_can_set_reset_mode(dev);
/* common open */
err = open_candev(dev);
if (err)
goto exit_open;
/* register interrupt handler */
err = request_irq(priv->rx_irq, &bfin_can_interrupt, 0,
"bfin-can-rx", dev);
if (err)
goto exit_rx_irq;
err = request_irq(priv->tx_irq, &bfin_can_interrupt, 0,
"bfin-can-tx", dev);
if (err)
goto exit_tx_irq;
err = request_irq(priv->err_irq, &bfin_can_interrupt, 0,
"bfin-can-err", dev);
if (err)
goto exit_err_irq;
bfin_can_start(dev);
netif_start_queue(dev);
return 0;
exit_err_irq:
free_irq(priv->tx_irq, dev);
exit_tx_irq:
free_irq(priv->rx_irq, dev);
exit_rx_irq:
close_candev(dev);
exit_open:
return err;
}
static int bfin_can_close(struct net_device *dev)
{
struct bfin_can_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
bfin_can_set_reset_mode(dev);
close_candev(dev);
free_irq(priv->rx_irq, dev);
free_irq(priv->tx_irq, dev);
free_irq(priv->err_irq, dev);
return 0;
}
static struct net_device *alloc_bfin_candev(void)
{
struct net_device *dev;
struct bfin_can_priv *priv;
dev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
if (!dev)
return NULL;
priv = netdev_priv(dev);
priv->dev = dev;
priv->can.bittiming_const = &bfin_can_bittiming_const;
priv->can.do_set_bittiming = bfin_can_set_bittiming;
priv->can.do_set_mode = bfin_can_set_mode;
priv->can.do_get_berr_counter = bfin_can_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
return dev;
}
static const struct net_device_ops bfin_can_netdev_ops = {
.ndo_open = bfin_can_open,
.ndo_stop = bfin_can_close,
.ndo_start_xmit = bfin_can_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static int bfin_can_probe(struct platform_device *pdev)
{
int err;
struct net_device *dev;
struct bfin_can_priv *priv;
struct resource *res_mem, *rx_irq, *tx_irq, *err_irq;
unsigned short *pdata;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform data provided!\n");
err = -EINVAL;
goto exit;
}
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rx_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
tx_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
err_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
if (!res_mem || !rx_irq || !tx_irq || !err_irq) {
err = -EINVAL;
goto exit;
}
if (!request_mem_region(res_mem->start, resource_size(res_mem),
dev_name(&pdev->dev))) {
err = -EBUSY;
goto exit;
}
/* request peripheral pins */
err = peripheral_request_list(pdata, dev_name(&pdev->dev));
if (err)
goto exit_mem_release;
dev = alloc_bfin_candev();
if (!dev) {
err = -ENOMEM;
goto exit_peri_pin_free;
}
priv = netdev_priv(dev);
priv->membase = (void __iomem *)res_mem->start;
priv->rx_irq = rx_irq->start;
priv->tx_irq = tx_irq->start;
priv->err_irq = err_irq->start;
priv->pin_list = pdata;
priv->can.clock.freq = get_sclk();
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &bfin_can_netdev_ops;
bfin_can_set_reset_mode(dev);
err = register_candev(dev);
if (err) {
dev_err(&pdev->dev, "registering failed (err=%d)\n", err);
goto exit_candev_free;
}
dev_info(&pdev->dev,
"%s device registered"
"(&reg_base=%p, rx_irq=%d, tx_irq=%d, err_irq=%d, sclk=%d)\n",
DRV_NAME, priv->membase, priv->rx_irq,
priv->tx_irq, priv->err_irq, priv->can.clock.freq);
return 0;
exit_candev_free:
free_candev(dev);
exit_peri_pin_free:
peripheral_free_list(pdata);
exit_mem_release:
release_mem_region(res_mem->start, resource_size(res_mem));
exit:
return err;
}
static int bfin_can_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct resource *res;
bfin_can_set_reset_mode(dev);
unregister_candev(dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
peripheral_free_list(priv->pin_list);
free_candev(dev);
return 0;
}
#ifdef CONFIG_PM
static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
int timeout = BFIN_CAN_TIMEOUT;
if (netif_running(dev)) {
/* enter sleep mode */
bfin_write(&reg->control, bfin_read(&reg->control) | SMR);
SSYNC();
while (!(bfin_read(&reg->intr) & SMACK)) {
udelay(10);
if (--timeout == 0) {
netdev_err(dev, "fail to enter sleep mode\n");
BUG();
}
}
}
return 0;
}
static int bfin_can_resume(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
if (netif_running(dev)) {
/* leave sleep mode */
bfin_write(&reg->intr, 0);
SSYNC();
}
return 0;
}
#else
#define bfin_can_suspend NULL
#define bfin_can_resume NULL
#endif /* CONFIG_PM */
static struct platform_driver bfin_can_driver = {
.probe = bfin_can_probe,
.remove = bfin_can_remove,
.suspend = bfin_can_suspend,
.resume = bfin_can_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
module_platform_driver(bfin_can_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Blackfin on-chip CAN netdevice driver");
MODULE_ALIAS("platform:" DRV_NAME);

View file

@ -0,0 +1,23 @@
menuconfig CAN_C_CAN
tristate "Bosch C_CAN/D_CAN devices"
depends on HAS_IOMEM
if CAN_C_CAN
config CAN_C_CAN_PLATFORM
tristate "Generic Platform Bus based C_CAN/D_CAN driver"
---help---
This driver adds support for the C_CAN/D_CAN chips connected
to the "platform bus" (Linux abstraction for directly to the
processor attached devices) which can be found on various
boards from ST Microelectronics (http://www.st.com) like the
SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
boards like am335x, dm814x, dm813x and dm811x.
config CAN_C_CAN_PCI
tristate "Generic PCI Bus based C_CAN/D_CAN driver"
depends on PCI
---help---
This driver adds support for the C_CAN/D_CAN chips connected
to the PCI bus.
endif

View file

@ -0,0 +1,7 @@
#
# Makefile for the Bosch C_CAN controller drivers.
#
obj-$(CONFIG_CAN_C_CAN) += c_can.o
obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,207 @@
/*
* CAN bus driver for Bosch C_CAN controller
*
* Copyright (C) 2010 ST Microelectronics
* Bhupesh Sharma <bhupesh.sharma@st.com>
*
* Borrowed heavily from the C_CAN driver originally written by:
* Copyright (C) 2007
* - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
* - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
*
* Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
* Bosch C_CAN user manual can be obtained from:
* http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
* users_manual_c_can.pdf
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef C_CAN_H
#define C_CAN_H
/* message object split */
#define C_CAN_NO_OF_OBJECTS 32
#define C_CAN_MSG_OBJ_RX_NUM 16
#define C_CAN_MSG_OBJ_TX_NUM 16
#define C_CAN_MSG_OBJ_RX_FIRST 1
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
C_CAN_MSG_OBJ_RX_NUM - 1)
#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
C_CAN_MSG_OBJ_TX_NUM - 1)
#define C_CAN_MSG_OBJ_RX_SPLIT 9
#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
#define RECEIVE_OBJECT_BITS 0x0000ffff
enum reg {
C_CAN_CTRL_REG = 0,
C_CAN_CTRL_EX_REG,
C_CAN_STS_REG,
C_CAN_ERR_CNT_REG,
C_CAN_BTR_REG,
C_CAN_INT_REG,
C_CAN_TEST_REG,
C_CAN_BRPEXT_REG,
C_CAN_IF1_COMREQ_REG,
C_CAN_IF1_COMMSK_REG,
C_CAN_IF1_MASK1_REG,
C_CAN_IF1_MASK2_REG,
C_CAN_IF1_ARB1_REG,
C_CAN_IF1_ARB2_REG,
C_CAN_IF1_MSGCTRL_REG,
C_CAN_IF1_DATA1_REG,
C_CAN_IF1_DATA2_REG,
C_CAN_IF1_DATA3_REG,
C_CAN_IF1_DATA4_REG,
C_CAN_IF2_COMREQ_REG,
C_CAN_IF2_COMMSK_REG,
C_CAN_IF2_MASK1_REG,
C_CAN_IF2_MASK2_REG,
C_CAN_IF2_ARB1_REG,
C_CAN_IF2_ARB2_REG,
C_CAN_IF2_MSGCTRL_REG,
C_CAN_IF2_DATA1_REG,
C_CAN_IF2_DATA2_REG,
C_CAN_IF2_DATA3_REG,
C_CAN_IF2_DATA4_REG,
C_CAN_TXRQST1_REG,
C_CAN_TXRQST2_REG,
C_CAN_NEWDAT1_REG,
C_CAN_NEWDAT2_REG,
C_CAN_INTPND1_REG,
C_CAN_INTPND2_REG,
C_CAN_MSGVAL1_REG,
C_CAN_MSGVAL2_REG,
C_CAN_FUNCTION_REG,
};
static const u16 reg_map_c_can[] = {
[C_CAN_CTRL_REG] = 0x00,
[C_CAN_STS_REG] = 0x02,
[C_CAN_ERR_CNT_REG] = 0x04,
[C_CAN_BTR_REG] = 0x06,
[C_CAN_INT_REG] = 0x08,
[C_CAN_TEST_REG] = 0x0A,
[C_CAN_BRPEXT_REG] = 0x0C,
[C_CAN_IF1_COMREQ_REG] = 0x10,
[C_CAN_IF1_COMMSK_REG] = 0x12,
[C_CAN_IF1_MASK1_REG] = 0x14,
[C_CAN_IF1_MASK2_REG] = 0x16,
[C_CAN_IF1_ARB1_REG] = 0x18,
[C_CAN_IF1_ARB2_REG] = 0x1A,
[C_CAN_IF1_MSGCTRL_REG] = 0x1C,
[C_CAN_IF1_DATA1_REG] = 0x1E,
[C_CAN_IF1_DATA2_REG] = 0x20,
[C_CAN_IF1_DATA3_REG] = 0x22,
[C_CAN_IF1_DATA4_REG] = 0x24,
[C_CAN_IF2_COMREQ_REG] = 0x40,
[C_CAN_IF2_COMMSK_REG] = 0x42,
[C_CAN_IF2_MASK1_REG] = 0x44,
[C_CAN_IF2_MASK2_REG] = 0x46,
[C_CAN_IF2_ARB1_REG] = 0x48,
[C_CAN_IF2_ARB2_REG] = 0x4A,
[C_CAN_IF2_MSGCTRL_REG] = 0x4C,
[C_CAN_IF2_DATA1_REG] = 0x4E,
[C_CAN_IF2_DATA2_REG] = 0x50,
[C_CAN_IF2_DATA3_REG] = 0x52,
[C_CAN_IF2_DATA4_REG] = 0x54,
[C_CAN_TXRQST1_REG] = 0x80,
[C_CAN_TXRQST2_REG] = 0x82,
[C_CAN_NEWDAT1_REG] = 0x90,
[C_CAN_NEWDAT2_REG] = 0x92,
[C_CAN_INTPND1_REG] = 0xA0,
[C_CAN_INTPND2_REG] = 0xA2,
[C_CAN_MSGVAL1_REG] = 0xB0,
[C_CAN_MSGVAL2_REG] = 0xB2,
};
static const u16 reg_map_d_can[] = {
[C_CAN_CTRL_REG] = 0x00,
[C_CAN_CTRL_EX_REG] = 0x02,
[C_CAN_STS_REG] = 0x04,
[C_CAN_ERR_CNT_REG] = 0x08,
[C_CAN_BTR_REG] = 0x0C,
[C_CAN_BRPEXT_REG] = 0x0E,
[C_CAN_INT_REG] = 0x10,
[C_CAN_TEST_REG] = 0x14,
[C_CAN_FUNCTION_REG] = 0x18,
[C_CAN_TXRQST1_REG] = 0x88,
[C_CAN_TXRQST2_REG] = 0x8A,
[C_CAN_NEWDAT1_REG] = 0x9C,
[C_CAN_NEWDAT2_REG] = 0x9E,
[C_CAN_INTPND1_REG] = 0xB0,
[C_CAN_INTPND2_REG] = 0xB2,
[C_CAN_MSGVAL1_REG] = 0xC4,
[C_CAN_MSGVAL2_REG] = 0xC6,
[C_CAN_IF1_COMREQ_REG] = 0x100,
[C_CAN_IF1_COMMSK_REG] = 0x102,
[C_CAN_IF1_MASK1_REG] = 0x104,
[C_CAN_IF1_MASK2_REG] = 0x106,
[C_CAN_IF1_ARB1_REG] = 0x108,
[C_CAN_IF1_ARB2_REG] = 0x10A,
[C_CAN_IF1_MSGCTRL_REG] = 0x10C,
[C_CAN_IF1_DATA1_REG] = 0x110,
[C_CAN_IF1_DATA2_REG] = 0x112,
[C_CAN_IF1_DATA3_REG] = 0x114,
[C_CAN_IF1_DATA4_REG] = 0x116,
[C_CAN_IF2_COMREQ_REG] = 0x120,
[C_CAN_IF2_COMMSK_REG] = 0x122,
[C_CAN_IF2_MASK1_REG] = 0x124,
[C_CAN_IF2_MASK2_REG] = 0x126,
[C_CAN_IF2_ARB1_REG] = 0x128,
[C_CAN_IF2_ARB2_REG] = 0x12A,
[C_CAN_IF2_MSGCTRL_REG] = 0x12C,
[C_CAN_IF2_DATA1_REG] = 0x130,
[C_CAN_IF2_DATA2_REG] = 0x132,
[C_CAN_IF2_DATA3_REG] = 0x134,
[C_CAN_IF2_DATA4_REG] = 0x136,
};
enum c_can_dev_id {
BOSCH_C_CAN_PLATFORM,
BOSCH_C_CAN,
BOSCH_D_CAN,
};
/* c_can private data structure */
struct c_can_priv {
struct can_priv can; /* must be the first member */
struct napi_struct napi;
struct net_device *dev;
struct device *device;
atomic_t tx_active;
unsigned long tx_dir;
int last_status;
u16 (*read_reg) (const struct c_can_priv *priv, enum reg index);
void (*write_reg) (const struct c_can_priv *priv, enum reg index, u16 val);
u32 (*read_reg32) (const struct c_can_priv *priv, enum reg index);
void (*write_reg32) (const struct c_can_priv *priv, enum reg index, u32 val);
void __iomem *base;
const u16 *regs;
void *priv; /* for board-specific data */
enum c_can_dev_id type;
u32 __iomem *raminit_ctrlreg;
int instance;
void (*raminit) (const struct c_can_priv *priv, bool enable);
u32 comm_rcv_high;
u32 rxmasked;
u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
};
struct net_device *alloc_c_can_dev(void);
void free_c_can_dev(struct net_device *dev);
int register_c_can_dev(struct net_device *dev);
void unregister_c_can_dev(struct net_device *dev);
#ifdef CONFIG_PM
int c_can_power_up(struct net_device *dev);
int c_can_power_down(struct net_device *dev);
#endif
#endif /* C_CAN_H */

View file

@ -0,0 +1,293 @@
/*
* PCI bus driver for Bosch C_CAN/D_CAN controller
*
* Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
*
* Borrowed from c_can_platform.c
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/can/dev.h>
#include "c_can.h"
#define PCI_DEVICE_ID_PCH_CAN 0x8818
#define PCH_PCI_SOFT_RESET 0x01fc
enum c_can_pci_reg_align {
C_CAN_REG_ALIGN_16,
C_CAN_REG_ALIGN_32,
C_CAN_REG_32,
};
struct c_can_pci_data {
/* Specify if is C_CAN or D_CAN */
enum c_can_dev_id type;
/* Set the register alignment in the memory */
enum c_can_pci_reg_align reg_align;
/* Set the frequency */
unsigned int freq;
/* PCI bar number */
int bar;
/* Callback for reset */
void (*init)(const struct c_can_priv *priv, bool enable);
};
/*
* 16-bit c_can registers can be arranged differently in the memory
* architecture of different implementations. For example: 16-bit
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface.
*/
static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + priv->regs[index]);
}
static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + priv->regs[index]);
}
static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + 2 * priv->regs[index]);
}
static u16 c_can_pci_read_reg_32bit(const struct c_can_priv *priv,
enum reg index)
{
return (u16)ioread32(priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_write_reg_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
iowrite32((u32)val, priv->base + 2 * priv->regs[index]);
}
static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index)
{
u32 val;
val = priv->read_reg(priv, index);
val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
return val;
}
static void c_can_pci_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
{
priv->write_reg(priv, index + 1, val >> 16);
priv->write_reg(priv, index, val);
}
static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable)
{
if (enable) {
u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET;
/* write to sw reset register */
iowrite32(1, addr);
iowrite32(0, addr);
}
}
static int c_can_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
struct c_can_priv *priv;
struct net_device *dev;
void __iomem *addr;
int ret;
ret = pci_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "pci_enable_device FAILED\n");
goto out;
}
ret = pci_request_regions(pdev, KBUILD_MODNAME);
if (ret) {
dev_err(&pdev->dev, "pci_request_regions FAILED\n");
goto out_disable_device;
}
ret = pci_enable_msi(pdev);
if (!ret) {
dev_info(&pdev->dev, "MSI enabled\n");
pci_set_master(pdev);
}
addr = pci_iomap(pdev, c_can_pci_data->bar,
pci_resource_len(pdev, c_can_pci_data->bar));
if (!addr) {
dev_err(&pdev->dev,
"device has no PCI memory resources, "
"failing adapter\n");
ret = -ENOMEM;
goto out_release_regions;
}
/* allocate the c_can device */
dev = alloc_c_can_dev();
if (!dev) {
ret = -ENOMEM;
goto out_iounmap;
}
priv = netdev_priv(dev);
pci_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->irq = pdev->irq;
priv->base = addr;
if (!c_can_pci_data->freq) {
dev_err(&pdev->dev, "no clock frequency defined\n");
ret = -ENODEV;
goto out_free_c_can;
} else {
priv->can.clock.freq = c_can_pci_data->freq;
}
/* Configure CAN type */
switch (c_can_pci_data->type) {
case BOSCH_C_CAN:
priv->regs = reg_map_c_can;
break;
case BOSCH_D_CAN:
priv->regs = reg_map_d_can;
priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
break;
default:
ret = -EINVAL;
goto out_free_c_can;
}
priv->type = c_can_pci_data->type;
/* Configure access to registers */
switch (c_can_pci_data->reg_align) {
case C_CAN_REG_ALIGN_32:
priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
break;
case C_CAN_REG_ALIGN_16:
priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
break;
case C_CAN_REG_32:
priv->read_reg = c_can_pci_read_reg_32bit;
priv->write_reg = c_can_pci_write_reg_32bit;
break;
default:
ret = -EINVAL;
goto out_free_c_can;
}
priv->read_reg32 = c_can_pci_read_reg32;
priv->write_reg32 = c_can_pci_write_reg32;
priv->raminit = c_can_pci_data->init;
ret = register_c_can_dev(dev);
if (ret) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
KBUILD_MODNAME, ret);
goto out_free_c_can;
}
dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
KBUILD_MODNAME, priv->regs, dev->irq);
return 0;
out_free_c_can:
free_c_can_dev(dev);
out_iounmap:
pci_iounmap(pdev, addr);
out_release_regions:
pci_disable_msi(pdev);
pci_clear_master(pdev);
pci_release_regions(pdev);
out_disable_device:
pci_disable_device(pdev);
out:
return ret;
}
static void c_can_pci_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct c_can_priv *priv = netdev_priv(dev);
unregister_c_can_dev(dev);
free_c_can_dev(dev);
pci_iounmap(pdev, priv->base);
pci_disable_msi(pdev);
pci_clear_master(pdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
static struct c_can_pci_data c_can_sta2x11= {
.type = BOSCH_C_CAN,
.reg_align = C_CAN_REG_ALIGN_32,
.freq = 52000000, /* 52 Mhz */
.bar = 0,
};
static struct c_can_pci_data c_can_pch = {
.type = BOSCH_C_CAN,
.reg_align = C_CAN_REG_32,
.freq = 50000000, /* 50 MHz */
.init = c_can_pci_reset_pch,
.bar = 1,
};
#define C_CAN_ID(_vend, _dev, _driverdata) { \
PCI_DEVICE(_vend, _dev), \
.driver_data = (unsigned long)&_driverdata, \
}
static const struct pci_device_id c_can_pci_tbl[] = {
C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
c_can_sta2x11),
C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,
c_can_pch),
{},
};
static struct pci_driver c_can_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = c_can_pci_tbl,
.probe = c_can_pci_probe,
.remove = c_can_pci_remove,
};
module_pci_driver(c_can_pci_driver);
MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);

View file

@ -0,0 +1,409 @@
/*
* Platform CAN bus driver for Bosch C_CAN controller
*
* Copyright (C) 2010 ST Microelectronics
* Bhupesh Sharma <bhupesh.sharma@st.com>
*
* Borrowed heavily from the C_CAN driver originally written by:
* Copyright (C) 2007
* - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
* - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
*
* Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
* Bosch C_CAN user manual can be obtained from:
* http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
* users_manual_c_can.pdf
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/can/dev.h>
#include "c_can.h"
#define CAN_RAMINIT_START_MASK(i) (0x001 << (i))
#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i))
#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i))
#define DCAN_RAM_INIT_BIT (1 << 3)
static DEFINE_SPINLOCK(raminit_lock);
/*
* 16-bit c_can registers can be arranged differently in the memory
* architecture of different implementations. For example: 16-bit
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface.
*/
static u16 c_can_plat_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + priv->regs[index]);
}
static void c_can_plat_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + priv->regs[index]);
}
static u16 c_can_plat_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index)
{
return readw(priv->base + 2 * priv->regs[index]);
}
static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
{
writew(val, priv->base + 2 * priv->regs[index]);
}
static void c_can_hw_raminit_wait_ti(const struct c_can_priv *priv, u32 mask,
u32 val)
{
/* We look only at the bits of our instance. */
val &= mask;
while ((readl(priv->raminit_ctrlreg) & mask) != val)
udelay(1);
}
static void c_can_hw_raminit_ti(const struct c_can_priv *priv, bool enable)
{
u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance);
u32 ctrl;
spin_lock(&raminit_lock);
ctrl = readl(priv->raminit_ctrlreg);
/* We clear the done and start bit first. The start bit is
* looking at the 0 -> transition, but is not self clearing;
* And we clear the init done bit as well.
*/
ctrl &= ~CAN_RAMINIT_START_MASK(priv->instance);
ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
writel(ctrl, priv->raminit_ctrlreg);
ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance);
c_can_hw_raminit_wait_ti(priv, mask, ctrl);
if (enable) {
/* Set start bit and wait for the done bit. */
ctrl |= CAN_RAMINIT_START_MASK(priv->instance);
writel(ctrl, priv->raminit_ctrlreg);
ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
c_can_hw_raminit_wait_ti(priv, mask, ctrl);
}
spin_unlock(&raminit_lock);
}
static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
{
u32 val;
val = priv->read_reg(priv, index);
val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
return val;
}
static void c_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
{
priv->write_reg(priv, index + 1, val >> 16);
priv->write_reg(priv, index, val);
}
static u32 d_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
{
return readl(priv->base + priv->regs[index]);
}
static void d_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
{
writel(val, priv->base + priv->regs[index]);
}
static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask)
{
while (priv->read_reg32(priv, C_CAN_FUNCTION_REG) & mask)
udelay(1);
}
static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
{
u32 ctrl;
ctrl = priv->read_reg32(priv, C_CAN_FUNCTION_REG);
ctrl &= ~DCAN_RAM_INIT_BIT;
priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl);
c_can_hw_raminit_wait(priv, ctrl);
if (enable) {
ctrl |= DCAN_RAM_INIT_BIT;
priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl);
c_can_hw_raminit_wait(priv, ctrl);
}
}
static struct platform_device_id c_can_id_table[] = {
[BOSCH_C_CAN_PLATFORM] = {
.name = KBUILD_MODNAME,
.driver_data = BOSCH_C_CAN,
},
[BOSCH_C_CAN] = {
.name = "c_can",
.driver_data = BOSCH_C_CAN,
},
[BOSCH_D_CAN] = {
.name = "d_can",
.driver_data = BOSCH_D_CAN,
}, {
}
};
MODULE_DEVICE_TABLE(platform, c_can_id_table);
static const struct of_device_id c_can_of_table[] = {
{ .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
{ .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, c_can_of_table);
static int c_can_plat_probe(struct platform_device *pdev)
{
int ret;
void __iomem *addr;
struct net_device *dev;
struct c_can_priv *priv;
const struct of_device_id *match;
const struct platform_device_id *id;
struct resource *mem, *res;
int irq;
struct clk *clk;
if (pdev->dev.of_node) {
match = of_match_device(c_can_of_table, &pdev->dev);
if (!match) {
dev_err(&pdev->dev, "Failed to find matching dt id\n");
ret = -EINVAL;
goto exit;
}
id = match->data;
} else {
id = platform_get_device_id(pdev);
}
/* get the appropriate clk */
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
goto exit;
}
/* get the platform data */
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
ret = -ENODEV;
goto exit;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) {
ret = PTR_ERR(addr);
goto exit;
}
/* allocate the c_can device */
dev = alloc_c_can_dev();
if (!dev) {
ret = -ENOMEM;
goto exit;
}
priv = netdev_priv(dev);
switch (id->driver_data) {
case BOSCH_C_CAN:
priv->regs = reg_map_c_can;
switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
case IORESOURCE_MEM_32BIT:
priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
priv->read_reg32 = c_can_plat_read_reg32;
priv->write_reg32 = c_can_plat_write_reg32;
break;
case IORESOURCE_MEM_16BIT:
default:
priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
priv->read_reg32 = c_can_plat_read_reg32;
priv->write_reg32 = c_can_plat_write_reg32;
break;
}
break;
case BOSCH_D_CAN:
priv->regs = reg_map_d_can;
priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
priv->read_reg32 = d_can_plat_read_reg32;
priv->write_reg32 = d_can_plat_write_reg32;
if (pdev->dev.of_node)
priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
else
priv->instance = pdev->id;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
/* Not all D_CAN modules have a separate register for the D_CAN
* RAM initialization. Use default RAM init bit in D_CAN module
* if not specified in DT.
*/
if (!res) {
priv->raminit = c_can_hw_raminit;
break;
}
priv->raminit_ctrlreg = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!priv->raminit_ctrlreg || priv->instance < 0)
dev_info(&pdev->dev, "control memory is not used for raminit\n");
else
priv->raminit = c_can_hw_raminit_ti;
break;
default:
ret = -EINVAL;
goto exit_free_device;
}
dev->irq = irq;
priv->base = addr;
priv->device = &pdev->dev;
priv->can.clock.freq = clk_get_rate(clk);
priv->priv = clk;
priv->type = id->driver_data;
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
ret = register_c_can_dev(dev);
if (ret) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
KBUILD_MODNAME, ret);
goto exit_free_device;
}
dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
KBUILD_MODNAME, priv->base, dev->irq);
return 0;
exit_free_device:
free_c_can_dev(dev);
exit:
dev_err(&pdev->dev, "probe failed\n");
return ret;
}
static int c_can_plat_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_c_can_dev(dev);
free_c_can_dev(dev);
return 0;
}
#ifdef CONFIG_PM
static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
{
int ret;
struct net_device *ndev = platform_get_drvdata(pdev);
struct c_can_priv *priv = netdev_priv(ndev);
if (priv->type != BOSCH_D_CAN) {
dev_warn(&pdev->dev, "Not supported\n");
return 0;
}
if (netif_running(ndev)) {
netif_stop_queue(ndev);
netif_device_detach(ndev);
}
ret = c_can_power_down(ndev);
if (ret) {
netdev_err(ndev, "failed to enter power down mode\n");
return ret;
}
priv->can.state = CAN_STATE_SLEEPING;
return 0;
}
static int c_can_resume(struct platform_device *pdev)
{
int ret;
struct net_device *ndev = platform_get_drvdata(pdev);
struct c_can_priv *priv = netdev_priv(ndev);
if (priv->type != BOSCH_D_CAN) {
dev_warn(&pdev->dev, "Not supported\n");
return 0;
}
ret = c_can_power_up(ndev);
if (ret) {
netdev_err(ndev, "Still in power down mode\n");
return ret;
}
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) {
netif_device_attach(ndev);
netif_start_queue(ndev);
}
return 0;
}
#else
#define c_can_suspend NULL
#define c_can_resume NULL
#endif
static struct platform_driver c_can_plat_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.of_match_table = c_can_of_table,
},
.probe = c_can_plat_probe,
.remove = c_can_plat_remove,
.suspend = c_can_suspend,
.resume = c_can_resume,
.id_table = c_can_id_table,
};
module_platform_driver(c_can_plat_driver);
MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");

View file

@ -0,0 +1,21 @@
menuconfig CAN_CC770
tristate "Bosch CC770 and Intel AN82527 devices"
depends on HAS_IOMEM
if CAN_CC770
config CAN_CC770_ISA
tristate "ISA Bus based legacy CC770 driver"
---help---
This driver adds legacy support for CC770 and AN82527 chips
connected to the ISA bus using I/O port, memory mapped or
indirect access.
config CAN_CC770_PLATFORM
tristate "Generic Platform Bus based CC770 driver"
---help---
This driver adds support for the CC770 and AN82527 chips
connected to the "platform bus" (Linux abstraction for directly
to the processor attached devices).
endif

View file

@ -0,0 +1,7 @@
#
# Makefile for the Bosch CC770 CAN controller drivers.
#
obj-$(CONFIG_CAN_CC770) += cc770.o
obj-$(CONFIG_CAN_CC770_ISA) += cc770_isa.o
obj-$(CONFIG_CAN_CC770_PLATFORM) += cc770_platform.o

View file

@ -0,0 +1,883 @@
/*
* Core driver for the CC770 and AN82527 CAN controllers
*
* Copyright (C) 2009, 2011 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#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 <linux/can/platform/cc770.h>
#include "cc770.h"
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(KBUILD_MODNAME "CAN netdevice driver");
/*
* The CC770 is a CAN controller from Bosch, which is 100% compatible
* with the AN82527 from Intel, but with "bugs" being fixed and some
* additional functionality, mainly:
*
* 1. RX and TX error counters are readable.
* 2. Support of silent (listen-only) mode.
* 3. Message object 15 can receive all types of frames, also RTR and EFF.
*
* Details are available from Bosch's "CC770_Product_Info_2007-01.pdf",
* which explains in detail the compatibility between the CC770 and the
* 82527. This driver use the additional functionality 3. on real CC770
* devices. Unfortunately, the CC770 does still not store the message
* identifier of received remote transmission request frames and
* therefore it's set to 0.
*
* The message objects 1..14 can be used for TX and RX while the message
* objects 15 is optimized for RX. It has a shadow register for reliable
* data receiption under heavy bus load. Therefore it makes sense to use
* this message object for the needed use case. The frame type (EFF/SFF)
* for the message object 15 can be defined via kernel module parameter
* "msgobj15_eff". If not equal 0, it will receive 29-bit EFF frames,
* otherwise 11 bit SFF messages.
*/
static int msgobj15_eff;
module_param(msgobj15_eff, int, S_IRUGO);
MODULE_PARM_DESC(msgobj15_eff, "Extended 29-bit frames for message object 15 "
"(default: 11-bit standard frames)");
static int i82527_compat;
module_param(i82527_compat, int, S_IRUGO);
MODULE_PARM_DESC(i82527_compat, "Strict Intel 82527 comptibility mode "
"without using additional functions");
/*
* This driver uses the last 5 message objects 11..15. The definitions
* and structure below allows to configure and assign them to the real
* message object.
*/
static unsigned char cc770_obj_flags[CC770_OBJ_MAX] = {
[CC770_OBJ_RX0] = CC770_OBJ_FLAG_RX,
[CC770_OBJ_RX1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_EFF,
[CC770_OBJ_RX_RTR0] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR,
[CC770_OBJ_RX_RTR1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR |
CC770_OBJ_FLAG_EFF,
[CC770_OBJ_TX] = 0,
};
static const struct can_bittiming_const cc770_bittiming_const = {
.name = KBUILD_MODNAME,
.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 inline int intid2obj(unsigned int intid)
{
if (intid == 2)
return 0;
else
return MSGOBJ_LAST + 2 - intid;
}
static void enable_all_objs(const struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
u8 msgcfg;
unsigned char obj_flags;
unsigned int o, mo;
for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) {
obj_flags = priv->obj_flags[o];
mo = obj2msgobj(o);
if (obj_flags & CC770_OBJ_FLAG_RX) {
/*
* We don't need extra objects for RTR and EFF if
* the additional CC770 functions are enabled.
*/
if (priv->control_normal_mode & CTRL_EAF) {
if (o > 0)
continue;
netdev_dbg(dev, "Message object %d for "
"RX data, RTR, SFF and EFF\n", mo);
} else {
netdev_dbg(dev,
"Message object %d for RX %s %s\n",
mo, obj_flags & CC770_OBJ_FLAG_RTR ?
"RTR" : "data",
obj_flags & CC770_OBJ_FLAG_EFF ?
"EFF" : "SFF");
}
if (obj_flags & CC770_OBJ_FLAG_EFF)
msgcfg = MSGCFG_XTD;
else
msgcfg = 0;
if (obj_flags & CC770_OBJ_FLAG_RTR)
msgcfg |= MSGCFG_DIR;
cc770_write_reg(priv, msgobj[mo].config, msgcfg);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_SET | TXIE_RES |
RXIE_SET | INTPND_RES);
if (obj_flags & CC770_OBJ_FLAG_RTR)
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | CPUUPD_SET |
TXRQST_RES | RMTPND_RES);
else
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | MSGLST_RES |
TXRQST_RES | RMTPND_RES);
} else {
netdev_dbg(dev, "Message object %d for "
"TX data, RTR, SFF and EFF\n", mo);
cc770_write_reg(priv, msgobj[mo].ctrl1,
RMTPND_RES | TXRQST_RES |
CPUUPD_RES | NEWDAT_RES);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_RES | TXIE_RES |
RXIE_RES | INTPND_RES);
}
}
}
static void disable_all_objs(const struct cc770_priv *priv)
{
int o, mo;
for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) {
mo = obj2msgobj(o);
if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) {
if (o > 0 && priv->control_normal_mode & CTRL_EAF)
continue;
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | MSGLST_RES |
TXRQST_RES | RMTPND_RES);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_RES | TXIE_RES |
RXIE_RES | INTPND_RES);
} else {
/* Clear message object for send */
cc770_write_reg(priv, msgobj[mo].ctrl1,
RMTPND_RES | TXRQST_RES |
CPUUPD_RES | NEWDAT_RES);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_RES | TXIE_RES |
RXIE_RES | INTPND_RES);
}
}
}
static void set_reset_mode(struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
/* Enable configuration and puts chip in bus-off, disable interrupts */
cc770_write_reg(priv, control, CTRL_CCE | CTRL_INI);
priv->can.state = CAN_STATE_STOPPED;
/* Clear interrupts */
cc770_read_reg(priv, interrupt);
/* Clear status register */
cc770_write_reg(priv, status, 0);
/* Disable all used message objects */
disable_all_objs(priv);
}
static void set_normal_mode(struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
/* Clear interrupts */
cc770_read_reg(priv, interrupt);
/* Clear status register and pre-set last error code */
cc770_write_reg(priv, status, STAT_LEC_MASK);
/* Enable all used message objects*/
enable_all_objs(dev);
/*
* Clear bus-off, interrupts only for errors,
* not for status change
*/
cc770_write_reg(priv, control, priv->control_normal_mode);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
static void chipset_init(struct cc770_priv *priv)
{
int mo, id, data;
/* Enable configuration and put chip in bus-off, disable interrupts */
cc770_write_reg(priv, control, (CTRL_CCE | CTRL_INI));
/* Set CLKOUT divider and slew rates */
cc770_write_reg(priv, clkout, priv->clkout);
/* Configure CPU interface / CLKOUT enable */
cc770_write_reg(priv, cpu_interface, priv->cpu_interface);
/* Set bus configuration */
cc770_write_reg(priv, bus_config, priv->bus_config);
/* Clear interrupts */
cc770_read_reg(priv, interrupt);
/* Clear status register */
cc770_write_reg(priv, status, 0);
/* Clear and invalidate message objects */
for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++) {
cc770_write_reg(priv, msgobj[mo].ctrl0,
INTPND_UNC | RXIE_RES |
TXIE_RES | MSGVAL_RES);
cc770_write_reg(priv, msgobj[mo].ctrl0,
INTPND_RES | RXIE_RES |
TXIE_RES | MSGVAL_RES);
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | MSGLST_RES |
TXRQST_RES | RMTPND_RES);
for (data = 0; data < 8; data++)
cc770_write_reg(priv, msgobj[mo].data[data], 0);
for (id = 0; id < 4; id++)
cc770_write_reg(priv, msgobj[mo].id[id], 0);
cc770_write_reg(priv, msgobj[mo].config, 0);
}
/* Set all global ID masks to "don't care" */
cc770_write_reg(priv, global_mask_std[0], 0);
cc770_write_reg(priv, global_mask_std[1], 0);
cc770_write_reg(priv, global_mask_ext[0], 0);
cc770_write_reg(priv, global_mask_ext[1], 0);
cc770_write_reg(priv, global_mask_ext[2], 0);
cc770_write_reg(priv, global_mask_ext[3], 0);
}
static int cc770_probe_chip(struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
/* Enable configuration, put chip in bus-off, disable ints */
cc770_write_reg(priv, control, CTRL_CCE | CTRL_EAF | CTRL_INI);
/* Configure cpu interface / CLKOUT disable */
cc770_write_reg(priv, cpu_interface, priv->cpu_interface);
/*
* Check if hardware reset is still inactive or maybe there
* is no chip in this address space
*/
if (cc770_read_reg(priv, cpu_interface) & CPUIF_RST) {
netdev_info(dev, "probing @0x%p failed (reset)\n",
priv->reg_base);
return -ENODEV;
}
/* Write and read back test pattern (some arbitrary values) */
cc770_write_reg(priv, msgobj[1].data[1], 0x25);
cc770_write_reg(priv, msgobj[2].data[3], 0x52);
cc770_write_reg(priv, msgobj[10].data[6], 0xc3);
if ((cc770_read_reg(priv, msgobj[1].data[1]) != 0x25) ||
(cc770_read_reg(priv, msgobj[2].data[3]) != 0x52) ||
(cc770_read_reg(priv, msgobj[10].data[6]) != 0xc3)) {
netdev_info(dev, "probing @0x%p failed (pattern)\n",
priv->reg_base);
return -ENODEV;
}
/* Check if this chip is a CC770 supporting additional functions */
if (cc770_read_reg(priv, control) & CTRL_EAF)
priv->control_normal_mode |= CTRL_EAF;
return 0;
}
static void cc770_start(struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
/* leave reset mode */
if (priv->can.state != CAN_STATE_STOPPED)
set_reset_mode(dev);
/* leave reset mode */
set_normal_mode(dev);
}
static int cc770_set_mode(struct net_device *dev, enum can_mode mode)
{
switch (mode) {
case CAN_MODE_START:
cc770_start(dev);
netif_wake_queue(dev);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int cc770_set_bittiming(struct net_device *dev)
{
struct cc770_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);
cc770_write_reg(priv, bit_timing_0, btr0);
cc770_write_reg(priv, bit_timing_1, btr1);
return 0;
}
static int cc770_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct cc770_priv *priv = netdev_priv(dev);
bec->txerr = cc770_read_reg(priv, tx_error_counter);
bec->rxerr = cc770_read_reg(priv, rx_error_counter);
return 0;
}
static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf = (struct can_frame *)skb->data;
unsigned int mo = obj2msgobj(CC770_OBJ_TX);
u8 dlc, rtr;
u32 id;
int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
if ((cc770_read_reg(priv,
msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
netdev_err(dev, "TX register is still occupied!\n");
return NETDEV_TX_BUSY;
}
netif_stop_queue(dev);
dlc = cf->can_dlc;
id = cf->can_id;
if (cf->can_id & CAN_RTR_FLAG)
rtr = 0;
else
rtr = MSGCFG_DIR;
cc770_write_reg(priv, msgobj[mo].ctrl1,
RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES);
if (id & CAN_EFF_FLAG) {
id &= CAN_EFF_MASK;
cc770_write_reg(priv, msgobj[mo].config,
(dlc << 4) | rtr | MSGCFG_XTD);
cc770_write_reg(priv, msgobj[mo].id[3], id << 3);
cc770_write_reg(priv, msgobj[mo].id[2], id >> 5);
cc770_write_reg(priv, msgobj[mo].id[1], id >> 13);
cc770_write_reg(priv, msgobj[mo].id[0], id >> 21);
} else {
id &= CAN_SFF_MASK;
cc770_write_reg(priv, msgobj[mo].config, (dlc << 4) | rtr);
cc770_write_reg(priv, msgobj[mo].id[0], id >> 3);
cc770_write_reg(priv, msgobj[mo].id[1], id << 5);
}
for (i = 0; i < dlc; i++)
cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]);
/* Store echo skb before starting the transfer */
can_put_echo_skb(skb, dev, 0);
cc770_write_reg(priv, msgobj[mo].ctrl1,
RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
stats->tx_bytes += dlc;
/*
* HM: We had some cases of repeated IRQs so make sure the
* INT is acknowledged I know it's already further up, but
* doing again fixed the issue
*/
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
return NETDEV_TX_OK;
}
static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1)
{
struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u8 config;
u32 id;
int i;
skb = alloc_can_skb(dev, &cf);
if (!skb)
return;
config = cc770_read_reg(priv, msgobj[mo].config);
if (ctrl1 & RMTPND_SET) {
/*
* Unfortunately, the chip does not store the real message
* identifier of the received remote transmission request
* frame. Therefore we set it to 0.
*/
cf->can_id = CAN_RTR_FLAG;
if (config & MSGCFG_XTD)
cf->can_id |= CAN_EFF_FLAG;
cf->can_dlc = 0;
} else {
if (config & MSGCFG_XTD) {
id = cc770_read_reg(priv, msgobj[mo].id[3]);
id |= cc770_read_reg(priv, msgobj[mo].id[2]) << 8;
id |= cc770_read_reg(priv, msgobj[mo].id[1]) << 16;
id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 24;
id >>= 3;
id |= CAN_EFF_FLAG;
} else {
id = cc770_read_reg(priv, msgobj[mo].id[1]);
id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 8;
id >>= 5;
}
cf->can_id = id;
cf->can_dlc = get_can_dlc((config & 0xf0) >> 4);
for (i = 0; i < cf->can_dlc; i++)
cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]);
}
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
}
static int cc770_err(struct net_device *dev, u8 status)
{
struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u8 lec;
netdev_dbg(dev, "status interrupt (%#x)\n", status);
skb = alloc_can_err_skb(dev, &cf);
if (!skb)
return -ENOMEM;
/* Use extended functions of the CC770 */
if (priv->control_normal_mode & CTRL_EAF) {
cf->data[6] = cc770_read_reg(priv, tx_error_counter);
cf->data[7] = cc770_read_reg(priv, rx_error_counter);
}
if (status & STAT_BOFF) {
/* Disable interrupts */
cc770_write_reg(priv, control, CTRL_INI);
cf->can_id |= CAN_ERR_BUSOFF;
priv->can.state = CAN_STATE_BUS_OFF;
can_bus_off(dev);
} else if (status & STAT_WARN) {
cf->can_id |= CAN_ERR_CRTL;
/* Only the CC770 does show error passive */
if (cf->data[7] > 127) {
cf->data[1] = CAN_ERR_CRTL_RX_PASSIVE |
CAN_ERR_CRTL_TX_PASSIVE;
priv->can.state = CAN_STATE_ERROR_PASSIVE;
priv->can.can_stats.error_passive++;
} else {
cf->data[1] = CAN_ERR_CRTL_RX_WARNING |
CAN_ERR_CRTL_TX_WARNING;
priv->can.state = CAN_STATE_ERROR_WARNING;
priv->can.can_stats.error_warning++;
}
} else {
/* Back to error avtive */
cf->can_id |= CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_ACTIVE;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
lec = status & STAT_LEC_MASK;
if (lec < 7 && lec > 0) {
if (lec == STAT_LEC_ACK) {
cf->can_id |= CAN_ERR_ACK;
} else {
cf->can_id |= CAN_ERR_PROT;
switch (lec) {
case STAT_LEC_STUFF:
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
case STAT_LEC_FORM:
cf->data[2] |= CAN_ERR_PROT_FORM;
break;
case STAT_LEC_BIT1:
cf->data[2] |= CAN_ERR_PROT_BIT1;
break;
case STAT_LEC_BIT0:
cf->data[2] |= CAN_ERR_PROT_BIT0;
break;
case STAT_LEC_CRC:
cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
break;
}
}
}
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
return 0;
}
static int cc770_status_interrupt(struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
u8 status;
status = cc770_read_reg(priv, status);
/* Reset the status register including RXOK and TXOK */
cc770_write_reg(priv, status, STAT_LEC_MASK);
if (status & (STAT_WARN | STAT_BOFF) ||
(status & STAT_LEC_MASK) != STAT_LEC_MASK) {
cc770_err(dev, status);
return status & STAT_BOFF;
}
return 0;
}
static void cc770_rx_interrupt(struct net_device *dev, unsigned int o)
{
struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
unsigned int mo = obj2msgobj(o);
u8 ctrl1;
int n = CC770_MAX_MSG;
while (n--) {
ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
if (!(ctrl1 & NEWDAT_SET)) {
/* Check for RTR if additional functions are enabled */
if (priv->control_normal_mode & CTRL_EAF) {
if (!(cc770_read_reg(priv, msgobj[mo].ctrl0) &
INTPND_SET))
break;
} else {
break;
}
}
if (ctrl1 & MSGLST_SET) {
stats->rx_over_errors++;
stats->rx_errors++;
}
if (mo < MSGOBJ_LAST)
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | MSGLST_RES |
TXRQST_UNC | RMTPND_UNC);
cc770_rx(dev, mo, ctrl1);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_SET | TXIE_RES |
RXIE_SET | INTPND_RES);
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | MSGLST_RES |
TXRQST_RES | RMTPND_RES);
}
}
static void cc770_rtr_interrupt(struct net_device *dev, unsigned int o)
{
struct cc770_priv *priv = netdev_priv(dev);
unsigned int mo = obj2msgobj(o);
u8 ctrl0, ctrl1;
int n = CC770_MAX_MSG;
while (n--) {
ctrl0 = cc770_read_reg(priv, msgobj[mo].ctrl0);
if (!(ctrl0 & INTPND_SET))
break;
ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
cc770_rx(dev, mo, ctrl1);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_SET | TXIE_RES |
RXIE_SET | INTPND_RES);
cc770_write_reg(priv, msgobj[mo].ctrl1,
NEWDAT_RES | CPUUPD_SET |
TXRQST_RES | RMTPND_RES);
}
}
static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
{
struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
unsigned int mo = obj2msgobj(o);
/* Nothing more to send, switch off interrupts */
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
/*
* We had some cases of repeated IRQ so make sure the
* INT is acknowledged
*/
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
stats->tx_packets++;
can_get_echo_skb(dev, 0);
netif_wake_queue(dev);
}
static irqreturn_t cc770_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct cc770_priv *priv = netdev_priv(dev);
u8 intid;
int o, n = 0;
/* Shared interrupts and IRQ off? */
if (priv->can.state == CAN_STATE_STOPPED)
return IRQ_NONE;
if (priv->pre_irq)
priv->pre_irq(priv);
while (n < CC770_MAX_IRQ) {
/* Read the highest pending interrupt request */
intid = cc770_read_reg(priv, interrupt);
if (!intid)
break;
n++;
if (intid == 1) {
/* Exit in case of bus-off */
if (cc770_status_interrupt(dev))
break;
} else {
o = intid2obj(intid);
if (o >= CC770_OBJ_MAX) {
netdev_err(dev, "Unexpected interrupt id %d\n",
intid);
continue;
}
if (priv->obj_flags[o] & CC770_OBJ_FLAG_RTR)
cc770_rtr_interrupt(dev, o);
else if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX)
cc770_rx_interrupt(dev, o);
else
cc770_tx_interrupt(dev, o);
}
}
if (priv->post_irq)
priv->post_irq(priv);
if (n >= CC770_MAX_IRQ)
netdev_dbg(dev, "%d messages handled in ISR", n);
return (n) ? IRQ_HANDLED : IRQ_NONE;
}
static int cc770_open(struct net_device *dev)
{
struct cc770_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;
err = request_irq(dev->irq, &cc770_interrupt, priv->irq_flags,
dev->name, dev);
if (err) {
close_candev(dev);
return -EAGAIN;
}
/* init and start chip */
cc770_start(dev);
netif_start_queue(dev);
return 0;
}
static int cc770_close(struct net_device *dev)
{
netif_stop_queue(dev);
set_reset_mode(dev);
free_irq(dev->irq, dev);
close_candev(dev);
return 0;
}
struct net_device *alloc_cc770dev(int sizeof_priv)
{
struct net_device *dev;
struct cc770_priv *priv;
dev = alloc_candev(sizeof(struct cc770_priv) + sizeof_priv,
CC770_ECHO_SKB_MAX);
if (!dev)
return NULL;
priv = netdev_priv(dev);
priv->dev = dev;
priv->can.bittiming_const = &cc770_bittiming_const;
priv->can.do_set_bittiming = cc770_set_bittiming;
priv->can.do_set_mode = cc770_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags));
if (sizeof_priv)
priv->priv = (void *)priv + sizeof(struct cc770_priv);
return dev;
}
EXPORT_SYMBOL_GPL(alloc_cc770dev);
void free_cc770dev(struct net_device *dev)
{
free_candev(dev);
}
EXPORT_SYMBOL_GPL(free_cc770dev);
static const struct net_device_ops cc770_netdev_ops = {
.ndo_open = cc770_open,
.ndo_stop = cc770_close,
.ndo_start_xmit = cc770_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
int register_cc770dev(struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
int err;
err = cc770_probe_chip(dev);
if (err)
return err;
dev->netdev_ops = &cc770_netdev_ops;
dev->flags |= IFF_ECHO; /* we support local echo */
/* Should we use additional functions? */
if (!i82527_compat && priv->control_normal_mode & CTRL_EAF) {
priv->can.do_get_berr_counter = cc770_get_berr_counter;
priv->control_normal_mode = CTRL_IE | CTRL_EAF | CTRL_EIE;
netdev_dbg(dev, "i82527 mode with additional functions\n");
} else {
priv->control_normal_mode = CTRL_IE | CTRL_EIE;
netdev_dbg(dev, "strict i82527 compatibility mode\n");
}
chipset_init(priv);
set_reset_mode(dev);
return register_candev(dev);
}
EXPORT_SYMBOL_GPL(register_cc770dev);
void unregister_cc770dev(struct net_device *dev)
{
set_reset_mode(dev);
unregister_candev(dev);
}
EXPORT_SYMBOL_GPL(unregister_cc770dev);
static __init int cc770_init(void)
{
if (msgobj15_eff) {
cc770_obj_flags[CC770_OBJ_RX0] |= CC770_OBJ_FLAG_EFF;
cc770_obj_flags[CC770_OBJ_RX1] &= ~CC770_OBJ_FLAG_EFF;
}
pr_info("CAN netdevice driver\n");
return 0;
}
module_init(cc770_init);
static __exit void cc770_exit(void)
{
pr_info("driver removed\n");
}
module_exit(cc770_exit);

View file

@ -0,0 +1,203 @@
/*
* Core driver for the CC770 and AN82527 CAN controllers
*
* Copyright (C) 2009, 2011 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.
*/
#ifndef CC770_DEV_H
#define CC770_DEV_H
#include <linux/can/dev.h>
struct cc770_msgobj {
u8 ctrl0;
u8 ctrl1;
u8 id[4];
u8 config;
u8 data[8];
u8 dontuse; /* padding */
} __packed;
struct cc770_regs {
union {
struct cc770_msgobj msgobj[16]; /* Message object 1..15 */
struct {
u8 control; /* Control Register */
u8 status; /* Status Register */
u8 cpu_interface; /* CPU Interface Register */
u8 dontuse1;
u8 high_speed_read[2]; /* High Speed Read */
u8 global_mask_std[2]; /* Standard Global Mask */
u8 global_mask_ext[4]; /* Extended Global Mask */
u8 msg15_mask[4]; /* Message 15 Mask */
u8 dontuse2[15];
u8 clkout; /* Clock Out Register */
u8 dontuse3[15];
u8 bus_config; /* Bus Configuration Register */
u8 dontuse4[15];
u8 bit_timing_0; /* Bit Timing Register byte 0 */
u8 dontuse5[15];
u8 bit_timing_1; /* Bit Timing Register byte 1 */
u8 dontuse6[15];
u8 interrupt; /* Interrupt Register */
u8 dontuse7[15];
u8 rx_error_counter; /* Receive Error Counter */
u8 dontuse8[15];
u8 tx_error_counter; /* Transmit Error Counter */
u8 dontuse9[31];
u8 p1_conf;
u8 dontuse10[15];
u8 p2_conf;
u8 dontuse11[15];
u8 p1_in;
u8 dontuse12[15];
u8 p2_in;
u8 dontuse13[15];
u8 p1_out;
u8 dontuse14[15];
u8 p2_out;
u8 dontuse15[15];
u8 serial_reset_addr;
};
};
} __packed;
/* Control Register (0x00) */
#define CTRL_INI 0x01 /* Initialization */
#define CTRL_IE 0x02 /* Interrupt Enable */
#define CTRL_SIE 0x04 /* Status Interrupt Enable */
#define CTRL_EIE 0x08 /* Error Interrupt Enable */
#define CTRL_EAF 0x20 /* Enable additional functions */
#define CTRL_CCE 0x40 /* Change Configuration Enable */
/* Status Register (0x01) */
#define STAT_LEC_STUFF 0x01 /* Stuff error */
#define STAT_LEC_FORM 0x02 /* Form error */
#define STAT_LEC_ACK 0x03 /* Acknowledgement error */
#define STAT_LEC_BIT1 0x04 /* Bit1 error */
#define STAT_LEC_BIT0 0x05 /* Bit0 error */
#define STAT_LEC_CRC 0x06 /* CRC error */
#define STAT_LEC_MASK 0x07 /* Last Error Code mask */
#define STAT_TXOK 0x08 /* Transmit Message Successfully */
#define STAT_RXOK 0x10 /* Receive Message Successfully */
#define STAT_WAKE 0x20 /* Wake Up Status */
#define STAT_WARN 0x40 /* Warning Status */
#define STAT_BOFF 0x80 /* Bus Off Status */
/*
* CPU Interface Register (0x02)
* Clock Out Register (0x1f)
* Bus Configuration Register (0x2f)
*
* see include/linux/can/platform/cc770.h
*/
/* Message Control Register 0 (Base Address + 0x0) */
#define INTPND_RES 0x01 /* No Interrupt pending */
#define INTPND_SET 0x02 /* Interrupt pending */
#define INTPND_UNC 0x03
#define RXIE_RES 0x04 /* Receive Interrupt Disable */
#define RXIE_SET 0x08 /* Receive Interrupt Enable */
#define RXIE_UNC 0x0c
#define TXIE_RES 0x10 /* Transmit Interrupt Disable */
#define TXIE_SET 0x20 /* Transmit Interrupt Enable */
#define TXIE_UNC 0x30
#define MSGVAL_RES 0x40 /* Message Invalid */
#define MSGVAL_SET 0x80 /* Message Valid */
#define MSGVAL_UNC 0xc0
/* Message Control Register 1 (Base Address + 0x01) */
#define NEWDAT_RES 0x01 /* No New Data */
#define NEWDAT_SET 0x02 /* New Data */
#define NEWDAT_UNC 0x03
#define MSGLST_RES 0x04 /* No Message Lost */
#define MSGLST_SET 0x08 /* Message Lost */
#define MSGLST_UNC 0x0c
#define CPUUPD_RES 0x04 /* No CPU Updating */
#define CPUUPD_SET 0x08 /* CPU Updating */
#define CPUUPD_UNC 0x0c
#define TXRQST_RES 0x10 /* No Transmission Request */
#define TXRQST_SET 0x20 /* Transmission Request */
#define TXRQST_UNC 0x30
#define RMTPND_RES 0x40 /* No Remote Request Pending */
#define RMTPND_SET 0x80 /* Remote Request Pending */
#define RMTPND_UNC 0xc0
/* Message Configuration Register (Base Address + 0x06) */
#define MSGCFG_XTD 0x04 /* Extended Identifier */
#define MSGCFG_DIR 0x08 /* Direction is Transmit */
#define MSGOBJ_FIRST 1
#define MSGOBJ_LAST 15
#define CC770_IO_SIZE 0x100
#define CC770_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
#define CC770_MAX_MSG 4 /* max. number of messages handled in ISR */
#define CC770_ECHO_SKB_MAX 1
#define cc770_read_reg(priv, member) \
priv->read_reg(priv, offsetof(struct cc770_regs, member))
#define cc770_write_reg(priv, member, value) \
priv->write_reg(priv, offsetof(struct cc770_regs, member), value)
/*
* Message objects and flags used by this driver
*/
#define CC770_OBJ_FLAG_RX 0x01
#define CC770_OBJ_FLAG_RTR 0x02
#define CC770_OBJ_FLAG_EFF 0x04
enum {
CC770_OBJ_RX0 = 0, /* for receiving normal messages */
CC770_OBJ_RX1, /* for receiving normal messages */
CC770_OBJ_RX_RTR0, /* for receiving remote transmission requests */
CC770_OBJ_RX_RTR1, /* for receiving remote transmission requests */
CC770_OBJ_TX, /* for sending messages */
CC770_OBJ_MAX
};
#define obj2msgobj(o) (MSGOBJ_LAST - (o)) /* message object 11..15 */
/*
* CC770 private data structure
*/
struct cc770_priv {
struct can_priv can; /* must be the first member */
struct sk_buff *echo_skb;
/* the lower-layer is responsible for appropriate locking */
u8 (*read_reg)(const struct cc770_priv *priv, int reg);
void (*write_reg)(const struct cc770_priv *priv, int reg, u8 val);
void (*pre_irq)(const struct cc770_priv *priv);
void (*post_irq)(const struct cc770_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() */
unsigned char obj_flags[CC770_OBJ_MAX];
u8 control_normal_mode; /* Control register for normal mode */
u8 cpu_interface; /* CPU interface register */
u8 clkout; /* Clock out register */
u8 bus_config; /* Bus conffiguration register */
};
struct net_device *alloc_cc770dev(int sizeof_priv);
void free_cc770dev(struct net_device *dev);
int register_cc770dev(struct net_device *dev);
void unregister_cc770dev(struct net_device *dev);
#endif /* CC770_DEV_H */

View file

@ -0,0 +1,380 @@
/*
* Driver for CC770 and AN82527 CAN controllers on the legacy ISA bus
*
* Copyright (C) 2009, 2011 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.
*/
/*
* Bosch CC770 and Intel AN82527 CAN controllers on the ISA or PC-104 bus.
* The I/O port or memory address and the IRQ number must be specified via
* module parameters:
*
* insmod cc770_isa.ko port=0x310,0x380 irq=7,11
*
* for ISA devices using I/O ports or:
*
* insmod cc770_isa.ko mem=0xd1000,0xd1000 irq=7,11
*
* for memory mapped ISA devices.
*
* Indirect access via address and data port is supported as well:
*
* insmod cc770_isa.ko port=0x310,0x380 indirect=1 irq=7,11
*
* Furthermore, the following mode parameter can be defined:
*
* clk: External oscillator clock frequency (default=16000000 [16 MHz])
* cir: CPU interface register (default=0x40 [DSC])
* bcr: Bus configuration register (default=0x40 [CBY])
* cor: Clockout register (default=0x00)
*
* Note: for clk, cir, bcr and cor, the first argument re-defines the
* default for all other devices, e.g.:
*
* insmod cc770_isa.ko mem=0xd1000,0xd1000 irq=7,11 clk=24000000
*
* is equivalent to
*
* insmod cc770_isa.ko mem=0xd1000,0xd1000 irq=7,11 clk=24000000,24000000
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#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.h>
#include <linux/can/dev.h>
#include <linux/can/platform/cc770.h>
#include "cc770.h"
#define MAXDEV 8
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the ISA bus");
MODULE_LICENSE("GPL v2");
#define CLK_DEFAULT 16000000 /* 16 MHz */
#define COR_DEFAULT 0x00
#define BCR_DEFAULT BUSCFG_CBY
static unsigned long port[MAXDEV];
static unsigned long mem[MAXDEV];
static int irq[MAXDEV];
static int clk[MAXDEV];
static u8 cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static u8 cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static u8 bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static int 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(cir, byte, NULL, S_IRUGO);
MODULE_PARM_DESC(cir, "CPU interface register (default=0x40 [DSC])");
module_param_array(cor, byte, NULL, S_IRUGO);
MODULE_PARM_DESC(cor, "Clockout register (default=0x00)");
module_param_array(bcr, byte, NULL, S_IRUGO);
MODULE_PARM_DESC(bcr, "Bus configuration register (default=0x40 [CBY])");
#define CC770_IOSIZE 0x20
#define CC770_IOSIZE_INDIRECT 0x02
/* Spinlock for cc770_isa_port_write_reg_indirect
* and cc770_isa_port_read_reg_indirect
*/
static DEFINE_SPINLOCK(cc770_isa_port_lock);
static struct platform_device *cc770_isa_devs[MAXDEV];
static u8 cc770_isa_mem_read_reg(const struct cc770_priv *priv, int reg)
{
return readb(priv->reg_base + reg);
}
static void cc770_isa_mem_write_reg(const struct cc770_priv *priv,
int reg, u8 val)
{
writeb(val, priv->reg_base + reg);
}
static u8 cc770_isa_port_read_reg(const struct cc770_priv *priv, int reg)
{
return inb((unsigned long)priv->reg_base + reg);
}
static void cc770_isa_port_write_reg(const struct cc770_priv *priv,
int reg, u8 val)
{
outb(val, (unsigned long)priv->reg_base + reg);
}
static u8 cc770_isa_port_read_reg_indirect(const struct cc770_priv *priv,
int reg)
{
unsigned long base = (unsigned long)priv->reg_base;
unsigned long flags;
u8 val;
spin_lock_irqsave(&cc770_isa_port_lock, flags);
outb(reg, base);
val = inb(base + 1);
spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
return val;
}
static void cc770_isa_port_write_reg_indirect(const struct cc770_priv *priv,
int reg, u8 val)
{
unsigned long base = (unsigned long)priv->reg_base;
unsigned long flags;
spin_lock_irqsave(&cc770_isa_port_lock, flags);
outb(reg, base);
outb(val, base + 1);
spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
}
static int cc770_isa_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct cc770_priv *priv;
void __iomem *base = NULL;
int iosize = CC770_IOSIZE;
int idx = pdev->id;
int err;
u32 clktmp;
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, KBUILD_MODNAME)) {
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 = CC770_IOSIZE_INDIRECT;
if (!request_region(port[idx], iosize, KBUILD_MODNAME)) {
err = -EBUSY;
goto exit;
}
}
dev = alloc_cc770dev(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 = cc770_isa_mem_read_reg;
priv->write_reg = cc770_isa_mem_write_reg;
} else {
priv->reg_base = (void __iomem *)port[idx];
dev->base_addr = port[idx];
if (iosize == CC770_IOSIZE_INDIRECT) {
priv->read_reg = cc770_isa_port_read_reg_indirect;
priv->write_reg = cc770_isa_port_write_reg_indirect;
} else {
priv->read_reg = cc770_isa_port_read_reg;
priv->write_reg = cc770_isa_port_write_reg;
}
}
if (clk[idx])
clktmp = clk[idx];
else if (clk[0])
clktmp = clk[0];
else
clktmp = CLK_DEFAULT;
priv->can.clock.freq = clktmp;
if (cir[idx] != 0xff) {
priv->cpu_interface = cir[idx];
} else if (cir[0] != 0xff) {
priv->cpu_interface = cir[0];
} else {
/* The system clock may not exceed 10 MHz */
if (clktmp > 10000000) {
priv->cpu_interface |= CPUIF_DSC;
clktmp /= 2;
}
/* The memory clock may not exceed 8 MHz */
if (clktmp > 8000000)
priv->cpu_interface |= CPUIF_DMC;
}
if (priv->cpu_interface & CPUIF_DSC)
priv->can.clock.freq /= 2;
if (bcr[idx] != 0xff)
priv->bus_config = bcr[idx];
else if (bcr[0] != 0xff)
priv->bus_config = bcr[0];
else
priv->bus_config = BCR_DEFAULT;
if (cor[idx] != 0xff)
priv->clkout = cor[idx];
else if (cor[0] != 0xff)
priv->clkout = cor[0];
else
priv->clkout = COR_DEFAULT;
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_cc770dev(dev);
if (err) {
dev_err(&pdev->dev,
"couldn't register device (err=%d)\n", err);
goto exit_unmap;
}
dev_info(&pdev->dev, "device registered (reg_base=0x%p, irq=%d)\n",
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 cc770_isa_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_cc770dev(dev);
if (mem[idx]) {
iounmap(priv->reg_base);
release_mem_region(mem[idx], CC770_IOSIZE);
} else {
if (priv->read_reg == cc770_isa_port_read_reg_indirect)
release_region(port[idx], CC770_IOSIZE_INDIRECT);
else
release_region(port[idx], CC770_IOSIZE);
}
free_cc770dev(dev);
return 0;
}
static struct platform_driver cc770_isa_driver = {
.probe = cc770_isa_probe,
.remove = cc770_isa_remove,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
};
static int __init cc770_isa_init(void)
{
int idx, err;
for (idx = 0; idx < ARRAY_SIZE(cc770_isa_devs); idx++) {
if ((port[idx] || mem[idx]) && irq[idx]) {
cc770_isa_devs[idx] =
platform_device_alloc(KBUILD_MODNAME, idx);
if (!cc770_isa_devs[idx]) {
err = -ENOMEM;
goto exit_free_devices;
}
err = platform_device_add(cc770_isa_devs[idx]);
if (err) {
platform_device_put(cc770_isa_devs[idx]);
goto exit_free_devices;
}
pr_debug("platform device %d: port=%#lx, mem=%#lx, "
"irq=%d\n",
idx, port[idx], mem[idx], irq[idx]);
} else if (idx == 0 || port[idx] || mem[idx]) {
pr_err("insufficient parameters supplied\n");
err = -EINVAL;
goto exit_free_devices;
}
}
err = platform_driver_register(&cc770_isa_driver);
if (err)
goto exit_free_devices;
pr_info("driver for max. %d devices registered\n", MAXDEV);
return 0;
exit_free_devices:
while (--idx >= 0) {
if (cc770_isa_devs[idx])
platform_device_unregister(cc770_isa_devs[idx]);
}
return err;
}
module_init(cc770_isa_init);
static void __exit cc770_isa_exit(void)
{
int idx;
platform_driver_unregister(&cc770_isa_driver);
for (idx = 0; idx < ARRAY_SIZE(cc770_isa_devs); idx++) {
if (cc770_isa_devs[idx])
platform_device_unregister(cc770_isa_devs[idx]);
}
}
module_exit(cc770_isa_exit);

View file

@ -0,0 +1,274 @@
/*
* Driver for CC770 and AN82527 CAN controllers on the platform bus
*
* Copyright (C) 2009, 2011 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.
*/
/*
* If platform data are used you should have similar definitions
* in your board-specific code:
*
* static struct cc770_platform_data myboard_cc770_pdata = {
* .osc_freq = 16000000,
* .cir = 0x41,
* .cor = 0x20,
* .bcr = 0x40,
* };
*
* Please see include/linux/can/platform/cc770.h for description of
* above fields.
*
* If the device tree is used, you need a CAN node definition in your
* DTS file similar to:
*
* can@3,100 {
* compatible = "bosch,cc770";
* reg = <3 0x100 0x80>;
* interrupts = <2 0>;
* interrupt-parent = <&mpic>;
* bosch,external-clock-frequency = <16000000>;
* };
*
* See "Documentation/devicetree/bindings/net/can/cc770.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/platform_device.h>
#include <linux/of.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/platform/cc770.h>
#include "cc770.h"
#define DRV_NAME "cc770_platform"
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the platform bus");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
#define CC770_PLATFORM_CAN_CLOCK 16000000
static u8 cc770_platform_read_reg(const struct cc770_priv *priv, int reg)
{
return ioread8(priv->reg_base + reg);
}
static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg,
u8 val)
{
iowrite8(val, priv->reg_base + reg);
}
static int cc770_get_of_node_data(struct platform_device *pdev,
struct cc770_priv *priv)
{
struct device_node *np = pdev->dev.of_node;
const u32 *prop;
int prop_size;
u32 clkext;
prop = of_get_property(np, "bosch,external-clock-frequency",
&prop_size);
if (prop && (prop_size == sizeof(u32)))
clkext = *prop;
else
clkext = CC770_PLATFORM_CAN_CLOCK; /* default */
priv->can.clock.freq = clkext;
/* The system clock may not exceed 10 MHz */
if (priv->can.clock.freq > 10000000) {
priv->cpu_interface |= CPUIF_DSC;
priv->can.clock.freq /= 2;
}
/* The memory clock may not exceed 8 MHz */
if (priv->can.clock.freq > 8000000)
priv->cpu_interface |= CPUIF_DMC;
if (of_get_property(np, "bosch,divide-memory-clock", NULL))
priv->cpu_interface |= CPUIF_DMC;
if (of_get_property(np, "bosch,iso-low-speed-mux", NULL))
priv->cpu_interface |= CPUIF_MUX;
if (!of_get_property(np, "bosch,no-comperator-bypass", NULL))
priv->bus_config |= BUSCFG_CBY;
if (of_get_property(np, "bosch,disconnect-rx0-input", NULL))
priv->bus_config |= BUSCFG_DR0;
if (of_get_property(np, "bosch,disconnect-rx1-input", NULL))
priv->bus_config |= BUSCFG_DR1;
if (of_get_property(np, "bosch,disconnect-tx1-output", NULL))
priv->bus_config |= BUSCFG_DT1;
if (of_get_property(np, "bosch,polarity-dominant", NULL))
priv->bus_config |= BUSCFG_POL;
prop = of_get_property(np, "bosch,clock-out-frequency", &prop_size);
if (prop && (prop_size == sizeof(u32)) && *prop > 0) {
u32 cdv = clkext / *prop;
int slew;
if (cdv > 0 && cdv < 16) {
priv->cpu_interface |= CPUIF_CEN;
priv->clkout |= (cdv - 1) & CLKOUT_CD_MASK;
prop = of_get_property(np, "bosch,slew-rate",
&prop_size);
if (prop && (prop_size == sizeof(u32))) {
slew = *prop;
} else {
/* Determine default slew rate */
slew = (CLKOUT_SL_MASK >>
CLKOUT_SL_SHIFT) -
((cdv * clkext - 1) / 8000000);
if (slew < 0)
slew = 0;
}
priv->clkout |= (slew << CLKOUT_SL_SHIFT) &
CLKOUT_SL_MASK;
} else {
dev_dbg(&pdev->dev, "invalid clock-out-frequency\n");
}
}
return 0;
}
static int cc770_get_platform_data(struct platform_device *pdev,
struct cc770_priv *priv)
{
struct cc770_platform_data *pdata = dev_get_platdata(&pdev->dev);
priv->can.clock.freq = pdata->osc_freq;
if (priv->cpu_interface & CPUIF_DSC)
priv->can.clock.freq /= 2;
priv->clkout = pdata->cor;
priv->bus_config = pdata->bcr;
priv->cpu_interface = pdata->cir;
return 0;
}
static int cc770_platform_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct cc770_priv *priv;
struct resource *mem;
resource_size_t mem_size;
void __iomem *base;
int err, irq;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!mem || irq <= 0)
return -ENODEV;
mem_size = resource_size(mem);
if (!request_mem_region(mem->start, mem_size, pdev->name))
return -EBUSY;
base = ioremap(mem->start, mem_size);
if (!base) {
err = -ENOMEM;
goto exit_release_mem;
}
dev = alloc_cc770dev(0);
if (!dev) {
err = -ENOMEM;
goto exit_unmap_mem;
}
dev->irq = irq;
priv = netdev_priv(dev);
priv->read_reg = cc770_platform_read_reg;
priv->write_reg = cc770_platform_write_reg;
priv->irq_flags = IRQF_SHARED;
priv->reg_base = base;
if (pdev->dev.of_node)
err = cc770_get_of_node_data(pdev, priv);
else if (dev_get_platdata(&pdev->dev))
err = cc770_get_platform_data(pdev, priv);
else
err = -ENODEV;
if (err)
goto exit_free_cc770;
dev_dbg(&pdev->dev,
"reg_base=0x%p irq=%d clock=%d cpu_interface=0x%02x "
"bus_config=0x%02x clkout=0x%02x\n",
priv->reg_base, dev->irq, priv->can.clock.freq,
priv->cpu_interface, priv->bus_config, priv->clkout);
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_cc770dev(dev);
if (err) {
dev_err(&pdev->dev,
"couldn't register CC700 device (err=%d)\n", err);
goto exit_free_cc770;
}
return 0;
exit_free_cc770:
free_cc770dev(dev);
exit_unmap_mem:
iounmap(base);
exit_release_mem:
release_mem_region(mem->start, mem_size);
return err;
}
static int cc770_platform_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
struct resource *mem;
unregister_cc770dev(dev);
iounmap(priv->reg_base);
free_cc770dev(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, resource_size(mem));
return 0;
}
static struct of_device_id cc770_platform_table[] = {
{.compatible = "bosch,cc770"}, /* CC770 from Bosch */
{.compatible = "intc,82527"}, /* AN82527 from Intel CP */
{},
};
MODULE_DEVICE_TABLE(of, cc770_platform_table);
static struct platform_driver cc770_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = cc770_platform_table,
},
.probe = cc770_platform_probe,
.remove = cc770_platform_remove,
};
module_platform_driver(cc770_platform_driver);

950
drivers/net/can/dev.c Normal file
View file

@ -0,0 +1,950 @@
/*
* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/can/netlink.h>
#include <linux/can/led.h>
#include <net/rtnetlink.h>
#define MOD_DESC "CAN device driver interface"
MODULE_DESCRIPTION(MOD_DESC);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
/* CAN DLC to real data length conversion helpers */
static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 12, 16, 20, 24, 32, 48, 64};
/* get data length from can_dlc with sanitized can_dlc */
u8 can_dlc2len(u8 can_dlc)
{
return dlc2len[can_dlc & 0x0F];
}
EXPORT_SYMBOL_GPL(can_dlc2len);
static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
9, 9, 9, 9, /* 9 - 12 */
10, 10, 10, 10, /* 13 - 16 */
11, 11, 11, 11, /* 17 - 20 */
12, 12, 12, 12, /* 21 - 24 */
13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
/* map the sanitized data length to an appropriate data length code */
u8 can_len2dlc(u8 len)
{
if (unlikely(len > 64))
return 0xF;
return len2dlc[len];
}
EXPORT_SYMBOL_GPL(can_len2dlc);
#ifdef CONFIG_CAN_CALC_BITTIMING
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
/*
* Bit-timing calculation derived from:
*
* Code based on LinCAN sources and H8S2638 project
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
* Copyright 2005 Stanislav Marek
* email: pisa@cmp.felk.cvut.cz
*
* Calculates proper bit-timing parameters for a specified bit-rate
* and sample-point, which can then be used to set the bit-timing
* registers of the CAN controller. You can find more information
* in the header file linux/can/netlink.h.
*/
static int can_update_spt(const struct can_bittiming_const *btc,
int sampl_pt, int tseg, int *tseg1, int *tseg2)
{
*tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
if (*tseg2 < btc->tseg2_min)
*tseg2 = btc->tseg2_min;
if (*tseg2 > btc->tseg2_max)
*tseg2 = btc->tseg2_max;
*tseg1 = tseg - *tseg2;
if (*tseg1 > btc->tseg1_max) {
*tseg1 = btc->tseg1_max;
*tseg2 = tseg - *tseg1;
}
return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
}
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{
struct can_priv *priv = netdev_priv(dev);
long best_error = 1000000000, error = 0;
int best_tseg = 0, best_brp = 0, brp = 0;
int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
int spt_error = 1000, spt = 0, sampl_pt;
long rate;
u64 v64;
/* Use CiA recommended sample points */
if (bt->sample_point) {
sampl_pt = bt->sample_point;
} else {
if (bt->bitrate > 800000)
sampl_pt = 750;
else if (bt->bitrate > 500000)
sampl_pt = 800;
else
sampl_pt = 875;
}
/* tseg even = round down, odd = round up */
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
tsegall = 1 + tseg / 2;
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
/* chose brp step which is possible in system */
brp = (brp / btc->brp_inc) * btc->brp_inc;
if ((brp < btc->brp_min) || (brp > btc->brp_max))
continue;
rate = priv->clock.freq / (brp * tsegall);
error = bt->bitrate - rate;
/* tseg brp biterror */
if (error < 0)
error = -error;
if (error > best_error)
continue;
best_error = error;
if (error == 0) {
spt = can_update_spt(btc, sampl_pt, tseg / 2,
&tseg1, &tseg2);
error = sampl_pt - spt;
if (error < 0)
error = -error;
if (error > spt_error)
continue;
spt_error = error;
}
best_tseg = tseg / 2;
best_brp = brp;
if (error == 0)
break;
}
if (best_error) {
/* Error in one-tenth of a percent */
error = (best_error * 1000) / bt->bitrate;
if (error > CAN_CALC_MAX_ERROR) {
netdev_err(dev,
"bitrate error %ld.%ld%% too high\n",
error / 10, error % 10);
return -EDOM;
} else {
netdev_warn(dev, "bitrate error %ld.%ld%%\n",
error / 10, error % 10);
}
}
/* real sample point */
bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg,
&tseg1, &tseg2);
v64 = (u64)best_brp * 1000000000UL;
do_div(v64, priv->clock.freq);
bt->tq = (u32)v64;
bt->prop_seg = tseg1 / 2;
bt->phase_seg1 = tseg1 - bt->prop_seg;
bt->phase_seg2 = tseg2;
/* check for sjw user settings */
if (!bt->sjw || !btc->sjw_max)
bt->sjw = 1;
else {
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
if (bt->sjw > btc->sjw_max)
bt->sjw = btc->sjw_max;
/* bt->sjw must not be higher than tseg2 */
if (tseg2 < bt->sjw)
bt->sjw = tseg2;
}
bt->brp = best_brp;
/* real bit-rate */
bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
return 0;
}
#else /* !CONFIG_CAN_CALC_BITTIMING */
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{
netdev_err(dev, "bit-timing calculation not available\n");
return -EINVAL;
}
#endif /* CONFIG_CAN_CALC_BITTIMING */
/*
* Checks the validity of the specified bit-timing parameters prop_seg,
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
* prescaler value brp. You can find more information in the header
* file linux/can/netlink.h.
*/
static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{
struct can_priv *priv = netdev_priv(dev);
int tseg1, alltseg;
u64 brp64;
tseg1 = bt->prop_seg + bt->phase_seg1;
if (!bt->sjw)
bt->sjw = 1;
if (bt->sjw > btc->sjw_max ||
tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
return -ERANGE;
brp64 = (u64)priv->clock.freq * (u64)bt->tq;
if (btc->brp_inc > 1)
do_div(brp64, btc->brp_inc);
brp64 += 500000000UL - 1;
do_div(brp64, 1000000000UL); /* the practicable BRP */
if (btc->brp_inc > 1)
brp64 *= btc->brp_inc;
bt->brp = (u32)brp64;
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
return -EINVAL;
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
return 0;
}
static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{
int err;
/* Check if the CAN device has bit-timing parameters */
if (!btc)
return -EOPNOTSUPP;
/*
* Depending on the given can_bittiming parameter structure the CAN
* timing parameters are calculated based on the provided bitrate OR
* alternatively the CAN timing parameters (tq, prop_seg, etc.) are
* provided directly which are then checked and fixed up.
*/
if (!bt->tq && bt->bitrate)
err = can_calc_bittiming(dev, bt, btc);
else if (bt->tq && !bt->bitrate)
err = can_fixup_bittiming(dev, bt, btc);
else
err = -EINVAL;
return err;
}
/*
* Local echo of CAN messages
*
* CAN network devices *should* support a local echo functionality
* (see Documentation/networking/can.txt). To test the handling of CAN
* interfaces that do not support the local echo both driver types are
* implemented. In the case that the driver does not support the echo
* the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
* to perform the echo as a fallback solution.
*/
static void can_flush_echo_skb(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
int i;
for (i = 0; i < priv->echo_skb_max; i++) {
if (priv->echo_skb[i]) {
kfree_skb(priv->echo_skb[i]);
priv->echo_skb[i] = NULL;
stats->tx_dropped++;
stats->tx_aborted_errors++;
}
}
}
/*
* Put the skb on the stack to be looped backed locally lateron
*
* The function is typically called in the start_xmit function
* of the device driver. The driver must protect access to
* priv->echo_skb, if necessary.
*/
void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
/* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
(skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD))) {
kfree_skb(skb);
return;
}
if (!priv->echo_skb[idx]) {
skb = can_create_echo_skb(skb);
if (!skb)
return;
/* make settings for echo to reduce code in irq context */
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev;
/* save this skb for tx interrupt echo handling */
priv->echo_skb[idx] = skb;
} else {
/* locking problem with netif_stop_queue() ?? */
netdev_err(dev, "%s: BUG! echo_skb is occupied!\n", __func__);
kfree_skb(skb);
}
}
EXPORT_SYMBOL_GPL(can_put_echo_skb);
/*
* Get the skb from the stack and loop it back locally
*
* The function is typically called when the TX done interrupt
* is handled in the device driver. The driver must protect
* access to priv->echo_skb, if necessary.
*/
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
if (priv->echo_skb[idx]) {
struct sk_buff *skb = priv->echo_skb[idx];
struct can_frame *cf = (struct can_frame *)skb->data;
u8 dlc = cf->can_dlc;
netif_rx(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
return dlc;
}
return 0;
}
EXPORT_SYMBOL_GPL(can_get_echo_skb);
/*
* Remove the skb from the stack and free it.
*
* The function is typically called when TX failed.
*/
void can_free_echo_skb(struct net_device *dev, unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
if (priv->echo_skb[idx]) {
dev_kfree_skb_any(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
}
}
EXPORT_SYMBOL_GPL(can_free_echo_skb);
/*
* CAN device restart for bus-off recovery
*/
static void can_restart(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb;
struct can_frame *cf;
int err;
BUG_ON(netif_carrier_ok(dev));
/*
* No synchronization needed because the device is bus-off and
* no messages can come in or go out.
*/
can_flush_echo_skb(dev);
/* send restart message upstream */
skb = alloc_can_err_skb(dev, &cf);
if (skb == NULL) {
err = -ENOMEM;
goto restart;
}
cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
restart:
netdev_dbg(dev, "restarted\n");
priv->can_stats.restarts++;
/* Now restart the device */
err = priv->do_set_mode(dev, CAN_MODE_START);
netif_carrier_on(dev);
if (err)
netdev_err(dev, "Error %d during restart", err);
}
int can_restart_now(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
/*
* A manual restart is only permitted if automatic restart is
* disabled and the device is in the bus-off state
*/
if (priv->restart_ms)
return -EINVAL;
if (priv->state != CAN_STATE_BUS_OFF)
return -EBUSY;
/* Runs as soon as possible in the timer context */
mod_timer(&priv->restart_timer, jiffies);
return 0;
}
/*
* CAN bus-off
*
* This functions should be called when the device goes bus-off to
* tell the netif layer that no more packets can be sent or received.
* If enabled, a timer is started to trigger bus-off recovery.
*/
void can_bus_off(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
netdev_dbg(dev, "bus-off\n");
netif_carrier_off(dev);
priv->can_stats.bus_off++;
if (priv->restart_ms)
mod_timer(&priv->restart_timer,
jiffies + (priv->restart_ms * HZ) / 1000);
}
EXPORT_SYMBOL_GPL(can_bus_off);
static void can_setup(struct net_device *dev)
{
dev->type = ARPHRD_CAN;
dev->mtu = CAN_MTU;
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->tx_queue_len = 10;
/* New-style flags. */
dev->flags = IFF_NOARP;
dev->features = NETIF_F_HW_CSUM;
}
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{
struct sk_buff *skb;
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
sizeof(struct can_frame));
if (unlikely(!skb))
return NULL;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex;
*cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(*cf, 0, sizeof(struct can_frame));
return skb;
}
EXPORT_SYMBOL_GPL(alloc_can_skb);
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
struct canfd_frame **cfd)
{
struct sk_buff *skb;
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
sizeof(struct canfd_frame));
if (unlikely(!skb))
return NULL;
skb->protocol = htons(ETH_P_CANFD);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = dev->ifindex;
*cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame));
memset(*cfd, 0, sizeof(struct canfd_frame));
return skb;
}
EXPORT_SYMBOL_GPL(alloc_canfd_skb);
struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
{
struct sk_buff *skb;
skb = alloc_can_skb(dev, cf);
if (unlikely(!skb))
return NULL;
(*cf)->can_id = CAN_ERR_FLAG;
(*cf)->can_dlc = CAN_ERR_DLC;
return skb;
}
EXPORT_SYMBOL_GPL(alloc_can_err_skb);
/*
* Allocate and setup space for the CAN network device
*/
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
{
struct net_device *dev;
struct can_priv *priv;
int size;
if (echo_skb_max)
size = ALIGN(sizeof_priv, sizeof(struct sk_buff *)) +
echo_skb_max * sizeof(struct sk_buff *);
else
size = sizeof_priv;
dev = alloc_netdev(size, "can%d", NET_NAME_UNKNOWN, can_setup);
if (!dev)
return NULL;
priv = netdev_priv(dev);
if (echo_skb_max) {
priv->echo_skb_max = echo_skb_max;
priv->echo_skb = (void *)priv +
ALIGN(sizeof_priv, sizeof(struct sk_buff *));
}
priv->state = CAN_STATE_STOPPED;
init_timer(&priv->restart_timer);
return dev;
}
EXPORT_SYMBOL_GPL(alloc_candev);
/*
* Free space of the CAN network device
*/
void free_candev(struct net_device *dev)
{
free_netdev(dev);
}
EXPORT_SYMBOL_GPL(free_candev);
/*
* changing MTU and control mode for CAN/CANFD devices
*/
int can_change_mtu(struct net_device *dev, int new_mtu)
{
struct can_priv *priv = netdev_priv(dev);
/* Do not allow changing the MTU while running */
if (dev->flags & IFF_UP)
return -EBUSY;
/* allow change of MTU according to the CANFD ability of the device */
switch (new_mtu) {
case CAN_MTU:
priv->ctrlmode &= ~CAN_CTRLMODE_FD;
break;
case CANFD_MTU:
if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
return -EINVAL;
priv->ctrlmode |= CAN_CTRLMODE_FD;
break;
default:
return -EINVAL;
}
dev->mtu = new_mtu;
return 0;
}
EXPORT_SYMBOL_GPL(can_change_mtu);
/*
* Common open function when the device gets opened.
*
* This function should be called in the open function of the device
* driver.
*/
int open_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
if (!priv->bittiming.bitrate) {
netdev_err(dev, "bit-timing not yet defined\n");
return -EINVAL;
}
/* For CAN FD the data bitrate has to be >= the arbitration bitrate */
if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
(!priv->data_bittiming.bitrate ||
(priv->data_bittiming.bitrate < priv->bittiming.bitrate))) {
netdev_err(dev, "incorrect/missing data bit-timing\n");
return -EINVAL;
}
/* Switch carrier on if device was stopped while in bus-off state */
if (!netif_carrier_ok(dev))
netif_carrier_on(dev);
setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);
return 0;
}
EXPORT_SYMBOL_GPL(open_candev);
/*
* Common close function for cleanup before the device gets closed.
*
* This function should be called in the close function of the device
* driver.
*/
void close_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
del_timer_sync(&priv->restart_timer);
can_flush_echo_skb(dev);
}
EXPORT_SYMBOL_GPL(close_candev);
/*
* CAN netlink interface
*/
static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_STATE] = { .type = NLA_U32 },
[IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
[IFLA_CAN_RESTART] = { .type = NLA_U32 },
[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
[IFLA_CAN_DATA_BITTIMING]
= { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_DATA_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
};
static int can_changelink(struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct can_priv *priv = netdev_priv(dev);
int err;
/* We need synchronization with dev->stop() */
ASSERT_RTNL();
if (data[IFLA_CAN_BITTIMING]) {
struct can_bittiming bt;
/* Do not allow changing bittiming while running */
if (dev->flags & IFF_UP)
return -EBUSY;
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
err = can_get_bittiming(dev, &bt, priv->bittiming_const);
if (err)
return err;
memcpy(&priv->bittiming, &bt, sizeof(bt));
if (priv->do_set_bittiming) {
/* Finally, set the bit-timing registers */
err = priv->do_set_bittiming(dev);
if (err)
return err;
}
}
if (data[IFLA_CAN_CTRLMODE]) {
struct can_ctrlmode *cm;
/* Do not allow changing controller mode while running */
if (dev->flags & IFF_UP)
return -EBUSY;
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
/* check whether changed bits are allowed to be modified */
if (cm->mask & ~priv->ctrlmode_supported)
return -EOPNOTSUPP;
/* clear bits to be modified and copy the flag values */
priv->ctrlmode &= ~cm->mask;
priv->ctrlmode |= (cm->flags & cm->mask);
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
if (priv->ctrlmode & CAN_CTRLMODE_FD)
dev->mtu = CANFD_MTU;
else
dev->mtu = CAN_MTU;
}
if (data[IFLA_CAN_RESTART_MS]) {
/* Do not allow changing restart delay while running */
if (dev->flags & IFF_UP)
return -EBUSY;
priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
}
if (data[IFLA_CAN_RESTART]) {
/* Do not allow a restart while not running */
if (!(dev->flags & IFF_UP))
return -EINVAL;
err = can_restart_now(dev);
if (err)
return err;
}
if (data[IFLA_CAN_DATA_BITTIMING]) {
struct can_bittiming dbt;
/* Do not allow changing bittiming while running */
if (dev->flags & IFF_UP)
return -EBUSY;
memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
sizeof(dbt));
err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const);
if (err)
return err;
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
if (priv->do_set_data_bittiming) {
/* Finally, set the bit-timing registers */
err = priv->do_set_data_bittiming(dev);
if (err)
return err;
}
}
return 0;
}
static size_t can_get_size(const struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
size_t size = 0;
if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */
size += nla_total_size(sizeof(struct can_bittiming));
if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
size += nla_total_size(sizeof(struct can_bittiming_const));
size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
size += nla_total_size(sizeof(struct can_berr_counter));
if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */
size += nla_total_size(sizeof(struct can_bittiming));
if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */
size += nla_total_size(sizeof(struct can_bittiming_const));
return size;
}
static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct can_ctrlmode cm = {.flags = priv->ctrlmode};
struct can_berr_counter bec;
enum can_state state = priv->state;
if (priv->do_get_state)
priv->do_get_state(dev, &state);
if ((priv->bittiming.bitrate &&
nla_put(skb, IFLA_CAN_BITTIMING,
sizeof(priv->bittiming), &priv->bittiming)) ||
(priv->bittiming_const &&
nla_put(skb, IFLA_CAN_BITTIMING_CONST,
sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) ||
nla_put_u32(skb, IFLA_CAN_STATE, state) ||
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
(priv->do_get_berr_counter &&
!priv->do_get_berr_counter(dev, &bec) &&
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
(priv->data_bittiming.bitrate &&
nla_put(skb, IFLA_CAN_DATA_BITTIMING,
sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
(priv->data_bittiming_const &&
nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
sizeof(*priv->data_bittiming_const),
priv->data_bittiming_const)))
return -EMSGSIZE;
return 0;
}
static size_t can_get_xstats_size(const struct net_device *dev)
{
return sizeof(struct can_device_stats);
}
static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
if (nla_put(skb, IFLA_INFO_XSTATS,
sizeof(priv->can_stats), &priv->can_stats))
goto nla_put_failure;
return 0;
nla_put_failure:
return -EMSGSIZE;
}
static int can_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
return -EOPNOTSUPP;
}
static struct rtnl_link_ops can_link_ops __read_mostly = {
.kind = "can",
.maxtype = IFLA_CAN_MAX,
.policy = can_policy,
.setup = can_setup,
.newlink = can_newlink,
.changelink = can_changelink,
.get_size = can_get_size,
.fill_info = can_fill_info,
.get_xstats_size = can_get_xstats_size,
.fill_xstats = can_fill_xstats,
};
/*
* Register the CAN network device
*/
int register_candev(struct net_device *dev)
{
dev->rtnl_link_ops = &can_link_ops;
return register_netdev(dev);
}
EXPORT_SYMBOL_GPL(register_candev);
/*
* Unregister the CAN network device
*/
void unregister_candev(struct net_device *dev)
{
unregister_netdev(dev);
}
EXPORT_SYMBOL_GPL(unregister_candev);
/*
* Test if a network device is a candev based device
* and return the can_priv* if so.
*/
struct can_priv *safe_candev_priv(struct net_device *dev)
{
if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops))
return NULL;
return netdev_priv(dev);
}
EXPORT_SYMBOL_GPL(safe_candev_priv);
static __init int can_dev_init(void)
{
int err;
can_led_notifier_init();
err = rtnl_link_register(&can_link_ops);
if (!err)
printk(KERN_INFO MOD_DESC "\n");
return err;
}
module_init(can_dev_init);
static __exit void can_dev_exit(void)
{
rtnl_link_unregister(&can_link_ops);
can_led_notifier_exit();
}
module_exit(can_dev_exit);
MODULE_ALIAS_RTNL_LINK("can");

1389
drivers/net/can/flexcan.c Normal file

File diff suppressed because it is too large Load diff

1752
drivers/net/can/grcan.c Normal file

File diff suppressed because it is too large Load diff

1924
drivers/net/can/janz-ican3.c Normal file

File diff suppressed because it is too large Load diff

127
drivers/net/can/led.c Normal file
View file

@ -0,0 +1,127 @@
/*
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
* Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/can/dev.h>
#include <linux/can/led.h>
static unsigned long led_delay = 50;
module_param(led_delay, ulong, 0644);
MODULE_PARM_DESC(led_delay,
"blink delay time for activity leds (msecs, default: 50).");
/* Trigger a LED event in response to a CAN device event */
void can_led_event(struct net_device *netdev, enum can_led_event event)
{
struct can_priv *priv = netdev_priv(netdev);
switch (event) {
case CAN_LED_EVENT_OPEN:
led_trigger_event(priv->tx_led_trig, LED_FULL);
led_trigger_event(priv->rx_led_trig, LED_FULL);
break;
case CAN_LED_EVENT_STOP:
led_trigger_event(priv->tx_led_trig, LED_OFF);
led_trigger_event(priv->rx_led_trig, LED_OFF);
break;
case CAN_LED_EVENT_TX:
if (led_delay)
led_trigger_blink_oneshot(priv->tx_led_trig,
&led_delay, &led_delay, 1);
break;
case CAN_LED_EVENT_RX:
if (led_delay)
led_trigger_blink_oneshot(priv->rx_led_trig,
&led_delay, &led_delay, 1);
break;
}
}
EXPORT_SYMBOL_GPL(can_led_event);
static void can_led_release(struct device *gendev, void *res)
{
struct can_priv *priv = netdev_priv(to_net_dev(gendev));
led_trigger_unregister_simple(priv->tx_led_trig);
led_trigger_unregister_simple(priv->rx_led_trig);
}
/* Register CAN LED triggers for a CAN device
*
* This is normally called from a driver's probe function
*/
void devm_can_led_init(struct net_device *netdev)
{
struct can_priv *priv = netdev_priv(netdev);
void *res;
res = devres_alloc(can_led_release, 0, GFP_KERNEL);
if (!res) {
netdev_err(netdev, "cannot register LED triggers\n");
return;
}
snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
"%s-tx", netdev->name);
snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
"%s-rx", netdev->name);
led_trigger_register_simple(priv->tx_led_trig_name,
&priv->tx_led_trig);
led_trigger_register_simple(priv->rx_led_trig_name,
&priv->rx_led_trig);
devres_add(&netdev->dev, res);
}
EXPORT_SYMBOL_GPL(devm_can_led_init);
/* NETDEV rename notifier to rename the associated led triggers too */
static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
struct can_priv *priv = safe_candev_priv(netdev);
char name[CAN_LED_NAME_SZ];
if (!priv)
return NOTIFY_DONE;
if (!priv->tx_led_trig || !priv->rx_led_trig)
return NOTIFY_DONE;
if (msg == NETDEV_CHANGENAME) {
snprintf(name, sizeof(name), "%s-tx", netdev->name);
led_trigger_rename_static(name, priv->tx_led_trig);
snprintf(name, sizeof(name), "%s-rx", netdev->name);
led_trigger_rename_static(name, priv->rx_led_trig);
}
return NOTIFY_DONE;
}
/* notifier block for netdevice event */
static struct notifier_block can_netdev_notifier __read_mostly = {
.notifier_call = can_led_notifier,
};
int __init can_led_notifier_init(void)
{
return register_netdevice_notifier(&can_netdev_notifier);
}
void __exit can_led_notifier_exit(void)
{
unregister_netdevice_notifier(&can_netdev_notifier);
}

View file

@ -0,0 +1,5 @@
config CAN_M_CAN
depends on HAS_IOMEM
tristate "Bosch M_CAN devices"
---help---
Say Y here if you want to support for Bosch M_CAN controller.

View file

@ -0,0 +1,5 @@
#
# Makefile for the Bosch M_CAN controller driver.
#
obj-$(CONFIG_CAN_M_CAN) += m_can.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
config CAN_MSCAN
depends on PPC
tristate "Support for Freescale MSCAN based chips"
---help---
The Motorola Scalable Controller Area Network (MSCAN) definition
is based on the MSCAN12 definition which is the specific
implementation of the Motorola Scalable CAN concept targeted for
the Motorola MC68HC12 Microcontroller Family.
if CAN_MSCAN
config CAN_MPC5XXX
tristate "Freescale MPC5xxx onboard CAN controller"
depends on (PPC_MPC52xx || PPC_MPC512x)
---help---
If you say yes here you get support for Freescale's MPC5xxx
onboard CAN controller. Currently, the MPC5200, MPC5200B and
MPC5121 (Rev. 2 and later) are supported.
This driver can also be built as a module. If so, the module
will be called mscan-mpc5xxx.ko.
endif

View file

@ -0,0 +1,3 @@
obj-$(CONFIG_CAN_MPC5XXX) += mscan-mpc5xxx.o
mscan-mpc5xxx-objs := mscan.o mpc5xxx_can.o

View file

@ -0,0 +1,459 @@
/*
* CAN bus driver for the Freescale MPC5xxx embedded CPU.
*
* Copyright (C) 2004-2005 Andrey Volkov <avolkov@varma-el.com>,
* Varma Electronics Oy
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2009 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/can/dev.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/mpc52xx.h>
#include "mscan.h"
#define DRV_NAME "mpc5xxx_can"
struct mpc5xxx_can_data {
unsigned int type;
u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
int *mscan_clksrc);
void (*put_clock)(struct platform_device *ofdev);
};
#ifdef CONFIG_PPC_MPC52xx
static struct of_device_id mpc52xx_cdm_ids[] = {
{ .compatible = "fsl,mpc5200-cdm", },
{}
};
static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
const char *clock_name, int *mscan_clksrc)
{
unsigned int pvr;
struct mpc52xx_cdm __iomem *cdm;
struct device_node *np_cdm;
unsigned int freq;
u32 val;
pvr = mfspr(SPRN_PVR);
/*
* Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
* (IP_CLK) can be selected as MSCAN clock source. According to
* the MPC5200 user's manual, the oscillator clock is the better
* choice as it has less jitter. For this reason, it is selected
* by default. Unfortunately, it can not be selected for the old
* MPC5200 Rev. A chips due to a hardware bug (check errata).
*/
if (clock_name && strcmp(clock_name, "ip") == 0)
*mscan_clksrc = MSCAN_CLKSRC_BUS;
else
*mscan_clksrc = MSCAN_CLKSRC_XTAL;
freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
if (!freq)
return 0;
if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
return freq;
/* Determine SYS_XTAL_IN frequency from the clock domain settings */
np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);
if (!np_cdm) {
dev_err(&ofdev->dev, "can't get clock node!\n");
return 0;
}
cdm = of_iomap(np_cdm, 0);
if (in_8(&cdm->ipb_clk_sel) & 0x1)
freq *= 2;
val = in_be32(&cdm->rstcfg);
freq *= (val & (1 << 5)) ? 8 : 4;
freq /= (val & (1 << 6)) ? 12 : 16;
of_node_put(np_cdm);
iounmap(cdm);
return freq;
}
#else /* !CONFIG_PPC_MPC52xx */
static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
const char *clock_name, int *mscan_clksrc)
{
return 0;
}
#endif /* CONFIG_PPC_MPC52xx */
#ifdef CONFIG_PPC_MPC512x
static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
const char *clock_source, int *mscan_clksrc)
{
struct device_node *np;
u32 clockdiv;
enum {
CLK_FROM_AUTO,
CLK_FROM_IPS,
CLK_FROM_SYS,
CLK_FROM_REF,
} clk_from;
struct clk *clk_in, *clk_can;
unsigned long freq_calc;
struct mscan_priv *priv;
struct clk *clk_ipg;
/* the caller passed in the clock source spec that was read from
* the device tree, get the optional clock divider as well
*/
np = ofdev->dev.of_node;
clockdiv = 1;
of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
clock_source ? clock_source : "<NULL>", clockdiv);
/* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
* get set, and the 'ips' clock is the input to the MSCAN
* component
*
* for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
* bit needs to get cleared, an optional clock-divider may have
* been specified (the default value is 1), the appropriate
* MSCAN related MCLK is the input to the MSCAN component
*
* in the absence of a clock-source spec, first an optimal clock
* gets determined based on the 'sys' clock, if that fails the
* 'ref' clock is used
*/
clk_from = CLK_FROM_AUTO;
if (clock_source) {
/* interpret the device tree's spec for the clock source */
if (!strcmp(clock_source, "ip"))
clk_from = CLK_FROM_IPS;
else if (!strcmp(clock_source, "sys"))
clk_from = CLK_FROM_SYS;
else if (!strcmp(clock_source, "ref"))
clk_from = CLK_FROM_REF;
else
goto err_invalid;
dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
}
if (clk_from == CLK_FROM_AUTO) {
/* no spec so far, try the 'sys' clock; round to the
* next MHz and see if we can get a multiple of 16MHz
*/
dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
clk_in = devm_clk_get(&ofdev->dev, "sys");
if (IS_ERR(clk_in))
goto err_notavail;
freq_calc = clk_get_rate(clk_in);
freq_calc += 499999;
freq_calc /= 1000000;
freq_calc *= 1000000;
if ((freq_calc % 16000000) == 0) {
clk_from = CLK_FROM_SYS;
clockdiv = freq_calc / 16000000;
dev_dbg(&ofdev->dev,
"clk fit, sys[%lu] div[%d] freq[%lu]\n",
freq_calc, clockdiv, freq_calc / clockdiv);
}
}
if (clk_from == CLK_FROM_AUTO) {
/* no spec so far, use the 'ref' clock */
dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
clk_in = devm_clk_get(&ofdev->dev, "ref");
if (IS_ERR(clk_in))
goto err_notavail;
clk_from = CLK_FROM_REF;
freq_calc = clk_get_rate(clk_in);
dev_dbg(&ofdev->dev,
"clk fit, ref[%lu] (no div) freq[%lu]\n",
freq_calc, freq_calc);
}
/* select IPS or MCLK as the MSCAN input (returned to the caller),
* setup the MCLK mux source and rate if applicable, apply the
* optionally specified or derived above divider, and determine
* the actual resulting clock rate to return to the caller
*/
switch (clk_from) {
case CLK_FROM_IPS:
clk_can = devm_clk_get(&ofdev->dev, "ips");
if (IS_ERR(clk_can))
goto err_notavail;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
priv->clk_can = clk_can;
freq_calc = clk_get_rate(clk_can);
*mscan_clksrc = MSCAN_CLKSRC_IPS;
dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
*mscan_clksrc, freq_calc);
break;
case CLK_FROM_SYS:
case CLK_FROM_REF:
clk_can = devm_clk_get(&ofdev->dev, "mclk");
if (IS_ERR(clk_can))
goto err_notavail;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
priv->clk_can = clk_can;
if (clk_from == CLK_FROM_SYS)
clk_in = devm_clk_get(&ofdev->dev, "sys");
if (clk_from == CLK_FROM_REF)
clk_in = devm_clk_get(&ofdev->dev, "ref");
if (IS_ERR(clk_in))
goto err_notavail;
clk_set_parent(clk_can, clk_in);
freq_calc = clk_get_rate(clk_in);
freq_calc /= clockdiv;
clk_set_rate(clk_can, freq_calc);
freq_calc = clk_get_rate(clk_can);
*mscan_clksrc = MSCAN_CLKSRC_BUS;
dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
*mscan_clksrc, freq_calc);
break;
default:
goto err_invalid;
}
/* the above clk_can item is used for the bitrate, access to
* the peripheral's register set needs the clk_ipg item
*/
clk_ipg = devm_clk_get(&ofdev->dev, "ipg");
if (IS_ERR(clk_ipg))
goto err_notavail_ipg;
if (clk_prepare_enable(clk_ipg))
goto err_notavail_ipg;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
priv->clk_ipg = clk_ipg;
/* return the determined clock source rate */
return freq_calc;
err_invalid:
dev_err(&ofdev->dev, "invalid clock source specification\n");
/* clock source rate could not get determined */
return 0;
err_notavail:
dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");
/* clock source rate could not get determined */
return 0;
err_notavail_ipg:
dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");
/* clock source rate could not get determined */
return 0;
}
static void mpc512x_can_put_clock(struct platform_device *ofdev)
{
struct mscan_priv *priv;
priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
if (priv->clk_ipg)
clk_disable_unprepare(priv->clk_ipg);
}
#else /* !CONFIG_PPC_MPC512x */
static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
const char *clock_name, int *mscan_clksrc)
{
return 0;
}
#define mpc512x_can_put_clock NULL
#endif /* CONFIG_PPC_MPC512x */
static const struct of_device_id mpc5xxx_can_table[];
static int mpc5xxx_can_probe(struct platform_device *ofdev)
{
const struct of_device_id *match;
const struct mpc5xxx_can_data *data;
struct device_node *np = ofdev->dev.of_node;
struct net_device *dev;
struct mscan_priv *priv;
void __iomem *base;
const char *clock_name = NULL;
int irq, mscan_clksrc = 0;
int err = -ENOMEM;
match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
if (!match)
return -EINVAL;
data = match->data;
base = of_iomap(np, 0);
if (!base) {
dev_err(&ofdev->dev, "couldn't ioremap\n");
return err;
}
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
dev_err(&ofdev->dev, "no irq found\n");
err = -ENODEV;
goto exit_unmap_mem;
}
dev = alloc_mscandev();
if (!dev)
goto exit_dispose_irq;
platform_set_drvdata(ofdev, dev);
SET_NETDEV_DEV(dev, &ofdev->dev);
priv = netdev_priv(dev);
priv->reg_base = base;
dev->irq = irq;
clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL);
BUG_ON(!data);
priv->type = data->type;
priv->can.clock.freq = data->get_clock(ofdev, clock_name,
&mscan_clksrc);
if (!priv->can.clock.freq) {
dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
goto exit_free_mscan;
}
err = register_mscandev(dev, mscan_clksrc);
if (err) {
dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
DRV_NAME, err);
goto exit_free_mscan;
}
dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
priv->reg_base, dev->irq, priv->can.clock.freq);
return 0;
exit_free_mscan:
free_candev(dev);
exit_dispose_irq:
irq_dispose_mapping(irq);
exit_unmap_mem:
iounmap(base);
return err;
}
static int mpc5xxx_can_remove(struct platform_device *ofdev)
{
const struct of_device_id *match;
const struct mpc5xxx_can_data *data;
struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
data = match ? match->data : NULL;
unregister_mscandev(dev);
if (data && data->put_clock)
data->put_clock(ofdev);
iounmap(priv->reg_base);
irq_dispose_mapping(dev->irq);
free_candev(dev);
return 0;
}
#ifdef CONFIG_PM
static struct mscan_regs saved_regs;
static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state)
{
struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
_memcpy_fromio(&saved_regs, regs, sizeof(*regs));
return 0;
}
static int mpc5xxx_can_resume(struct platform_device *ofdev)
{
struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
regs->canctl0 |= MSCAN_INITRQ;
while (!(regs->canctl1 & MSCAN_INITAK))
udelay(10);
regs->canctl1 = saved_regs.canctl1;
regs->canbtr0 = saved_regs.canbtr0;
regs->canbtr1 = saved_regs.canbtr1;
regs->canidac = saved_regs.canidac;
/* restore masks, buffers etc. */
_memcpy_toio(&regs->canidar1_0, (void *)&saved_regs.canidar1_0,
sizeof(*regs) - offsetof(struct mscan_regs, canidar1_0));
regs->canctl0 &= ~MSCAN_INITRQ;
regs->cantbsel = saved_regs.cantbsel;
regs->canrier = saved_regs.canrier;
regs->cantier = saved_regs.cantier;
regs->canctl0 = saved_regs.canctl0;
return 0;
}
#endif
static const struct mpc5xxx_can_data mpc5200_can_data = {
.type = MSCAN_TYPE_MPC5200,
.get_clock = mpc52xx_can_get_clock,
/* .put_clock not applicable */
};
static const struct mpc5xxx_can_data mpc5121_can_data = {
.type = MSCAN_TYPE_MPC5121,
.get_clock = mpc512x_can_get_clock,
.put_clock = mpc512x_can_put_clock,
};
static const struct of_device_id mpc5xxx_can_table[] = {
{ .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },
/* Note that only MPC5121 Rev. 2 (and later) is supported */
{ .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },
{},
};
MODULE_DEVICE_TABLE(of, mpc5xxx_can_table);
static struct platform_driver mpc5xxx_can_driver = {
.driver = {
.name = "mpc5xxx_can",
.owner = THIS_MODULE,
.of_match_table = mpc5xxx_can_table,
},
.probe = mpc5xxx_can_probe,
.remove = mpc5xxx_can_remove,
#ifdef CONFIG_PM
.suspend = mpc5xxx_can_suspend,
.resume = mpc5xxx_can_resume,
#endif
};
module_platform_driver(mpc5xxx_can_driver);
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,737 @@
/*
* CAN bus driver for the alone generic (as possible as) MSCAN controller.
*
* Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>,
* Varma Electronics Oy
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/io.h>
#include "mscan.h"
static const struct can_bittiming_const mscan_bittiming_const = {
.name = "mscan",
.tseg1_min = 4,
.tseg1_max = 16,
.tseg2_min = 2,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.brp_inc = 1,
};
struct mscan_state {
u8 mode;
u8 canrier;
u8 cantier;
};
static enum can_state state_map[] = {
CAN_STATE_ERROR_ACTIVE,
CAN_STATE_ERROR_WARNING,
CAN_STATE_ERROR_PASSIVE,
CAN_STATE_BUS_OFF
};
static int mscan_set_mode(struct net_device *dev, u8 mode)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
int ret = 0;
int i;
u8 canctl1;
if (mode != MSCAN_NORMAL_MODE) {
if (priv->tx_active) {
/* Abort transfers before going to sleep */#
out_8(&regs->cantarq, priv->tx_active);
/* Suppress TX done interrupts */
out_8(&regs->cantier, 0);
}
canctl1 = in_8(&regs->canctl1);
if ((mode & MSCAN_SLPRQ) && !(canctl1 & MSCAN_SLPAK)) {
setbits8(&regs->canctl0, MSCAN_SLPRQ);
for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
if (in_8(&regs->canctl1) & MSCAN_SLPAK)
break;
udelay(100);
}
/*
* The mscan controller will fail to enter sleep mode,
* while there are irregular activities on bus, like
* somebody keeps retransmitting. This behavior is
* undocumented and seems to differ between mscan built
* in mpc5200b and mpc5200. We proceed in that case,
* since otherwise the slprq will be kept set and the
* controller will get stuck. NOTE: INITRQ or CSWAI
* will abort all active transmit actions, if still
* any, at once.
*/
if (i >= MSCAN_SET_MODE_RETRIES)
netdev_dbg(dev,
"device failed to enter sleep mode. "
"We proceed anyhow.\n");
else
priv->can.state = CAN_STATE_SLEEPING;
}
if ((mode & MSCAN_INITRQ) && !(canctl1 & MSCAN_INITAK)) {
setbits8(&regs->canctl0, MSCAN_INITRQ);
for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
if (in_8(&regs->canctl1) & MSCAN_INITAK)
break;
}
if (i >= MSCAN_SET_MODE_RETRIES)
ret = -ENODEV;
}
if (!ret)
priv->can.state = CAN_STATE_STOPPED;
if (mode & MSCAN_CSWAI)
setbits8(&regs->canctl0, MSCAN_CSWAI);
} else {
canctl1 = in_8(&regs->canctl1);
if (canctl1 & (MSCAN_SLPAK | MSCAN_INITAK)) {
clrbits8(&regs->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ);
for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
canctl1 = in_8(&regs->canctl1);
if (!(canctl1 & (MSCAN_INITAK | MSCAN_SLPAK)))
break;
}
if (i >= MSCAN_SET_MODE_RETRIES)
ret = -ENODEV;
else
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
}
return ret;
}
static int mscan_start(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
u8 canrflg;
int err;
out_8(&regs->canrier, 0);
INIT_LIST_HEAD(&priv->tx_head);
priv->prev_buf_id = 0;
priv->cur_pri = 0;
priv->tx_active = 0;
priv->shadow_canrier = 0;
priv->flags = 0;
if (priv->type == MSCAN_TYPE_MPC5121) {
/* Clear pending bus-off condition */
if (in_8(&regs->canmisc) & MSCAN_BOHOLD)
out_8(&regs->canmisc, MSCAN_BOHOLD);
}
err = mscan_set_mode(dev, MSCAN_NORMAL_MODE);
if (err)
return err;
canrflg = in_8(&regs->canrflg);
priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
priv->can.state = state_map[max(MSCAN_STATE_RX(canrflg),
MSCAN_STATE_TX(canrflg))];
out_8(&regs->cantier, 0);
/* Enable receive interrupts. */
out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
return 0;
}
static int mscan_restart(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
if (priv->type == MSCAN_TYPE_MPC5121) {
struct mscan_regs __iomem *regs = priv->reg_base;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
"bus-off state expected\n");
out_8(&regs->canmisc, MSCAN_BOHOLD);
/* Re-enable receive interrupts. */
out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
} else {
if (priv->can.state <= CAN_STATE_BUS_OFF)
mscan_set_mode(dev, MSCAN_INIT_MODE);
return mscan_start(dev);
}
return 0;
}
static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct can_frame *frame = (struct can_frame *)skb->data;
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
int i, rtr, buf_id;
u32 can_id;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
out_8(&regs->cantier, 0);
i = ~priv->tx_active & MSCAN_TXE;
buf_id = ffs(i) - 1;
switch (hweight8(i)) {
case 0:
netif_stop_queue(dev);
netdev_err(dev, "Tx Ring full when queue awake!\n");
return NETDEV_TX_BUSY;
case 1:
/*
* if buf_id < 3, then current frame will be send out of order,
* since buffer with lower id have higher priority (hell..)
*/
netif_stop_queue(dev);
case 2:
if (buf_id < priv->prev_buf_id) {
priv->cur_pri++;
if (priv->cur_pri == 0xff) {
set_bit(F_TX_WAIT_ALL, &priv->flags);
netif_stop_queue(dev);
}
}
set_bit(F_TX_PROGRESS, &priv->flags);
break;
}
priv->prev_buf_id = buf_id;
out_8(&regs->cantbsel, i);
rtr = frame->can_id & CAN_RTR_FLAG;
/* RTR is always the lowest bit of interest, then IDs follow */
if (frame->can_id & CAN_EFF_FLAG) {
can_id = (frame->can_id & CAN_EFF_MASK)
<< (MSCAN_EFF_RTR_SHIFT + 1);
if (rtr)
can_id |= 1 << MSCAN_EFF_RTR_SHIFT;
out_be16(&regs->tx.idr3_2, can_id);
can_id >>= 16;
/* EFF_FLAGS are between the IDs :( */
can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0)
| MSCAN_EFF_FLAGS;
} else {
can_id = (frame->can_id & CAN_SFF_MASK)
<< (MSCAN_SFF_RTR_SHIFT + 1);
if (rtr)
can_id |= 1 << MSCAN_SFF_RTR_SHIFT;
}
out_be16(&regs->tx.idr1_0, can_id);
if (!rtr) {
void __iomem *data = &regs->tx.dsr1_0;
u16 *payload = (u16 *)frame->data;
for (i = 0; i < frame->can_dlc / 2; i++) {
out_be16(data, *payload++);
data += 2 + _MSCAN_RESERVED_DSR_SIZE;
}
/* write remaining byte if necessary */
if (frame->can_dlc & 1)
out_8(data, frame->data[frame->can_dlc - 1]);
}
out_8(&regs->tx.dlr, frame->can_dlc);
out_8(&regs->tx.tbpr, priv->cur_pri);
/* Start transmission. */
out_8(&regs->cantflg, 1 << buf_id);
if (!test_bit(F_TX_PROGRESS, &priv->flags))
dev->trans_start = jiffies;
list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head);
can_put_echo_skb(skb, dev, buf_id);
/* Enable interrupt. */
priv->tx_active |= 1 << buf_id;
out_8(&regs->cantier, priv->tx_active);
return NETDEV_TX_OK;
}
/* This function returns the old state to see where we came from */
static enum can_state check_set_state(struct net_device *dev, u8 canrflg)
{
struct mscan_priv *priv = netdev_priv(dev);
enum can_state state, old_state = priv->can.state;
if (canrflg & MSCAN_CSCIF && old_state <= CAN_STATE_BUS_OFF) {
state = state_map[max(MSCAN_STATE_RX(canrflg),
MSCAN_STATE_TX(canrflg))];
priv->can.state = state;
}
return old_state;
}
static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
u32 can_id;
int i;
can_id = in_be16(&regs->rx.idr1_0);
if (can_id & (1 << 3)) {
frame->can_id = CAN_EFF_FLAG;
can_id = ((can_id << 16) | in_be16(&regs->rx.idr3_2));
can_id = ((can_id & 0xffe00000) |
((can_id & 0x7ffff) << 2)) >> 2;
} else {
can_id >>= 4;
frame->can_id = 0;
}
frame->can_id |= can_id >> 1;
if (can_id & 1)
frame->can_id |= CAN_RTR_FLAG;
frame->can_dlc = get_can_dlc(in_8(&regs->rx.dlr) & 0xf);
if (!(frame->can_id & CAN_RTR_FLAG)) {
void __iomem *data = &regs->rx.dsr1_0;
u16 *payload = (u16 *)frame->data;
for (i = 0; i < frame->can_dlc / 2; i++) {
*payload++ = in_be16(data);
data += 2 + _MSCAN_RESERVED_DSR_SIZE;
}
/* read remaining byte if necessary */
if (frame->can_dlc & 1)
frame->data[frame->can_dlc - 1] = in_8(data);
}
out_8(&regs->canrflg, MSCAN_RXF);
}
static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
u8 canrflg)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
enum can_state old_state;
netdev_dbg(dev, "error interrupt (canrflg=%#x)\n", canrflg);
frame->can_id = CAN_ERR_FLAG;
if (canrflg & MSCAN_OVRIF) {
frame->can_id |= CAN_ERR_CRTL;
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
stats->rx_errors++;
} else {
frame->data[1] = 0;
}
old_state = check_set_state(dev, canrflg);
/* State changed */
if (old_state != priv->can.state) {
switch (priv->can.state) {
case CAN_STATE_ERROR_WARNING:
frame->can_id |= CAN_ERR_CRTL;
priv->can.can_stats.error_warning++;
if ((priv->shadow_statflg & MSCAN_RSTAT_MSK) <
(canrflg & MSCAN_RSTAT_MSK))
frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
if ((priv->shadow_statflg & MSCAN_TSTAT_MSK) <
(canrflg & MSCAN_TSTAT_MSK))
frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
break;
case CAN_STATE_ERROR_PASSIVE:
frame->can_id |= CAN_ERR_CRTL;
priv->can.can_stats.error_passive++;
frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
break;
case CAN_STATE_BUS_OFF:
frame->can_id |= CAN_ERR_BUSOFF;
/*
* The MSCAN on the MPC5200 does recover from bus-off
* automatically. To avoid that we stop the chip doing
* a light-weight stop (we are in irq-context).
*/
if (priv->type != MSCAN_TYPE_MPC5121) {
out_8(&regs->cantier, 0);
out_8(&regs->canrier, 0);
setbits8(&regs->canctl0,
MSCAN_SLPRQ | MSCAN_INITRQ);
}
can_bus_off(dev);
break;
default:
break;
}
}
priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
frame->can_dlc = CAN_ERR_DLC;
out_8(&regs->canrflg, MSCAN_ERR_IF);
}
static int mscan_rx_poll(struct napi_struct *napi, int quota)
{
struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi);
struct net_device *dev = napi->dev;
struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
int npackets = 0;
int ret = 1;
struct sk_buff *skb;
struct can_frame *frame;
u8 canrflg;
while (npackets < quota) {
canrflg = in_8(&regs->canrflg);
if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF)))
break;
skb = alloc_can_skb(dev, &frame);
if (!skb) {
if (printk_ratelimit())
netdev_notice(dev, "packet dropped\n");
stats->rx_dropped++;
out_8(&regs->canrflg, canrflg);
continue;
}
if (canrflg & MSCAN_RXF)
mscan_get_rx_frame(dev, frame);
else if (canrflg & MSCAN_ERR_IF)
mscan_get_err_frame(dev, frame, canrflg);
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
npackets++;
netif_receive_skb(skb);
}
if (!(in_8(&regs->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) {
napi_complete(&priv->napi);
clear_bit(F_RX_PROGRESS, &priv->flags);
if (priv->can.state < CAN_STATE_BUS_OFF)
out_8(&regs->canrier, priv->shadow_canrier);
ret = 0;
}
return ret;
}
static irqreturn_t mscan_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
u8 cantier, cantflg, canrflg;
irqreturn_t ret = IRQ_NONE;
cantier = in_8(&regs->cantier) & MSCAN_TXE;
cantflg = in_8(&regs->cantflg) & cantier;
if (cantier && cantflg) {
struct list_head *tmp, *pos;
list_for_each_safe(pos, tmp, &priv->tx_head) {
struct tx_queue_entry *entry =
list_entry(pos, struct tx_queue_entry, list);
u8 mask = entry->mask;
if (!(cantflg & mask))
continue;
out_8(&regs->cantbsel, mask);
stats->tx_bytes += in_8(&regs->tx.dlr);
stats->tx_packets++;
can_get_echo_skb(dev, entry->id);
priv->tx_active &= ~mask;
list_del(pos);
}
if (list_empty(&priv->tx_head)) {
clear_bit(F_TX_WAIT_ALL, &priv->flags);
clear_bit(F_TX_PROGRESS, &priv->flags);
priv->cur_pri = 0;
} else {
dev->trans_start = jiffies;
}
if (!test_bit(F_TX_WAIT_ALL, &priv->flags))
netif_wake_queue(dev);
out_8(&regs->cantier, priv->tx_active);
ret = IRQ_HANDLED;
}
canrflg = in_8(&regs->canrflg);
if ((canrflg & ~MSCAN_STAT_MSK) &&
!test_and_set_bit(F_RX_PROGRESS, &priv->flags)) {
if (canrflg & ~MSCAN_STAT_MSK) {
priv->shadow_canrier = in_8(&regs->canrier);
out_8(&regs->canrier, 0);
napi_schedule(&priv->napi);
ret = IRQ_HANDLED;
} else {
clear_bit(F_RX_PROGRESS, &priv->flags);
}
}
return ret;
}
static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
{
int ret = 0;
switch (mode) {
case CAN_MODE_START:
ret = mscan_restart(dev);
if (ret)
break;
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static int mscan_do_set_bittiming(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
struct can_bittiming *bt = &priv->can.bittiming;
u8 btr0, btr1;
btr0 = BTR0_SET_BRP(bt->brp) | BTR0_SET_SJW(bt->sjw);
btr1 = (BTR1_SET_TSEG1(bt->prop_seg + bt->phase_seg1) |
BTR1_SET_TSEG2(bt->phase_seg2) |
BTR1_SET_SAM(priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES));
netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
out_8(&regs->canbtr0, btr0);
out_8(&regs->canbtr1, btr1);
return 0;
}
static int mscan_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
bec->txerr = in_8(&regs->cantxerr);
bec->rxerr = in_8(&regs->canrxerr);
return 0;
}
static int mscan_open(struct net_device *dev)
{
int ret;
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
if (priv->clk_ipg) {
ret = clk_prepare_enable(priv->clk_ipg);
if (ret)
goto exit_retcode;
}
if (priv->clk_can) {
ret = clk_prepare_enable(priv->clk_can);
if (ret)
goto exit_dis_ipg_clock;
}
/* common open */
ret = open_candev(dev);
if (ret)
goto exit_dis_can_clock;
napi_enable(&priv->napi);
ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);
if (ret < 0) {
netdev_err(dev, "failed to attach interrupt\n");
goto exit_napi_disable;
}
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
setbits8(&regs->canctl1, MSCAN_LISTEN);
else
clrbits8(&regs->canctl1, MSCAN_LISTEN);
ret = mscan_start(dev);
if (ret)
goto exit_free_irq;
netif_start_queue(dev);
return 0;
exit_free_irq:
free_irq(dev->irq, dev);
exit_napi_disable:
napi_disable(&priv->napi);
close_candev(dev);
exit_dis_can_clock:
if (priv->clk_can)
clk_disable_unprepare(priv->clk_can);
exit_dis_ipg_clock:
if (priv->clk_ipg)
clk_disable_unprepare(priv->clk_ipg);
exit_retcode:
return ret;
}
static int mscan_close(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
netif_stop_queue(dev);
napi_disable(&priv->napi);
out_8(&regs->cantier, 0);
out_8(&regs->canrier, 0);
mscan_set_mode(dev, MSCAN_INIT_MODE);
close_candev(dev);
free_irq(dev->irq, dev);
if (priv->clk_can)
clk_disable_unprepare(priv->clk_can);
if (priv->clk_ipg)
clk_disable_unprepare(priv->clk_ipg);
return 0;
}
static const struct net_device_ops mscan_netdev_ops = {
.ndo_open = mscan_open,
.ndo_stop = mscan_close,
.ndo_start_xmit = mscan_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
int register_mscandev(struct net_device *dev, int mscan_clksrc)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
u8 ctl1;
ctl1 = in_8(&regs->canctl1);
if (mscan_clksrc)
ctl1 |= MSCAN_CLKSRC;
else
ctl1 &= ~MSCAN_CLKSRC;
if (priv->type == MSCAN_TYPE_MPC5121) {
priv->can.do_get_berr_counter = mscan_get_berr_counter;
ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */
}
ctl1 |= MSCAN_CANE;
out_8(&regs->canctl1, ctl1);
udelay(100);
/* acceptance mask/acceptance code (accept everything) */
out_be16(&regs->canidar1_0, 0);
out_be16(&regs->canidar3_2, 0);
out_be16(&regs->canidar5_4, 0);
out_be16(&regs->canidar7_6, 0);
out_be16(&regs->canidmr1_0, 0xffff);
out_be16(&regs->canidmr3_2, 0xffff);
out_be16(&regs->canidmr5_4, 0xffff);
out_be16(&regs->canidmr7_6, 0xffff);
/* Two 32 bit Acceptance Filters */
out_8(&regs->canidac, MSCAN_AF_32BIT);
mscan_set_mode(dev, MSCAN_INIT_MODE);
return register_candev(dev);
}
void unregister_mscandev(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs __iomem *regs = priv->reg_base;
mscan_set_mode(dev, MSCAN_INIT_MODE);
clrbits8(&regs->canctl1, MSCAN_CANE);
unregister_candev(dev);
}
struct net_device *alloc_mscandev(void)
{
struct net_device *dev;
struct mscan_priv *priv;
int i;
dev = alloc_candev(sizeof(struct mscan_priv), MSCAN_ECHO_SKB_MAX);
if (!dev)
return NULL;
priv = netdev_priv(dev);
dev->netdev_ops = &mscan_netdev_ops;
dev->flags |= IFF_ECHO; /* we support local echo */
netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8);
priv->can.bittiming_const = &mscan_bittiming_const;
priv->can.do_set_bittiming = mscan_do_set_bittiming;
priv->can.do_set_mode = mscan_do_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LISTENONLY;
for (i = 0; i < TX_QUEUE_SIZE; i++) {
priv->tx_queue[i].id = i;
priv->tx_queue[i].mask = 1 << i;
}
return dev;
}
MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CAN port driver for a MSCAN based chips");

View file

@ -0,0 +1,303 @@
/*
* Definitions of consts/structs to drive the Freescale MSCAN.
*
* Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>,
* Varma Electronics Oy
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MSCAN_H__
#define __MSCAN_H__
#include <linux/clk.h>
#include <linux/types.h>
/* MSCAN control register 0 (CANCTL0) bits */
#define MSCAN_RXFRM 0x80
#define MSCAN_RXACT 0x40
#define MSCAN_CSWAI 0x20
#define MSCAN_SYNCH 0x10
#define MSCAN_TIME 0x08
#define MSCAN_WUPE 0x04
#define MSCAN_SLPRQ 0x02
#define MSCAN_INITRQ 0x01
/* MSCAN control register 1 (CANCTL1) bits */
#define MSCAN_CANE 0x80
#define MSCAN_CLKSRC 0x40
#define MSCAN_LOOPB 0x20
#define MSCAN_LISTEN 0x10
#define MSCAN_BORM 0x08
#define MSCAN_WUPM 0x04
#define MSCAN_SLPAK 0x02
#define MSCAN_INITAK 0x01
/* Use the MPC5XXX MSCAN variant? */
#ifdef CONFIG_PPC
#define MSCAN_FOR_MPC5XXX
#endif
#ifdef MSCAN_FOR_MPC5XXX
#define MSCAN_CLKSRC_BUS 0
#define MSCAN_CLKSRC_XTAL MSCAN_CLKSRC
#define MSCAN_CLKSRC_IPS MSCAN_CLKSRC
#else
#define MSCAN_CLKSRC_BUS MSCAN_CLKSRC
#define MSCAN_CLKSRC_XTAL 0
#endif
/* MSCAN receiver flag register (CANRFLG) bits */
#define MSCAN_WUPIF 0x80
#define MSCAN_CSCIF 0x40
#define MSCAN_RSTAT1 0x20
#define MSCAN_RSTAT0 0x10
#define MSCAN_TSTAT1 0x08
#define MSCAN_TSTAT0 0x04
#define MSCAN_OVRIF 0x02
#define MSCAN_RXF 0x01
#define MSCAN_ERR_IF (MSCAN_OVRIF | MSCAN_CSCIF)
#define MSCAN_RSTAT_MSK (MSCAN_RSTAT1 | MSCAN_RSTAT0)
#define MSCAN_TSTAT_MSK (MSCAN_TSTAT1 | MSCAN_TSTAT0)
#define MSCAN_STAT_MSK (MSCAN_RSTAT_MSK | MSCAN_TSTAT_MSK)
#define MSCAN_STATE_BUS_OFF (MSCAN_RSTAT1 | MSCAN_RSTAT0 | \
MSCAN_TSTAT1 | MSCAN_TSTAT0)
#define MSCAN_STATE_TX(canrflg) (((canrflg)&MSCAN_TSTAT_MSK)>>2)
#define MSCAN_STATE_RX(canrflg) (((canrflg)&MSCAN_RSTAT_MSK)>>4)
#define MSCAN_STATE_ACTIVE 0
#define MSCAN_STATE_WARNING 1
#define MSCAN_STATE_PASSIVE 2
#define MSCAN_STATE_BUSOFF 3
/* MSCAN receiver interrupt enable register (CANRIER) bits */
#define MSCAN_WUPIE 0x80
#define MSCAN_CSCIE 0x40
#define MSCAN_RSTATE1 0x20
#define MSCAN_RSTATE0 0x10
#define MSCAN_TSTATE1 0x08
#define MSCAN_TSTATE0 0x04
#define MSCAN_OVRIE 0x02
#define MSCAN_RXFIE 0x01
/* MSCAN transmitter flag register (CANTFLG) bits */
#define MSCAN_TXE2 0x04
#define MSCAN_TXE1 0x02
#define MSCAN_TXE0 0x01
#define MSCAN_TXE (MSCAN_TXE2 | MSCAN_TXE1 | MSCAN_TXE0)
/* MSCAN transmitter interrupt enable register (CANTIER) bits */
#define MSCAN_TXIE2 0x04
#define MSCAN_TXIE1 0x02
#define MSCAN_TXIE0 0x01
#define MSCAN_TXIE (MSCAN_TXIE2 | MSCAN_TXIE1 | MSCAN_TXIE0)
/* MSCAN transmitter message abort request (CANTARQ) bits */
#define MSCAN_ABTRQ2 0x04
#define MSCAN_ABTRQ1 0x02
#define MSCAN_ABTRQ0 0x01
/* MSCAN transmitter message abort ack (CANTAAK) bits */
#define MSCAN_ABTAK2 0x04
#define MSCAN_ABTAK1 0x02
#define MSCAN_ABTAK0 0x01
/* MSCAN transmit buffer selection (CANTBSEL) bits */
#define MSCAN_TX2 0x04
#define MSCAN_TX1 0x02
#define MSCAN_TX0 0x01
/* MSCAN ID acceptance control register (CANIDAC) bits */
#define MSCAN_IDAM1 0x20
#define MSCAN_IDAM0 0x10
#define MSCAN_IDHIT2 0x04
#define MSCAN_IDHIT1 0x02
#define MSCAN_IDHIT0 0x01
#define MSCAN_AF_32BIT 0x00
#define MSCAN_AF_16BIT MSCAN_IDAM0
#define MSCAN_AF_8BIT MSCAN_IDAM1
#define MSCAN_AF_CLOSED (MSCAN_IDAM0|MSCAN_IDAM1)
#define MSCAN_AF_MASK (~(MSCAN_IDAM0|MSCAN_IDAM1))
/* MSCAN Miscellaneous Register (CANMISC) bits */
#define MSCAN_BOHOLD 0x01
/* MSCAN Identifier Register (IDR) bits */
#define MSCAN_SFF_RTR_SHIFT 4
#define MSCAN_EFF_RTR_SHIFT 0
#define MSCAN_EFF_FLAGS 0x18 /* IDE + SRR */
#ifdef MSCAN_FOR_MPC5XXX
#define _MSCAN_RESERVED_(n, num) u8 _res##n[num]
#define _MSCAN_RESERVED_DSR_SIZE 2
#else
#define _MSCAN_RESERVED_(n, num)
#define _MSCAN_RESERVED_DSR_SIZE 0
#endif
/* Structure of the hardware registers */
struct mscan_regs {
/* (see doc S12MSCANV3/D) MPC5200 MSCAN */
u8 canctl0; /* + 0x00 0x00 */
u8 canctl1; /* + 0x01 0x01 */
_MSCAN_RESERVED_(1, 2); /* + 0x02 */
u8 canbtr0; /* + 0x04 0x02 */
u8 canbtr1; /* + 0x05 0x03 */
_MSCAN_RESERVED_(2, 2); /* + 0x06 */
u8 canrflg; /* + 0x08 0x04 */
u8 canrier; /* + 0x09 0x05 */
_MSCAN_RESERVED_(3, 2); /* + 0x0a */
u8 cantflg; /* + 0x0c 0x06 */
u8 cantier; /* + 0x0d 0x07 */
_MSCAN_RESERVED_(4, 2); /* + 0x0e */
u8 cantarq; /* + 0x10 0x08 */
u8 cantaak; /* + 0x11 0x09 */
_MSCAN_RESERVED_(5, 2); /* + 0x12 */
u8 cantbsel; /* + 0x14 0x0a */
u8 canidac; /* + 0x15 0x0b */
u8 reserved; /* + 0x16 0x0c */
_MSCAN_RESERVED_(6, 2); /* + 0x17 */
u8 canmisc; /* + 0x19 0x0d */
_MSCAN_RESERVED_(7, 2); /* + 0x1a */
u8 canrxerr; /* + 0x1c 0x0e */
u8 cantxerr; /* + 0x1d 0x0f */
_MSCAN_RESERVED_(8, 2); /* + 0x1e */
u16 canidar1_0; /* + 0x20 0x10 */
_MSCAN_RESERVED_(9, 2); /* + 0x22 */
u16 canidar3_2; /* + 0x24 0x12 */
_MSCAN_RESERVED_(10, 2); /* + 0x26 */
u16 canidmr1_0; /* + 0x28 0x14 */
_MSCAN_RESERVED_(11, 2); /* + 0x2a */
u16 canidmr3_2; /* + 0x2c 0x16 */
_MSCAN_RESERVED_(12, 2); /* + 0x2e */
u16 canidar5_4; /* + 0x30 0x18 */
_MSCAN_RESERVED_(13, 2); /* + 0x32 */
u16 canidar7_6; /* + 0x34 0x1a */
_MSCAN_RESERVED_(14, 2); /* + 0x36 */
u16 canidmr5_4; /* + 0x38 0x1c */
_MSCAN_RESERVED_(15, 2); /* + 0x3a */
u16 canidmr7_6; /* + 0x3c 0x1e */
_MSCAN_RESERVED_(16, 2); /* + 0x3e */
struct {
u16 idr1_0; /* + 0x40 0x20 */
_MSCAN_RESERVED_(17, 2); /* + 0x42 */
u16 idr3_2; /* + 0x44 0x22 */
_MSCAN_RESERVED_(18, 2); /* + 0x46 */
u16 dsr1_0; /* + 0x48 0x24 */
_MSCAN_RESERVED_(19, 2); /* + 0x4a */
u16 dsr3_2; /* + 0x4c 0x26 */
_MSCAN_RESERVED_(20, 2); /* + 0x4e */
u16 dsr5_4; /* + 0x50 0x28 */
_MSCAN_RESERVED_(21, 2); /* + 0x52 */
u16 dsr7_6; /* + 0x54 0x2a */
_MSCAN_RESERVED_(22, 2); /* + 0x56 */
u8 dlr; /* + 0x58 0x2c */
u8 reserved; /* + 0x59 0x2d */
_MSCAN_RESERVED_(23, 2); /* + 0x5a */
u16 time; /* + 0x5c 0x2e */
} rx;
_MSCAN_RESERVED_(24, 2); /* + 0x5e */
struct {
u16 idr1_0; /* + 0x60 0x30 */
_MSCAN_RESERVED_(25, 2); /* + 0x62 */
u16 idr3_2; /* + 0x64 0x32 */
_MSCAN_RESERVED_(26, 2); /* + 0x66 */
u16 dsr1_0; /* + 0x68 0x34 */
_MSCAN_RESERVED_(27, 2); /* + 0x6a */
u16 dsr3_2; /* + 0x6c 0x36 */
_MSCAN_RESERVED_(28, 2); /* + 0x6e */
u16 dsr5_4; /* + 0x70 0x38 */
_MSCAN_RESERVED_(29, 2); /* + 0x72 */
u16 dsr7_6; /* + 0x74 0x3a */
_MSCAN_RESERVED_(30, 2); /* + 0x76 */
u8 dlr; /* + 0x78 0x3c */
u8 tbpr; /* + 0x79 0x3d */
_MSCAN_RESERVED_(31, 2); /* + 0x7a */
u16 time; /* + 0x7c 0x3e */
} tx;
_MSCAN_RESERVED_(32, 2); /* + 0x7e */
} __packed;
#undef _MSCAN_RESERVED_
#define MSCAN_REGION sizeof(struct mscan)
#define MSCAN_NORMAL_MODE 0
#define MSCAN_SLEEP_MODE MSCAN_SLPRQ
#define MSCAN_INIT_MODE (MSCAN_INITRQ | MSCAN_SLPRQ)
#define MSCAN_POWEROFF_MODE (MSCAN_CSWAI | MSCAN_SLPRQ)
#define MSCAN_SET_MODE_RETRIES 255
#define MSCAN_ECHO_SKB_MAX 3
#define MSCAN_RX_INTS_ENABLE (MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE | \
MSCAN_RSTATE1 | MSCAN_RSTATE0 | \
MSCAN_TSTATE1 | MSCAN_TSTATE0)
/* MSCAN type variants */
enum {
MSCAN_TYPE_MPC5200,
MSCAN_TYPE_MPC5121
};
#define BTR0_BRP_MASK 0x3f
#define BTR0_SJW_SHIFT 6
#define BTR0_SJW_MASK (0x3 << BTR0_SJW_SHIFT)
#define BTR1_TSEG1_MASK 0xf
#define BTR1_TSEG2_SHIFT 4
#define BTR1_TSEG2_MASK (0x7 << BTR1_TSEG2_SHIFT)
#define BTR1_SAM_SHIFT 7
#define BTR0_SET_BRP(brp) (((brp) - 1) & BTR0_BRP_MASK)
#define BTR0_SET_SJW(sjw) ((((sjw) - 1) << BTR0_SJW_SHIFT) & \
BTR0_SJW_MASK)
#define BTR1_SET_TSEG1(tseg1) (((tseg1) - 1) & BTR1_TSEG1_MASK)
#define BTR1_SET_TSEG2(tseg2) ((((tseg2) - 1) << BTR1_TSEG2_SHIFT) & \
BTR1_TSEG2_MASK)
#define BTR1_SET_SAM(sam) ((sam) ? 1 << BTR1_SAM_SHIFT : 0)
#define F_RX_PROGRESS 0
#define F_TX_PROGRESS 1
#define F_TX_WAIT_ALL 2
#define TX_QUEUE_SIZE 3
struct tx_queue_entry {
struct list_head list;
u8 mask;
u8 id;
};
struct mscan_priv {
struct can_priv can; /* must be the first member */
unsigned int type; /* MSCAN type variants */
unsigned long flags;
void __iomem *reg_base; /* ioremap'ed address to registers */
struct clk *clk_ipg; /* clock for registers */
struct clk *clk_can; /* clock for bitrates */
u8 shadow_statflg;
u8 shadow_canrier;
u8 cur_pri;
u8 prev_buf_id;
u8 tx_active;
struct list_head tx_head;
struct tx_queue_entry tx_queue[TX_QUEUE_SIZE];
struct napi_struct napi;
};
struct net_device *alloc_mscandev(void);
int register_mscandev(struct net_device *dev, int mscan_clksrc);
void unregister_mscandev(struct net_device *dev);
#endif /* __MSCAN_H__ */

1279
drivers/net/can/pch_can.c Normal file

File diff suppressed because it is too large Load diff

923
drivers/net/can/rcar_can.c Normal file
View file

@ -0,0 +1,923 @@
/* Renesas R-Car CAN device driver
*
* Copyright (C) 2013 Cogent Embedded, Inc. <source@cogentembedded.com>
* Copyright (C) 2013 Renesas Solutions Corp.
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/can/led.h>
#include <linux/can/dev.h>
#include <linux/clk.h>
#include <linux/can/platform/rcar_can.h>
#include <linux/of.h>
#define RCAR_CAN_DRV_NAME "rcar_can"
/* Mailbox configuration:
* mailbox 60 - 63 - Rx FIFO mailboxes
* mailbox 56 - 59 - Tx FIFO mailboxes
* non-FIFO mailboxes are not used
*/
#define RCAR_CAN_N_MBX 64 /* Number of mailboxes in non-FIFO mode */
#define RCAR_CAN_RX_FIFO_MBX 60 /* Mailbox - window to Rx FIFO */
#define RCAR_CAN_TX_FIFO_MBX 56 /* Mailbox - window to Tx FIFO */
#define RCAR_CAN_FIFO_DEPTH 4
/* Mailbox registers structure */
struct rcar_can_mbox_regs {
u32 id; /* IDE and RTR bits, SID and EID */
u8 stub; /* Not used */
u8 dlc; /* Data Length Code - bits [0..3] */
u8 data[8]; /* Data Bytes */
u8 tsh; /* Time Stamp Higher Byte */
u8 tsl; /* Time Stamp Lower Byte */
};
struct rcar_can_regs {
struct rcar_can_mbox_regs mb[RCAR_CAN_N_MBX]; /* Mailbox registers */
u32 mkr_2_9[8]; /* Mask Registers 2-9 */
u32 fidcr[2]; /* FIFO Received ID Compare Register */
u32 mkivlr1; /* Mask Invalid Register 1 */
u32 mier1; /* Mailbox Interrupt Enable Register 1 */
u32 mkr_0_1[2]; /* Mask Registers 0-1 */
u32 mkivlr0; /* Mask Invalid Register 0*/
u32 mier0; /* Mailbox Interrupt Enable Register 0 */
u8 pad_440[0x3c0];
u8 mctl[64]; /* Message Control Registers */
u16 ctlr; /* Control Register */
u16 str; /* Status register */
u8 bcr[3]; /* Bit Configuration Register */
u8 clkr; /* Clock Select Register */
u8 rfcr; /* Receive FIFO Control Register */
u8 rfpcr; /* Receive FIFO Pointer Control Register */
u8 tfcr; /* Transmit FIFO Control Register */
u8 tfpcr; /* Transmit FIFO Pointer Control Register */
u8 eier; /* Error Interrupt Enable Register */
u8 eifr; /* Error Interrupt Factor Judge Register */
u8 recr; /* Receive Error Count Register */
u8 tecr; /* Transmit Error Count Register */
u8 ecsr; /* Error Code Store Register */
u8 cssr; /* Channel Search Support Register */
u8 mssr; /* Mailbox Search Status Register */
u8 msmr; /* Mailbox Search Mode Register */
u16 tsr; /* Time Stamp Register */
u8 afsr; /* Acceptance Filter Support Register */
u8 pad_857;
u8 tcr; /* Test Control Register */
u8 pad_859[7];
u8 ier; /* Interrupt Enable Register */
u8 isr; /* Interrupt Status Register */
u8 pad_862;
u8 mbsmr; /* Mailbox Search Mask Register */
};
struct rcar_can_priv {
struct can_priv can; /* Must be the first member! */
struct net_device *ndev;
struct napi_struct napi;
struct rcar_can_regs __iomem *regs;
struct clk *clk;
struct clk *can_clk;
u8 tx_dlc[RCAR_CAN_FIFO_DEPTH];
u32 tx_head;
u32 tx_tail;
u8 clock_select;
u8 ier;
};
static const struct can_bittiming_const rcar_can_bittiming_const = {
.name = RCAR_CAN_DRV_NAME,
.tseg1_min = 4,
.tseg1_max = 16,
.tseg2_min = 2,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 1024,
.brp_inc = 1,
};
/* Control Register bits */
#define RCAR_CAN_CTLR_BOM (3 << 11) /* Bus-Off Recovery Mode Bits */
#define RCAR_CAN_CTLR_BOM_ENT (1 << 11) /* Entry to halt mode */
/* at bus-off entry */
#define RCAR_CAN_CTLR_SLPM (1 << 10)
#define RCAR_CAN_CTLR_CANM (3 << 8) /* Operating Mode Select Bit */
#define RCAR_CAN_CTLR_CANM_HALT (1 << 9)
#define RCAR_CAN_CTLR_CANM_RESET (1 << 8)
#define RCAR_CAN_CTLR_CANM_FORCE_RESET (3 << 8)
#define RCAR_CAN_CTLR_MLM (1 << 3) /* Message Lost Mode Select */
#define RCAR_CAN_CTLR_IDFM (3 << 1) /* ID Format Mode Select Bits */
#define RCAR_CAN_CTLR_IDFM_MIXED (1 << 2) /* Mixed ID mode */
#define RCAR_CAN_CTLR_MBM (1 << 0) /* Mailbox Mode select */
/* Status Register bits */
#define RCAR_CAN_STR_RSTST (1 << 8) /* Reset Status Bit */
/* FIFO Received ID Compare Registers 0 and 1 bits */
#define RCAR_CAN_FIDCR_IDE (1 << 31) /* ID Extension Bit */
#define RCAR_CAN_FIDCR_RTR (1 << 30) /* Remote Transmission Request Bit */
/* Receive FIFO Control Register bits */
#define RCAR_CAN_RFCR_RFEST (1 << 7) /* Receive FIFO Empty Status Flag */
#define RCAR_CAN_RFCR_RFE (1 << 0) /* Receive FIFO Enable */
/* Transmit FIFO Control Register bits */
#define RCAR_CAN_TFCR_TFUST (7 << 1) /* Transmit FIFO Unsent Message */
/* Number Status Bits */
#define RCAR_CAN_TFCR_TFUST_SHIFT 1 /* Offset of Transmit FIFO Unsent */
/* Message Number Status Bits */
#define RCAR_CAN_TFCR_TFE (1 << 0) /* Transmit FIFO Enable */
#define RCAR_CAN_N_RX_MKREGS1 2 /* Number of mask registers */
/* for Rx mailboxes 0-31 */
#define RCAR_CAN_N_RX_MKREGS2 8
/* Bit Configuration Register settings */
#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20)
#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8)
#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4)
#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07)
/* Mailbox and Mask Registers bits */
#define RCAR_CAN_IDE (1 << 31)
#define RCAR_CAN_RTR (1 << 30)
#define RCAR_CAN_SID_SHIFT 18
/* Mailbox Interrupt Enable Register 1 bits */
#define RCAR_CAN_MIER1_RXFIE (1 << 28) /* Receive FIFO Interrupt Enable */
#define RCAR_CAN_MIER1_TXFIE (1 << 24) /* Transmit FIFO Interrupt Enable */
/* Interrupt Enable Register bits */
#define RCAR_CAN_IER_ERSIE (1 << 5) /* Error (ERS) Interrupt Enable Bit */
#define RCAR_CAN_IER_RXFIE (1 << 4) /* Reception FIFO Interrupt */
/* Enable Bit */
#define RCAR_CAN_IER_TXFIE (1 << 3) /* Transmission FIFO Interrupt */
/* Enable Bit */
/* Interrupt Status Register bits */
#define RCAR_CAN_ISR_ERSF (1 << 5) /* Error (ERS) Interrupt Status Bit */
#define RCAR_CAN_ISR_RXFF (1 << 4) /* Reception FIFO Interrupt */
/* Status Bit */
#define RCAR_CAN_ISR_TXFF (1 << 3) /* Transmission FIFO Interrupt */
/* Status Bit */
/* Error Interrupt Enable Register bits */
#define RCAR_CAN_EIER_BLIE (1 << 7) /* Bus Lock Interrupt Enable */
#define RCAR_CAN_EIER_OLIE (1 << 6) /* Overload Frame Transmit */
/* Interrupt Enable */
#define RCAR_CAN_EIER_ORIE (1 << 5) /* Receive Overrun Interrupt Enable */
#define RCAR_CAN_EIER_BORIE (1 << 4) /* Bus-Off Recovery Interrupt Enable */
#define RCAR_CAN_EIER_BOEIE (1 << 3) /* Bus-Off Entry Interrupt Enable */
#define RCAR_CAN_EIER_EPIE (1 << 2) /* Error Passive Interrupt Enable */
#define RCAR_CAN_EIER_EWIE (1 << 1) /* Error Warning Interrupt Enable */
#define RCAR_CAN_EIER_BEIE (1 << 0) /* Bus Error Interrupt Enable */
/* Error Interrupt Factor Judge Register bits */
#define RCAR_CAN_EIFR_BLIF (1 << 7) /* Bus Lock Detect Flag */
#define RCAR_CAN_EIFR_OLIF (1 << 6) /* Overload Frame Transmission */
/* Detect Flag */
#define RCAR_CAN_EIFR_ORIF (1 << 5) /* Receive Overrun Detect Flag */
#define RCAR_CAN_EIFR_BORIF (1 << 4) /* Bus-Off Recovery Detect Flag */
#define RCAR_CAN_EIFR_BOEIF (1 << 3) /* Bus-Off Entry Detect Flag */
#define RCAR_CAN_EIFR_EPIF (1 << 2) /* Error Passive Detect Flag */
#define RCAR_CAN_EIFR_EWIF (1 << 1) /* Error Warning Detect Flag */
#define RCAR_CAN_EIFR_BEIF (1 << 0) /* Bus Error Detect Flag */
/* Error Code Store Register bits */
#define RCAR_CAN_ECSR_EDPM (1 << 7) /* Error Display Mode Select Bit */
#define RCAR_CAN_ECSR_ADEF (1 << 6) /* ACK Delimiter Error Flag */
#define RCAR_CAN_ECSR_BE0F (1 << 5) /* Bit Error (dominant) Flag */
#define RCAR_CAN_ECSR_BE1F (1 << 4) /* Bit Error (recessive) Flag */
#define RCAR_CAN_ECSR_CEF (1 << 3) /* CRC Error Flag */
#define RCAR_CAN_ECSR_AEF (1 << 2) /* ACK Error Flag */
#define RCAR_CAN_ECSR_FEF (1 << 1) /* Form Error Flag */
#define RCAR_CAN_ECSR_SEF (1 << 0) /* Stuff Error Flag */
#define RCAR_CAN_NAPI_WEIGHT 4
#define MAX_STR_READS 0x100
static void tx_failure_cleanup(struct net_device *ndev)
{
int i;
for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++)
can_free_echo_skb(ndev, i);
}
static void rcar_can_error(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u8 eifr, txerr = 0, rxerr = 0;
/* Propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(ndev, &cf);
eifr = readb(&priv->regs->eifr);
if (eifr & (RCAR_CAN_EIFR_EWIF | RCAR_CAN_EIFR_EPIF)) {
txerr = readb(&priv->regs->tecr);
rxerr = readb(&priv->regs->recr);
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
}
if (eifr & RCAR_CAN_EIFR_BEIF) {
int rx_errors = 0, tx_errors = 0;
u8 ecsr;
netdev_dbg(priv->ndev, "Bus error interrupt:\n");
if (skb) {
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_UNSPEC;
}
ecsr = readb(&priv->regs->ecsr);
if (ecsr & RCAR_CAN_ECSR_ADEF) {
netdev_dbg(priv->ndev, "ACK Delimiter Error\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr);
if (skb)
cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL;
}
if (ecsr & RCAR_CAN_ECSR_BE0F) {
netdev_dbg(priv->ndev, "Bit Error (dominant)\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_BE0F, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_BIT0;
}
if (ecsr & RCAR_CAN_ECSR_BE1F) {
netdev_dbg(priv->ndev, "Bit Error (recessive)\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_BE1F, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_BIT1;
}
if (ecsr & RCAR_CAN_ECSR_CEF) {
netdev_dbg(priv->ndev, "CRC Error\n");
rx_errors++;
writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr);
if (skb)
cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
}
if (ecsr & RCAR_CAN_ECSR_AEF) {
netdev_dbg(priv->ndev, "ACK Error\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr);
if (skb) {
cf->can_id |= CAN_ERR_ACK;
cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
}
}
if (ecsr & RCAR_CAN_ECSR_FEF) {
netdev_dbg(priv->ndev, "Form Error\n");
rx_errors++;
writeb(~RCAR_CAN_ECSR_FEF, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_FORM;
}
if (ecsr & RCAR_CAN_ECSR_SEF) {
netdev_dbg(priv->ndev, "Stuff Error\n");
rx_errors++;
writeb(~RCAR_CAN_ECSR_SEF, &priv->regs->ecsr);
if (skb)
cf->data[2] |= CAN_ERR_PROT_STUFF;
}
priv->can.can_stats.bus_error++;
ndev->stats.rx_errors += rx_errors;
ndev->stats.tx_errors += tx_errors;
writeb(~RCAR_CAN_EIFR_BEIF, &priv->regs->eifr);
}
if (eifr & RCAR_CAN_EIFR_EWIF) {
netdev_dbg(priv->ndev, "Error warning interrupt\n");
priv->can.state = CAN_STATE_ERROR_WARNING;
priv->can.can_stats.error_warning++;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_EWIF, &priv->regs->eifr);
if (skb)
cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
}
if (eifr & RCAR_CAN_EIFR_EPIF) {
netdev_dbg(priv->ndev, "Error passive interrupt\n");
priv->can.state = CAN_STATE_ERROR_PASSIVE;
priv->can.can_stats.error_passive++;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_EPIF, &priv->regs->eifr);
if (skb)
cf->data[1] = txerr > rxerr ? CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
}
if (eifr & RCAR_CAN_EIFR_BOEIF) {
netdev_dbg(priv->ndev, "Bus-off entry interrupt\n");
tx_failure_cleanup(ndev);
priv->ier = RCAR_CAN_IER_ERSIE;
writeb(priv->ier, &priv->regs->ier);
priv->can.state = CAN_STATE_BUS_OFF;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr);
can_bus_off(ndev);
if (skb)
cf->can_id |= CAN_ERR_BUSOFF;
}
if (eifr & RCAR_CAN_EIFR_ORIF) {
netdev_dbg(priv->ndev, "Receive overrun error interrupt\n");
ndev->stats.rx_over_errors++;
ndev->stats.rx_errors++;
writeb(~RCAR_CAN_EIFR_ORIF, &priv->regs->eifr);
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
}
}
if (eifr & RCAR_CAN_EIFR_OLIF) {
netdev_dbg(priv->ndev,
"Overload Frame Transmission error interrupt\n");
ndev->stats.rx_over_errors++;
ndev->stats.rx_errors++;
writeb(~RCAR_CAN_EIFR_OLIF, &priv->regs->eifr);
if (skb) {
cf->can_id |= CAN_ERR_PROT;
cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
}
}
if (skb) {
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
}
}
static void rcar_can_tx_done(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
u8 isr;
while (1) {
u8 unsent = readb(&priv->regs->tfcr);
unsent = (unsent & RCAR_CAN_TFCR_TFUST) >>
RCAR_CAN_TFCR_TFUST_SHIFT;
if (priv->tx_head - priv->tx_tail <= unsent)
break;
stats->tx_packets++;
stats->tx_bytes += priv->tx_dlc[priv->tx_tail %
RCAR_CAN_FIFO_DEPTH];
priv->tx_dlc[priv->tx_tail % RCAR_CAN_FIFO_DEPTH] = 0;
can_get_echo_skb(ndev, priv->tx_tail % RCAR_CAN_FIFO_DEPTH);
priv->tx_tail++;
netif_wake_queue(ndev);
}
/* Clear interrupt */
isr = readb(&priv->regs->isr);
writeb(isr & ~RCAR_CAN_ISR_TXFF, &priv->regs->isr);
can_led_event(ndev, CAN_LED_EVENT_TX);
}
static irqreturn_t rcar_can_interrupt(int irq, void *dev_id)
{
struct net_device *ndev = dev_id;
struct rcar_can_priv *priv = netdev_priv(ndev);
u8 isr;
isr = readb(&priv->regs->isr);
if (!(isr & priv->ier))
return IRQ_NONE;
if (isr & RCAR_CAN_ISR_ERSF)
rcar_can_error(ndev);
if (isr & RCAR_CAN_ISR_TXFF)
rcar_can_tx_done(ndev);
if (isr & RCAR_CAN_ISR_RXFF) {
if (napi_schedule_prep(&priv->napi)) {
/* Disable Rx FIFO interrupts */
priv->ier &= ~RCAR_CAN_IER_RXFIE;
writeb(priv->ier, &priv->regs->ier);
__napi_schedule(&priv->napi);
}
}
return IRQ_HANDLED;
}
static void rcar_can_set_bittiming(struct net_device *dev)
{
struct rcar_can_priv *priv = netdev_priv(dev);
struct can_bittiming *bt = &priv->can.bittiming;
u32 bcr;
bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
RCAR_CAN_BCR_BPR(bt->brp - 1) | RCAR_CAN_BCR_SJW(bt->sjw - 1) |
RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1);
/* Don't overwrite CLKR with 32-bit BCR access; CLKR has 8-bit access.
* All the registers are big-endian but they get byte-swapped on 32-bit
* read/write (but not on 8-bit, contrary to the manuals)...
*/
writel((bcr << 8) | priv->clock_select, &priv->regs->bcr);
}
static void rcar_can_start(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
int i;
/* Set controller to known mode:
* - FIFO mailbox mode
* - accept all messages
* - overrun mode
* CAN is in sleep mode after MCU hardware or software reset.
*/
ctlr = readw(&priv->regs->ctlr);
ctlr &= ~RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
/* Go to reset mode */
ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET;
writew(ctlr, &priv->regs->ctlr);
for (i = 0; i < MAX_STR_READS; i++) {
if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)
break;
}
rcar_can_set_bittiming(ndev);
ctlr |= RCAR_CAN_CTLR_IDFM_MIXED; /* Select mixed ID mode */
ctlr |= RCAR_CAN_CTLR_BOM_ENT; /* Entry to halt mode automatically */
/* at bus-off */
ctlr |= RCAR_CAN_CTLR_MBM; /* Select FIFO mailbox mode */
ctlr |= RCAR_CAN_CTLR_MLM; /* Overrun mode */
writew(ctlr, &priv->regs->ctlr);
/* Accept all SID and EID */
writel(0, &priv->regs->mkr_2_9[6]);
writel(0, &priv->regs->mkr_2_9[7]);
/* In FIFO mailbox mode, write "0" to bits 24 to 31 */
writel(0, &priv->regs->mkivlr1);
/* Accept all frames */
writel(0, &priv->regs->fidcr[0]);
writel(RCAR_CAN_FIDCR_IDE | RCAR_CAN_FIDCR_RTR, &priv->regs->fidcr[1]);
/* Enable and configure FIFO mailbox interrupts */
writel(RCAR_CAN_MIER1_RXFIE | RCAR_CAN_MIER1_TXFIE, &priv->regs->mier1);
priv->ier = RCAR_CAN_IER_ERSIE | RCAR_CAN_IER_RXFIE |
RCAR_CAN_IER_TXFIE;
writeb(priv->ier, &priv->regs->ier);
/* Accumulate error codes */
writeb(RCAR_CAN_ECSR_EDPM, &priv->regs->ecsr);
/* Enable error interrupts */
writeb(RCAR_CAN_EIER_EWIE | RCAR_CAN_EIER_EPIE | RCAR_CAN_EIER_BOEIE |
(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING ?
RCAR_CAN_EIER_BEIE : 0) | RCAR_CAN_EIER_ORIE |
RCAR_CAN_EIER_OLIE, &priv->regs->eier);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* Go to operation mode */
writew(ctlr & ~RCAR_CAN_CTLR_CANM, &priv->regs->ctlr);
for (i = 0; i < MAX_STR_READS; i++) {
if (!(readw(&priv->regs->str) & RCAR_CAN_STR_RSTST))
break;
}
/* Enable Rx and Tx FIFO */
writeb(RCAR_CAN_RFCR_RFE, &priv->regs->rfcr);
writeb(RCAR_CAN_TFCR_TFE, &priv->regs->tfcr);
}
static int rcar_can_open(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
int err;
err = clk_prepare_enable(priv->clk);
if (err) {
netdev_err(ndev, "failed to enable periperal clock, error %d\n",
err);
goto out;
}
err = clk_prepare_enable(priv->can_clk);
if (err) {
netdev_err(ndev, "failed to enable CAN clock, error %d\n",
err);
goto out_clock;
}
err = open_candev(ndev);
if (err) {
netdev_err(ndev, "open_candev() failed, error %d\n", err);
goto out_can_clock;
}
napi_enable(&priv->napi);
err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
if (err) {
netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq);
goto out_close;
}
can_led_event(ndev, CAN_LED_EVENT_OPEN);
rcar_can_start(ndev);
netif_start_queue(ndev);
return 0;
out_close:
napi_disable(&priv->napi);
close_candev(ndev);
out_can_clock:
clk_disable_unprepare(priv->can_clk);
out_clock:
clk_disable_unprepare(priv->clk);
out:
return err;
}
static void rcar_can_stop(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
int i;
/* Go to (force) reset mode */
ctlr = readw(&priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_CANM_FORCE_RESET;
writew(ctlr, &priv->regs->ctlr);
for (i = 0; i < MAX_STR_READS; i++) {
if (readw(&priv->regs->str) & RCAR_CAN_STR_RSTST)
break;
}
writel(0, &priv->regs->mier0);
writel(0, &priv->regs->mier1);
writeb(0, &priv->regs->ier);
writeb(0, &priv->regs->eier);
/* Go to sleep mode */
ctlr |= RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_STOPPED;
}
static int rcar_can_close(struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev);
rcar_can_stop(ndev);
free_irq(ndev->irq, ndev);
napi_disable(&priv->napi);
clk_disable_unprepare(priv->can_clk);
clk_disable_unprepare(priv->clk);
close_candev(ndev);
can_led_event(ndev, CAN_LED_EVENT_STOP);
return 0;
}
static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
struct rcar_can_priv *priv = netdev_priv(ndev);
struct can_frame *cf = (struct can_frame *)skb->data;
u32 data, i;
if (can_dropped_invalid_skb(ndev, skb))
return NETDEV_TX_OK;
if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE;
else /* Standard frame format */
data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT;
if (cf->can_id & CAN_RTR_FLAG) { /* Remote transmission request */
data |= RCAR_CAN_RTR;
} else {
for (i = 0; i < cf->can_dlc; i++)
writeb(cf->data[i],
&priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].data[i]);
}
writel(data, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].id);
writeb(cf->can_dlc, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc);
priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->can_dlc;
can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH);
priv->tx_head++;
/* Start Tx: write 0xff to the TFPCR register to increment
* the CPU-side pointer for the transmit FIFO to the next
* mailbox location
*/
writeb(0xff, &priv->regs->tfpcr);
/* Stop the queue if we've filled all FIFO entries */
if (priv->tx_head - priv->tx_tail >= RCAR_CAN_FIFO_DEPTH)
netif_stop_queue(ndev);
return NETDEV_TX_OK;
}
static const struct net_device_ops rcar_can_netdev_ops = {
.ndo_open = rcar_can_open,
.ndo_stop = rcar_can_close,
.ndo_start_xmit = rcar_can_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
{
struct net_device_stats *stats = &priv->ndev->stats;
struct can_frame *cf;
struct sk_buff *skb;
u32 data;
u8 dlc;
skb = alloc_can_skb(priv->ndev, &cf);
if (!skb) {
stats->rx_dropped++;
return;
}
data = readl(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].id);
if (data & RCAR_CAN_IDE)
cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK;
dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc);
cf->can_dlc = get_can_dlc(dlc);
if (data & RCAR_CAN_RTR) {
cf->can_id |= CAN_RTR_FLAG;
} else {
for (dlc = 0; dlc < cf->can_dlc; dlc++)
cf->data[dlc] =
readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].data[dlc]);
}
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
stats->rx_bytes += cf->can_dlc;
stats->rx_packets++;
netif_receive_skb(skb);
}
static int rcar_can_rx_poll(struct napi_struct *napi, int quota)
{
struct rcar_can_priv *priv = container_of(napi,
struct rcar_can_priv, napi);
int num_pkts;
for (num_pkts = 0; num_pkts < quota; num_pkts++) {
u8 rfcr, isr;
isr = readb(&priv->regs->isr);
/* Clear interrupt bit */
if (isr & RCAR_CAN_ISR_RXFF)
writeb(isr & ~RCAR_CAN_ISR_RXFF, &priv->regs->isr);
rfcr = readb(&priv->regs->rfcr);
if (rfcr & RCAR_CAN_RFCR_RFEST)
break;
rcar_can_rx_pkt(priv);
/* Write 0xff to the RFPCR register to increment
* the CPU-side pointer for the receive FIFO
* to the next mailbox location
*/
writeb(0xff, &priv->regs->rfpcr);
}
/* All packets processed */
if (num_pkts < quota) {
napi_complete(napi);
priv->ier |= RCAR_CAN_IER_RXFIE;
writeb(priv->ier, &priv->regs->ier);
}
return num_pkts;
}
static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
{
switch (mode) {
case CAN_MODE_START:
rcar_can_start(ndev);
netif_wake_queue(ndev);
return 0;
default:
return -EOPNOTSUPP;
}
}
static int rcar_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct rcar_can_priv *priv = netdev_priv(dev);
int err;
err = clk_prepare_enable(priv->clk);
if (err)
return err;
bec->txerr = readb(&priv->regs->tecr);
bec->rxerr = readb(&priv->regs->recr);
clk_disable_unprepare(priv->clk);
return 0;
}
static const char * const clock_names[] = {
[CLKR_CLKP1] = "clkp1",
[CLKR_CLKP2] = "clkp2",
[CLKR_CLKEXT] = "can_clk",
};
static int rcar_can_probe(struct platform_device *pdev)
{
struct rcar_can_platform_data *pdata;
struct rcar_can_priv *priv;
struct net_device *ndev;
struct resource *mem;
void __iomem *addr;
u32 clock_select = CLKR_CLKP1;
int err = -ENODEV;
int irq;
if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node,
"renesas,can-clock-select", &clock_select);
} else {
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform data provided!\n");
goto fail;
}
clock_select = pdata->clock_select;
}
irq = platform_get_irq(pdev, 0);
if (!irq) {
dev_err(&pdev->dev, "No IRQ resource\n");
goto fail;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) {
err = PTR_ERR(addr);
goto fail;
}
ndev = alloc_candev(sizeof(struct rcar_can_priv), RCAR_CAN_FIFO_DEPTH);
if (!ndev) {
dev_err(&pdev->dev, "alloc_candev() failed\n");
err = -ENOMEM;
goto fail;
}
priv = netdev_priv(ndev);
priv->clk = devm_clk_get(&pdev->dev, "clkp1");
if (IS_ERR(priv->clk)) {
err = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err);
goto fail_clk;
}
if (clock_select >= ARRAY_SIZE(clock_names)) {
err = -EINVAL;
dev_err(&pdev->dev, "invalid CAN clock selected\n");
goto fail_clk;
}
priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]);
if (IS_ERR(priv->can_clk)) {
err = PTR_ERR(priv->can_clk);
dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err);
goto fail_clk;
}
ndev->netdev_ops = &rcar_can_netdev_ops;
ndev->irq = irq;
ndev->flags |= IFF_ECHO;
priv->ndev = ndev;
priv->regs = addr;
priv->clock_select = clock_select;
priv->can.clock.freq = clk_get_rate(priv->can_clk);
priv->can.bittiming_const = &rcar_can_bittiming_const;
priv->can.do_set_mode = rcar_can_do_set_mode;
priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll,
RCAR_CAN_NAPI_WEIGHT);
err = register_candev(ndev);
if (err) {
dev_err(&pdev->dev, "register_candev() failed, error %d\n",
err);
goto fail_candev;
}
devm_can_led_init(ndev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->regs, ndev->irq);
return 0;
fail_candev:
netif_napi_del(&priv->napi);
fail_clk:
free_candev(ndev);
fail:
return err;
}
static int rcar_can_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct rcar_can_priv *priv = netdev_priv(ndev);
unregister_candev(ndev);
netif_napi_del(&priv->napi);
free_candev(ndev);
return 0;
}
static int __maybe_unused rcar_can_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
if (netif_running(ndev)) {
netif_stop_queue(ndev);
netif_device_detach(ndev);
}
ctlr = readw(&priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_CANM_HALT;
writew(ctlr, &priv->regs->ctlr);
ctlr |= RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_SLEEPING;
clk_disable(priv->clk);
return 0;
}
static int __maybe_unused rcar_can_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct rcar_can_priv *priv = netdev_priv(ndev);
u16 ctlr;
int err;
err = clk_enable(priv->clk);
if (err) {
netdev_err(ndev, "clk_enable() failed, error %d\n", err);
return err;
}
ctlr = readw(&priv->regs->ctlr);
ctlr &= ~RCAR_CAN_CTLR_SLPM;
writew(ctlr, &priv->regs->ctlr);
ctlr &= ~RCAR_CAN_CTLR_CANM;
writew(ctlr, &priv->regs->ctlr);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) {
netif_device_attach(ndev);
netif_start_queue(ndev);
}
return 0;
}
static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume);
static const struct of_device_id rcar_can_of_table[] __maybe_unused = {
{ .compatible = "renesas,can-r8a7778" },
{ .compatible = "renesas,can-r8a7779" },
{ .compatible = "renesas,can-r8a7790" },
{ .compatible = "renesas,can-r8a7791" },
{ }
};
MODULE_DEVICE_TABLE(of, rcar_can_of_table);
static struct platform_driver rcar_can_driver = {
.driver = {
.name = RCAR_CAN_DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rcar_can_of_table),
.pm = &rcar_can_pm_ops,
},
.probe = rcar_can_probe,
.remove = rcar_can_remove,
};
module_platform_driver(rcar_can_driver);
MODULE_AUTHOR("Cogent Embedded, Inc.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CAN driver for Renesas R-Car SoC");
MODULE_ALIAS("platform:" RCAR_CAN_DRV_NAME);

View file

@ -0,0 +1,103 @@
menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices"
depends on 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. It also provides 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
depends on HAS_IOPORT_MAP
---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 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/)
- Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card (http://www.connecttech.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,14 @@
#
# 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_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

View file

@ -0,0 +1,372 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#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 const 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, SJA1000_MOD, 1);
priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
res = priv->read_reg(priv, SJA1000_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);
}
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 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) {
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);
dev->dev_id = i;
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,
};
module_pci_driver(ems_pci_driver);

View file

@ -0,0 +1,320 @@
/*
* 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, SJA1000_MOD, 1);
ems_pcmcia_write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
if (ems_pcmcia_read_reg(priv, SJA1000_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 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);
dev->dev_id = i;
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 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,
};
module_pcmcia_driver(ems_pcmcia_driver);

View file

@ -0,0 +1,396 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#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 const 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) + SJA1000_MOD);
status = ioread8(base_addr +
(i * KVASER_PCI_PORT_BYTES) + SJA1000_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;
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;
/* 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;
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);
dev->dev_id = channel;
/* 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 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 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);
}
static struct pci_driver kvaser_pci_driver = {
.name = DRV_NAME,
.id_table = kvaser_pci_tbl,
.probe = kvaser_pci_init_one,
.remove = kvaser_pci_remove_one,
};
module_pci_driver(kvaser_pci_driver);

View file

@ -0,0 +1,765 @@
/*
* 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("Stephane Grosjean <s.grosjean@peak-system.com>");
MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
MODULE_SUPPORTED_DEVICE("PEAK PCAN miniPCIe/cPCI PC/104+ PCI/104e 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_CPCI_DEVICE_ID 0x0004 /* for nextgen cPCI slot cards */
#define PEAK_MPCI_DEVICE_ID 0x0005 /* for nextgen miniPCI slot cards */
#define PEAK_PC_104P_DEVICE_ID 0x0006 /* PCAN-PC/104+ cards */
#define PEAK_PCI_104E_DEVICE_ID 0x0007 /* PCAN-PCI/104 Express cards */
#define PEAK_MPCIE_DEVICE_ID 0x0008 /* The miniPCIe slot cards */
#define PEAK_PCIE_OEM_ID 0x0009 /* PCAN-PCI Express OEM */
#define PEAK_PCIEC34_DEVICE_ID 0x000A /* PCAN-PCI Express 34 (one channel) */
#define PEAK_PCI_CHAN_MAX 4
static const u16 peak_pci_icr_masks[PEAK_PCI_CHAN_MAX] = {
0x02, 0x01, 0x40, 0x80
};
static const struct pci_device_id 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,},
{PEAK_PCI_VENDOR_ID, PEAK_MPCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_PC_104P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_PCI_104E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_CPCI_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,},
{PEAK_PCI_VENDOR_ID, PEAK_PCIEC34_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)
{
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 == SJA1000_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)
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 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, *prev_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");
err = -ENOMEM;
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");
err = -ENOMEM;
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);
dev->dev_id = i;
/* 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 ||
pdev->device == PEAK_PCIEC34_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 = prev_dev) {
priv = netdev_priv(dev);
chan = priv->priv;
prev_dev = chan->prev_dev;
unregister_sja1000dev(dev);
free_sja1000dev(dev);
}
/* 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 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) {
struct net_device *prev_dev = chan->prev_dev;
dev_info(&pdev->dev, "removing device %s\n", dev->name);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
dev = 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);
}
static struct pci_driver peak_pci_driver = {
.name = DRV_NAME,
.id_table = peak_pci_tbl,
.probe = peak_pci_probe,
.remove = peak_pci_remove,
};
module_pci_driver(peak_pci_driver);

View file

@ -0,0 +1,744 @@
/*
* 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 == SJA1000_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, SJA1000_MOD, 1);
pcan_write_canreg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
if (pcan_read_canreg(priv, SJA1000_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);
netdev->dev_id = i;
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 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) {
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) {
err = -ENOMEM;
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,
};
module_pcmcia_driver(pcan_driver);

View file

@ -0,0 +1,650 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#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, "
"Connect Tech Inc. CANpro/104-Plus Opto (CRG001), "
"IXXAT PC-I 04/PCI, "
"ELCUS CAN-200-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 CAN200PCI_DEVICE_ID 0x9030
#define CAN200PCI_VENDOR_ID 0x10b5
#define CAN200PCI_SUB_DEVICE_ID 0x0301
#define CAN200PCI_SUB_VENDOR_ID 0xe1c5
#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
#define CTI_PCI_VENDOR_ID 0x12c4
#define CTI_PCI_DEVICE_ID_CRG001 0x0900
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 = {
"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 = {
"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 = {
"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 = {
"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 = {
"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 = {
"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 = {
"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 = {
"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 struct plx_pci_card_info plx_pci_card_info_cti = {
"Connect Tech Inc. CANpro/104-Plus Opto (CRG001)", 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 struct plx_pci_card_info plx_pci_card_info_elcus = {
"Eclus CAN-200-PCI", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{1, 0x00, 0x00}, { {2, 0x00, 0x80}, {3, 0x00, 0x80} },
&plx_pci_reset_common
/* based on PLX9030 */
};
static const struct pci_device_id 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
},
{
/* Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card */
PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
CTI_PCI_VENDOR_ID, CTI_PCI_DEVICE_ID_CRG001,
0, 0,
(kernel_ulong_t)&plx_pci_card_info_cti
},
{
/* Elcus CAN-200-PCI */
CAN200PCI_VENDOR_ID, CAN200PCI_DEVICE_ID,
CAN200PCI_SUB_VENDOR_ID, CAN200PCI_SUB_DEVICE_ID,
0, 0,
(kernel_ulong_t)&plx_pci_card_info_elcus
},
{ 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, SJA1000_SR) == REG_SR_BASICCAN_INITIAL) &&
(priv->read_reg(priv, SJA1000_IR) == REG_IR_BASICCAN_INITIAL))
flag = 1;
/* Bring the SJA1000 into the PeliCAN mode*/
priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/*
* Check registers after reset in the PeliCAN mode.
* See states on p. 23 of the Datasheet.
*/
if (priv->read_reg(priv, SJA1000_MOD) == REG_MOD_PELICAN_INITIAL &&
priv->read_reg(priv, SJA1000_SR) == REG_SR_PELICAN_INITIAL &&
priv->read_reg(priv, SJA1000_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);
}
/*
* Probe PLX90xx based device for the SJA1000 chips and register each
* available CAN channel to SJA1000 Socket-CAN subsystem.
*/
static int 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) {
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);
dev->dev_id = i;
/* 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,
};
module_pci_driver(plx_pci_driver);

View file

@ -0,0 +1,709 @@
/*
* 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 <linux/can/led.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 const 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, SJA1000_CMR, val);
priv->read_reg(priv, SJA1000_SR);
spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
}
static int sja1000_is_absent(struct sja1000_priv *priv)
{
return (priv->read_reg(priv, SJA1000_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)) {
netdev_err(dev, "probing failed\n");
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, SJA1000_MOD);
int i;
/* disable interrupts */
priv->write_reg(priv, SJA1000_IER, IRQ_OFF);
for (i = 0; i < 100; i++) {
/* check reset bit */
if (status & MOD_RM) {
priv->can.state = CAN_STATE_STOPPED;
return;
}
/* reset chip */
priv->write_reg(priv, SJA1000_MOD, MOD_RM);
udelay(10);
status = priv->read_reg(priv, SJA1000_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, SJA1000_MOD);
u8 mod_reg_val = 0x00;
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, SJA1000_IER, IRQ_ALL);
else
priv->write_reg(priv, SJA1000_IER,
IRQ_ALL & ~IRQ_BEI);
return;
}
/* set chip to normal mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
mod_reg_val |= MOD_LOM;
if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK)
mod_reg_val |= MOD_STM;
priv->write_reg(priv, SJA1000_MOD, mod_reg_val);
udelay(10);
status = priv->read_reg(priv, SJA1000_MOD);
}
netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
}
/*
* 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, SJA1000_CDR, priv->cdr | CDR_PELICAN);
/* set acceptance filter (accept all) */
priv->write_reg(priv, SJA1000_ACCC0, 0x00);
priv->write_reg(priv, SJA1000_ACCC1, 0x00);
priv->write_reg(priv, SJA1000_ACCC2, 0x00);
priv->write_reg(priv, SJA1000_ACCC3, 0x00);
priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
}
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);
/* Initialize chip if uninitialized at this stage */
if (!(priv->read_reg(priv, SJA1000_CDR) & CDR_PELICAN))
chipset_init(dev);
/* Clear error counters and error code capture */
priv->write_reg(priv, SJA1000_TXERR, 0x0);
priv->write_reg(priv, SJA1000_RXERR, 0x0);
priv->read_reg(priv, SJA1000_ECC);
/* leave reset mode */
set_normal_mode(dev);
}
static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
{
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, SJA1000_BTR0, btr0);
priv->write_reg(priv, SJA1000_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, SJA1000_TXERR);
bec->rxerr = priv->read_reg(priv, SJA1000_RXERR);
return 0;
}
/*
* 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;
u8 cmd_reg_val = 0x00;
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 |= SJA1000_FI_RTR;
if (id & CAN_EFF_FLAG) {
fi |= SJA1000_FI_FF;
dreg = SJA1000_EFF_BUF;
priv->write_reg(priv, SJA1000_FI, fi);
priv->write_reg(priv, SJA1000_ID1, (id & 0x1fe00000) >> 21);
priv->write_reg(priv, SJA1000_ID2, (id & 0x001fe000) >> 13);
priv->write_reg(priv, SJA1000_ID3, (id & 0x00001fe0) >> 5);
priv->write_reg(priv, SJA1000_ID4, (id & 0x0000001f) << 3);
} else {
dreg = SJA1000_SFF_BUF;
priv->write_reg(priv, SJA1000_FI, fi);
priv->write_reg(priv, SJA1000_ID1, (id & 0x000007f8) >> 3);
priv->write_reg(priv, SJA1000_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);
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
cmd_reg_val |= CMD_AT;
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
cmd_reg_val |= CMD_SRR;
else
cmd_reg_val |= CMD_TR;
sja1000_write_cmdreg(priv, cmd_reg_val);
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, SJA1000_FI);
if (fi & SJA1000_FI_FF) {
/* extended frame format (EFF) */
dreg = SJA1000_EFF_BUF;
id = (priv->read_reg(priv, SJA1000_ID1) << 21)
| (priv->read_reg(priv, SJA1000_ID2) << 13)
| (priv->read_reg(priv, SJA1000_ID3) << 5)
| (priv->read_reg(priv, SJA1000_ID4) >> 3);
id |= CAN_EFF_FLAG;
} else {
/* standard frame format (SFF) */
dreg = SJA1000_SFF_BUF;
id = (priv->read_reg(priv, SJA1000_ID1) << 3)
| (priv->read_reg(priv, SJA1000_ID2) >> 5);
}
cf->can_dlc = get_can_dlc(fi & 0x0F);
if (fi & SJA1000_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;
can_led_event(dev, CAN_LED_EVENT_RX);
}
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, SJA1000_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, SJA1000_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, SJA1000_RXERR);
uint8_t txerr = priv->read_reg(priv, SJA1000_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;
if (priv->pre_irq)
priv->pre_irq(priv);
/* Shared interrupts and IRQ off? */
if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
goto out;
while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
(n < SJA1000_MAX_IRQ)) {
status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller due to hw unplug */
if (status == 0xFF && sja1000_is_absent(priv))
goto out;
if (isrc & IRQ_WUI)
netdev_warn(dev, "wakeup interrupt\n");
if (isrc & IRQ_TI) {
/* transmission buffer released */
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
!(status & SR_TCS)) {
stats->tx_errors++;
can_free_echo_skb(dev, 0);
} else {
/* transmission complete */
stats->tx_bytes +=
priv->read_reg(priv, SJA1000_FI) & 0xf;
stats->tx_packets++;
can_get_echo_skb(dev, 0);
}
netif_wake_queue(dev);
can_led_event(dev, CAN_LED_EVENT_TX);
}
if (isrc & IRQ_RI) {
/* receive interrupt */
while (status & SR_RBS) {
sja1000_rx(dev);
status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller */
if (status == 0xFF && sja1000_is_absent(priv))
goto out;
}
}
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
/* error interrupt */
if (sja1000_err(dev, isrc, status))
break;
}
n++;
}
out:
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);
can_led_event(dev, CAN_LED_EVENT_OPEN);
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);
can_led_event(dev, CAN_LED_EVENT_STOP);
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_LOOPBACK |
CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_ONE_SHOT |
CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_PRESUME_ACK;
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,
.ndo_change_mtu = can_change_mtu,
};
int register_sja1000dev(struct net_device *dev)
{
int ret;
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);
ret = register_candev(dev);
if (!ret)
devm_can_led_init(dev);
return ret;
}
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.
*
*/
#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 SJA1000_MOD 0x00
#define SJA1000_CMR 0x01
#define SJA1000_SR 0x02
#define SJA1000_IR 0x03
#define SJA1000_IER 0x04
#define SJA1000_ALC 0x0B
#define SJA1000_ECC 0x0C
#define SJA1000_EWL 0x0D
#define SJA1000_RXERR 0x0E
#define SJA1000_TXERR 0x0F
#define SJA1000_ACCC0 0x10
#define SJA1000_ACCC1 0x11
#define SJA1000_ACCC2 0x12
#define SJA1000_ACCC3 0x13
#define SJA1000_ACCM0 0x14
#define SJA1000_ACCM1 0x15
#define SJA1000_ACCM2 0x16
#define SJA1000_ACCM3 0x17
#define SJA1000_RMC 0x1D
#define SJA1000_RBSA 0x1E
/* Common registers - manual section 6.5 */
#define SJA1000_BTR0 0x06
#define SJA1000_BTR1 0x07
#define SJA1000_OCR 0x08
#define SJA1000_CDR 0x1F
#define SJA1000_FI 0x10
#define SJA1000_SFF_BUF 0x13
#define SJA1000_EFF_BUF 0x15
#define SJA1000_FI_FF 0x80
#define SJA1000_FI_RTR 0x40
#define SJA1000_ID1 0x11
#define SJA1000_ID2 0x12
#define SJA1000_ID3 0x13
#define SJA1000_ID4 0x14
#define SJA1000_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 */
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,324 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#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 irq[MAXDEV];
static int clk[MAXDEV];
static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
static spinlock_t indirect_lock[MAXDEV]; /* lock for indirect access mode */
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 flags, base = (unsigned long)priv->reg_base;
u8 readval;
spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
outb(reg, base);
readval = inb(base + 1);
spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
return readval;
}
static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
int reg, u8 val)
{
unsigned long flags, base = (unsigned long)priv->reg_base;
spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
outb(reg, base);
outb(val, base + 1);
spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
}
static int 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;
spin_lock_init(&indirect_lock[idx]);
} 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;
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->dev_id = idx;
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 sja1000_isa_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_sja1000dev(dev);
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 = 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,261 @@
/*
* 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, see <http://www.gnu.org/licenses/>.
*/
#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 <linux/of.h>
#include <linux/of_irq.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_platform"
#define SP_CAN_CLOCK (16000000 / 2)
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
MODULE_ALIAS("platform:" DRV_NAME);
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 void sp_populate(struct sja1000_priv *priv,
struct sja1000_platform_data *pdata,
unsigned long resource_mem_flags)
{
/* 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 (resource_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;
}
}
static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
{
int err;
u32 prop;
err = of_property_read_u32(of, "reg-io-width", &prop);
if (err)
prop = 1; /* 8 bit is default */
switch (prop) {
case 4:
priv->read_reg = sp_read_reg32;
priv->write_reg = sp_write_reg32;
break;
case 2:
priv->read_reg = sp_read_reg16;
priv->write_reg = sp_write_reg16;
break;
case 1: /* fallthrough */
default:
priv->read_reg = sp_read_reg8;
priv->write_reg = sp_write_reg8;
}
err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
if (!err)
priv->can.clock.freq = prop / 2;
else
priv->can.clock.freq = SP_CAN_CLOCK; /* default */
err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
if (!err)
priv->ocr |= prop & OCR_MODE_MASK;
else
priv->ocr |= OCR_MODE_NORMAL; /* default */
err = of_property_read_u32(of, "nxp,tx-output-config", &prop);
if (!err)
priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
else
priv->ocr |= OCR_TX0_PULLDOWN; /* default */
err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop);
if (!err && 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 */
}
if (!of_property_read_bool(of, "nxp,no-comparator-bypass"))
priv->cdr |= CDR_CBP; /* default */
}
static int sp_probe(struct platform_device *pdev)
{
int err, irq = 0;
void __iomem *addr;
struct net_device *dev;
struct sja1000_priv *priv;
struct resource *res_mem, *res_irq = NULL;
struct sja1000_platform_data *pdata;
struct device_node *of = pdev->dev.of_node;
pdata = dev_get_platdata(&pdev->dev);
if (!pdata && !of) {
dev_err(&pdev->dev, "No platform data provided!\n");
return -ENODEV;
}
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_mem)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, res_mem->start,
resource_size(res_mem), DRV_NAME))
return -EBUSY;
addr = devm_ioremap_nocache(&pdev->dev, res_mem->start,
resource_size(res_mem));
if (!addr)
return -ENOMEM;
if (of)
irq = irq_of_parse_and_map(of, 0);
else
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq && !res_irq)
return -ENODEV;
dev = alloc_sja1000dev(0);
if (!dev)
return -ENOMEM;
priv = netdev_priv(dev);
if (res_irq) {
irq = res_irq->start;
priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
priv->irq_flags |= IRQF_SHARED;
} else {
priv->irq_flags = IRQF_SHARED;
}
dev->irq = irq;
priv->reg_base = addr;
if (of)
sp_populate_of(priv, of);
else
sp_populate(priv, pdata, res_mem->flags);
platform_set_drvdata(pdev, 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);
return err;
}
static int sp_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
return 0;
}
static struct of_device_id sp_of_table[] = {
{.compatible = "nxp,sja1000"},
{},
};
MODULE_DEVICE_TABLE(of, sp_of_table);
static struct platform_driver sp_driver = {
.probe = sp_probe,
.remove = sp_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = sp_of_table,
},
};
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[] = {
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 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 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 = 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);

782
drivers/net/can/slcan.c Normal file
View file

@ -0,0 +1,782 @@
/*
* slcan.c - serial line CAN interface driver (using tty line discipline)
*
* This file is derived from linux/drivers/net/slip/slip.c
*
* slip.c Authors : Laurence Culhane <loz@holmes.demon.co.uk>
* Fred N. van Kempen <waltje@uwalt.nl.mugnet.org>
* slcan.c Author : Oliver Hartkopp <socketcan@hartkopp.net>
*
* 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/gpl.html
*
* 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/moduleparam.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/can.h>
#include <linux/can/skb.h>
static __initconst const char banner[] =
KERN_INFO "slcan: serial line CAN interface driver\n";
MODULE_ALIAS_LDISC(N_SLCAN);
MODULE_DESCRIPTION("serial line CAN interface");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
#define SLCAN_MAGIC 0x53CA
static int maxdev = 10; /* MAX number of SLCAN channels;
This can be overridden with
insmod slcan.ko maxdev=nnn */
module_param(maxdev, int, 0);
MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
/* maximum rx buffer len: extended CAN frame with timestamp */
#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
#define SLC_CMD_LEN 1
#define SLC_SFF_ID_LEN 3
#define SLC_EFF_ID_LEN 8
struct slcan {
int magic;
/* Various fields. */
struct tty_struct *tty; /* ptr to TTY structure */
struct net_device *dev; /* easy for intr handling */
spinlock_t lock;
struct work_struct tx_work; /* Flushes transmit buffer */
/* These are pointers to the malloc()ed frame buffers. */
unsigned char rbuff[SLC_MTU]; /* receiver buffer */
int rcount; /* received chars counter */
unsigned char xbuff[SLC_MTU]; /* transmitter buffer */
unsigned char *xhead; /* pointer to next XMIT byte */
int xleft; /* bytes left in XMIT queue */
unsigned long flags; /* Flag values/ mode etc */
#define SLF_INUSE 0 /* Channel in use */
#define SLF_ERROR 1 /* Parity, etc. error */
};
static struct net_device **slcan_devs;
/************************************************************************
* SLCAN ENCAPSULATION FORMAT *
************************************************************************/
/*
* A CAN frame has a can_id (11 bit standard frame format OR 29 bit extended
* frame format) a data length code (can_dlc) which can be from 0 to 8
* and up to <can_dlc> data bytes as payload.
* Additionally a CAN frame may become a remote transmission frame if the
* RTR-bit is set. This causes another ECU to send a CAN frame with the
* given can_id.
*
* The SLCAN ASCII representation of these different frame types is:
* <type> <id> <dlc> <data>*
*
* Extended frames (29 bit) are defined by capital characters in the type.
* RTR frames are defined as 'r' types - normal frames have 't' type:
* t => 11 bit data frame
* r => 11 bit RTR frame
* T => 29 bit data frame
* R => 29 bit RTR frame
*
* The <id> is 3 (standard) or 8 (extended) bytes in ASCII Hex (base64).
* The <dlc> is a one byte ASCII number ('0' - '8')
* The <data> section has at much ASCII Hex bytes as defined by the <dlc>
*
* Examples:
*
* t1230 : can_id 0x123, can_dlc 0, no data
* t4563112233 : can_id 0x456, can_dlc 3, data 0x11 0x22 0x33
* T12ABCDEF2AA55 : extended can_id 0x12ABCDEF, can_dlc 2, data 0xAA 0x55
* r1230 : can_id 0x123, can_dlc 0, no data, remote transmission request
*
*/
/************************************************************************
* STANDARD SLCAN DECAPSULATION *
************************************************************************/
/* Send one completely decapsulated can_frame to the network layer */
static void slc_bump(struct slcan *sl)
{
struct sk_buff *skb;
struct can_frame cf;
int i, tmp;
u32 tmpid;
char *cmd = sl->rbuff;
cf.can_id = 0;
switch (*cmd) {
case 'r':
cf.can_id = CAN_RTR_FLAG;
/* fallthrough */
case 't':
/* store dlc ASCII value and terminate SFF CAN ID string */
cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0;
/* point to payload data behind the dlc */
cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1;
break;
case 'R':
cf.can_id = CAN_RTR_FLAG;
/* fallthrough */
case 'T':
cf.can_id |= CAN_EFF_FLAG;
/* store dlc ASCII value and terminate EFF CAN ID string */
cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0;
/* point to payload data behind the dlc */
cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1;
break;
default:
return;
}
if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
return;
cf.can_id |= tmpid;
/* get can_dlc from sanitized ASCII value */
if (cf.can_dlc >= '0' && cf.can_dlc < '9')
cf.can_dlc -= '0';
else
return;
*(u64 *) (&cf.data) = 0; /* clear payload */
/* RTR frames may have a dlc > 0 but they never have any data bytes */
if (!(cf.can_id & CAN_RTR_FLAG)) {
for (i = 0; i < cf.can_dlc; i++) {
tmp = hex_to_bin(*cmd++);
if (tmp < 0)
return;
cf.data[i] = (tmp << 4);
tmp = hex_to_bin(*cmd++);
if (tmp < 0)
return;
cf.data[i] |= tmp;
}
}
skb = dev_alloc_skb(sizeof(struct can_frame) +
sizeof(struct can_skb_priv));
if (!skb)
return;
skb->dev = sl->dev;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
can_skb_reserve(skb);
can_skb_prv(skb)->ifindex = sl->dev->ifindex;
memcpy(skb_put(skb, sizeof(struct can_frame)),
&cf, sizeof(struct can_frame));
netif_rx_ni(skb);
sl->dev->stats.rx_packets++;
sl->dev->stats.rx_bytes += cf.can_dlc;
}
/* parse tty input stream */
static void slcan_unesc(struct slcan *sl, unsigned char s)
{
if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
(sl->rcount > 4)) {
slc_bump(sl);
}
sl->rcount = 0;
} else {
if (!test_bit(SLF_ERROR, &sl->flags)) {
if (sl->rcount < SLC_MTU) {
sl->rbuff[sl->rcount++] = s;
return;
} else {
sl->dev->stats.rx_over_errors++;
set_bit(SLF_ERROR, &sl->flags);
}
}
}
}
/************************************************************************
* STANDARD SLCAN ENCAPSULATION *
************************************************************************/
/* Encapsulate one can_frame and stuff into a TTY queue. */
static void slc_encaps(struct slcan *sl, struct can_frame *cf)
{
int actual, i;
unsigned char *pos;
unsigned char *endpos;
canid_t id = cf->can_id;
pos = sl->xbuff;
if (cf->can_id & CAN_RTR_FLAG)
*pos = 'R'; /* becomes 'r' in standard frame format (SFF) */
else
*pos = 'T'; /* becomes 't' in standard frame format (SSF) */
/* determine number of chars for the CAN-identifier */
if (cf->can_id & CAN_EFF_FLAG) {
id &= CAN_EFF_MASK;
endpos = pos + SLC_EFF_ID_LEN;
} else {
*pos |= 0x20; /* convert R/T to lower case for SFF */
id &= CAN_SFF_MASK;
endpos = pos + SLC_SFF_ID_LEN;
}
/* build 3 (SFF) or 8 (EFF) digit CAN identifier */
pos++;
while (endpos >= pos) {
*endpos-- = hex_asc_upper[id & 0xf];
id >>= 4;
}
pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN;
*pos++ = cf->can_dlc + '0';
/* RTR frames may have a dlc > 0 but they never have any data bytes */
if (!(cf->can_id & CAN_RTR_FLAG)) {
for (i = 0; i < cf->can_dlc; i++)
pos = hex_byte_pack_upper(pos, cf->data[i]);
}
*pos++ = '\r';
/* Order of next two lines is *very* important.
* When we are sending a little amount of data,
* the transfer may be completed inside the ops->write()
* routine, because it's running with interrupts enabled.
* In this case we *never* got WRITE_WAKEUP event,
* if we did not request it before write operation.
* 14 Oct 1994 Dmitry Gorodchanin.
*/
set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
actual = sl->tty->ops->write(sl->tty, sl->xbuff, pos - sl->xbuff);
sl->xleft = (pos - sl->xbuff) - actual;
sl->xhead = sl->xbuff + actual;
sl->dev->stats.tx_bytes += cf->can_dlc;
}
/* Write out any remaining transmit buffer. Scheduled when tty is writable */
static void slcan_transmit(struct work_struct *work)
{
struct slcan *sl = container_of(work, struct slcan, tx_work);
int actual;
spin_lock_bh(&sl->lock);
/* First make sure we're connected. */
if (!sl->tty || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) {
spin_unlock_bh(&sl->lock);
return;
}
if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sl->dev->stats.tx_packets++;
clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
spin_unlock_bh(&sl->lock);
netif_wake_queue(sl->dev);
return;
}
actual = sl->tty->ops->write(sl->tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
spin_unlock_bh(&sl->lock);
}
/*
* Called by the driver when there's room for more data.
* Schedule the transmit.
*/
static void slcan_write_wakeup(struct tty_struct *tty)
{
struct slcan *sl = tty->disc_data;
schedule_work(&sl->tx_work);
}
/* Send a can_frame to a TTY queue. */
static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct slcan *sl = netdev_priv(dev);
if (skb->len != sizeof(struct can_frame))
goto out;
spin_lock(&sl->lock);
if (!netif_running(dev)) {
spin_unlock(&sl->lock);
printk(KERN_WARNING "%s: xmit: iface is down\n", dev->name);
goto out;
}
if (sl->tty == NULL) {
spin_unlock(&sl->lock);
goto out;
}
netif_stop_queue(sl->dev);
slc_encaps(sl, (struct can_frame *) skb->data); /* encaps & send */
spin_unlock(&sl->lock);
out:
kfree_skb(skb);
return NETDEV_TX_OK;
}
/******************************************
* Routines looking at netdevice side.
******************************************/
/* Netdevice UP -> DOWN routine */
static int slc_close(struct net_device *dev)
{
struct slcan *sl = netdev_priv(dev);
spin_lock_bh(&sl->lock);
if (sl->tty) {
/* TTY discipline is running. */
clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
}
netif_stop_queue(dev);
sl->rcount = 0;
sl->xleft = 0;
spin_unlock_bh(&sl->lock);
return 0;
}
/* Netdevice DOWN -> UP routine */
static int slc_open(struct net_device *dev)
{
struct slcan *sl = netdev_priv(dev);
if (sl->tty == NULL)
return -ENODEV;
sl->flags &= (1 << SLF_INUSE);
netif_start_queue(dev);
return 0;
}
/* Hook the destructor so we can free slcan devs at the right point in time */
static void slc_free_netdev(struct net_device *dev)
{
int i = dev->base_addr;
free_netdev(dev);
slcan_devs[i] = NULL;
}
static int slcan_change_mtu(struct net_device *dev, int new_mtu)
{
return -EINVAL;
}
static const struct net_device_ops slc_netdev_ops = {
.ndo_open = slc_open,
.ndo_stop = slc_close,
.ndo_start_xmit = slc_xmit,
.ndo_change_mtu = slcan_change_mtu,
};
static void slc_setup(struct net_device *dev)
{
dev->netdev_ops = &slc_netdev_ops;
dev->destructor = slc_free_netdev;
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->tx_queue_len = 10;
dev->mtu = sizeof(struct can_frame);
dev->type = ARPHRD_CAN;
/* New-style flags. */
dev->flags = IFF_NOARP;
dev->features = NETIF_F_HW_CSUM;
}
/******************************************
Routines looking at TTY side.
******************************************/
/*
* Handle the 'receiver data ready' interrupt.
* This function is called by the 'tty_io' module in the kernel when
* a block of SLCAN data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing. This will not
* be re-entered while running but other ldisc functions may be called
* in parallel
*/
static void slcan_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
return;
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
cp++;
continue;
}
slcan_unesc(sl, *cp++);
}
}
/************************************
* slcan_open helper routines.
************************************/
/* Collect hanged up channels */
static void slc_sync(void)
{
int i;
struct net_device *dev;
struct slcan *sl;
for (i = 0; i < maxdev; i++) {
dev = slcan_devs[i];
if (dev == NULL)
break;
sl = netdev_priv(dev);
if (sl->tty)
continue;
if (dev->flags & IFF_UP)
dev_close(dev);
}
}
/* Find a free SLCAN channel, and link in this `tty' line. */
static struct slcan *slc_alloc(dev_t line)
{
int i;
char name[IFNAMSIZ];
struct net_device *dev = NULL;
struct slcan *sl;
for (i = 0; i < maxdev; i++) {
dev = slcan_devs[i];
if (dev == NULL)
break;
}
/* Sorry, too many, all slots in use */
if (i >= maxdev)
return NULL;
sprintf(name, "slcan%d", i);
dev = alloc_netdev(sizeof(*sl), name, NET_NAME_UNKNOWN, slc_setup);
if (!dev)
return NULL;
dev->base_addr = i;
sl = netdev_priv(dev);
/* Initialize channel control data */
sl->magic = SLCAN_MAGIC;
sl->dev = dev;
spin_lock_init(&sl->lock);
INIT_WORK(&sl->tx_work, slcan_transmit);
slcan_devs[i] = dev;
return sl;
}
/*
* Open the high-level part of the SLCAN channel.
* This function is called by the TTY module when the
* SLCAN line discipline is called for. Because we are
* sure the tty line exists, we only have to link it to
* a free SLCAN channel...
*
* Called in process context serialized from other ldisc calls.
*/
static int slcan_open(struct tty_struct *tty)
{
struct slcan *sl;
int err;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
/* RTnetlink lock is misused here to serialize concurrent
opens of slcan channels. There are better ways, but it is
the simplest one.
*/
rtnl_lock();
/* Collect hanged up channels. */
slc_sync();
sl = tty->disc_data;
err = -EEXIST;
/* First make sure we're not already connected. */
if (sl && sl->magic == SLCAN_MAGIC)
goto err_exit;
/* OK. Find a free SLCAN channel to use. */
err = -ENFILE;
sl = slc_alloc(tty_devnum(tty));
if (sl == NULL)
goto err_exit;
sl->tty = tty;
tty->disc_data = sl;
if (!test_bit(SLF_INUSE, &sl->flags)) {
/* Perform the low-level SLCAN initialization. */
sl->rcount = 0;
sl->xleft = 0;
set_bit(SLF_INUSE, &sl->flags);
err = register_netdevice(sl->dev);
if (err)
goto err_free_chan;
}
/* Done. We have linked the TTY line to a channel. */
rtnl_unlock();
tty->receive_room = 65536; /* We don't flow control */
/* TTY layer expects 0 on success */
return 0;
err_free_chan:
sl->tty = NULL;
tty->disc_data = NULL;
clear_bit(SLF_INUSE, &sl->flags);
err_exit:
rtnl_unlock();
/* Count references from TTY module */
return err;
}
/*
* Close down a SLCAN channel.
* This means flushing out any pending queues, and then returning. This
* call is serialized against other ldisc functions.
*
* We also use this method for a hangup event.
*/
static void slcan_close(struct tty_struct *tty)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
/* First make sure we're connected. */
if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty)
return;
spin_lock_bh(&sl->lock);
tty->disc_data = NULL;
sl->tty = NULL;
spin_unlock_bh(&sl->lock);
flush_work(&sl->tx_work);
/* Flush network side */
unregister_netdev(sl->dev);
/* This will complete via sl_free_netdev */
}
static int slcan_hangup(struct tty_struct *tty)
{
slcan_close(tty);
return 0;
}
/* Perform I/O control on an active SLCAN channel. */
static int slcan_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
unsigned int tmp;
/* First make sure we're connected. */
if (!sl || sl->magic != SLCAN_MAGIC)
return -EINVAL;
switch (cmd) {
case SIOCGIFNAME:
tmp = strlen(sl->dev->name) + 1;
if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
return -EFAULT;
return 0;
case SIOCSIFHWADDR:
return -EINVAL;
default:
return tty_mode_ioctl(tty, file, cmd, arg);
}
}
static struct tty_ldisc_ops slc_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "slcan",
.open = slcan_open,
.close = slcan_close,
.hangup = slcan_hangup,
.ioctl = slcan_ioctl,
.receive_buf = slcan_receive_buf,
.write_wakeup = slcan_write_wakeup,
};
static int __init slcan_init(void)
{
int status;
if (maxdev < 4)
maxdev = 4; /* Sanity */
printk(banner);
printk(KERN_INFO "slcan: %d dynamic interface channels.\n", maxdev);
slcan_devs = kzalloc(sizeof(struct net_device *)*maxdev, GFP_KERNEL);
if (!slcan_devs)
return -ENOMEM;
/* Fill in our line protocol discipline, and register it */
status = tty_register_ldisc(N_SLCAN, &slc_ldisc);
if (status) {
printk(KERN_ERR "slcan: can't register line discipline\n");
kfree(slcan_devs);
}
return status;
}
static void __exit slcan_exit(void)
{
int i;
struct net_device *dev;
struct slcan *sl;
unsigned long timeout = jiffies + HZ;
int busy = 0;
if (slcan_devs == NULL)
return;
/* First of all: check for active disciplines and hangup them.
*/
do {
if (busy)
msleep_interruptible(100);
busy = 0;
for (i = 0; i < maxdev; i++) {
dev = slcan_devs[i];
if (!dev)
continue;
sl = netdev_priv(dev);
spin_lock_bh(&sl->lock);
if (sl->tty) {
busy++;
tty_hangup(sl->tty);
}
spin_unlock_bh(&sl->lock);
}
} while (busy && time_before(jiffies, timeout));
/* FIXME: hangup is async so we should wait when doing this second
phase */
for (i = 0; i < maxdev; i++) {
dev = slcan_devs[i];
if (!dev)
continue;
slcan_devs[i] = NULL;
sl = netdev_priv(dev);
if (sl->tty) {
printk(KERN_ERR "%s: tty discipline still running\n",
dev->name);
/* Intentionally leak the control block. */
dev->destructor = NULL;
}
unregister_netdev(dev);
}
kfree(slcan_devs);
slcan_devs = NULL;
i = tty_unregister_ldisc(N_SLCAN);
if (i)
printk(KERN_ERR "slcan: can't unregister ldisc (err %d)\n", i);
}
module_init(slcan_init);
module_exit(slcan_exit);

View file

@ -0,0 +1,30 @@
config CAN_SOFTING
tristate "Softing Gmbh CAN generic support"
depends on HAS_IOMEM
---help---
Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh.
Softing Gmbh CAN cards come with 1 or 2 physical busses.
Those cards typically use Dual Port RAM to communicate
with the host CPU. The interface is then identical for PCI
and PCMCIA cards. This driver operates on a platform device,
which has been created by softing_cs or softing_pci driver.
Warning:
The API of the card does not allow fine control per bus, but
controls the 2 busses on the card together.
As such, some actions (start/stop/busoff recovery) on 1 bus
must bring down the other bus too temporarily.
config CAN_SOFTING_CS
tristate "Softing Gmbh CAN pcmcia cards"
depends on PCMCIA
depends on CAN_SOFTING
---help---
Support for PCMCIA cards from Softing Gmbh & some cards
from Vector Gmbh.
You need firmware for these, which you can get at
http://developer.berlios.de/projects/socketcan/
This version of the driver is written against
firmware version 4.6 (softing-fw-4.6-binaries.tar.gz)
In order to use the card as CAN device, you need the Softing generic
support too.

View file

@ -0,0 +1,4 @@
softing-y := softing_main.o softing_fw.o
obj-$(CONFIG_CAN_SOFTING) += softing.o
obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o

View file

@ -0,0 +1,167 @@
/*
* softing common interfaces
*
* by Kurt Van Dijck, 2008-2010
*/
#include <linux/atomic.h>
#include <linux/netdevice.h>
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include "softing_platform.h"
struct softing;
struct softing_priv {
struct can_priv can; /* must be the first member! */
struct net_device *netdev;
struct softing *card;
struct {
int pending;
/* variables which hold the circular buffer */
int echo_put;
int echo_get;
} tx;
struct can_bittiming_const btr_const;
int index;
uint8_t output;
uint16_t chip;
};
#define netdev2softing(netdev) ((struct softing_priv *)netdev_priv(netdev))
struct softing {
const struct softing_platform_data *pdat;
struct platform_device *pdev;
struct net_device *net[2];
spinlock_t spin; /* protect this structure & DPRAM access */
ktime_t ts_ref;
ktime_t ts_overflow; /* timestamp overflow value, in ktime */
struct {
/* indication of firmware status */
int up;
/* protection of the 'up' variable */
struct mutex lock;
} fw;
struct {
int nr;
int requested;
int svc_count;
unsigned int dpram_position;
} irq;
struct {
int pending;
int last_bus;
/*
* keep the bus that last tx'd a message,
* in order to let every netdev queue resume
*/
} tx;
__iomem uint8_t *dpram;
unsigned long dpram_phys;
unsigned long dpram_size;
struct {
uint16_t fw_version, hw_version, license, serial;
uint16_t chip[2];
unsigned int freq; /* remote cpu's operating frequency */
} id;
};
int softing_default_output(struct net_device *netdev);
ktime_t softing_raw2ktime(struct softing *card, u32 raw);
int softing_chip_poweron(struct softing *card);
int softing_bootloader_command(struct softing *card, int16_t cmd,
const char *msg);
/* Load firmware after reset */
int softing_load_fw(const char *file, struct softing *card,
__iomem uint8_t *virt, unsigned int size, int offset);
/* Load final application firmware after bootloader */
int softing_load_app_fw(const char *file, struct softing *card);
/*
* enable or disable irq
* only called with fw.lock locked
*/
int softing_enable_irq(struct softing *card, int enable);
/* start/stop 1 bus on card */
int softing_startstop(struct net_device *netdev, int up);
/* netif_rx() */
int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
ktime_t ktime);
/* SOFTING DPRAM mappings */
#define DPRAM_RX 0x0000
#define DPRAM_RX_SIZE 32
#define DPRAM_RX_CNT 16
#define DPRAM_RX_RD 0x0201 /* uint8_t */
#define DPRAM_RX_WR 0x0205 /* uint8_t */
#define DPRAM_RX_LOST 0x0207 /* uint8_t */
#define DPRAM_FCT_PARAM 0x0300 /* int16_t [20] */
#define DPRAM_FCT_RESULT 0x0328 /* int16_t */
#define DPRAM_FCT_HOST 0x032b /* uint16_t */
#define DPRAM_INFO_BUSSTATE 0x0331 /* uint16_t */
#define DPRAM_INFO_BUSSTATE2 0x0335 /* uint16_t */
#define DPRAM_INFO_ERRSTATE 0x0339 /* uint16_t */
#define DPRAM_INFO_ERRSTATE2 0x033d /* uint16_t */
#define DPRAM_RESET 0x0341 /* uint16_t */
#define DPRAM_CLR_RECV_FIFO 0x0345 /* uint16_t */
#define DPRAM_RESET_TIME 0x034d /* uint16_t */
#define DPRAM_TIME 0x0350 /* uint64_t */
#define DPRAM_WR_START 0x0358 /* uint8_t */
#define DPRAM_WR_END 0x0359 /* uint8_t */
#define DPRAM_RESET_RX_FIFO 0x0361 /* uint16_t */
#define DPRAM_RESET_TX_FIFO 0x0364 /* uint8_t */
#define DPRAM_READ_FIFO_LEVEL 0x0365 /* uint8_t */
#define DPRAM_RX_FIFO_LEVEL 0x0366 /* uint16_t */
#define DPRAM_TX_FIFO_LEVEL 0x0366 /* uint16_t */
#define DPRAM_TX 0x0400 /* uint16_t */
#define DPRAM_TX_SIZE 16
#define DPRAM_TX_CNT 32
#define DPRAM_TX_RD 0x0601 /* uint8_t */
#define DPRAM_TX_WR 0x0605 /* uint8_t */
#define DPRAM_COMMAND 0x07e0 /* uint16_t */
#define DPRAM_RECEIPT 0x07f0 /* uint16_t */
#define DPRAM_IRQ_TOHOST 0x07fe /* uint8_t */
#define DPRAM_IRQ_TOCARD 0x07ff /* uint8_t */
#define DPRAM_V2_RESET 0x0e00 /* uint8_t */
#define DPRAM_V2_IRQ_TOHOST 0x0e02 /* uint8_t */
#define TXMAX (DPRAM_TX_CNT - 1)
/* DPRAM return codes */
#define RES_NONE 0
#define RES_OK 1
#define RES_NOK 2
#define RES_UNKNOWN 3
/* DPRAM flags */
#define CMD_TX 0x01
#define CMD_ACK 0x02
#define CMD_XTD 0x04
#define CMD_RTR 0x08
#define CMD_ERR 0x10
#define CMD_BUS2 0x80
/* returned fifo entry bus state masks */
#define SF_MASK_BUSOFF 0x80
#define SF_MASK_EPASSIVE 0x60
/* bus states */
#define STATE_BUSOFF 2
#define STATE_EPASSIVE 1
#define STATE_EACTIVE 0

View file

@ -0,0 +1,346 @@
/*
* Copyright (C) 2008-2010
*
* - Kurt Van Dijck, EIA Electronics
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "softing_platform.h"
static int softingcs_index;
static DEFINE_SPINLOCK(softingcs_index_lock);
static int softingcs_reset(struct platform_device *pdev, int v);
static int softingcs_enable_irq(struct platform_device *pdev, int v);
/*
* platform_data descriptions
*/
#define MHZ (1000*1000)
static const struct softing_platform_data softingcs_platform_data[] = {
{
.name = "CANcard",
.manf = 0x0168, .prod = 0x001,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "CANcard-NEC",
.manf = 0x0168, .prod = 0x002,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "CANcard-SJA",
.manf = 0x0168, .prod = 0x004,
.generation = 1,
.nbus = 2,
.freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "CANcard-2",
.manf = 0x0168, .prod = 0x005,
.generation = 2,
.nbus = 2,
.freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x1000,
.boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
.reset = softingcs_reset,
.enable_irq = NULL,
}, {
.name = "Vector-CANcard",
.manf = 0x0168, .prod = 0x081,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "Vector-CANcard-SJA",
.manf = 0x0168, .prod = 0x084,
.generation = 1,
.nbus = 2,
.freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "Vector-CANcard-2",
.manf = 0x0168, .prod = 0x085,
.generation = 2,
.nbus = 2,
.freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x1000,
.boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
.reset = softingcs_reset,
.enable_irq = NULL,
}, {
.name = "EDICcard-NEC",
.manf = 0x0168, .prod = 0x102,
.generation = 1,
.nbus = 2,
.freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x0800,
.boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
.reset = softingcs_reset,
.enable_irq = softingcs_enable_irq,
}, {
.name = "EDICcard-2",
.manf = 0x0168, .prod = 0x105,
.generation = 2,
.nbus = 2,
.freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
.dpram_size = 0x1000,
.boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
.load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
.app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
.reset = softingcs_reset,
.enable_irq = NULL,
}, {
0, 0,
},
};
MODULE_FIRMWARE(fw_dir "bcard.bin");
MODULE_FIRMWARE(fw_dir "ldcard.bin");
MODULE_FIRMWARE(fw_dir "cancard.bin");
MODULE_FIRMWARE(fw_dir "cansja.bin");
MODULE_FIRMWARE(fw_dir "bcard2.bin");
MODULE_FIRMWARE(fw_dir "ldcard2.bin");
MODULE_FIRMWARE(fw_dir "cancrd2.bin");
static const struct softing_platform_data
*softingcs_find_platform_data(unsigned int manf, unsigned int prod)
{
const struct softing_platform_data *lp;
for (lp = softingcs_platform_data; lp->manf; ++lp) {
if ((lp->manf == manf) && (lp->prod == prod))
return lp;
}
return NULL;
}
/*
* platformdata callbacks
*/
static int softingcs_reset(struct platform_device *pdev, int v)
{
struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
}
static int softingcs_enable_irq(struct platform_device *pdev, int v)
{
struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
}
/*
* pcmcia check
*/
static int softingcs_probe_config(struct pcmcia_device *pcmcia, void *priv_data)
{
struct softing_platform_data *pdat = priv_data;
struct resource *pres;
int memspeed = 0;
WARN_ON(!pdat);
pres = pcmcia->resource[PCMCIA_IOMEM_0];
if (resource_size(pres) < 0x1000)
return -ERANGE;
pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
if (pdat->generation < 2) {
pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
memspeed = 3;
} else {
pres->flags |= WIN_DATA_WIDTH_16;
}
return pcmcia_request_window(pcmcia, pres, memspeed);
}
static void softingcs_remove(struct pcmcia_device *pcmcia)
{
struct platform_device *pdev = pcmcia->priv;
/* free bits */
platform_device_unregister(pdev);
/* release pcmcia stuff */
pcmcia_disable_device(pcmcia);
}
/*
* platform_device wrapper
* pdev->resource has 2 entries: io & irq
*/
static void softingcs_pdev_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
kfree(pdev);
}
static int softingcs_probe(struct pcmcia_device *pcmcia)
{
int ret;
struct platform_device *pdev;
const struct softing_platform_data *pdat;
struct resource *pres;
struct dev {
struct platform_device pdev;
struct resource res[2];
} *dev;
/* find matching platform_data */
pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
if (!pdat)
return -ENOTTY;
/* setup pcmcia device */
pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
if (ret)
goto pcmcia_failed;
ret = pcmcia_enable_device(pcmcia);
if (ret < 0)
goto pcmcia_failed;
pres = pcmcia->resource[PCMCIA_IOMEM_0];
if (!pres) {
ret = -EBADF;
goto pcmcia_bad;
}
/* create softing platform device */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
ret = -ENOMEM;
goto mem_failed;
}
dev->pdev.resource = dev->res;
dev->pdev.num_resources = ARRAY_SIZE(dev->res);
dev->pdev.dev.release = softingcs_pdev_release;
pdev = &dev->pdev;
pdev->dev.platform_data = (void *)pdat;
pdev->dev.parent = &pcmcia->dev;
pcmcia->priv = pdev;
/* platform device resources */
pdev->resource[0].flags = IORESOURCE_MEM;
pdev->resource[0].start = pres->start;
pdev->resource[0].end = pres->end;
pdev->resource[1].flags = IORESOURCE_IRQ;
pdev->resource[1].start = pcmcia->irq;
pdev->resource[1].end = pdev->resource[1].start;
/* platform device setup */
spin_lock(&softingcs_index_lock);
pdev->id = softingcs_index++;
spin_unlock(&softingcs_index_lock);
pdev->name = "softing";
dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
ret = platform_device_register(pdev);
if (ret < 0)
goto platform_failed;
dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
return 0;
platform_failed:
kfree(dev);
mem_failed:
pcmcia_bad:
pcmcia_failed:
pcmcia_disable_device(pcmcia);
pcmcia->priv = NULL;
return ret ?: -ENODEV;
}
static const struct pcmcia_device_id softingcs_ids[] = {
/* softing */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
/* vector, manufacturer? */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
/* EDIC */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
static struct pcmcia_driver softingcs_driver = {
.owner = THIS_MODULE,
.name = "softingcs",
.id_table = softingcs_ids,
.probe = softingcs_probe,
.remove = softingcs_remove,
};
module_pcmcia_driver(softingcs_driver);
MODULE_DESCRIPTION("softing CANcard driver"
", links PCMCIA card to softing driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,692 @@
/*
* Copyright (C) 2008-2010
*
* - Kurt Van Dijck, EIA Electronics
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/firmware.h>
#include <linux/sched.h>
#include <asm/div64.h>
#include <asm/io.h>
#include "softing.h"
/*
* low level DPRAM command.
* Make sure that card->dpram[DPRAM_FCT_HOST] is preset
*/
static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
const char *msg)
{
int ret;
unsigned long stamp;
iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
/* be sure to flush this to the card */
wmb();
stamp = jiffies + 1 * HZ;
/* wait for card */
do {
/* DPRAM_FCT_HOST is _not_ aligned */
ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
(ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
/* don't have any cached variables */
rmb();
if (ret == RES_OK)
/* read return-value now */
return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
if ((ret != vector) || time_after(jiffies, stamp))
break;
/* process context => relax */
usleep_range(500, 10000);
} while (1);
ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
return ret;
}
static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
{
int ret;
ret = _softing_fct_cmd(card, cmd, 0, msg);
if (ret > 0) {
dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
ret = -EIO;
}
return ret;
}
int softing_bootloader_command(struct softing *card, int16_t cmd,
const char *msg)
{
int ret;
unsigned long stamp;
iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
/* be sure to flush this to the card */
wmb();
stamp = jiffies + 3 * HZ;
/* wait for card */
do {
ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
/* don't have any cached variables */
rmb();
if (ret == RES_OK)
return 0;
if (time_after(jiffies, stamp))
break;
/* process context => relax */
usleep_range(500, 10000);
} while (!signal_pending(current));
ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
return ret;
}
static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
uint16_t *plen, const uint8_t **pdat)
{
uint16_t checksum[2];
const uint8_t *mem;
const uint8_t *end;
/*
* firmware records are a binary, unaligned stream composed of:
* uint16_t type;
* uint32_t addr;
* uint16_t len;
* uint8_t dat[len];
* uint16_t checksum;
* all values in little endian.
* We could define a struct for this, with __attribute__((packed)),
* but would that solve the alignment in _all_ cases (cfr. the
* struct itself may be an odd address)?
*
* I chose to use leXX_to_cpup() since this solves both
* endianness & alignment.
*/
mem = *pmem;
*ptype = le16_to_cpup((void *)&mem[0]);
*paddr = le32_to_cpup((void *)&mem[2]);
*plen = le16_to_cpup((void *)&mem[6]);
*pdat = &mem[8];
/* verify checksum */
end = &mem[8 + *plen];
checksum[0] = le16_to_cpup((void *)end);
for (checksum[1] = 0; mem < end; ++mem)
checksum[1] += *mem;
if (checksum[0] != checksum[1])
return -EINVAL;
/* increment */
*pmem += 10 + *plen;
return 0;
}
int softing_load_fw(const char *file, struct softing *card,
__iomem uint8_t *dpram, unsigned int size, int offset)
{
const struct firmware *fw;
int ret;
const uint8_t *mem, *end, *dat;
uint16_t type, len;
uint32_t addr;
uint8_t *buf = NULL, *new_buf;
int buflen = 0;
int8_t type_end = 0;
ret = request_firmware(&fw, file, &card->pdev->dev);
if (ret < 0)
return ret;
dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
", offset %c0x%04x\n",
card->pdat->name, file, (unsigned int)fw->size,
(offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
/* parse the firmware */
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type != 0xffff)
goto failed;
if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
ret = -EINVAL;
goto failed;
}
/* ok, we had a header */
while (mem < end) {
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type == 3) {
/* start address, not used here */
continue;
} else if (type == 1) {
/* eof */
type_end = 1;
break;
} else if (type != 0) {
ret = -EINVAL;
goto failed;
}
if ((addr + len + offset) > size)
goto failed;
memcpy_toio(&dpram[addr + offset], dat, len);
/* be sure to flush caches from IO space */
mb();
if (len > buflen) {
/* align buflen */
buflen = (len + (1024-1)) & ~(1024-1);
new_buf = krealloc(buf, buflen, GFP_KERNEL);
if (!new_buf) {
ret = -ENOMEM;
goto failed;
}
buf = new_buf;
}
/* verify record data */
memcpy_fromio(buf, &dpram[addr + offset], len);
if (memcmp(buf, dat, len)) {
/* is not ok */
dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
ret = -EIO;
goto failed;
}
}
if (!type_end)
/* no end record seen */
goto failed;
ret = 0;
failed:
kfree(buf);
release_firmware(fw);
if (ret < 0)
dev_info(&card->pdev->dev, "firmware %s failed\n", file);
return ret;
}
int softing_load_app_fw(const char *file, struct softing *card)
{
const struct firmware *fw;
const uint8_t *mem, *end, *dat;
int ret, j;
uint16_t type, len;
uint32_t addr, start_addr = 0;
unsigned int sum, rx_sum;
int8_t type_end = 0, type_entrypoint = 0;
ret = request_firmware(&fw, file, &card->pdev->dev);
if (ret) {
dev_alert(&card->pdev->dev, "request_firmware(%s) got %i\n",
file, ret);
return ret;
}
dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
file, (unsigned long)fw->size);
/* parse the firmware */
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret)
goto failed;
ret = -EINVAL;
if (type != 0xffff) {
dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
type);
goto failed;
}
if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
len, dat);
goto failed;
}
/* ok, we had a header */
while (mem < end) {
ret = fw_parse(&mem, &type, &addr, &len, &dat);
if (ret)
goto failed;
if (type == 3) {
/* start address */
start_addr = addr;
type_entrypoint = 1;
continue;
} else if (type == 1) {
/* eof */
type_end = 1;
break;
} else if (type != 0) {
dev_alert(&card->pdev->dev,
"unknown record type 0x%04x\n", type);
ret = -EINVAL;
goto failed;
}
/* regualar data */
for (sum = 0, j = 0; j < len; ++j)
sum += dat[j];
/* work in 16bit (target) */
sum &= 0xffff;
memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
iowrite32(card->pdat->app.offs + card->pdat->app.addr,
&card->dpram[DPRAM_COMMAND + 2]);
iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
ret = softing_bootloader_command(card, 1, "loading app.");
if (ret < 0)
goto failed;
/* verify checksum */
rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
if (rx_sum != sum) {
dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
ret = -EIO;
goto failed;
}
}
if (!type_end || !type_entrypoint)
goto failed;
/* start application in card */
iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
ret = softing_bootloader_command(card, 3, "start app.");
if (ret < 0)
goto failed;
ret = 0;
failed:
release_firmware(fw);
if (ret < 0)
dev_info(&card->pdev->dev, "firmware %s failed\n", file);
return ret;
}
static int softing_reset_chip(struct softing *card)
{
int ret;
do {
/* reset chip */
iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
iowrite8(1, &card->dpram[DPRAM_RESET]);
iowrite8(0, &card->dpram[DPRAM_RESET+1]);
ret = softing_fct_cmd(card, 0, "reset_can");
if (!ret)
break;
if (signal_pending(current))
/* don't wait any longer */
break;
} while (1);
card->tx.pending = 0;
return ret;
}
int softing_chip_poweron(struct softing *card)
{
int ret;
/* sync */
ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
if (ret < 0)
goto failed;
ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
if (ret < 0)
goto failed;
ret = softing_reset_chip(card);
if (ret < 0)
goto failed;
/* get_serial */
ret = softing_fct_cmd(card, 43, "get_serial_number");
if (ret < 0)
goto failed;
card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
/* get_version */
ret = softing_fct_cmd(card, 12, "get_version");
if (ret < 0)
goto failed;
card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
return 0;
failed:
return ret;
}
static void softing_initialize_timestamp(struct softing *card)
{
uint64_t ovf;
card->ts_ref = ktime_get();
/* 16MHz is the reference */
ovf = 0x100000000ULL * 16;
do_div(ovf, card->pdat->freq ?: 16);
card->ts_overflow = ktime_add_us(ktime_set(0, 0), ovf);
}
ktime_t softing_raw2ktime(struct softing *card, u32 raw)
{
uint64_t rawl;
ktime_t now, real_offset;
ktime_t target;
ktime_t tmp;
now = ktime_get();
real_offset = ktime_sub(ktime_get_real(), now);
/* find nsec from card */
rawl = raw * 16;
do_div(rawl, card->pdat->freq ?: 16);
target = ktime_add_us(card->ts_ref, rawl);
/* test for overflows */
tmp = ktime_add(target, card->ts_overflow);
while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
target = tmp;
tmp = ktime_add(target, card->ts_overflow);
}
return ktime_add(target, real_offset);
}
static inline int softing_error_reporting(struct net_device *netdev)
{
struct softing_priv *priv = netdev_priv(netdev);
return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
? 1 : 0;
}
int softing_startstop(struct net_device *dev, int up)
{
int ret;
struct softing *card;
struct softing_priv *priv;
struct net_device *netdev;
int bus_bitmask_start;
int j, error_reporting;
struct can_frame msg;
const struct can_bittiming *bt;
priv = netdev_priv(dev);
card = priv->card;
if (!card->fw.up)
return -EIO;
ret = mutex_lock_interruptible(&card->fw.lock);
if (ret)
return ret;
bus_bitmask_start = 0;
if (dev && up)
/* prepare to start this bus as well */
bus_bitmask_start |= (1 << priv->index);
/* bring netdevs down */
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
netdev = card->net[j];
if (!netdev)
continue;
priv = netdev_priv(netdev);
if (dev != netdev)
netif_stop_queue(netdev);
if (netif_running(netdev)) {
if (dev != netdev)
bus_bitmask_start |= (1 << j);
priv->tx.pending = 0;
priv->tx.echo_put = 0;
priv->tx.echo_get = 0;
/*
* this bus' may just have called open_candev()
* which is rather stupid to call close_candev()
* already
* but we may come here from busoff recovery too
* in which case the echo_skb _needs_ flushing too.
* just be sure to call open_candev() again
*/
close_candev(netdev);
}
priv->can.state = CAN_STATE_STOPPED;
}
card->tx.pending = 0;
softing_enable_irq(card, 0);
ret = softing_reset_chip(card);
if (ret)
goto failed;
if (!bus_bitmask_start)
/* no busses to be brought up */
goto card_done;
if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
&& (softing_error_reporting(card->net[0])
!= softing_error_reporting(card->net[1]))) {
dev_alert(&card->pdev->dev,
"err_reporting flag differs for busses\n");
goto invalid;
}
error_reporting = 0;
if (bus_bitmask_start & 1) {
netdev = card->net[0];
priv = netdev_priv(netdev);
error_reporting += softing_error_reporting(netdev);
/* init chip 1 */
bt = &priv->can.bittiming;
iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
iowrite16(bt->phase_seg1 + bt->prop_seg,
&card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
&card->dpram[DPRAM_FCT_PARAM + 10]);
ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
if (ret < 0)
goto failed;
/* set mode */
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
ret = softing_fct_cmd(card, 3, "set_mode[0]");
if (ret < 0)
goto failed;
/* set filter */
/* 11bit id & mask */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
/* 29bit id.lo & mask.lo & id.hi & mask.hi */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
ret = softing_fct_cmd(card, 7, "set_filter[0]");
if (ret < 0)
goto failed;
/* set output control */
iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
ret = softing_fct_cmd(card, 5, "set_output[0]");
if (ret < 0)
goto failed;
}
if (bus_bitmask_start & 2) {
netdev = card->net[1];
priv = netdev_priv(netdev);
error_reporting += softing_error_reporting(netdev);
/* init chip2 */
bt = &priv->can.bittiming;
iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
iowrite16(bt->phase_seg1 + bt->prop_seg,
&card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
&card->dpram[DPRAM_FCT_PARAM + 10]);
ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
if (ret < 0)
goto failed;
/* set mode2 */
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
ret = softing_fct_cmd(card, 4, "set_mode[1]");
if (ret < 0)
goto failed;
/* set filter2 */
/* 11bit id & mask */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
/* 29bit id.lo & mask.lo & id.hi & mask.hi */
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
ret = softing_fct_cmd(card, 8, "set_filter[1]");
if (ret < 0)
goto failed;
/* set output control2 */
iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
ret = softing_fct_cmd(card, 6, "set_output[1]");
if (ret < 0)
goto failed;
}
/* enable_error_frame */
/*
* Error reporting is switched off at the moment since
* the receiving of them is not yet 100% verified
* This should be enabled sooner or later
*
if (error_reporting) {
ret = softing_fct_cmd(card, 51, "enable_error_frame");
if (ret < 0)
goto failed;
}
*/
/* initialize interface */
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
ret = softing_fct_cmd(card, 17, "initialize_interface");
if (ret < 0)
goto failed;
/* enable_fifo */
ret = softing_fct_cmd(card, 36, "enable_fifo");
if (ret < 0)
goto failed;
/* enable fifo tx ack */
ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
if (ret < 0)
goto failed;
/* enable fifo tx ack2 */
ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
if (ret < 0)
goto failed;
/* start_chip */
ret = softing_fct_cmd(card, 11, "start_chip");
if (ret < 0)
goto failed;
iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
if (card->pdat->generation < 2) {
iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
/* flush the DPRAM caches */
wmb();
}
softing_initialize_timestamp(card);
/*
* do socketcan notifications/status changes
* from here, no errors should occur, or the failed: part
* must be reviewed
*/
memset(&msg, 0, sizeof(msg));
msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
msg.can_dlc = CAN_ERR_DLC;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (!(bus_bitmask_start & (1 << j)))
continue;
netdev = card->net[j];
if (!netdev)
continue;
priv = netdev_priv(netdev);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
open_candev(netdev);
if (dev != netdev) {
/* notify other busses on the restart */
softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
++priv->can.can_stats.restarts;
}
netif_wake_queue(netdev);
}
/* enable interrupts */
ret = softing_enable_irq(card, 1);
if (ret)
goto failed;
card_done:
mutex_unlock(&card->fw.lock);
return 0;
invalid:
ret = -EINVAL;
failed:
softing_enable_irq(card, 0);
softing_reset_chip(card);
mutex_unlock(&card->fw.lock);
/* bring all other interfaces down */
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
netdev = card->net[j];
if (!netdev)
continue;
dev_close(netdev);
}
return ret;
}
int softing_default_output(struct net_device *netdev)
{
struct softing_priv *priv = netdev_priv(netdev);
struct softing *card = priv->card;
switch (priv->chip) {
case 1000:
return (card->pdat->generation < 2) ? 0xfb : 0xfa;
case 5:
return 0x60;
default:
return 0x40;
}
}

View file

@ -0,0 +1,870 @@
/*
* Copyright (C) 2008-2010
*
* - Kurt Van Dijck, EIA Electronics
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include "softing.h"
#define TX_ECHO_SKB_MAX (((TXMAX+1)/2)-1)
/*
* test is a specific CAN netdev
* is online (ie. up 'n running, not sleeping, not busoff
*/
static inline int canif_is_active(struct net_device *netdev)
{
struct can_priv *can = netdev_priv(netdev);
if (!netif_running(netdev))
return 0;
return (can->state <= CAN_STATE_ERROR_PASSIVE);
}
/* reset DPRAM */
static inline void softing_set_reset_dpram(struct softing *card)
{
if (card->pdat->generation >= 2) {
spin_lock_bh(&card->spin);
iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) & ~1,
&card->dpram[DPRAM_V2_RESET]);
spin_unlock_bh(&card->spin);
}
}
static inline void softing_clr_reset_dpram(struct softing *card)
{
if (card->pdat->generation >= 2) {
spin_lock_bh(&card->spin);
iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) | 1,
&card->dpram[DPRAM_V2_RESET]);
spin_unlock_bh(&card->spin);
}
}
/* trigger the tx queue-ing */
static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct softing_priv *priv = netdev_priv(dev);
struct softing *card = priv->card;
int ret;
uint8_t *ptr;
uint8_t fifo_wr, fifo_rd;
struct can_frame *cf = (struct can_frame *)skb->data;
uint8_t buf[DPRAM_TX_SIZE];
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
spin_lock(&card->spin);
ret = NETDEV_TX_BUSY;
if (!card->fw.up ||
(card->tx.pending >= TXMAX) ||
(priv->tx.pending >= TX_ECHO_SKB_MAX))
goto xmit_done;
fifo_wr = ioread8(&card->dpram[DPRAM_TX_WR]);
fifo_rd = ioread8(&card->dpram[DPRAM_TX_RD]);
if (fifo_wr == fifo_rd)
/* fifo full */
goto xmit_done;
memset(buf, 0, sizeof(buf));
ptr = buf;
*ptr = CMD_TX;
if (cf->can_id & CAN_RTR_FLAG)
*ptr |= CMD_RTR;
if (cf->can_id & CAN_EFF_FLAG)
*ptr |= CMD_XTD;
if (priv->index)
*ptr |= CMD_BUS2;
++ptr;
*ptr++ = cf->can_dlc;
*ptr++ = (cf->can_id >> 0);
*ptr++ = (cf->can_id >> 8);
if (cf->can_id & CAN_EFF_FLAG) {
*ptr++ = (cf->can_id >> 16);
*ptr++ = (cf->can_id >> 24);
} else {
/* increment 1, not 2 as you might think */
ptr += 1;
}
if (!(cf->can_id & CAN_RTR_FLAG))
memcpy(ptr, &cf->data[0], cf->can_dlc);
memcpy_toio(&card->dpram[DPRAM_TX + DPRAM_TX_SIZE * fifo_wr],
buf, DPRAM_TX_SIZE);
if (++fifo_wr >= DPRAM_TX_CNT)
fifo_wr = 0;
iowrite8(fifo_wr, &card->dpram[DPRAM_TX_WR]);
card->tx.last_bus = priv->index;
++card->tx.pending;
++priv->tx.pending;
can_put_echo_skb(skb, dev, priv->tx.echo_put);
++priv->tx.echo_put;
if (priv->tx.echo_put >= TX_ECHO_SKB_MAX)
priv->tx.echo_put = 0;
/* can_put_echo_skb() saves the skb, safe to return TX_OK */
ret = NETDEV_TX_OK;
xmit_done:
spin_unlock(&card->spin);
if (card->tx.pending >= TXMAX) {
int j;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (card->net[j])
netif_stop_queue(card->net[j]);
}
}
if (ret != NETDEV_TX_OK)
netif_stop_queue(dev);
return ret;
}
/*
* shortcut for skb delivery
*/
int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
ktime_t ktime)
{
struct sk_buff *skb;
struct can_frame *cf;
skb = alloc_can_skb(netdev, &cf);
if (!skb)
return -ENOMEM;
memcpy(cf, msg, sizeof(*msg));
skb->tstamp = ktime;
return netif_rx(skb);
}
/*
* softing_handle_1
* pop 1 entry from the DPRAM queue, and process
*/
static int softing_handle_1(struct softing *card)
{
struct net_device *netdev;
struct softing_priv *priv;
ktime_t ktime;
struct can_frame msg;
int cnt = 0, lost_msg;
uint8_t fifo_rd, fifo_wr, cmd;
uint8_t *ptr;
uint32_t tmp_u32;
uint8_t buf[DPRAM_RX_SIZE];
memset(&msg, 0, sizeof(msg));
/* test for lost msgs */
lost_msg = ioread8(&card->dpram[DPRAM_RX_LOST]);
if (lost_msg) {
int j;
/* reset condition */
iowrite8(0, &card->dpram[DPRAM_RX_LOST]);
/* prepare msg */
msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
msg.can_dlc = CAN_ERR_DLC;
msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
/*
* service to all busses, we don't know which it was applicable
* but only service busses that are online
*/
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
netdev = card->net[j];
if (!netdev)
continue;
if (!canif_is_active(netdev))
/* a dead bus has no overflows */
continue;
++netdev->stats.rx_over_errors;
softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
}
/* prepare for other use */
memset(&msg, 0, sizeof(msg));
++cnt;
}
fifo_rd = ioread8(&card->dpram[DPRAM_RX_RD]);
fifo_wr = ioread8(&card->dpram[DPRAM_RX_WR]);
if (++fifo_rd >= DPRAM_RX_CNT)
fifo_rd = 0;
if (fifo_wr == fifo_rd)
return cnt;
memcpy_fromio(buf, &card->dpram[DPRAM_RX + DPRAM_RX_SIZE*fifo_rd],
DPRAM_RX_SIZE);
mb();
/* trigger dual port RAM */
iowrite8(fifo_rd, &card->dpram[DPRAM_RX_RD]);
ptr = buf;
cmd = *ptr++;
if (cmd == 0xff)
/* not quite useful, probably the card has got out */
return 0;
netdev = card->net[0];
if (cmd & CMD_BUS2)
netdev = card->net[1];
priv = netdev_priv(netdev);
if (cmd & CMD_ERR) {
uint8_t can_state, state;
state = *ptr++;
msg.can_id = CAN_ERR_FLAG;
msg.can_dlc = CAN_ERR_DLC;
if (state & SF_MASK_BUSOFF) {
can_state = CAN_STATE_BUS_OFF;
msg.can_id |= CAN_ERR_BUSOFF;
state = STATE_BUSOFF;
} else if (state & SF_MASK_EPASSIVE) {
can_state = CAN_STATE_ERROR_PASSIVE;
msg.can_id |= CAN_ERR_CRTL;
msg.data[1] = CAN_ERR_CRTL_TX_PASSIVE;
state = STATE_EPASSIVE;
} else {
can_state = CAN_STATE_ERROR_ACTIVE;
msg.can_id |= CAN_ERR_CRTL;
state = STATE_EACTIVE;
}
/* update DPRAM */
iowrite8(state, &card->dpram[priv->index ?
DPRAM_INFO_BUSSTATE2 : DPRAM_INFO_BUSSTATE]);
/* timestamp */
tmp_u32 = le32_to_cpup((void *)ptr);
ptr += 4;
ktime = softing_raw2ktime(card, tmp_u32);
++netdev->stats.rx_errors;
/* update internal status */
if (can_state != priv->can.state) {
priv->can.state = can_state;
if (can_state == CAN_STATE_ERROR_PASSIVE)
++priv->can.can_stats.error_passive;
else if (can_state == CAN_STATE_BUS_OFF) {
/* this calls can_close_cleanup() */
can_bus_off(netdev);
netif_stop_queue(netdev);
}
/* trigger socketcan */
softing_netdev_rx(netdev, &msg, ktime);
}
} else {
if (cmd & CMD_RTR)
msg.can_id |= CAN_RTR_FLAG;
msg.can_dlc = get_can_dlc(*ptr++);
if (cmd & CMD_XTD) {
msg.can_id |= CAN_EFF_FLAG;
msg.can_id |= le32_to_cpup((void *)ptr);
ptr += 4;
} else {
msg.can_id |= le16_to_cpup((void *)ptr);
ptr += 2;
}
/* timestamp */
tmp_u32 = le32_to_cpup((void *)ptr);
ptr += 4;
ktime = softing_raw2ktime(card, tmp_u32);
if (!(msg.can_id & CAN_RTR_FLAG))
memcpy(&msg.data[0], ptr, 8);
ptr += 8;
/* update socket */
if (cmd & CMD_ACK) {
/* acknowledge, was tx msg */
struct sk_buff *skb;
skb = priv->can.echo_skb[priv->tx.echo_get];
if (skb)
skb->tstamp = ktime;
can_get_echo_skb(netdev, priv->tx.echo_get);
++priv->tx.echo_get;
if (priv->tx.echo_get >= TX_ECHO_SKB_MAX)
priv->tx.echo_get = 0;
if (priv->tx.pending)
--priv->tx.pending;
if (card->tx.pending)
--card->tx.pending;
++netdev->stats.tx_packets;
if (!(msg.can_id & CAN_RTR_FLAG))
netdev->stats.tx_bytes += msg.can_dlc;
} else {
int ret;
ret = softing_netdev_rx(netdev, &msg, ktime);
if (ret == NET_RX_SUCCESS) {
++netdev->stats.rx_packets;
if (!(msg.can_id & CAN_RTR_FLAG))
netdev->stats.rx_bytes += msg.can_dlc;
} else {
++netdev->stats.rx_dropped;
}
}
}
++cnt;
return cnt;
}
/*
* real interrupt handler
*/
static irqreturn_t softing_irq_thread(int irq, void *dev_id)
{
struct softing *card = (struct softing *)dev_id;
struct net_device *netdev;
struct softing_priv *priv;
int j, offset, work_done;
work_done = 0;
spin_lock_bh(&card->spin);
while (softing_handle_1(card) > 0) {
++card->irq.svc_count;
++work_done;
}
spin_unlock_bh(&card->spin);
/* resume tx queue's */
offset = card->tx.last_bus;
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (card->tx.pending >= TXMAX)
break;
netdev = card->net[(j + offset + 1) % card->pdat->nbus];
if (!netdev)
continue;
priv = netdev_priv(netdev);
if (!canif_is_active(netdev))
/* it makes no sense to wake dead busses */
continue;
if (priv->tx.pending >= TX_ECHO_SKB_MAX)
continue;
++work_done;
netif_wake_queue(netdev);
}
return work_done ? IRQ_HANDLED : IRQ_NONE;
}
/*
* interrupt routines:
* schedule the 'real interrupt handler'
*/
static irqreturn_t softing_irq_v2(int irq, void *dev_id)
{
struct softing *card = (struct softing *)dev_id;
uint8_t ir;
ir = ioread8(&card->dpram[DPRAM_V2_IRQ_TOHOST]);
iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
return (1 == ir) ? IRQ_WAKE_THREAD : IRQ_NONE;
}
static irqreturn_t softing_irq_v1(int irq, void *dev_id)
{
struct softing *card = (struct softing *)dev_id;
uint8_t ir;
ir = ioread8(&card->dpram[DPRAM_IRQ_TOHOST]);
iowrite8(0, &card->dpram[DPRAM_IRQ_TOHOST]);
return ir ? IRQ_WAKE_THREAD : IRQ_NONE;
}
/*
* netdev/candev inter-operability
*/
static int softing_netdev_open(struct net_device *ndev)
{
int ret;
/* check or determine and set bittime */
ret = open_candev(ndev);
if (!ret)
ret = softing_startstop(ndev, 1);
return ret;
}
static int softing_netdev_stop(struct net_device *ndev)
{
int ret;
netif_stop_queue(ndev);
/* softing cycle does close_candev() */
ret = softing_startstop(ndev, 0);
return ret;
}
static int softing_candev_set_mode(struct net_device *ndev, enum can_mode mode)
{
int ret;
switch (mode) {
case CAN_MODE_START:
/* softing_startstop does close_candev() */
ret = softing_startstop(ndev, 1);
return ret;
case CAN_MODE_STOP:
case CAN_MODE_SLEEP:
return -EOPNOTSUPP;
}
return 0;
}
/*
* Softing device management helpers
*/
int softing_enable_irq(struct softing *card, int enable)
{
int ret;
if (!card->irq.nr) {
return 0;
} else if (card->irq.requested && !enable) {
free_irq(card->irq.nr, card);
card->irq.requested = 0;
} else if (!card->irq.requested && enable) {
ret = request_threaded_irq(card->irq.nr,
(card->pdat->generation >= 2) ?
softing_irq_v2 : softing_irq_v1,
softing_irq_thread, IRQF_SHARED,
dev_name(&card->pdev->dev), card);
if (ret) {
dev_alert(&card->pdev->dev,
"request_threaded_irq(%u) failed\n",
card->irq.nr);
return ret;
}
card->irq.requested = 1;
}
return 0;
}
static void softing_card_shutdown(struct softing *card)
{
int fw_up = 0;
if (mutex_lock_interruptible(&card->fw.lock))
/* return -ERESTARTSYS */;
fw_up = card->fw.up;
card->fw.up = 0;
if (card->irq.requested && card->irq.nr) {
free_irq(card->irq.nr, card);
card->irq.requested = 0;
}
if (fw_up) {
if (card->pdat->enable_irq)
card->pdat->enable_irq(card->pdev, 0);
softing_set_reset_dpram(card);
if (card->pdat->reset)
card->pdat->reset(card->pdev, 1);
}
mutex_unlock(&card->fw.lock);
}
static int softing_card_boot(struct softing *card)
{
int ret, j;
static const uint8_t stream[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
unsigned char back[sizeof(stream)];
if (mutex_lock_interruptible(&card->fw.lock))
return -ERESTARTSYS;
if (card->fw.up) {
mutex_unlock(&card->fw.lock);
return 0;
}
/* reset board */
if (card->pdat->enable_irq)
card->pdat->enable_irq(card->pdev, 1);
/* boot card */
softing_set_reset_dpram(card);
if (card->pdat->reset)
card->pdat->reset(card->pdev, 1);
for (j = 0; (j + sizeof(stream)) < card->dpram_size;
j += sizeof(stream)) {
memcpy_toio(&card->dpram[j], stream, sizeof(stream));
/* flush IO cache */
mb();
memcpy_fromio(back, &card->dpram[j], sizeof(stream));
if (!memcmp(back, stream, sizeof(stream)))
continue;
/* memory is not equal */
dev_alert(&card->pdev->dev, "dpram failed at 0x%04x\n", j);
ret = -EIO;
goto failed;
}
wmb();
/* load boot firmware */
ret = softing_load_fw(card->pdat->boot.fw, card, card->dpram,
card->dpram_size,
card->pdat->boot.offs - card->pdat->boot.addr);
if (ret < 0)
goto failed;
/* load loader firmware */
ret = softing_load_fw(card->pdat->load.fw, card, card->dpram,
card->dpram_size,
card->pdat->load.offs - card->pdat->load.addr);
if (ret < 0)
goto failed;
if (card->pdat->reset)
card->pdat->reset(card->pdev, 0);
softing_clr_reset_dpram(card);
ret = softing_bootloader_command(card, 0, "card boot");
if (ret < 0)
goto failed;
ret = softing_load_app_fw(card->pdat->app.fw, card);
if (ret < 0)
goto failed;
ret = softing_chip_poweron(card);
if (ret < 0)
goto failed;
card->fw.up = 1;
mutex_unlock(&card->fw.lock);
return 0;
failed:
card->fw.up = 0;
if (card->pdat->enable_irq)
card->pdat->enable_irq(card->pdev, 0);
softing_set_reset_dpram(card);
if (card->pdat->reset)
card->pdat->reset(card->pdev, 1);
mutex_unlock(&card->fw.lock);
return ret;
}
/*
* netdev sysfs
*/
static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "%i\n", priv->chip);
}
static ssize_t show_output(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
return sprintf(buf, "0x%02x\n", priv->output);
}
static ssize_t store_output(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct net_device *ndev = to_net_dev(dev);
struct softing_priv *priv = netdev2softing(ndev);
struct softing *card = priv->card;
unsigned long val;
int ret;
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
val &= 0xFF;
ret = mutex_lock_interruptible(&card->fw.lock);
if (ret)
return -ERESTARTSYS;
if (netif_running(ndev)) {
mutex_unlock(&card->fw.lock);
return -EBUSY;
}
priv->output = val;
mutex_unlock(&card->fw.lock);
return count;
}
static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
static const struct attribute *const netdev_sysfs_attrs[] = {
&dev_attr_chip.attr,
&dev_attr_output.attr,
NULL,
};
static const struct attribute_group netdev_sysfs_group = {
.name = NULL,
.attrs = (struct attribute **)netdev_sysfs_attrs,
};
static const struct net_device_ops softing_netdev_ops = {
.ndo_open = softing_netdev_open,
.ndo_stop = softing_netdev_stop,
.ndo_start_xmit = softing_netdev_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const softing_btr_const = {
.name = "softing",
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4, /* overruled */
.brp_min = 1,
.brp_max = 32, /* overruled */
.brp_inc = 1,
};
static struct net_device *softing_netdev_create(struct softing *card,
uint16_t chip_id)
{
struct net_device *netdev;
struct softing_priv *priv;
netdev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
if (!netdev) {
dev_alert(&card->pdev->dev, "alloc_candev failed\n");
return NULL;
}
priv = netdev_priv(netdev);
priv->netdev = netdev;
priv->card = card;
memcpy(&priv->btr_const, &softing_btr_const, sizeof(priv->btr_const));
priv->btr_const.brp_max = card->pdat->max_brp;
priv->btr_const.sjw_max = card->pdat->max_sjw;
priv->can.bittiming_const = &priv->btr_const;
priv->can.clock.freq = 8000000;
priv->chip = chip_id;
priv->output = softing_default_output(netdev);
SET_NETDEV_DEV(netdev, &card->pdev->dev);
netdev->flags |= IFF_ECHO;
netdev->netdev_ops = &softing_netdev_ops;
priv->can.do_set_mode = softing_candev_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
return netdev;
}
static int softing_netdev_register(struct net_device *netdev)
{
int ret;
ret = register_candev(netdev);
if (ret) {
dev_alert(&netdev->dev, "register failed\n");
return ret;
}
if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0)
netdev_alert(netdev, "sysfs group failed\n");
return 0;
}
static void softing_netdev_cleanup(struct net_device *netdev)
{
sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group);
unregister_candev(netdev);
free_candev(netdev);
}
/*
* sysfs for Platform device
*/
#define DEV_ATTR_RO(name, member) \
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
return sprintf(buf, "%u\n", card->member); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
#define DEV_ATTR_RO_STR(name, member) \
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
return sprintf(buf, "%s\n", card->member); \
} \
static DEVICE_ATTR(name, 0444, show_##name, NULL)
DEV_ATTR_RO(serial, id.serial);
DEV_ATTR_RO_STR(firmware, pdat->app.fw);
DEV_ATTR_RO(firmware_version, id.fw_version);
DEV_ATTR_RO_STR(hardware, pdat->name);
DEV_ATTR_RO(hardware_version, id.hw_version);
DEV_ATTR_RO(license, id.license);
static struct attribute *softing_pdev_attrs[] = {
&dev_attr_serial.attr,
&dev_attr_firmware.attr,
&dev_attr_firmware_version.attr,
&dev_attr_hardware.attr,
&dev_attr_hardware_version.attr,
&dev_attr_license.attr,
NULL,
};
static const struct attribute_group softing_pdev_group = {
.name = NULL,
.attrs = softing_pdev_attrs,
};
/*
* platform driver
*/
static int softing_pdev_remove(struct platform_device *pdev)
{
struct softing *card = platform_get_drvdata(pdev);
int j;
/* first, disable card*/
softing_card_shutdown(card);
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (!card->net[j])
continue;
softing_netdev_cleanup(card->net[j]);
card->net[j] = NULL;
}
sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
iounmap(card->dpram);
kfree(card);
return 0;
}
static int softing_pdev_probe(struct platform_device *pdev)
{
const struct softing_platform_data *pdat = dev_get_platdata(&pdev->dev);
struct softing *card;
struct net_device *netdev;
struct softing_priv *priv;
struct resource *pres;
int ret;
int j;
if (!pdat) {
dev_warn(&pdev->dev, "no platform data\n");
return -EINVAL;
}
if (pdat->nbus > ARRAY_SIZE(card->net)) {
dev_warn(&pdev->dev, "%u nets??\n", pdat->nbus);
return -EINVAL;
}
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
card->pdat = pdat;
card->pdev = pdev;
platform_set_drvdata(pdev, card);
mutex_init(&card->fw.lock);
spin_lock_init(&card->spin);
ret = -EINVAL;
pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!pres)
goto platform_resource_failed;
card->dpram_phys = pres->start;
card->dpram_size = resource_size(pres);
card->dpram = ioremap_nocache(card->dpram_phys, card->dpram_size);
if (!card->dpram) {
dev_alert(&card->pdev->dev, "dpram ioremap failed\n");
goto ioremap_failed;
}
pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (pres)
card->irq.nr = pres->start;
/* reset card */
ret = softing_card_boot(card);
if (ret < 0) {
dev_alert(&pdev->dev, "failed to boot\n");
goto boot_failed;
}
/* only now, the chip's are known */
card->id.freq = card->pdat->freq;
ret = sysfs_create_group(&pdev->dev.kobj, &softing_pdev_group);
if (ret < 0) {
dev_alert(&card->pdev->dev, "sysfs failed\n");
goto sysfs_failed;
}
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
card->net[j] = netdev =
softing_netdev_create(card, card->id.chip[j]);
if (!netdev) {
dev_alert(&pdev->dev, "failed to make can[%i]", j);
ret = -ENOMEM;
goto netdev_failed;
}
netdev->dev_id = j;
priv = netdev_priv(card->net[j]);
priv->index = j;
ret = softing_netdev_register(netdev);
if (ret) {
free_candev(netdev);
card->net[j] = NULL;
dev_alert(&card->pdev->dev,
"failed to register can[%i]\n", j);
goto netdev_failed;
}
}
dev_info(&card->pdev->dev, "%s ready.\n", card->pdat->name);
return 0;
netdev_failed:
for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
if (!card->net[j])
continue;
softing_netdev_cleanup(card->net[j]);
}
sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
sysfs_failed:
softing_card_shutdown(card);
boot_failed:
iounmap(card->dpram);
ioremap_failed:
platform_resource_failed:
kfree(card);
return ret;
}
static struct platform_driver softing_driver = {
.driver = {
.name = "softing",
.owner = THIS_MODULE,
},
.probe = softing_pdev_probe,
.remove = softing_pdev_remove,
};
module_platform_driver(softing_driver);
MODULE_ALIAS("platform:softing");
MODULE_DESCRIPTION("Softing DPRAM CAN driver");
MODULE_AUTHOR("Kurt Van Dijck <kurt.van.dijck@eia.be>");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,40 @@
#include <linux/platform_device.h>
#ifndef _SOFTING_DEVICE_H_
#define _SOFTING_DEVICE_H_
/* softing firmware directory prefix */
#define fw_dir "softing-4.6/"
struct softing_platform_data {
unsigned int manf;
unsigned int prod;
/*
* generation
* 1st with NEC or SJA1000
* 8bit, exclusive interrupt, ...
* 2nd only SJA1000
* 16bit, shared interrupt
*/
int generation;
int nbus; /* # busses on device */
unsigned int freq; /* operating frequency in Hz */
unsigned int max_brp;
unsigned int max_sjw;
unsigned long dpram_size;
const char *name;
struct {
unsigned long offs;
unsigned long addr;
const char *fw;
} boot, load, app;
/*
* reset() function
* bring pdev in or out of reset, depending on value
*/
int (*reset)(struct platform_device *pdev, int value);
int (*enable_irq)(struct platform_device *pdev, int value);
};
#endif

View file

@ -0,0 +1,10 @@
menu "CAN SPI interfaces"
depends on SPI
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
endmenu

View file

@ -0,0 +1,6 @@
#
# Makefile for the Linux Controller Area Network SPI drivers.
#
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o

File diff suppressed because it is too large Load diff

1055
drivers/net/can/ti_hecc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,67 @@
menu "CAN USB interfaces"
depends on USB
config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
---help---
This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
config CAN_ESD_USB2
tristate "ESD USB/2 CAN/USB interface"
---help---
This driver supports the CAN-USB/2 interface
from esd electronic system design gmbh (http://www.esd.eu).
config CAN_GS_USB
tristate "Geschwister Schneider UG interfaces"
---help---
This driver supports the Geschwister Schneider USB/CAN devices.
If unsure choose N,
choose Y for built in support,
M to compile as module (module will be named: gs_usb).
config CAN_KVASER_USB
tristate "Kvaser CAN/USB interface"
---help---
This driver adds support for Kvaser CAN/USB devices like Kvaser
Leaf Light.
The driver provides support for the following devices:
- Kvaser Leaf Light
- Kvaser Leaf Professional HS
- Kvaser Leaf SemiPro HS
- Kvaser Leaf Professional LS
- Kvaser Leaf Professional SWC
- Kvaser Leaf Professional LIN
- Kvaser Leaf SemiPro LS
- Kvaser Leaf SemiPro SWC
- Kvaser Memorator II HS/HS
- Kvaser USBcan Professional HS/HS
- Kvaser Leaf Light GI
- Kvaser Leaf Professional HS (OBD-II connector)
- Kvaser Memorator Professional HS/LS
- Kvaser Leaf Light "China"
- Kvaser BlackBird SemiPro
- Kvaser USBcan R
- Kvaser Leaf Light v2
- Kvaser Mini PCI Express HS
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called kvaser_usb.
config CAN_PEAK_USB
tristate "PEAK PCAN-USB/USB Pro interfaces"
---help---
This driver supports the PCAN-USB and PCAN-USB Pro adapters
from PEAK-System Technik (http://www.peak-system.com).
config CAN_8DEV_USB
tristate "8 devices USB2CAN interface"
---help---
This driver supports the USB2CAN interface
from 8 devices (http://www.8devices.com).
endmenu

View file

@ -0,0 +1,10 @@
#
# Makefile for the Linux Controller Area Network USB drivers.
#
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,972 @@
/* CAN driver for Geschwister Schneider USB/CAN devices.
*
* Copyright (C) 2013 Geschwister Schneider Technologie-,
* Entwicklungs- und Vertriebs UG (Haftungsbeschränkt).
*
* Many thanks to all socketcan devs!
*
* 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; version 2 of the License.
*
* 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/init.h>
#include <linux/signal.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
/* Device specific constants */
#define USB_GSUSB_1_VENDOR_ID 0x1d50
#define USB_GSUSB_1_PRODUCT_ID 0x606f
#define GSUSB_ENDPOINT_IN 1
#define GSUSB_ENDPOINT_OUT 2
/* Device specific constants */
enum gs_usb_breq {
GS_USB_BREQ_HOST_FORMAT = 0,
GS_USB_BREQ_BITTIMING,
GS_USB_BREQ_MODE,
GS_USB_BREQ_BERR,
GS_USB_BREQ_BT_CONST,
GS_USB_BREQ_DEVICE_CONFIG
};
enum gs_can_mode {
/* reset a channel. turns it off */
GS_CAN_MODE_RESET = 0,
/* starts a channel */
GS_CAN_MODE_START
};
enum gs_can_state {
GS_CAN_STATE_ERROR_ACTIVE = 0,
GS_CAN_STATE_ERROR_WARNING,
GS_CAN_STATE_ERROR_PASSIVE,
GS_CAN_STATE_BUS_OFF,
GS_CAN_STATE_STOPPED,
GS_CAN_STATE_SLEEPING
};
/* data types passed between host and device */
struct gs_host_config {
u32 byte_order;
} __packed;
/* All data exchanged between host and device is exchanged in host byte order,
* thanks to the struct gs_host_config byte_order member, which is sent first
* to indicate the desired byte order.
*/
struct gs_device_config {
u8 reserved1;
u8 reserved2;
u8 reserved3;
u8 icount;
u32 sw_version;
u32 hw_version;
} __packed;
#define GS_CAN_MODE_NORMAL 0
#define GS_CAN_MODE_LISTEN_ONLY (1<<0)
#define GS_CAN_MODE_LOOP_BACK (1<<1)
#define GS_CAN_MODE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_MODE_ONE_SHOT (1<<3)
struct gs_device_mode {
u32 mode;
u32 flags;
} __packed;
struct gs_device_state {
u32 state;
u32 rxerr;
u32 txerr;
} __packed;
struct gs_device_bittiming {
u32 prop_seg;
u32 phase_seg1;
u32 phase_seg2;
u32 sjw;
u32 brp;
} __packed;
#define GS_CAN_FEATURE_LISTEN_ONLY (1<<0)
#define GS_CAN_FEATURE_LOOP_BACK (1<<1)
#define GS_CAN_FEATURE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_FEATURE_ONE_SHOT (1<<3)
struct gs_device_bt_const {
u32 feature;
u32 fclk_can;
u32 tseg1_min;
u32 tseg1_max;
u32 tseg2_min;
u32 tseg2_max;
u32 sjw_max;
u32 brp_min;
u32 brp_max;
u32 brp_inc;
} __packed;
#define GS_CAN_FLAG_OVERFLOW 1
struct gs_host_frame {
u32 echo_id;
u32 can_id;
u8 can_dlc;
u8 channel;
u8 flags;
u8 reserved;
u8 data[8];
} __packed;
/* The GS USB devices make use of the same flags and masks as in
* linux/can.h and linux/can/error.h, and no additional mapping is necessary.
*/
/* Only send a max of GS_MAX_TX_URBS frames per channel at a time. */
#define GS_MAX_TX_URBS 10
/* Only launch a max of GS_MAX_RX_URBS usb requests at a time. */
#define GS_MAX_RX_URBS 30
/* Maximum number of interfaces the driver supports per device.
* Current hardware only supports 2 interfaces. The future may vary.
*/
#define GS_MAX_INTF 2
struct gs_tx_context {
struct gs_can *dev;
unsigned int echo_id;
};
struct gs_can {
struct can_priv can; /* must be the first member */
struct gs_usb *parent;
struct net_device *netdev;
struct usb_device *udev;
struct usb_interface *iface;
struct can_bittiming_const bt_const;
unsigned int channel; /* channel number */
/* This lock prevents a race condition between xmit and recieve. */
spinlock_t tx_ctx_lock;
struct gs_tx_context tx_context[GS_MAX_TX_URBS];
struct usb_anchor tx_submitted;
atomic_t active_tx_urbs;
};
/* usb interface struct */
struct gs_usb {
struct gs_can *canch[GS_MAX_INTF];
struct usb_anchor rx_submitted;
atomic_t active_channels;
struct usb_device *udev;
};
/* 'allocate' a tx context.
* returns a valid tx context or NULL if there is no space.
*/
static struct gs_tx_context *gs_alloc_tx_context(struct gs_can *dev)
{
int i = 0;
unsigned long flags;
spin_lock_irqsave(&dev->tx_ctx_lock, flags);
for (; i < GS_MAX_TX_URBS; i++) {
if (dev->tx_context[i].echo_id == GS_MAX_TX_URBS) {
dev->tx_context[i].echo_id = i;
spin_unlock_irqrestore(&dev->tx_ctx_lock, flags);
return &dev->tx_context[i];
}
}
spin_unlock_irqrestore(&dev->tx_ctx_lock, flags);
return NULL;
}
/* releases a tx context
*/
static void gs_free_tx_context(struct gs_tx_context *txc)
{
txc->echo_id = GS_MAX_TX_URBS;
}
/* Get a tx context by id.
*/
static struct gs_tx_context *gs_get_tx_context(struct gs_can *dev, unsigned int id)
{
unsigned long flags;
if (id < GS_MAX_TX_URBS) {
spin_lock_irqsave(&dev->tx_ctx_lock, flags);
if (dev->tx_context[id].echo_id == id) {
spin_unlock_irqrestore(&dev->tx_ctx_lock, flags);
return &dev->tx_context[id];
}
spin_unlock_irqrestore(&dev->tx_ctx_lock, flags);
}
return NULL;
}
static int gs_cmd_reset(struct gs_usb *gsusb, struct gs_can *gsdev)
{
struct gs_device_mode *dm;
struct usb_interface *intf = gsdev->iface;
int rc;
dm = kzalloc(sizeof(*dm), GFP_KERNEL);
if (!dm)
return -ENOMEM;
dm->mode = GS_CAN_MODE_RESET;
rc = usb_control_msg(interface_to_usbdev(intf),
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
GS_USB_BREQ_MODE,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
gsdev->channel,
0,
dm,
sizeof(*dm),
1000);
return rc;
}
static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
{
struct can_device_stats *can_stats = &dev->can.can_stats;
if (cf->can_id & CAN_ERR_RESTARTED) {
dev->can.state = CAN_STATE_ERROR_ACTIVE;
can_stats->restarts++;
} else if (cf->can_id & CAN_ERR_BUSOFF) {
dev->can.state = CAN_STATE_BUS_OFF;
can_stats->bus_off++;
} else if (cf->can_id & CAN_ERR_CRTL) {
if ((cf->data[1] & CAN_ERR_CRTL_TX_WARNING) ||
(cf->data[1] & CAN_ERR_CRTL_RX_WARNING)) {
dev->can.state = CAN_STATE_ERROR_WARNING;
can_stats->error_warning++;
} else if ((cf->data[1] & CAN_ERR_CRTL_TX_PASSIVE) ||
(cf->data[1] & CAN_ERR_CRTL_RX_PASSIVE)) {
dev->can.state = CAN_STATE_ERROR_PASSIVE;
can_stats->error_passive++;
} else {
dev->can.state = CAN_STATE_ERROR_ACTIVE;
}
}
}
static void gs_usb_recieve_bulk_callback(struct urb *urb)
{
struct gs_usb *usbcan = urb->context;
struct gs_can *dev;
struct net_device *netdev;
int rc;
struct net_device_stats *stats;
struct gs_host_frame *hf = urb->transfer_buffer;
struct gs_tx_context *txc;
struct can_frame *cf;
struct sk_buff *skb;
BUG_ON(!usbcan);
switch (urb->status) {
case 0: /* success */
break;
case -ENOENT:
case -ESHUTDOWN:
return;
default:
/* do not resubmit aborted urbs. eg: when device goes down */
return;
}
/* device reports out of range channel id */
if (hf->channel >= GS_MAX_INTF)
goto resubmit_urb;
dev = usbcan->canch[hf->channel];
netdev = dev->netdev;
stats = &netdev->stats;
if (!netif_device_present(netdev))
return;
if (hf->echo_id == -1) { /* normal rx */
skb = alloc_can_skb(dev->netdev, &cf);
if (!skb)
return;
cf->can_id = hf->can_id;
cf->can_dlc = get_can_dlc(hf->can_dlc);
memcpy(cf->data, hf->data, 8);
/* ERROR frames tell us information about the controller */
if (hf->can_id & CAN_ERR_FLAG)
gs_update_state(dev, cf);
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += hf->can_dlc;
netif_rx(skb);
} else { /* echo_id == hf->echo_id */
if (hf->echo_id >= GS_MAX_TX_URBS) {
netdev_err(netdev,
"Unexpected out of range echo id %d\n",
hf->echo_id);
goto resubmit_urb;
}
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += hf->can_dlc;
txc = gs_get_tx_context(dev, hf->echo_id);
/* bad devices send bad echo_ids. */
if (!txc) {
netdev_err(netdev,
"Unexpected unused echo id %d\n",
hf->echo_id);
goto resubmit_urb;
}
can_get_echo_skb(netdev, hf->echo_id);
gs_free_tx_context(txc);
netif_wake_queue(netdev);
}
if (hf->flags & GS_CAN_FLAG_OVERFLOW) {
skb = alloc_can_err_skb(netdev, &cf);
if (!skb)
goto resubmit_urb;
cf->can_id |= CAN_ERR_CRTL;
cf->can_dlc = CAN_ERR_DLC;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
stats->rx_errors++;
netif_rx(skb);
}
resubmit_urb:
usb_fill_bulk_urb(urb,
usbcan->udev,
usb_rcvbulkpipe(usbcan->udev, GSUSB_ENDPOINT_IN),
hf,
sizeof(struct gs_host_frame),
gs_usb_recieve_bulk_callback,
usbcan
);
rc = usb_submit_urb(urb, GFP_ATOMIC);
/* USB failure take down all interfaces */
if (rc == -ENODEV) {
for (rc = 0; rc < GS_MAX_INTF; rc++) {
if (usbcan->canch[rc])
netif_device_detach(usbcan->canch[rc]->netdev);
}
}
}
static int gs_usb_set_bittiming(struct net_device *netdev)
{
struct gs_can *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.bittiming;
struct usb_interface *intf = dev->iface;
int rc;
struct gs_device_bittiming *dbt;
dbt = kmalloc(sizeof(*dbt), GFP_KERNEL);
if (!dbt)
return -ENOMEM;
dbt->prop_seg = bt->prop_seg;
dbt->phase_seg1 = bt->phase_seg1;
dbt->phase_seg2 = bt->phase_seg2;
dbt->sjw = bt->sjw;
dbt->brp = bt->brp;
/* request bit timings */
rc = usb_control_msg(interface_to_usbdev(intf),
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
GS_USB_BREQ_BITTIMING,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
dev->channel,
0,
dbt,
sizeof(*dbt),
1000);
kfree(dbt);
if (rc < 0)
dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)",
rc);
return rc;
}
static void gs_usb_xmit_callback(struct urb *urb)
{
struct gs_tx_context *txc = urb->context;
struct gs_can *dev = txc->dev;
struct net_device *netdev = dev->netdev;
if (urb->status)
netdev_info(netdev, "usb xmit fail %d\n", txc->echo_id);
usb_free_coherent(urb->dev,
urb->transfer_buffer_length,
urb->transfer_buffer,
urb->transfer_dma);
atomic_dec(&dev->active_tx_urbs);
if (!netif_device_present(netdev))
return;
if (netif_queue_stopped(netdev))
netif_wake_queue(netdev);
}
static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct gs_can *dev = netdev_priv(netdev);
struct net_device_stats *stats = &dev->netdev->stats;
struct urb *urb;
struct gs_host_frame *hf;
struct can_frame *cf;
int rc;
unsigned int idx;
struct gs_tx_context *txc;
if (can_dropped_invalid_skb(netdev, skb))
return NETDEV_TX_OK;
/* find an empty context to keep track of transmission */
txc = gs_alloc_tx_context(dev);
if (!txc)
return NETDEV_TX_BUSY;
/* create a URB, and a buffer for it */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
netdev_err(netdev, "No memory left for URB\n");
goto nomem_urb;
}
hf = usb_alloc_coherent(dev->udev, sizeof(*hf), GFP_ATOMIC,
&urb->transfer_dma);
if (!hf) {
netdev_err(netdev, "No memory left for USB buffer\n");
goto nomem_hf;
}
idx = txc->echo_id;
if (idx >= GS_MAX_TX_URBS) {
netdev_err(netdev, "Invalid tx context %d\n", idx);
goto badidx;
}
hf->echo_id = idx;
hf->channel = dev->channel;
cf = (struct can_frame *)skb->data;
hf->can_id = cf->can_id;
hf->can_dlc = cf->can_dlc;
memcpy(hf->data, cf->data, cf->can_dlc);
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, GSUSB_ENDPOINT_OUT),
hf,
sizeof(*hf),
gs_usb_xmit_callback,
txc);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &dev->tx_submitted);
can_put_echo_skb(skb, netdev, idx);
atomic_inc(&dev->active_tx_urbs);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(rc)) { /* usb send failed */
atomic_dec(&dev->active_tx_urbs);
can_free_echo_skb(netdev, idx);
gs_free_tx_context(txc);
usb_unanchor_urb(urb);
usb_free_coherent(dev->udev,
sizeof(*hf),
hf,
urb->transfer_dma);
if (rc == -ENODEV) {
netif_device_detach(netdev);
} else {
netdev_err(netdev, "usb_submit failed (err=%d)\n", rc);
stats->tx_dropped++;
}
} else {
/* Slow down tx path */
if (atomic_read(&dev->active_tx_urbs) >= GS_MAX_TX_URBS)
netif_stop_queue(netdev);
}
/* let usb core take care of this urb */
usb_free_urb(urb);
return NETDEV_TX_OK;
badidx:
usb_free_coherent(dev->udev,
sizeof(*hf),
hf,
urb->transfer_dma);
nomem_hf:
usb_free_urb(urb);
nomem_urb:
gs_free_tx_context(txc);
dev_kfree_skb(skb);
stats->tx_dropped++;
return NETDEV_TX_OK;
}
static int gs_can_open(struct net_device *netdev)
{
struct gs_can *dev = netdev_priv(netdev);
struct gs_usb *parent = dev->parent;
int rc, i;
struct gs_device_mode *dm;
u32 ctrlmode;
rc = open_candev(netdev);
if (rc)
return rc;
if (atomic_add_return(1, &parent->active_channels) == 1) {
for (i = 0; i < GS_MAX_RX_URBS; i++) {
struct urb *urb;
u8 *buf;
/* alloc rx urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
netdev_err(netdev,
"No memory left for URB\n");
return -ENOMEM;
}
/* alloc rx buffer */
buf = usb_alloc_coherent(dev->udev,
sizeof(struct gs_host_frame),
GFP_KERNEL,
&urb->transfer_dma);
if (!buf) {
netdev_err(netdev,
"No memory left for USB buffer\n");
usb_free_urb(urb);
return -ENOMEM;
}
/* fill, anchor, and submit rx urb */
usb_fill_bulk_urb(urb,
dev->udev,
usb_rcvbulkpipe(dev->udev,
GSUSB_ENDPOINT_IN),
buf,
sizeof(struct gs_host_frame),
gs_usb_recieve_bulk_callback,
parent);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &parent->rx_submitted);
rc = usb_submit_urb(urb, GFP_KERNEL);
if (rc) {
if (rc == -ENODEV)
netif_device_detach(dev->netdev);
netdev_err(netdev,
"usb_submit failed (err=%d)\n",
rc);
usb_unanchor_urb(urb);
break;
}
/* Drop reference,
* USB core will take care of freeing it
*/
usb_free_urb(urb);
}
}
dm = kmalloc(sizeof(*dm), GFP_KERNEL);
if (!dm)
return -ENOMEM;
/* flags */
ctrlmode = dev->can.ctrlmode;
dm->flags = 0;
if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
dm->flags |= GS_CAN_MODE_LOOP_BACK;
else if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
dm->flags |= GS_CAN_MODE_LISTEN_ONLY;
/* Controller is not allowed to retry TX
* this mode is unavailable on atmels uc3c hardware
*/
if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
dm->flags |= GS_CAN_MODE_ONE_SHOT;
if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
dm->flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
/* finally start device */
dm->mode = GS_CAN_MODE_START;
rc = usb_control_msg(interface_to_usbdev(dev->iface),
usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0),
GS_USB_BREQ_MODE,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
dev->channel,
0,
dm,
sizeof(*dm),
1000);
if (rc < 0) {
netdev_err(netdev, "Couldn't start device (err=%d)\n", rc);
kfree(dm);
return rc;
}
kfree(dm);
dev->can.state = CAN_STATE_ERROR_ACTIVE;
if (!(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
netif_start_queue(netdev);
return 0;
}
static int gs_can_close(struct net_device *netdev)
{
int rc;
struct gs_can *dev = netdev_priv(netdev);
struct gs_usb *parent = dev->parent;
netif_stop_queue(netdev);
/* Stop polling */
if (atomic_dec_and_test(&parent->active_channels))
usb_kill_anchored_urbs(&parent->rx_submitted);
/* Stop sending URBs */
usb_kill_anchored_urbs(&dev->tx_submitted);
atomic_set(&dev->active_tx_urbs, 0);
/* reset the device */
rc = gs_cmd_reset(parent, dev);
if (rc < 0)
netdev_warn(netdev, "Couldn't shutdown device (err=%d)", rc);
/* reset tx contexts */
for (rc = 0; rc < GS_MAX_TX_URBS; rc++) {
dev->tx_context[rc].dev = dev;
dev->tx_context[rc].echo_id = GS_MAX_TX_URBS;
}
/* close the netdev */
close_candev(netdev);
return 0;
}
static const struct net_device_ops gs_usb_netdev_ops = {
.ndo_open = gs_can_open,
.ndo_stop = gs_can_close,
.ndo_start_xmit = gs_can_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf)
{
struct gs_can *dev;
struct net_device *netdev;
int rc;
struct gs_device_bt_const *bt_const;
bt_const = kmalloc(sizeof(*bt_const), GFP_KERNEL);
if (!bt_const)
return ERR_PTR(-ENOMEM);
/* fetch bit timing constants */
rc = usb_control_msg(interface_to_usbdev(intf),
usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
GS_USB_BREQ_BT_CONST,
USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
channel,
0,
bt_const,
sizeof(*bt_const),
1000);
if (rc < 0) {
dev_err(&intf->dev,
"Couldn't get bit timing const for channel (err=%d)\n",
rc);
kfree(bt_const);
return ERR_PTR(rc);
}
/* create netdev */
netdev = alloc_candev(sizeof(struct gs_can), GS_MAX_TX_URBS);
if (!netdev) {
dev_err(&intf->dev, "Couldn't allocate candev\n");
kfree(bt_const);
return ERR_PTR(-ENOMEM);
}
dev = netdev_priv(netdev);
netdev->netdev_ops = &gs_usb_netdev_ops;
netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */
/* dev settup */
strcpy(dev->bt_const.name, "gs_usb");
dev->bt_const.tseg1_min = bt_const->tseg1_min;
dev->bt_const.tseg1_max = bt_const->tseg1_max;
dev->bt_const.tseg2_min = bt_const->tseg2_min;
dev->bt_const.tseg2_max = bt_const->tseg2_max;
dev->bt_const.sjw_max = bt_const->sjw_max;
dev->bt_const.brp_min = bt_const->brp_min;
dev->bt_const.brp_max = bt_const->brp_max;
dev->bt_const.brp_inc = bt_const->brp_inc;
dev->udev = interface_to_usbdev(intf);
dev->iface = intf;
dev->netdev = netdev;
dev->channel = channel;
init_usb_anchor(&dev->tx_submitted);
atomic_set(&dev->active_tx_urbs, 0);
spin_lock_init(&dev->tx_ctx_lock);
for (rc = 0; rc < GS_MAX_TX_URBS; rc++) {
dev->tx_context[rc].dev = dev;
dev->tx_context[rc].echo_id = GS_MAX_TX_URBS;
}
/* can settup */
dev->can.state = CAN_STATE_STOPPED;
dev->can.clock.freq = bt_const->fclk_can;
dev->can.bittiming_const = &dev->bt_const;
dev->can.do_set_bittiming = gs_usb_set_bittiming;
dev->can.ctrlmode_supported = 0;
if (bt_const->feature & GS_CAN_FEATURE_LISTEN_ONLY)
dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
if (bt_const->feature & GS_CAN_FEATURE_LOOP_BACK)
dev->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK;
if (bt_const->feature & GS_CAN_FEATURE_TRIPLE_SAMPLE)
dev->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT)
dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
kfree(bt_const);
SET_NETDEV_DEV(netdev, &intf->dev);
rc = register_candev(dev->netdev);
if (rc) {
free_candev(dev->netdev);
dev_err(&intf->dev, "Couldn't register candev (err=%d)\n", rc);
return ERR_PTR(rc);
}
return dev;
}
static void gs_destroy_candev(struct gs_can *dev)
{
unregister_candev(dev->netdev);
free_candev(dev->netdev);
usb_kill_anchored_urbs(&dev->tx_submitted);
kfree(dev);
}
static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct gs_usb *dev;
int rc = -ENOMEM;
unsigned int icount, i;
struct gs_host_config *hconf;
struct gs_device_config *dconf;
hconf = kmalloc(sizeof(*hconf), GFP_KERNEL);
if (!hconf)
return -ENOMEM;
hconf->byte_order = 0x0000beef;
/* send host config */
rc = usb_control_msg(interface_to_usbdev(intf),
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
GS_USB_BREQ_HOST_FORMAT,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
1,
intf->altsetting[0].desc.bInterfaceNumber,
hconf,
sizeof(*hconf),
1000);
kfree(hconf);
if (rc < 0) {
dev_err(&intf->dev, "Couldn't send data format (err=%d)\n",
rc);
return rc;
}
dconf = kmalloc(sizeof(*dconf), GFP_KERNEL);
if (!dconf)
return -ENOMEM;
/* read device config */
rc = usb_control_msg(interface_to_usbdev(intf),
usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
GS_USB_BREQ_DEVICE_CONFIG,
USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
1,
intf->altsetting[0].desc.bInterfaceNumber,
dconf,
sizeof(*dconf),
1000);
if (rc < 0) {
dev_err(&intf->dev, "Couldn't get device config: (err=%d)\n",
rc);
kfree(dconf);
return rc;
}
icount = dconf->icount+1;
kfree(dconf);
dev_info(&intf->dev, "Configuring for %d interfaces\n", icount);
if (icount > GS_MAX_INTF) {
dev_err(&intf->dev,
"Driver cannot handle more that %d CAN interfaces\n",
GS_MAX_INTF);
return -EINVAL;
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
init_usb_anchor(&dev->rx_submitted);
atomic_set(&dev->active_channels, 0);
usb_set_intfdata(intf, dev);
dev->udev = interface_to_usbdev(intf);
for (i = 0; i < icount; i++) {
dev->canch[i] = gs_make_candev(i, intf);
if (IS_ERR_OR_NULL(dev->canch[i])) {
/* on failure destroy previously created candevs */
icount = i;
for (i = 0; i < icount; i++) {
gs_destroy_candev(dev->canch[i]);
dev->canch[i] = NULL;
}
kfree(dev);
return rc;
}
dev->canch[i]->parent = dev;
}
return 0;
}
static void gs_usb_disconnect(struct usb_interface *intf)
{
unsigned i;
struct gs_usb *dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (!dev) {
dev_err(&intf->dev, "Disconnect (nodata)\n");
return;
}
for (i = 0; i < GS_MAX_INTF; i++) {
struct gs_can *can = dev->canch[i];
if (!can)
continue;
gs_destroy_candev(can);
}
usb_kill_anchored_urbs(&dev->rx_submitted);
}
static const struct usb_device_id gs_usb_table[] = {
{USB_DEVICE(USB_GSUSB_1_VENDOR_ID, USB_GSUSB_1_PRODUCT_ID)},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, gs_usb_table);
static struct usb_driver gs_usb_driver = {
.name = "gs_usb",
.probe = gs_usb_probe,
.disconnect = gs_usb_disconnect,
.id_table = gs_usb_table,
};
module_usb_driver(gs_usb_driver);
MODULE_AUTHOR("Maximilian Schneider <mws@schneidersoft.net>");
MODULE_DESCRIPTION(
"Socket CAN device driver for Geschwister Schneider Technologie-, "
"Entwicklungs- und Vertriebs UG. USB2.0 to CAN interfaces.");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o
peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o

View file

@ -0,0 +1,903 @@
/*
* CAN driver for PEAK System PCAN-USB adapter
* Derived from the PCAN project file driver/src/pcan_usb.c
*
* Copyright (C) 2003-2010 PEAK System-Technik GmbH
* Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*
* 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; version 2 of the License.
*
* 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/netdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "pcan_usb_core.h"
MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter");
/* PCAN-USB Endpoints */
#define PCAN_USB_EP_CMDOUT 1
#define PCAN_USB_EP_CMDIN (PCAN_USB_EP_CMDOUT | USB_DIR_IN)
#define PCAN_USB_EP_MSGOUT 2
#define PCAN_USB_EP_MSGIN (PCAN_USB_EP_MSGOUT | USB_DIR_IN)
/* PCAN-USB command struct */
#define PCAN_USB_CMD_FUNC 0
#define PCAN_USB_CMD_NUM 1
#define PCAN_USB_CMD_ARGS 2
#define PCAN_USB_CMD_ARGS_LEN 14
#define PCAN_USB_CMD_LEN (PCAN_USB_CMD_ARGS + \
PCAN_USB_CMD_ARGS_LEN)
/* PCAN-USB command timeout (ms.) */
#define PCAN_USB_COMMAND_TIMEOUT 1000
/* PCAN-USB startup timeout (ms.) */
#define PCAN_USB_STARTUP_TIMEOUT 10
/* PCAN-USB rx/tx buffers size */
#define PCAN_USB_RX_BUFFER_SIZE 64
#define PCAN_USB_TX_BUFFER_SIZE 64
#define PCAN_USB_MSG_HEADER_LEN 2
/* PCAN-USB adapter internal clock (MHz) */
#define PCAN_USB_CRYSTAL_HZ 16000000
/* PCAN-USB USB message record status/len field */
#define PCAN_USB_STATUSLEN_TIMESTAMP (1 << 7)
#define PCAN_USB_STATUSLEN_INTERNAL (1 << 6)
#define PCAN_USB_STATUSLEN_EXT_ID (1 << 5)
#define PCAN_USB_STATUSLEN_RTR (1 << 4)
#define PCAN_USB_STATUSLEN_DLC (0xf)
/* PCAN-USB error flags */
#define PCAN_USB_ERROR_TXFULL 0x01
#define PCAN_USB_ERROR_RXQOVR 0x02
#define PCAN_USB_ERROR_BUS_LIGHT 0x04
#define PCAN_USB_ERROR_BUS_HEAVY 0x08
#define PCAN_USB_ERROR_BUS_OFF 0x10
#define PCAN_USB_ERROR_RXQEMPTY 0x20
#define PCAN_USB_ERROR_QOVR 0x40
#define PCAN_USB_ERROR_TXQFULL 0x80
/* SJA1000 modes */
#define SJA1000_MODE_NORMAL 0x00
#define SJA1000_MODE_INIT 0x01
/*
* tick duration = 42.666 us =>
* (tick_number * 44739243) >> 20 ~ (tick_number * 42666) / 1000
* accuracy = 10^-7
*/
#define PCAN_USB_TS_DIV_SHIFTER 20
#define PCAN_USB_TS_US_PER_TICK 44739243
/* PCAN-USB messages record types */
#define PCAN_USB_REC_ERROR 1
#define PCAN_USB_REC_ANALOG 2
#define PCAN_USB_REC_BUSLOAD 3
#define PCAN_USB_REC_TS 4
#define PCAN_USB_REC_BUSEVT 5
/* private to PCAN-USB adapter */
struct pcan_usb {
struct peak_usb_device dev;
struct peak_time_ref time_ref;
struct timer_list restart_timer;
};
/* incoming message context for decoding */
struct pcan_usb_msg_context {
u16 ts16;
u8 prev_ts8;
u8 *ptr;
u8 *end;
u8 rec_cnt;
u8 rec_idx;
u8 rec_data_idx;
struct net_device *netdev;
struct pcan_usb *pdev;
};
/*
* send a command
*/
static int pcan_usb_send_cmd(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
{
int err;
int actual_length;
/* usb device unregistered? */
if (!(dev->state & PCAN_USB_STATE_CONNECTED))
return 0;
dev->cmd_buf[PCAN_USB_CMD_FUNC] = f;
dev->cmd_buf[PCAN_USB_CMD_NUM] = n;
if (p)
memcpy(dev->cmd_buf + PCAN_USB_CMD_ARGS,
p, PCAN_USB_CMD_ARGS_LEN);
err = usb_bulk_msg(dev->udev,
usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT),
dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length,
PCAN_USB_COMMAND_TIMEOUT);
if (err)
netdev_err(dev->netdev,
"sending cmd f=0x%x n=0x%x failure: %d\n",
f, n, err);
return err;
}
/*
* send a command then wait for its response
*/
static int pcan_usb_wait_rsp(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
{
int err;
int actual_length;
/* usb device unregistered? */
if (!(dev->state & PCAN_USB_STATE_CONNECTED))
return 0;
/* first, send command */
err = pcan_usb_send_cmd(dev, f, n, NULL);
if (err)
return err;
err = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN),
dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length,
PCAN_USB_COMMAND_TIMEOUT);
if (err)
netdev_err(dev->netdev,
"waiting rsp f=0x%x n=0x%x failure: %d\n", f, n, err);
else if (p)
memcpy(p, dev->cmd_buf + PCAN_USB_CMD_ARGS,
PCAN_USB_CMD_ARGS_LEN);
return err;
}
static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode)
{
u8 args[PCAN_USB_CMD_ARGS_LEN] = {
[1] = mode,
};
return pcan_usb_send_cmd(dev, 9, 2, args);
}
static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff)
{
u8 args[PCAN_USB_CMD_ARGS_LEN] = {
[0] = !!onoff,
};
return pcan_usb_send_cmd(dev, 3, 2, args);
}
static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff)
{
u8 args[PCAN_USB_CMD_ARGS_LEN] = {
[0] = !!onoff,
};
return pcan_usb_send_cmd(dev, 3, 3, args);
}
static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
{
u8 args[PCAN_USB_CMD_ARGS_LEN] = {
[0] = !!onoff,
};
return pcan_usb_send_cmd(dev, 10, 2, args);
}
/*
* set bittiming value to can
*/
static int pcan_usb_set_bittiming(struct peak_usb_device *dev,
struct can_bittiming *bt)
{
u8 args[PCAN_USB_CMD_ARGS_LEN];
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 (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
netdev_info(dev->netdev, "setting BTR0=0x%02x BTR1=0x%02x\n",
btr0, btr1);
args[0] = btr1;
args[1] = btr0;
return pcan_usb_send_cmd(dev, 1, 2, args);
}
/*
* init/reset can
*/
static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff)
{
int err;
err = pcan_usb_set_bus(dev, onoff);
if (err)
return err;
if (!onoff) {
err = pcan_usb_set_sja1000(dev, SJA1000_MODE_INIT);
} else {
/* the PCAN-USB needs time to init */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT));
}
return err;
}
/*
* handle end of waiting for the device to reset
*/
static void pcan_usb_restart(unsigned long arg)
{
/* notify candev and netdev */
peak_usb_restart_complete((struct peak_usb_device *)arg);
}
/*
* handle the submission of the restart urb
*/
static void pcan_usb_restart_pending(struct urb *urb)
{
struct pcan_usb *pdev = urb->context;
/* the PCAN-USB needs time to restart */
mod_timer(&pdev->restart_timer,
jiffies + msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT));
/* can delete usb resources */
peak_usb_async_complete(urb);
}
/*
* handle asynchronous restart
*/
static int pcan_usb_restart_async(struct peak_usb_device *dev, struct urb *urb,
u8 *buf)
{
struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
if (timer_pending(&pdev->restart_timer))
return -EBUSY;
/* set bus on */
buf[PCAN_USB_CMD_FUNC] = 3;
buf[PCAN_USB_CMD_NUM] = 2;
buf[PCAN_USB_CMD_ARGS] = 1;
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT),
buf, PCAN_USB_CMD_LEN,
pcan_usb_restart_pending, pdev);
return usb_submit_urb(urb, GFP_ATOMIC);
}
/*
* read serial number from device
*/
static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
{
u8 args[PCAN_USB_CMD_ARGS_LEN];
int err;
err = pcan_usb_wait_rsp(dev, 6, 1, args);
if (err) {
netdev_err(dev->netdev, "getting serial failure: %d\n", err);
} else if (serial_number) {
u32 tmp32;
memcpy(&tmp32, args, 4);
*serial_number = le32_to_cpu(tmp32);
}
return err;
}
/*
* read device id from device
*/
static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
{
u8 args[PCAN_USB_CMD_ARGS_LEN];
int err;
err = pcan_usb_wait_rsp(dev, 4, 1, args);
if (err)
netdev_err(dev->netdev, "getting device id failure: %d\n", err);
else if (device_id)
*device_id = args[0];
return err;
}
/*
* update current time ref with received timestamp
*/
static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc)
{
u16 tmp16;
if ((mc->ptr+2) > mc->end)
return -EINVAL;
memcpy(&tmp16, mc->ptr, 2);
mc->ts16 = le16_to_cpu(tmp16);
if (mc->rec_idx > 0)
peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16);
else
peak_usb_set_ts_now(&mc->pdev->time_ref, mc->ts16);
return 0;
}
/*
* decode received timestamp
*/
static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet)
{
/* only 1st packet supplies a word timestamp */
if (first_packet) {
u16 tmp16;
if ((mc->ptr + 2) > mc->end)
return -EINVAL;
memcpy(&tmp16, mc->ptr, 2);
mc->ptr += 2;
mc->ts16 = le16_to_cpu(tmp16);
mc->prev_ts8 = mc->ts16 & 0x00ff;
} else {
u8 ts8;
if ((mc->ptr + 1) > mc->end)
return -EINVAL;
ts8 = *mc->ptr++;
if (ts8 < mc->prev_ts8)
mc->ts16 += 0x100;
mc->ts16 &= 0xff00;
mc->ts16 |= ts8;
mc->prev_ts8 = ts8;
}
return 0;
}
static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
u8 status_len)
{
struct sk_buff *skb;
struct can_frame *cf;
struct timeval tv;
enum can_state new_state;
/* ignore this error until 1st ts received */
if (n == PCAN_USB_ERROR_QOVR)
if (!mc->pdev->time_ref.tick_count)
return 0;
new_state = mc->pdev->dev.can.state;
switch (mc->pdev->dev.can.state) {
case CAN_STATE_ERROR_ACTIVE:
if (n & PCAN_USB_ERROR_BUS_LIGHT) {
new_state = CAN_STATE_ERROR_WARNING;
break;
}
case CAN_STATE_ERROR_WARNING:
if (n & PCAN_USB_ERROR_BUS_HEAVY) {
new_state = CAN_STATE_ERROR_PASSIVE;
break;
}
if (n & PCAN_USB_ERROR_BUS_OFF) {
new_state = CAN_STATE_BUS_OFF;
break;
}
if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
/*
* trick to bypass next comparison and process other
* errors
*/
new_state = CAN_STATE_MAX;
break;
}
if ((n & PCAN_USB_ERROR_BUS_LIGHT) == 0) {
/* no error (back to active state) */
mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
}
break;
case CAN_STATE_ERROR_PASSIVE:
if (n & PCAN_USB_ERROR_BUS_OFF) {
new_state = CAN_STATE_BUS_OFF;
break;
}
if (n & PCAN_USB_ERROR_BUS_LIGHT) {
new_state = CAN_STATE_ERROR_WARNING;
break;
}
if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
/*
* trick to bypass next comparison and process other
* errors
*/
new_state = CAN_STATE_MAX;
break;
}
if ((n & PCAN_USB_ERROR_BUS_HEAVY) == 0) {
/* no error (back to active state) */
mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
}
break;
default:
/* do nothing waiting for restart */
return 0;
}
/* donot post any error if current state didn't change */
if (mc->pdev->dev.can.state == new_state)
return 0;
/* allocate an skb to store the error frame */
skb = alloc_can_err_skb(mc->netdev, &cf);
if (!skb)
return -ENOMEM;
switch (new_state) {
case CAN_STATE_BUS_OFF:
cf->can_id |= CAN_ERR_BUSOFF;
can_bus_off(mc->netdev);
break;
case CAN_STATE_ERROR_PASSIVE:
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE |
CAN_ERR_CRTL_RX_PASSIVE;
mc->pdev->dev.can.can_stats.error_passive++;
break;
case CAN_STATE_ERROR_WARNING:
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] |= CAN_ERR_CRTL_TX_WARNING |
CAN_ERR_CRTL_RX_WARNING;
mc->pdev->dev.can.can_stats.error_warning++;
break;
default:
/* CAN_STATE_MAX (trick to handle other errors) */
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
mc->netdev->stats.rx_over_errors++;
mc->netdev->stats.rx_errors++;
new_state = mc->pdev->dev.can.state;
break;
}
mc->pdev->dev.can.state = new_state;
if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
hwts->hwtstamp = timeval_to_ktime(tv);
}
netif_rx(skb);
mc->netdev->stats.rx_packets++;
mc->netdev->stats.rx_bytes += cf->can_dlc;
return 0;
}
/*
* decode non-data usb message
*/
static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc,
u8 status_len)
{
u8 rec_len = status_len & PCAN_USB_STATUSLEN_DLC;
u8 f, n;
int err;
/* check whether function and number can be read */
if ((mc->ptr + 2) > mc->end)
return -EINVAL;
f = mc->ptr[PCAN_USB_CMD_FUNC];
n = mc->ptr[PCAN_USB_CMD_NUM];
mc->ptr += PCAN_USB_CMD_ARGS;
if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
int err = pcan_usb_decode_ts(mc, !mc->rec_idx);
if (err)
return err;
}
switch (f) {
case PCAN_USB_REC_ERROR:
err = pcan_usb_decode_error(mc, n, status_len);
if (err)
return err;
break;
case PCAN_USB_REC_ANALOG:
/* analog values (ignored) */
rec_len = 2;
break;
case PCAN_USB_REC_BUSLOAD:
/* bus load (ignored) */
rec_len = 1;
break;
case PCAN_USB_REC_TS:
/* only timestamp */
if (pcan_usb_update_ts(mc))
return -EINVAL;
break;
case PCAN_USB_REC_BUSEVT:
/* error frame/bus event */
if (n & PCAN_USB_ERROR_TXQFULL)
netdev_dbg(mc->netdev, "device Tx queue full)\n");
break;
default:
netdev_err(mc->netdev, "unexpected function %u\n", f);
break;
}
if ((mc->ptr + rec_len) > mc->end)
return -EINVAL;
mc->ptr += rec_len;
return 0;
}
/*
* decode data usb message
*/
static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
{
u8 rec_len = status_len & PCAN_USB_STATUSLEN_DLC;
struct sk_buff *skb;
struct can_frame *cf;
struct timeval tv;
struct skb_shared_hwtstamps *hwts;
skb = alloc_can_skb(mc->netdev, &cf);
if (!skb)
return -ENOMEM;
if (status_len & PCAN_USB_STATUSLEN_EXT_ID) {
u32 tmp32;
if ((mc->ptr + 4) > mc->end)
goto decode_failed;
memcpy(&tmp32, mc->ptr, 4);
mc->ptr += 4;
cf->can_id = le32_to_cpu(tmp32 >> 3) | CAN_EFF_FLAG;
} else {
u16 tmp16;
if ((mc->ptr + 2) > mc->end)
goto decode_failed;
memcpy(&tmp16, mc->ptr, 2);
mc->ptr += 2;
cf->can_id = le16_to_cpu(tmp16 >> 5);
}
cf->can_dlc = get_can_dlc(rec_len);
/* first data packet timestamp is a word */
if (pcan_usb_decode_ts(mc, !mc->rec_data_idx))
goto decode_failed;
/* read data */
memset(cf->data, 0x0, sizeof(cf->data));
if (status_len & PCAN_USB_STATUSLEN_RTR) {
cf->can_id |= CAN_RTR_FLAG;
} else {
if ((mc->ptr + rec_len) > mc->end)
goto decode_failed;
memcpy(cf->data, mc->ptr, cf->can_dlc);
mc->ptr += rec_len;
}
/* convert timestamp into kernel time */
peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
hwts = skb_hwtstamps(skb);
hwts->hwtstamp = timeval_to_ktime(tv);
/* push the skb */
netif_rx(skb);
/* update statistics */
mc->netdev->stats.rx_packets++;
mc->netdev->stats.rx_bytes += cf->can_dlc;
return 0;
decode_failed:
dev_kfree_skb(skb);
return -EINVAL;
}
/*
* process incoming message
*/
static int pcan_usb_decode_msg(struct peak_usb_device *dev, u8 *ibuf, u32 lbuf)
{
struct pcan_usb_msg_context mc = {
.rec_cnt = ibuf[1],
.ptr = ibuf + PCAN_USB_MSG_HEADER_LEN,
.end = ibuf + lbuf,
.netdev = dev->netdev,
.pdev = container_of(dev, struct pcan_usb, dev),
};
int err;
for (err = 0; mc.rec_idx < mc.rec_cnt && !err; mc.rec_idx++) {
u8 sl = *mc.ptr++;
/* handle status and error frames here */
if (sl & PCAN_USB_STATUSLEN_INTERNAL) {
err = pcan_usb_decode_status(&mc, sl);
/* handle normal can frames here */
} else {
err = pcan_usb_decode_data(&mc, sl);
mc.rec_data_idx++;
}
}
return err;
}
/*
* process any incoming buffer
*/
static int pcan_usb_decode_buf(struct peak_usb_device *dev, struct urb *urb)
{
int err = 0;
if (urb->actual_length > PCAN_USB_MSG_HEADER_LEN) {
err = pcan_usb_decode_msg(dev, urb->transfer_buffer,
urb->actual_length);
} else if (urb->actual_length > 0) {
netdev_err(dev->netdev, "usb message length error (%u)\n",
urb->actual_length);
err = -EINVAL;
}
return err;
}
/*
* process outgoing packet
*/
static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
u8 *obuf, size_t *size)
{
struct net_device *netdev = dev->netdev;
struct net_device_stats *stats = &netdev->stats;
struct can_frame *cf = (struct can_frame *)skb->data;
u8 *pc;
obuf[0] = 2;
obuf[1] = 1;
pc = obuf + PCAN_USB_MSG_HEADER_LEN;
/* status/len byte */
*pc = cf->can_dlc;
if (cf->can_id & CAN_RTR_FLAG)
*pc |= PCAN_USB_STATUSLEN_RTR;
/* can id */
if (cf->can_id & CAN_EFF_FLAG) {
__le32 tmp32 = cpu_to_le32((cf->can_id & CAN_ERR_MASK) << 3);
*pc |= PCAN_USB_STATUSLEN_EXT_ID;
memcpy(++pc, &tmp32, 4);
pc += 4;
} else {
__le16 tmp16 = cpu_to_le16((cf->can_id & CAN_ERR_MASK) << 5);
memcpy(++pc, &tmp16, 2);
pc += 2;
}
/* can data */
if (!(cf->can_id & CAN_RTR_FLAG)) {
memcpy(pc, cf->data, cf->can_dlc);
pc += cf->can_dlc;
}
obuf[(*size)-1] = (u8)(stats->tx_packets & 0xff);
return 0;
}
/*
* start interface
*/
static int pcan_usb_start(struct peak_usb_device *dev)
{
struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
/* number of bits used in timestamps read from adapter struct */
peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb);
/* if revision greater than 3, can put silent mode on/off */
if (dev->device_rev > 3) {
int err;
err = pcan_usb_set_silent(dev,
dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY);
if (err)
return err;
}
return pcan_usb_set_ext_vcc(dev, 0);
}
static int pcan_usb_init(struct peak_usb_device *dev)
{
struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
u32 serial_number;
int err;
/* initialize a timer needed to wait for hardware restart */
init_timer(&pdev->restart_timer);
pdev->restart_timer.function = pcan_usb_restart;
pdev->restart_timer.data = (unsigned long)dev;
/*
* explicit use of dev_xxx() instead of netdev_xxx() here:
* information displayed are related to the device itself, not
* to the canx netdevice.
*/
err = pcan_usb_get_serial(dev, &serial_number);
if (err) {
dev_err(dev->netdev->dev.parent,
"unable to read %s serial number (err %d)\n",
pcan_usb.name, err);
return err;
}
dev_info(dev->netdev->dev.parent,
"PEAK-System %s adapter hwrev %u serial %08X (%u channel)\n",
pcan_usb.name, dev->device_rev, serial_number,
pcan_usb.ctrl_count);
return 0;
}
/*
* probe function for new PCAN-USB usb interface
*/
static int pcan_usb_probe(struct usb_interface *intf)
{
struct usb_host_interface *if_desc;
int i;
if_desc = intf->altsetting;
/* check interface endpoint addresses */
for (i = 0; i < if_desc->desc.bNumEndpoints; i++) {
struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc;
switch (ep->bEndpointAddress) {
case PCAN_USB_EP_CMDOUT:
case PCAN_USB_EP_CMDIN:
case PCAN_USB_EP_MSGOUT:
case PCAN_USB_EP_MSGIN:
break;
default:
return -ENODEV;
}
}
return 0;
}
/*
* describe the PCAN-USB adapter
*/
struct peak_usb_adapter pcan_usb = {
.name = "PCAN-USB",
.device_id = PCAN_USB_PRODUCT_ID,
.ctrl_count = 1,
.clock = {
.freq = PCAN_USB_CRYSTAL_HZ / 2 ,
},
.bittiming_const = {
.name = "pcan_usb",
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.brp_inc = 1,
},
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb),
/* timestamps usage */
.ts_used_bits = 16,
.ts_period = 24575, /* calibration period in ts. */
.us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us=(ts*scale) */
.us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER, /* >> shift */
/* give here messages in/out endpoints */
.ep_msg_in = PCAN_USB_EP_MSGIN,
.ep_msg_out = {PCAN_USB_EP_MSGOUT},
/* size of rx/tx usb buffers */
.rx_buffer_size = PCAN_USB_RX_BUFFER_SIZE,
.tx_buffer_size = PCAN_USB_TX_BUFFER_SIZE,
/* device callbacks */
.intf_probe = pcan_usb_probe,
.dev_init = pcan_usb_init,
.dev_set_bus = pcan_usb_write_mode,
.dev_set_bittiming = pcan_usb_set_bittiming,
.dev_get_device_id = pcan_usb_get_device_id,
.dev_decode_buf = pcan_usb_decode_buf,
.dev_encode_msg = pcan_usb_encode_msg,
.dev_start = pcan_usb_start,
.dev_restart_async = pcan_usb_restart_async,
};

View file

@ -0,0 +1,953 @@
/*
* CAN driver for PEAK System USB adapters
* Derived from the PCAN project file driver/src/pcan_usb_core.c
*
* Copyright (C) 2003-2010 PEAK System-Technik GmbH
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*
* 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; version 2 of the License.
*
* 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/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "pcan_usb_core.h"
MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters");
MODULE_LICENSE("GPL v2");
/* Table of devices that work with this driver */
static struct usb_device_id peak_usb_table[] = {
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, peak_usb_table);
/* List of supported PCAN-USB adapters (NULL terminated list) */
static struct peak_usb_adapter *peak_usb_adapters_list[] = {
&pcan_usb,
&pcan_usb_pro,
NULL,
};
/*
* dump memory
*/
#define DUMP_WIDTH 16
void pcan_dump_mem(char *prompt, void *p, int l)
{
pr_info("%s dumping %s (%d bytes):\n",
PCAN_USB_DRIVER_NAME, prompt ? prompt : "memory", l);
print_hex_dump(KERN_INFO, PCAN_USB_DRIVER_NAME " ", DUMP_PREFIX_NONE,
DUMP_WIDTH, 1, p, l, false);
}
/*
* initialize a time_ref object with usb adapter own settings
*/
void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
struct peak_usb_adapter *adapter)
{
if (time_ref) {
memset(time_ref, 0, sizeof(struct peak_time_ref));
time_ref->adapter = adapter;
}
}
static void peak_usb_add_us(struct timeval *tv, u32 delta_us)
{
/* number of s. to add to final time */
u32 delta_s = delta_us / 1000000;
delta_us -= delta_s * 1000000;
tv->tv_usec += delta_us;
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
delta_s++;
}
tv->tv_sec += delta_s;
}
/*
* sometimes, another now may be more recent than current one...
*/
void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now)
{
time_ref->ts_dev_2 = ts_now;
/* should wait at least two passes before computing */
if (time_ref->tv_host.tv_sec > 0) {
u32 delta_ts = time_ref->ts_dev_2 - time_ref->ts_dev_1;
if (time_ref->ts_dev_2 < time_ref->ts_dev_1)
delta_ts &= (1 << time_ref->adapter->ts_used_bits) - 1;
time_ref->ts_total += delta_ts;
}
}
/*
* register device timestamp as now
*/
void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now)
{
if (time_ref->tv_host_0.tv_sec == 0) {
/* use monotonic clock to correctly compute further deltas */
time_ref->tv_host_0 = ktime_to_timeval(ktime_get());
time_ref->tv_host.tv_sec = 0;
} else {
/*
* delta_us should not be >= 2^32 => delta_s should be < 4294
* handle 32-bits wrapping here: if count of s. reaches 4200,
* reset counters and change time base
*/
if (time_ref->tv_host.tv_sec != 0) {
u32 delta_s = time_ref->tv_host.tv_sec
- time_ref->tv_host_0.tv_sec;
if (delta_s > 4200) {
time_ref->tv_host_0 = time_ref->tv_host;
time_ref->ts_total = 0;
}
}
time_ref->tv_host = ktime_to_timeval(ktime_get());
time_ref->tick_count++;
}
time_ref->ts_dev_1 = time_ref->ts_dev_2;
peak_usb_update_ts_now(time_ref, ts_now);
}
/*
* compute timeval according to current ts and time_ref data
*/
void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts,
struct timeval *tv)
{
/* protect from getting timeval before setting now */
if (time_ref->tv_host.tv_sec > 0) {
u64 delta_us;
delta_us = ts - time_ref->ts_dev_2;
if (ts < time_ref->ts_dev_2)
delta_us &= (1 << time_ref->adapter->ts_used_bits) - 1;
delta_us += time_ref->ts_total;
delta_us *= time_ref->adapter->us_per_ts_scale;
delta_us >>= time_ref->adapter->us_per_ts_shift;
*tv = time_ref->tv_host_0;
peak_usb_add_us(tv, (u32)delta_us);
} else {
*tv = ktime_to_timeval(ktime_get());
}
}
/*
* callback for bulk Rx urb
*/
static void peak_usb_read_bulk_callback(struct urb *urb)
{
struct peak_usb_device *dev = urb->context;
struct net_device *netdev;
int err;
netdev = dev->netdev;
if (!netif_device_present(netdev))
return;
/* check reception status */
switch (urb->status) {
case 0:
/* success */
break;
case -EILSEQ:
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
return;
default:
if (net_ratelimit())
netdev_err(netdev,
"Rx urb aborted (%d)\n", urb->status);
goto resubmit_urb;
}
/* protect from any incoming empty msgs */
if ((urb->actual_length > 0) && (dev->adapter->dev_decode_buf)) {
/* handle these kinds of msgs only if _start callback called */
if (dev->state & PCAN_USB_STATE_STARTED) {
err = dev->adapter->dev_decode_buf(dev, urb);
if (err)
pcan_dump_mem("received usb message",
urb->transfer_buffer,
urb->transfer_buffer_length);
}
}
resubmit_urb:
usb_fill_bulk_urb(urb, dev->udev,
usb_rcvbulkpipe(dev->udev, dev->ep_msg_in),
urb->transfer_buffer, dev->adapter->rx_buffer_size,
peak_usb_read_bulk_callback, dev);
usb_anchor_urb(urb, &dev->rx_submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (!err)
return;
usb_unanchor_urb(urb);
if (err == -ENODEV)
netif_device_detach(netdev);
else
netdev_err(netdev, "failed resubmitting read bulk urb: %d\n",
err);
}
/*
* callback for bulk Tx urb
*/
static void peak_usb_write_bulk_callback(struct urb *urb)
{
struct peak_tx_urb_context *context = urb->context;
struct peak_usb_device *dev;
struct net_device *netdev;
BUG_ON(!context);
dev = context->dev;
netdev = dev->netdev;
atomic_dec(&dev->active_tx_urbs);
if (!netif_device_present(netdev))
return;
/* check tx status */
switch (urb->status) {
case 0:
/* transmission complete */
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += context->dlc;
/* prevent tx timeout */
netdev->trans_start = jiffies;
break;
default:
if (net_ratelimit())
netdev_err(netdev, "Tx urb aborted (%d)\n",
urb->status);
case -EPROTO:
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
break;
}
/* should always release echo skb and corresponding context */
can_get_echo_skb(netdev, context->echo_index);
context->echo_index = PCAN_USB_MAX_TX_URBS;
/* do wakeup tx queue in case of success only */
if (!urb->status)
netif_wake_queue(netdev);
}
/*
* called by netdev to send one skb on the CAN interface.
*/
static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct peak_usb_device *dev = netdev_priv(netdev);
struct peak_tx_urb_context *context = NULL;
struct net_device_stats *stats = &netdev->stats;
struct can_frame *cf = (struct can_frame *)skb->data;
struct urb *urb;
u8 *obuf;
int i, err;
size_t size = dev->adapter->tx_buffer_size;
if (can_dropped_invalid_skb(netdev, skb))
return NETDEV_TX_OK;
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++)
if (dev->tx_contexts[i].echo_index == PCAN_USB_MAX_TX_URBS) {
context = dev->tx_contexts + i;
break;
}
if (!context) {
/* should not occur except during restart */
return NETDEV_TX_BUSY;
}
urb = context->urb;
obuf = urb->transfer_buffer;
err = dev->adapter->dev_encode_msg(dev, skb, obuf, &size);
if (err) {
if (net_ratelimit())
netdev_err(netdev, "packet dropped\n");
dev_kfree_skb(skb);
stats->tx_dropped++;
return NETDEV_TX_OK;
}
context->echo_index = i;
context->dlc = cf->can_dlc;
usb_anchor_urb(urb, &dev->tx_submitted);
can_put_echo_skb(skb, netdev, context->echo_index);
atomic_inc(&dev->active_tx_urbs);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
can_free_echo_skb(netdev, context->echo_index);
usb_unanchor_urb(urb);
/* this context is not used in fact */
context->echo_index = PCAN_USB_MAX_TX_URBS;
atomic_dec(&dev->active_tx_urbs);
switch (err) {
case -ENODEV:
netif_device_detach(netdev);
break;
default:
netdev_warn(netdev, "tx urb submitting failed err=%d\n",
err);
case -ENOENT:
/* cable unplugged */
stats->tx_dropped++;
}
} else {
netdev->trans_start = jiffies;
/* slow down tx path */
if (atomic_read(&dev->active_tx_urbs) >= PCAN_USB_MAX_TX_URBS)
netif_stop_queue(netdev);
}
return NETDEV_TX_OK;
}
/*
* start the CAN interface.
* Rx and Tx urbs are allocated here. Rx urbs are submitted here.
*/
static int peak_usb_start(struct peak_usb_device *dev)
{
struct net_device *netdev = dev->netdev;
int err, i;
for (i = 0; i < PCAN_USB_MAX_RX_URBS; i++) {
struct urb *urb;
u8 *buf;
/* create a URB, and a buffer for it, to receive usb messages */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
netdev_err(netdev, "No memory left for URBs\n");
err = -ENOMEM;
break;
}
buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL);
if (!buf) {
usb_free_urb(urb);
err = -ENOMEM;
break;
}
usb_fill_bulk_urb(urb, dev->udev,
usb_rcvbulkpipe(dev->udev, dev->ep_msg_in),
buf, dev->adapter->rx_buffer_size,
peak_usb_read_bulk_callback, dev);
/* ask last usb_free_urb() to also kfree() transfer_buffer */
urb->transfer_flags |= URB_FREE_BUFFER;
usb_anchor_urb(urb, &dev->rx_submitted);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
if (err == -ENODEV)
netif_device_detach(dev->netdev);
usb_unanchor_urb(urb);
kfree(buf);
usb_free_urb(urb);
break;
}
/* drop reference, USB core will take care of freeing it */
usb_free_urb(urb);
}
/* did we submit any URBs? Warn if we was not able to submit all urbs */
if (i < PCAN_USB_MAX_RX_URBS) {
if (i == 0) {
netdev_err(netdev, "couldn't setup any rx URB\n");
return err;
}
netdev_warn(netdev, "rx performance may be slow\n");
}
/* pre-alloc tx buffers and corresponding urbs */
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
struct peak_tx_urb_context *context;
struct urb *urb;
u8 *buf;
/* create a URB and a buffer for it, to transmit usb messages */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
netdev_err(netdev, "No memory left for URBs\n");
err = -ENOMEM;
break;
}
buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL);
if (!buf) {
usb_free_urb(urb);
err = -ENOMEM;
break;
}
context = dev->tx_contexts + i;
context->dev = dev;
context->urb = urb;
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->ep_msg_out),
buf, dev->adapter->tx_buffer_size,
peak_usb_write_bulk_callback, context);
/* ask last usb_free_urb() to also kfree() transfer_buffer */
urb->transfer_flags |= URB_FREE_BUFFER;
}
/* warn if we were not able to allocate enough tx contexts */
if (i < PCAN_USB_MAX_TX_URBS) {
if (i == 0) {
netdev_err(netdev, "couldn't setup any tx URB\n");
goto err_tx;
}
netdev_warn(netdev, "tx performance may be slow\n");
}
if (dev->adapter->dev_start) {
err = dev->adapter->dev_start(dev);
if (err)
goto err_adapter;
}
dev->state |= PCAN_USB_STATE_STARTED;
/* can set bus on now */
if (dev->adapter->dev_set_bus) {
err = dev->adapter->dev_set_bus(dev, 1);
if (err)
goto err_adapter;
}
dev->can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
err_adapter:
if (err == -ENODEV)
netif_device_detach(dev->netdev);
netdev_warn(netdev, "couldn't submit control: %d\n", err);
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
usb_free_urb(dev->tx_contexts[i].urb);
dev->tx_contexts[i].urb = NULL;
}
err_tx:
usb_kill_anchored_urbs(&dev->rx_submitted);
return err;
}
/*
* called by netdev to open the corresponding CAN interface.
*/
static int peak_usb_ndo_open(struct net_device *netdev)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err;
/* common open */
err = open_candev(netdev);
if (err)
return err;
/* finally start device */
err = peak_usb_start(dev);
if (err) {
netdev_err(netdev, "couldn't start device: %d\n", err);
close_candev(netdev);
return err;
}
netif_start_queue(netdev);
return 0;
}
/*
* unlink in-flight Rx and Tx urbs and free their memory.
*/
static void peak_usb_unlink_all_urbs(struct peak_usb_device *dev)
{
int i;
/* free all Rx (submitted) urbs */
usb_kill_anchored_urbs(&dev->rx_submitted);
/* free unsubmitted Tx urbs first */
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
struct urb *urb = dev->tx_contexts[i].urb;
if (!urb ||
dev->tx_contexts[i].echo_index != PCAN_USB_MAX_TX_URBS) {
/*
* this urb is already released or always submitted,
* let usb core free by itself
*/
continue;
}
usb_free_urb(urb);
dev->tx_contexts[i].urb = NULL;
}
/* then free all submitted Tx urbs */
usb_kill_anchored_urbs(&dev->tx_submitted);
atomic_set(&dev->active_tx_urbs, 0);
}
/*
* called by netdev to close the corresponding CAN interface.
*/
static int peak_usb_ndo_stop(struct net_device *netdev)
{
struct peak_usb_device *dev = netdev_priv(netdev);
dev->state &= ~PCAN_USB_STATE_STARTED;
netif_stop_queue(netdev);
/* unlink all pending urbs and free used memory */
peak_usb_unlink_all_urbs(dev);
if (dev->adapter->dev_stop)
dev->adapter->dev_stop(dev);
close_candev(netdev);
dev->can.state = CAN_STATE_STOPPED;
/* can set bus off now */
if (dev->adapter->dev_set_bus) {
int err = dev->adapter->dev_set_bus(dev, 0);
if (err)
return err;
}
return 0;
}
/*
* handle end of waiting for the device to reset
*/
void peak_usb_restart_complete(struct peak_usb_device *dev)
{
/* finally MUST update can state */
dev->can.state = CAN_STATE_ERROR_ACTIVE;
/* netdev queue can be awaken now */
netif_wake_queue(dev->netdev);
}
void peak_usb_async_complete(struct urb *urb)
{
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
/*
* device (auto-)restart mechanism runs in a timer context =>
* MUST handle restart with asynchronous usb transfers
*/
static int peak_usb_restart(struct peak_usb_device *dev)
{
struct urb *urb;
int err;
u8 *buf;
/*
* if device doesn't define any asynchronous restart handler, simply
* wake the netdev queue up
*/
if (!dev->adapter->dev_restart_async) {
peak_usb_restart_complete(dev);
return 0;
}
/* first allocate a urb to handle the asynchronous steps */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
netdev_err(dev->netdev, "no memory left for urb\n");
return -ENOMEM;
}
/* also allocate enough space for the commands to send */
buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC);
if (!buf) {
usb_free_urb(urb);
return -ENOMEM;
}
/* call the device specific handler for the restart */
err = dev->adapter->dev_restart_async(dev, urb, buf);
if (!err)
return 0;
kfree(buf);
usb_free_urb(urb);
return err;
}
/*
* candev callback used to change CAN mode.
* Warning: this is called from a timer context!
*/
static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (mode) {
case CAN_MODE_START:
err = peak_usb_restart(dev);
if (err)
netdev_err(netdev, "couldn't start device (err %d)\n",
err);
break;
default:
return -EOPNOTSUPP;
}
return err;
}
/*
* candev callback used to set device bitrate.
*/
static int peak_usb_set_bittiming(struct net_device *netdev)
{
struct peak_usb_device *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.bittiming;
if (dev->adapter->dev_set_bittiming) {
int err = dev->adapter->dev_set_bittiming(dev, bt);
if (err)
netdev_info(netdev, "couldn't set bitrate (err %d)\n",
err);
return err;
}
return 0;
}
static const struct net_device_ops peak_usb_netdev_ops = {
.ndo_open = peak_usb_ndo_open,
.ndo_stop = peak_usb_ndo_stop,
.ndo_start_xmit = peak_usb_ndo_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
/*
* create one device which is attached to CAN controller #ctrl_idx of the
* usb adapter.
*/
static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
struct usb_interface *intf, int ctrl_idx)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
int sizeof_candev = peak_usb_adapter->sizeof_dev_private;
struct peak_usb_device *dev;
struct net_device *netdev;
int i, err;
u16 tmp16;
if (sizeof_candev < sizeof(struct peak_usb_device))
sizeof_candev = sizeof(struct peak_usb_device);
netdev = alloc_candev(sizeof_candev, PCAN_USB_MAX_TX_URBS);
if (!netdev) {
dev_err(&intf->dev, "%s: couldn't alloc candev\n",
PCAN_USB_DRIVER_NAME);
return -ENOMEM;
}
dev = netdev_priv(netdev);
/* allocate a buffer large enough to send commands */
dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
if (!dev->cmd_buf) {
err = -ENOMEM;
goto lbl_free_candev;
}
dev->udev = usb_dev;
dev->netdev = netdev;
dev->adapter = peak_usb_adapter;
dev->ctrl_idx = ctrl_idx;
dev->state = PCAN_USB_STATE_CONNECTED;
dev->ep_msg_in = peak_usb_adapter->ep_msg_in;
dev->ep_msg_out = peak_usb_adapter->ep_msg_out[ctrl_idx];
dev->can.clock = peak_usb_adapter->clock;
dev->can.bittiming_const = &peak_usb_adapter->bittiming_const;
dev->can.do_set_bittiming = peak_usb_set_bittiming;
dev->can.do_set_mode = peak_usb_set_mode;
dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LISTENONLY;
netdev->netdev_ops = &peak_usb_netdev_ops;
netdev->flags |= IFF_ECHO; /* we support local echo */
init_usb_anchor(&dev->rx_submitted);
init_usb_anchor(&dev->tx_submitted);
atomic_set(&dev->active_tx_urbs, 0);
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++)
dev->tx_contexts[i].echo_index = PCAN_USB_MAX_TX_URBS;
dev->prev_siblings = usb_get_intfdata(intf);
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
netdev->dev_id = ctrl_idx;
err = register_candev(netdev);
if (err) {
dev_err(&intf->dev, "couldn't register CAN device: %d\n", err);
goto lbl_restore_intf_data;
}
if (dev->prev_siblings)
(dev->prev_siblings)->next_siblings = dev;
/* keep hw revision into the netdevice */
tmp16 = le16_to_cpu(usb_dev->descriptor.bcdDevice);
dev->device_rev = tmp16 >> 8;
if (dev->adapter->dev_init) {
err = dev->adapter->dev_init(dev);
if (err)
goto lbl_unregister_candev;
}
/* set bus off */
if (dev->adapter->dev_set_bus) {
err = dev->adapter->dev_set_bus(dev, 0);
if (err)
goto lbl_unregister_candev;
}
/* get device number early */
if (dev->adapter->dev_get_device_id)
dev->adapter->dev_get_device_id(dev, &dev->device_number);
netdev_info(netdev, "attached to %s channel %u (device %u)\n",
peak_usb_adapter->name, ctrl_idx, dev->device_number);
return 0;
lbl_unregister_candev:
unregister_candev(netdev);
lbl_restore_intf_data:
usb_set_intfdata(intf, dev->prev_siblings);
kfree(dev->cmd_buf);
lbl_free_candev:
free_candev(netdev);
return err;
}
/*
* called by the usb core when the device is unplugged from the system
*/
static void peak_usb_disconnect(struct usb_interface *intf)
{
struct peak_usb_device *dev;
/* unregister as many netdev devices as siblings */
for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) {
struct net_device *netdev = dev->netdev;
char name[IFNAMSIZ];
dev->state &= ~PCAN_USB_STATE_CONNECTED;
strncpy(name, netdev->name, IFNAMSIZ);
unregister_netdev(netdev);
free_candev(netdev);
kfree(dev->cmd_buf);
dev->next_siblings = NULL;
if (dev->adapter->dev_free)
dev->adapter->dev_free(dev);
dev_info(&intf->dev, "%s removed\n", name);
}
usb_set_intfdata(intf, NULL);
}
/*
* probe function for new PEAK-System devices
*/
static int peak_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct peak_usb_adapter *peak_usb_adapter, **pp;
int i, err = -ENOMEM;
usb_dev = interface_to_usbdev(intf);
/* get corresponding PCAN-USB adapter */
for (pp = peak_usb_adapters_list; *pp; pp++)
if ((*pp)->device_id == usb_dev->descriptor.idProduct)
break;
peak_usb_adapter = *pp;
if (!peak_usb_adapter) {
/* should never come except device_id bad usage in this file */
pr_err("%s: didn't find device id. 0x%x in devices list\n",
PCAN_USB_DRIVER_NAME, usb_dev->descriptor.idProduct);
return -ENODEV;
}
/* got corresponding adapter: check if it handles current interface */
if (peak_usb_adapter->intf_probe) {
err = peak_usb_adapter->intf_probe(intf);
if (err)
return err;
}
for (i = 0; i < peak_usb_adapter->ctrl_count; i++) {
err = peak_usb_create_dev(peak_usb_adapter, intf, i);
if (err) {
/* deregister already created devices */
peak_usb_disconnect(intf);
break;
}
}
return err;
}
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver peak_usb_driver = {
.name = PCAN_USB_DRIVER_NAME,
.disconnect = peak_usb_disconnect,
.probe = peak_usb_probe,
.id_table = peak_usb_table,
};
static int __init peak_usb_init(void)
{
int err;
/* register this driver with the USB subsystem */
err = usb_register(&peak_usb_driver);
if (err)
pr_err("%s: usb_register failed (err %d)\n",
PCAN_USB_DRIVER_NAME, err);
return err;
}
static int peak_usb_do_device_exit(struct device *d, void *arg)
{
struct usb_interface *intf = to_usb_interface(d);
struct peak_usb_device *dev;
/* stop as many netdev devices as siblings */
for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) {
struct net_device *netdev = dev->netdev;
if (netif_device_present(netdev))
if (dev->adapter->dev_exit)
dev->adapter->dev_exit(dev);
}
return 0;
}
static void __exit peak_usb_exit(void)
{
int err;
/* last chance do send any synchronous commands here */
err = driver_for_each_device(&peak_usb_driver.drvwrap.driver, NULL,
NULL, peak_usb_do_device_exit);
if (err)
pr_err("%s: failed to stop all can devices (err %d)\n",
PCAN_USB_DRIVER_NAME, err);
/* deregister this driver with the USB subsystem */
usb_deregister(&peak_usb_driver);
pr_info("%s: PCAN-USB interfaces driver unloaded\n",
PCAN_USB_DRIVER_NAME);
}
module_init(peak_usb_init);
module_exit(peak_usb_exit);

View file

@ -0,0 +1,145 @@
/*
* CAN driver for PEAK System USB adapters
* Derived from the PCAN project file driver/src/pcan_usb_core.c
*
* Copyright (C) 2003-2010 PEAK System-Technik GmbH
* Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*
* 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; version 2 of the License.
*
* 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.
*/
#ifndef PCAN_USB_CORE_H
#define PCAN_USB_CORE_H
/* PEAK-System vendor id. */
#define PCAN_USB_VENDOR_ID 0x0c72
/* supported device ids. */
#define PCAN_USB_PRODUCT_ID 0x000c
#define PCAN_USBPRO_PRODUCT_ID 0x000d
#define PCAN_USB_DRIVER_NAME "peak_usb"
/* number of urbs that are submitted for rx/tx per channel */
#define PCAN_USB_MAX_RX_URBS 4
#define PCAN_USB_MAX_TX_URBS 10
/* usb adapters maximum channels per usb interface */
#define PCAN_USB_MAX_CHANNEL 2
/* maximum length of the usb commands sent to/received from the devices */
#define PCAN_USB_MAX_CMD_LEN 32
struct peak_usb_device;
/* PEAK-System USB adapter descriptor */
struct peak_usb_adapter {
char *name;
u32 device_id;
struct can_clock clock;
const struct can_bittiming_const bittiming_const;
unsigned int ctrl_count;
int (*intf_probe)(struct usb_interface *intf);
int (*dev_init)(struct peak_usb_device *dev);
void (*dev_exit)(struct peak_usb_device *dev);
void (*dev_free)(struct peak_usb_device *dev);
int (*dev_open)(struct peak_usb_device *dev);
int (*dev_close)(struct peak_usb_device *dev);
int (*dev_set_bittiming)(struct peak_usb_device *dev,
struct can_bittiming *bt);
int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff);
int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id);
int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb);
int (*dev_encode_msg)(struct peak_usb_device *dev, struct sk_buff *skb,
u8 *obuf, size_t *size);
int (*dev_start)(struct peak_usb_device *dev);
int (*dev_stop)(struct peak_usb_device *dev);
int (*dev_restart_async)(struct peak_usb_device *dev, struct urb *urb,
u8 *buf);
u8 ep_msg_in;
u8 ep_msg_out[PCAN_USB_MAX_CHANNEL];
u8 ts_used_bits;
u32 ts_period;
u8 us_per_ts_shift;
u32 us_per_ts_scale;
int rx_buffer_size;
int tx_buffer_size;
int sizeof_dev_private;
};
extern struct peak_usb_adapter pcan_usb;
extern struct peak_usb_adapter pcan_usb_pro;
struct peak_time_ref {
struct timeval tv_host_0, tv_host;
u32 ts_dev_1, ts_dev_2;
u64 ts_total;
u32 tick_count;
struct peak_usb_adapter *adapter;
};
struct peak_tx_urb_context {
struct peak_usb_device *dev;
u32 echo_index;
u8 dlc;
struct urb *urb;
};
#define PCAN_USB_STATE_CONNECTED 0x00000001
#define PCAN_USB_STATE_STARTED 0x00000002
/* PEAK-System USB device */
struct peak_usb_device {
struct can_priv can;
struct peak_usb_adapter *adapter;
unsigned int ctrl_idx;
u32 state;
struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS];
struct usb_device *udev;
struct net_device *netdev;
atomic_t active_tx_urbs;
struct usb_anchor tx_submitted;
struct peak_tx_urb_context tx_contexts[PCAN_USB_MAX_TX_URBS];
u8 *cmd_buf;
struct usb_anchor rx_submitted;
u32 device_number;
u8 device_rev;
u8 ep_msg_in;
u8 ep_msg_out;
u16 bus_load;
struct peak_usb_device *prev_siblings;
struct peak_usb_device *next_siblings;
};
void pcan_dump_mem(char *prompt, void *p, int l);
/* common timestamp management */
void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
struct peak_usb_adapter *adapter);
void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts,
struct timeval *tv);
void peak_usb_async_complete(struct urb *urb);
void peak_usb_restart_complete(struct peak_usb_device *dev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,179 @@
/*
* CAN driver for PEAK System PCAN-USB Pro adapter
* Derived from the PCAN project file driver/src/pcan_usbpro_fw.h
*
* Copyright (C) 2003-2011 PEAK System-Technik GmbH
* Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* 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; version 2 of the License.
*
* 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.
*/
#ifndef PCAN_USB_PRO_H
#define PCAN_USB_PRO_H
/*
* USB Vendor request data types
*/
#define PCAN_USBPRO_REQ_INFO 0
#define PCAN_USBPRO_REQ_FCT 2
/* Vendor Request value for XXX_INFO */
#define PCAN_USBPRO_INFO_BL 0
#define PCAN_USBPRO_INFO_FW 1
/* Vendor Request value for XXX_FCT */
#define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */
#define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16
/* PCAN_USBPRO_INFO_BL vendor request record type */
struct __packed pcan_usb_pro_blinfo {
u32 ctrl_type;
u8 version[4];
u8 day;
u8 month;
u8 year;
u8 dummy;
u32 serial_num_hi;
u32 serial_num_lo;
u32 hw_type;
u32 hw_rev;
};
/* PCAN_USBPRO_INFO_FW vendor request record type */
struct __packed pcan_usb_pro_fwinfo {
u32 ctrl_type;
u8 version[4];
u8 day;
u8 month;
u8 year;
u8 dummy;
u32 fw_type;
};
/*
* USB Command record types
*/
#define PCAN_USBPRO_SETBTR 0x02
#define PCAN_USBPRO_SETBUSACT 0x04
#define PCAN_USBPRO_SETSILENT 0x05
#define PCAN_USBPRO_SETFILTR 0x0a
#define PCAN_USBPRO_SETTS 0x10
#define PCAN_USBPRO_GETDEVID 0x12
#define PCAN_USBPRO_SETLED 0x1C
#define PCAN_USBPRO_RXMSG8 0x80
#define PCAN_USBPRO_RXMSG4 0x81
#define PCAN_USBPRO_RXMSG0 0x82
#define PCAN_USBPRO_RXRTR 0x83
#define PCAN_USBPRO_RXSTATUS 0x84
#define PCAN_USBPRO_RXTS 0x85
#define PCAN_USBPRO_TXMSG8 0x41
#define PCAN_USBPRO_TXMSG4 0x42
#define PCAN_USBPRO_TXMSG0 0x43
/* record structures */
struct __packed pcan_usb_pro_btr {
u8 data_type;
u8 channel;
u16 dummy;
u32 CCBT;
};
struct __packed pcan_usb_pro_busact {
u8 data_type;
u8 channel;
u16 onoff;
};
struct __packed pcan_usb_pro_silent {
u8 data_type;
u8 channel;
u16 onoff;
};
struct __packed pcan_usb_pro_filter {
u8 data_type;
u8 dummy;
u16 filter_mode;
};
struct __packed pcan_usb_pro_setts {
u8 data_type;
u8 dummy;
u16 mode;
};
struct __packed pcan_usb_pro_devid {
u8 data_type;
u8 channel;
u16 dummy;
u32 serial_num;
};
struct __packed pcan_usb_pro_setled {
u8 data_type;
u8 channel;
u16 mode;
u32 timeout;
};
struct __packed pcan_usb_pro_rxmsg {
u8 data_type;
u8 client;
u8 flags;
u8 len;
u32 ts32;
u32 id;
u8 data[8];
};
#define PCAN_USBPRO_STATUS_ERROR 0x0001
#define PCAN_USBPRO_STATUS_BUS 0x0002
#define PCAN_USBPRO_STATUS_OVERRUN 0x0004
#define PCAN_USBPRO_STATUS_QOVERRUN 0x0008
struct __packed pcan_usb_pro_rxstatus {
u8 data_type;
u8 channel;
u16 status;
u32 ts32;
u32 err_frm;
};
struct __packed pcan_usb_pro_rxts {
u8 data_type;
u8 dummy[3];
u32 ts64[2];
};
struct __packed pcan_usb_pro_txmsg {
u8 data_type;
u8 client;
u8 flags;
u8 len;
u32 id;
u8 data[8];
};
union pcan_usb_pro_rec {
u8 data_type;
struct pcan_usb_pro_btr btr;
struct pcan_usb_pro_busact bus_act;
struct pcan_usb_pro_silent silent_mode;
struct pcan_usb_pro_filter filter_mode;
struct pcan_usb_pro_setts ts;
struct pcan_usb_pro_devid dev_id;
struct pcan_usb_pro_setled set_led;
struct pcan_usb_pro_rxmsg rx_msg;
struct pcan_usb_pro_rxstatus rx_status;
struct pcan_usb_pro_rxts rx_ts;
struct pcan_usb_pro_txmsg tx_msg;
};
#endif

File diff suppressed because it is too large Load diff

190
drivers/net/can/vcan.c Normal file
View file

@ -0,0 +1,190 @@
/*
* vcan.c - Virtual CAN interface
*
* 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/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
#include <linux/slab.h>
#include <net/rtnetlink.h>
static __initconst const char banner[] =
KERN_INFO "vcan: Virtual CAN interface driver\n";
MODULE_DESCRIPTION("virtual CAN interface");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
/*
* CAN test feature:
* Enable the echo on driver level for testing the CAN core echo modes.
* See Documentation/networking/can.txt for details.
*/
static bool echo; /* echo testing. Default: 0 (Off) */
module_param(echo, bool, S_IRUGO);
MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
{
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
struct net_device_stats *stats = &dev->stats;
stats->rx_packets++;
stats->rx_bytes += cfd->len;
skb->pkt_type = PACKET_BROADCAST;
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx_ni(skb);
}
static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
{
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
struct net_device_stats *stats = &dev->stats;
int loop;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
stats->tx_packets++;
stats->tx_bytes += cfd->len;
/* set flag whether this packet has to be looped back */
loop = skb->pkt_type == PACKET_LOOPBACK;
if (!echo) {
/* no echo handling available inside this driver */
if (loop) {
/*
* only count the packets here, because the
* CAN core already did the echo for us
*/
stats->rx_packets++;
stats->rx_bytes += cfd->len;
}
consume_skb(skb);
return NETDEV_TX_OK;
}
/* perform standard echo handling for CAN network interfaces */
if (loop) {
skb = can_create_echo_skb(skb);
if (!skb)
return NETDEV_TX_OK;
/* receive with packet counting */
vcan_rx(skb, dev);
} else {
/* no looped packets => no counting */
consume_skb(skb);
}
return NETDEV_TX_OK;
}
static int vcan_change_mtu(struct net_device *dev, int new_mtu)
{
/* Do not allow changing the MTU while running */
if (dev->flags & IFF_UP)
return -EBUSY;
if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
static const struct net_device_ops vcan_netdev_ops = {
.ndo_start_xmit = vcan_tx,
.ndo_change_mtu = vcan_change_mtu,
};
static void vcan_setup(struct net_device *dev)
{
dev->type = ARPHRD_CAN;
dev->mtu = CAN_MTU;
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->tx_queue_len = 0;
dev->flags = IFF_NOARP;
/* set flags according to driver capabilities */
if (echo)
dev->flags |= IFF_ECHO;
dev->netdev_ops = &vcan_netdev_ops;
dev->destructor = free_netdev;
}
static struct rtnl_link_ops vcan_link_ops __read_mostly = {
.kind = "vcan",
.setup = vcan_setup,
};
static __init int vcan_init_module(void)
{
printk(banner);
if (echo)
printk(KERN_INFO "vcan: enabled echo on driver level.\n");
return rtnl_link_register(&vcan_link_ops);
}
static __exit void vcan_cleanup_module(void)
{
rtnl_link_unregister(&vcan_link_ops);
}
module_init(vcan_init_module);
module_exit(vcan_cleanup_module);

1210
drivers/net/can/xilinx_can.c Normal file

File diff suppressed because it is too large Load diff