aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/can
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/can')
-rw-r--r--drivers/net/can/Kconfig72
-rw-r--r--drivers/net/can/Makefile7
-rw-r--r--drivers/net/can/at91_can.c117
-rw-r--r--drivers/net/can/bfin_can.c25
-rw-r--r--drivers/net/can/c_can/Kconfig2
-rw-r--r--drivers/net/can/c_can/c_can.c958
-rw-r--r--drivers/net/can/c_can/c_can.h39
-rw-r--r--drivers/net/can/c_can/c_can_pci.c97
-rw-r--r--drivers/net/can/c_can/c_can_platform.c149
-rw-r--r--drivers/net/can/cc770/Kconfig2
-rw-r--r--drivers/net/can/cc770/cc770.c1
-rw-r--r--drivers/net/can/cc770/cc770_isa.c23
-rw-r--r--drivers/net/can/cc770/cc770_platform.c26
-rw-r--r--drivers/net/can/dev.c289
-rw-r--r--drivers/net/can/flexcan.c361
-rw-r--r--drivers/net/can/grcan.c1752
-rw-r--r--drivers/net/can/janz-ican3.c118
-rw-r--r--drivers/net/can/led.c127
-rw-r--r--drivers/net/can/mscan/Kconfig2
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c323
-rw-r--r--drivers/net/can/mscan/mscan.c43
-rw-r--r--drivers/net/can/mscan/mscan.h13
-rw-r--r--drivers/net/can/pch_can.c14
-rw-r--r--drivers/net/can/rcar_can.c876
-rw-r--r--drivers/net/can/sja1000/Kconfig29
-rw-r--r--drivers/net/can/sja1000/Makefile1
-rw-r--r--drivers/net/can/sja1000/ems_pci.c16
-rw-r--r--drivers/net/can/sja1000/ems_pcmcia.c25
-rw-r--r--drivers/net/can/sja1000/kvaser_pci.c17
-rw-r--r--drivers/net/can/sja1000/peak_pci.c47
-rw-r--r--drivers/net/can/sja1000/peak_pcmcia.c25
-rw-r--r--drivers/net/can/sja1000/plx_pci.c80
-rw-r--r--drivers/net/can/sja1000/sja1000.c174
-rw-r--r--drivers/net/can/sja1000/sja1000.h69
-rw-r--r--drivers/net/can/sja1000/sja1000_isa.c40
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c223
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c203
-rw-r--r--drivers/net/can/sja1000/tscan1.c8
-rw-r--r--drivers/net/can/slcan.c192
-rw-r--r--drivers/net/can/softing/Kconfig2
-rw-r--r--drivers/net/can/softing/softing.h24
-rw-r--r--drivers/net/can/softing/softing_cs.c30
-rw-r--r--drivers/net/can/softing/softing_fw.c3
-rw-r--r--drivers/net/can/softing/softing_main.c44
-rw-r--r--drivers/net/can/spi/Kconfig10
-rw-r--r--drivers/net/can/spi/Makefile8
-rw-r--r--drivers/net/can/spi/mcp251x.c (renamed from drivers/net/can/mcp251x.c)380
-rw-r--r--drivers/net/can/ti_hecc.c44
-rw-r--r--drivers/net/can/usb/Kconfig47
-rw-r--r--drivers/net/can/usb/Makefile3
-rw-r--r--drivers/net/can/usb/ems_usb.c20
-rw-r--r--drivers/net/can/usb/esd_usb2.c183
-rw-r--r--drivers/net/can/usb/gs_usb.c971
-rw-r--r--drivers/net/can/usb/kvaser_usb.c1665
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb.c10
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c27
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.h1
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c72
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.h1
-rw-r--r--drivers/net/can/usb/usb_8dev.c1035
-rw-r--r--drivers/net/can/vcan.c9
-rw-r--r--drivers/net/can/xilinx_can.c1208
62 files changed, 10326 insertions, 2056 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index bb709fd6699..41688229c57 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -1,9 +1,7 @@
menu "CAN Device Drivers"
- depends on CAN
config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)"
- depends on CAN
---help---
Similar to the network loopback devices, vcan offers a
virtual local CAN interface.
@@ -13,7 +11,7 @@ config CAN_VCAN
config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)"
- depends on CAN
+ 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
@@ -33,16 +31,16 @@ config CAN_SLCAN
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
- depends on CAN
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"
- depends on CAN_DEV
default y
---help---
If enabled, CAN bit-timing parameters will be calculated for the
@@ -54,28 +52,33 @@ config CAN_CALC_BITTIMING
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 CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
+ depends on ARCH_AT91 || COMPILE_TEST
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors.
config CAN_TI_HECC
- depends on CAN_DEV && ARCH_OMAP3
+ 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_MCP251X
- tristate "Microchip MCP251x SPI CAN controllers"
- depends on CAN_DEV && SPI && HAS_DMA
- ---help---
- Driver for the Microchip MCP251x SPI CAN controllers.
-
config CAN_BFIN
- depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x)
+ 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
@@ -85,7 +88,7 @@ config CAN_BFIN
config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
- depends on CAN_DEV && MFD_JANZ_CMODIO
+ depends on MFD_JANZ_CMODIO
---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board.
@@ -93,23 +96,47 @@ config CAN_JANZ_ICAN3
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
-config HAVE_CAN_FLEXCAN
- bool
-
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
- depends on CAN_DEV && HAVE_CAN_FLEXCAN
+ 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 CAN_DEV && PCI
+ 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"
@@ -118,13 +145,16 @@ source "drivers/net/can/c_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"
- depends on CAN
---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
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 938be37b670..1697f22353a 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -8,6 +8,9 @@ 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/
@@ -17,10 +20,12 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
-obj-$(CONFIG_CAN_MCP251X) += mcp251x.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
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index fcff73a73b1..f07fa89b5fd 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -22,22 +22,22 @@
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/platform_data/atmel.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
-
-#include <mach/board.h>
+#include <linux/can/led.h>
#define AT91_MB_MASK(i) ((1 << (i)) - 1)
@@ -155,19 +155,20 @@ struct at91_priv {
canid_t mb0_id;
};
-static const struct at91_devtype_data at91_devtype_data[] __devinitconst = {
- [AT91_DEVTYPE_SAM9263] = {
- .rx_first = 1,
- .rx_split = 8,
- .rx_last = 11,
- .tx_shift = 2,
- },
- [AT91_DEVTYPE_SAM9X5] = {
- .rx_first = 0,
- .rx_split = 4,
- .rx_last = 5,
- .tx_shift = 1,
- },
+static const struct at91_devtype_data at91_at91sam9263_data = {
+ .rx_first = 1,
+ .rx_split = 8,
+ .rx_last = 11,
+ .tx_shift = 2,
+ .type = AT91_DEVTYPE_SAM9263,
+};
+
+static const struct at91_devtype_data at91_at91sam9x5_data = {
+ .rx_first = 0,
+ .rx_split = 4,
+ .rx_last = 5,
+ .tx_shift = 1,
+ .type = AT91_DEVTYPE_SAM9X5,
};
static const struct can_bittiming_const at91_bittiming_const = {
@@ -419,7 +420,11 @@ static void at91_chip_start(struct net_device *dev)
at91_transceiver_switch(priv, 1);
/* enable chip */
- at91_write(priv, AT91_MR, AT91_MR_CANEN);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ reg_mr = AT91_MR_CANEN | AT91_MR_ABM;
+ else
+ reg_mr = AT91_MR_CANEN;
+ at91_write(priv, AT91_MR, reg_mr);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -642,6 +647,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+
+ can_led_event(dev, CAN_LED_EVENT_RX);
}
/**
@@ -876,6 +883,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
dev->stats.tx_packets++;
+ can_led_event(dev, CAN_LED_EVENT_TX);
}
}
@@ -1129,6 +1137,8 @@ static int at91_open(struct net_device *dev)
goto out_close;
}
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
/* start chip and queuing */
at91_chip_start(dev);
napi_enable(&priv->napi);
@@ -1160,6 +1170,8 @@ static int at91_close(struct net_device *dev)
close_candev(dev);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -1182,6 +1194,7 @@ static const struct net_device_ops at91_netdev_ops = {
.ndo_open = at91_open,
.ndo_stop = at91_close,
.ndo_start_xmit = at91_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
@@ -1211,7 +1224,7 @@ static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
goto out;
}
- err = strict_strtoul(buf, 0, &can_id);
+ err = kstrtoul(buf, 0, &can_id);
if (err) {
ret = err;
goto out;
@@ -1242,10 +1255,40 @@ static struct attribute_group at91_sysfs_attr_group = {
.attrs = at91_sysfs_attrs,
};
-static int __devinit at91_can_probe(struct platform_device *pdev)
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_can_dt_ids[] = {
+ {
+ .compatible = "atmel,at91sam9x5-can",
+ .data = &at91_at91sam9x5_data,
+ }, {
+ .compatible = "atmel,at91sam9263-can",
+ .data = &at91_at91sam9263_data,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, at91_can_dt_ids);
+#endif
+
+static const struct at91_devtype_data *at91_can_get_driver_data(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+
+ match = of_match_node(at91_can_dt_ids, pdev->dev.of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "no matching node found in dtb\n");
+ return NULL;
+ }
+ return (const struct at91_devtype_data *)match->data;
+ }
+ return (const struct at91_devtype_data *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
+static int at91_can_probe(struct platform_device *pdev)
{
const struct at91_devtype_data *devtype_data;
- enum at91_devtype devtype;
struct net_device *dev;
struct at91_priv *priv;
struct resource *res;
@@ -1253,8 +1296,12 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
void __iomem *addr;
int err, irq;
- devtype = pdev->id_entry->driver_data;
- devtype_data = &at91_devtype_data[devtype];
+ devtype_data = at91_can_get_driver_data(pdev);
+ if (!devtype_data) {
+ dev_err(&pdev->dev, "no driver data\n");
+ err = -ENODEV;
+ goto exit;
+ }
clk = clk_get(&pdev->dev, "can_clk");
if (IS_ERR(clk)) {
@@ -1299,13 +1346,13 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
priv->can.bittiming_const = &at91_bittiming_const;
priv->can.do_set_mode = at91_set_mode;
priv->can.do_get_berr_counter = at91_get_berr_counter;
- priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_LISTENONLY;
priv->dev = dev;
priv->reg_base = addr;
priv->devtype_data = *devtype_data;
- priv->devtype_data.type = devtype;
priv->clk = clk;
- priv->pdata = pdev->dev.platform_data;
+ priv->pdata = dev_get_platdata(&pdev->dev);
priv->mb0_id = 0x7ff;
netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv));
@@ -1313,7 +1360,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
if (at91_is_sam9263(priv))
dev->sysfs_groups[0] = &at91_sysfs_attr_group;
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_candev(dev);
@@ -1322,6 +1369,8 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
goto exit_free;
}
+ devm_can_led_init(dev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->reg_base, dev->irq);
@@ -1339,7 +1388,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
return err;
}
-static int __devexit at91_can_remove(struct platform_device *pdev)
+static int at91_can_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct at91_priv *priv = netdev_priv(dev);
@@ -1347,8 +1396,6 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
unregister_netdev(dev);
- platform_set_drvdata(pdev, NULL);
-
iounmap(priv->reg_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1363,22 +1410,24 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
static const struct platform_device_id at91_can_id_table[] = {
{
- .name = "at91_can",
- .driver_data = AT91_DEVTYPE_SAM9263,
- }, {
.name = "at91sam9x5_can",
- .driver_data = AT91_DEVTYPE_SAM9X5,
+ .driver_data = (kernel_ulong_t)&at91_at91sam9x5_data,
+ }, {
+ .name = "at91_can",
+ .driver_data = (kernel_ulong_t)&at91_at91sam9263_data,
}, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(platform, at91_can_id_table);
static struct platform_driver at91_can_driver = {
.probe = at91_can_probe,
- .remove = __devexit_p(at91_can_remove),
+ .remove = at91_can_remove,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_can_dt_ids),
},
.id_table = at91_can_id_table,
};
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index f2d6d258a28..543ecceb33e 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -9,7 +9,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
@@ -412,7 +411,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
return 0;
}
-irqreturn_t bfin_can_interrupt(int irq, void *dev_id)
+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);
@@ -504,7 +503,7 @@ static int bfin_can_close(struct net_device *dev)
return 0;
}
-struct net_device *alloc_bfin_candev(void)
+static struct net_device *alloc_bfin_candev(void)
{
struct net_device *dev;
struct bfin_can_priv *priv;
@@ -529,9 +528,10 @@ 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 __devinit bfin_can_probe(struct platform_device *pdev)
+static int bfin_can_probe(struct platform_device *pdev)
{
int err;
struct net_device *dev;
@@ -539,7 +539,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev)
struct resource *res_mem, *rx_irq, *tx_irq, *err_irq;
unsigned short *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform data provided!\n");
err = -EINVAL;
@@ -580,7 +580,7 @@ static int __devinit bfin_can_probe(struct platform_device *pdev)
priv->pin_list = pdata;
priv->can.clock.freq = get_sclk();
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->flags |= IFF_ECHO; /* we support local echo */
@@ -611,9 +611,9 @@ exit:
return err;
}
-static int __devexit bfin_can_remove(struct platform_device *pdev)
+static int bfin_can_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct resource *res;
@@ -621,8 +621,6 @@ static int __devexit bfin_can_remove(struct platform_device *pdev)
unregister_candev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
@@ -635,7 +633,7 @@ static int __devexit bfin_can_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ 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;
@@ -658,7 +656,7 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg)
static int bfin_can_resume(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
@@ -677,7 +675,7 @@ static int bfin_can_resume(struct platform_device *pdev)
static struct platform_driver bfin_can_driver = {
.probe = bfin_can_probe,
- .remove = __devexit_p(bfin_can_remove),
+ .remove = bfin_can_remove,
.suspend = bfin_can_suspend,
.resume = bfin_can_resume,
.driver = {
@@ -691,3 +689,4 @@ 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);
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index 3b83bafcd94..61ffc12d8fd 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_C_CAN
tristate "Bosch C_CAN/D_CAN devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_C_CAN
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index e5180dfddba..8e78bb48f5a 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -39,6 +39,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include "c_can.h"
@@ -59,6 +60,8 @@
#define CONTROL_IE BIT(1)
#define CONTROL_INIT BIT(0)
+#define CONTROL_IRQMSK (CONTROL_EIE | CONTROL_IE | CONTROL_SIE)
+
/* test register */
#define TEST_RX BIT(7)
#define TEST_TX1 BIT(6)
@@ -107,21 +110,38 @@
#define IF_COMM_CONTROL BIT(4)
#define IF_COMM_CLR_INT_PND BIT(3)
#define IF_COMM_TXRQST BIT(2)
+#define IF_COMM_CLR_NEWDAT IF_COMM_TXRQST
#define IF_COMM_DATAA BIT(1)
#define IF_COMM_DATAB BIT(0)
-#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \
- IF_COMM_CONTROL | IF_COMM_TXRQST | \
- IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* TX buffer setup */
+#define IF_COMM_TX (IF_COMM_ARB | IF_COMM_CONTROL | \
+ IF_COMM_TXRQST | \
+ IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* For the low buffers we clear the interrupt bit, but keep newdat */
+#define IF_COMM_RCV_LOW (IF_COMM_MASK | IF_COMM_ARB | \
+ IF_COMM_CONTROL | IF_COMM_CLR_INT_PND | \
+ IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* For the high buffers we clear the interrupt bit and newdat */
+#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_CLR_NEWDAT)
+
+
+/* Receive setup of message objects */
+#define IF_COMM_RCV_SETUP (IF_COMM_MASK | IF_COMM_ARB | IF_COMM_CONTROL)
+
+/* Invalidation of message objects */
+#define IF_COMM_INVAL (IF_COMM_ARB | IF_COMM_CONTROL)
/* IFx arbitration */
-#define IF_ARB_MSGVAL BIT(15)
-#define IF_ARB_MSGXTD BIT(14)
-#define IF_ARB_TRANSMIT BIT(13)
+#define IF_ARB_MSGVAL BIT(31)
+#define IF_ARB_MSGXTD BIT(30)
+#define IF_ARB_TRANSMIT BIT(29)
/* IFx message control */
#define IF_MCONT_NEWDAT BIT(15)
#define IF_MCONT_MSGLST BIT(14)
-#define IF_MCONT_CLR_MSGLST (0 << 14)
#define IF_MCONT_INTPND BIT(13)
#define IF_MCONT_UMASK BIT(12)
#define IF_MCONT_TXIE BIT(11)
@@ -131,39 +151,16 @@
#define IF_MCONT_EOB BIT(7)
#define IF_MCONT_DLC_MASK 0xf
-/*
- * IFx register masks:
- * allow easy operation on 16-bit registers when the
- * argument is 32-bit instead
- */
-#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
-#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
-
-/* 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 C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
-#define RECEIVE_OBJECT_BITS 0x0000ffff
+#define IF_MCONT_RCV (IF_MCONT_RXIE | IF_MCONT_UMASK)
+#define IF_MCONT_RCV_EOB (IF_MCONT_RCV | IF_MCONT_EOB)
-/* status interrupt */
-#define STATUS_INTERRUPT 0x8000
+#define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB)
-/* global interrupt masks */
-#define ENABLE_ALL_INTERRUPTS 1
-#define DISABLE_ALL_INTERRUPTS 0
+/*
+ * Use IF1 for RX and IF2 for TX
+ */
+#define IF_RX 0
+#define IF_TX 1
/* minimum timeout for checking BUSY status */
#define MIN_TIMEOUT_VALUE 6
@@ -184,6 +181,7 @@ enum c_can_lec_type {
LEC_BIT0_ERROR,
LEC_CRC_ERROR,
LEC_UNUSED,
+ LEC_MASK = LEC_UNUSED,
};
/*
@@ -233,210 +231,155 @@ static inline void c_can_pm_runtime_put_sync(const struct c_can_priv *priv)
pm_runtime_put_sync(priv->device);
}
-static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
-{
- return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
- C_CAN_MSG_OBJ_TX_FIRST;
-}
-
-static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
+static inline void c_can_reset_ram(const struct c_can_priv *priv, bool enable)
{
- return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
- C_CAN_MSG_OBJ_TX_FIRST;
+ if (priv->raminit)
+ priv->raminit(priv, enable);
}
-static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
+static void c_can_irq_control(struct c_can_priv *priv, bool enable)
{
- u32 val = priv->read_reg(priv, index);
- val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
- return val;
-}
-
-static void c_can_enable_all_interrupts(struct c_can_priv *priv,
- int enable)
-{
- unsigned int cntrl_save = priv->read_reg(priv,
- C_CAN_CTRL_REG);
+ u32 ctrl = priv->read_reg(priv, C_CAN_CTRL_REG) & ~CONTROL_IRQMSK;
if (enable)
- cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
- else
- cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
+ ctrl |= CONTROL_IRQMSK;
- priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save);
+ priv->write_reg(priv, C_CAN_CTRL_REG, ctrl);
}
-static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
+static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj)
{
- int count = MIN_TIMEOUT_VALUE;
+ struct c_can_priv *priv = netdev_priv(dev);
+ int cnt, reg = C_CAN_IFACE(COMREQ_REG, iface);
+
+ priv->write_reg32(priv, reg, (cmd << 16) | obj);
- while (count && priv->read_reg(priv,
- C_CAN_IFACE(COMREQ_REG, iface)) &
- IF_COMR_BUSY) {
- count--;
+ for (cnt = MIN_TIMEOUT_VALUE; cnt; cnt--) {
+ if (!(priv->read_reg(priv, reg) & IF_COMR_BUSY))
+ return;
udelay(1);
}
+ netdev_err(dev, "Updating object timed out\n");
- if (!count)
- return 1;
+}
- return 0;
+static inline void c_can_object_get(struct net_device *dev, int iface,
+ u32 obj, u32 cmd)
+{
+ c_can_obj_update(dev, iface, cmd, obj);
}
-static inline void c_can_object_get(struct net_device *dev,
- int iface, int objno, int mask)
+static inline void c_can_object_put(struct net_device *dev, int iface,
+ u32 obj, u32 cmd)
{
- struct c_can_priv *priv = netdev_priv(dev);
+ c_can_obj_update(dev, iface, cmd | IF_COMM_WR, obj);
+}
- /*
- * As per specs, after writting the message object number in the
- * IF command request register the transfer b/w interface
- * register and message RAM must be complete in 6 CAN-CLK
- * period.
- */
- priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
- IFX_WRITE_LOW_16BIT(mask));
- priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
- IFX_WRITE_LOW_16BIT(objno));
+/*
+ * Note: According to documentation clearing TXIE while MSGVAL is set
+ * is not allowed, but works nicely on C/DCAN. And that lowers the I/O
+ * load significantly.
+ */
+static void c_can_inval_tx_object(struct net_device *dev, int iface, int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
- if (c_can_msg_obj_is_busy(priv, iface))
- netdev_err(dev, "timed out in object get\n");
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
+ c_can_object_put(dev, iface, obj, IF_COMM_INVAL);
}
-static inline void c_can_object_put(struct net_device *dev,
- int iface, int objno, int mask)
+static void c_can_inval_msg_object(struct net_device *dev, int iface, int obj)
{
struct c_can_priv *priv = netdev_priv(dev);
- /*
- * As per specs, after writting the message object number in the
- * IF command request register the transfer b/w interface
- * register and message RAM must be complete in 6 CAN-CLK
- * period.
- */
- priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
- (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
- priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
- IFX_WRITE_LOW_16BIT(objno));
-
- if (c_can_msg_obj_is_busy(priv, iface))
- netdev_err(dev, "timed out in object put\n");
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
+ c_can_inval_tx_object(dev, iface, obj);
}
-static void c_can_write_msg_object(struct net_device *dev,
- int iface, struct can_frame *frame, int objno)
+static void c_can_setup_tx_object(struct net_device *dev, int iface,
+ struct can_frame *frame, int idx)
{
- int i;
- u16 flags = 0;
- unsigned int id;
struct c_can_priv *priv = netdev_priv(dev);
-
- if (!(frame->can_id & CAN_RTR_FLAG))
- flags |= IF_ARB_TRANSMIT;
+ u16 ctrl = IF_MCONT_TX | frame->can_dlc;
+ bool rtr = frame->can_id & CAN_RTR_FLAG;
+ u32 arb = IF_ARB_MSGVAL;
+ int i;
if (frame->can_id & CAN_EFF_FLAG) {
- id = frame->can_id & CAN_EFF_MASK;
- flags |= IF_ARB_MSGXTD;
- } else
- id = ((frame->can_id & CAN_SFF_MASK) << 18);
+ arb |= frame->can_id & CAN_EFF_MASK;
+ arb |= IF_ARB_MSGXTD;
+ } else {
+ arb |= (frame->can_id & CAN_SFF_MASK) << 18;
+ }
- flags |= IF_ARB_MSGVAL;
+ if (!rtr)
+ arb |= IF_ARB_TRANSMIT;
- priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
- IFX_WRITE_LOW_16BIT(id));
- priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags |
- IFX_WRITE_HIGH_16BIT(id));
+ /*
+ * If we change the DIR bit, we need to invalidate the buffer
+ * first, i.e. clear the MSGVAL flag in the arbiter.
+ */
+ if (rtr != (bool)test_bit(idx, &priv->tx_dir)) {
+ u32 obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
- for (i = 0; i < frame->can_dlc; i += 2) {
- priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
- frame->data[i] | (frame->data[i + 1] << 8));
+ c_can_inval_msg_object(dev, iface, obj);
+ change_bit(idx, &priv->tx_dir);
}
- /* enable interrupt for this message object */
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
- frame->can_dlc);
- c_can_object_put(dev, iface, objno, IF_COMM_ALL);
-}
+ priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), arb);
-static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
- int iface, int ctrl_mask,
- int obj)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
- c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
+ frame->data[i] | (frame->data[i + 1] << 8));
+ }
}
static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
- int iface,
- int ctrl_mask)
+ int iface)
{
int i;
- struct c_can_priv *priv = netdev_priv(dev);
- for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST |
- IF_MCONT_INTPND | IF_MCONT_NEWDAT));
- c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
- }
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++)
+ c_can_object_get(dev, iface, i, IF_COMM_CLR_NEWDAT);
}
-static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
- int iface, int ctrl_mask,
- int obj)
+static int c_can_handle_lost_msg_obj(struct net_device *dev,
+ int iface, int objno, u32 ctrl)
{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST |
- IF_MCONT_INTPND | IF_MCONT_NEWDAT));
- c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
-}
-
-static void c_can_handle_lost_msg_obj(struct net_device *dev,
- int iface, int objno)
-{
- struct c_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
+ struct c_can_priv *priv = netdev_priv(dev);
struct can_frame *frame;
+ struct sk_buff *skb;
- netdev_err(dev, "msg lost in buffer %d\n", objno);
-
- c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- IF_MCONT_CLR_MSGLST);
+ ctrl &= ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT);
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
+ c_can_object_put(dev, iface, objno, IF_COMM_CONTROL);
- c_can_object_put(dev, 0, objno, IF_COMM_CONTROL);
+ stats->rx_errors++;
+ stats->rx_over_errors++;
/* create an error msg */
skb = alloc_can_err_skb(dev, &frame);
if (unlikely(!skb))
- return;
+ return 0;
frame->can_id |= CAN_ERR_CRTL;
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
- stats->rx_errors++;
- stats->rx_over_errors++;
netif_receive_skb(skb);
+ return 1;
}
-static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
+static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
{
- u16 flags, data;
- int i;
- unsigned int val;
- struct c_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
+ struct c_can_priv *priv = netdev_priv(dev);
struct can_frame *frame;
+ struct sk_buff *skb;
+ u32 arb, data;
skb = alloc_can_skb(dev, &frame);
if (!skb) {
@@ -446,113 +389,98 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
frame->can_dlc = get_can_dlc(ctrl & 0x0F);
- flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
- val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
- (flags << 16);
+ arb = priv->read_reg32(priv, C_CAN_IFACE(ARB1_REG, iface));
- if (flags & IF_ARB_MSGXTD)
- frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ if (arb & IF_ARB_MSGXTD)
+ frame->can_id = (arb & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
- frame->can_id = (val >> 18) & CAN_SFF_MASK;
+ frame->can_id = (arb >> 18) & CAN_SFF_MASK;
- if (flags & IF_ARB_TRANSMIT)
+ if (arb & IF_ARB_TRANSMIT) {
frame->can_id |= CAN_RTR_FLAG;
- else {
- for (i = 0; i < frame->can_dlc; i += 2) {
- data = priv->read_reg(priv,
- C_CAN_IFACE(DATA1_REG, iface) + i / 2);
+ } else {
+ int i, dreg = C_CAN_IFACE(DATA1_REG, iface);
+
+ for (i = 0; i < frame->can_dlc; i += 2, dreg ++) {
+ data = priv->read_reg(priv, dreg);
frame->data[i] = data;
frame->data[i + 1] = data >> 8;
}
}
- netif_receive_skb(skb);
-
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
+ netif_receive_skb(skb);
return 0;
}
static void c_can_setup_receive_object(struct net_device *dev, int iface,
- int objno, unsigned int mask,
- unsigned int id, unsigned int mcont)
+ u32 obj, u32 mask, u32 id, u32 mcont)
{
struct c_can_priv *priv = netdev_priv(dev);
- priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
- IFX_WRITE_LOW_16BIT(mask));
- priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
- IFX_WRITE_HIGH_16BIT(mask));
+ mask |= BIT(29);
+ priv->write_reg32(priv, C_CAN_IFACE(MASK1_REG, iface), mask);
- priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
- IFX_WRITE_LOW_16BIT(id));
- priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface),
- (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
+ id |= IF_ARB_MSGVAL;
+ priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), id);
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
- c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
-
- netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
- c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
-}
-
-static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
- priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
-
- c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
-
- netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
- c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
-}
-
-static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int objno)
-{
- int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
-
- /*
- * as transmission request register's bit n-1 corresponds to
- * message object n, we need to handle the same properly.
- */
- if (val & (1 << (objno - 1)))
- return 1;
-
- return 0;
+ c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP);
}
static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
+ struct net_device *dev)
{
- u32 msg_obj_no;
- struct c_can_priv *priv = netdev_priv(dev);
struct can_frame *frame = (struct can_frame *)skb->data;
+ struct c_can_priv *priv = netdev_priv(dev);
+ u32 idx, obj;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
-
- msg_obj_no = get_tx_next_msg_obj(priv);
-
- /* prepare message object for transmission */
- c_can_write_msg_object(dev, 0, frame, msg_obj_no);
- can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
-
/*
- * we have to stop the queue in case of a wrap around or
- * if the next TX message object is still in use
+ * This is not a FIFO. C/D_CAN sends out the buffers
+ * prioritized. The lowest buffer number wins.
*/
- priv->tx_next++;
- if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
- (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
+ idx = fls(atomic_read(&priv->tx_active));
+ obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
+
+ /* If this is the last buffer, stop the xmit queue */
+ if (idx == C_CAN_MSG_OBJ_TX_NUM - 1)
netif_stop_queue(dev);
+ /*
+ * Store the message in the interface so we can call
+ * can_put_echo_skb(). We must do this before we enable
+ * transmit as we might race against do_tx().
+ */
+ c_can_setup_tx_object(dev, IF_TX, frame, idx);
+ priv->dlc[idx] = frame->can_dlc;
+ can_put_echo_skb(skb, dev, idx);
+
+ /* Update the active bits */
+ atomic_add((1 << idx), &priv->tx_active);
+ /* Start transmission */
+ c_can_object_put(dev, IF_TX, obj, IF_COMM_TX);
return NETDEV_TX_OK;
}
+static int c_can_wait_for_ctrl_init(struct net_device *dev,
+ struct c_can_priv *priv, u32 init)
+{
+ int retry = 0;
+
+ while (init != (priv->read_reg(priv, C_CAN_CTRL_REG) & CONTROL_INIT)) {
+ udelay(10);
+ if (retry++ > 1000) {
+ netdev_err(dev, "CCTRL: set CONTROL_INIT failed\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
static int c_can_set_bittiming(struct net_device *dev)
{
unsigned int reg_btr, reg_brpe, ctrl_save;
@@ -560,6 +488,7 @@ static int c_can_set_bittiming(struct net_device *dev)
u32 ten_bit_brp;
struct c_can_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
+ int res;
/* c_can provides a 6-bit brp and 4-bit brpe fields */
ten_bit_brp = bt->brp - 1;
@@ -577,13 +506,17 @@ static int c_can_set_bittiming(struct net_device *dev)
"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
- priv->write_reg(priv, C_CAN_CTRL_REG,
- ctrl_save | CONTROL_CCE | CONTROL_INIT);
+ ctrl_save &= ~CONTROL_INIT;
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT);
+ res = c_can_wait_for_ctrl_init(dev, priv, CONTROL_INIT);
+ if (res)
+ return res;
+
priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
- return 0;
+ return c_can_wait_for_ctrl_init(dev, priv, 0);
}
/*
@@ -601,15 +534,14 @@ static void c_can_configure_msg_objects(struct net_device *dev)
/* first invalidate all message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
- c_can_inval_msg_object(dev, 0, i);
+ c_can_inval_msg_object(dev, IF_RX, i);
/* setup receive message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
- c_can_setup_receive_object(dev, 0, i, 0, 0,
- (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
+ c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV);
- c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
- IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
+ c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
+ IF_MCONT_RCV_EOB);
}
/*
@@ -618,35 +550,27 @@ static void c_can_configure_msg_objects(struct net_device *dev)
* - set operating mode
* - configure message objects
*/
-static void c_can_chip_config(struct net_device *dev)
+static int c_can_chip_config(struct net_device *dev)
{
struct c_can_priv *priv = netdev_priv(dev);
/* enable automatic retransmission */
- priv->write_reg(priv, C_CAN_CTRL_REG,
- CONTROL_ENABLE_AR);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
(priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
/* loopback + silent mode : useful for hot self-test */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
- CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
- priv->write_reg(priv, C_CAN_TEST_REG,
- TEST_LBACK | TEST_SILENT);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* loopback mode : useful for self-test function */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
- CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
/* silent mode : bus-monitoring mode */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
- CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
- } else
- /* normal mode*/
- priv->write_reg(priv, C_CAN_CTRL_REG,
- CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
+ }
/* configure message objects */
c_can_configure_msg_objects(dev);
@@ -654,43 +578,54 @@ static void c_can_chip_config(struct net_device *dev)
/* set a `lec` value so that we can check for updates later */
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+ /* Clear all internal status */
+ atomic_set(&priv->tx_active, 0);
+ priv->rxmasked = 0;
+ priv->tx_dir = 0;
+
/* set bittiming params */
- c_can_set_bittiming(dev);
+ return c_can_set_bittiming(dev);
}
-static void c_can_start(struct net_device *dev)
+static int c_can_start(struct net_device *dev)
{
struct c_can_priv *priv = netdev_priv(dev);
+ int err;
/* basic c_can configuration */
- c_can_chip_config(dev);
+ err = c_can_chip_config(dev);
+ if (err)
+ return err;
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ /* Setup the command for new messages */
+ priv->comm_rcv_high = priv->type != BOSCH_D_CAN ?
+ IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
- /* reset tx helper pointers */
- priv->tx_next = priv->tx_echo = 0;
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
- /* enable status change, error and module interrupts */
- c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+ return 0;
}
static void c_can_stop(struct net_device *dev)
{
struct c_can_priv *priv = netdev_priv(dev);
- /* disable all interrupts */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
-
- /* set the state as STOPPED */
+ c_can_irq_control(priv, false);
priv->can.state = CAN_STATE_STOPPED;
}
static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
{
+ struct c_can_priv *priv = netdev_priv(dev);
+ int err;
+
switch (mode) {
case CAN_MODE_START:
- c_can_start(dev);
+ err = c_can_start(dev);
+ if (err)
+ return err;
netif_wake_queue(dev);
+ c_can_irq_control(priv, true);
break;
default:
return -EOPNOTSUPP;
@@ -699,62 +634,153 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
return 0;
}
-static int c_can_get_berr_counter(const struct net_device *dev,
- struct can_berr_counter *bec)
+static int __c_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
{
unsigned int reg_err_counter;
struct c_can_priv *priv = netdev_priv(dev);
- c_can_pm_runtime_get_sync(priv);
-
reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
ERR_CNT_REC_SHIFT;
bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
+ return 0;
+}
+
+static int c_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ int err;
+
+ c_can_pm_runtime_get_sync(priv);
+ err = __c_can_get_berr_counter(dev, bec);
c_can_pm_runtime_put_sync(priv);
- return 0;
+ return err;
}
-/*
- * theory of operation:
- *
- * priv->tx_echo holds the number of the oldest can_frame put for
- * transmission into the hardware, but not yet ACKed by the CAN tx
- * complete IRQ.
- *
- * We iterate from priv->tx_echo to priv->tx_next and check if the
- * packet has been transmitted, echo it back to the CAN framework.
- * If we discover a not yet transmitted packet, stop looking for more.
- */
static void c_can_do_tx(struct net_device *dev)
{
- u32 val;
- u32 msg_obj_no;
struct c_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
+ u32 idx, obj, pkts = 0, bytes = 0, pend, clr;
+
+ clr = pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
+
+ while ((idx = ffs(pend))) {
+ idx--;
+ pend &= ~(1 << idx);
+ obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
+ c_can_inval_tx_object(dev, IF_RX, obj);
+ can_get_echo_skb(dev, idx);
+ bytes += priv->dlc[idx];
+ pkts++;
+ }
- for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
- msg_obj_no = get_tx_echo_msg_obj(priv);
- val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
- if (!(val & (1 << (msg_obj_no - 1)))) {
- can_get_echo_skb(dev,
- msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
- stats->tx_bytes += priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0))
- & IF_MCONT_DLC_MASK;
- stats->tx_packets++;
- c_can_inval_msg_object(dev, 0, msg_obj_no);
- } else {
- break;
+ /* Clear the bits in the tx_active mask */
+ atomic_sub(clr, &priv->tx_active);
+
+ if (clr & (1 << (C_CAN_MSG_OBJ_TX_NUM - 1)))
+ netif_wake_queue(dev);
+
+ if (pkts) {
+ stats->tx_bytes += bytes;
+ stats->tx_packets += pkts;
+ can_led_event(dev, CAN_LED_EVENT_TX);
+ }
+}
+
+/*
+ * If we have a gap in the pending bits, that means we either
+ * raced with the hardware or failed to readout all upper
+ * objects in the last run due to quota limit.
+ */
+static u32 c_can_adjust_pending(u32 pend)
+{
+ u32 weight, lasts;
+
+ if (pend == RECEIVE_OBJECT_BITS)
+ return pend;
+
+ /*
+ * If the last set bit is larger than the number of pending
+ * bits we have a gap.
+ */
+ weight = hweight32(pend);
+ lasts = fls(pend);
+
+ /* If the bits are linear, nothing to do */
+ if (lasts == weight)
+ return pend;
+
+ /*
+ * Find the first set bit after the gap. We walk backwards
+ * from the last set bit.
+ */
+ for (lasts--; pend & (1 << (lasts - 1)); lasts--);
+
+ return pend & ~((1 << lasts) - 1);
+}
+
+static inline void c_can_rx_object_get(struct net_device *dev,
+ struct c_can_priv *priv, u32 obj)
+{
+ c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high);
+}
+
+static inline void c_can_rx_finalize(struct net_device *dev,
+ struct c_can_priv *priv, u32 obj)
+{
+ if (priv->type != BOSCH_D_CAN)
+ c_can_object_get(dev, IF_RX, obj, IF_COMM_CLR_NEWDAT);
+}
+
+static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
+ u32 pend, int quota)
+{
+ u32 pkts = 0, ctrl, obj;
+
+ while ((obj = ffs(pend)) && quota > 0) {
+ pend &= ~BIT(obj - 1);
+
+ c_can_rx_object_get(dev, priv, obj);
+ ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX));
+
+ if (ctrl & IF_MCONT_MSGLST) {
+ int n = c_can_handle_lost_msg_obj(dev, IF_RX, obj, ctrl);
+
+ pkts += n;
+ quota -= n;
+ continue;
}
+
+ /*
+ * This really should not happen, but this covers some
+ * odd HW behaviour. Do not remove that unless you
+ * want to brick your machine.
+ */
+ if (!(ctrl & IF_MCONT_NEWDAT))
+ continue;
+
+ /* read the data from the message object */
+ c_can_read_msg_object(dev, IF_RX, ctrl);
+
+ c_can_rx_finalize(dev, priv, obj);
+
+ pkts++;
+ quota--;
}
- /* restart queue if wrap-up or if queue stalled on last pkt */
- if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
- ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
- netif_wake_queue(dev);
+ return pkts;
+}
+
+static inline u32 c_can_get_pending(struct c_can_priv *priv)
+{
+ u32 pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
+
+ return pend;
}
/*
@@ -766,80 +792,47 @@ static void c_can_do_tx(struct net_device *dev)
* has arrived. To work-around this issue, we keep two groups of message
* objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT.
*
- * To ensure in-order frame reception we use the following
- * approach while re-activating a message object to receive further
- * frames:
- * - if the current message object number is lower than
- * C_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing
- * the INTPND bit.
- * - if the current message object number is equal to
- * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower
- * receive message objects.
- * - if the current message object number is greater than
- * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
- * only this message object.
+ * We clear the newdat bit right away.
+ *
+ * This can result in packet reordering when the readout is slow.
*/
static int c_can_do_rx_poll(struct net_device *dev, int quota)
{
- u32 num_rx_pkts = 0;
- unsigned int msg_obj, msg_ctrl_save;
struct c_can_priv *priv = netdev_priv(dev);
- u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG);
+ u32 pkts = 0, pend = 0, toread, n;
- for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
- msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
- val = c_can_read_reg32(priv, C_CAN_INTPND1_REG),
- msg_obj++) {
- /*
- * as interrupt pending register's bit n-1 corresponds to
- * message object n, we need to handle the same properly.
- */
- if (val & (1 << (msg_obj - 1))) {
- c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
- ~IF_COMM_TXRQST);
- msg_ctrl_save = priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0));
-
- if (msg_ctrl_save & IF_MCONT_EOB)
- return num_rx_pkts;
-
- if (msg_ctrl_save & IF_MCONT_MSGLST) {
- c_can_handle_lost_msg_obj(dev, 0, msg_obj);
- num_rx_pkts++;
- quota--;
- continue;
- }
-
- if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
- continue;
-
- /* read the data from the message object */
- c_can_read_msg_object(dev, 0, msg_ctrl_save);
-
- if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
- c_can_mark_rx_msg_obj(dev, 0,
- msg_ctrl_save, msg_obj);
- else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
- /* activate this msg obj */
- c_can_activate_rx_msg_obj(dev, 0,
- msg_ctrl_save, msg_obj);
- else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
- /* activate all lower message objects */
- c_can_activate_all_lower_rx_msg_obj(dev,
- 0, msg_ctrl_save);
-
- num_rx_pkts++;
- quota--;
+ /*
+ * It is faster to read only one 16bit register. This is only possible
+ * for a maximum number of 16 objects.
+ */
+ BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
+ "Implementation does not support more message objects than 16");
+
+ while (quota > 0) {
+ if (!pend) {
+ pend = c_can_get_pending(priv);
+ if (!pend)
+ break;
+ /*
+ * If the pending field has a gap, handle the
+ * bits above the gap first.
+ */
+ toread = c_can_adjust_pending(pend);
+ } else {
+ toread = pend;
}
+ /* Remove the bits from pend */
+ pend &= ~toread;
+ /* Read the objects */
+ n = c_can_read_objects(dev, priv, toread, quota);
+ pkts += n;
+ quota -= n;
}
- return num_rx_pkts;
-}
+ if (pkts)
+ can_led_event(dev, CAN_LED_EVENT_RX);
-static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
-{
- return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
- (priv->current_status & LEC_UNUSED);
+ return pkts;
}
static int c_can_handle_state_change(struct net_device *dev,
@@ -853,12 +846,32 @@ static int c_can_handle_state_change(struct net_device *dev,
struct sk_buff *skb;
struct can_berr_counter bec;
+ switch (error_type) {
+ case C_CAN_ERROR_WARNING:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ break;
+ case C_CAN_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ break;
+ case C_CAN_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+
/* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf);
if (unlikely(!skb))
return 0;
- c_can_get_berr_counter(dev, &bec);
+ __c_can_get_berr_counter(dev, &bec);
reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
ERR_CNT_RP_SHIFT;
@@ -866,8 +879,6 @@ static int c_can_handle_state_change(struct net_device *dev,
switch (error_type) {
case C_CAN_ERROR_WARNING:
/* error warning state */
- priv->can.can_stats.error_warning++;
- priv->can.state = CAN_STATE_ERROR_WARNING;
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = (bec.txerr > bec.rxerr) ?
CAN_ERR_CRTL_TX_WARNING :
@@ -878,8 +889,6 @@ static int c_can_handle_state_change(struct net_device *dev,
break;
case C_CAN_ERROR_PASSIVE:
/* error passive state */
- priv->can.can_stats.error_passive++;
- priv->can.state = CAN_STATE_ERROR_PASSIVE;
cf->can_id |= CAN_ERR_CRTL;
if (rx_err_passive)
cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
@@ -891,22 +900,16 @@ static int c_can_handle_state_change(struct net_device *dev,
break;
case C_CAN_BUS_OFF:
/* bus-off state */
- priv->can.state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
- /*
- * disable all interrupts in bus-off mode to ensure that
- * the CPU is not hogged down
- */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
can_bus_off(dev);
break;
default:
break;
}
- netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+ netif_receive_skb(skb);
return 1;
}
@@ -927,6 +930,13 @@ static int c_can_handle_bus_err(struct net_device *dev,
if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
return 0;
+ if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
+ return 0;
+
+ /* common for all type of bus errors */
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+
/* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf);
if (unlikely(!skb))
@@ -936,10 +946,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
* check for 'last error code' which tells us the
* type of the last error to occur on the CAN bus
*/
-
- /* common for all type of bus errors */
- priv->can.can_stats.bus_error++;
- stats->rx_errors++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
@@ -954,7 +960,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
break;
case LEC_ACK_ERROR:
netdev_dbg(dev, "ack error\n");
- cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
+ cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
CAN_ERR_PROT_LOC_ACK_DEL);
break;
case LEC_BIT1_ERROR:
@@ -967,102 +973,71 @@ static int c_can_handle_bus_err(struct net_device *dev,
break;
case LEC_CRC_ERROR:
netdev_dbg(dev, "CRC error\n");
- cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+ cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
CAN_ERR_PROT_LOC_CRC_DEL);
break;
default:
break;
}
- /* set a `lec` value so that we can check for updates later */
- priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
-
- netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
-
+ netif_receive_skb(skb);
return 1;
}
static int c_can_poll(struct napi_struct *napi, int quota)
{
- u16 irqstatus;
- int lec_type = 0;
- int work_done = 0;
struct net_device *dev = napi->dev;
struct c_can_priv *priv = netdev_priv(dev);
+ u16 curr, last = priv->last_status;
+ int work_done = 0;
- irqstatus = priv->irqstatus;
- if (!irqstatus)
- goto end;
+ priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
+ /* Ack status on C_CAN. D_CAN is self clearing */
+ if (priv->type != BOSCH_D_CAN)
+ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
- /* status events have the highest priority */
- if (irqstatus == STATUS_INTERRUPT) {
- priv->current_status = priv->read_reg(priv,
- C_CAN_STS_REG);
-
- /* handle Tx/Rx events */
- if (priv->current_status & STATUS_TXOK)
- priv->write_reg(priv, C_CAN_STS_REG,
- priv->current_status & ~STATUS_TXOK);
-
- if (priv->current_status & STATUS_RXOK)
- priv->write_reg(priv, C_CAN_STS_REG,
- priv->current_status & ~STATUS_RXOK);
-
- /* handle state changes */
- if ((priv->current_status & STATUS_EWARN) &&
- (!(priv->last_status & STATUS_EWARN))) {
- netdev_dbg(dev, "entered error warning state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_WARNING);
- }
- if ((priv->current_status & STATUS_EPASS) &&
- (!(priv->last_status & STATUS_EPASS))) {
- netdev_dbg(dev, "entered error passive state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_PASSIVE);
- }
- if ((priv->current_status & STATUS_BOFF) &&
- (!(priv->last_status & STATUS_BOFF))) {
- netdev_dbg(dev, "entered bus off state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_BUS_OFF);
- }
+ /* handle state changes */
+ if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
+ netdev_dbg(dev, "entered error warning state\n");
+ work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING);
+ }
- /* handle bus recovery events */
- if ((!(priv->current_status & STATUS_BOFF)) &&
- (priv->last_status & STATUS_BOFF)) {
- netdev_dbg(dev, "left bus off state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- }
- if ((!(priv->current_status & STATUS_EPASS)) &&
- (priv->last_status & STATUS_EPASS)) {
- netdev_dbg(dev, "left error passive state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- }
+ if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) {
+ netdev_dbg(dev, "entered error passive state\n");
+ work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
+ }
- priv->last_status = priv->current_status;
-
- /* handle lec errors on the bus */
- lec_type = c_can_has_and_handle_berr(priv);
- if (lec_type)
- work_done += c_can_handle_bus_err(dev, lec_type);
- } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
- /* handle events corresponding to receive message objects */
- work_done += c_can_do_rx_poll(dev, (quota - work_done));
- } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
- /* handle events corresponding to transmit message objects */
- c_can_do_tx(dev);
+ if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) {
+ netdev_dbg(dev, "entered bus off state\n");
+ work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF);
+ goto end;
}
+ /* handle bus recovery events */
+ if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) {
+ netdev_dbg(dev, "left bus off state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) {
+ netdev_dbg(dev, "left error passive state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ /* handle lec errors on the bus */
+ work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);
+
+ /* Handle Tx/Rx events. We do this unconditionally */
+ work_done += c_can_do_rx_poll(dev, (quota - work_done));
+ c_can_do_tx(dev);
+
end:
if (work_done < quota) {
napi_complete(napi);
- /* enable all IRQs */
- c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+ /* enable all IRQs if we are not in bus off state */
+ if (priv->can.state != CAN_STATE_BUS_OFF)
+ c_can_irq_control(priv, true);
}
return work_done;
@@ -1073,12 +1048,11 @@ static irqreturn_t c_can_isr(int irq, void *dev_id)
struct net_device *dev = (struct net_device *)dev_id;
struct c_can_priv *priv = netdev_priv(dev);
- priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
- if (!priv->irqstatus)
+ if (!priv->read_reg(priv, C_CAN_INT_REG))
return IRQ_NONE;
/* disable all interrupts and schedule the NAPI */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ c_can_irq_control(priv, false);
napi_schedule(&priv->napi);
return IRQ_HANDLED;
@@ -1090,6 +1064,7 @@ static int c_can_open(struct net_device *dev)
struct c_can_priv *priv = netdev_priv(dev);
c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
/* open the can device */
err = open_candev(dev);
@@ -1106,18 +1081,26 @@ static int c_can_open(struct net_device *dev)
goto exit_irq_fail;
}
- napi_enable(&priv->napi);
-
/* start the c_can controller */
- c_can_start(dev);
+ err = c_can_start(dev);
+ if (err)
+ goto exit_start_fail;
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
+ napi_enable(&priv->napi);
+ /* enable status change, error and module interrupts */
+ c_can_irq_control(priv, true);
netif_start_queue(dev);
return 0;
+exit_start_fail:
+ free_irq(dev->irq, dev);
exit_irq_fail:
close_candev(dev);
exit_open_fail:
+ c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv);
return err;
}
@@ -1131,8 +1114,12 @@ static int c_can_close(struct net_device *dev)
c_can_stop(dev);
free_irq(dev->irq, dev);
close_candev(dev);
+
+ c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -1188,6 +1175,7 @@ int c_can_power_down(struct net_device *dev)
c_can_stop(dev);
+ c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv);
return 0;
@@ -1199,6 +1187,7 @@ int c_can_power_up(struct net_device *dev)
u32 val;
unsigned long time_out;
struct c_can_priv *priv = netdev_priv(dev);
+ int ret;
if (!(dev->flags & IFF_UP))
return 0;
@@ -1206,6 +1195,7 @@ int c_can_power_up(struct net_device *dev)
WARN_ON(priv->type != BOSCH_D_CAN);
c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
/* Clear PDR and INIT bits */
val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
@@ -1224,15 +1214,20 @@ int c_can_power_up(struct net_device *dev)
if (time_after(jiffies, time_out))
return -ETIMEDOUT;
- c_can_start(dev);
+ ret = c_can_start(dev);
+ if (!ret)
+ c_can_irq_control(priv, true);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(c_can_power_up);
#endif
void free_c_can_dev(struct net_device *dev)
{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ netif_napi_del(&priv->napi);
free_candev(dev);
}
EXPORT_SYMBOL_GPL(free_c_can_dev);
@@ -1241,6 +1236,7 @@ static const struct net_device_ops c_can_netdev_ops = {
.ndo_open = c_can_open,
.ndo_stop = c_can_close,
.ndo_start_xmit = c_can_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
int register_c_can_dev(struct net_device *dev)
@@ -1256,6 +1252,8 @@ int register_c_can_dev(struct net_device *dev)
err = register_candev(dev);
if (err)
c_can_pm_runtime_disable(priv);
+ else
+ devm_can_led_init(dev);
return err;
}
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index e5ed41dafa1..99ad1aa576b 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -22,6 +22,23 @@
#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,
@@ -61,6 +78,7 @@ enum reg {
C_CAN_INTPND2_REG,
C_CAN_MSGVAL1_REG,
C_CAN_MSGVAL2_REG,
+ C_CAN_FUNCTION_REG,
};
static const u16 reg_map_c_can[] = {
@@ -112,6 +130,7 @@ static const u16 reg_map_d_can[] = {
[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,
@@ -156,19 +175,23 @@ struct c_can_priv {
struct napi_struct napi;
struct net_device *dev;
struct device *device;
- int tx_object;
- int current_status;
+ atomic_t tx_active;
+ unsigned long tx_dir;
int last_status;
- u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
- void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
+ 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;
- unsigned long irq_flags; /* for request_irq() */
- unsigned int tx_next;
- unsigned int tx_echo;
void *priv; /* for board-specific data */
- u16 irqstatus;
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);
diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c
index 3d7830bcd2b..5d11e0e4225 100644
--- a/drivers/net/can/c_can/c_can_pci.c
+++ b/drivers/net/can/c_can/c_can_pci.c
@@ -19,9 +19,13 @@
#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 {
@@ -31,6 +35,10 @@ struct c_can_pci_data {
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);
};
/*
@@ -39,32 +47,72 @@ struct c_can_pci_data {
* 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(struct c_can_priv *priv,
+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(struct c_can_priv *priv,
+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(struct c_can_priv *priv,
+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(struct c_can_priv *priv,
+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 int __devinit c_can_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+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;
@@ -84,10 +132,14 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev,
goto out_disable_device;
}
- pci_set_master(pdev);
- pci_enable_msi(pdev);
+ ret = pci_enable_msi(pdev);
+ if (!ret) {
+ dev_info(&pdev->dev, "MSI enabled\n");
+ pci_set_master(pdev);
+ }
- addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ 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, "
@@ -132,6 +184,8 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev,
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:
@@ -142,10 +196,18 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev,
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) {
@@ -160,7 +222,6 @@ static int __devinit c_can_pci_probe(struct pci_dev *pdev,
return 0;
out_free_c_can:
- pci_set_drvdata(pdev, NULL);
free_c_can_dev(dev);
out_iounmap:
pci_iounmap(pdev, addr);
@@ -174,14 +235,13 @@ out:
return ret;
}
-static void __devexit c_can_pci_remove(struct pci_dev *pdev)
+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);
- pci_set_drvdata(pdev, NULL);
free_c_can_dev(dev);
pci_iounmap(pdev, priv->base);
@@ -195,6 +255,15 @@ 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) { \
@@ -204,13 +273,15 @@ static struct c_can_pci_data c_can_sta2x11= {
static DEFINE_PCI_DEVICE_TABLE(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 = __devexit_p(c_can_pci_remove),
+ .remove = c_can_pci_remove,
};
module_pci_driver(c_can_pci_driver);
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index ee1416132ab..12430be6448 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -32,42 +32,133 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/pinctrl/consumer.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(struct c_can_priv *priv,
+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(struct c_can_priv *priv,
+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(struct c_can_priv *priv,
+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(struct c_can_priv *priv,
+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, ctrl, mask);
+
+ 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, ctrl, mask);
+ }
+ 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,
@@ -83,14 +174,16 @@ static struct platform_device_id c_can_id_table[] = {
}, {
}
};
+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 __devinit c_can_plat_probe(struct platform_device *pdev)
+static int c_can_plat_probe(struct platform_device *pdev)
{
int ret;
void __iomem *addr;
@@ -98,8 +191,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
struct c_can_priv *priv;
const struct of_device_id *match;
const struct platform_device_id *id;
- struct pinctrl *pinctrl;
- struct resource *mem;
+ struct resource *mem, *res;
int irq;
struct clk *clk;
@@ -115,11 +207,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
id = platform_get_device_id(pdev);
}
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&pdev->dev,
- "failed to configure pins from driver\n");
-
/* get the appropriate clk */
clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
@@ -165,11 +252,15 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
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;
@@ -178,6 +269,30 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
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 (IS_ERR(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;
@@ -206,7 +321,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
return 0;
exit_free_device:
- platform_set_drvdata(pdev, NULL);
free_c_can_dev(dev);
exit_iounmap:
iounmap(addr);
@@ -220,14 +334,13 @@ exit:
return ret;
}
-static int __devexit c_can_plat_remove(struct platform_device *pdev)
+static int c_can_plat_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct c_can_priv *priv = netdev_priv(dev);
struct resource *mem;
unregister_c_can_dev(dev);
- platform_set_drvdata(pdev, NULL);
free_c_can_dev(dev);
iounmap(priv->base);
@@ -303,10 +416,10 @@ static struct platform_driver c_can_plat_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(c_can_of_table),
+ .of_match_table = c_can_of_table,
},
.probe = c_can_plat_probe,
- .remove = __devexit_p(c_can_plat_remove),
+ .remove = c_can_plat_remove,
.suspend = c_can_suspend,
.resume = c_can_resume,
.id_table = c_can_id_table,
diff --git a/drivers/net/can/cc770/Kconfig b/drivers/net/can/cc770/Kconfig
index 22c07a8c8b4..6a9a5ba7922 100644
--- a/drivers/net/can/cc770/Kconfig
+++ b/drivers/net/can/cc770/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_CC770
tristate "Bosch CC770 and Intel AN82527 devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_CC770
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c
index 0f12abf6591..d8379278d64 100644
--- a/drivers/net/can/cc770/cc770.c
+++ b/drivers/net/can/cc770/cc770.c
@@ -823,6 +823,7 @@ 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)
diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c
index 9f3a25ccd66..87a47c0cfd4 100644
--- a/drivers/net/can/cc770/cc770_isa.c
+++ b/drivers/net/can/cc770/cc770_isa.c
@@ -75,12 +75,12 @@ MODULE_LICENSE("GPL v2");
static unsigned long port[MAXDEV];
static unsigned long mem[MAXDEV];
-static int __devinitdata irq[MAXDEV];
-static int __devinitdata clk[MAXDEV];
-static u8 __devinitdata cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static u8 __devinitdata cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static u8 __devinitdata bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+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");
@@ -166,7 +166,7 @@ static void cc770_isa_port_write_reg_indirect(const struct cc770_priv *priv,
spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
}
-static int __devinit cc770_isa_probe(struct platform_device *pdev)
+static int cc770_isa_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct cc770_priv *priv;
@@ -265,7 +265,7 @@ static int __devinit cc770_isa_probe(struct platform_device *pdev)
else
priv->clkout = COR_DEFAULT;
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_cc770dev(dev);
@@ -291,14 +291,13 @@ static int __devinit cc770_isa_probe(struct platform_device *pdev)
return err;
}
-static int __devexit cc770_isa_remove(struct platform_device *pdev)
+static int cc770_isa_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_cc770dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
if (mem[idx]) {
iounmap(priv->reg_base);
@@ -316,7 +315,7 @@ static int __devexit cc770_isa_remove(struct platform_device *pdev)
static struct platform_driver cc770_isa_driver = {
.probe = cc770_isa_probe,
- .remove = __devexit_p(cc770_isa_remove),
+ .remove = cc770_isa_remove,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c
index 688371cda37..ad76734b3ec 100644
--- a/drivers/net/can/cc770/cc770_platform.c
+++ b/drivers/net/can/cc770/cc770_platform.c
@@ -60,6 +60,7 @@
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
@@ -74,8 +75,8 @@ static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg,
iowrite8(val, priv->reg_base + reg);
}
-static int __devinit cc770_get_of_node_data(struct platform_device *pdev,
- struct cc770_priv *priv)
+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;
@@ -147,11 +148,11 @@ static int __devinit cc770_get_of_node_data(struct platform_device *pdev,
return 0;
}
-static int __devinit cc770_get_platform_data(struct platform_device *pdev,
- struct cc770_priv *priv)
+static int cc770_get_platform_data(struct platform_device *pdev,
+ struct cc770_priv *priv)
{
- struct cc770_platform_data *pdata = pdev->dev.platform_data;
+ struct cc770_platform_data *pdata = dev_get_platdata(&pdev->dev);
priv->can.clock.freq = pdata->osc_freq;
if (priv->cpu_interface & CPUIF_DSC)
@@ -163,7 +164,7 @@ static int __devinit cc770_get_platform_data(struct platform_device *pdev,
return 0;
}
-static int __devinit cc770_platform_probe(struct platform_device *pdev)
+static int cc770_platform_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct cc770_priv *priv;
@@ -202,7 +203,7 @@ static int __devinit cc770_platform_probe(struct platform_device *pdev)
if (pdev->dev.of_node)
err = cc770_get_of_node_data(pdev, priv);
- else if (pdev->dev.platform_data)
+ else if (dev_get_platdata(&pdev->dev))
err = cc770_get_platform_data(pdev, priv);
else
err = -ENODEV;
@@ -215,7 +216,7 @@ static int __devinit cc770_platform_probe(struct platform_device *pdev)
priv->reg_base, dev->irq, priv->can.clock.freq,
priv->cpu_interface, priv->bus_config, priv->clkout);
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_cc770dev(dev);
@@ -237,9 +238,9 @@ exit_release_mem:
return err;
}
-static int __devexit cc770_platform_remove(struct platform_device *pdev)
+static int cc770_platform_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
struct resource *mem;
@@ -253,11 +254,12 @@ static int __devexit cc770_platform_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id __devinitdata cc770_platform_table[] = {
+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 = {
@@ -266,7 +268,7 @@ static struct platform_driver cc770_platform_driver = {
.of_match_table = cc770_platform_table,
},
.probe = cc770_platform_probe,
- .remove = __devexit_p(cc770_platform_remove),
+ .remove = cc770_platform_remove,
};
module_platform_driver(cc770_platform_driver);
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 963e2ccd10d..e318e87e2bf 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -13,8 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
@@ -24,7 +23,9 @@
#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"
@@ -98,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc,
return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
}
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+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);
- const struct can_bittiming_const *btc = priv->bittiming_const;
long rate, best_rate = 0;
long best_error = 1000000000, error = 0;
int best_tseg = 0, best_brp = 0, brp = 0;
@@ -109,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
int spt_error = 1000, spt = 0, sampl_pt;
u64 v64;
- if (!priv->bittiming_const)
- return -ENOTSUPP;
-
/* Use CIA recommended sample points */
if (bt->sample_point) {
sampl_pt = bt->sample_point;
@@ -203,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
return 0;
}
#else /* !CONFIG_CAN_CALC_BITTIMING */
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+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;
@@ -216,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
* 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)
+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);
- const struct can_bittiming_const *btc = priv->bittiming_const;
int tseg1, alltseg;
u64 brp64;
- if (!priv->bittiming_const)
- return -ENOTSUPP;
-
tseg1 = bt->prop_seg + bt->phase_seg1;
if (!bt->sjw)
bt->sjw = 1;
@@ -253,26 +249,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
return 0;
}
-static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
+ const struct can_bittiming_const *btc)
{
- struct can_priv *priv = netdev_priv(dev);
int err;
/* Check if the CAN device has bit-timing parameters */
- if (priv->bittiming_const) {
+ if (!btc)
+ return -EOPNOTSUPP;
- /* Non-expert mode? Check if the bitrate has been pre-defined */
- if (!bt->tq)
- /* Determine bit-timing parameters */
- err = can_calc_bittiming(dev, bt);
- else
- /* Check bit-timing params and calculate proper brp */
- err = can_fixup_bittiming(dev, bt);
- if (err)
- return err;
- }
+ /*
+ * 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 0;
+ return err;
}
/*
@@ -316,28 +315,20 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *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) {
+ 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]) {
- struct sock *srcsk = skb->sk;
- if (atomic_read(&skb->users) != 1) {
- struct sk_buff *old_skb = skb;
-
- skb = skb_clone(old_skb, GFP_ATOMIC);
- kfree_skb(old_skb);
- if (!skb)
- return;
- } else
- skb_orphan(skb);
-
- skb->sk = srcsk;
+ skb = can_create_echo_skb(skb);
+ if (!skb)
+ return;
/* make settings for echo to reduce code in irq context */
- skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev;
@@ -501,13 +492,18 @@ 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_frame));
+ 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;
+
+ 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));
@@ -515,6 +511,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
}
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;
+
+ 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;
@@ -575,6 +595,39 @@ void free_candev(struct net_device *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
@@ -584,11 +637,19 @@ int open_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
- if (!priv->bittiming.tq && !priv->bittiming.bitrate) {
+ 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);
@@ -609,8 +670,7 @@ void close_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
- if (del_timer_sync(&priv->restart_timer))
- dev_put(dev);
+ del_timer_sync(&priv->restart_timer);
can_flush_echo_skb(dev);
}
EXPORT_SYMBOL_GPL(close_candev);
@@ -628,6 +688,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
= { .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,
@@ -639,19 +703,6 @@ static int can_changelink(struct net_device *dev,
/* We need synchronization with dev->stop() */
ASSERT_RTNL();
- 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]);
- if (cm->flags & ~priv->ctrlmode_supported)
- return -EOPNOTSUPP;
- priv->ctrlmode &= ~cm->mask;
- priv->ctrlmode |= cm->flags;
- }
-
if (data[IFLA_CAN_BITTIMING]) {
struct can_bittiming bt;
@@ -659,9 +710,7 @@ static int can_changelink(struct net_device *dev,
if (dev->flags & IFF_UP)
return -EBUSY;
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
- if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq))
- return -EINVAL;
- err = can_get_bittiming(dev, &bt);
+ err = can_get_bittiming(dev, &bt, priv->bittiming_const);
if (err)
return err;
memcpy(&priv->bittiming, &bt, sizeof(bt));
@@ -674,6 +723,25 @@ static int can_changelink(struct net_device *dev,
}
}
+ 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]);
+ if (cm->flags & ~priv->ctrlmode_supported)
+ return -EOPNOTSUPP;
+ priv->ctrlmode &= ~cm->mask;
+ priv->ctrlmode |= cm->flags;
+
+ /* 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)
@@ -690,23 +758,49 @@ static int can_changelink(struct net_device *dev,
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;
-
- size = nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
- size += sizeof(struct can_ctrlmode); /* IFLA_CAN_CTRLMODE */
- size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
- size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */
- size += sizeof(struct can_clock); /* IFLA_CAN_CLOCK */
- if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
- size += sizeof(struct can_berr_counter);
- if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
- size += sizeof(struct can_bittiming_const);
+ 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;
}
@@ -720,23 +814,35 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
if (priv->do_get_state)
priv->do_get_state(dev, &state);
- if (nla_put_u32(skb, IFLA_CAN_STATE, 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) ||
- nla_put(skb, IFLA_CAN_BITTIMING,
- sizeof(priv->bittiming), &priv->bittiming) ||
- nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) ||
+
(priv->do_get_berr_counter &&
!priv->do_get_berr_counter(dev, &bec) &&
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
- (priv->bittiming_const &&
- nla_put(skb, IFLA_CAN_BITTIMING_CONST,
- sizeof(*priv->bittiming_const), priv->bittiming_const)))
- goto nla_put_failure;
- return 0;
-nla_put_failure:
- return -EMSGSIZE;
+ (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)
@@ -795,10 +901,25 @@ void unregister_candev(struct net_device *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");
@@ -810,6 +931,8 @@ 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);
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index c78ecfca1e4..f425ec2c783 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -23,7 +23,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
-#include <linux/can/platform/flexcan.h>
+#include <linux/can/led.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/if_arp.h>
@@ -36,7 +36,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
#define DRV_NAME "flexcan"
@@ -62,7 +62,7 @@
#define FLEXCAN_MCR_BCC BIT(16)
#define FLEXCAN_MCR_LPRIO_EN BIT(13)
#define FLEXCAN_MCR_AEN BIT(12)
-#define FLEXCAN_MCR_MAXMB(x) ((x) & 0xf)
+#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x1f)
#define FLEXCAN_MCR_IDAM_A (0 << 8)
#define FLEXCAN_MCR_IDAM_B (1 << 8)
#define FLEXCAN_MCR_IDAM_C (2 << 8)
@@ -144,9 +144,24 @@
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
-/* FLEXCAN hardware feature flags */
+#define FLEXCAN_TIMEOUT_US (50)
+
+/*
+ * FLEXCAN hardware feature flags
+ *
+ * Below is some version info we got:
+ * SOC Version IP-Version Glitch- [TR]WRN_INT
+ * Filter? connected?
+ * MX25 FlexCAN2 03.00.00.00 no no
+ * MX28 FlexCAN2 03.00.04.00 yes yes
+ * MX35 FlexCAN2 03.00.00.00 no no
+ * MX53 FlexCAN2 03.00.00.00 yes no
+ * MX6s FlexCAN3 10.00.12.00 yes yes
+ *
+ * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
+ */
#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
-#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* Broken error state handling */
+#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */
/* Structure of the message buffer */
struct flexcan_mb {
@@ -198,6 +213,7 @@ struct flexcan_priv {
struct clk *clk_per;
struct flexcan_platform_data *pdata;
const struct flexcan_devtype_data *devtype_data;
+ struct regulator *reg_xceiver;
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
@@ -205,7 +221,7 @@ static struct flexcan_devtype_data fsl_p1010_devtype_data = {
};
static struct flexcan_devtype_data fsl_imx28_devtype_data;
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
- .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_BROKEN_ERR_STATE,
+ .features = FLEXCAN_HAS_V10_FEATURES,
};
static const struct can_bittiming_const flexcan_bittiming_const = {
@@ -221,9 +237,12 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
};
/*
- * Abstract off the read/write for arm versus ppc.
+ * Abstract off the read/write for arm versus ppc. This
+ * assumes that PPC uses big-endian registers and everything
+ * else uses little-endian registers, independent of CPU
+ * endianess.
*/
-#if defined(__BIG_ENDIAN)
+#if defined(CONFIG_PPC)
static inline u32 flexcan_read(void __iomem *addr)
{
return in_be32(addr);
@@ -245,13 +264,20 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
}
#endif
-/*
- * Swtich transceiver on or off
- */
-static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on)
+static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
{
- if (priv->pdata && priv->pdata->transceiver_switch)
- priv->pdata->transceiver_switch(on);
+ if (!priv->reg_xceiver)
+ return 0;
+
+ return regulator_enable(priv->reg_xceiver);
+}
+
+static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
+{
+ if (!priv->reg_xceiver)
+ return 0;
+
+ return regulator_disable(priv->reg_xceiver);
}
static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
@@ -261,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
(reg_esr & FLEXCAN_ESR_ERR_BUS);
}
-static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+static int flexcan_chip_enable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg &= ~FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr);
- udelay(10);
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+ return -ETIMEDOUT;
+
+ return 0;
}
-static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+static int flexcan_chip_disable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_freeze(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+ u32 reg;
+
+ reg = flexcan_read(&regs->mcr);
+ reg |= FLEXCAN_MCR_HALT;
+ flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ usleep_range(100, 200);
+
+ if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+ u32 reg;
+
+ reg = flexcan_read(&regs->mcr);
+ reg &= ~FLEXCAN_MCR_HALT;
+ flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_softreset(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+ flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+ return -ETIMEDOUT;
+
+ return 0;
}
static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -551,6 +646,8 @@ static int flexcan_read_frame(struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+ can_led_event(dev, CAN_LED_EVENT_RX);
+
return 1;
}
@@ -639,6 +736,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
stats->tx_bytes += can_get_echo_skb(dev, 0);
stats->tx_packets++;
+ can_led_event(dev, CAN_LED_EVENT_TX);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev);
}
@@ -694,24 +792,18 @@ static int flexcan_chip_start(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- unsigned int i;
int err;
u32 reg_mcr, reg_ctrl;
/* enable module */
- flexcan_chip_enable(priv);
+ err = flexcan_chip_enable(priv);
+ if (err)
+ return err;
/* soft reset */
- flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
- udelay(10);
-
- reg_mcr = flexcan_read(&regs->mcr);
- if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
- netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
- reg_mcr);
- err = -ENODEV;
- goto out;
- }
+ err = flexcan_chip_softreset(priv);
+ if (err)
+ goto out_chip_disable;
flexcan_set_bittiming(dev);
@@ -728,9 +820,11 @@ static int flexcan_chip_start(struct net_device *dev)
*
*/
reg_mcr = flexcan_read(&regs->mcr);
+ reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
- FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS;
+ FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
+ FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
flexcan_write(reg_mcr, &regs->mcr);
@@ -764,16 +858,9 @@ static int flexcan_chip_start(struct net_device *dev)
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
flexcan_write(reg_ctrl, &regs->ctrl);
- for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
- flexcan_write(0, &regs->cantxfg[i].can_ctrl);
- flexcan_write(0, &regs->cantxfg[i].can_id);
- flexcan_write(0, &regs->cantxfg[i].data[0]);
- flexcan_write(0, &regs->cantxfg[i].data[1]);
-
- /* put MB into rx queue */
- flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
- &regs->cantxfg[i].can_ctrl);
- }
+ /* Abort any pending TX, mark Mailbox as INACTIVE */
+ flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
+ &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
/* acceptance mask/acceptance code (accept everything) */
flexcan_write(0x0, &regs->rxgmask);
@@ -783,12 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, &regs->rxfgmask);
- flexcan_transceiver_switch(priv, 1);
+ err = flexcan_transceiver_enable(priv);
+ if (err)
+ goto out_chip_disable;
/* synchronize with the can bus */
- reg_mcr = flexcan_read(&regs->mcr);
- reg_mcr &= ~FLEXCAN_MCR_HALT;
- flexcan_write(reg_mcr, &regs->mcr);
+ err = flexcan_chip_unfreeze(priv);
+ if (err)
+ goto out_transceiver_disable;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -801,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
return 0;
- out:
+ out_transceiver_disable:
+ flexcan_transceiver_disable(priv);
+ out_chip_disable:
flexcan_chip_disable(priv);
return err;
}
@@ -816,17 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- u32 reg;
+
+ /* freeze + disable module */
+ flexcan_chip_freeze(priv);
+ flexcan_chip_disable(priv);
/* Disable all interrupts */
flexcan_write(0, &regs->imask1);
+ flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+ &regs->ctrl);
- /* Disable + halt module */
- reg = flexcan_read(&regs->mcr);
- reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
- flexcan_write(reg, &regs->mcr);
-
- flexcan_transceiver_switch(priv, 0);
+ flexcan_transceiver_disable(priv);
priv->can.state = CAN_STATE_STOPPED;
return;
@@ -837,12 +928,17 @@ static int flexcan_open(struct net_device *dev)
struct flexcan_priv *priv = netdev_priv(dev);
int err;
- clk_prepare_enable(priv->clk_ipg);
- clk_prepare_enable(priv->clk_per);
+ err = clk_prepare_enable(priv->clk_ipg);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(priv->clk_per);
+ if (err)
+ goto out_disable_ipg;
err = open_candev(dev);
if (err)
- goto out;
+ goto out_disable_per;
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
if (err)
@@ -851,16 +947,22 @@ static int flexcan_open(struct net_device *dev)
/* start chip and queuing */
err = flexcan_chip_start(dev);
if (err)
- goto out_close;
+ goto out_free_irq;
+
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
napi_enable(&priv->napi);
netif_start_queue(dev);
return 0;
+ out_free_irq:
+ free_irq(dev->irq, dev);
out_close:
close_candev(dev);
- out:
+ out_disable_per:
clk_disable_unprepare(priv->clk_per);
+ out_disable_ipg:
clk_disable_unprepare(priv->clk_ipg);
return err;
@@ -880,6 +982,8 @@ static int flexcan_close(struct net_device *dev)
close_candev(dev);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -907,24 +1011,34 @@ static const struct net_device_ops flexcan_netdev_ops = {
.ndo_open = flexcan_open,
.ndo_stop = flexcan_close,
.ndo_start_xmit = flexcan_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
-static int __devinit register_flexcandev(struct net_device *dev)
+static int register_flexcandev(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
u32 reg, err;
- clk_prepare_enable(priv->clk_ipg);
- clk_prepare_enable(priv->clk_per);
+ err = clk_prepare_enable(priv->clk_ipg);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(priv->clk_per);
+ if (err)
+ goto out_disable_ipg;
/* select "bus clock", chip must be disabled */
- flexcan_chip_disable(priv);
+ err = flexcan_chip_disable(priv);
+ if (err)
+ goto out_disable_per;
reg = flexcan_read(&regs->ctrl);
reg |= FLEXCAN_CTRL_CLK_SRC;
flexcan_write(reg, &regs->ctrl);
- flexcan_chip_enable(priv);
+ err = flexcan_chip_enable(priv);
+ if (err)
+ goto out_chip_disable;
/* set freeze, halt and activate FIFO, restrict register access */
reg = flexcan_read(&regs->mcr);
@@ -941,38 +1055,42 @@ static int __devinit register_flexcandev(struct net_device *dev)
if (!(reg & FLEXCAN_MCR_FEN)) {
netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
err = -ENODEV;
- goto out;
+ goto out_chip_disable;
}
err = register_candev(dev);
- out:
/* disable core and turn off clocks */
+ out_chip_disable:
flexcan_chip_disable(priv);
+ out_disable_per:
clk_disable_unprepare(priv->clk_per);
+ out_disable_ipg:
clk_disable_unprepare(priv->clk_ipg);
return err;
}
-static void __devexit unregister_flexcandev(struct net_device *dev)
+static void unregister_flexcandev(struct net_device *dev)
{
unregister_candev(dev);
}
static const struct of_device_id flexcan_of_match[] = {
- { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
- { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
+ { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
+ { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, flexcan_of_match);
static const struct platform_device_id flexcan_id_table[] = {
{ .name = "flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(platform, flexcan_id_table);
-static int __devinit flexcan_probe(struct platform_device *pdev)
+static int flexcan_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
const struct flexcan_devtype_data *devtype_data;
@@ -980,16 +1098,10 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
struct flexcan_priv *priv;
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
- struct pinctrl *pinctrl;
void __iomem *base;
- resource_size_t mem_size;
int err, irq;
u32 clock_freq = 0;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- return PTR_ERR(pinctrl);
-
if (pdev->dev.of_node)
of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &clock_freq);
@@ -998,55 +1110,40 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(clk_ipg)) {
dev_err(&pdev->dev, "no ipg clock defined\n");
- err = PTR_ERR(clk_ipg);
- goto failed_clock;
+ return PTR_ERR(clk_ipg);
}
- clock_freq = clk_get_rate(clk_ipg);
clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(clk_per)) {
dev_err(&pdev->dev, "no per clock defined\n");
- err = PTR_ERR(clk_per);
- goto failed_clock;
+ return PTR_ERR(clk_per);
}
+ clock_freq = clk_get_rate(clk_per);
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!mem || irq <= 0) {
- err = -ENODEV;
- goto failed_get;
- }
-
- mem_size = resource_size(mem);
- if (!request_mem_region(mem->start, mem_size, pdev->name)) {
- err = -EBUSY;
- goto failed_get;
- }
+ if (irq <= 0)
+ return -ENODEV;
- base = ioremap(mem->start, mem_size);
- if (!base) {
- err = -ENOMEM;
- goto failed_map;
- }
-
- dev = alloc_candev(sizeof(struct flexcan_priv), 1);
- if (!dev) {
- err = -ENOMEM;
- goto failed_alloc;
- }
+ base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
of_id = of_match_device(flexcan_of_match, &pdev->dev);
if (of_id) {
devtype_data = of_id->data;
- } else if (pdev->id_entry->driver_data) {
+ } else if (platform_get_device_id(pdev)->driver_data) {
devtype_data = (struct flexcan_devtype_data *)
- pdev->id_entry->driver_data;
+ platform_get_device_id(pdev)->driver_data;
} else {
- err = -ENODEV;
- goto failed_devtype;
+ return -ENODEV;
}
+ dev = alloc_candev(sizeof(struct flexcan_priv), 1);
+ if (!dev)
+ return -ENOMEM;
+
dev->netdev_ops = &flexcan_netdev_ops;
dev->irq = irq;
dev->flags |= IFF_ECHO;
@@ -1063,12 +1160,16 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
priv->dev = dev;
priv->clk_ipg = clk_ipg;
priv->clk_per = clk_per;
- priv->pdata = pdev->dev.platform_data;
+ priv->pdata = dev_get_platdata(&pdev->dev);
priv->devtype_data = devtype_data;
+ priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+ if (IS_ERR(priv->reg_xceiver))
+ priv->reg_xceiver = NULL;
+
netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_flexcandev(dev);
@@ -1077,48 +1178,39 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
goto failed_register;
}
+ devm_can_led_init(dev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->base, dev->irq);
return 0;
failed_register:
- failed_devtype:
free_candev(dev);
- failed_alloc:
- iounmap(base);
- failed_map:
- release_mem_region(mem->start, mem_size);
- failed_get:
- failed_clock:
return err;
}
-static int __devexit flexcan_remove(struct platform_device *pdev)
+static int flexcan_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct flexcan_priv *priv = netdev_priv(dev);
- struct resource *mem;
unregister_flexcandev(dev);
- platform_set_drvdata(pdev, NULL);
- iounmap(priv->base);
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, resource_size(mem));
-
+ netif_napi_del(&priv->napi);
free_candev(dev);
return 0;
}
-#ifdef CONFIG_PM
-static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
+static int __maybe_unused flexcan_suspend(struct device *device)
{
- struct net_device *dev = platform_get_drvdata(pdev);
+ struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
+ int err;
- flexcan_chip_disable(priv);
+ err = flexcan_chip_disable(priv);
+ if (err)
+ return err;
if (netif_running(dev)) {
netif_stop_queue(dev);
@@ -1129,9 +1221,9 @@ static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int flexcan_resume(struct platform_device *pdev)
+static int __maybe_unused flexcan_resume(struct device *device)
{
- struct net_device *dev = platform_get_drvdata(pdev);
+ struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -1139,25 +1231,20 @@ static int flexcan_resume(struct platform_device *pdev)
netif_device_attach(dev);
netif_start_queue(dev);
}
- flexcan_chip_enable(priv);
-
- return 0;
+ return flexcan_chip_enable(priv);
}
-#else
-#define flexcan_suspend NULL
-#define flexcan_resume NULL
-#endif
+
+static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
static struct platform_driver flexcan_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &flexcan_pm_ops,
.of_match_table = flexcan_of_match,
},
.probe = flexcan_probe,
- .remove = __devexit_p(flexcan_remove),
- .suspend = flexcan_suspend,
- .resume = flexcan_resume,
+ .remove = flexcan_remove,
.id_table = flexcan_id_table,
};
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
new file mode 100644
index 00000000000..3fd9fd942c6
--- /dev/null
+++ b/drivers/net/can/grcan.c
@@ -0,0 +1,1752 @@
+/*
+ * Socket CAN driver for Aeroflex Gaisler GRCAN and GRHCAN.
+ *
+ * 2012 (c) Aeroflex Gaisler AB
+ *
+ * This driver supports GRCAN and GRHCAN CAN controllers available in the GRLIB
+ * VHDL IP core library.
+ *
+ * Full documentation of the GRCAN core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * See "Documentation/devicetree/bindings/net/can/grcan.txt" for information on
+ * open firmware properties.
+ *
+ * See "Documentation/ABI/testing/sysfs-class-net-grcan" for information on the
+ * sysfs interface.
+ *
+ * See "Documentation/kernel-parameters.txt" for information on the module
+ * parameters.
+ *
+ * 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.
+ *
+ * Contributors: Andreas Larsson <andreas@gaisler.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/can/dev.h>
+#include <linux/spinlock.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+
+#include <linux/dma-mapping.h>
+
+#define DRV_NAME "grcan"
+
+#define GRCAN_NAPI_WEIGHT 32
+
+#define GRCAN_RESERVE_SIZE(slot1, slot2) (((slot2) - (slot1)) / 4 - 1)
+
+struct grcan_registers {
+ u32 conf; /* 0x00 */
+ u32 stat; /* 0x04 */
+ u32 ctrl; /* 0x08 */
+ u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
+ u32 smask; /* 0x18 - CanMASK */
+ u32 scode; /* 0x1c - CanCODE */
+ u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x100)];
+ u32 pimsr; /* 0x100 */
+ u32 pimr; /* 0x104 */
+ u32 pisr; /* 0x108 */
+ u32 pir; /* 0x10C */
+ u32 imr; /* 0x110 */
+ u32 picr; /* 0x114 */
+ u32 __reserved3[GRCAN_RESERVE_SIZE(0x114, 0x200)];
+ u32 txctrl; /* 0x200 */
+ u32 txaddr; /* 0x204 */
+ u32 txsize; /* 0x208 */
+ u32 txwr; /* 0x20C */
+ u32 txrd; /* 0x210 */
+ u32 txirq; /* 0x214 */
+ u32 __reserved4[GRCAN_RESERVE_SIZE(0x214, 0x300)];
+ u32 rxctrl; /* 0x300 */
+ u32 rxaddr; /* 0x304 */
+ u32 rxsize; /* 0x308 */
+ u32 rxwr; /* 0x30C */
+ u32 rxrd; /* 0x310 */
+ u32 rxirq; /* 0x314 */
+ u32 rxmask; /* 0x318 */
+ u32 rxcode; /* 0x31C */
+};
+
+#define GRCAN_CONF_ABORT 0x00000001
+#define GRCAN_CONF_ENABLE0 0x00000002
+#define GRCAN_CONF_ENABLE1 0x00000004
+#define GRCAN_CONF_SELECT 0x00000008
+#define GRCAN_CONF_SILENT 0x00000010
+#define GRCAN_CONF_SAM 0x00000020 /* Available in some hardware */
+#define GRCAN_CONF_BPR 0x00000300 /* Note: not BRP */
+#define GRCAN_CONF_RSJ 0x00007000
+#define GRCAN_CONF_PS1 0x00f00000
+#define GRCAN_CONF_PS2 0x000f0000
+#define GRCAN_CONF_SCALER 0xff000000
+#define GRCAN_CONF_OPERATION \
+ (GRCAN_CONF_ABORT | GRCAN_CONF_ENABLE0 | GRCAN_CONF_ENABLE1 \
+ | GRCAN_CONF_SELECT | GRCAN_CONF_SILENT | GRCAN_CONF_SAM)
+#define GRCAN_CONF_TIMING \
+ (GRCAN_CONF_BPR | GRCAN_CONF_RSJ | GRCAN_CONF_PS1 \
+ | GRCAN_CONF_PS2 | GRCAN_CONF_SCALER)
+
+#define GRCAN_CONF_RSJ_MIN 1
+#define GRCAN_CONF_RSJ_MAX 4
+#define GRCAN_CONF_PS1_MIN 1
+#define GRCAN_CONF_PS1_MAX 15
+#define GRCAN_CONF_PS2_MIN 2
+#define GRCAN_CONF_PS2_MAX 8
+#define GRCAN_CONF_SCALER_MIN 0
+#define GRCAN_CONF_SCALER_MAX 255
+#define GRCAN_CONF_SCALER_INC 1
+
+#define GRCAN_CONF_BPR_BIT 8
+#define GRCAN_CONF_RSJ_BIT 12
+#define GRCAN_CONF_PS1_BIT 20
+#define GRCAN_CONF_PS2_BIT 16
+#define GRCAN_CONF_SCALER_BIT 24
+
+#define GRCAN_STAT_PASS 0x000001
+#define GRCAN_STAT_OFF 0x000002
+#define GRCAN_STAT_OR 0x000004
+#define GRCAN_STAT_AHBERR 0x000008
+#define GRCAN_STAT_ACTIVE 0x000010
+#define GRCAN_STAT_RXERRCNT 0x00ff00
+#define GRCAN_STAT_TXERRCNT 0xff0000
+
+#define GRCAN_STAT_ERRCTR_RELATED (GRCAN_STAT_PASS | GRCAN_STAT_OFF)
+
+#define GRCAN_STAT_RXERRCNT_BIT 8
+#define GRCAN_STAT_TXERRCNT_BIT 16
+
+#define GRCAN_STAT_ERRCNT_WARNING_LIMIT 96
+#define GRCAN_STAT_ERRCNT_PASSIVE_LIMIT 127
+
+#define GRCAN_CTRL_RESET 0x2
+#define GRCAN_CTRL_ENABLE 0x1
+
+#define GRCAN_TXCTRL_ENABLE 0x1
+#define GRCAN_TXCTRL_ONGOING 0x2
+#define GRCAN_TXCTRL_SINGLE 0x4
+
+#define GRCAN_RXCTRL_ENABLE 0x1
+#define GRCAN_RXCTRL_ONGOING 0x2
+
+/* Relative offset of IRQ sources to AMBA Plug&Play */
+#define GRCAN_IRQIX_IRQ 0
+#define GRCAN_IRQIX_TXSYNC 1
+#define GRCAN_IRQIX_RXSYNC 2
+
+#define GRCAN_IRQ_PASS 0x00001
+#define GRCAN_IRQ_OFF 0x00002
+#define GRCAN_IRQ_OR 0x00004
+#define GRCAN_IRQ_RXAHBERR 0x00008
+#define GRCAN_IRQ_TXAHBERR 0x00010
+#define GRCAN_IRQ_RXIRQ 0x00020
+#define GRCAN_IRQ_TXIRQ 0x00040
+#define GRCAN_IRQ_RXFULL 0x00080
+#define GRCAN_IRQ_TXEMPTY 0x00100
+#define GRCAN_IRQ_RX 0x00200
+#define GRCAN_IRQ_TX 0x00400
+#define GRCAN_IRQ_RXSYNC 0x00800
+#define GRCAN_IRQ_TXSYNC 0x01000
+#define GRCAN_IRQ_RXERRCTR 0x02000
+#define GRCAN_IRQ_TXERRCTR 0x04000
+#define GRCAN_IRQ_RXMISS 0x08000
+#define GRCAN_IRQ_TXLOSS 0x10000
+
+#define GRCAN_IRQ_NONE 0
+#define GRCAN_IRQ_ALL \
+ (GRCAN_IRQ_PASS | GRCAN_IRQ_OFF | GRCAN_IRQ_OR \
+ | GRCAN_IRQ_RXAHBERR | GRCAN_IRQ_TXAHBERR \
+ | GRCAN_IRQ_RXIRQ | GRCAN_IRQ_TXIRQ \
+ | GRCAN_IRQ_RXFULL | GRCAN_IRQ_TXEMPTY \
+ | GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_RXSYNC \
+ | GRCAN_IRQ_TXSYNC | GRCAN_IRQ_RXERRCTR \
+ | GRCAN_IRQ_TXERRCTR | GRCAN_IRQ_RXMISS \
+ | GRCAN_IRQ_TXLOSS)
+
+#define GRCAN_IRQ_ERRCTR_RELATED (GRCAN_IRQ_RXERRCTR | GRCAN_IRQ_TXERRCTR \
+ | GRCAN_IRQ_PASS | GRCAN_IRQ_OFF)
+#define GRCAN_IRQ_ERRORS (GRCAN_IRQ_ERRCTR_RELATED | GRCAN_IRQ_OR \
+ | GRCAN_IRQ_TXAHBERR | GRCAN_IRQ_RXAHBERR \
+ | GRCAN_IRQ_TXLOSS)
+#define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
+
+#define GRCAN_MSG_SIZE 16
+
+#define GRCAN_MSG_IDE 0x80000000
+#define GRCAN_MSG_RTR 0x40000000
+#define GRCAN_MSG_BID 0x1ffc0000
+#define GRCAN_MSG_EID 0x1fffffff
+#define GRCAN_MSG_IDE_BIT 31
+#define GRCAN_MSG_RTR_BIT 30
+#define GRCAN_MSG_BID_BIT 18
+#define GRCAN_MSG_EID_BIT 0
+
+#define GRCAN_MSG_DLC 0xf0000000
+#define GRCAN_MSG_TXERRC 0x00ff0000
+#define GRCAN_MSG_RXERRC 0x0000ff00
+#define GRCAN_MSG_DLC_BIT 28
+#define GRCAN_MSG_TXERRC_BIT 16
+#define GRCAN_MSG_RXERRC_BIT 8
+#define GRCAN_MSG_AHBERR 0x00000008
+#define GRCAN_MSG_OR 0x00000004
+#define GRCAN_MSG_OFF 0x00000002
+#define GRCAN_MSG_PASS 0x00000001
+
+#define GRCAN_MSG_DATA_SLOT_INDEX(i) (2 + (i) / 4)
+#define GRCAN_MSG_DATA_SHIFT(i) ((3 - (i) % 4) * 8)
+
+#define GRCAN_BUFFER_ALIGNMENT 1024
+#define GRCAN_DEFAULT_BUFFER_SIZE 1024
+#define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
+
+#define GRCAN_INVALID_BUFFER_SIZE(s) \
+ ((s) == 0 || ((s) & ~GRCAN_VALID_TR_SIZE_MASK))
+
+#if GRCAN_INVALID_BUFFER_SIZE(GRCAN_DEFAULT_BUFFER_SIZE)
+#error "Invalid default buffer size"
+#endif
+
+struct grcan_dma_buffer {
+ size_t size;
+ void *buf;
+ dma_addr_t handle;
+};
+
+struct grcan_dma {
+ size_t base_size;
+ void *base_buf;
+ dma_addr_t base_handle;
+ struct grcan_dma_buffer tx;
+ struct grcan_dma_buffer rx;
+};
+
+/* GRCAN configuration parameters */
+struct grcan_device_config {
+ unsigned short enable0;
+ unsigned short enable1;
+ unsigned short select;
+ unsigned int txsize;
+ unsigned int rxsize;
+};
+
+#define GRCAN_DEFAULT_DEVICE_CONFIG { \
+ .enable0 = 0, \
+ .enable1 = 0, \
+ .select = 0, \
+ .txsize = GRCAN_DEFAULT_BUFFER_SIZE, \
+ .rxsize = GRCAN_DEFAULT_BUFFER_SIZE, \
+ }
+
+#define GRCAN_TXBUG_SAFE_GRLIB_VERSION 0x4100
+#define GRLIB_VERSION_MASK 0xffff
+
+/* GRCAN private data structure */
+struct grcan_priv {
+ struct can_priv can; /* must be the first member */
+ struct net_device *dev;
+ struct napi_struct napi;
+
+ struct grcan_registers __iomem *regs; /* ioremap'ed registers */
+ struct grcan_device_config config;
+ struct grcan_dma dma;
+
+ struct sk_buff **echo_skb; /* We allocate this on our own */
+ u8 *txdlc; /* Length of queued frames */
+
+ /* The echo skb pointer, pointing into echo_skb and indicating which
+ * frames can be echoed back. See the "Notes on the tx cyclic buffer
+ * handling"-comment for grcan_start_xmit for more details.
+ */
+ u32 eskbp;
+
+ /* Lock for controlling changes to the netif tx queue state, accesses to
+ * the echo_skb pointer eskbp and for making sure that a running reset
+ * and/or a close of the interface is done without interference from
+ * other parts of the code.
+ *
+ * The echo_skb pointer, eskbp, should only be accessed under this lock
+ * as it can be changed in several places and together with decisions on
+ * whether to wake up the tx queue.
+ *
+ * The tx queue must never be woken up if there is a running reset or
+ * close in progress.
+ *
+ * A running reset (see below on need_txbug_workaround) should never be
+ * done if the interface is closing down and several running resets
+ * should never be scheduled simultaneously.
+ */
+ spinlock_t lock;
+
+ /* Whether a workaround is needed due to a bug in older hardware. In
+ * this case, the driver both tries to prevent the bug from being
+ * triggered and recovers, if the bug nevertheless happens, by doing a
+ * running reset. A running reset, resets the device and continues from
+ * where it were without being noticeable from outside the driver (apart
+ * from slight delays).
+ */
+ bool need_txbug_workaround;
+
+ /* To trigger initization of running reset and to trigger running reset
+ * respectively in the case of a hanged device due to a txbug.
+ */
+ struct timer_list hang_timer;
+ struct timer_list rr_timer;
+
+ /* To avoid waking up the netif queue and restarting timers
+ * when a reset is scheduled or when closing of the device is
+ * undergoing
+ */
+ bool resetting;
+ bool closing;
+};
+
+/* Wait time for a short wait for ongoing to clear */
+#define GRCAN_SHORTWAIT_USECS 10
+
+/* Limit on the number of transmitted bits of an eff frame according to the CAN
+ * specification: 1 bit start of frame, 32 bits arbitration field, 6 bits
+ * control field, 8 bytes data field, 16 bits crc field, 2 bits ACK field and 7
+ * bits end of frame
+ */
+#define GRCAN_EFF_FRAME_MAX_BITS (1+32+6+8*8+16+2+7)
+
+#if defined(__BIG_ENDIAN)
+static inline u32 grcan_read_reg(u32 __iomem *reg)
+{
+ return ioread32be(reg);
+}
+
+static inline void grcan_write_reg(u32 __iomem *reg, u32 val)
+{
+ iowrite32be(val, reg);
+}
+#else
+static inline u32 grcan_read_reg(u32 __iomem *reg)
+{
+ return ioread32(reg);
+}
+
+static inline void grcan_write_reg(u32 __iomem *reg, u32 val)
+{
+ iowrite32(val, reg);
+}
+#endif
+
+static inline void grcan_clear_bits(u32 __iomem *reg, u32 mask)
+{
+ grcan_write_reg(reg, grcan_read_reg(reg) & ~mask);
+}
+
+static inline void grcan_set_bits(u32 __iomem *reg, u32 mask)
+{
+ grcan_write_reg(reg, grcan_read_reg(reg) | mask);
+}
+
+static inline u32 grcan_read_bits(u32 __iomem *reg, u32 mask)
+{
+ return grcan_read_reg(reg) & mask;
+}
+
+static inline void grcan_write_bits(u32 __iomem *reg, u32 value, u32 mask)
+{
+ u32 old = grcan_read_reg(reg);
+
+ grcan_write_reg(reg, (old & ~mask) | (value & mask));
+}
+
+/* a and b should both be in [0,size] and a == b == size should not hold */
+static inline u32 grcan_ring_add(u32 a, u32 b, u32 size)
+{
+ u32 sum = a + b;
+
+ if (sum < size)
+ return sum;
+ else
+ return sum - size;
+}
+
+/* a and b should both be in [0,size) */
+static inline u32 grcan_ring_sub(u32 a, u32 b, u32 size)
+{
+ return grcan_ring_add(a, size - b, size);
+}
+
+/* Available slots for new transmissions */
+static inline u32 grcan_txspace(size_t txsize, u32 txwr, u32 eskbp)
+{
+ u32 slots = txsize / GRCAN_MSG_SIZE - 1;
+ u32 used = grcan_ring_sub(txwr, eskbp, txsize) / GRCAN_MSG_SIZE;
+
+ return slots - used;
+}
+
+/* Configuration parameters that can be set via module parameters */
+static struct grcan_device_config grcan_module_config =
+ GRCAN_DEFAULT_DEVICE_CONFIG;
+
+static const struct can_bittiming_const grcan_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = GRCAN_CONF_PS1_MIN + 1,
+ .tseg1_max = GRCAN_CONF_PS1_MAX + 1,
+ .tseg2_min = GRCAN_CONF_PS2_MIN,
+ .tseg2_max = GRCAN_CONF_PS2_MAX,
+ .sjw_max = GRCAN_CONF_RSJ_MAX,
+ .brp_min = GRCAN_CONF_SCALER_MIN + 1,
+ .brp_max = GRCAN_CONF_SCALER_MAX + 1,
+ .brp_inc = GRCAN_CONF_SCALER_INC,
+};
+
+static int grcan_set_bittiming(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct can_bittiming *bt = &priv->can.bittiming;
+ u32 timing = 0;
+ int bpr, rsj, ps1, ps2, scaler;
+
+ /* Should never happen - function will not be called when
+ * device is up
+ */
+ if (grcan_read_bits(&regs->ctrl, GRCAN_CTRL_ENABLE))
+ return -EBUSY;
+
+ bpr = 0; /* Note bpr and brp are different concepts */
+ rsj = bt->sjw;
+ ps1 = (bt->prop_seg + bt->phase_seg1) - 1; /* tseg1 - 1 */
+ ps2 = bt->phase_seg2;
+ scaler = (bt->brp - 1);
+ netdev_dbg(dev, "Request for BPR=%d, RSJ=%d, PS1=%d, PS2=%d, SCALER=%d",
+ bpr, rsj, ps1, ps2, scaler);
+ if (!(ps1 > ps2)) {
+ netdev_err(dev, "PS1 > PS2 must hold: PS1=%d, PS2=%d\n",
+ ps1, ps2);
+ return -EINVAL;
+ }
+ if (!(ps2 >= rsj)) {
+ netdev_err(dev, "PS2 >= RSJ must hold: PS2=%d, RSJ=%d\n",
+ ps2, rsj);
+ return -EINVAL;
+ }
+
+ timing |= (bpr << GRCAN_CONF_BPR_BIT) & GRCAN_CONF_BPR;
+ timing |= (rsj << GRCAN_CONF_RSJ_BIT) & GRCAN_CONF_RSJ;
+ timing |= (ps1 << GRCAN_CONF_PS1_BIT) & GRCAN_CONF_PS1;
+ timing |= (ps2 << GRCAN_CONF_PS2_BIT) & GRCAN_CONF_PS2;
+ timing |= (scaler << GRCAN_CONF_SCALER_BIT) & GRCAN_CONF_SCALER;
+ netdev_info(dev, "setting timing=0x%x\n", timing);
+ grcan_write_bits(&regs->conf, timing, GRCAN_CONF_TIMING);
+
+ return 0;
+}
+
+static int grcan_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ u32 status = grcan_read_reg(&regs->stat);
+
+ bec->txerr = (status & GRCAN_STAT_TXERRCNT) >> GRCAN_STAT_TXERRCNT_BIT;
+ bec->rxerr = (status & GRCAN_STAT_RXERRCNT) >> GRCAN_STAT_RXERRCNT_BIT;
+ return 0;
+}
+
+static int grcan_poll(struct napi_struct *napi, int budget);
+
+/* Reset device, but keep configuration information */
+static void grcan_reset(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ u32 config = grcan_read_reg(&regs->conf);
+
+ grcan_set_bits(&regs->ctrl, GRCAN_CTRL_RESET);
+ grcan_write_reg(&regs->conf, config);
+
+ priv->eskbp = grcan_read_reg(&regs->txrd);
+ priv->can.state = CAN_STATE_STOPPED;
+
+ /* Turn off hardware filtering - regs->rxcode set to 0 by reset */
+ grcan_write_reg(&regs->rxmask, 0);
+}
+
+/* stop device without changing any configurations */
+static void grcan_stop_hardware(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+
+ grcan_write_reg(&regs->imr, GRCAN_IRQ_NONE);
+ grcan_clear_bits(&regs->txctrl, GRCAN_TXCTRL_ENABLE);
+ grcan_clear_bits(&regs->rxctrl, GRCAN_RXCTRL_ENABLE);
+ grcan_clear_bits(&regs->ctrl, GRCAN_CTRL_ENABLE);
+}
+
+/* Let priv->eskbp catch up to regs->txrd and echo back the skbs if echo
+ * is true and free them otherwise.
+ *
+ * If budget is >= 0, stop after handling at most budget skbs. Otherwise,
+ * continue until priv->eskbp catches up to regs->txrd.
+ *
+ * priv->lock *must* be held when calling this function
+ */
+static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_dma *dma = &priv->dma;
+ struct net_device_stats *stats = &dev->stats;
+ int i, work_done;
+
+ /* Updates to priv->eskbp and wake-ups of the queue needs to
+ * be atomic towards the reads of priv->eskbp and shut-downs
+ * of the queue in grcan_start_xmit.
+ */
+ u32 txrd = grcan_read_reg(&regs->txrd);
+
+ for (work_done = 0; work_done < budget || budget < 0; work_done++) {
+ if (priv->eskbp == txrd)
+ break;
+ i = priv->eskbp / GRCAN_MSG_SIZE;
+ if (echo) {
+ /* Normal echo of messages */
+ stats->tx_packets++;
+ stats->tx_bytes += priv->txdlc[i];
+ priv->txdlc[i] = 0;
+ can_get_echo_skb(dev, i);
+ } else {
+ /* For cleanup of untransmitted messages */
+ can_free_echo_skb(dev, i);
+ }
+
+ priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
+ dma->tx.size);
+ txrd = grcan_read_reg(&regs->txrd);
+ }
+ return work_done;
+}
+
+static void grcan_lost_one_shot_frame(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_dma *dma = &priv->dma;
+ u32 txrd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ catch_up_echo_skb(dev, -1, true);
+
+ if (unlikely(grcan_read_bits(&regs->txctrl, GRCAN_TXCTRL_ENABLE))) {
+ /* Should never happen */
+ netdev_err(dev, "TXCTRL enabled at TXLOSS in one shot mode\n");
+ } else {
+ /* By the time an GRCAN_IRQ_TXLOSS is generated in
+ * one-shot mode there is no problem in writing
+ * to TXRD even in versions of the hardware in
+ * which GRCAN_TXCTRL_ONGOING is not cleared properly
+ * in one-shot mode.
+ */
+
+ /* Skip message and discard echo-skb */
+ txrd = grcan_read_reg(&regs->txrd);
+ txrd = grcan_ring_add(txrd, GRCAN_MSG_SIZE, dma->tx.size);
+ grcan_write_reg(&regs->txrd, txrd);
+ catch_up_echo_skb(dev, -1, false);
+
+ if (!priv->resetting && !priv->closing &&
+ !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) {
+ netif_wake_queue(dev);
+ grcan_set_bits(&regs->txctrl, GRCAN_TXCTRL_ENABLE);
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void grcan_err(struct net_device *dev, u32 sources, u32 status)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_dma *dma = &priv->dma;
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame cf;
+
+ /* Zero potential error_frame */
+ memset(&cf, 0, sizeof(cf));
+
+ /* Message lost interrupt. This might be due to arbitration error, but
+ * is also triggered when there is no one else on the can bus or when
+ * there is a problem with the hardware interface or the bus itself. As
+ * arbitration errors can not be singled out, no error frames are
+ * generated reporting this event as an arbitration error.
+ */
+ if (sources & GRCAN_IRQ_TXLOSS) {
+ /* Take care of failed one-shot transmit */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ grcan_lost_one_shot_frame(dev);
+
+ /* Stop printing as soon as error passive or bus off is in
+ * effect to limit the amount of txloss debug printouts.
+ */
+ if (!(status & GRCAN_STAT_ERRCTR_RELATED)) {
+ netdev_dbg(dev, "tx message lost\n");
+ stats->tx_errors++;
+ }
+ }
+
+ /* Conditions dealing with the error counters. There is no interrupt for
+ * error warning, but there are interrupts for increases of the error
+ * counters.
+ */
+ if ((sources & GRCAN_IRQ_ERRCTR_RELATED) ||
+ (status & GRCAN_STAT_ERRCTR_RELATED)) {
+ enum can_state state = priv->can.state;
+ enum can_state oldstate = state;
+ u32 txerr = (status & GRCAN_STAT_TXERRCNT)
+ >> GRCAN_STAT_TXERRCNT_BIT;
+ u32 rxerr = (status & GRCAN_STAT_RXERRCNT)
+ >> GRCAN_STAT_RXERRCNT_BIT;
+
+ /* Figure out current state */
+ if (status & GRCAN_STAT_OFF) {
+ state = CAN_STATE_BUS_OFF;
+ } else if (status & GRCAN_STAT_PASS) {
+ state = CAN_STATE_ERROR_PASSIVE;
+ } else if (txerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT ||
+ rxerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT) {
+ state = CAN_STATE_ERROR_WARNING;
+ } else {
+ state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ /* Handle and report state changes */
+ if (state != oldstate) {
+ switch (state) {
+ case CAN_STATE_BUS_OFF:
+ netdev_dbg(dev, "bus-off\n");
+ netif_carrier_off(dev);
+ priv->can.can_stats.bus_off++;
+
+ /* Prevent the hardware from recovering from bus
+ * off on its own if restart is disabled.
+ */
+ if (!priv->can.restart_ms)
+ grcan_stop_hardware(dev);
+
+ cf.can_id |= CAN_ERR_BUSOFF;
+ break;
+
+ case CAN_STATE_ERROR_PASSIVE:
+ netdev_dbg(dev, "Error passive condition\n");
+ priv->can.can_stats.error_passive++;
+
+ cf.can_id |= CAN_ERR_CRTL;
+ if (txerr >= GRCAN_STAT_ERRCNT_PASSIVE_LIMIT)
+ cf.data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ if (rxerr >= GRCAN_STAT_ERRCNT_PASSIVE_LIMIT)
+ cf.data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ break;
+
+ case CAN_STATE_ERROR_WARNING:
+ netdev_dbg(dev, "Error warning condition\n");
+ priv->can.can_stats.error_warning++;
+
+ cf.can_id |= CAN_ERR_CRTL;
+ if (txerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT)
+ cf.data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ if (rxerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT)
+ cf.data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ break;
+
+ case CAN_STATE_ERROR_ACTIVE:
+ netdev_dbg(dev, "Error active condition\n");
+ cf.can_id |= CAN_ERR_CRTL;
+ break;
+
+ default:
+ /* There are no others at this point */
+ break;
+ }
+ cf.data[6] = txerr;
+ cf.data[7] = rxerr;
+ priv->can.state = state;
+ }
+
+ /* Report automatic restarts */
+ if (priv->can.restart_ms && oldstate == CAN_STATE_BUS_OFF) {
+ unsigned long flags;
+
+ cf.can_id |= CAN_ERR_RESTARTED;
+ netdev_dbg(dev, "restarted\n");
+ priv->can.can_stats.restarts++;
+ netif_carrier_on(dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!priv->resetting && !priv->closing) {
+ u32 txwr = grcan_read_reg(&regs->txwr);
+
+ if (grcan_txspace(dma->tx.size, txwr,
+ priv->eskbp))
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ }
+
+ /* Data overrun interrupt */
+ if ((sources & GRCAN_IRQ_OR) || (status & GRCAN_STAT_OR)) {
+ netdev_dbg(dev, "got data overrun interrupt\n");
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+
+ cf.can_id |= CAN_ERR_CRTL;
+ cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ }
+
+ /* AHB bus error interrupts (not CAN bus errors) - shut down the
+ * device.
+ */
+ if (sources & (GRCAN_IRQ_TXAHBERR | GRCAN_IRQ_RXAHBERR) ||
+ (status & GRCAN_STAT_AHBERR)) {
+ char *txrx = "";
+ unsigned long flags;
+
+ if (sources & GRCAN_IRQ_TXAHBERR) {
+ txrx = "on tx ";
+ stats->tx_errors++;
+ } else if (sources & GRCAN_IRQ_RXAHBERR) {
+ txrx = "on rx ";
+ stats->rx_errors++;
+ }
+ netdev_err(dev, "Fatal AHB buss error %s- halting device\n",
+ txrx);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Prevent anything to be enabled again and halt device */
+ priv->closing = true;
+ netif_stop_queue(dev);
+ grcan_stop_hardware(dev);
+ priv->can.state = CAN_STATE_STOPPED;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ /* Pass on error frame if something to report,
+ * i.e. id contains some information
+ */
+ if (cf.can_id) {
+ struct can_frame *skb_cf;
+ struct sk_buff *skb = alloc_can_err_skb(dev, &skb_cf);
+
+ if (skb == NULL) {
+ netdev_dbg(dev, "could not allocate error frame\n");
+ return;
+ }
+ skb_cf->can_id |= cf.can_id;
+ memcpy(skb_cf->data, cf.data, sizeof(cf.data));
+
+ netif_rx(skb);
+ }
+}
+
+static irqreturn_t grcan_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ u32 sources, status;
+
+ /* Find out the source */
+ sources = grcan_read_reg(&regs->pimsr);
+ if (!sources)
+ return IRQ_NONE;
+ grcan_write_reg(&regs->picr, sources);
+ status = grcan_read_reg(&regs->stat);
+
+ /* If we got TX progress, the device has not hanged,
+ * so disable the hang timer
+ */
+ if (priv->need_txbug_workaround &&
+ (sources & (GRCAN_IRQ_TX | GRCAN_IRQ_TXLOSS))) {
+ del_timer(&priv->hang_timer);
+ }
+
+ /* Frame(s) received or transmitted */
+ if (sources & (GRCAN_IRQ_TX | GRCAN_IRQ_RX)) {
+ /* Disable tx/rx interrupts and schedule poll(). No need for
+ * locking as interference from a running reset at worst leads
+ * to an extra interrupt.
+ */
+ grcan_clear_bits(&regs->imr, GRCAN_IRQ_TX | GRCAN_IRQ_RX);
+ napi_schedule(&priv->napi);
+ }
+
+ /* (Potential) error conditions to take care of */
+ if (sources & GRCAN_IRQ_ERRORS)
+ grcan_err(dev, sources, status);
+
+ return IRQ_HANDLED;
+}
+
+/* Reset device and restart operations from where they were.
+ *
+ * This assumes that RXCTRL & RXCTRL is properly disabled and that RX
+ * is not ONGOING (TX might be stuck in ONGOING due to a harwrware bug
+ * for single shot)
+ */
+static void grcan_running_reset(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ unsigned long flags;
+
+ /* This temporarily messes with eskbp, so we need to lock
+ * priv->lock
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->resetting = false;
+ del_timer(&priv->hang_timer);
+ del_timer(&priv->rr_timer);
+
+ if (!priv->closing) {
+ /* Save and reset - config register preserved by grcan_reset */
+ u32 imr = grcan_read_reg(&regs->imr);
+
+ u32 txaddr = grcan_read_reg(&regs->txaddr);
+ u32 txsize = grcan_read_reg(&regs->txsize);
+ u32 txwr = grcan_read_reg(&regs->txwr);
+ u32 txrd = grcan_read_reg(&regs->txrd);
+ u32 eskbp = priv->eskbp;
+
+ u32 rxaddr = grcan_read_reg(&regs->rxaddr);
+ u32 rxsize = grcan_read_reg(&regs->rxsize);
+ u32 rxwr = grcan_read_reg(&regs->rxwr);
+ u32 rxrd = grcan_read_reg(&regs->rxrd);
+
+ grcan_reset(dev);
+
+ /* Restore */
+ grcan_write_reg(&regs->txaddr, txaddr);
+ grcan_write_reg(&regs->txsize, txsize);
+ grcan_write_reg(&regs->txwr, txwr);
+ grcan_write_reg(&regs->txrd, txrd);
+ priv->eskbp = eskbp;
+
+ grcan_write_reg(&regs->rxaddr, rxaddr);
+ grcan_write_reg(&regs->rxsize, rxsize);
+ grcan_write_reg(&regs->rxwr, rxwr);
+ grcan_write_reg(&regs->rxrd, rxrd);
+
+ /* Turn on device again */
+ grcan_write_reg(&regs->imr, imr);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ grcan_write_reg(&regs->txctrl, GRCAN_TXCTRL_ENABLE
+ | (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT
+ ? GRCAN_TXCTRL_SINGLE : 0));
+ grcan_write_reg(&regs->rxctrl, GRCAN_RXCTRL_ENABLE);
+ grcan_write_reg(&regs->ctrl, GRCAN_CTRL_ENABLE);
+
+ /* Start queue if there is size and listen-onle mode is not
+ * enabled
+ */
+ if (grcan_txspace(priv->dma.tx.size, txwr, priv->eskbp) &&
+ !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ netdev_err(dev, "Device reset and restored\n");
+}
+
+/* Waiting time in usecs corresponding to the transmission of three maximum
+ * sized can frames in the given bitrate (in bits/sec). Waiting for this amount
+ * of time makes sure that the can controller have time to finish sending or
+ * receiving a frame with a good margin.
+ *
+ * usecs/sec * number of frames * bits/frame / bits/sec
+ */
+static inline u32 grcan_ongoing_wait_usecs(__u32 bitrate)
+{
+ return 1000000 * 3 * GRCAN_EFF_FRAME_MAX_BITS / bitrate;
+}
+
+/* Set timer so that it will not fire until after a period in which the can
+ * controller have a good margin to finish transmitting a frame unless it has
+ * hanged
+ */
+static inline void grcan_reset_timer(struct timer_list *timer, __u32 bitrate)
+{
+ u32 wait_jiffies = usecs_to_jiffies(grcan_ongoing_wait_usecs(bitrate));
+
+ mod_timer(timer, jiffies + wait_jiffies);
+}
+
+/* Disable channels and schedule a running reset */
+static void grcan_initiate_running_reset(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ unsigned long flags;
+
+ netdev_err(dev, "Device seems hanged - reset scheduled\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* The main body of this function must never be executed again
+ * until after an execution of grcan_running_reset
+ */
+ if (!priv->resetting && !priv->closing) {
+ priv->resetting = true;
+ netif_stop_queue(dev);
+ grcan_clear_bits(&regs->txctrl, GRCAN_TXCTRL_ENABLE);
+ grcan_clear_bits(&regs->rxctrl, GRCAN_RXCTRL_ENABLE);
+ grcan_reset_timer(&priv->rr_timer, priv->can.bittiming.bitrate);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void grcan_free_dma_buffers(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_dma *dma = &priv->dma;
+
+ dma_free_coherent(&dev->dev, dma->base_size, dma->base_buf,
+ dma->base_handle);
+ memset(dma, 0, sizeof(*dma));
+}
+
+static int grcan_allocate_dma_buffers(struct net_device *dev,
+ size_t tsize, size_t rsize)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_dma *dma = &priv->dma;
+ struct grcan_dma_buffer *large = rsize > tsize ? &dma->rx : &dma->tx;
+ struct grcan_dma_buffer *small = rsize > tsize ? &dma->tx : &dma->rx;
+ size_t shift;
+
+ /* Need a whole number of GRCAN_BUFFER_ALIGNMENT for the large,
+ * i.e. first buffer
+ */
+ size_t maxs = max(tsize, rsize);
+ size_t lsize = ALIGN(maxs, GRCAN_BUFFER_ALIGNMENT);
+
+ /* Put the small buffer after that */
+ size_t ssize = min(tsize, rsize);
+
+ /* Extra GRCAN_BUFFER_ALIGNMENT to allow for alignment */
+ dma->base_size = lsize + ssize + GRCAN_BUFFER_ALIGNMENT;
+ dma->base_buf = dma_alloc_coherent(&dev->dev,
+ dma->base_size,
+ &dma->base_handle,
+ GFP_KERNEL);
+
+ if (!dma->base_buf)
+ return -ENOMEM;
+
+ dma->tx.size = tsize;
+ dma->rx.size = rsize;
+
+ large->handle = ALIGN(dma->base_handle, GRCAN_BUFFER_ALIGNMENT);
+ small->handle = large->handle + lsize;
+ shift = large->handle - dma->base_handle;
+
+ large->buf = dma->base_buf + shift;
+ small->buf = large->buf + lsize;
+
+ return 0;
+}
+
+/* priv->lock *must* be held when calling this function */
+static int grcan_start(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ u32 confop, txctrl;
+
+ grcan_reset(dev);
+
+ grcan_write_reg(&regs->txaddr, priv->dma.tx.handle);
+ grcan_write_reg(&regs->txsize, priv->dma.tx.size);
+ /* regs->txwr, regs->txrd and priv->eskbp already set to 0 by reset */
+
+ grcan_write_reg(&regs->rxaddr, priv->dma.rx.handle);
+ grcan_write_reg(&regs->rxsize, priv->dma.rx.size);
+ /* regs->rxwr and regs->rxrd already set to 0 by reset */
+
+ /* Enable interrupts */
+ grcan_read_reg(&regs->pir);
+ grcan_write_reg(&regs->imr, GRCAN_IRQ_DEFAULT);
+
+ /* Enable interfaces, channels and device */
+ confop = GRCAN_CONF_ABORT
+ | (priv->config.enable0 ? GRCAN_CONF_ENABLE0 : 0)
+ | (priv->config.enable1 ? GRCAN_CONF_ENABLE1 : 0)
+ | (priv->config.select ? GRCAN_CONF_SELECT : 0)
+ | (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY ?
+ GRCAN_CONF_SILENT : 0)
+ | (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ?
+ GRCAN_CONF_SAM : 0);
+ grcan_write_bits(&regs->conf, confop, GRCAN_CONF_OPERATION);
+ txctrl = GRCAN_TXCTRL_ENABLE
+ | (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT
+ ? GRCAN_TXCTRL_SINGLE : 0);
+ grcan_write_reg(&regs->txctrl, txctrl);
+ grcan_write_reg(&regs->rxctrl, GRCAN_RXCTRL_ENABLE);
+ grcan_write_reg(&regs->ctrl, GRCAN_CTRL_ENABLE);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+}
+
+static int grcan_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+ int err = 0;
+
+ if (mode == CAN_MODE_START) {
+ /* This might be called to restart the device to recover from
+ * bus off errors
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->closing || priv->resetting) {
+ err = -EBUSY;
+ } else {
+ netdev_info(dev, "Restarting device\n");
+ grcan_start(dev);
+ if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return err;
+ }
+ return -EOPNOTSUPP;
+}
+
+static int grcan_open(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_dma *dma = &priv->dma;
+ unsigned long flags;
+ int err;
+
+ /* Allocate memory */
+ err = grcan_allocate_dma_buffers(dev, priv->config.txsize,
+ priv->config.rxsize);
+ if (err) {
+ netdev_err(dev, "could not allocate DMA buffers\n");
+ return err;
+ }
+
+ priv->echo_skb = kzalloc(dma->tx.size * sizeof(*priv->echo_skb),
+ GFP_KERNEL);
+ if (!priv->echo_skb) {
+ err = -ENOMEM;
+ goto exit_free_dma_buffers;
+ }
+ priv->can.echo_skb_max = dma->tx.size;
+ priv->can.echo_skb = priv->echo_skb;
+
+ priv->txdlc = kzalloc(dma->tx.size * sizeof(*priv->txdlc), GFP_KERNEL);
+ if (!priv->txdlc) {
+ err = -ENOMEM;
+ goto exit_free_echo_skb;
+ }
+
+ /* Get can device up */
+ err = open_candev(dev);
+ if (err)
+ goto exit_free_txdlc;
+
+ err = request_irq(dev->irq, grcan_interrupt, IRQF_SHARED,
+ dev->name, dev);
+ if (err)
+ goto exit_close_candev;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ napi_enable(&priv->napi);
+ grcan_start(dev);
+ if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
+ netif_start_queue(dev);
+ priv->resetting = false;
+ priv->closing = false;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+
+exit_close_candev:
+ close_candev(dev);
+exit_free_txdlc:
+ kfree(priv->txdlc);
+exit_free_echo_skb:
+ kfree(priv->echo_skb);
+exit_free_dma_buffers:
+ grcan_free_dma_buffers(dev);
+ return err;
+}
+
+static int grcan_close(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ napi_disable(&priv->napi);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->closing = true;
+ if (priv->need_txbug_workaround) {
+ del_timer_sync(&priv->hang_timer);
+ del_timer_sync(&priv->rr_timer);
+ }
+ netif_stop_queue(dev);
+ grcan_stop_hardware(dev);
+ priv->can.state = CAN_STATE_STOPPED;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ free_irq(dev->irq, dev);
+ close_candev(dev);
+
+ grcan_free_dma_buffers(dev);
+ priv->can.echo_skb_max = 0;
+ priv->can.echo_skb = NULL;
+ kfree(priv->echo_skb);
+ kfree(priv->txdlc);
+
+ return 0;
+}
+
+static int grcan_transmit_catch_up(struct net_device *dev, int budget)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+ int work_done;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ work_done = catch_up_echo_skb(dev, budget, true);
+ if (work_done) {
+ if (!priv->resetting && !priv->closing &&
+ !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
+ netif_wake_queue(dev);
+
+ /* With napi we don't get TX interrupts for a while,
+ * so prevent a running reset while catching up
+ */
+ if (priv->need_txbug_workaround)
+ del_timer(&priv->hang_timer);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return work_done;
+}
+
+static int grcan_receive(struct net_device *dev, int budget)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_dma *dma = &priv->dma;
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 wr, rd, startrd;
+ u32 *slot;
+ u32 i, rtr, eff, j, shift;
+ int work_done = 0;
+
+ rd = grcan_read_reg(&regs->rxrd);
+ startrd = rd;
+ for (work_done = 0; work_done < budget; work_done++) {
+ /* Check for packet to receive */
+ wr = grcan_read_reg(&regs->rxwr);
+ if (rd == wr)
+ break;
+
+ /* Take care of packet */
+ skb = alloc_can_skb(dev, &cf);
+ if (skb == NULL) {
+ netdev_err(dev,
+ "dropping frame: skb allocation failed\n");
+ stats->rx_dropped++;
+ continue;
+ }
+
+ slot = dma->rx.buf + rd;
+ eff = slot[0] & GRCAN_MSG_IDE;
+ rtr = slot[0] & GRCAN_MSG_RTR;
+ if (eff) {
+ cf->can_id = ((slot[0] & GRCAN_MSG_EID)
+ >> GRCAN_MSG_EID_BIT);
+ cf->can_id |= CAN_EFF_FLAG;
+ } else {
+ cf->can_id = ((slot[0] & GRCAN_MSG_BID)
+ >> GRCAN_MSG_BID_BIT);
+ }
+ cf->can_dlc = get_can_dlc((slot[1] & GRCAN_MSG_DLC)
+ >> GRCAN_MSG_DLC_BIT);
+ if (rtr) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ for (i = 0; i < cf->can_dlc; i++) {
+ j = GRCAN_MSG_DATA_SLOT_INDEX(i);
+ shift = GRCAN_MSG_DATA_SHIFT(i);
+ cf->data[i] = (u8)(slot[j] >> shift);
+ }
+ }
+ netif_receive_skb(skb);
+
+ /* Update statistics and read pointer */
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
+ }
+
+ /* Make sure everything is read before allowing hardware to
+ * use the memory
+ */
+ mb();
+
+ /* Update read pointer - no need to check for ongoing */
+ if (likely(rd != startrd))
+ grcan_write_reg(&regs->rxrd, rd);
+
+ return work_done;
+}
+
+static int grcan_poll(struct napi_struct *napi, int budget)
+{
+ struct grcan_priv *priv = container_of(napi, struct grcan_priv, napi);
+ struct net_device *dev = priv->dev;
+ struct grcan_registers __iomem *regs = priv->regs;
+ unsigned long flags;
+ int tx_work_done, rx_work_done;
+ int rx_budget = budget / 2;
+ int tx_budget = budget - rx_budget;
+
+ /* Half of the budget for receiveing messages */
+ rx_work_done = grcan_receive(dev, rx_budget);
+
+ /* Half of the budget for transmitting messages as that can trigger echo
+ * frames being received
+ */
+ tx_work_done = grcan_transmit_catch_up(dev, tx_budget);
+
+ if (rx_work_done < rx_budget && tx_work_done < tx_budget) {
+ napi_complete(napi);
+
+ /* Guarantee no interference with a running reset that otherwise
+ * could turn off interrupts.
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Enable tx and rx interrupts again. No need to check
+ * priv->closing as napi_disable in grcan_close is waiting for
+ * scheduled napi calls to finish.
+ */
+ grcan_set_bits(&regs->imr, GRCAN_IRQ_TX | GRCAN_IRQ_RX);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ return rx_work_done + tx_work_done;
+}
+
+/* Work tx bug by waiting while for the risky situation to clear. If that fails,
+ * drop a frame in one-shot mode or indicate a busy device otherwise.
+ *
+ * Returns 0 on successful wait. Otherwise it sets *netdev_tx_status to the
+ * value that should be returned by grcan_start_xmit when aborting the xmit.
+ */
+static int grcan_txbug_workaround(struct net_device *dev, struct sk_buff *skb,
+ u32 txwr, u32 oneshotmode,
+ netdev_tx_t *netdev_tx_status)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_dma *dma = &priv->dma;
+ int i;
+ unsigned long flags;
+
+ /* Wait a while for ongoing to be cleared or read pointer to catch up to
+ * write pointer. The latter is needed due to a bug in older versions of
+ * GRCAN in which ONGOING is not cleared properly one-shot mode when a
+ * transmission fails.
+ */
+ for (i = 0; i < GRCAN_SHORTWAIT_USECS; i++) {
+ udelay(1);
+ if (!grcan_read_bits(&regs->txctrl, GRCAN_TXCTRL_ONGOING) ||
+ grcan_read_reg(&regs->txrd) == txwr) {
+ return 0;
+ }
+ }
+
+ /* Clean up, in case the situation was not resolved */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->resetting && !priv->closing) {
+ /* Queue might have been stopped earlier in grcan_start_xmit */
+ if (grcan_txspace(dma->tx.size, txwr, priv->eskbp))
+ netif_wake_queue(dev);
+ /* Set a timer to resolve a hanged tx controller */
+ if (!timer_pending(&priv->hang_timer))
+ grcan_reset_timer(&priv->hang_timer,
+ priv->can.bittiming.bitrate);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (oneshotmode) {
+ /* In one-shot mode we should never end up here because
+ * then the interrupt handler increases txrd on TXLOSS,
+ * but it is consistent with one-shot mode to drop the
+ * frame in this case.
+ */
+ kfree_skb(skb);
+ *netdev_tx_status = NETDEV_TX_OK;
+ } else {
+ /* In normal mode the socket-can transmission queue get
+ * to keep the frame so that it can be retransmitted
+ * later
+ */
+ *netdev_tx_status = NETDEV_TX_BUSY;
+ }
+ return -EBUSY;
+}
+
+/* Notes on the tx cyclic buffer handling:
+ *
+ * regs->txwr - the next slot for the driver to put data to be sent
+ * regs->txrd - the next slot for the device to read data
+ * priv->eskbp - the next slot for the driver to call can_put_echo_skb for
+ *
+ * grcan_start_xmit can enter more messages as long as regs->txwr does
+ * not reach priv->eskbp (within 1 message gap)
+ *
+ * The device sends messages until regs->txrd reaches regs->txwr
+ *
+ * The interrupt calls handler calls can_put_echo_skb until
+ * priv->eskbp reaches regs->txrd
+ */
+static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_dma *dma = &priv->dma;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 id, txwr, txrd, space, txctrl;
+ int slotindex;
+ u32 *slot;
+ u32 i, rtr, eff, dlc, tmp, err;
+ int j, shift;
+ unsigned long flags;
+ u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
+
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
+ /* Trying to transmit in silent mode will generate error interrupts, but
+ * this should never happen - the queue should not have been started.
+ */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ return NETDEV_TX_BUSY;
+
+ /* Reads of priv->eskbp and shut-downs of the queue needs to
+ * be atomic towards the updates to priv->eskbp and wake-ups
+ * of the queue in the interrupt handler.
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ txwr = grcan_read_reg(&regs->txwr);
+ space = grcan_txspace(dma->tx.size, txwr, priv->eskbp);
+
+ slotindex = txwr / GRCAN_MSG_SIZE;
+ slot = dma->tx.buf + txwr;
+
+ if (unlikely(space == 1))
+ netif_stop_queue(dev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /* End of critical section*/
+
+ /* This should never happen. If circular buffer is full, the
+ * netif_stop_queue should have been stopped already.
+ */
+ if (unlikely(!space)) {
+ netdev_err(dev, "No buffer space, but queue is non-stopped.\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Convert and write CAN message to DMA buffer */
+ eff = cf->can_id & CAN_EFF_FLAG;
+ rtr = cf->can_id & CAN_RTR_FLAG;
+ id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
+ dlc = cf->can_dlc;
+ if (eff)
+ tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
+ else
+ tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
+ slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
+
+ slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
+ slot[2] = 0;
+ slot[3] = 0;
+ for (i = 0; i < dlc; i++) {
+ j = GRCAN_MSG_DATA_SLOT_INDEX(i);
+ shift = GRCAN_MSG_DATA_SHIFT(i);
+ slot[j] |= cf->data[i] << shift;
+ }
+
+ /* Checking that channel has not been disabled. These cases
+ * should never happen
+ */
+ txctrl = grcan_read_reg(&regs->txctrl);
+ if (!(txctrl & GRCAN_TXCTRL_ENABLE))
+ netdev_err(dev, "tx channel spuriously disabled\n");
+
+ if (oneshotmode && !(txctrl & GRCAN_TXCTRL_SINGLE))
+ netdev_err(dev, "one-shot mode spuriously disabled\n");
+
+ /* Bug workaround for old version of grcan where updating txwr
+ * in the same clock cycle as the controller updates txrd to
+ * the current txwr could hang the can controller
+ */
+ if (priv->need_txbug_workaround) {
+ txrd = grcan_read_reg(&regs->txrd);
+ if (unlikely(grcan_ring_sub(txwr, txrd, dma->tx.size) == 1)) {
+ netdev_tx_t txstatus;
+
+ err = grcan_txbug_workaround(dev, skb, txwr,
+ oneshotmode, &txstatus);
+ if (err)
+ return txstatus;
+ }
+ }
+
+ /* Prepare skb for echoing. This must be after the bug workaround above
+ * as ownership of the skb is passed on by calling can_put_echo_skb.
+ * Returning NETDEV_TX_BUSY or accessing skb or cf after a call to
+ * can_put_echo_skb would be an error unless other measures are
+ * taken.
+ */
+ priv->txdlc[slotindex] = cf->can_dlc; /* Store dlc for statistics */
+ can_put_echo_skb(skb, dev, slotindex);
+
+ /* Make sure everything is written before allowing hardware to
+ * read from the memory
+ */
+ wmb();
+
+ /* Update write pointer to start transmission */
+ grcan_write_reg(&regs->txwr,
+ grcan_ring_add(txwr, GRCAN_MSG_SIZE, dma->tx.size));
+
+ return NETDEV_TX_OK;
+}
+
+/* ========== Setting up sysfs interface and module parameters ========== */
+
+#define GRCAN_NOT_BOOL(unsigned_val) ((unsigned_val) > 1)
+
+#define GRCAN_MODULE_PARAM(name, mtype, valcheckf, desc) \
+ static void grcan_sanitize_##name(struct platform_device *pd) \
+ { \
+ struct grcan_device_config grcan_default_config \
+ = GRCAN_DEFAULT_DEVICE_CONFIG; \
+ if (valcheckf(grcan_module_config.name)) { \
+ dev_err(&pd->dev, \
+ "Invalid module parameter value for " \
+ #name " - setting default\n"); \
+ grcan_module_config.name = \
+ grcan_default_config.name; \
+ } \
+ } \
+ module_param_named(name, grcan_module_config.name, \
+ mtype, S_IRUGO); \
+ MODULE_PARM_DESC(name, desc)
+
+#define GRCAN_CONFIG_ATTR(name, desc) \
+ static ssize_t grcan_store_##name(struct device *sdev, \
+ struct device_attribute *att, \
+ const char *buf, \
+ size_t count) \
+ { \
+ struct net_device *dev = to_net_dev(sdev); \
+ struct grcan_priv *priv = netdev_priv(dev); \
+ u8 val; \
+ int ret; \
+ if (dev->flags & IFF_UP) \
+ return -EBUSY; \
+ ret = kstrtou8(buf, 0, &val); \
+ if (ret < 0 || val > 1) \
+ return -EINVAL; \
+ priv->config.name = val; \
+ return count; \
+ } \
+ static ssize_t grcan_show_##name(struct device *sdev, \
+ struct device_attribute *att, \
+ char *buf) \
+ { \
+ struct net_device *dev = to_net_dev(sdev); \
+ struct grcan_priv *priv = netdev_priv(dev); \
+ return sprintf(buf, "%d\n", priv->config.name); \
+ } \
+ static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \
+ grcan_show_##name, \
+ grcan_store_##name); \
+ GRCAN_MODULE_PARAM(name, ushort, GRCAN_NOT_BOOL, desc)
+
+/* The following configuration options are made available both via module
+ * parameters and writable sysfs files. See the chapter about GRCAN in the
+ * documentation for the GRLIB VHDL library for further details.
+ */
+GRCAN_CONFIG_ATTR(enable0,
+ "Configuration of physical interface 0. Determines\n" \
+ "the \"Enable 0\" bit of the configuration register.\n" \
+ "Format: 0 | 1\nDefault: 0\n");
+
+GRCAN_CONFIG_ATTR(enable1,
+ "Configuration of physical interface 1. Determines\n" \
+ "the \"Enable 1\" bit of the configuration register.\n" \
+ "Format: 0 | 1\nDefault: 0\n");
+
+GRCAN_CONFIG_ATTR(select,
+ "Select which physical interface to use.\n" \
+ "Format: 0 | 1\nDefault: 0\n");
+
+/* The tx and rx buffer size configuration options are only available via module
+ * parameters.
+ */
+GRCAN_MODULE_PARAM(txsize, uint, GRCAN_INVALID_BUFFER_SIZE,
+ "Sets the size of the tx buffer.\n" \
+ "Format: <unsigned int> where (txsize & ~0x1fffc0) == 0\n" \
+ "Default: 1024\n");
+GRCAN_MODULE_PARAM(rxsize, uint, GRCAN_INVALID_BUFFER_SIZE,
+ "Sets the size of the rx buffer.\n" \
+ "Format: <unsigned int> where (size & ~0x1fffc0) == 0\n" \
+ "Default: 1024\n");
+
+/* Function that makes sure that configuration done using
+ * module parameters are set to valid values
+ */
+static void grcan_sanitize_module_config(struct platform_device *ofdev)
+{
+ grcan_sanitize_enable0(ofdev);
+ grcan_sanitize_enable1(ofdev);
+ grcan_sanitize_select(ofdev);
+ grcan_sanitize_txsize(ofdev);
+ grcan_sanitize_rxsize(ofdev);
+}
+
+static const struct attribute *const sysfs_grcan_attrs[] = {
+ /* Config attrs */
+ &dev_attr_enable0.attr,
+ &dev_attr_enable1.attr,
+ &dev_attr_select.attr,
+ NULL,
+};
+
+static const struct attribute_group sysfs_grcan_group = {
+ .name = "grcan",
+ .attrs = (struct attribute **)sysfs_grcan_attrs,
+};
+
+/* ========== Setting up the driver ========== */
+
+static const struct net_device_ops grcan_netdev_ops = {
+ .ndo_open = grcan_open,
+ .ndo_stop = grcan_close,
+ .ndo_start_xmit = grcan_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static int grcan_setup_netdev(struct platform_device *ofdev,
+ void __iomem *base,
+ int irq, u32 ambafreq, bool txbug)
+{
+ struct net_device *dev;
+ struct grcan_priv *priv;
+ struct grcan_registers __iomem *regs;
+ int err;
+
+ dev = alloc_candev(sizeof(struct grcan_priv), 0);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->irq = irq;
+ dev->flags |= IFF_ECHO;
+ dev->netdev_ops = &grcan_netdev_ops;
+ dev->sysfs_groups[0] = &sysfs_grcan_group;
+
+ priv = netdev_priv(dev);
+ memcpy(&priv->config, &grcan_module_config,
+ sizeof(struct grcan_device_config));
+ priv->dev = dev;
+ priv->regs = base;
+ priv->can.bittiming_const = &grcan_bittiming_const;
+ priv->can.do_set_bittiming = grcan_set_bittiming;
+ priv->can.do_set_mode = grcan_set_mode;
+ priv->can.do_get_berr_counter = grcan_get_berr_counter;
+ priv->can.clock.freq = ambafreq;
+ priv->can.ctrlmode_supported =
+ CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
+ priv->need_txbug_workaround = txbug;
+
+ /* Discover if triple sampling is supported by hardware */
+ regs = priv->regs;
+ grcan_set_bits(&regs->ctrl, GRCAN_CTRL_RESET);
+ grcan_set_bits(&regs->conf, GRCAN_CONF_SAM);
+ if (grcan_read_bits(&regs->conf, GRCAN_CONF_SAM)) {
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ dev_dbg(&ofdev->dev, "Hardware supports triple-sampling\n");
+ }
+
+ spin_lock_init(&priv->lock);
+
+ if (priv->need_txbug_workaround) {
+ init_timer(&priv->rr_timer);
+ priv->rr_timer.function = grcan_running_reset;
+ priv->rr_timer.data = (unsigned long)dev;
+
+ init_timer(&priv->hang_timer);
+ priv->hang_timer.function = grcan_initiate_running_reset;
+ priv->hang_timer.data = (unsigned long)dev;
+ }
+
+ netif_napi_add(dev, &priv->napi, grcan_poll, GRCAN_NAPI_WEIGHT);
+
+ SET_NETDEV_DEV(dev, &ofdev->dev);
+ dev_info(&ofdev->dev, "regs=0x%p, irq=%d, clock=%d\n",
+ priv->regs, dev->irq, priv->can.clock.freq);
+
+ err = register_candev(dev);
+ if (err)
+ goto exit_free_candev;
+
+ platform_set_drvdata(ofdev, dev);
+
+ /* Reset device to allow bit-timing to be set. No need to call
+ * grcan_reset at this stage. That is done in grcan_open.
+ */
+ grcan_write_reg(&regs->ctrl, GRCAN_CTRL_RESET);
+
+ return 0;
+exit_free_candev:
+ free_candev(dev);
+ return err;
+}
+
+static int grcan_probe(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ struct resource *res;
+ u32 sysid, ambafreq;
+ int irq, err;
+ void __iomem *base;
+ bool txbug = true;
+
+ /* Compare GRLIB version number with the first that does not
+ * have the tx bug (see start_xmit)
+ */
+ err = of_property_read_u32(np, "systemid", &sysid);
+ if (!err && ((sysid & GRLIB_VERSION_MASK)
+ >= GRCAN_TXBUG_SAFE_GRLIB_VERSION))
+ txbug = false;
+
+ err = of_property_read_u32(np, "freq", &ambafreq);
+ if (err) {
+ dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n");
+ goto exit_error;
+ }
+
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(base)) {
+ err = PTR_ERR(base);
+ goto exit_error;
+ }
+
+ irq = irq_of_parse_and_map(np, GRCAN_IRQIX_IRQ);
+ if (!irq) {
+ dev_err(&ofdev->dev, "no irq found\n");
+ err = -ENODEV;
+ goto exit_error;
+ }
+
+ grcan_sanitize_module_config(ofdev);
+
+ err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug);
+ if (err)
+ goto exit_dispose_irq;
+
+ return 0;
+
+exit_dispose_irq:
+ irq_dispose_mapping(irq);
+exit_error:
+ dev_err(&ofdev->dev,
+ "%s socket CAN driver initialization failed with error %d\n",
+ DRV_NAME, err);
+ return err;
+}
+
+static int grcan_remove(struct platform_device *ofdev)
+{
+ struct net_device *dev = platform_get_drvdata(ofdev);
+ struct grcan_priv *priv = netdev_priv(dev);
+
+ unregister_candev(dev); /* Will in turn call grcan_close */
+
+ irq_dispose_mapping(dev->irq);
+ netif_napi_del(&priv->napi);
+ free_candev(dev);
+
+ return 0;
+}
+
+static struct of_device_id grcan_match[] = {
+ {.name = "GAISLER_GRCAN"},
+ {.name = "01_03d"},
+ {.name = "GAISLER_GRHCAN"},
+ {.name = "01_034"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, grcan_match);
+
+static struct platform_driver grcan_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = grcan_match,
+ },
+ .probe = grcan_probe,
+ .remove = grcan_remove,
+};
+
+module_platform_driver(grcan_driver);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB.");
+MODULE_DESCRIPTION("Socket CAN driver for Aeroflex Gaisler GRCAN");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 7edadee487b..2382c04dc78 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -19,6 +18,7 @@
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
+#include <linux/can/skb.h>
#include <linux/can/error.h>
#include <linux/mfd/janz.h>
@@ -198,9 +198,6 @@ struct ican3_dev {
struct net_device *ndev;
struct napi_struct napi;
- /* Device for printing */
- struct device *dev;
-
/* module number */
unsigned int num;
@@ -295,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
xord = locl ^ peer;
if ((xord & MSYNC_RB_MASK) == 0x00) {
- dev_dbg(mod->dev, "no mbox for reading\n");
+ netdev_dbg(mod->ndev, "no mbox for reading\n");
return -ENOMEM;
}
@@ -340,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
xord = locl ^ peer;
if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) {
- dev_err(mod->dev, "no mbox for writing\n");
+ netdev_err(mod->ndev, "no mbox for writing\n");
return -ENOMEM;
}
@@ -365,7 +362,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
* ICAN3 "new-style" Host Interface Setup
*/
-static void __devinit ican3_init_new_host_interface(struct ican3_dev *mod)
+static void ican3_init_new_host_interface(struct ican3_dev *mod)
{
struct ican3_new_desc desc;
unsigned long flags;
@@ -444,7 +441,7 @@ static void __devinit ican3_init_new_host_interface(struct ican3_dev *mod)
* ICAN3 Fast Host Interface Setup
*/
-static void __devinit ican3_init_fast_host_interface(struct ican3_dev *mod)
+static void ican3_init_fast_host_interface(struct ican3_dev *mod)
{
struct ican3_fast_desc desc;
unsigned long flags;
@@ -542,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
memcpy_fromio(&desc, desc_addr, sizeof(desc));
if (!(desc.control & DESC_VALID)) {
- dev_dbg(mod->dev, "%s: no free buffers\n", __func__);
+ netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__);
return -ENOMEM;
}
@@ -573,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
memcpy_fromio(&desc, desc_addr, sizeof(desc));
if (!(desc.control & DESC_VALID)) {
- dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__);
+ netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__);
return -ENOMEM;
}
@@ -631,7 +628,7 @@ static int ican3_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
* Quick Pre-constructed Messages
*/
-static int __devinit ican3_msg_connect(struct ican3_dev *mod)
+static int ican3_msg_connect(struct ican3_dev *mod)
{
struct ican3_msg msg;
@@ -642,7 +639,7 @@ static int __devinit ican3_msg_connect(struct ican3_dev *mod)
return ican3_send_msg(mod, &msg);
}
-static int __devexit ican3_msg_disconnect(struct ican3_dev *mod)
+static int ican3_msg_disconnect(struct ican3_dev *mod)
{
struct ican3_msg msg;
@@ -653,7 +650,7 @@ static int __devexit ican3_msg_disconnect(struct ican3_dev *mod)
return ican3_send_msg(mod, &msg);
}
-static int __devinit ican3_msg_newhostif(struct ican3_dev *mod)
+static int ican3_msg_newhostif(struct ican3_dev *mod)
{
struct ican3_msg msg;
int ret;
@@ -674,7 +671,7 @@ static int __devinit ican3_msg_newhostif(struct ican3_dev *mod)
return 0;
}
-static int __devinit ican3_msg_fasthostif(struct ican3_dev *mod)
+static int ican3_msg_fasthostif(struct ican3_dev *mod)
{
struct ican3_msg msg;
unsigned int addr;
@@ -707,7 +704,7 @@ static int __devinit ican3_msg_fasthostif(struct ican3_dev *mod)
* Setup the CAN filter to either accept or reject all
* messages from the CAN bus.
*/
-static int __devinit ican3_set_id_filter(struct ican3_dev *mod, bool accept)
+static int ican3_set_id_filter(struct ican3_dev *mod, bool accept)
{
struct ican3_msg msg;
int ret;
@@ -883,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod,
*/
static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg)
{
- dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data);
+ netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data);
}
static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
@@ -899,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
* error frame for userspace
*/
if (msg->spec == MSG_MSGLOST) {
- dev_err(mod->dev, "lost %d control messages\n", msg->data[0]);
+ netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]);
return;
}
@@ -939,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
/* we can only handle the SJA1000 part */
if (msg->data[1] != CEVTIND_CHIP_SJA1000) {
- dev_err(mod->dev, "unable to handle errors on non-SJA1000\n");
+ netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n");
return -ENODEV;
}
/* check the message length for sanity */
if (le16_to_cpu(msg->len) < 6) {
- dev_err(mod->dev, "error message too short\n");
+ netdev_err(mod->ndev, "error message too short\n");
return -EINVAL;
}
@@ -967,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
*/
if (isrc == CEVTIND_BEI) {
int ret;
- dev_dbg(mod->dev, "bus error interrupt\n");
+ netdev_dbg(mod->ndev, "bus error interrupt\n");
/* TX error */
if (!(ecc & ECC_DIR)) {
@@ -983,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
*/
ret = ican3_set_buserror(mod, 1);
if (ret) {
- dev_err(mod->dev, "unable to re-enable bus-error\n");
+ netdev_err(mod->ndev, "unable to re-enable bus-error\n");
return ret;
}
@@ -998,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
/* data overrun interrupt */
if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) {
- dev_dbg(mod->dev, "data overrun interrupt\n");
+ netdev_dbg(mod->ndev, "data overrun interrupt\n");
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
@@ -1007,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
/* error warning + passive interrupt */
if (isrc == CEVTIND_EI) {
- dev_dbg(mod->dev, "error warning + passive interrupt\n");
+ netdev_dbg(mod->ndev, "error warning + passive interrupt\n");
if (status & SR_BS) {
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
@@ -1088,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
complete(&mod->termination_comp);
break;
default:
- dev_err(mod->dev, "received an unknown inquiry response\n");
+ netdev_err(mod->ndev, "received an unknown inquiry response\n");
break;
}
}
@@ -1096,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
static void ican3_handle_unknown_message(struct ican3_dev *mod,
struct ican3_msg *msg)
{
- dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n",
+ netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n",
msg->spec, le16_to_cpu(msg->len));
}
@@ -1105,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod,
*/
static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
{
- dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
+ netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
mod->num, msg->spec, le16_to_cpu(msg->len));
switch (msg->spec) {
@@ -1134,20 +1131,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
*/
static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
{
- struct sock *srcsk = skb->sk;
-
- if (atomic_read(&skb->users) != 1) {
- struct sk_buff *old_skb = skb;
-
- skb = skb_clone(old_skb, GFP_ATOMIC);
- kfree_skb(old_skb);
- if (!skb)
- return;
- } else {
- skb_orphan(skb);
- }
-
- skb->sk = srcsk;
+ skb = can_create_echo_skb(skb);
+ if (!skb)
+ return;
/* save this skb for tx interrupt echo handling */
skb_queue_tail(&mod->echoq, skb);
@@ -1323,7 +1309,7 @@ static int ican3_napi(struct napi_struct *napi, int budget)
/* process all communication messages */
while (true) {
- struct ican3_msg msg;
+ struct ican3_msg uninitialized_var(msg);
ret = ican3_recv_msg(mod, &msg);
if (ret)
break;
@@ -1417,11 +1403,11 @@ static int ican3_reset_module(struct ican3_dev *mod)
msleep(10);
} while (time_before(jiffies, start + HZ / 4));
- dev_err(mod->dev, "failed to reset CAN module\n");
+ netdev_err(mod->ndev, "failed to reset CAN module\n");
return -ETIMEDOUT;
}
-static void __devexit ican3_shutdown_module(struct ican3_dev *mod)
+static void ican3_shutdown_module(struct ican3_dev *mod)
{
ican3_msg_disconnect(mod);
ican3_reset_module(mod);
@@ -1430,13 +1416,13 @@ static void __devexit ican3_shutdown_module(struct ican3_dev *mod)
/*
* Startup an ICAN module, bringing it into fast mode
*/
-static int __devinit ican3_startup_module(struct ican3_dev *mod)
+static int ican3_startup_module(struct ican3_dev *mod)
{
int ret;
ret = ican3_reset_module(mod);
if (ret) {
- dev_err(mod->dev, "unable to reset module\n");
+ netdev_err(mod->ndev, "unable to reset module\n");
return ret;
}
@@ -1445,41 +1431,41 @@ static int __devinit ican3_startup_module(struct ican3_dev *mod)
ret = ican3_msg_connect(mod);
if (ret) {
- dev_err(mod->dev, "unable to connect to module\n");
+ netdev_err(mod->ndev, "unable to connect to module\n");
return ret;
}
ican3_init_new_host_interface(mod);
ret = ican3_msg_newhostif(mod);
if (ret) {
- dev_err(mod->dev, "unable to switch to new-style interface\n");
+ netdev_err(mod->ndev, "unable to switch to new-style interface\n");
return ret;
}
/* default to "termination on" */
ret = ican3_set_termination(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to enable termination\n");
+ netdev_err(mod->ndev, "unable to enable termination\n");
return ret;
}
/* default to "bus errors enabled" */
ret = ican3_set_buserror(mod, 1);
if (ret) {
- dev_err(mod->dev, "unable to set bus-error\n");
+ netdev_err(mod->ndev, "unable to set bus-error\n");
return ret;
}
ican3_init_fast_host_interface(mod);
ret = ican3_msg_fasthostif(mod);
if (ret) {
- dev_err(mod->dev, "unable to switch to fast host interface\n");
+ netdev_err(mod->ndev, "unable to switch to fast host interface\n");
return ret;
}
ret = ican3_set_id_filter(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to set acceptance filter\n");
+ netdev_err(mod->ndev, "unable to set acceptance filter\n");
return ret;
}
@@ -1498,14 +1484,14 @@ static int ican3_open(struct net_device *ndev)
/* open the CAN layer */
ret = open_candev(ndev);
if (ret) {
- dev_err(mod->dev, "unable to start CAN layer\n");
+ netdev_err(mod->ndev, "unable to start CAN layer\n");
return ret;
}
/* bring the bus online */
ret = ican3_set_bus_state(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to set bus-on\n");
+ netdev_err(mod->ndev, "unable to set bus-on\n");
close_candev(ndev);
return ret;
}
@@ -1529,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev)
/* bring the bus offline, stop receiving packets */
ret = ican3_set_bus_state(mod, false);
if (ret) {
- dev_err(mod->dev, "unable to set bus-off\n");
+ netdev_err(mod->ndev, "unable to set bus-off\n");
return ret;
}
@@ -1556,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
/* check that we can actually transmit */
if (!ican3_txok(mod)) {
- dev_err(mod->dev, "BUG: no free descriptors\n");
+ netdev_err(mod->ndev, "BUG: no free descriptors\n");
spin_unlock_irqrestore(&mod->lock, flags);
return NETDEV_TX_BUSY;
}
@@ -1608,6 +1594,7 @@ static const struct net_device_ops ican3_netdev_ops = {
.ndo_open = ican3_open,
.ndo_stop = ican3_stop,
.ndo_start_xmit = ican3_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
/*
@@ -1668,7 +1655,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
/* bring the bus online */
ret = ican3_set_bus_state(mod, true);
if (ret) {
- dev_err(mod->dev, "unable to set bus-on\n");
+ netdev_err(ndev, "unable to set bus-on\n");
return ret;
}
@@ -1692,8 +1679,8 @@ static int ican3_get_berr_counter(const struct net_device *ndev,
return ret;
ret = wait_for_completion_timeout(&mod->buserror_comp, HZ);
- if (ret <= 0) {
- dev_info(mod->dev, "%s timed out\n", __func__);
+ if (ret == 0) {
+ netdev_info(mod->ndev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -1718,8 +1705,8 @@ static ssize_t ican3_sysfs_show_term(struct device *dev,
return ret;
ret = wait_for_completion_timeout(&mod->termination_comp, HZ);
- if (ret <= 0) {
- dev_info(mod->dev, "%s timed out\n", __func__);
+ if (ret == 0) {
+ netdev_info(mod->ndev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -1734,7 +1721,7 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
unsigned long enable;
int ret;
- if (strict_strtoul(buf, 0, &enable))
+ if (kstrtoul(buf, 0, &enable))
return -EINVAL;
ret = ican3_set_termination(mod, enable);
@@ -1760,7 +1747,7 @@ static struct attribute_group ican3_sysfs_attr_group = {
* PCI Subsystem
*/
-static int __devinit ican3_probe(struct platform_device *pdev)
+static int ican3_probe(struct platform_device *pdev)
{
struct janz_platform_data *pdata;
struct net_device *ndev;
@@ -1769,7 +1756,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
struct device *dev;
int ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata)
return -ENXIO;
@@ -1789,7 +1776,6 @@ static int __devinit ican3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
mod = netdev_priv(ndev);
mod->ndev = ndev;
- mod->dev = &pdev->dev;
mod->num = pdata->modno;
netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS);
skb_queue_head_init(&mod->echoq);
@@ -1898,7 +1884,7 @@ out_return:
return ret;
}
-static int __devexit ican3_remove(struct platform_device *pdev)
+static int ican3_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ican3_dev *mod = netdev_priv(ndev);
@@ -1927,7 +1913,7 @@ static struct platform_driver ican3_driver = {
.owner = THIS_MODULE,
},
.probe = ican3_probe,
- .remove = __devexit_p(ican3_remove),
+ .remove = ican3_remove,
};
module_platform_driver(ican3_driver);
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c
new file mode 100644
index 00000000000..ab7f1b01be4
--- /dev/null
+++ b/drivers/net/can/led.c
@@ -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);
+}
diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig
index d38706958af..81c71171949 100644
--- a/drivers/net/can/mscan/Kconfig
+++ b/drivers/net/can/mscan/Kconfig
@@ -1,5 +1,5 @@
config CAN_MSCAN
- depends on CAN_DEV && (PPC || M68K)
+ depends on PPC
tristate "Support for Freescale MSCAN based chips"
---help---
The Motorola Scalable Controller Area Network (MSCAN) definition
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 799c354083c..44725296f72 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -16,8 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -40,17 +39,17 @@ 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 __devinitdata mpc52xx_cdm_ids[] = {
+static struct of_device_id mpc52xx_cdm_ids[] = {
{ .compatible = "fsl,mpc5200-cdm", },
{}
};
-static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev,
- const char *clock_name,
- int *mscan_clksrc)
+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;
@@ -101,154 +100,190 @@ static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev,
return freq;
}
#else /* !CONFIG_PPC_MPC52xx */
-static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev,
- const char *clock_name,
- int *mscan_clksrc)
+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
-struct mpc512x_clockctl {
- u32 spmr; /* System PLL Mode Reg */
- u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
- u32 scfr1; /* System Clk Freq Reg 1 */
- u32 scfr2; /* System Clk Freq Reg 2 */
- u32 reserved;
- u32 bcr; /* Bread Crumb Reg */
- u32 pccr[12]; /* PSC Clk Ctrl Reg 0-11 */
- u32 spccr; /* SPDIF Clk Ctrl Reg */
- u32 cccr; /* CFM Clk Ctrl Reg */
- u32 dccr; /* DIU Clk Cnfg Reg */
- u32 mccr[4]; /* MSCAN Clk Ctrl Reg 1-3 */
-};
-
-static struct of_device_id __devinitdata mpc512x_clock_ids[] = {
- { .compatible = "fsl,mpc5121-clock", },
- {}
-};
-
-static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
- const char *clock_name,
- int *mscan_clksrc)
+static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
+ const char *clock_source, int *mscan_clksrc)
{
- struct mpc512x_clockctl __iomem *clockctl;
- struct device_node *np_clock;
- struct clk *sys_clk, *ref_clk;
- int plen, clockidx, clocksrc = -1;
- u32 sys_freq, val, clockdiv = 1, freq = 0;
- const u32 *pval;
-
- np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
- if (!np_clock) {
- dev_err(&ofdev->dev, "couldn't find clock node\n");
- return 0;
+ 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);
}
- clockctl = of_iomap(np_clock, 0);
- if (!clockctl) {
- dev_err(&ofdev->dev, "couldn't map clock registers\n");
- goto exit_put;
+ 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);
}
- /* Determine the MSCAN device index from the physical address */
- pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
- BUG_ON(!pval || plen < sizeof(*pval));
- clockidx = (*pval & 0x80) ? 1 : 0;
- if (*pval & 0x2000)
- clockidx += 2;
-
- /*
- * Clock source and divider selection: 3 different clock sources
- * can be selected: "ip", "ref" or "sys". For the latter two, a
- * clock divider can be defined as well. If the clock source is
- * not specified by the device tree, we first try to find an
- * optimal CAN source clock based on the system clock. If that
- * is not posslible, the reference clock will be used.
+ /* 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
*/
- if (clock_name && !strcmp(clock_name, "ip")) {
+ 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;
- freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
- } else {
+ 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;
-
- pval = of_get_property(ofdev->dev.of_node,
- "fsl,mscan-clock-divider", &plen);
- if (pval && plen == sizeof(*pval))
- clockdiv = *pval;
- if (!clockdiv)
- clockdiv = 1;
-
- if (!clock_name || !strcmp(clock_name, "sys")) {
- sys_clk = clk_get(&ofdev->dev, "sys_clk");
- if (IS_ERR(sys_clk)) {
- dev_err(&ofdev->dev, "couldn't get sys_clk\n");
- goto exit_unmap;
- }
- /* Get and round up/down sys clock rate */
- sys_freq = 1000000 *
- ((clk_get_rate(sys_clk) + 499999) / 1000000);
-
- if (!clock_name) {
- /* A multiple of 16 MHz would be optimal */
- if ((sys_freq % 16000000) == 0) {
- clocksrc = 0;
- clockdiv = sys_freq / 16000000;
- freq = sys_freq / clockdiv;
- }
- } else {
- clocksrc = 0;
- freq = sys_freq / clockdiv;
- }
- }
-
- if (clocksrc < 0) {
- ref_clk = clk_get(&ofdev->dev, "ref_clk");
- if (IS_ERR(ref_clk)) {
- dev_err(&ofdev->dev, "couldn't get ref_clk\n");
- goto exit_unmap;
- }
- clocksrc = 1;
- freq = clk_get_rate(ref_clk) / clockdiv;
- }
+ dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+ *mscan_clksrc, freq_calc);
+ break;
+ default:
+ goto err_invalid;
}
- /* Disable clock */
- out_be32(&clockctl->mccr[clockidx], 0x0);
- if (clocksrc >= 0) {
- /* Set source and divider */
- val = (clocksrc << 14) | ((clockdiv - 1) << 17);
- out_be32(&clockctl->mccr[clockidx], val);
- /* Enable clock */
- out_be32(&clockctl->mccr[clockidx], val | 0x10000);
- }
+ /* 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;
- /* Enable MSCAN clock domain */
- val = in_be32(&clockctl->sccr[1]);
- if (!(val & (1 << 25)))
- out_be32(&clockctl->sccr[1], val | (1 << 25));
+err_notavail:
+ dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");
+ /* clock source rate could not get determined */
+ return 0;
- dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
- *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
- clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
+err_notavail_ipg:
+ dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");
+ /* clock source rate could not get determined */
+ return 0;
+}
-exit_unmap:
- iounmap(clockctl);
-exit_put:
- of_node_put(np_clock);
- return freq;
+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 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
- const char *clock_name,
- int *mscan_clksrc)
+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 __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
+static int mpc5xxx_can_probe(struct platform_device *ofdev)
{
const struct of_device_id *match;
const struct mpc5xxx_can_data *data;
@@ -281,6 +316,8 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
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;
@@ -297,8 +334,6 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
goto exit_free_mscan;
}
- SET_NETDEV_DEV(dev, &ofdev->dev);
-
err = register_mscandev(dev, mscan_clksrc);
if (err) {
dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
@@ -306,8 +341,6 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev)
goto exit_free_mscan;
}
- dev_set_drvdata(&ofdev->dev, dev);
-
dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
priv->reg_base, dev->irq, priv->can.clock.freq);
@@ -323,14 +356,19 @@ exit_unmap_mem:
return err;
}
-static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev)
+static int mpc5xxx_can_remove(struct platform_device *ofdev)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ 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);
- dev_set_drvdata(&ofdev->dev, NULL);
+ 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);
@@ -342,7 +380,7 @@ static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev)
static struct mscan_regs saved_regs;
static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ 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;
@@ -353,7 +391,7 @@ static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state
static int mpc5xxx_can_resume(struct platform_device *ofdev)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ 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;
@@ -380,22 +418,25 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
}
#endif
-static const struct mpc5xxx_can_data __devinitconst mpc5200_can_data = {
+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 __devinitconst mpc5121_can_data = {
+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 __devinitconst mpc5xxx_can_table[] = {
+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 = {
@@ -404,7 +445,7 @@ static struct platform_driver mpc5xxx_can_driver = {
.of_match_table = mpc5xxx_can_table,
},
.probe = mpc5xxx_can_probe,
- .remove = __devexit_p(mpc5xxx_can_remove),
+ .remove = mpc5xxx_can_remove,
#ifdef CONFIG_PM
.suspend = mpc5xxx_can_suspend,
.resume = mpc5xxx_can_resume,
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 2b104d5f422..e0c9be5e2ab 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -16,8 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -517,12 +516,8 @@ static irqreturn_t mscan_isr(int irq, void *dev_id)
static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
{
- struct mscan_priv *priv = netdev_priv(dev);
int ret = 0;
- if (!priv->open_time)
- return -EINVAL;
-
switch (mode) {
case CAN_MODE_START:
ret = mscan_restart(dev);
@@ -577,10 +572,21 @@ static int mscan_open(struct net_device *dev)
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)
- return ret;
+ goto exit_dis_can_clock;
napi_enable(&priv->napi);
@@ -590,8 +596,6 @@ static int mscan_open(struct net_device *dev)
goto exit_napi_disable;
}
- priv->open_time = jiffies;
-
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
setbits8(&regs->canctl1, MSCAN_LISTEN);
else
@@ -606,11 +610,17 @@ static int mscan_open(struct net_device *dev)
return 0;
exit_free_irq:
- priv->open_time = 0;
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;
}
@@ -627,15 +637,20 @@ static int mscan_close(struct net_device *dev)
mscan_set_mode(dev, MSCAN_INIT_MODE);
close_candev(dev);
free_irq(dev->irq, dev);
- priv->open_time = 0;
+
+ 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_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)
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index b43e9f5d326..ad8e08f9c49 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -14,13 +14,13 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 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 */
@@ -281,9 +281,10 @@ struct tx_queue_entry {
struct mscan_priv {
struct can_priv can; /* must be the first member */
unsigned int type; /* MSCAN type variants */
- long open_time;
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;
@@ -295,8 +296,8 @@ struct mscan_priv {
struct napi_struct napi;
};
-extern struct net_device *alloc_mscandev(void);
-extern int register_mscandev(struct net_device *dev, int mscan_clksrc);
-extern void unregister_mscandev(struct net_device *dev);
+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__ */
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index 48b3d62b34c..6472562efed 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -12,8 +12,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
@@ -22,7 +21,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -560,7 +558,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
stats->rx_errors++;
break;
case PCH_CRC_ERR:
- cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
CAN_ERR_PROT_LOC_CRC_DEL;
priv->can.can_stats.bus_error++;
stats->rx_errors++;
@@ -952,9 +950,10 @@ static const struct net_device_ops pch_can_netdev_ops = {
.ndo_open = pch_can_open,
.ndo_stop = pch_close,
.ndo_start_xmit = pch_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
-static void __devexit pch_can_remove(struct pci_dev *pdev)
+static void pch_can_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
struct pch_can_priv *priv = netdev_priv(ndev);
@@ -964,7 +963,6 @@ static void __devexit pch_can_remove(struct pci_dev *pdev)
pci_disable_msi(priv->dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
pch_can_reset(priv);
pci_iounmap(pdev, priv->regs);
free_candev(priv->ndev);
@@ -1178,7 +1176,7 @@ static int pch_can_get_berr_counter(const struct net_device *dev,
return 0;
}
-static int __devinit pch_can_probe(struct pci_dev *pdev,
+static int pch_can_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct net_device *ndev;
@@ -1269,7 +1267,7 @@ static struct pci_driver pch_can_pci_driver = {
.name = "pch_can",
.id_table = pch_pci_tbl,
.probe = pch_can_probe,
- .remove = __devexit_p(pch_can_remove),
+ .remove = pch_can_remove,
.suspend = pch_can_suspend,
.resume = pch_can_resume,
};
diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c
new file mode 100644
index 00000000000..5268d216ecf
--- /dev/null
+++ b/drivers/net/can/rcar_can.c
@@ -0,0 +1,876 @@
+/* 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>
+
+#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;
+ 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, "clk_prepare_enable() failed, error %d\n",
+ err);
+ goto out;
+ }
+ err = open_candev(ndev);
+ if (err) {
+ netdev_err(ndev, "open_candev() failed, error %d\n", err);
+ goto out_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_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->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,
+};
+
+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 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;
+ int err = -ENODEV;
+ int irq;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data provided!\n");
+ goto fail;
+ }
+
+ 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, NULL);
+ if (IS_ERR(priv->clk)) {
+ err = PTR_ERR(priv->clk);
+ dev_err(&pdev->dev, "cannot get 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 = pdata->clock_select;
+ priv->can.clock.freq = clk_get_rate(priv->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 struct platform_driver rcar_can_driver = {
+ .driver = {
+ .name = RCAR_CAN_DRV_NAME,
+ .owner = THIS_MODULE,
+ .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);
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 03df9a8f2bb..1e65cb6c259 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_SJA1000
@@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM
the "platform bus" (Linux abstraction for directly to the
processor attached devices). Which can be found on various
boards from Phytec (http://www.phytec.de) like the PCM027,
- PCM038.
-
-config CAN_SJA1000_OF_PLATFORM
- tristate "Generic OF Platform Bus based SJA1000 driver"
- depends on PPC_OF
- ---help---
- This driver adds support for the SJA1000 chips connected to
- the OpenFirmware "platform bus" found on embedded systems with
- OpenFirmware bindings, e.g. if you have a PowerPC based system
- you may want to enable this option.
+ 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"
@@ -46,6 +39,7 @@ config CAN_EMS_PCI
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
@@ -93,16 +87,17 @@ config CAN_PLX_PCI
- 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).
+ 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
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index b3d05cbfec3..531d5fcc97e 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_CAN_SJA1000) += sja1000.o
obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
-obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 5c6d412bafb..fd13dbf07d9 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -13,8 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -168,12 +167,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
unsigned char res;
/* Make sure SJA1000 is in reset mode */
- priv->write_reg(priv, REG_MOD, 1);
+ priv->write_reg(priv, SJA1000_MOD, 1);
- priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- res = priv->read_reg(priv, REG_CDR);
+ res = priv->read_reg(priv, SJA1000_CDR);
if (res == CDR_PELICAN)
return 1;
@@ -207,7 +206,6 @@ static void ems_pci_del_card(struct pci_dev *pdev)
kfree(card);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
}
static void ems_pci_card_reset(struct ems_pci_card *card)
@@ -220,8 +218,8 @@ static void ems_pci_card_reset(struct ems_pci_card *card)
* Probe PCI device for EMS CAN signature and register each available
* CAN channel to SJA1000 Socket-CAN subsystem.
*/
-static int __devinit ems_pci_add_card(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int ems_pci_add_card(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct net_device *dev;
@@ -238,7 +236,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
/* Allocating card structures to hold addresses, ... */
card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
if (card == NULL) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
@@ -326,6 +323,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
if (card->version == 1)
/* reset int flag of pita */
diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
index 075a5457a19..381de998d2f 100644
--- a/drivers/net/can/sja1000/ems_pcmcia.c
+++ b/drivers/net/can/sja1000/ems_pcmcia.c
@@ -126,11 +126,11 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)
{
/* Make sure SJA1000 is in reset mode */
- ems_pcmcia_write_reg(priv, REG_MOD, 1);
- ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN);
+ 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, REG_CDR) == CDR_PELICAN)
+ if (ems_pcmcia_read_reg(priv, SJA1000_CDR) == CDR_PELICAN)
return 1;
return 0;
@@ -166,8 +166,7 @@ static void ems_pcmcia_del_card(struct pcmcia_device *pdev)
* Probe PCI device for EMS CAN signature and register each available
* CAN channel to SJA1000 Socket-CAN subsystem.
*/
-static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
- unsigned long base)
+static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base)
{
struct sja1000_priv *priv;
struct net_device *dev;
@@ -212,6 +211,7 @@ static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
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;
@@ -256,7 +256,7 @@ failure_cleanup:
/*
* Setup PCMCIA socket and probe for EMS CPC-CARD
*/
-static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev)
+static int ems_pcmcia_probe(struct pcmcia_device *dev)
{
int csval;
@@ -317,15 +317,4 @@ static struct pcmcia_driver ems_pcmcia_driver = {
.remove = ems_pcmcia_remove,
.id_table = ems_pcmcia_tbl,
};
-
-static int __init ems_pcmcia_init(void)
-{
- return pcmcia_register_driver(&ems_pcmcia_driver);
-}
-module_init(ems_pcmcia_init);
-
-static void __exit ems_pcmcia_exit(void)
-{
- pcmcia_unregister_driver(&ems_pcmcia_driver);
-}
-module_exit(ems_pcmcia_exit);
+module_pcmcia_driver(ems_pcmcia_driver);
diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index 23ed6ea4c7c..23b8e1324e2 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -26,8 +26,7 @@
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -159,9 +158,9 @@ static int number_of_sja1000_chip(void __iomem *base_addr)
for (i = 0; i < MAX_NO_OF_CHANNELS; i++) {
/* reset chip */
iowrite8(MOD_RM, base_addr +
- (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+ (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD);
status = ioread8(base_addr +
- (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+ (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD);
/* check reset bit */
if (!(status & MOD_RM))
break;
@@ -271,6 +270,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
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);
@@ -290,8 +290,8 @@ failure:
return err;
}
-static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int kvaser_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
int err;
struct net_device *master_dev = NULL;
@@ -379,7 +379,7 @@ failure:
}
-static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev)
+static void kvaser_pci_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -387,14 +387,13 @@ static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
}
static struct pci_driver kvaser_pci_driver = {
.name = DRV_NAME,
.id_table = kvaser_pci_tbl,
.probe = kvaser_pci_init_one,
- .remove = __devexit_p(kvaser_pci_remove_one),
+ .remove = kvaser_pci_remove_one,
};
module_pci_driver(kvaser_pci_driver);
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index f5b82aeb254..564933ae218 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -30,9 +30,10 @@
#include "sja1000.h"
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+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"
@@ -64,7 +65,11 @@ struct peak_pci_chan {
#define PEAK_PCI_DEVICE_ID 0x0001 /* for PCI/PCIe slot cards */
#define PEAK_PCIEC_DEVICE_ID 0x0002 /* for ExpressCard slot cards */
#define PEAK_PCIE_DEVICE_ID 0x0003 /* for nextgen PCIe slot cards */
-#define PEAK_MPCI_DEVICE_ID 0x0008 /* The miniPCI slot cards */
+#define PEAK_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_PCI_CHAN_MAX 4
@@ -76,6 +81,10 @@ static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = {
{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {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,},
#endif
@@ -330,8 +339,7 @@ static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
*/
static void peak_pciec_start_led_work(struct peak_pciec_card *card)
{
- if (!delayed_work_pending(&card->led_work))
- schedule_delayed_work(&card->led_work, HZ);
+ schedule_delayed_work(&card->led_work, HZ);
}
/*
@@ -394,7 +402,7 @@ static void peak_pciec_write_reg(const struct sja1000_priv *priv,
int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE;
/* sja1000 register changes control the leds state */
- if (port == REG_MOD)
+ if (port == SJA1000_MOD)
switch (val) {
case MOD_RM:
/* Reset Mode: set led on */
@@ -442,11 +450,8 @@ static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
} else {
/* create the bit banging I2C adapter structure */
card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
- if (!card) {
- dev_err(&pdev->dev,
- "failed allocating memory for i2c chip\n");
+ if (!card)
return -ENOMEM;
- }
card->cfg_base = chan->cfg_base;
card->reg_base = priv->reg_base;
@@ -542,12 +547,11 @@ static void peak_pci_post_irq(const struct sja1000_priv *priv)
writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
}
-static int __devinit peak_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+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;
+ struct net_device *dev, *prev_dev;
void __iomem *cfg_base, *reg_base;
u16 sub_sys_id, icr;
int i, err, channels;
@@ -638,6 +642,7 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
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);
@@ -683,11 +688,13 @@ failure_remove_channels:
writew(0x0, cfg_base + PITA_ICR + 2);
chan = NULL;
- for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
- unregister_sja1000dev(dev);
- free_sja1000dev(dev);
+ 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 */
@@ -708,7 +715,7 @@ failure_disable_pci:
return err;
}
-static void __devexit peak_pci_remove(struct pci_dev *pdev)
+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);
@@ -721,10 +728,12 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
/* 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 = chan->prev_dev;
+ dev = prev_dev;
if (!dev) {
/* do that only for first channel */
@@ -740,15 +749,13 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
pci_iounmap(pdev, cfg_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
-
- pci_set_drvdata(pdev, NULL);
}
static struct pci_driver peak_pci_driver = {
.name = DRV_NAME,
.id_table = peak_pci_tbl,
.probe = peak_pci_probe,
- .remove = __devexit_p(peak_pci_remove),
+ .remove = peak_pci_remove,
};
module_pci_driver(peak_pci_driver);
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
index 272a85f32b1..dd56133cc46 100644
--- a/drivers/net/can/sja1000/peak_pcmcia.c
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -196,7 +196,7 @@ static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v)
int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;
/* sja1000 register changes control the leds state */
- if (port == REG_MOD)
+ if (port == SJA1000_MOD)
switch (v) {
case MOD_RM:
/* Reset Mode: set led on */
@@ -509,11 +509,11 @@ static void pcan_free_channels(struct pcan_pccard *card)
static inline int pcan_channel_present(struct sja1000_priv *priv)
{
/* make sure SJA1000 is in reset mode */
- pcan_write_canreg(priv, REG_MOD, 1);
- pcan_write_canreg(priv, REG_CDR, CDR_PELICAN);
+ pcan_write_canreg(priv, SJA1000_MOD, 1);
+ pcan_write_canreg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- if (pcan_read_canreg(priv, REG_CDR) == CDR_PELICAN)
+ if (pcan_read_canreg(priv, SJA1000_CDR) == CDR_PELICAN)
return 1;
return 0;
@@ -550,6 +550,7 @@ static int pcan_add_channels(struct pcan_pccard *card)
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;
@@ -632,7 +633,7 @@ static void pcan_free(struct pcmcia_device *pdev)
/*
* setup PCMCIA socket and probe for PEAK-System PC-CARD
*/
-static int __devinit pcan_probe(struct pcmcia_device *pdev)
+static int pcan_probe(struct pcmcia_device *pdev)
{
struct pcan_pccard *card;
int err;
@@ -660,7 +661,6 @@ static int __devinit pcan_probe(struct pcmcia_device *pdev)
card = kzalloc(sizeof(struct pcan_pccard), GFP_KERNEL);
if (!card) {
- dev_err(&pdev->dev, "couldn't allocate card memory\n");
err = -ENOMEM;
goto probe_err_2;
}
@@ -741,15 +741,4 @@ static struct pcmcia_driver pcan_driver = {
.remove = pcan_remove,
.id_table = pcan_table,
};
-
-static int __init pcan_init(void)
-{
- return pcmcia_register_driver(&pcan_driver);
-}
-module_init(pcan_init);
-
-static void __exit pcan_exit(void)
-{
- pcmcia_unregister_driver(&pcan_driver);
-}
-module_exit(pcan_exit);
+module_pcmcia_driver(pcan_driver);
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index 8bc95982840..ec39b7cb228 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -16,8 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -44,7 +43,9 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
"esd CAN-PCI/CPCI/PCI104/200, "
"esd CAN-PCI/PMC/266, "
"esd CAN-PCIe/2000, "
- "IXXAT PC-I 04/PCI")
+ "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
@@ -122,6 +123,11 @@ struct plx_pci_card {
#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
@@ -131,6 +137,9 @@ struct plx_pci_card {
#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);
@@ -158,7 +167,7 @@ struct plx_pci_card_info {
void (*reset_func)(struct pci_dev *pdev);
};
-static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+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} },
@@ -166,7 +175,7 @@ static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
/* based on PLX9052 */
};
-static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+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} },
@@ -174,7 +183,7 @@ static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
/* based on PLX9052 */
};
-static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = {
+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} },
@@ -182,7 +191,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = {
/* based on PLX9030/9050 */
};
-static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = {
+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} },
@@ -190,7 +199,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = {
/* based on PLX9056 */
};
-static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = {
+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} },
@@ -198,7 +207,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = {
/* based on PEX8311 */
};
-static struct plx_pci_card_info plx_pci_card_info_ixxat __devinitdata = {
+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} },
@@ -206,7 +215,7 @@ static struct plx_pci_card_info plx_pci_card_info_ixxat __devinitdata = {
/* based on PLX9050 */
};
-static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+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} },
@@ -214,7 +223,7 @@ static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
/* based on PLX9052 */
};
-static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+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} },
@@ -222,6 +231,22 @@ static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
/* 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 DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
{
/* Adlink PCI-7841/cPCI-7841 */
@@ -300,6 +325,20 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
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);
@@ -329,20 +368,20 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
*/
if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
REG_CR_BASICCAN_INITIAL &&
- (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
- (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+ (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, REG_CDR, CDR_PELICAN);
+ 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, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
- priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
- priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+ 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;
@@ -458,15 +497,14 @@ static void plx_pci_del_card(struct pci_dev *pdev)
kfree(card);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
}
/*
* Probe PLX90xx based device for the SJA1000 chips and register each
* available CAN channel to SJA1000 Socket-CAN subsystem.
*/
-static int __devinit plx_pci_add_card(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int plx_pci_add_card(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct net_device *dev;
@@ -489,7 +527,6 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
/* Allocate card structures to hold addresses, ... */
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
@@ -550,6 +587,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
priv->cdr = ci->cdr;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
/* Register SJA1000 device */
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 25011dbe1b9..f31499a32d7 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -60,6 +60,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include "sja1000.h"
@@ -90,14 +91,14 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
* the write_reg() operation - especially on SMP systems.
*/
spin_lock_irqsave(&priv->cmdreg_lock, flags);
- priv->write_reg(priv, REG_CMR, val);
- priv->read_reg(priv, REG_SR);
+ 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, REG_MOD) == 0xFF);
+ return (priv->read_reg(priv, SJA1000_MOD) == 0xFF);
}
static int sja1000_probe_chip(struct net_device *dev)
@@ -105,8 +106,7 @@ static int sja1000_probe_chip(struct net_device *dev)
struct sja1000_priv *priv = netdev_priv(dev);
if (priv->reg_base && sja1000_is_absent(priv)) {
- printk(KERN_INFO "%s: probing @0x%lX failed\n",
- DRV_NAME, dev->base_addr);
+ netdev_err(dev, "probing failed\n");
return 0;
}
return -1;
@@ -115,11 +115,11 @@ static int sja1000_probe_chip(struct net_device *dev)
static void set_reset_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- unsigned char status = priv->read_reg(priv, REG_MOD);
+ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i;
/* disable interrupts */
- priv->write_reg(priv, REG_IER, IRQ_OFF);
+ priv->write_reg(priv, SJA1000_IER, IRQ_OFF);
for (i = 0; i < 100; i++) {
/* check reset bit */
@@ -128,9 +128,10 @@ static void set_reset_mode(struct net_device *dev)
return;
}
- priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */
+ /* reset chip */
+ priv->write_reg(priv, SJA1000_MOD, MOD_RM);
udelay(10);
- status = priv->read_reg(priv, REG_MOD);
+ status = priv->read_reg(priv, SJA1000_MOD);
}
netdev_err(dev, "setting SJA1000 into reset mode failed!\n");
@@ -139,7 +140,7 @@ static void set_reset_mode(struct net_device *dev)
static void set_normal_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- unsigned char status = priv->read_reg(priv, REG_MOD);
+ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i;
for (i = 0; i < 100; i++) {
@@ -148,22 +149,22 @@ static void set_normal_mode(struct net_device *dev)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
- priv->write_reg(priv, REG_IER, IRQ_ALL);
+ priv->write_reg(priv, SJA1000_IER, IRQ_ALL);
else
- priv->write_reg(priv, REG_IER,
+ priv->write_reg(priv, SJA1000_IER,
IRQ_ALL & ~IRQ_BEI);
return;
}
/* set chip to normal mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
- priv->write_reg(priv, REG_MOD, MOD_LOM);
+ priv->write_reg(priv, SJA1000_MOD, MOD_LOM);
else
- priv->write_reg(priv, REG_MOD, 0x00);
+ priv->write_reg(priv, SJA1000_MOD, 0x00);
udelay(10);
- status = priv->read_reg(priv, REG_MOD);
+ status = priv->read_reg(priv, SJA1000_MOD);
}
netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
@@ -178,9 +179,9 @@ static void sja1000_start(struct net_device *dev)
set_reset_mode(dev);
/* Clear error counters and error code capture */
- priv->write_reg(priv, REG_TXERR, 0x0);
- priv->write_reg(priv, REG_RXERR, 0x0);
- priv->read_reg(priv, REG_ECC);
+ 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);
@@ -188,11 +189,6 @@ static void sja1000_start(struct net_device *dev)
static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
{
- struct sja1000_priv *priv = netdev_priv(dev);
-
- if (!priv->open_time)
- return -EINVAL;
-
switch (mode) {
case CAN_MODE_START:
sja1000_start(dev);
@@ -221,8 +217,8 @@ static int sja1000_set_bittiming(struct net_device *dev)
netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
- priv->write_reg(priv, REG_BTR0, btr0);
- priv->write_reg(priv, REG_BTR1, btr1);
+ priv->write_reg(priv, SJA1000_BTR0, btr0);
+ priv->write_reg(priv, SJA1000_BTR1, btr1);
return 0;
}
@@ -232,8 +228,8 @@ static int sja1000_get_berr_counter(const struct net_device *dev,
{
struct sja1000_priv *priv = netdev_priv(dev);
- bec->txerr = priv->read_reg(priv, REG_TXERR);
- bec->rxerr = priv->read_reg(priv, REG_RXERR);
+ bec->txerr = priv->read_reg(priv, SJA1000_TXERR);
+ bec->rxerr = priv->read_reg(priv, SJA1000_RXERR);
return 0;
}
@@ -251,20 +247,20 @@ static void chipset_init(struct net_device *dev)
struct sja1000_priv *priv = netdev_priv(dev);
/* set clock divider and output control register */
- priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
/* set acceptance filter (accept all) */
- priv->write_reg(priv, REG_ACCC0, 0x00);
- priv->write_reg(priv, REG_ACCC1, 0x00);
- priv->write_reg(priv, REG_ACCC2, 0x00);
- priv->write_reg(priv, REG_ACCC3, 0x00);
+ priv->write_reg(priv, 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, REG_ACCM0, 0xFF);
- priv->write_reg(priv, REG_ACCM1, 0xFF);
- priv->write_reg(priv, REG_ACCM2, 0xFF);
- priv->write_reg(priv, REG_ACCM3, 0xFF);
+ priv->write_reg(priv, 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, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
+ priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
}
/*
@@ -293,21 +289,21 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
id = cf->can_id;
if (id & CAN_RTR_FLAG)
- fi |= FI_RTR;
+ fi |= SJA1000_FI_RTR;
if (id & CAN_EFF_FLAG) {
- fi |= FI_FF;
- dreg = EFF_BUF;
- priv->write_reg(priv, REG_FI, fi);
- priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
- priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8));
- priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5);
- priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3);
+ 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 = SFF_BUF;
- priv->write_reg(priv, REG_FI, fi);
- priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3);
- priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5);
+ 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++)
@@ -339,25 +335,25 @@ static void sja1000_rx(struct net_device *dev)
if (skb == NULL)
return;
- fi = priv->read_reg(priv, REG_FI);
+ fi = priv->read_reg(priv, SJA1000_FI);
- if (fi & FI_FF) {
+ if (fi & SJA1000_FI_FF) {
/* extended frame format (EFF) */
- dreg = EFF_BUF;
- id = (priv->read_reg(priv, REG_ID1) << (5 + 16))
- | (priv->read_reg(priv, REG_ID2) << (5 + 8))
- | (priv->read_reg(priv, REG_ID3) << 5)
- | (priv->read_reg(priv, REG_ID4) >> 3);
+ 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 = SFF_BUF;
- id = (priv->read_reg(priv, REG_ID1) << 3)
- | (priv->read_reg(priv, REG_ID2) >> 5);
+ 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 & FI_RTR) {
+ if (fi & SJA1000_FI_RTR) {
id |= CAN_RTR_FLAG;
} else {
for (i = 0; i < cf->can_dlc; i++)
@@ -373,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
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)
@@ -416,7 +414,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
priv->can.can_stats.bus_error++;
stats->rx_errors++;
- ecc = priv->read_reg(priv, REG_ECC);
+ ecc = priv->read_reg(priv, SJA1000_ECC);
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -450,7 +448,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (isrc & IRQ_ALI) {
/* arbitration lost interrupt */
netdev_dbg(dev, "arbitration lost interrupt\n");
- alc = priv->read_reg(priv, REG_ALC);
+ alc = priv->read_reg(priv, SJA1000_ALC);
priv->can.can_stats.arbitration_lost++;
stats->tx_errors++;
cf->can_id |= CAN_ERR_LOSTARB;
@@ -459,8 +457,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
state == CAN_STATE_ERROR_PASSIVE)) {
- uint8_t rxerr = priv->read_reg(priv, REG_RXERR);
- uint8_t txerr = priv->read_reg(priv, REG_TXERR);
+ 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++;
@@ -495,19 +493,20 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
uint8_t isrc, status;
int n = 0;
- /* Shared interrupts and IRQ off? */
- if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
- return IRQ_NONE;
-
if (priv->pre_irq)
priv->pre_irq(priv);
- while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
- n++;
- status = priv->read_reg(priv, REG_SR);
+ /* 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))
- return IRQ_NONE;
+ goto out;
if (isrc & IRQ_WUI)
netdev_warn(dev, "wakeup interrupt\n");
@@ -521,20 +520,21 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
} else {
/* transmission complete */
stats->tx_bytes +=
- priv->read_reg(priv, REG_FI) & 0xf;
+ 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, REG_SR);
+ status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller */
if (status == 0xFF && sja1000_is_absent(priv))
- return IRQ_NONE;
+ goto out;
}
}
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
@@ -542,8 +542,9 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
if (sja1000_err(dev, isrc, status))
break;
}
+ n++;
}
-
+out:
if (priv->post_irq)
priv->post_irq(priv);
@@ -579,7 +580,8 @@ static int sja1000_open(struct net_device *dev)
/* init and start chi */
sja1000_start(dev);
- priv->open_time = jiffies;
+
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
netif_start_queue(dev);
@@ -598,7 +600,7 @@ static int sja1000_close(struct net_device *dev)
close_candev(dev);
- priv->open_time = 0;
+ can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
@@ -640,13 +642,16 @@ void free_sja1000dev(struct net_device *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_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;
@@ -656,7 +661,12 @@ int register_sja1000dev(struct net_device *dev)
set_reset_mode(dev);
chipset_init(dev);
- return register_candev(dev);
+ ret = register_candev(dev);
+
+ if (!ret)
+ devm_can_led_init(dev);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(register_sja1000dev);
diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h
index 23fff06875f..9d46398f815 100644
--- a/drivers/net/can/sja1000/sja1000.h
+++ b/drivers/net/can/sja1000/sja1000.h
@@ -54,46 +54,46 @@
#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
-#define REG_MOD 0x00
-#define REG_CMR 0x01
-#define REG_SR 0x02
-#define REG_IR 0x03
-#define REG_IER 0x04
-#define REG_ALC 0x0B
-#define REG_ECC 0x0C
-#define REG_EWL 0x0D
-#define REG_RXERR 0x0E
-#define REG_TXERR 0x0F
-#define REG_ACCC0 0x10
-#define REG_ACCC1 0x11
-#define REG_ACCC2 0x12
-#define REG_ACCC3 0x13
-#define REG_ACCM0 0x14
-#define REG_ACCM1 0x15
-#define REG_ACCM2 0x16
-#define REG_ACCM3 0x17
-#define REG_RMC 0x1D
-#define REG_RBSA 0x1E
+#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 REG_BTR0 0x06
-#define REG_BTR1 0x07
-#define REG_OCR 0x08
-#define REG_CDR 0x1F
+#define SJA1000_BTR0 0x06
+#define SJA1000_BTR1 0x07
+#define SJA1000_OCR 0x08
+#define SJA1000_CDR 0x1F
-#define REG_FI 0x10
-#define SFF_BUF 0x13
-#define EFF_BUF 0x15
+#define SJA1000_FI 0x10
+#define SJA1000_SFF_BUF 0x13
+#define SJA1000_EFF_BUF 0x15
-#define FI_FF 0x80
-#define FI_RTR 0x40
+#define SJA1000_FI_FF 0x80
+#define SJA1000_FI_RTR 0x40
-#define REG_ID1 0x11
-#define REG_ID2 0x12
-#define REG_ID3 0x13
-#define REG_ID4 0x14
+#define SJA1000_ID1 0x11
+#define SJA1000_ID2 0x12
+#define SJA1000_ID3 0x13
+#define SJA1000_ID4 0x14
-#define CAN_RAM 0x20
+#define SJA1000_CAN_RAM 0x20
/* mode register */
#define MOD_RM 0x01
@@ -152,7 +152,6 @@
*/
struct sja1000_priv {
struct can_priv can; /* must be the first member */
- int open_time;
struct sk_buff *echo_skb;
/* the lower-layer is responsible for appropriate locking */
diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c
index 90c5c2dfd2f..014695d7e6a 100644
--- a/drivers/net/can/sja1000/sja1000_isa.c
+++ b/drivers/net/can/sja1000/sja1000_isa.c
@@ -11,8 +11,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -42,11 +41,12 @@ MODULE_LICENSE("GPL v2");
static unsigned long port[MAXDEV];
static unsigned long mem[MAXDEV];
-static int __devinitdata irq[MAXDEV];
-static int __devinitdata clk[MAXDEV];
-static unsigned char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static unsigned char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+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");
@@ -102,22 +102,29 @@ static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
int reg)
{
- unsigned long base = (unsigned long)priv->reg_base;
+ unsigned long flags, base = (unsigned long)priv->reg_base;
+ u8 readval;
+ spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
outb(reg, base);
- return inb(base + 1);
+ 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 base = (unsigned long)priv->reg_base;
+ 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 __devinit sja1000_isa_probe(struct platform_device *pdev)
+static int sja1000_isa_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sja1000_priv *priv;
@@ -170,6 +177,7 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev)
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;
@@ -197,8 +205,9 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev)
else
priv->cdr = CDR_DEFAULT;
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = idx;
err = register_sja1000dev(dev);
if (err) {
@@ -223,14 +232,13 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev)
return err;
}
-static int __devexit sja1000_isa_remove(struct platform_device *pdev)
+static int sja1000_isa_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_sja1000dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
if (mem[idx]) {
iounmap(priv->reg_base);
@@ -248,7 +256,7 @@ static int __devexit sja1000_isa_remove(struct platform_device *pdev)
static struct platform_driver sja1000_isa_driver = {
.probe = sja1000_isa_probe,
- .remove = __devexit_p(sja1000_isa_remove),
+ .remove = sja1000_isa_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
deleted file mode 100644
index f2683eb6a3d..00000000000
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
- *
- * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
- * bus found on embedded PowerPC systems. You need a SJA1000 CAN node
- * definition in your flattened device tree source (DTS) file similar to:
- *
- * can@3,100 {
- * compatible = "nxp,sja1000";
- * reg = <3 0x100 0x80>;
- * interrupts = <2 0>;
- * interrupt-parent = <&mpic>;
- * nxp,external-clock-frequency = <16000000>;
- * };
- *
- * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further
- * information.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/can/dev.h>
-
-#include <linux/of_platform.h>
-#include <asm/prom.h>
-
-#include "sja1000.h"
-
-#define DRV_NAME "sja1000_of_platform"
-
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
-MODULE_LICENSE("GPL v2");
-
-#define SJA1000_OFP_CAN_CLOCK (16000000 / 2)
-
-#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN
-#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF)
-
-static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
-{
- return in_8(priv->reg_base + reg);
-}
-
-static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
- int reg, u8 val)
-{
- out_8(priv->reg_base + reg, val);
-}
-
-static int __devexit sja1000_ofp_remove(struct platform_device *ofdev)
-{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
- struct sja1000_priv *priv = netdev_priv(dev);
- struct device_node *np = ofdev->dev.of_node;
- struct resource res;
-
- dev_set_drvdata(&ofdev->dev, NULL);
-
- unregister_sja1000dev(dev);
- free_sja1000dev(dev);
- iounmap(priv->reg_base);
- irq_dispose_mapping(dev->irq);
-
- of_address_to_resource(np, 0, &res);
- release_mem_region(res.start, resource_size(&res));
-
- return 0;
-}
-
-static int __devinit sja1000_ofp_probe(struct platform_device *ofdev)
-{
- struct device_node *np = ofdev->dev.of_node;
- struct net_device *dev;
- struct sja1000_priv *priv;
- struct resource res;
- const u32 *prop;
- int err, irq, res_size, prop_size;
- void __iomem *base;
-
- err = of_address_to_resource(np, 0, &res);
- if (err) {
- dev_err(&ofdev->dev, "invalid address\n");
- return err;
- }
-
- res_size = resource_size(&res);
-
- if (!request_mem_region(res.start, res_size, DRV_NAME)) {
- dev_err(&ofdev->dev, "couldn't request %pR\n", &res);
- return -EBUSY;
- }
-
- base = ioremap_nocache(res.start, res_size);
- if (!base) {
- dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
- err = -ENOMEM;
- goto exit_release_mem;
- }
-
- irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
- dev_err(&ofdev->dev, "no irq found\n");
- err = -ENODEV;
- goto exit_unmap_mem;
- }
-
- dev = alloc_sja1000dev(0);
- if (!dev) {
- err = -ENOMEM;
- goto exit_dispose_irq;
- }
-
- priv = netdev_priv(dev);
-
- priv->read_reg = sja1000_ofp_read_reg;
- priv->write_reg = sja1000_ofp_write_reg;
-
- prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->can.clock.freq = *prop / 2;
- else
- priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
-
- prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->ocr |= *prop & OCR_MODE_MASK;
- else
- priv->ocr |= OCR_MODE_NORMAL; /* default */
-
- prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
- else
- priv->ocr |= OCR_TX0_PULLDOWN; /* default */
-
- prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
- if (prop && (prop_size == sizeof(u32)) && *prop) {
- u32 divider = priv->can.clock.freq * 2 / *prop;
-
- if (divider > 1)
- priv->cdr |= divider / 2 - 1;
- else
- priv->cdr |= CDR_CLKOUT_MASK;
- } else {
- priv->cdr |= CDR_CLK_OFF; /* default */
- }
-
- prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
- if (!prop)
- priv->cdr |= CDR_CBP; /* default */
-
- priv->irq_flags = IRQF_SHARED;
- priv->reg_base = base;
-
- dev->irq = irq;
-
- dev_info(&ofdev->dev,
- "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
- priv->reg_base, dev->irq, priv->can.clock.freq,
- priv->ocr, priv->cdr);
-
- dev_set_drvdata(&ofdev->dev, dev);
- SET_NETDEV_DEV(dev, &ofdev->dev);
-
- err = register_sja1000dev(dev);
- if (err) {
- dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
- DRV_NAME, err);
- goto exit_free_sja1000;
- }
-
- return 0;
-
-exit_free_sja1000:
- free_sja1000dev(dev);
-exit_dispose_irq:
- irq_dispose_mapping(irq);
-exit_unmap_mem:
- iounmap(base);
-exit_release_mem:
- release_mem_region(res.start, res_size);
-
- return err;
-}
-
-static struct of_device_id __devinitdata sja1000_ofp_table[] = {
- {.compatible = "nxp,sja1000"},
- {},
-};
-MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
-
-static struct platform_driver sja1000_ofp_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .of_match_table = sja1000_ofp_table,
- },
- .probe = sja1000_ofp_probe,
- .remove = __devexit_p(sja1000_ofp_remove),
-};
-
-module_platform_driver(sja1000_ofp_driver);
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index 662c5f7eb0c..95a844a7ee7 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -12,8 +12,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -27,13 +26,18 @@
#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)
@@ -66,59 +70,16 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
iowrite8(val, priv->reg_base + reg * 4);
}
-static int sp_probe(struct platform_device *pdev)
+static void sp_populate(struct sja1000_priv *priv,
+ struct sja1000_platform_data *pdata,
+ unsigned long resource_mem_flags)
{
- int err;
- void __iomem *addr;
- struct net_device *dev;
- struct sja1000_priv *priv;
- struct resource *res_mem, *res_irq;
- struct sja1000_platform_data *pdata;
-
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data provided!\n");
- err = -ENODEV;
- goto exit;
- }
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_mem || !res_irq) {
- err = -ENODEV;
- goto exit;
- }
-
- if (!request_mem_region(res_mem->start, resource_size(res_mem),
- DRV_NAME)) {
- err = -EBUSY;
- goto exit;
- }
-
- addr = ioremap_nocache(res_mem->start, resource_size(res_mem));
- if (!addr) {
- err = -ENOMEM;
- goto exit_release;
- }
-
- dev = alloc_sja1000dev(0);
- if (!dev) {
- err = -ENOMEM;
- goto exit_iounmap;
- }
- priv = netdev_priv(dev);
-
- dev->irq = res_irq->start;
- priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
- if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
- priv->irq_flags |= IRQF_SHARED;
- priv->reg_base = addr;
/* The CAN clock frequency is half the oscillator clock frequency */
priv->can.clock.freq = pdata->osc_freq / 2;
priv->ocr = pdata->ocr;
priv->cdr = pdata->cdr;
- switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+ switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) {
case IORESOURCE_MEM_32BIT:
priv->read_reg = sp_read_reg32;
priv->write_reg = sp_write_reg32;
@@ -133,8 +94,126 @@ static int sp_probe(struct platform_device *pdev)
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;
+ }
- dev_set_drvdata(&pdev->dev, dev);
+ 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);
@@ -150,40 +229,32 @@ static int sp_probe(struct platform_device *pdev)
exit_free:
free_sja1000dev(dev);
- exit_iounmap:
- iounmap(addr);
- exit_release:
- release_mem_region(res_mem->start, resource_size(res_mem));
- exit:
return err;
}
static int sp_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
- struct sja1000_priv *priv = netdev_priv(dev);
- struct resource *res;
+ struct net_device *dev = platform_get_drvdata(pdev);
unregister_sja1000dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
-
- if (priv->reg_base)
- iounmap(priv->reg_base);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
free_sja1000dev(dev);
return 0;
}
+static struct 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,
},
};
diff --git a/drivers/net/can/sja1000/tscan1.c b/drivers/net/can/sja1000/tscan1.c
index 9756099a883..76513dd780c 100644
--- a/drivers/net/can/sja1000/tscan1.c
+++ b/drivers/net/can/sja1000/tscan1.c
@@ -71,7 +71,7 @@ MODULE_LICENSE("GPL");
#define TSCAN1_SJA1000_XTAL 16000000
/* SJA1000 IO base addresses */
-static const unsigned short tscan1_sja1000_addresses[] __devinitconst = {
+static const unsigned short tscan1_sja1000_addresses[] = {
0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320
};
@@ -88,7 +88,7 @@ static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
}
/* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */
-static int __devinit tscan1_probe(struct device *dev, unsigned id)
+static int tscan1_probe(struct device *dev, unsigned id)
{
struct net_device *netdev;
struct sja1000_priv *priv;
@@ -171,7 +171,7 @@ static int __devinit tscan1_probe(struct device *dev, unsigned id)
return -ENXIO;
}
-static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/)
+static int tscan1_remove(struct device *dev, unsigned id /*unused*/)
{
struct net_device *netdev;
struct sja1000_priv *priv;
@@ -197,7 +197,7 @@ static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/)
static struct isa_driver tscan1_isa_driver = {
.probe = tscan1_probe,
- .remove = __devexit_p(tscan1_remove),
+ .remove = tscan1_remove,
.driver = {
.name = "tscan1",
},
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index adc3708d882..ea4d4f1a641 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -18,9 +18,7 @@
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307. You can also get it
- * at http://www.gnu.org/licenses/gpl.html
+ * 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
@@ -54,7 +52,9 @@
#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";
@@ -75,6 +75,10 @@ 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;
@@ -82,6 +86,7 @@ struct slcan {
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 */
@@ -141,50 +146,67 @@ static void slc_bump(struct slcan *sl)
{
struct sk_buff *skb;
struct can_frame cf;
- int i, dlc_pos, tmp;
- unsigned long ultmp;
- char cmd = sl->rbuff[0];
-
- if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
+ 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 (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */
- dlc_pos = 4; /* dlc position tiiid */
- else
- dlc_pos = 9; /* dlc position Tiiiiiiiid */
-
- if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9')))
+ if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
return;
- cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */
+ cf.can_id |= tmpid;
- sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
-
- if (strict_strtoul(sl->rbuff+1, 16, &ultmp))
+ /* get can_dlc from sanitized ASCII value */
+ if (cf.can_dlc >= '0' && cf.can_dlc < '9')
+ cf.can_dlc -= '0';
+ else
return;
- cf.can_id = ultmp;
-
- if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
- cf.can_id |= CAN_EFF_FLAG;
-
- if ((cmd | 0x20) == 'r') /* RTR frame */
- cf.can_id |= CAN_RTR_FLAG;
-
*(u64 *) (&cf.data) = 0; /* clear payload */
- for (i = 0, dlc_pos++; i < cf.can_dlc; i++) {
- tmp = hex_to_bin(sl->rbuff[dlc_pos++]);
- if (tmp < 0)
- return;
- cf.data[i] = (tmp << 4);
- tmp = hex_to_bin(sl->rbuff[dlc_pos++]);
- if (tmp < 0)
- return;
- cf.data[i] |= tmp;
+ /* 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));
+ skb = dev_alloc_skb(sizeof(struct can_frame) +
+ sizeof(struct can_skb_priv));
if (!skb)
return;
@@ -192,6 +214,10 @@ static void slc_bump(struct slcan *sl)
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);
@@ -203,7 +229,6 @@ static void slc_bump(struct slcan *sl)
/* 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)) {
@@ -230,27 +255,46 @@ static void slcan_unesc(struct slcan *sl, unsigned char s)
/* Encapsulate one can_frame and stuff into a TTY queue. */
static void slc_encaps(struct slcan *sl, struct can_frame *cf)
{
- int actual, idx, i;
- char cmd;
+ 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)
- cmd = 'R'; /* becomes 'r' in standard frame format */
+ *pos = 'R'; /* becomes 'r' in standard frame format (SFF) */
else
- cmd = 'T'; /* becomes 't' in standard frame format */
+ *pos = 'T'; /* becomes 't' in standard frame format (SSF) */
- if (cf->can_id & CAN_EFF_FLAG)
- sprintf(sl->xbuff, "%c%08X%d", cmd,
- cf->can_id & CAN_EFF_MASK, cf->can_dlc);
- else
- sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20,
- cf->can_id & CAN_SFF_MASK, cf->can_dlc);
+ /* 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;
+ }
- idx = strlen(sl->xbuff);
+ /* build 3 (SFF) or 8 (EFF) digit CAN identifier */
+ pos++;
+ while (endpos >= pos) {
+ *endpos-- = hex_asc_upper[id & 0xf];
+ id >>= 4;
+ }
- for (i = 0; i < cf->can_dlc; i++)
- sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]);
+ pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN;
- strcat(sl->xbuff, "\r"); /* add terminating character */
+ *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,
@@ -261,37 +305,50 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf)
* 14 Oct 1994 Dmitry Gorodchanin.
*/
set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
- actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff));
- sl->xleft = strlen(sl->xbuff) - actual;
+ 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;
}
-/*
- * Called by the driver when there's room for more data. If we have
- * more packets to send, we send them here.
- */
-static void slcan_write_wakeup(struct tty_struct *tty)
+/* 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;
- struct slcan *sl = (struct slcan *) tty->disc_data;
+ spin_lock_bh(&sl->lock);
/* First make sure we're connected. */
- if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+ 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, &tty->flags);
+ clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+ spin_unlock_bh(&sl->lock);
netif_wake_queue(sl->dev);
return;
}
- actual = tty->ops->write(tty, sl->xhead, sl->xleft);
+ 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. */
@@ -366,10 +423,16 @@ static void slc_free_netdev(struct net_device *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)
@@ -477,6 +540,7 @@ static struct slcan *slc_alloc(dev_t line)
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;
@@ -575,8 +639,12 @@ static void slcan_close(struct tty_struct *tty)
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);
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
index 5de46a9a77b..96b6fe158b5 100644
--- a/drivers/net/can/softing/Kconfig
+++ b/drivers/net/can/softing/Kconfig
@@ -1,6 +1,6 @@
config CAN_SOFTING
tristate "Softing Gmbh CAN generic support"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
---help---
Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh.
diff --git a/drivers/net/can/softing/softing.h b/drivers/net/can/softing/softing.h
index afd7d85b691..35f062282db 100644
--- a/drivers/net/can/softing/softing.h
+++ b/drivers/net/can/softing/softing.h
@@ -71,34 +71,34 @@ struct softing {
} id;
};
-extern int softing_default_output(struct net_device *netdev);
+int softing_default_output(struct net_device *netdev);
-extern ktime_t softing_raw2ktime(struct softing *card, u32 raw);
+ktime_t softing_raw2ktime(struct softing *card, u32 raw);
-extern int softing_chip_poweron(struct softing *card);
+int softing_chip_poweron(struct softing *card);
-extern int softing_bootloader_command(struct softing *card, int16_t cmd,
- const char *msg);
+int softing_bootloader_command(struct softing *card, int16_t cmd,
+ const char *msg);
/* Load firmware after reset */
-extern int softing_load_fw(const char *file, struct softing *card,
- __iomem uint8_t *virt, unsigned int size, int offset);
+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 */
-extern int softing_load_app_fw(const char *file, struct softing *card);
+int softing_load_app_fw(const char *file, struct softing *card);
/*
* enable or disable irq
* only called with fw.lock locked
*/
-extern int softing_enable_irq(struct softing *card, int enable);
+int softing_enable_irq(struct softing *card, int enable);
/* start/stop 1 bus on card */
-extern int softing_startstop(struct net_device *netdev, int up);
+int softing_startstop(struct net_device *netdev, int up);
/* netif_rx() */
-extern int softing_netdev_rx(struct net_device *netdev,
- const struct can_frame *msg, ktime_t ktime);
+int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
+ ktime_t ktime);
/* SOFTING DPRAM mappings */
#define DPRAM_RX 0x0000
diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c
index c0e1b1eb87a..cdc0c7433a4 100644
--- a/drivers/net/can/softing/softing_cs.c
+++ b/drivers/net/can/softing/softing_cs.c
@@ -13,8 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
@@ -27,7 +26,7 @@
#include "softing_platform.h"
static int softingcs_index;
-static spinlock_t softingcs_index_lock;
+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);
@@ -159,7 +158,7 @@ MODULE_FIRMWARE(fw_dir "bcard2.bin");
MODULE_FIRMWARE(fw_dir "ldcard2.bin");
MODULE_FIRMWARE(fw_dir "cancrd2.bin");
-static __devinit const struct softing_platform_data
+static const struct softing_platform_data
*softingcs_find_platform_data(unsigned int manf, unsigned int prod)
{
const struct softing_platform_data *lp;
@@ -193,8 +192,7 @@ static int softingcs_enable_irq(struct platform_device *pdev, int v)
/*
* pcmcia check
*/
-static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia,
- void *priv_data)
+static int softingcs_probe_config(struct pcmcia_device *pcmcia, void *priv_data)
{
struct softing_platform_data *pdat = priv_data;
struct resource *pres;
@@ -215,7 +213,7 @@ static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia,
return pcmcia_request_window(pcmcia, pres, memspeed);
}
-static __devexit void softingcs_remove(struct pcmcia_device *pcmcia)
+static void softingcs_remove(struct pcmcia_device *pcmcia)
{
struct platform_device *pdev = pcmcia->priv;
@@ -235,7 +233,7 @@ static void softingcs_pdev_release(struct device *dev)
kfree(pdev);
}
-static __devinit int softingcs_probe(struct pcmcia_device *pcmcia)
+static int softingcs_probe(struct pcmcia_device *pcmcia)
{
int ret;
struct platform_device *pdev;
@@ -338,22 +336,10 @@ static struct pcmcia_driver softingcs_driver = {
.name = "softingcs",
.id_table = softingcs_ids,
.probe = softingcs_probe,
- .remove = __devexit_p(softingcs_remove),
+ .remove = softingcs_remove,
};
-static int __init softingcs_start(void)
-{
- spin_lock_init(&softingcs_index_lock);
- return pcmcia_register_driver(&softingcs_driver);
-}
-
-static void __exit softingcs_stop(void)
-{
- pcmcia_unregister_driver(&softingcs_driver);
-}
-
-module_init(softingcs_start);
-module_exit(softingcs_stop);
+module_pcmcia_driver(softingcs_driver);
MODULE_DESCRIPTION("softing CANcard driver"
", links PCMCIA card to softing driver");
diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c
index b595d3422b9..52fe50725d7 100644
--- a/drivers/net/can/softing/softing_fw.c
+++ b/drivers/net/can/softing/softing_fw.c
@@ -13,8 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/firmware.h>
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index f2a221e7b96..bacd236ce30 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -13,12 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
@@ -478,7 +476,7 @@ static void softing_card_shutdown(struct softing *card)
mutex_unlock(&card->fw.lock);
}
-static __devinit int softing_card_boot(struct softing *card)
+static int softing_card_boot(struct softing *card)
{
int ret, j;
static const uint8_t stream[] = {
@@ -558,15 +556,6 @@ failed:
/*
* netdev sysfs
*/
-static ssize_t show_channel(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->index);
-}
-
static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -594,7 +583,7 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 0, &val);
+ ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
val &= 0xFF;
@@ -611,12 +600,10 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr,
return count;
}
-static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
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_channel.attr,
&dev_attr_chip.attr,
&dev_attr_output.attr,
NULL,
@@ -630,6 +617,7 @@ 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 = {
@@ -645,8 +633,8 @@ static const struct can_bittiming_const softing_btr_const = {
};
-static __devinit struct net_device *softing_netdev_create(struct softing *card,
- uint16_t chip_id)
+static struct net_device *softing_netdev_create(struct softing *card,
+ uint16_t chip_id)
{
struct net_device *netdev;
struct softing_priv *priv;
@@ -676,21 +664,24 @@ static __devinit struct net_device *softing_netdev_create(struct softing *card,
return netdev;
}
-static __devinit int softing_netdev_register(struct net_device *netdev)
+static int softing_netdev_register(struct net_device *netdev)
{
int ret;
- netdev->sysfs_groups[0] = &netdev_sysfs_group;
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);
}
@@ -722,8 +713,6 @@ 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);
-DEV_ATTR_RO(frequency, id.freq);
-DEV_ATTR_RO(txpending, tx.pending);
static struct attribute *softing_pdev_attrs[] = {
&dev_attr_serial.attr,
@@ -732,8 +721,6 @@ static struct attribute *softing_pdev_attrs[] = {
&dev_attr_hardware.attr,
&dev_attr_hardware_version.attr,
&dev_attr_license.attr,
- &dev_attr_frequency.attr,
- &dev_attr_txpending.attr,
NULL,
};
@@ -745,7 +732,7 @@ static const struct attribute_group softing_pdev_group = {
/*
* platform driver
*/
-static __devexit int softing_pdev_remove(struct platform_device *pdev)
+static int softing_pdev_remove(struct platform_device *pdev)
{
struct softing *card = platform_get_drvdata(pdev);
int j;
@@ -766,9 +753,9 @@ static __devexit int softing_pdev_remove(struct platform_device *pdev)
return 0;
}
-static __devinit int softing_pdev_probe(struct platform_device *pdev)
+static int softing_pdev_probe(struct platform_device *pdev)
{
- const struct softing_platform_data *pdat = pdev->dev.platform_data;
+ const struct softing_platform_data *pdat = dev_get_platdata(&pdev->dev);
struct softing *card;
struct net_device *netdev;
struct softing_priv *priv;
@@ -834,6 +821,7 @@ static __devinit int softing_pdev_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto netdev_failed;
}
+ netdev->dev_id = j;
priv = netdev_priv(card->net[j]);
priv->index = j;
ret = softing_netdev_register(netdev);
@@ -871,7 +859,7 @@ static struct platform_driver softing_driver = {
.owner = THIS_MODULE,
},
.probe = softing_pdev_probe,
- .remove = __devexit_p(softing_pdev_remove),
+ .remove = softing_pdev_remove,
};
module_platform_driver(softing_driver);
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
new file mode 100644
index 00000000000..148cae5871a
--- /dev/null
+++ b/drivers/net/can/spi/Kconfig
@@ -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
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
new file mode 100644
index 00000000000..90bcacffbc6
--- /dev/null
+++ b/drivers/net/can/spi/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Linux Controller Area Network SPI drivers.
+#
+
+
+obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 26e7129332a..5df239e6881 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -28,8 +28,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*
*
@@ -37,9 +36,6 @@
*
* static struct mcp251x_platform_data mcp251x_info = {
* .oscillator_frequency = 8000000,
- * .board_specific_setup = &mcp251x_setup,
- * .power_enable = mcp251x_power_enable,
- * .transceiver_enable = NULL,
* };
*
* static struct spi_board_info spi_board_info[] = {
@@ -60,7 +56,9 @@
#include <linux/can/core.h>
#include <linux/can/dev.h>
+#include <linux/can/led.h>
#include <linux/can/platform/mcp251x.h>
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -71,10 +69,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
/* SPI interface instruction set */
#define INSTRUCTION_WRITE 0x02
@@ -213,6 +214,8 @@
#define TX_ECHO_SKB_MAX 1
+#define MCP251X_OST_DELAY_MS (5)
+
#define DEVICE_NAME "mcp251x"
static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
@@ -263,12 +266,15 @@ struct mcp251x_priv {
#define AFTER_SUSPEND_POWER 4
#define AFTER_SUSPEND_RESTART 8
int restart_tx;
+ struct regulator *power;
+ struct regulator *transceiver;
+ struct clk *clk;
};
#define MCP251X_IS(_model) \
static inline int mcp251x_is_##_model(struct spi_device *spi) \
{ \
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \
+ struct mcp251x_priv *priv = spi_get_drvdata(spi); \
return priv->model == CAN_MCP251X_MCP##_model; \
}
@@ -304,7 +310,7 @@ static void mcp251x_clean(struct net_device *net)
*/
static int mcp251x_spi_trans(struct spi_device *spi, int len)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct spi_transfer t = {
.tx_buf = priv->spi_tx_buf,
.rx_buf = priv->spi_rx_buf,
@@ -332,7 +338,7 @@ static int mcp251x_spi_trans(struct spi_device *spi, int len)
static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
u8 val = 0;
priv->spi_tx_buf[0] = INSTRUCTION_READ;
@@ -347,7 +353,7 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
uint8_t *v1, uint8_t *v2)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
priv->spi_tx_buf[0] = INSTRUCTION_READ;
priv->spi_tx_buf[1] = reg;
@@ -360,7 +366,7 @@ static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
priv->spi_tx_buf[1] = reg;
@@ -372,7 +378,7 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
u8 mask, uint8_t val)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
priv->spi_tx_buf[1] = reg;
@@ -385,7 +391,7 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
int len, int tx_buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (mcp251x_is_2510(spi)) {
int i;
@@ -402,7 +408,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
int tx_buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
u32 sid, eid, exide, rtr;
u8 buf[SPI_TRANSFER_BUF_LEN];
@@ -433,7 +439,7 @@ static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
int buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (mcp251x_is_2510(spi)) {
int i, len;
@@ -453,7 +459,7 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct sk_buff *skb;
struct can_frame *frame;
u8 buf[SPI_TRANSFER_BUF_LEN];
@@ -494,6 +500,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
priv->net->stats.rx_packets++;
priv->net->stats.rx_bytes += frame->can_dlc;
+
+ can_led_event(priv->net, CAN_LED_EVENT_RX);
+
netif_rx_ni(skb);
}
@@ -546,7 +555,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
static int mcp251x_set_normal_mode(struct spi_device *spi)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
unsigned long timeout;
/* Enable interrupts */
@@ -594,10 +603,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
(bt->prop_seg - 1));
mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
(bt->phase_seg2 - 1));
- dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
- mcp251x_read_reg(spi, CNF1),
- mcp251x_read_reg(spi, CNF2),
- mcp251x_read_reg(spi, CNF3));
+ dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+ mcp251x_read_reg(spi, CNF1),
+ mcp251x_read_reg(spi, CNF2),
+ mcp251x_read_reg(spi, CNF3));
return 0;
}
@@ -616,63 +625,67 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
static int mcp251x_hw_reset(struct spi_device *spi)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
+ u8 reg;
int ret;
- unsigned long timeout;
+
+ /* Wait for oscillator startup timer after power up */
+ mdelay(MCP251X_OST_DELAY_MS);
priv->spi_tx_buf[0] = INSTRUCTION_RESET;
- ret = spi_write(spi, priv->spi_tx_buf, 1);
- if (ret) {
- dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
- return -EIO;
- }
+ ret = mcp251x_spi_trans(spi, 1);
+ if (ret)
+ return ret;
+
+ /* Wait for oscillator startup timer after reset */
+ mdelay(MCP251X_OST_DELAY_MS);
+
+ reg = mcp251x_read_reg(spi, CANSTAT);
+ if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
+ return -ENODEV;
- /* Wait for reset to finish */
- timeout = jiffies + HZ;
- mdelay(10);
- while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)
- != CANCTRL_REQOP_CONF) {
- schedule();
- if (time_after(jiffies, timeout)) {
- dev_err(&spi->dev, "MCP251x didn't"
- " enter in conf mode after reset\n");
- return -EBUSY;
- }
- }
return 0;
}
static int mcp251x_hw_probe(struct spi_device *spi)
{
- int st1, st2;
+ u8 ctrl;
+ int ret;
- mcp251x_hw_reset(spi);
+ ret = mcp251x_hw_reset(spi);
+ if (ret)
+ return ret;
- /*
- * Please note that these are "magic values" based on after
- * reset defaults taken from data sheet which allows us to see
- * if we really have a chip on the bus (we avoid common all
- * zeroes or all ones situations)
- */
- st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
- st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
+ ctrl = mcp251x_read_reg(spi, CANCTRL);
- dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
+ dev_dbg(&spi->dev, "CANCTRL 0x%02x\n", ctrl);
- /* Check for power up default values */
- return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
+ /* Check for power up default value */
+ if ((ctrl & 0x17) != 0x07)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int mcp251x_power_enable(struct regulator *reg, int enable)
+{
+ if (IS_ERR_OR_NULL(reg))
+ return 0;
+
+ if (enable)
+ return regulator_enable(reg);
+ else
+ return regulator_disable(reg);
}
static void mcp251x_open_clean(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
free_irq(spi->irq, priv);
mcp251x_hw_sleep(spi);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
+ mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
}
@@ -680,7 +693,6 @@ static int mcp251x_stop(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
close_candev(net);
@@ -700,13 +712,14 @@ static int mcp251x_stop(struct net_device *net)
mcp251x_hw_sleep(spi);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
+ mcp251x_power_enable(priv->transceiver, 0);
priv->can.state = CAN_STATE_STOPPED;
mutex_unlock(&priv->mcp_lock);
+ can_led_event(net, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -760,7 +773,6 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) {
- mdelay(10);
mcp251x_hw_reset(spi);
mcp251x_setup(net, priv, spi);
if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
@@ -905,6 +917,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf & CANINTF_TX) {
net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1;
+ can_led_event(net, CAN_LED_EVENT_TX);
if (priv->tx_len) {
can_get_echo_skb(net, 0);
priv->tx_len = 0;
@@ -921,7 +934,7 @@ static int mcp251x_open(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_FALLING;
int ret;
ret = open_candev(net);
@@ -931,20 +944,17 @@ static int mcp251x_open(struct net_device *net)
}
mutex_lock(&priv->mcp_lock);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(1);
+ mcp251x_power_enable(priv->transceiver, 1);
priv->force_quit = 0;
priv->tx_skb = NULL;
priv->tx_len = 0;
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
- pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
- DEVICE_NAME, priv);
+ flags | IRQF_ONESHOT, DEVICE_NAME, priv);
if (ret) {
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
+ mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
goto open_unlock;
}
@@ -968,6 +978,9 @@ static int mcp251x_open(struct net_device *net)
mcp251x_open_clean(net);
goto open_unlock;
}
+
+ can_led_event(net, CAN_LED_EVENT_OPEN);
+
netif_wake_queue(net);
open_unlock:
@@ -979,24 +992,68 @@ static const struct net_device_ops mcp251x_netdev_ops = {
.ndo_open = mcp251x_open,
.ndo_stop = mcp251x_stop,
.ndo_start_xmit = mcp251x_hard_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static const struct of_device_id mcp251x_of_match[] = {
+ {
+ .compatible = "microchip,mcp2510",
+ .data = (void *)CAN_MCP251X_MCP2510,
+ },
+ {
+ .compatible = "microchip,mcp2515",
+ .data = (void *)CAN_MCP251X_MCP2515,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp251x_of_match);
+
+static const struct spi_device_id mcp251x_id_table[] = {
+ {
+ .name = "mcp2510",
+ .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2510,
+ },
+ {
+ .name = "mcp2515",
+ .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2515,
+ },
+ { }
};
+MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
-static int __devinit mcp251x_can_probe(struct spi_device *spi)
+static int mcp251x_can_probe(struct spi_device *spi)
{
+ const struct of_device_id *of_id = of_match_device(mcp251x_of_match,
+ &spi->dev);
+ struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
struct net_device *net;
struct mcp251x_priv *priv;
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- int ret = -ENODEV;
+ struct clk *clk;
+ int freq, ret;
+
+ clk = devm_clk_get(&spi->dev, NULL);
+ if (IS_ERR(clk)) {
+ if (pdata)
+ freq = pdata->oscillator_frequency;
+ else
+ return PTR_ERR(clk);
+ } else {
+ freq = clk_get_rate(clk);
+ }
- if (!pdata)
- /* Platform data is required for osc freq */
- goto error_out;
+ /* Sanity check */
+ if (freq < 1000000 || freq > 25000000)
+ return -ERANGE;
/* Allocate can/net device */
net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
- if (!net) {
- ret = -ENOMEM;
- goto error_alloc;
+ if (!net)
+ return -ENOMEM;
+
+ if (!IS_ERR(clk)) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto out_free;
}
net->netdev_ops = &mcp251x_netdev_ops;
@@ -1005,12 +1062,39 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
priv = netdev_priv(net);
priv->can.bittiming_const = &mcp251x_bittiming_const;
priv->can.do_set_mode = mcp251x_do_set_mode;
- priv->can.clock.freq = pdata->oscillator_frequency / 2;
+ priv->can.clock.freq = freq / 2;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
- priv->model = spi_get_device_id(spi)->driver_data;
+ if (of_id)
+ priv->model = (enum mcp251x_model)of_id->data;
+ else
+ priv->model = spi_get_device_id(spi)->driver_data;
priv->net = net;
- dev_set_drvdata(&spi->dev, priv);
+ priv->clk = clk;
+
+ spi_set_drvdata(spi, priv);
+
+ /* Configure the SPI bus */
+ spi->bits_per_word = 8;
+ if (mcp251x_is_2510(spi))
+ spi->max_speed_hz = spi->max_speed_hz ? : 5 * 1000 * 1000;
+ else
+ spi->max_speed_hz = spi->max_speed_hz ? : 10 * 1000 * 1000;
+ ret = spi_setup(spi);
+ if (ret)
+ goto out_clk;
+
+ priv->power = devm_regulator_get(&spi->dev, "vdd");
+ priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
+ if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
+ (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
+ ret = -EPROBE_DEFER;
+ goto out_clk;
+ }
+
+ ret = mcp251x_power_enable(priv->power, 1);
+ if (ret)
+ goto out_clk;
priv->spi = spi;
mutex_init(&priv->mcp_lock);
@@ -1040,94 +1124,79 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
/* Allocate non-DMA buffers */
if (!mcp251x_enable_dma) {
- priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+ priv->spi_tx_buf = devm_kzalloc(&spi->dev, SPI_TRANSFER_BUF_LEN,
+ GFP_KERNEL);
if (!priv->spi_tx_buf) {
ret = -ENOMEM;
- goto error_tx_buf;
+ goto error_probe;
}
- priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+ priv->spi_rx_buf = devm_kzalloc(&spi->dev, SPI_TRANSFER_BUF_LEN,
+ GFP_KERNEL);
if (!priv->spi_rx_buf) {
ret = -ENOMEM;
- goto error_rx_buf;
+ goto error_probe;
}
}
- if (pdata->power_enable)
- pdata->power_enable(1);
-
- /* Call out to platform specific setup */
- if (pdata->board_specific_setup)
- pdata->board_specific_setup(spi);
-
SET_NETDEV_DEV(net, &spi->dev);
- /* Configure the SPI bus */
- spi->mode = SPI_MODE_0;
- spi->bits_per_word = 8;
- spi_setup(spi);
-
/* Here is OK to not lock the MCP, no one knows about it yet */
- if (!mcp251x_hw_probe(spi)) {
- dev_info(&spi->dev, "Probe failed\n");
+ ret = mcp251x_hw_probe(spi);
+ if (ret)
goto error_probe;
- }
- mcp251x_hw_sleep(spi);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
+ mcp251x_hw_sleep(spi);
ret = register_candev(net);
- if (!ret) {
- dev_info(&spi->dev, "probed\n");
- return ret;
- }
+ if (ret)
+ goto error_probe;
+
+ devm_can_led_init(net);
+
+ return 0;
+
error_probe:
- if (!mcp251x_enable_dma)
- kfree(priv->spi_rx_buf);
-error_rx_buf:
- if (!mcp251x_enable_dma)
- kfree(priv->spi_tx_buf);
-error_tx_buf:
- free_candev(net);
if (mcp251x_enable_dma)
dma_free_coherent(&spi->dev, PAGE_SIZE,
priv->spi_tx_buf, priv->spi_tx_dma);
-error_alloc:
- if (pdata->power_enable)
- pdata->power_enable(0);
- dev_err(&spi->dev, "probe failed\n");
-error_out:
+ mcp251x_power_enable(priv->power, 0);
+
+out_clk:
+ if (!IS_ERR(clk))
+ clk_disable_unprepare(clk);
+
+out_free:
+ free_candev(net);
+
return ret;
}
-static int __devexit mcp251x_can_remove(struct spi_device *spi)
+static int mcp251x_can_remove(struct spi_device *spi)
{
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct net_device *net = priv->net;
unregister_candev(net);
- free_candev(net);
if (mcp251x_enable_dma) {
dma_free_coherent(&spi->dev, PAGE_SIZE,
priv->spi_tx_buf, priv->spi_tx_dma);
- } else {
- kfree(priv->spi_tx_buf);
- kfree(priv->spi_rx_buf);
}
- if (pdata->power_enable)
- pdata->power_enable(0);
+ mcp251x_power_enable(priv->power, 0);
+
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+
+ free_candev(net);
return 0;
}
-#ifdef CONFIG_PM
-static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
+static int __maybe_unused mcp251x_can_suspend(struct device *dev)
{
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct spi_device *spi = to_spi_device(dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct net_device *net = priv->net;
priv->force_quit = 1;
@@ -1140,33 +1209,31 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
netif_device_detach(net);
mcp251x_hw_sleep(spi);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
+ mcp251x_power_enable(priv->transceiver, 0);
priv->after_suspend = AFTER_SUSPEND_UP;
} else {
priv->after_suspend = AFTER_SUSPEND_DOWN;
}
- if (pdata->power_enable) {
- pdata->power_enable(0);
+ if (!IS_ERR_OR_NULL(priv->power)) {
+ regulator_disable(priv->power);
priv->after_suspend |= AFTER_SUSPEND_POWER;
}
return 0;
}
-static int mcp251x_can_resume(struct spi_device *spi)
+static int __maybe_unused mcp251x_can_resume(struct device *dev)
{
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct spi_device *spi = to_spi_device(dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
- pdata->power_enable(1);
+ mcp251x_power_enable(priv->power, 1);
queue_work(priv->wq, &priv->restart_work);
} else {
if (priv->after_suspend & AFTER_SUSPEND_UP) {
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(1);
+ mcp251x_power_enable(priv->transceiver, 1);
queue_work(priv->wq, &priv->restart_work);
} else {
priv->after_suspend = 0;
@@ -1176,45 +1243,22 @@ static int mcp251x_can_resume(struct spi_device *spi)
enable_irq(spi->irq);
return 0;
}
-#else
-#define mcp251x_can_suspend NULL
-#define mcp251x_can_resume NULL
-#endif
-
-static const struct spi_device_id mcp251x_id_table[] = {
- { "mcp2510", CAN_MCP251X_MCP2510 },
- { "mcp2515", CAN_MCP251X_MCP2515 },
- { },
-};
-MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
+static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
+ mcp251x_can_resume);
static struct spi_driver mcp251x_can_driver = {
.driver = {
.name = DEVICE_NAME,
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
+ .of_match_table = mcp251x_of_match,
+ .pm = &mcp251x_can_pm_ops,
},
-
.id_table = mcp251x_id_table,
.probe = mcp251x_can_probe,
- .remove = __devexit_p(mcp251x_can_remove),
- .suspend = mcp251x_can_suspend,
- .resume = mcp251x_can_resume,
+ .remove = mcp251x_can_remove,
};
-
-static int __init mcp251x_can_init(void)
-{
- return spi_register_driver(&mcp251x_can_driver);
-}
-
-static void __exit mcp251x_can_exit(void)
-{
- spi_unregister_driver(&mcp251x_can_driver);
-}
-
-module_init(mcp251x_can_init);
-module_exit(mcp251x_can_exit);
+module_spi_driver(mcp251x_can_driver);
MODULE_AUTHOR("Chris Elston <celston@katalix.com>, "
"Christian Pellegrin <chripell@evolware.org>");
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 9ded21e79db..258b9c4856e 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -37,7 +37,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
@@ -50,6 +49,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include <linux/can/platform/ti_hecc.h>
#define DRV_NAME "ti_hecc"
@@ -285,15 +285,6 @@ static inline u32 hecc_get_bit(struct ti_hecc_priv *priv, int reg, u32 bit_mask)
return (hecc_read(priv, reg) & bit_mask) ? 1 : 0;
}
-static int ti_hecc_get_state(const struct net_device *ndev,
- enum can_state *state)
-{
- struct ti_hecc_priv *priv = netdev_priv(ndev);
-
- *state = priv->can.state;
- return 0;
-}
-
static int ti_hecc_set_btc(struct ti_hecc_priv *priv)
{
struct can_bittiming *bit_timing = &priv->can.bittiming;
@@ -526,10 +517,10 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
data = (cf->can_id & CAN_SFF_MASK) << 18;
hecc_write_mbx(priv, mbxno, HECC_CANMID, data);
hecc_write_mbx(priv, mbxno, HECC_CANMDL,
- be32_to_cpu(*(u32 *)(cf->data)));
+ be32_to_cpu(*(__be32 *)(cf->data)));
if (cf->can_dlc > 4)
hecc_write_mbx(priv, mbxno, HECC_CANMDH,
- be32_to_cpu(*(u32 *)(cf->data + 4)));
+ be32_to_cpu(*(__be32 *)(cf->data + 4)));
else
*(u32 *)(cf->data + 4) = 0;
can_put_echo_skb(skb, ndev, mbxno);
@@ -577,12 +568,10 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
cf->can_id |= CAN_RTR_FLAG;
cf->can_dlc = get_can_dlc(data & 0xF);
data = hecc_read_mbx(priv, mbxno, HECC_CANMDL);
- *(u32 *)(cf->data) = cpu_to_be32(data);
+ *(__be32 *)(cf->data) = cpu_to_be32(data);
if (cf->can_dlc > 4) {
data = hecc_read_mbx(priv, mbxno, HECC_CANMDH);
- *(u32 *)(cf->data + 4) = cpu_to_be32(data);
- } else {
- *(u32 *)(cf->data + 4) = 0;
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(data);
}
spin_lock_irqsave(&priv->mbx_lock, flags);
hecc_clear_bit(priv, HECC_CANME, mbx_mask);
@@ -593,6 +582,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
stats->rx_bytes += cf->can_dlc;
+ can_led_event(priv->ndev, CAN_LED_EVENT_RX);
netif_receive_skb(skb);
stats->rx_packets++;
@@ -746,12 +736,12 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
}
if (err_status & HECC_CANES_CRCE) {
hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE);
- cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
CAN_ERR_PROT_LOC_CRC_DEL;
}
if (err_status & HECC_CANES_ACKE) {
hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE);
- cf->data[2] |= CAN_ERR_PROT_LOC_ACK |
+ cf->data[3] |= CAN_ERR_PROT_LOC_ACK |
CAN_ERR_PROT_LOC_ACK_DEL;
}
}
@@ -796,6 +786,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
stats->tx_bytes += hecc_read_mbx(priv, mbxno,
HECC_CANMCF) & 0xF;
stats->tx_packets++;
+ can_led_event(ndev, CAN_LED_EVENT_TX);
can_get_echo_skb(ndev, mbxno);
--priv->tx_tail;
}
@@ -851,6 +842,8 @@ static int ti_hecc_open(struct net_device *ndev)
return err;
}
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+
ti_hecc_start(ndev);
napi_enable(&priv->napi);
netif_start_queue(ndev);
@@ -869,6 +862,8 @@ static int ti_hecc_close(struct net_device *ndev)
close_candev(ndev);
ti_hecc_transceiver_switch(priv, 0);
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -876,6 +871,7 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
.ndo_open = ti_hecc_open,
.ndo_stop = ti_hecc_close,
.ndo_start_xmit = ti_hecc_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static int ti_hecc_probe(struct platform_device *pdev)
@@ -887,7 +883,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
void __iomem *addr;
int err = -ENODEV;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
goto probe_exit;
@@ -933,7 +929,6 @@ static int ti_hecc_probe(struct platform_device *pdev)
priv->can.bittiming_const = &ti_hecc_bittiming_const;
priv->can.do_set_mode = ti_hecc_do_set_mode;
- priv->can.do_get_state = ti_hecc_get_state;
priv->can.do_get_berr_counter = ti_hecc_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
@@ -961,6 +956,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register_candev() failed\n");
goto probe_exit_clk;
}
+
+ devm_can_led_init(ndev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->base, (u32) ndev->irq);
@@ -978,7 +976,7 @@ probe_exit:
return err;
}
-static int __devexit ti_hecc_remove(struct platform_device *pdev)
+static int ti_hecc_remove(struct platform_device *pdev)
{
struct resource *res;
struct net_device *ndev = platform_get_drvdata(pdev);
@@ -991,7 +989,6 @@ static int __devexit ti_hecc_remove(struct platform_device *pdev)
iounmap(priv->base);
release_mem_region(res->start, resource_size(res));
free_candev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -1045,7 +1042,7 @@ static struct platform_driver ti_hecc_driver = {
.owner = THIS_MODULE,
},
.probe = ti_hecc_probe,
- .remove = __devexit_p(ti_hecc_remove),
+ .remove = ti_hecc_remove,
.suspend = ti_hecc_suspend,
.resume = ti_hecc_resume,
};
@@ -1055,3 +1052,4 @@ module_platform_driver(ti_hecc_driver);
MODULE_AUTHOR("Anant Gole <anantgole@ti.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(DRV_DESC);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 0a6876841c2..a77db919363 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -1,5 +1,5 @@
menu "CAN USB interfaces"
- depends on USB && CAN_DEV
+ depends on USB
config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
@@ -13,10 +13,55 @@ config CAN_ESD_USB2
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
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index da6d1d3b296..7b9a393b1ac 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -4,6 +4,9 @@
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
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 086fa321677..00f2534dde7 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -16,7 +16,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -245,7 +244,6 @@ struct ems_tx_urb_context {
struct ems_usb {
struct can_priv can; /* must be the first member */
- int open_time;
struct sk_buff *echo_skb[MAX_TX_URBS];
@@ -626,6 +624,7 @@ static int ems_usb_start(struct ems_usb *dev)
usb_unanchor_urb(urb);
usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
urb->transfer_dma);
+ usb_free_urb(urb);
break;
}
@@ -728,7 +727,6 @@ static int ems_usb_open(struct net_device *netdev)
return err;
}
- dev->open_time = jiffies;
netif_start_queue(netdev);
@@ -800,8 +798,8 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
* allowed (MAX_TX_URBS).
*/
if (!context) {
- usb_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
+ usb_free_urb(urb);
netdev_warn(netdev, "couldn't find free context\n");
@@ -878,8 +876,6 @@ static int ems_usb_close(struct net_device *netdev)
close_candev(netdev);
- dev->open_time = 0;
-
return 0;
}
@@ -887,6 +883,7 @@ static const struct net_device_ops ems_usb_netdev_ops = {
.ndo_open = ems_usb_open,
.ndo_stop = ems_usb_close,
.ndo_start_xmit = ems_usb_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const ems_usb_bittiming_const = {
@@ -905,9 +902,6 @@ static int ems_usb_set_mode(struct net_device *netdev, enum can_mode mode)
{
struct ems_usb *dev = netdev_priv(netdev);
- if (!dev->open_time)
- return -EINVAL;
-
switch (mode) {
case CAN_MODE_START:
if (ems_usb_write_mode(dev, SJA1000_MOD_NORMAL))
@@ -1021,17 +1015,13 @@ static int ems_usb_probe(struct usb_interface *intf,
}
dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL);
- if (!dev->intr_in_buffer) {
- dev_err(&intf->dev, "Couldn't alloc Intr buffer\n");
+ if (!dev->intr_in_buffer)
goto cleanup_intr_urb;
- }
dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE +
sizeof(struct ems_cpc_msg), GFP_KERNEL);
- if (!dev->tx_msg_buffer) {
- dev_err(&intf->dev, "Couldn't alloc Tx buffer\n");
+ if (!dev->tx_msg_buffer)
goto cleanup_intr_in_buffer;
- }
usb_set_intfdata(intf, dev);
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index bd36e551717..b7c9e8b1146 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -1,7 +1,7 @@
/*
- * CAN driver for esd CAN-USB/2
+ * CAN driver for esd CAN-USB/2 and CAN-USB/Micro
*
- * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ * Copyright (C) 2010-2012 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
@@ -16,7 +16,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -28,14 +27,16 @@
#include <linux/can/error.h>
MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>");
-MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 interfaces");
+MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 and CAN-USB/Micro interfaces");
MODULE_LICENSE("GPL v2");
/* Define these values to match your devices */
#define USB_ESDGMBH_VENDOR_ID 0x0ab4
#define USB_CANUSB2_PRODUCT_ID 0x0010
+#define USB_CANUSBM_PRODUCT_ID 0x0011
#define ESD_USB2_CAN_CLOCK 60000000
+#define ESD_USBM_CAN_CLOCK 36000000
#define ESD_USB2_MAX_NETS 2
/* USB2 commands */
@@ -69,6 +70,7 @@ MODULE_LICENSE("GPL v2");
#define ESD_USB2_TSEG2_SHIFT 20
#define ESD_USB2_SJW_MAX 4
#define ESD_USB2_SJW_SHIFT 14
+#define ESD_USBM_SJW_SHIFT 24
#define ESD_USB2_BRP_MIN 1
#define ESD_USB2_BRP_MAX 1024
#define ESD_USB2_BRP_INC 1
@@ -183,6 +185,7 @@ struct __attribute__ ((packed)) esd_usb2_msg {
static struct usb_device_id esd_usb2_table[] = {
{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
+ {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE(usb, esd_usb2_table);
@@ -213,7 +216,6 @@ struct esd_usb2_net_priv {
struct usb_anchor tx_submitted;
struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
- int open_time;
struct esd_usb2 *usb2;
struct net_device *netdev;
int index;
@@ -409,10 +411,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
switch (msg->msg.hdr.cmd) {
case CMD_CAN_RX:
+ if (msg->msg.rx.net >= dev->net_count) {
+ dev_err(dev->udev->dev.parent, "format error\n");
+ break;
+ }
+
esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
break;
case CMD_CAN_TX:
+ if (msg->msg.txdone.net >= dev->net_count) {
+ dev_err(dev->udev->dev.parent, "format error\n");
+ break;
+ }
+
esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
msg);
break;
@@ -609,9 +621,15 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
{
struct esd_usb2 *dev = priv->usb2;
struct net_device *netdev = priv->netdev;
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
int err, i;
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
/*
* Enable all IDs
* The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
@@ -625,33 +643,32 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
* the number of the starting bitmask (0..64) to the filter.option
* field followed by only some bitmasks.
*/
- msg.msg.hdr.cmd = CMD_IDADD;
- msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
- msg.msg.filter.net = priv->index;
- msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ msg->msg.hdr.cmd = CMD_IDADD;
+ msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg->msg.filter.net = priv->index;
+ msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
for (i = 0; i < ESD_MAX_ID_SEGMENT; i++)
- msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff);
+ msg->msg.filter.mask[i] = cpu_to_le32(0xffffffff);
/* enable 29bit extended IDs */
- msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
+ msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
- err = esd_usb2_send_msg(dev, &msg);
+ err = esd_usb2_send_msg(dev, msg);
if (err)
- goto failed;
+ goto out;
err = esd_usb2_setup_rx_urbs(dev);
if (err)
- goto failed;
+ goto out;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
- return 0;
-
-failed:
+out:
if (err == -ENODEV)
netif_device_detach(netdev);
+ if (err)
+ netdev_err(netdev, "couldn't start device: %d\n", err);
- netdev_err(netdev, "couldn't start device: %d\n", err);
-
+ kfree(msg);
return err;
}
@@ -691,8 +708,6 @@ static int esd_usb2_open(struct net_device *netdev)
return err;
}
- priv->open_time = jiffies;
-
netif_start_queue(netdev);
return 0;
@@ -832,26 +847,30 @@ nourbmem:
static int esd_usb2_close(struct net_device *netdev)
{
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
int i;
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
/* Disable all IDs (see esd_usb2_start()) */
- msg.msg.hdr.cmd = CMD_IDADD;
- msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
- msg.msg.filter.net = priv->index;
- msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ msg->msg.hdr.cmd = CMD_IDADD;
+ msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg->msg.filter.net = priv->index;
+ msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
- msg.msg.filter.mask[i] = 0;
- if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ msg->msg.filter.mask[i] = 0;
+ if (esd_usb2_send_msg(priv->usb2, msg) < 0)
netdev_err(netdev, "sending idadd message failed\n");
/* set CAN controller to reset mode */
- msg.msg.hdr.len = 2;
- msg.msg.hdr.cmd = CMD_SETBAUD;
- msg.msg.setbaud.net = priv->index;
- msg.msg.setbaud.rsvd = 0;
- msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
- if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ msg->msg.hdr.len = 2;
+ msg->msg.hdr.cmd = CMD_SETBAUD;
+ msg->msg.setbaud.net = priv->index;
+ msg->msg.setbaud.rsvd = 0;
+ msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
+ if (esd_usb2_send_msg(priv->usb2, msg) < 0)
netdev_err(netdev, "sending setbaud message failed\n");
priv->can.state = CAN_STATE_STOPPED;
@@ -860,7 +879,7 @@ static int esd_usb2_close(struct net_device *netdev)
close_candev(netdev);
- priv->open_time = 0;
+ kfree(msg);
return 0;
}
@@ -869,6 +888,7 @@ static const struct net_device_ops esd_usb2_netdev_ops = {
.ndo_open = esd_usb2_open,
.ndo_stop = esd_usb2_close,
.ndo_start_xmit = esd_usb2_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const esd_usb2_bittiming_const = {
@@ -887,13 +907,25 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
{
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
struct can_bittiming *bt = &priv->can.bittiming;
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
+ int err;
u32 canbtr;
+ int sjw_shift;
canbtr = ESD_USB2_UBR;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ canbtr |= ESD_USB2_LOM;
+
canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
+
+ if (le16_to_cpu(priv->usb2->udev->descriptor.idProduct) ==
+ USB_CANUSBM_PRODUCT_ID)
+ sjw_shift = ESD_USBM_SJW_SHIFT;
+ else
+ sjw_shift = ESD_USB2_SJW_SHIFT;
+
canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1))
- << ESD_USB2_SJW_SHIFT;
+ << sjw_shift;
canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1)
& (ESD_USB2_TSEG1_MAX - 1))
<< ESD_USB2_TSEG1_SHIFT;
@@ -902,15 +934,22 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
canbtr |= ESD_USB2_3_SAMPLES;
- msg.msg.hdr.len = 2;
- msg.msg.hdr.cmd = CMD_SETBAUD;
- msg.msg.setbaud.net = priv->index;
- msg.msg.setbaud.rsvd = 0;
- msg.msg.setbaud.baud = cpu_to_le32(canbtr);
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->msg.hdr.len = 2;
+ msg->msg.hdr.cmd = CMD_SETBAUD;
+ msg->msg.setbaud.net = priv->index;
+ msg->msg.setbaud.rsvd = 0;
+ msg->msg.setbaud.baud = cpu_to_le32(canbtr);
netdev_info(netdev, "setting BTR=%#x\n", canbtr);
- return esd_usb2_send_msg(priv->usb2, &msg);
+ err = esd_usb2_send_msg(priv->usb2, msg);
+
+ kfree(msg);
+ return err;
}
static int esd_usb2_get_berr_counter(const struct net_device *netdev,
@@ -926,11 +965,6 @@ static int esd_usb2_get_berr_counter(const struct net_device *netdev,
static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
{
- struct esd_usb2_net_priv *priv = netdev_priv(netdev);
-
- if (!priv->open_time)
- return -EINVAL;
-
switch (mode) {
case CAN_MODE_START:
netif_wake_queue(netdev);
@@ -971,18 +1005,27 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
priv->index = index;
priv->can.state = CAN_STATE_STOPPED;
- priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY;
+
+ if (le16_to_cpu(dev->udev->descriptor.idProduct) ==
+ USB_CANUSBM_PRODUCT_ID)
+ priv->can.clock.freq = ESD_USBM_CAN_CLOCK;
+ else {
+ priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ }
+
priv->can.bittiming_const = &esd_usb2_bittiming_const;
priv->can.do_set_bittiming = esd_usb2_set_bittiming;
priv->can.do_set_mode = esd_usb2_set_mode;
priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
- priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
netdev->flags |= IFF_ECHO; /* we support local echo */
netdev->netdev_ops = &esd_usb2_netdev_ops;
SET_NETDEV_DEV(netdev, &intf->dev);
+ netdev->dev_id = index;
err = register_candev(netdev);
if (err) {
@@ -1009,7 +1052,7 @@ static int esd_usb2_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct esd_usb2 *dev;
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
int i, err;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1024,27 +1067,33 @@ static int esd_usb2_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto free_msg;
+ }
+
/* query number of CAN interfaces (nets) */
- msg.msg.hdr.cmd = CMD_VERSION;
- msg.msg.hdr.len = 2;
- msg.msg.version.rsvd = 0;
- msg.msg.version.flags = 0;
- msg.msg.version.drv_version = 0;
+ msg->msg.hdr.cmd = CMD_VERSION;
+ msg->msg.hdr.len = 2;
+ msg->msg.version.rsvd = 0;
+ msg->msg.version.flags = 0;
+ msg->msg.version.drv_version = 0;
- err = esd_usb2_send_msg(dev, &msg);
+ err = esd_usb2_send_msg(dev, msg);
if (err < 0) {
dev_err(&intf->dev, "sending version message failed\n");
- goto free_dev;
+ goto free_msg;
}
- err = esd_usb2_wait_msg(dev, &msg);
+ err = esd_usb2_wait_msg(dev, msg);
if (err < 0) {
dev_err(&intf->dev, "no version message answer\n");
- goto free_dev;
+ goto free_msg;
}
- dev->net_count = (int)msg.msg.version_reply.nets;
- dev->version = le32_to_cpu(msg.msg.version_reply.version);
+ dev->net_count = (int)msg->msg.version_reply.nets;
+ dev->version = le32_to_cpu(msg->msg.version_reply.version);
if (device_create_file(&intf->dev, &dev_attr_firmware))
dev_err(&intf->dev,
@@ -1062,10 +1111,10 @@ static int esd_usb2_probe(struct usb_interface *intf,
for (i = 0; i < dev->net_count; i++)
esd_usb2_probe_one_net(intf, i);
- return 0;
-
-free_dev:
- kfree(dev);
+free_msg:
+ kfree(msg);
+ if (err)
+ kfree(dev);
done:
return err;
}
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
new file mode 100644
index 00000000000..04b0f84612f
--- /dev/null
+++ b/drivers/net/can/usb/gs_usb.c
@@ -0,0 +1,971 @@
+/* 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,
+};
+
+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");
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
new file mode 100644
index 00000000000..541fb7a0562
--- /dev/null
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -0,0 +1,1665 @@
+/*
+ * 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.
+ *
+ * Parts of this driver are based on the following:
+ * - Kvaser linux leaf driver (version 4.78)
+ * - CAN driver for esd CAN-USB/2
+ *
+ * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
+ * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ */
+
+#include <linux/completion.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>
+
+#define MAX_TX_URBS 16
+#define MAX_RX_URBS 4
+#define START_TIMEOUT 1000 /* msecs */
+#define STOP_TIMEOUT 1000 /* msecs */
+#define USB_SEND_TIMEOUT 1000 /* msecs */
+#define USB_RECV_TIMEOUT 1000 /* msecs */
+#define RX_BUFFER_SIZE 3072
+#define CAN_USB_CLOCK 8000000
+#define MAX_NET_DEVICES 3
+
+/* Kvaser USB devices */
+#define KVASER_VENDOR_ID 0x0bfd
+#define USB_LEAF_DEVEL_PRODUCT_ID 10
+#define USB_LEAF_LITE_PRODUCT_ID 11
+#define USB_LEAF_PRO_PRODUCT_ID 12
+#define USB_LEAF_SPRO_PRODUCT_ID 14
+#define USB_LEAF_PRO_LS_PRODUCT_ID 15
+#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
+#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
+#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
+#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
+#define USB_MEMO2_DEVEL_PRODUCT_ID 22
+#define USB_MEMO2_HSHS_PRODUCT_ID 23
+#define USB_UPRO_HSHS_PRODUCT_ID 24
+#define USB_LEAF_LITE_GI_PRODUCT_ID 25
+#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
+#define USB_MEMO2_HSLS_PRODUCT_ID 27
+#define USB_LEAF_LITE_CH_PRODUCT_ID 28
+#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
+#define USB_OEM_MERCURY_PRODUCT_ID 34
+#define USB_OEM_LEAF_PRODUCT_ID 35
+#define USB_CAN_R_PRODUCT_ID 39
+#define USB_LEAF_LITE_V2_PRODUCT_ID 288
+#define USB_MINI_PCIE_HS_PRODUCT_ID 289
+
+/* USB devices features */
+#define KVASER_HAS_SILENT_MODE BIT(0)
+#define KVASER_HAS_TXRX_ERRORS BIT(1)
+
+/* Message header size */
+#define MSG_HEADER_LEN 2
+
+/* Can message flags */
+#define MSG_FLAG_ERROR_FRAME BIT(0)
+#define MSG_FLAG_OVERRUN BIT(1)
+#define MSG_FLAG_NERR BIT(2)
+#define MSG_FLAG_WAKEUP BIT(3)
+#define MSG_FLAG_REMOTE_FRAME BIT(4)
+#define MSG_FLAG_RESERVED BIT(5)
+#define MSG_FLAG_TX_ACK BIT(6)
+#define MSG_FLAG_TX_REQUEST BIT(7)
+
+/* Can states */
+#define M16C_STATE_BUS_RESET BIT(0)
+#define M16C_STATE_BUS_ERROR BIT(4)
+#define M16C_STATE_BUS_PASSIVE BIT(5)
+#define M16C_STATE_BUS_OFF BIT(6)
+
+/* Can msg ids */
+#define CMD_RX_STD_MESSAGE 12
+#define CMD_TX_STD_MESSAGE 13
+#define CMD_RX_EXT_MESSAGE 14
+#define CMD_TX_EXT_MESSAGE 15
+#define CMD_SET_BUS_PARAMS 16
+#define CMD_GET_BUS_PARAMS 17
+#define CMD_GET_BUS_PARAMS_REPLY 18
+#define CMD_GET_CHIP_STATE 19
+#define CMD_CHIP_STATE_EVENT 20
+#define CMD_SET_CTRL_MODE 21
+#define CMD_GET_CTRL_MODE 22
+#define CMD_GET_CTRL_MODE_REPLY 23
+#define CMD_RESET_CHIP 24
+#define CMD_RESET_CARD 25
+#define CMD_START_CHIP 26
+#define CMD_START_CHIP_REPLY 27
+#define CMD_STOP_CHIP 28
+#define CMD_STOP_CHIP_REPLY 29
+#define CMD_GET_CARD_INFO2 32
+#define CMD_GET_CARD_INFO 34
+#define CMD_GET_CARD_INFO_REPLY 35
+#define CMD_GET_SOFTWARE_INFO 38
+#define CMD_GET_SOFTWARE_INFO_REPLY 39
+#define CMD_ERROR_EVENT 45
+#define CMD_FLUSH_QUEUE 48
+#define CMD_RESET_ERROR_COUNTER 49
+#define CMD_TX_ACKNOWLEDGE 50
+#define CMD_CAN_ERROR_EVENT 51
+#define CMD_USB_THROTTLE 77
+#define CMD_LOG_MESSAGE 106
+
+/* error factors */
+#define M16C_EF_ACKE BIT(0)
+#define M16C_EF_CRCE BIT(1)
+#define M16C_EF_FORME BIT(2)
+#define M16C_EF_STFE BIT(3)
+#define M16C_EF_BITE0 BIT(4)
+#define M16C_EF_BITE1 BIT(5)
+#define M16C_EF_RCVE BIT(6)
+#define M16C_EF_TRE BIT(7)
+
+/* bittiming parameters */
+#define KVASER_USB_TSEG1_MIN 1
+#define KVASER_USB_TSEG1_MAX 16
+#define KVASER_USB_TSEG2_MIN 1
+#define KVASER_USB_TSEG2_MAX 8
+#define KVASER_USB_SJW_MAX 4
+#define KVASER_USB_BRP_MIN 1
+#define KVASER_USB_BRP_MAX 64
+#define KVASER_USB_BRP_INC 1
+
+/* ctrl modes */
+#define KVASER_CTRL_MODE_NORMAL 1
+#define KVASER_CTRL_MODE_SILENT 2
+#define KVASER_CTRL_MODE_SELFRECEPTION 3
+#define KVASER_CTRL_MODE_OFF 4
+
+/* log message */
+#define KVASER_EXTENDED_FRAME BIT(31)
+
+struct kvaser_msg_simple {
+ u8 tid;
+ u8 channel;
+} __packed;
+
+struct kvaser_msg_cardinfo {
+ u8 tid;
+ u8 nchannels;
+ __le32 serial_number;
+ __le32 padding;
+ __le32 clock_resolution;
+ __le32 mfgdate;
+ u8 ean[8];
+ u8 hw_revision;
+ u8 usb_hs_mode;
+ __le16 padding2;
+} __packed;
+
+struct kvaser_msg_cardinfo2 {
+ u8 tid;
+ u8 channel;
+ u8 pcb_id[24];
+ __le32 oem_unlock_code;
+} __packed;
+
+struct kvaser_msg_softinfo {
+ u8 tid;
+ u8 channel;
+ __le32 sw_options;
+ __le32 fw_version;
+ __le16 max_outstanding_tx;
+ __le16 padding[9];
+} __packed;
+
+struct kvaser_msg_busparams {
+ u8 tid;
+ u8 channel;
+ __le32 bitrate;
+ u8 tseg1;
+ u8 tseg2;
+ u8 sjw;
+ u8 no_samp;
+} __packed;
+
+struct kvaser_msg_tx_can {
+ u8 channel;
+ u8 tid;
+ u8 msg[14];
+ u8 padding;
+ u8 flags;
+} __packed;
+
+struct kvaser_msg_rx_can {
+ u8 channel;
+ u8 flag;
+ __le16 time[3];
+ u8 msg[14];
+} __packed;
+
+struct kvaser_msg_chip_state_event {
+ u8 tid;
+ u8 channel;
+ __le16 time[3];
+ u8 tx_errors_count;
+ u8 rx_errors_count;
+ u8 status;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg_tx_acknowledge {
+ u8 channel;
+ u8 tid;
+ __le16 time[3];
+ u8 flags;
+ u8 time_offset;
+} __packed;
+
+struct kvaser_msg_error_event {
+ u8 tid;
+ u8 flags;
+ __le16 time[3];
+ u8 channel;
+ u8 padding;
+ u8 tx_errors_count;
+ u8 rx_errors_count;
+ u8 status;
+ u8 error_factor;
+} __packed;
+
+struct kvaser_msg_ctrl_mode {
+ u8 tid;
+ u8 channel;
+ u8 ctrl_mode;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg_flush_queue {
+ u8 tid;
+ u8 channel;
+ u8 flags;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg_log_message {
+ u8 channel;
+ u8 flags;
+ __le16 time[3];
+ u8 dlc;
+ u8 time_offset;
+ __le32 id;
+ u8 data[8];
+} __packed;
+
+struct kvaser_msg {
+ u8 len;
+ u8 id;
+ union {
+ struct kvaser_msg_simple simple;
+ struct kvaser_msg_cardinfo cardinfo;
+ struct kvaser_msg_cardinfo2 cardinfo2;
+ struct kvaser_msg_softinfo softinfo;
+ struct kvaser_msg_busparams busparams;
+ struct kvaser_msg_tx_can tx_can;
+ struct kvaser_msg_rx_can rx_can;
+ struct kvaser_msg_chip_state_event chip_state_event;
+ struct kvaser_msg_tx_acknowledge tx_acknowledge;
+ struct kvaser_msg_error_event error_event;
+ struct kvaser_msg_ctrl_mode ctrl_mode;
+ struct kvaser_msg_flush_queue flush_queue;
+ struct kvaser_msg_log_message log_message;
+ } u;
+} __packed;
+
+struct kvaser_usb_tx_urb_context {
+ struct kvaser_usb_net_priv *priv;
+ u32 echo_index;
+ int dlc;
+};
+
+struct kvaser_usb {
+ struct usb_device *udev;
+ struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
+
+ struct usb_endpoint_descriptor *bulk_in, *bulk_out;
+ struct usb_anchor rx_submitted;
+
+ u32 fw_version;
+ unsigned int nchannels;
+
+ bool rxinitdone;
+ void *rxbuf[MAX_RX_URBS];
+ dma_addr_t rxbuf_dma[MAX_RX_URBS];
+};
+
+struct kvaser_usb_net_priv {
+ struct can_priv can;
+
+ atomic_t active_tx_urbs;
+ struct usb_anchor tx_submitted;
+ struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+ struct completion start_comp, stop_comp;
+
+ struct kvaser_usb *dev;
+ struct net_device *netdev;
+ int channel;
+
+ struct can_berr_counter bec;
+};
+
+static const struct usb_device_id kvaser_usb_table[] = {
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS |
+ KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
+
+static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev,
+ struct kvaser_msg *msg)
+{
+ int actual_len;
+
+ return usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out->bEndpointAddress),
+ msg, msg->len, &actual_len,
+ USB_SEND_TIMEOUT);
+}
+
+static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
+ struct kvaser_msg *msg)
+{
+ struct kvaser_msg *tmp;
+ void *buf;
+ int actual_len;
+ int err;
+ int pos;
+ unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT);
+
+ buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ do {
+ err = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in->bEndpointAddress),
+ buf, RX_BUFFER_SIZE, &actual_len,
+ USB_RECV_TIMEOUT);
+ if (err < 0)
+ goto end;
+
+ pos = 0;
+ while (pos <= actual_len - MSG_HEADER_LEN) {
+ tmp = buf + pos;
+
+ if (!tmp->len)
+ break;
+
+ if (pos + tmp->len > actual_len) {
+ dev_err(dev->udev->dev.parent,
+ "Format error\n");
+ break;
+ }
+
+ if (tmp->id == id) {
+ memcpy(msg, tmp, tmp->len);
+ goto end;
+ }
+
+ pos += tmp->len;
+ }
+ } while (time_before(jiffies, to));
+
+ err = -EINVAL;
+
+end:
+ kfree(buf);
+
+ return err;
+}
+
+static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
+ u8 msg_id, int channel)
+{
+ struct kvaser_msg *msg;
+ int rc;
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->id = msg_id;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
+ msg->u.simple.channel = channel;
+ msg->u.simple.tid = 0xff;
+
+ rc = kvaser_usb_send_msg(dev, msg);
+
+ kfree(msg);
+ return rc;
+}
+
+static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
+{
+ struct kvaser_msg msg;
+ int err;
+
+ err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
+ if (err)
+ return err;
+
+ err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
+ if (err)
+ return err;
+
+ dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+
+ return 0;
+}
+
+static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
+{
+ struct kvaser_msg msg;
+ int err;
+
+ err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
+ if (err)
+ return err;
+
+ err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
+ if (err)
+ return err;
+
+ dev->nchannels = msg.u.cardinfo.nchannels;
+ if (dev->nchannels > MAX_NET_DEVICES)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct net_device_stats *stats;
+ struct kvaser_usb_tx_urb_context *context;
+ struct kvaser_usb_net_priv *priv;
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ u8 channel = msg->u.tx_acknowledge.channel;
+ u8 tid = msg->u.tx_acknowledge.tid;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+
+ if (!netif_device_present(priv->netdev))
+ return;
+
+ stats = &priv->netdev->stats;
+
+ context = &priv->tx_contexts[tid % MAX_TX_URBS];
+
+ /* Sometimes the state change doesn't come after a bus-off event */
+ if (priv->can.restart_ms &&
+ (priv->can.state >= CAN_STATE_BUS_OFF)) {
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (skb) {
+ cf->can_id |= CAN_ERR_RESTARTED;
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ } else {
+ netdev_err(priv->netdev,
+ "No memory left for err_skb\n");
+ }
+
+ priv->can.can_stats.restarts++;
+ netif_carrier_on(priv->netdev);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ stats->tx_packets++;
+ stats->tx_bytes += context->dlc;
+ can_get_echo_skb(priv->netdev, context->echo_index);
+
+ context->echo_index = MAX_TX_URBS;
+ atomic_dec(&priv->active_tx_urbs);
+
+ netif_wake_queue(priv->netdev);
+}
+
+static void kvaser_usb_simple_msg_callback(struct urb *urb)
+{
+ struct net_device *netdev = urb->context;
+
+ kfree(urb->transfer_buffer);
+
+ if (urb->status)
+ netdev_warn(netdev, "urb status received: %d\n",
+ urb->status);
+}
+
+static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
+ u8 msg_id)
+{
+ struct kvaser_usb *dev = priv->dev;
+ struct net_device *netdev = priv->netdev;
+ struct kvaser_msg *msg;
+ struct urb *urb;
+ void *buf;
+ int err;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ return -ENOMEM;
+ }
+
+ buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
+ if (!buf) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ msg = (struct kvaser_msg *)buf;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
+ msg->id = msg_id;
+ msg->u.simple.channel = priv->channel;
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out->bEndpointAddress),
+ buf, msg->len,
+ kvaser_usb_simple_msg_callback, priv);
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ netdev_err(netdev, "Error transmitting URB\n");
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+ kfree(buf);
+ return err;
+ }
+
+ usb_free_urb(urb);
+
+ return 0;
+}
+
+static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+{
+ int i;
+
+ usb_kill_anchored_urbs(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ struct kvaser_usb_net_priv *priv;
+ unsigned int new_state;
+ u8 channel, status, txerr, rxerr, error_factor;
+
+ switch (msg->id) {
+ case CMD_CAN_ERROR_EVENT:
+ channel = msg->u.error_event.channel;
+ status = msg->u.error_event.status;
+ txerr = msg->u.error_event.tx_errors_count;
+ rxerr = msg->u.error_event.rx_errors_count;
+ error_factor = msg->u.error_event.error_factor;
+ break;
+ case CMD_LOG_MESSAGE:
+ channel = msg->u.log_message.channel;
+ status = msg->u.log_message.data[0];
+ txerr = msg->u.log_message.data[2];
+ rxerr = msg->u.log_message.data[3];
+ error_factor = msg->u.log_message.data[1];
+ break;
+ case CMD_CHIP_STATE_EVENT:
+ channel = msg->u.chip_state_event.channel;
+ status = msg->u.chip_state_event.status;
+ txerr = msg->u.chip_state_event.tx_errors_count;
+ rxerr = msg->u.chip_state_event.rx_errors_count;
+ error_factor = 0;
+ break;
+ default:
+ dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+ msg->id);
+ return;
+ }
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+ stats = &priv->netdev->stats;
+
+ if (status & M16C_STATE_BUS_RESET) {
+ kvaser_usb_unlink_tx_urbs(priv);
+ return;
+ }
+
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ new_state = priv->can.state;
+
+ netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
+
+ if (status & M16C_STATE_BUS_OFF) {
+ cf->can_id |= CAN_ERR_BUSOFF;
+
+ priv->can.can_stats.bus_off++;
+ if (!priv->can.restart_ms)
+ kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
+
+ netif_carrier_off(priv->netdev);
+
+ new_state = CAN_STATE_BUS_OFF;
+ } else if (status & M16C_STATE_BUS_PASSIVE) {
+ if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
+ cf->can_id |= CAN_ERR_CRTL;
+
+ if (txerr || rxerr)
+ cf->data[1] = (txerr > rxerr)
+ ? CAN_ERR_CRTL_TX_PASSIVE
+ : CAN_ERR_CRTL_RX_PASSIVE;
+ else
+ cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE |
+ CAN_ERR_CRTL_RX_PASSIVE;
+
+ priv->can.can_stats.error_passive++;
+ }
+
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ }
+
+ if (status == M16C_STATE_BUS_ERROR) {
+ if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
+ ((txerr >= 96) || (rxerr >= 96))) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (txerr > rxerr)
+ ? CAN_ERR_CRTL_TX_WARNING
+ : CAN_ERR_CRTL_RX_WARNING;
+
+ priv->can.can_stats.error_warning++;
+ new_state = CAN_STATE_ERROR_WARNING;
+ } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_ACTIVE;
+
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
+ }
+
+ if (!status) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_ACTIVE;
+
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ if (priv->can.restart_ms &&
+ (priv->can.state >= CAN_STATE_BUS_OFF) &&
+ (new_state < CAN_STATE_BUS_OFF)) {
+ cf->can_id |= CAN_ERR_RESTARTED;
+ netif_carrier_on(priv->netdev);
+
+ priv->can.can_stats.restarts++;
+ }
+
+ if (error_factor) {
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+
+ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+ if (error_factor & M16C_EF_ACKE)
+ cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+ if (error_factor & M16C_EF_CRCE)
+ cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL);
+ if (error_factor & M16C_EF_FORME)
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ if (error_factor & M16C_EF_STFE)
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ if (error_factor & M16C_EF_BITE0)
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ if (error_factor & M16C_EF_BITE1)
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ if (error_factor & M16C_EF_TRE)
+ cf->data[2] |= CAN_ERR_PROT_TX;
+ }
+
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+
+ priv->bec.txerr = txerr;
+ priv->bec.rxerr = rxerr;
+
+ priv->can.state = new_state;
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
+ const struct kvaser_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats = &priv->netdev->stats;
+
+ if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+ MSG_FLAG_NERR)) {
+ netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
+ msg->u.rx_can.flag);
+
+ stats->rx_errors++;
+ return;
+ }
+
+ if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ }
+}
+
+static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_net_priv *priv;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ u8 channel = msg->u.rx_can.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+ stats = &priv->netdev->stats;
+
+ if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
+ (msg->id == CMD_LOG_MESSAGE)) {
+ kvaser_usb_rx_error(dev, msg);
+ return;
+ } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+ MSG_FLAG_NERR |
+ MSG_FLAG_OVERRUN)) {
+ kvaser_usb_rx_can_err(priv, msg);
+ return;
+ } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
+ netdev_warn(priv->netdev,
+ "Unhandled frame (flags: 0x%02x)",
+ msg->u.rx_can.flag);
+ return;
+ }
+
+ skb = alloc_can_skb(priv->netdev, &cf);
+ if (!skb) {
+ stats->tx_dropped++;
+ return;
+ }
+
+ if (msg->id == CMD_LOG_MESSAGE) {
+ cf->can_id = le32_to_cpu(msg->u.log_message.id);
+ if (cf->can_id & KVASER_EXTENDED_FRAME)
+ cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
+ else
+ cf->can_id &= CAN_SFF_MASK;
+
+ cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
+
+ if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cf->data, &msg->u.log_message.data,
+ cf->can_dlc);
+ } else {
+ cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
+ (msg->u.rx_can.msg[1] & 0x3f);
+
+ if (msg->id == CMD_RX_EXT_MESSAGE) {
+ cf->can_id <<= 18;
+ cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
+ ((msg->u.rx_can.msg[3] & 0xff) << 6) |
+ (msg->u.rx_can.msg[4] & 0x3f);
+ cf->can_id |= CAN_EFF_FLAG;
+ }
+
+ cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+
+ if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cf->data, &msg->u.rx_can.msg[6],
+ cf->can_dlc);
+ }
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_net_priv *priv;
+ u8 channel = msg->u.simple.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+
+ if (completion_done(&priv->start_comp) &&
+ netif_queue_stopped(priv->netdev)) {
+ netif_wake_queue(priv->netdev);
+ } else {
+ netif_start_queue(priv->netdev);
+ complete(&priv->start_comp);
+ }
+}
+
+static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_net_priv *priv;
+ u8 channel = msg->u.simple.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+
+ complete(&priv->stop_comp);
+}
+
+static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ switch (msg->id) {
+ case CMD_START_CHIP_REPLY:
+ kvaser_usb_start_chip_reply(dev, msg);
+ break;
+
+ case CMD_STOP_CHIP_REPLY:
+ kvaser_usb_stop_chip_reply(dev, msg);
+ break;
+
+ case CMD_RX_STD_MESSAGE:
+ case CMD_RX_EXT_MESSAGE:
+ case CMD_LOG_MESSAGE:
+ kvaser_usb_rx_can_msg(dev, msg);
+ break;
+
+ case CMD_CHIP_STATE_EVENT:
+ case CMD_CAN_ERROR_EVENT:
+ kvaser_usb_rx_error(dev, msg);
+ break;
+
+ case CMD_TX_ACKNOWLEDGE:
+ kvaser_usb_tx_acknowledge(dev, msg);
+ break;
+
+ default:
+ dev_warn(dev->udev->dev.parent,
+ "Unhandled message (%d)\n", msg->id);
+ break;
+ }
+}
+
+static void kvaser_usb_read_bulk_callback(struct urb *urb)
+{
+ struct kvaser_usb *dev = urb->context;
+ struct kvaser_msg *msg;
+ int pos = 0;
+ int err, i;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
+ urb->status);
+ goto resubmit_urb;
+ }
+
+ while (pos <= urb->actual_length - MSG_HEADER_LEN) {
+ msg = urb->transfer_buffer + pos;
+
+ if (!msg->len)
+ break;
+
+ if (pos + msg->len > urb->actual_length) {
+ dev_err(dev->udev->dev.parent, "Format error\n");
+ break;
+ }
+
+ kvaser_usb_handle_message(dev, msg);
+
+ pos += msg->len;
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in->bEndpointAddress),
+ urb->transfer_buffer, RX_BUFFER_SIZE,
+ kvaser_usb_read_bulk_callback, dev);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err == -ENODEV) {
+ for (i = 0; i < dev->nchannels; i++) {
+ if (!dev->nets[i])
+ continue;
+
+ netif_device_detach(dev->nets[i]->netdev);
+ }
+ } else if (err) {
+ dev_err(dev->udev->dev.parent,
+ "Failed resubmitting read bulk urb: %d\n", err);
+ }
+
+ return;
+}
+
+static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
+{
+ int i, err = 0;
+
+ if (dev->rxinitdone)
+ return 0;
+
+ for (i = 0; i < MAX_RX_URBS; i++) {
+ struct urb *urb = NULL;
+ u8 *buf = NULL;
+ dma_addr_t buf_dma;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_warn(dev->udev->dev.parent,
+ "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
+ GFP_KERNEL, &buf_dma);
+ if (!buf) {
+ dev_warn(dev->udev->dev.parent,
+ "No memory left for USB buffer\n");
+ usb_free_urb(urb);
+ err = -ENOMEM;
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in->bEndpointAddress),
+ buf, RX_BUFFER_SIZE,
+ kvaser_usb_read_bulk_callback,
+ dev);
+ urb->transfer_dma = buf_dma;
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &dev->rx_submitted);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ usb_unanchor_urb(urb);
+ usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
+ buf_dma);
+ usb_free_urb(urb);
+ break;
+ }
+
+ dev->rxbuf[i] = buf;
+ dev->rxbuf_dma[i] = buf_dma;
+
+ usb_free_urb(urb);
+ }
+
+ if (i == 0) {
+ dev_warn(dev->udev->dev.parent,
+ "Cannot setup read URBs, error %d\n", err);
+ return err;
+ } else if (i < MAX_RX_URBS) {
+ dev_warn(dev->udev->dev.parent,
+ "RX performances may be slow\n");
+ }
+
+ dev->rxinitdone = true;
+
+ return 0;
+}
+
+static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
+{
+ struct kvaser_msg *msg;
+ int rc;
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->id = CMD_SET_CTRL_MODE;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_ctrl_mode);
+ msg->u.ctrl_mode.tid = 0xff;
+ msg->u.ctrl_mode.channel = priv->channel;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ msg->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
+ else
+ msg->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
+
+ rc = kvaser_usb_send_msg(priv->dev, msg);
+
+ kfree(msg);
+ return rc;
+}
+
+static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
+{
+ int err;
+
+ init_completion(&priv->start_comp);
+
+ err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
+ priv->channel);
+ if (err)
+ return err;
+
+ if (!wait_for_completion_timeout(&priv->start_comp,
+ msecs_to_jiffies(START_TIMEOUT)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int kvaser_usb_open(struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
+ int err;
+
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ err = kvaser_usb_setup_rx_urbs(dev);
+ if (err)
+ goto error;
+
+ err = kvaser_usb_set_opt_mode(priv);
+ if (err)
+ goto error;
+
+ err = kvaser_usb_start_chip(priv);
+ if (err) {
+ netdev_warn(netdev, "Cannot start device, error %d\n", err);
+ goto error;
+ }
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+
+error:
+ close_candev(netdev);
+ return err;
+}
+
+static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
+{
+ int i;
+
+ usb_kill_anchored_urbs(&dev->rx_submitted);
+
+ for (i = 0; i < MAX_RX_URBS; i++)
+ usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
+ dev->rxbuf[i],
+ dev->rxbuf_dma[i]);
+
+ for (i = 0; i < MAX_NET_DEVICES; i++) {
+ struct kvaser_usb_net_priv *priv = dev->nets[i];
+
+ if (priv)
+ kvaser_usb_unlink_tx_urbs(priv);
+ }
+}
+
+static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
+{
+ int err;
+
+ init_completion(&priv->stop_comp);
+
+ err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
+ priv->channel);
+ if (err)
+ return err;
+
+ if (!wait_for_completion_timeout(&priv->stop_comp,
+ msecs_to_jiffies(STOP_TIMEOUT)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
+{
+ struct kvaser_msg *msg;
+ int rc;
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->id = CMD_FLUSH_QUEUE;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_flush_queue);
+ msg->u.flush_queue.channel = priv->channel;
+ msg->u.flush_queue.flags = 0x00;
+
+ rc = kvaser_usb_send_msg(priv->dev, msg);
+
+ kfree(msg);
+ return rc;
+}
+
+static int kvaser_usb_close(struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
+ int err;
+
+ netif_stop_queue(netdev);
+
+ err = kvaser_usb_flush_queue(priv);
+ if (err)
+ netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
+
+ if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel))
+ netdev_warn(netdev, "Cannot reset card, error %d\n", err);
+
+ err = kvaser_usb_stop_chip(priv);
+ if (err)
+ netdev_warn(netdev, "Cannot stop device, error %d\n", err);
+
+ priv->can.state = CAN_STATE_STOPPED;
+ close_candev(priv->netdev);
+
+ return 0;
+}
+
+static void kvaser_usb_write_bulk_callback(struct urb *urb)
+{
+ struct kvaser_usb_tx_urb_context *context = urb->context;
+ struct kvaser_usb_net_priv *priv;
+ struct net_device *netdev;
+
+ if (WARN_ON(!context))
+ return;
+
+ priv = context->priv;
+ netdev = priv->netdev;
+
+ kfree(urb->transfer_buffer);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ if (urb->status)
+ netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
+}
+
+static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ struct kvaser_usb_tx_urb_context *context = NULL;
+ struct urb *urb;
+ void *buf;
+ struct kvaser_msg *msg;
+ int i, err;
+ int ret = NETDEV_TX_OK;
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ stats->tx_dropped++;
+ goto nourbmem;
+ }
+
+ buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
+ if (!buf) {
+ stats->tx_dropped++;
+ goto nobufmem;
+ }
+
+ msg = buf;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
+ msg->u.tx_can.flags = 0;
+ msg->u.tx_can.channel = priv->channel;
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ msg->id = CMD_TX_EXT_MESSAGE;
+ msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
+ msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
+ msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
+ msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
+ msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
+ } else {
+ msg->id = CMD_TX_STD_MESSAGE;
+ msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
+ msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
+ }
+
+ msg->u.tx_can.msg[5] = cf->can_dlc;
+ memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+
+ for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
+ if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+ context = &priv->tx_contexts[i];
+ break;
+ }
+ }
+
+ if (!context) {
+ netdev_warn(netdev, "cannot find free context\n");
+ ret = NETDEV_TX_BUSY;
+ goto releasebuf;
+ }
+
+ context->priv = priv;
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ msg->u.tx_can.tid = context->echo_index;
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out->bEndpointAddress),
+ buf, msg->len,
+ kvaser_usb_write_bulk_callback, context);
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ can_put_echo_skb(skb, netdev, context->echo_index);
+
+ atomic_inc(&priv->active_tx_urbs);
+
+ if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+ netif_stop_queue(netdev);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (unlikely(err)) {
+ can_free_echo_skb(netdev, context->echo_index);
+
+ skb = NULL; /* set to NULL to avoid double free in
+ * dev_kfree_skb(skb) */
+
+ atomic_dec(&priv->active_tx_urbs);
+ usb_unanchor_urb(urb);
+
+ stats->tx_dropped++;
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ netdev_warn(netdev, "Failed tx_urb %d\n", err);
+
+ goto releasebuf;
+ }
+
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+releasebuf:
+ kfree(buf);
+nobufmem:
+ usb_free_urb(urb);
+nourbmem:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static const struct net_device_ops kvaser_usb_netdev_ops = {
+ .ndo_open = kvaser_usb_open,
+ .ndo_stop = kvaser_usb_close,
+ .ndo_start_xmit = kvaser_usb_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static const struct can_bittiming_const kvaser_usb_bittiming_const = {
+ .name = "kvaser_usb",
+ .tseg1_min = KVASER_USB_TSEG1_MIN,
+ .tseg1_max = KVASER_USB_TSEG1_MAX,
+ .tseg2_min = KVASER_USB_TSEG2_MIN,
+ .tseg2_max = KVASER_USB_TSEG2_MAX,
+ .sjw_max = KVASER_USB_SJW_MAX,
+ .brp_min = KVASER_USB_BRP_MIN,
+ .brp_max = KVASER_USB_BRP_MAX,
+ .brp_inc = KVASER_USB_BRP_INC,
+};
+
+static int kvaser_usb_set_bittiming(struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct kvaser_usb *dev = priv->dev;
+ struct kvaser_msg *msg;
+ int rc;
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->id = CMD_SET_BUS_PARAMS;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_busparams);
+ msg->u.busparams.channel = priv->channel;
+ msg->u.busparams.tid = 0xff;
+ msg->u.busparams.bitrate = cpu_to_le32(bt->bitrate);
+ msg->u.busparams.sjw = bt->sjw;
+ msg->u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1;
+ msg->u.busparams.tseg2 = bt->phase_seg2;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ msg->u.busparams.no_samp = 3;
+ else
+ msg->u.busparams.no_samp = 1;
+
+ rc = kvaser_usb_send_msg(dev, msg);
+
+ kfree(msg);
+ return rc;
+}
+
+static int kvaser_usb_set_mode(struct net_device *netdev,
+ enum can_mode mode)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ int err;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP);
+ if (err)
+ return err;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
+ struct can_berr_counter *bec)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+
+ *bec = priv->bec;
+
+ return 0;
+}
+
+static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->nchannels; i++) {
+ if (!dev->nets[i])
+ continue;
+
+ unregister_netdev(dev->nets[i]->netdev);
+ }
+
+ kvaser_usb_unlink_all_urbs(dev);
+
+ for (i = 0; i < dev->nchannels; i++) {
+ if (!dev->nets[i])
+ continue;
+
+ free_candev(dev->nets[i]->netdev);
+ }
+}
+
+static int kvaser_usb_init_one(struct usb_interface *intf,
+ const struct usb_device_id *id, int channel)
+{
+ struct kvaser_usb *dev = usb_get_intfdata(intf);
+ struct net_device *netdev;
+ struct kvaser_usb_net_priv *priv;
+ int i, err;
+
+ netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "Cannot alloc candev\n");
+ return -ENOMEM;
+ }
+
+ priv = netdev_priv(netdev);
+
+ init_completion(&priv->start_comp);
+ init_completion(&priv->stop_comp);
+
+ init_usb_anchor(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+ priv->dev = dev;
+ priv->netdev = netdev;
+ priv->channel = channel;
+
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = CAN_USB_CLOCK;
+ priv->can.bittiming_const = &kvaser_usb_bittiming_const;
+ priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
+ priv->can.do_set_mode = kvaser_usb_set_mode;
+ if (id->driver_info & KVASER_HAS_TXRX_ERRORS)
+ priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+ if (id->driver_info & KVASER_HAS_SILENT_MODE)
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
+
+ netdev->flags |= IFF_ECHO;
+
+ netdev->netdev_ops = &kvaser_usb_netdev_ops;
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+ netdev->dev_id = channel;
+
+ dev->nets[channel] = priv;
+
+ err = register_candev(netdev);
+ if (err) {
+ dev_err(&intf->dev, "Failed to register can device\n");
+ free_candev(netdev);
+ dev->nets[channel] = NULL;
+ return err;
+ }
+
+ netdev_dbg(netdev, "device registered\n");
+
+ return 0;
+}
+
+static int kvaser_usb_get_endpoints(const struct usb_interface *intf,
+ struct usb_endpoint_descriptor **in,
+ struct usb_endpoint_descriptor **out)
+{
+ const struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+
+ iface_desc = &intf->altsetting[0];
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (!*in && usb_endpoint_is_bulk_in(endpoint))
+ *in = endpoint;
+
+ if (!*out && usb_endpoint_is_bulk_out(endpoint))
+ *out = endpoint;
+
+ /* use first bulk endpoint for in and out */
+ if (*in && *out)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int kvaser_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct kvaser_usb *dev;
+ int err = -ENOMEM;
+ int i;
+
+ dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
+ if (err) {
+ dev_err(&intf->dev, "Cannot get usb endpoint(s)");
+ return err;
+ }
+
+ dev->udev = interface_to_usbdev(intf);
+
+ init_usb_anchor(&dev->rx_submitted);
+
+ usb_set_intfdata(intf, dev);
+
+ for (i = 0; i < MAX_NET_DEVICES; i++)
+ kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
+
+ err = kvaser_usb_get_software_info(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get software infos, error %d\n", err);
+ return err;
+ }
+
+ err = kvaser_usb_get_card_info(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get card infos, error %d\n", err);
+ return err;
+ }
+
+ dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
+ ((dev->fw_version >> 24) & 0xff),
+ ((dev->fw_version >> 16) & 0xff),
+ (dev->fw_version & 0xffff));
+
+ for (i = 0; i < dev->nchannels; i++) {
+ err = kvaser_usb_init_one(intf, id, i);
+ if (err) {
+ kvaser_usb_remove_interfaces(dev);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void kvaser_usb_disconnect(struct usb_interface *intf)
+{
+ struct kvaser_usb *dev = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (!dev)
+ return;
+
+ kvaser_usb_remove_interfaces(dev);
+}
+
+static struct usb_driver kvaser_usb_driver = {
+ .name = "kvaser_usb",
+ .probe = kvaser_usb_probe,
+ .disconnect = kvaser_usb_disconnect,
+ .id_table = kvaser_usb_table,
+};
+
+module_usb_driver(kvaser_usb_driver);
+
+MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
+MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 86f26a1ede4..925ab8ec932 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
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);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts->hwtstamp = timeval_to_ktime(tv);
}
netif_rx(skb);
@@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
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)
@@ -646,13 +649,14 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
if ((mc->ptr + rec_len) > mc->end)
goto decode_failed;
- memcpy(cf->data, mc->ptr, rec_len);
+ 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);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
/* push the skb */
netif_rx(skb);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index c4643c400d4..644e6ab8a48 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -386,7 +386,6 @@ static int peak_usb_start(struct peak_usb_device *dev)
buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL);
if (!buf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
err = -ENOMEM;
break;
@@ -442,7 +441,6 @@ static int peak_usb_start(struct peak_usb_device *dev)
buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL);
if (!buf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
err = -ENOMEM;
break;
@@ -465,7 +463,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
if (i < PCAN_USB_MAX_TX_URBS) {
if (i == 0) {
netdev_err(netdev, "couldn't setup any tx URB\n");
- return err;
+ goto err_tx;
}
netdev_warn(netdev, "tx performance may be slow\n");
@@ -474,7 +472,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
if (dev->adapter->dev_start) {
err = dev->adapter->dev_start(dev);
if (err)
- goto failed;
+ goto err_adapter;
}
dev->state |= PCAN_USB_STATE_STARTED;
@@ -483,19 +481,26 @@ static int peak_usb_start(struct peak_usb_device *dev)
if (dev->adapter->dev_set_bus) {
err = dev->adapter->dev_set_bus(dev, 1);
if (err)
- goto failed;
+ goto err_adapter;
}
dev->can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
-failed:
+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;
}
@@ -520,7 +525,6 @@ static int peak_usb_ndo_open(struct net_device *netdev)
return err;
}
- dev->open_time = jiffies;
netif_start_queue(netdev);
return 0;
@@ -576,7 +580,6 @@ static int peak_usb_ndo_stop(struct net_device *netdev)
close_candev(netdev);
- dev->open_time = 0;
dev->can.state = CAN_STATE_STOPPED;
/* can set bus off now */
@@ -636,7 +639,6 @@ static int peak_usb_restart(struct peak_usb_device *dev)
/* also allocate enough space for the commands to send */
buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC);
if (!buf) {
- netdev_err(dev->netdev, "no memory left for async cmd\n");
usb_free_urb(urb);
return -ENOMEM;
}
@@ -661,9 +663,6 @@ 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;
- if (!dev->open_time)
- return -EINVAL;
-
switch (mode) {
case CAN_MODE_START:
err = peak_usb_restart(dev);
@@ -703,6 +702,7 @@ 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,
};
/*
@@ -734,8 +734,6 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
/* allocate a buffer large enough to send commands */
dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
if (!dev->cmd_buf) {
- dev_err(&intf->dev, "%s: couldn't alloc cmd buffer\n",
- PCAN_USB_DRIVER_NAME);
err = -ENOMEM;
goto lbl_set_intf_data;
}
@@ -772,6 +770,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
+ netdev->dev_id = ctrl_idx;
err = register_candev(netdev);
if (err) {
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
index c8e5e91d7cb..073b47ff8ee 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -104,7 +104,6 @@ struct peak_usb_device {
struct can_priv can;
struct peak_usb_adapter *adapter;
unsigned int ctrl_idx;
- int open_time;
u32 state;
struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS];
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index e1626d92511..263dd921edc 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -504,15 +504,24 @@ static int pcan_usb_pro_restart_async(struct peak_usb_device *dev,
return usb_submit_urb(urb, GFP_ATOMIC);
}
-static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
+static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
{
- u8 buffer[16];
+ u8 *buffer;
+ int err;
+
+ buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
buffer[0] = 0;
buffer[1] = !!loaded;
- pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
- PCAN_USBPRO_FCT_DRVLD, buffer, sizeof(buffer));
+ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
+ PCAN_USBPRO_FCT_DRVLD, buffer,
+ PCAN_USBPRO_FCT_DRVLD_REQ_LEN);
+ kfree(buffer);
+
+ return err;
}
static inline
@@ -532,6 +541,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
struct can_frame *can_frame;
struct sk_buff *skb;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
skb = alloc_can_skb(netdev, &can_frame);
if (!skb)
@@ -549,7 +559,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
memcpy(can_frame->data, rx->data, can_frame->can_dlc);
peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
@@ -570,6 +581,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
u8 err_mask = 0;
struct sk_buff *skb;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
/* nothing should be sent while in BUS_OFF state */
if (dev->can.state == CAN_STATE_BUS_OFF)
@@ -664,7 +676,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
dev->can.state = new_state;
peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += can_frame->can_dlc;
@@ -847,21 +860,24 @@ static int pcan_usb_pro_stop(struct peak_usb_device *dev)
*/
static int pcan_usb_pro_init(struct peak_usb_device *dev)
{
- struct pcan_usb_pro_interface *usb_if;
struct pcan_usb_pro_device *pdev =
container_of(dev, struct pcan_usb_pro_device, dev);
+ struct pcan_usb_pro_interface *usb_if = NULL;
+ struct pcan_usb_pro_fwinfo *fi = NULL;
+ struct pcan_usb_pro_blinfo *bi = NULL;
+ int err;
/* do this for 1st channel only */
if (!dev->prev_siblings) {
- struct pcan_usb_pro_fwinfo fi;
- struct pcan_usb_pro_blinfo bi;
- int err;
-
/* allocate netdevices common structure attached to first one */
usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface),
GFP_KERNEL);
- if (!usb_if)
- return -ENOMEM;
+ fi = kmalloc(sizeof(struct pcan_usb_pro_fwinfo), GFP_KERNEL);
+ bi = kmalloc(sizeof(struct pcan_usb_pro_blinfo), GFP_KERNEL);
+ if (!usb_if || !fi || !bi) {
+ err = -ENOMEM;
+ goto err_out;
+ }
/* number of ts msgs to ignore before taking one into account */
usb_if->cm_ignore_count = 5;
@@ -873,34 +889,34 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
*/
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
PCAN_USBPRO_INFO_FW,
- &fi, sizeof(fi));
+ fi, sizeof(*fi));
if (err) {
- kfree(usb_if);
dev_err(dev->netdev->dev.parent,
"unable to read %s firmware info (err %d)\n",
pcan_usb_pro.name, err);
- return err;
+ goto err_out;
}
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
PCAN_USBPRO_INFO_BL,
- &bi, sizeof(bi));
+ bi, sizeof(*bi));
if (err) {
- kfree(usb_if);
dev_err(dev->netdev->dev.parent,
"unable to read %s bootloader info (err %d)\n",
pcan_usb_pro.name, err);
- return err;
+ goto err_out;
}
+ /* tell the device the can driver is running */
+ err = pcan_usb_pro_drv_loaded(dev, 1);
+ if (err)
+ goto err_out;
+
dev_info(dev->netdev->dev.parent,
"PEAK-System %s hwrev %u serial %08X.%08X (%u channels)\n",
pcan_usb_pro.name,
- bi.hw_rev, bi.serial_num_hi, bi.serial_num_lo,
+ bi->hw_rev, bi->serial_num_hi, bi->serial_num_lo,
pcan_usb_pro.ctrl_count);
-
- /* tell the device the can driver is running */
- pcan_usb_pro_drv_loaded(dev, 1);
} else {
usb_if = pcan_usb_pro_dev_if(dev->prev_siblings);
}
@@ -911,7 +927,17 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
/* set LED in default state (end of init phase) */
pcan_usb_pro_set_led(dev, 0, 1);
+ kfree(bi);
+ kfree(fi);
+
return 0;
+
+ err_out:
+ kfree(bi);
+ kfree(fi);
+ kfree(usb_if);
+
+ return err;
}
static void pcan_usb_pro_exit(struct peak_usb_device *dev)
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
index a869918c562..32275af547e 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
@@ -29,6 +29,7 @@
/* 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 {
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
new file mode 100644
index 00000000000..ef674ecb82f
--- /dev/null
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -0,0 +1,1035 @@
+/*
+ * CAN driver for "8 devices" USB2CAN converter
+ *
+ * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at)
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.
+ *
+ * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c
+ * and drivers/net/can/usb/esd_usb2.c
+ *
+ * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de)
+ * for testing and fixing this driver. Also many thanks to "8 devices",
+ * who were very cooperative and answered my questions.
+ */
+
+#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 <linux/can/led.h>
+
+/* driver constants */
+#define MAX_RX_URBS 20
+#define MAX_TX_URBS 20
+#define RX_BUFFER_SIZE 64
+
+/* vendor and product id */
+#define USB_8DEV_VENDOR_ID 0x0483
+#define USB_8DEV_PRODUCT_ID 0x1234
+
+/* endpoints */
+enum usb_8dev_endpoint {
+ USB_8DEV_ENDP_DATA_RX = 1,
+ USB_8DEV_ENDP_DATA_TX,
+ USB_8DEV_ENDP_CMD_RX,
+ USB_8DEV_ENDP_CMD_TX
+};
+
+/* device CAN clock */
+#define USB_8DEV_ABP_CLOCK 32000000
+
+/* setup flags */
+#define USB_8DEV_SILENT 0x01
+#define USB_8DEV_LOOPBACK 0x02
+#define USB_8DEV_DISABLE_AUTO_RESTRANS 0x04
+#define USB_8DEV_STATUS_FRAME 0x08
+
+/* commands */
+enum usb_8dev_cmd {
+ USB_8DEV_RESET = 1,
+ USB_8DEV_OPEN,
+ USB_8DEV_CLOSE,
+ USB_8DEV_SET_SPEED,
+ USB_8DEV_SET_MASK_FILTER,
+ USB_8DEV_GET_STATUS,
+ USB_8DEV_GET_STATISTICS,
+ USB_8DEV_GET_SERIAL,
+ USB_8DEV_GET_SOFTW_VER,
+ USB_8DEV_GET_HARDW_VER,
+ USB_8DEV_RESET_TIMESTAMP,
+ USB_8DEV_GET_SOFTW_HARDW_VER
+};
+
+/* command options */
+#define USB_8DEV_BAUD_MANUAL 0x09
+#define USB_8DEV_CMD_START 0x11
+#define USB_8DEV_CMD_END 0x22
+
+#define USB_8DEV_CMD_SUCCESS 0
+#define USB_8DEV_CMD_ERROR 255
+
+#define USB_8DEV_CMD_TIMEOUT 1000
+
+/* frames */
+#define USB_8DEV_DATA_START 0x55
+#define USB_8DEV_DATA_END 0xAA
+
+#define USB_8DEV_TYPE_CAN_FRAME 0
+#define USB_8DEV_TYPE_ERROR_FRAME 3
+
+#define USB_8DEV_EXTID 0x01
+#define USB_8DEV_RTR 0x02
+#define USB_8DEV_ERR_FLAG 0x04
+
+/* status */
+#define USB_8DEV_STATUSMSG_OK 0x00 /* Normal condition. */
+#define USB_8DEV_STATUSMSG_OVERRUN 0x01 /* Overrun occured when sending */
+#define USB_8DEV_STATUSMSG_BUSLIGHT 0x02 /* Error counter has reached 96 */
+#define USB_8DEV_STATUSMSG_BUSHEAVY 0x03 /* Error count. has reached 128 */
+#define USB_8DEV_STATUSMSG_BUSOFF 0x04 /* Device is in BUSOFF */
+#define USB_8DEV_STATUSMSG_STUFF 0x20 /* Stuff Error */
+#define USB_8DEV_STATUSMSG_FORM 0x21 /* Form Error */
+#define USB_8DEV_STATUSMSG_ACK 0x23 /* Ack Error */
+#define USB_8DEV_STATUSMSG_BIT0 0x24 /* Bit1 Error */
+#define USB_8DEV_STATUSMSG_BIT1 0x25 /* Bit0 Error */
+#define USB_8DEV_STATUSMSG_CRC 0x27 /* CRC Error */
+
+#define USB_8DEV_RP_MASK 0x7F /* Mask for Receive Error Bit */
+
+
+/* table of devices that work with this driver */
+static const struct usb_device_id usb_8dev_table[] = {
+ { USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_8dev_table);
+
+struct usb_8dev_tx_urb_context {
+ struct usb_8dev_priv *priv;
+
+ u32 echo_index;
+ u8 dlc;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_8dev_priv {
+ struct can_priv can; /* must be the first member */
+
+ struct sk_buff *echo_skb[MAX_TX_URBS];
+
+ struct usb_device *udev;
+ struct net_device *netdev;
+
+ atomic_t active_tx_urbs;
+ struct usb_anchor tx_submitted;
+ struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+ struct usb_anchor rx_submitted;
+
+ struct can_berr_counter bec;
+
+ u8 *cmd_msg_buffer;
+
+ struct mutex usb_8dev_cmd_lock;
+
+};
+
+/* tx frame */
+struct __packed usb_8dev_tx_msg {
+ u8 begin;
+ u8 flags; /* RTR and EXT_ID flag */
+ __be32 id; /* upper 3 bits not used */
+ u8 dlc; /* data length code 0-8 bytes */
+ u8 data[8]; /* 64-bit data */
+ u8 end;
+};
+
+/* rx frame */
+struct __packed usb_8dev_rx_msg {
+ u8 begin;
+ u8 type; /* frame type */
+ u8 flags; /* RTR and EXT_ID flag */
+ __be32 id; /* upper 3 bits not used */
+ u8 dlc; /* data length code 0-8 bytes */
+ u8 data[8]; /* 64-bit data */
+ __be32 timestamp; /* 32-bit timestamp */
+ u8 end;
+};
+
+/* command frame */
+struct __packed usb_8dev_cmd_msg {
+ u8 begin;
+ u8 channel; /* unkown - always 0 */
+ u8 command; /* command to execute */
+ u8 opt1; /* optional parameter / return value */
+ u8 opt2; /* optional parameter 2 */
+ u8 data[10]; /* optional parameter and data */
+ u8 end;
+};
+
+static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size)
+{
+ int actual_length;
+
+ return usb_bulk_msg(priv->udev,
+ usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX),
+ msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size,
+ int *actual_length)
+{
+ return usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX),
+ msg, size, actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+/* Send command to device and receive result.
+ * Command was successful when opt1 = 0.
+ */
+static int usb_8dev_send_cmd(struct usb_8dev_priv *priv,
+ struct usb_8dev_cmd_msg *out,
+ struct usb_8dev_cmd_msg *in)
+{
+ int err;
+ int num_bytes_read;
+ struct net_device *netdev;
+
+ netdev = priv->netdev;
+
+ out->begin = USB_8DEV_CMD_START;
+ out->end = USB_8DEV_CMD_END;
+
+ mutex_lock(&priv->usb_8dev_cmd_lock);
+
+ memcpy(priv->cmd_msg_buffer, out,
+ sizeof(struct usb_8dev_cmd_msg));
+
+ err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer,
+ sizeof(struct usb_8dev_cmd_msg));
+ if (err < 0) {
+ netdev_err(netdev, "sending command message failed\n");
+ goto failed;
+ }
+
+ err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer,
+ sizeof(struct usb_8dev_cmd_msg),
+ &num_bytes_read);
+ if (err < 0) {
+ netdev_err(netdev, "no command message answer\n");
+ goto failed;
+ }
+
+ memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg));
+
+ if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END ||
+ num_bytes_read != 16 || in->opt1 != 0)
+ err = -EPROTO;
+
+failed:
+ mutex_unlock(&priv->usb_8dev_cmd_lock);
+ return err;
+}
+
+/* Send open command to device */
+static int usb_8dev_cmd_open(struct usb_8dev_priv *priv)
+{
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct usb_8dev_cmd_msg outmsg;
+ struct usb_8dev_cmd_msg inmsg;
+ u32 ctrlmode = priv->can.ctrlmode;
+ u32 flags = USB_8DEV_STATUS_FRAME;
+ __be32 beflags;
+ __be16 bebrp;
+
+ memset(&outmsg, 0, sizeof(outmsg));
+ outmsg.command = USB_8DEV_OPEN;
+ outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+ outmsg.data[0] = bt->prop_seg + bt->phase_seg1;
+ outmsg.data[1] = bt->phase_seg2;
+ outmsg.data[2] = bt->sjw;
+
+ /* BRP */
+ bebrp = cpu_to_be16((u16)bt->brp);
+ memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
+
+ /* flags */
+ if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ flags |= USB_8DEV_LOOPBACK;
+ if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ flags |= USB_8DEV_SILENT;
+ if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
+
+ beflags = cpu_to_be32(flags);
+ memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
+
+ return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Send close command to device */
+static int usb_8dev_cmd_close(struct usb_8dev_priv *priv)
+{
+ struct usb_8dev_cmd_msg inmsg;
+ struct usb_8dev_cmd_msg outmsg = {
+ .channel = 0,
+ .command = USB_8DEV_CLOSE,
+ .opt1 = 0,
+ .opt2 = 0
+ };
+
+ return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Get firmware and hardware version */
+static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res)
+{
+ struct usb_8dev_cmd_msg inmsg;
+ struct usb_8dev_cmd_msg outmsg = {
+ .channel = 0,
+ .command = USB_8DEV_GET_SOFTW_HARDW_VER,
+ .opt1 = 0,
+ .opt2 = 0
+ };
+
+ int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+ if (err)
+ return err;
+
+ *res = be32_to_cpup((__be32 *)inmsg.data);
+
+ return err;
+}
+
+/* Set network device mode
+ *
+ * Maybe we should leave this function empty, because the device
+ * set mode variable with open command.
+ */
+static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ int err = 0;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ err = usb_8dev_cmd_open(priv);
+ if (err)
+ netdev_warn(netdev, "couldn't start device");
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+/* Read error/status frames */
+static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
+ struct usb_8dev_rx_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats = &priv->netdev->stats;
+
+ /* Error message:
+ * byte 0: Status
+ * byte 1: bit 7: Receive Passive
+ * byte 1: bit 0-6: Receive Error Counter
+ * byte 2: Transmit Error Counter
+ * byte 3: Always 0 (maybe reserved for future use)
+ */
+
+ u8 state = msg->data[0];
+ u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
+ u8 txerr = msg->data[2];
+ int rx_errors = 0;
+ int tx_errors = 0;
+
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (!skb)
+ return;
+
+ switch (state) {
+ case USB_8DEV_STATUSMSG_OK:
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_ACTIVE;
+ break;
+ case USB_8DEV_STATUSMSG_BUSOFF:
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(priv->netdev);
+ break;
+ case USB_8DEV_STATUSMSG_OVERRUN:
+ case USB_8DEV_STATUSMSG_BUSLIGHT:
+ case USB_8DEV_STATUSMSG_BUSHEAVY:
+ cf->can_id |= CAN_ERR_CRTL;
+ break;
+ default:
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ priv->can.can_stats.bus_error++;
+ break;
+ }
+
+ switch (state) {
+ case USB_8DEV_STATUSMSG_OK:
+ case USB_8DEV_STATUSMSG_BUSOFF:
+ break;
+ case USB_8DEV_STATUSMSG_ACK:
+ cf->can_id |= CAN_ERR_ACK;
+ tx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_CRC:
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_BIT0:
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ tx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_BIT1:
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ tx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_FORM:
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_STUFF:
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_OVERRUN:
+ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_over_errors++;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_BUSLIGHT:
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->data[1] = (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ priv->can.can_stats.error_warning++;
+ break;
+ case USB_8DEV_STATUSMSG_BUSHEAVY:
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ cf->data[1] = (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_PASSIVE :
+ CAN_ERR_CRTL_RX_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ netdev_warn(priv->netdev,
+ "Unknown status/error message (%d)\n", state);
+ break;
+ }
+
+ if (tx_errors) {
+ cf->data[2] |= CAN_ERR_PROT_TX;
+ stats->tx_errors++;
+ }
+
+ if (rx_errors)
+ stats->rx_errors++;
+
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+
+ priv->bec.txerr = txerr;
+ priv->bec.rxerr = rxerr;
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+/* Read data and status frames */
+static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
+ struct usb_8dev_rx_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats = &priv->netdev->stats;
+
+ if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
+ msg->flags == USB_8DEV_ERR_FLAG) {
+ usb_8dev_rx_err_msg(priv, msg);
+ } else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
+ skb = alloc_can_skb(priv->netdev, &cf);
+ if (!skb)
+ return;
+
+ cf->can_id = be32_to_cpu(msg->id);
+ cf->can_dlc = get_can_dlc(msg->dlc & 0xF);
+
+ if (msg->flags & USB_8DEV_EXTID)
+ cf->can_id |= CAN_EFF_FLAG;
+
+ if (msg->flags & USB_8DEV_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cf->data, msg->data, cf->can_dlc);
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ can_led_event(priv->netdev, CAN_LED_EVENT_RX);
+ } else {
+ netdev_warn(priv->netdev, "frame type %d unknown",
+ msg->type);
+ }
+
+}
+
+/* Callback for reading data from device
+ *
+ * Check urb status, call read function and resubmit urb read operation.
+ */
+static void usb_8dev_read_bulk_callback(struct urb *urb)
+{
+ struct usb_8dev_priv *priv = urb->context;
+ struct net_device *netdev;
+ int retval;
+ int pos = 0;
+
+ netdev = priv->netdev;
+
+ if (!netif_device_present(netdev))
+ return;
+
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ netdev_info(netdev, "Rx URB aborted (%d)\n",
+ urb->status);
+ goto resubmit_urb;
+ }
+
+ while (pos < urb->actual_length) {
+ struct usb_8dev_rx_msg *msg;
+
+ if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) {
+ netdev_err(priv->netdev, "format error\n");
+ break;
+ }
+
+ msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos);
+ usb_8dev_rx_can_msg(priv, msg);
+
+ pos += sizeof(struct usb_8dev_rx_msg);
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
+ urb->transfer_buffer, RX_BUFFER_SIZE,
+ usb_8dev_read_bulk_callback, priv);
+
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (retval == -ENODEV)
+ netif_device_detach(netdev);
+ else if (retval)
+ netdev_err(netdev,
+ "failed resubmitting read bulk urb: %d\n", retval);
+}
+
+/* Callback handler for write operations
+ *
+ * Free allocated buffers, check transmit status and
+ * calculate statistic.
+ */
+static void usb_8dev_write_bulk_callback(struct urb *urb)
+{
+ struct usb_8dev_tx_urb_context *context = urb->context;
+ struct usb_8dev_priv *priv;
+ struct net_device *netdev;
+
+ BUG_ON(!context);
+
+ priv = context->priv;
+ netdev = priv->netdev;
+
+ /* free up our allocated buffer */
+ usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+
+ atomic_dec(&priv->active_tx_urbs);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ if (urb->status)
+ netdev_info(netdev, "Tx URB aborted (%d)\n",
+ urb->status);
+
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += context->dlc;
+
+ can_get_echo_skb(netdev, context->echo_index);
+
+ can_led_event(netdev, CAN_LED_EVENT_TX);
+
+ /* Release context */
+ context->echo_index = MAX_TX_URBS;
+
+ netif_wake_queue(netdev);
+}
+
+/* Send data to device */
+static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *) skb->data;
+ struct usb_8dev_tx_msg *msg;
+ struct urb *urb;
+ struct usb_8dev_tx_urb_context *context = NULL;
+ u8 *buf;
+ int i, err;
+ size_t size = sizeof(struct usb_8dev_tx_msg);
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ /* create a URB, and a buffer for it, and copy the data to the URB */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ goto nomem;
+ }
+
+ buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ goto nomembuf;
+ }
+
+ memset(buf, 0, size);
+
+ msg = (struct usb_8dev_tx_msg *)buf;
+ msg->begin = USB_8DEV_DATA_START;
+ msg->flags = 0x00;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ msg->flags |= USB_8DEV_RTR;
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ msg->flags |= USB_8DEV_EXTID;
+
+ msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK);
+ msg->dlc = cf->can_dlc;
+ memcpy(msg->data, cf->data, cf->can_dlc);
+ msg->end = USB_8DEV_DATA_END;
+
+ for (i = 0; i < MAX_TX_URBS; i++) {
+ if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+ context = &priv->tx_contexts[i];
+ break;
+ }
+ }
+
+ /* May never happen! When this happens we'd more URBs in flight as
+ * allowed (MAX_TX_URBS).
+ */
+ if (!context)
+ goto nofreecontext;
+
+ context->priv = priv;
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ usb_fill_bulk_urb(urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX),
+ buf, size, usb_8dev_write_bulk_callback, context);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ can_put_echo_skb(skb, netdev, context->echo_index);
+
+ atomic_inc(&priv->active_tx_urbs);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (unlikely(err))
+ goto failed;
+ else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+ /* Slow down tx path */
+ netif_stop_queue(netdev);
+
+ /* Release our reference to this URB, the USB core will eventually free
+ * it entirely.
+ */
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+nofreecontext:
+ usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+
+ netdev_warn(netdev, "couldn't find free context");
+
+ return NETDEV_TX_BUSY;
+
+failed:
+ can_free_echo_skb(netdev, context->echo_index);
+
+ usb_unanchor_urb(urb);
+ usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+ atomic_dec(&priv->active_tx_urbs);
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ netdev_warn(netdev, "failed tx_urb %d\n", err);
+
+nomembuf:
+ usb_free_urb(urb);
+
+nomem:
+ dev_kfree_skb(skb);
+ stats->tx_dropped++;
+
+ return NETDEV_TX_OK;
+}
+
+static int usb_8dev_get_berr_counter(const struct net_device *netdev,
+ struct can_berr_counter *bec)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+
+ bec->txerr = priv->bec.txerr;
+ bec->rxerr = priv->bec.rxerr;
+
+ return 0;
+}
+
+/* Start USB device */
+static int usb_8dev_start(struct usb_8dev_priv *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ int err, i;
+
+ for (i = 0; i < MAX_RX_URBS; i++) {
+ struct urb *urb = NULL;
+ u8 *buf;
+
+ /* create a URB, and a buffer for it */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ usb_free_urb(urb);
+ err = -ENOMEM;
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev,
+ USB_8DEV_ENDP_DATA_RX),
+ buf, RX_BUFFER_SIZE,
+ usb_8dev_read_bulk_callback, priv);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &priv->rx_submitted);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ usb_unanchor_urb(urb);
+ usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
+ urb->transfer_dma);
+ usb_free_urb(urb);
+ break;
+ }
+
+ /* Drop reference, USB core will take care of freeing it */
+ usb_free_urb(urb);
+ }
+
+ /* Did we submit any URBs */
+ if (i == 0) {
+ netdev_warn(netdev, "couldn't setup read URBs\n");
+ return err;
+ }
+
+ /* Warn if we've couldn't transmit all the URBs */
+ if (i < MAX_RX_URBS)
+ netdev_warn(netdev, "rx performance may be slow\n");
+
+ err = usb_8dev_cmd_open(priv);
+ if (err)
+ goto failed;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+
+failed:
+ if (err == -ENODEV)
+ netif_device_detach(priv->netdev);
+
+ netdev_warn(netdev, "couldn't submit control: %d\n", err);
+
+ return err;
+}
+
+/* Open USB device */
+static int usb_8dev_open(struct net_device *netdev)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ int err;
+
+ /* common open */
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ can_led_event(netdev, CAN_LED_EVENT_OPEN);
+
+ /* finally start device */
+ err = usb_8dev_start(priv);
+ if (err) {
+ if (err == -ENODEV)
+ netif_device_detach(priv->netdev);
+
+ netdev_warn(netdev, "couldn't start device: %d\n",
+ err);
+
+ close_candev(netdev);
+
+ return err;
+ }
+
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+static void unlink_all_urbs(struct usb_8dev_priv *priv)
+{
+ int i;
+
+ usb_kill_anchored_urbs(&priv->rx_submitted);
+
+ usb_kill_anchored_urbs(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+/* Close USB device */
+static int usb_8dev_close(struct net_device *netdev)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ int err = 0;
+
+ /* Send CLOSE command to CAN controller */
+ err = usb_8dev_cmd_close(priv);
+ if (err)
+ netdev_warn(netdev, "couldn't stop device");
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ netif_stop_queue(netdev);
+
+ /* Stop polling */
+ unlink_all_urbs(priv);
+
+ close_candev(netdev);
+
+ can_led_event(netdev, CAN_LED_EVENT_STOP);
+
+ return err;
+}
+
+static const struct net_device_ops usb_8dev_netdev_ops = {
+ .ndo_open = usb_8dev_open,
+ .ndo_stop = usb_8dev_close,
+ .ndo_start_xmit = usb_8dev_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
+};
+
+static const struct can_bittiming_const usb_8dev_bittiming_const = {
+ .name = "usb_8dev",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+/* Probe USB device
+ *
+ * Check device and firmware.
+ * Set supported modes and bittiming constants.
+ * Allocate some memory.
+ */
+static int usb_8dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct net_device *netdev;
+ struct usb_8dev_priv *priv;
+ int i, err = -ENOMEM;
+ u32 version;
+ char buf[18];
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ /* product id looks strange, better we also check iProduct string */
+ if (usb_string(usbdev, usbdev->descriptor.iProduct, buf,
+ sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) {
+ dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n");
+ return -ENODEV;
+ }
+
+ netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "Couldn't alloc candev\n");
+ return -ENOMEM;
+ }
+
+ priv = netdev_priv(netdev);
+
+ priv->udev = usbdev;
+ priv->netdev = netdev;
+
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = USB_8DEV_ABP_CLOCK;
+ priv->can.bittiming_const = &usb_8dev_bittiming_const;
+ priv->can.do_set_mode = usb_8dev_set_mode;
+ priv->can.do_get_berr_counter = usb_8dev_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_ONE_SHOT;
+
+ netdev->netdev_ops = &usb_8dev_netdev_ops;
+
+ netdev->flags |= IFF_ECHO; /* we support local echo */
+
+ init_usb_anchor(&priv->rx_submitted);
+
+ init_usb_anchor(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+ priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
+ GFP_KERNEL);
+ if (!priv->cmd_msg_buffer)
+ goto cleanup_candev;
+
+ usb_set_intfdata(intf, priv);
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ mutex_init(&priv->usb_8dev_cmd_lock);
+
+ err = register_candev(netdev);
+ if (err) {
+ netdev_err(netdev,
+ "couldn't register CAN device: %d\n", err);
+ goto cleanup_cmd_msg_buffer;
+ }
+
+ err = usb_8dev_cmd_version(priv, &version);
+ if (err) {
+ netdev_err(netdev, "can't get firmware version\n");
+ goto cleanup_unregister_candev;
+ } else {
+ netdev_info(netdev,
+ "firmware: %d.%d, hardware: %d.%d\n",
+ (version>>24) & 0xff, (version>>16) & 0xff,
+ (version>>8) & 0xff, version & 0xff);
+ }
+
+ devm_can_led_init(netdev);
+
+ return 0;
+
+cleanup_unregister_candev:
+ unregister_netdev(priv->netdev);
+
+cleanup_cmd_msg_buffer:
+ kfree(priv->cmd_msg_buffer);
+
+cleanup_candev:
+ free_candev(netdev);
+
+ return err;
+
+}
+
+/* Called by the usb core when driver is unloaded or device is removed */
+static void usb_8dev_disconnect(struct usb_interface *intf)
+{
+ struct usb_8dev_priv *priv = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (priv) {
+ netdev_info(priv->netdev, "device disconnected\n");
+
+ unregister_netdev(priv->netdev);
+ free_candev(priv->netdev);
+
+ unlink_all_urbs(priv);
+ }
+
+}
+
+static struct usb_driver usb_8dev_driver = {
+ .name = "usb_8dev",
+ .probe = usb_8dev_probe,
+ .disconnect = usb_8dev_disconnect,
+ .id_table = usb_8dev_table,
+};
+
+module_usb_driver(usb_8dev_driver);
+
+MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>");
+MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 0a2a5ee79a1..4e94057ef5c 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -46,6 +46,7 @@
#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>
@@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cfd->len;
}
- kfree_skb(skb);
+ consume_skb(skb);
return NETDEV_TX_OK;
}
/* perform standard echo handling for CAN network interfaces */
if (loop) {
- struct sock *srcsk = skb->sk;
- skb = skb_share_check(skb, GFP_ATOMIC);
+ skb = can_create_echo_skb(skb);
if (!skb)
return NETDEV_TX_OK;
/* receive with packet counting */
- skb->sk = srcsk;
vcan_rx(skb, dev);
} else {
/* no looped packets => no counting */
- kfree_skb(skb);
+ consume_skb(skb);
}
return NETDEV_TX_OK;
}
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
new file mode 100644
index 00000000000..5e8b5609c06
--- /dev/null
+++ b/drivers/net/can/xilinx_can.c
@@ -0,0 +1,1208 @@
+/* Xilinx CAN device driver
+ *
+ * Copyright (C) 2012 - 2014 Xilinx, Inc.
+ * Copyright (C) 2009 PetaLogix. All rights reserved.
+ *
+ * Description:
+ * This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/led.h>
+
+#define DRIVER_NAME "xilinx_can"
+
+/* CAN registers set */
+enum xcan_reg {
+ XCAN_SRR_OFFSET = 0x00, /* Software reset */
+ XCAN_MSR_OFFSET = 0x04, /* Mode select */
+ XCAN_BRPR_OFFSET = 0x08, /* Baud rate prescaler */
+ XCAN_BTR_OFFSET = 0x0C, /* Bit timing */
+ XCAN_ECR_OFFSET = 0x10, /* Error counter */
+ XCAN_ESR_OFFSET = 0x14, /* Error status */
+ XCAN_SR_OFFSET = 0x18, /* Status */
+ XCAN_ISR_OFFSET = 0x1C, /* Interrupt status */
+ XCAN_IER_OFFSET = 0x20, /* Interrupt enable */
+ XCAN_ICR_OFFSET = 0x24, /* Interrupt clear */
+ XCAN_TXFIFO_ID_OFFSET = 0x30,/* TX FIFO ID */
+ XCAN_TXFIFO_DLC_OFFSET = 0x34, /* TX FIFO DLC */
+ XCAN_TXFIFO_DW1_OFFSET = 0x38, /* TX FIFO Data Word 1 */
+ XCAN_TXFIFO_DW2_OFFSET = 0x3C, /* TX FIFO Data Word 2 */
+ XCAN_RXFIFO_ID_OFFSET = 0x50, /* RX FIFO ID */
+ XCAN_RXFIFO_DLC_OFFSET = 0x54, /* RX FIFO DLC */
+ XCAN_RXFIFO_DW1_OFFSET = 0x58, /* RX FIFO Data Word 1 */
+ XCAN_RXFIFO_DW2_OFFSET = 0x5C, /* RX FIFO Data Word 2 */
+};
+
+/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */
+#define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */
+#define XCAN_SRR_RESET_MASK 0x00000001 /* Soft Reset the CAN core */
+#define XCAN_MSR_LBACK_MASK 0x00000002 /* Loop back mode select */
+#define XCAN_MSR_SLEEP_MASK 0x00000001 /* Sleep mode select */
+#define XCAN_BRPR_BRP_MASK 0x000000FF /* Baud rate prescaler */
+#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */
+#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */
+#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */
+#define XCAN_ECR_REC_MASK 0x0000FF00 /* Receive error counter */
+#define XCAN_ECR_TEC_MASK 0x000000FF /* Transmit error counter */
+#define XCAN_ESR_ACKER_MASK 0x00000010 /* ACK error */
+#define XCAN_ESR_BERR_MASK 0x00000008 /* Bit error */
+#define XCAN_ESR_STER_MASK 0x00000004 /* Stuff error */
+#define XCAN_ESR_FMER_MASK 0x00000002 /* Form error */
+#define XCAN_ESR_CRCER_MASK 0x00000001 /* CRC error */
+#define XCAN_SR_TXFLL_MASK 0x00000400 /* TX FIFO is full */
+#define XCAN_SR_ESTAT_MASK 0x00000180 /* Error status */
+#define XCAN_SR_ERRWRN_MASK 0x00000040 /* Error warning */
+#define XCAN_SR_NORMAL_MASK 0x00000008 /* Normal mode */
+#define XCAN_SR_LBACK_MASK 0x00000002 /* Loop back mode */
+#define XCAN_SR_CONFIG_MASK 0x00000001 /* Configuration mode */
+#define XCAN_IXR_TXFEMP_MASK 0x00004000 /* TX FIFO Empty */
+#define XCAN_IXR_WKUP_MASK 0x00000800 /* Wake up interrupt */
+#define XCAN_IXR_SLP_MASK 0x00000400 /* Sleep interrupt */
+#define XCAN_IXR_BSOFF_MASK 0x00000200 /* Bus off interrupt */
+#define XCAN_IXR_ERROR_MASK 0x00000100 /* Error interrupt */
+#define XCAN_IXR_RXNEMP_MASK 0x00000080 /* RX FIFO NotEmpty intr */
+#define XCAN_IXR_RXOFLW_MASK 0x00000040 /* RX FIFO Overflow intr */
+#define XCAN_IXR_RXOK_MASK 0x00000010 /* Message received intr */
+#define XCAN_IXR_TXFLL_MASK 0x00000004 /* Tx FIFO Full intr */
+#define XCAN_IXR_TXOK_MASK 0x00000002 /* TX successful intr */
+#define XCAN_IXR_ARBLST_MASK 0x00000001 /* Arbitration lost intr */
+#define XCAN_IDR_ID1_MASK 0xFFE00000 /* Standard msg identifier */
+#define XCAN_IDR_SRR_MASK 0x00100000 /* Substitute remote TXreq */
+#define XCAN_IDR_IDE_MASK 0x00080000 /* Identifier extension */
+#define XCAN_IDR_ID2_MASK 0x0007FFFE /* Extended message ident */
+#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */
+#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */
+
+#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\
+ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \
+ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \
+ XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK)
+
+/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
+#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */
+#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */
+#define XCAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */
+#define XCAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */
+#define XCAN_DLCR_DLC_SHIFT 28 /* Data length code */
+#define XCAN_ESR_REC_SHIFT 8 /* Rx Error Count */
+
+/* CAN frame length constants */
+#define XCAN_FRAME_MAX_DATA_LEN 8
+#define XCAN_TIMEOUT (1 * HZ)
+
+/**
+ * struct xcan_priv - This definition define CAN driver instance
+ * @can: CAN private data structure.
+ * @tx_head: Tx CAN packets ready to send on the queue
+ * @tx_tail: Tx CAN packets successfully sended on the queue
+ * @tx_max: Maximum number packets the driver can send
+ * @napi: NAPI structure
+ * @read_reg: For reading data from CAN registers
+ * @write_reg: For writing data to CAN registers
+ * @dev: Network device data structure
+ * @reg_base: Ioremapped address to registers
+ * @irq_flags: For request_irq()
+ * @bus_clk: Pointer to struct clk
+ * @can_clk: Pointer to struct clk
+ */
+struct xcan_priv {
+ struct can_priv can;
+ unsigned int tx_head;
+ unsigned int tx_tail;
+ unsigned int tx_max;
+ struct napi_struct napi;
+ u32 (*read_reg)(const struct xcan_priv *priv, enum xcan_reg reg);
+ void (*write_reg)(const struct xcan_priv *priv, enum xcan_reg reg,
+ u32 val);
+ struct net_device *dev;
+ void __iomem *reg_base;
+ unsigned long irq_flags;
+ struct clk *bus_clk;
+ struct clk *can_clk;
+};
+
+/* CAN Bittiming constants as per Xilinx CAN specs */
+static const struct can_bittiming_const xcan_bittiming_const = {
+ .name = DRIVER_NAME,
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+};
+
+/**
+ * xcan_write_reg_le - Write a value to the device register little endian
+ * @priv: Driver private data structure
+ * @reg: Register offset
+ * @val: Value to write at the Register offset
+ *
+ * Write data to the paricular CAN register
+ */
+static void xcan_write_reg_le(const struct xcan_priv *priv, enum xcan_reg reg,
+ u32 val)
+{
+ iowrite32(val, priv->reg_base + reg);
+}
+
+/**
+ * xcan_read_reg_le - Read a value from the device register little endian
+ * @priv: Driver private data structure
+ * @reg: Register offset
+ *
+ * Read data from the particular CAN register
+ * Return: value read from the CAN register
+ */
+static u32 xcan_read_reg_le(const struct xcan_priv *priv, enum xcan_reg reg)
+{
+ return ioread32(priv->reg_base + reg);
+}
+
+/**
+ * xcan_write_reg_be - Write a value to the device register big endian
+ * @priv: Driver private data structure
+ * @reg: Register offset
+ * @val: Value to write at the Register offset
+ *
+ * Write data to the paricular CAN register
+ */
+static void xcan_write_reg_be(const struct xcan_priv *priv, enum xcan_reg reg,
+ u32 val)
+{
+ iowrite32be(val, priv->reg_base + reg);
+}
+
+/**
+ * xcan_read_reg_be - Read a value from the device register big endian
+ * @priv: Driver private data structure
+ * @reg: Register offset
+ *
+ * Read data from the particular CAN register
+ * Return: value read from the CAN register
+ */
+static u32 xcan_read_reg_be(const struct xcan_priv *priv, enum xcan_reg reg)
+{
+ return ioread32be(priv->reg_base + reg);
+}
+
+/**
+ * set_reset_mode - Resets the CAN device mode
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver reset mode routine.The driver
+ * enters into configuration mode.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int set_reset_mode(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ unsigned long timeout;
+
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+
+ timeout = jiffies + XCAN_TIMEOUT;
+ while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_CONFIG_MASK)) {
+ if (time_after(jiffies, timeout)) {
+ netdev_warn(ndev, "timed out for config mode\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(500, 10000);
+ }
+
+ return 0;
+}
+
+/**
+ * xcan_set_bittiming - CAN set bit timing routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver set bittiming routine.
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_set_bittiming(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ u32 btr0, btr1;
+ u32 is_config_mode;
+
+ /* Check whether Xilinx CAN is in configuration mode.
+ * It cannot set bit timing if Xilinx CAN is not in configuration mode.
+ */
+ is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) &
+ XCAN_SR_CONFIG_MASK;
+ if (!is_config_mode) {
+ netdev_alert(ndev,
+ "BUG! Cannot set bittiming - CAN is not in config mode\n");
+ return -EPERM;
+ }
+
+ /* Setting Baud Rate prescalar value in BRPR Register */
+ btr0 = (bt->brp - 1);
+
+ /* Setting Time Segment 1 in BTR Register */
+ btr1 = (bt->prop_seg + bt->phase_seg1 - 1);
+
+ /* Setting Time Segment 2 in BTR Register */
+ btr1 |= (bt->phase_seg2 - 1) << XCAN_BTR_TS2_SHIFT;
+
+ /* Setting Synchronous jump width in BTR Register */
+ btr1 |= (bt->sjw - 1) << XCAN_BTR_SJW_SHIFT;
+
+ priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0);
+ priv->write_reg(priv, XCAN_BTR_OFFSET, btr1);
+
+ netdev_dbg(ndev, "BRPR=0x%08x, BTR=0x%08x\n",
+ priv->read_reg(priv, XCAN_BRPR_OFFSET),
+ priv->read_reg(priv, XCAN_BTR_OFFSET));
+
+ return 0;
+}
+
+/**
+ * xcan_chip_start - This the drivers start routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the drivers start routine.
+ * Based on the State of the CAN device it puts
+ * the CAN device into a proper mode.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_chip_start(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 err, reg_msr, reg_sr_mask;
+ unsigned long timeout;
+
+ /* Check if it is in reset mode */
+ err = set_reset_mode(ndev);
+ if (err < 0)
+ return err;
+
+ err = xcan_set_bittiming(ndev);
+ if (err < 0)
+ return err;
+
+ /* Enable interrupts */
+ priv->write_reg(priv, XCAN_IER_OFFSET, XCAN_INTR_ALL);
+
+ /* Check whether it is loopback mode or normal mode */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ reg_msr = XCAN_MSR_LBACK_MASK;
+ reg_sr_mask = XCAN_SR_LBACK_MASK;
+ } else {
+ reg_msr = 0x0;
+ reg_sr_mask = XCAN_SR_NORMAL_MASK;
+ }
+
+ priv->write_reg(priv, XCAN_MSR_OFFSET, reg_msr);
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
+
+ timeout = jiffies + XCAN_TIMEOUT;
+ while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & reg_sr_mask)) {
+ if (time_after(jiffies, timeout)) {
+ netdev_warn(ndev,
+ "timed out for correct mode\n");
+ return -ETIMEDOUT;
+ }
+ }
+ netdev_dbg(ndev, "status:#x%08x\n",
+ priv->read_reg(priv, XCAN_SR_OFFSET));
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
+}
+
+/**
+ * xcan_do_set_mode - This sets the mode of the driver
+ * @ndev: Pointer to net_device structure
+ * @mode: Tells the mode of the driver
+ *
+ * This check the drivers state and calls the
+ * the corresponding modes to set.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ int ret;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ ret = xcan_chip_start(ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "xcan_chip_start failed!\n");
+ return ret;
+ }
+ netif_wake_queue(ndev);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * xcan_start_xmit - Starts the transmission
+ * @skb: sk_buff pointer that contains data to be Txed
+ * @ndev: Pointer to net_device structure
+ *
+ * This function is invoked from upper layers to initiate transmission. This
+ * function uses the next available free txbuff and populates their fields to
+ * start the transmission.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 id, dlc, data[2] = {0, 0};
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ /* Check if the TX buffer is full */
+ if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) &
+ XCAN_SR_TXFLL_MASK)) {
+ netif_stop_queue(ndev);
+ netdev_err(ndev, "BUG!, TX FIFO full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Watch carefully on the bit sequence */
+ if (cf->can_id & CAN_EFF_FLAG) {
+ /* Extended CAN ID format */
+ id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) &
+ XCAN_IDR_ID2_MASK;
+ id |= (((cf->can_id & CAN_EFF_MASK) >>
+ (CAN_EFF_ID_BITS-CAN_SFF_ID_BITS)) <<
+ XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK;
+
+ /* The substibute remote TX request bit should be "1"
+ * for extended frames as in the Xilinx CAN datasheet
+ */
+ id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ /* Extended frames remote TX request */
+ id |= XCAN_IDR_RTR_MASK;
+ } else {
+ /* Standard CAN ID format */
+ id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) &
+ XCAN_IDR_ID1_MASK;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ /* Standard frames remote TX request */
+ id |= XCAN_IDR_SRR_MASK;
+ }
+
+ dlc = cf->can_dlc << XCAN_DLCR_DLC_SHIFT;
+
+ if (cf->can_dlc > 0)
+ data[0] = be32_to_cpup((__be32 *)(cf->data + 0));
+ if (cf->can_dlc > 4)
+ data[1] = be32_to_cpup((__be32 *)(cf->data + 4));
+
+ can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max);
+ priv->tx_head++;
+
+ /* Write the Frame to Xilinx CAN TX FIFO */
+ priv->write_reg(priv, XCAN_TXFIFO_ID_OFFSET, id);
+ /* If the CAN frame is RTR frame this write triggers tranmission */
+ priv->write_reg(priv, XCAN_TXFIFO_DLC_OFFSET, dlc);
+ if (!(cf->can_id & CAN_RTR_FLAG)) {
+ priv->write_reg(priv, XCAN_TXFIFO_DW1_OFFSET, data[0]);
+ /* If the CAN frame is Standard/Extended frame this
+ * write triggers tranmission
+ */
+ priv->write_reg(priv, XCAN_TXFIFO_DW2_OFFSET, data[1]);
+ stats->tx_bytes += cf->can_dlc;
+ }
+
+ /* Check if the TX buffer is full */
+ if ((priv->tx_head - priv->tx_tail) == priv->tx_max)
+ netif_stop_queue(ndev);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * xcan_rx - Is called from CAN isr to complete the received
+ * frame processing
+ * @ndev: Pointer to net_device structure
+ *
+ * This function is invoked from the CAN isr(poll) to process the Rx frames. It
+ * does minimal processing and invokes "netif_receive_skb" to complete further
+ * processing.
+ * Return: 1 on success and 0 on failure.
+ */
+static int xcan_rx(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 id_xcan, dlc, data[2] = {0, 0};
+
+ skb = alloc_can_skb(ndev, &cf);
+ if (unlikely(!skb)) {
+ stats->rx_dropped++;
+ return 0;
+ }
+
+ /* Read a frame from Xilinx zynq CANPS */
+ id_xcan = priv->read_reg(priv, XCAN_RXFIFO_ID_OFFSET);
+ dlc = priv->read_reg(priv, XCAN_RXFIFO_DLC_OFFSET) >>
+ XCAN_DLCR_DLC_SHIFT;
+
+ /* Change Xilinx CAN data length format to socketCAN data format */
+ cf->can_dlc = get_can_dlc(dlc);
+
+ /* Change Xilinx CAN ID format to socketCAN ID format */
+ if (id_xcan & XCAN_IDR_IDE_MASK) {
+ /* The received frame is an Extended format frame */
+ cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
+ cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
+ XCAN_IDR_ID2_SHIFT;
+ cf->can_id |= CAN_EFF_FLAG;
+ if (id_xcan & XCAN_IDR_RTR_MASK)
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ /* The received frame is a standard format frame */
+ cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
+ XCAN_IDR_ID1_SHIFT;
+ if (id_xcan & XCAN_IDR_SRR_MASK)
+ cf->can_id |= CAN_RTR_FLAG;
+ }
+
+ if (!(id_xcan & XCAN_IDR_SRR_MASK)) {
+ data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET);
+ data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET);
+
+ /* Change Xilinx CAN data format to socketCAN data format */
+ if (cf->can_dlc > 0)
+ *(__be32 *)(cf->data) = cpu_to_be32(data[0]);
+ if (cf->can_dlc > 4)
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(data[1]);
+ }
+
+ stats->rx_bytes += cf->can_dlc;
+ stats->rx_packets++;
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+/**
+ * xcan_err_interrupt - error frame Isr
+ * @ndev: net_device pointer
+ * @isr: interrupt status register value
+ *
+ * This is the CAN error interrupt and it will
+ * check the the type of error and forward the error
+ * frame to upper layers.
+ */
+static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 err_status, status, txerr = 0, rxerr = 0;
+
+ skb = alloc_can_err_skb(ndev, &cf);
+
+ err_status = priv->read_reg(priv, XCAN_ESR_OFFSET);
+ priv->write_reg(priv, XCAN_ESR_OFFSET, err_status);
+ txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK;
+ rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) &
+ XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT);
+ status = priv->read_reg(priv, XCAN_SR_OFFSET);
+
+ if (isr & XCAN_IXR_BSOFF_MASK) {
+ priv->can.state = CAN_STATE_BUS_OFF;
+ priv->can.can_stats.bus_off++;
+ /* Leave device in Config Mode in bus-off state */
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+ can_bus_off(ndev);
+ if (skb)
+ cf->can_id |= CAN_ERR_BUSOFF;
+ } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) {
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (rxerr > 127) ?
+ CAN_ERR_CRTL_RX_PASSIVE :
+ CAN_ERR_CRTL_TX_PASSIVE;
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+ }
+ } else if (status & XCAN_SR_ERRWRN_MASK) {
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+ }
+ }
+
+ /* Check for Arbitration lost interrupt */
+ if (isr & XCAN_IXR_ARBLST_MASK) {
+ priv->can.can_stats.arbitration_lost++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_LOSTARB;
+ cf->data[0] = CAN_ERR_LOSTARB_UNSPEC;
+ }
+ }
+
+ /* Check for RX FIFO Overflow interrupt */
+ if (isr & XCAN_IXR_RXOFLW_MASK) {
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+ if (skb) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ }
+ }
+
+ /* Check for error interrupt */
+ if (isr & XCAN_IXR_ERROR_MASK) {
+ if (skb) {
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+ }
+
+ /* Check for Ack error interrupt */
+ if (err_status & XCAN_ESR_ACKER_MASK) {
+ stats->tx_errors++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_ACK;
+ cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ }
+ }
+
+ /* Check for Bit error interrupt */
+ if (err_status & XCAN_ESR_BERR_MASK) {
+ stats->tx_errors++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_BIT;
+ }
+ }
+
+ /* Check for Stuff error interrupt */
+ if (err_status & XCAN_ESR_STER_MASK) {
+ stats->rx_errors++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_STUFF;
+ }
+ }
+
+ /* Check for Form error interrupt */
+ if (err_status & XCAN_ESR_FMER_MASK) {
+ stats->rx_errors++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_FORM;
+ }
+ }
+
+ /* Check for CRC error interrupt */
+ if (err_status & XCAN_ESR_CRCER_MASK) {
+ stats->rx_errors++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ }
+ }
+ priv->can.can_stats.bus_error++;
+ }
+
+ if (skb) {
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_rx(skb);
+ }
+
+ netdev_dbg(ndev, "%s: error status register:0x%x\n",
+ __func__, priv->read_reg(priv, XCAN_ESR_OFFSET));
+}
+
+/**
+ * xcan_state_interrupt - It will check the state of the CAN device
+ * @ndev: net_device pointer
+ * @isr: interrupt status register value
+ *
+ * This will checks the state of the CAN device
+ * and puts the device into appropriate state.
+ */
+static void xcan_state_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ /* Check for Sleep interrupt if set put CAN device in sleep state */
+ if (isr & XCAN_IXR_SLP_MASK)
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ /* Check for Wake up interrupt if set put CAN device in Active state */
+ if (isr & XCAN_IXR_WKUP_MASK)
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+/**
+ * xcan_rx_poll - Poll routine for rx packets (NAPI)
+ * @napi: napi structure pointer
+ * @quota: Max number of rx packets to be processed.
+ *
+ * This is the poll routine for rx part.
+ * It will process the packets maximux quota value.
+ *
+ * Return: number of packets received
+ */
+static int xcan_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 isr, ier;
+ int work_done = 0;
+
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) {
+ if (isr & XCAN_IXR_RXOK_MASK) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET,
+ XCAN_IXR_RXOK_MASK);
+ work_done += xcan_rx(ndev);
+ } else {
+ priv->write_reg(priv, XCAN_ICR_OFFSET,
+ XCAN_IXR_RXNEMP_MASK);
+ break;
+ }
+ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK);
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ }
+
+ if (work_done)
+ can_led_event(ndev, CAN_LED_EVENT_RX);
+
+ if (work_done < quota) {
+ napi_complete(napi);
+ ier = priv->read_reg(priv, XCAN_IER_OFFSET);
+ ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK);
+ priv->write_reg(priv, XCAN_IER_OFFSET, ier);
+ }
+ return work_done;
+}
+
+/**
+ * xcan_tx_interrupt - Tx Done Isr
+ * @ndev: net_device pointer
+ * @isr: Interrupt status register value
+ */
+static void xcan_tx_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+
+ while ((priv->tx_head - priv->tx_tail > 0) &&
+ (isr & XCAN_IXR_TXOK_MASK)) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
+ can_get_echo_skb(ndev, priv->tx_tail %
+ priv->tx_max);
+ priv->tx_tail++;
+ stats->tx_packets++;
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ }
+ can_led_event(ndev, CAN_LED_EVENT_TX);
+ netif_wake_queue(ndev);
+}
+
+/**
+ * xcan_interrupt - CAN Isr
+ * @irq: irq number
+ * @dev_id: device id poniter
+ *
+ * This is the xilinx CAN Isr. It checks for the type of interrupt
+ * and invokes the corresponding ISR.
+ *
+ * Return:
+ * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise
+ */
+static irqreturn_t xcan_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)dev_id;
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 isr, ier;
+
+ /* Get the interrupt status from Xilinx CAN */
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ if (!isr)
+ return IRQ_NONE;
+
+ /* Check for the type of interrupt and Processing it */
+ if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_SLP_MASK |
+ XCAN_IXR_WKUP_MASK));
+ xcan_state_interrupt(ndev, isr);
+ }
+
+ /* Check for Tx interrupt and Processing it */
+ if (isr & XCAN_IXR_TXOK_MASK)
+ xcan_tx_interrupt(ndev, isr);
+
+ /* Check for the type of error interrupt and Processing it */
+ if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
+ XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK |
+ XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK |
+ XCAN_IXR_ARBLST_MASK));
+ xcan_err_interrupt(ndev, isr);
+ }
+
+ /* Check for the type of receive interrupt and Processing it */
+ if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) {
+ ier = priv->read_reg(priv, XCAN_IER_OFFSET);
+ ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK);
+ priv->write_reg(priv, XCAN_IER_OFFSET, ier);
+ napi_schedule(&priv->napi);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * xcan_chip_stop - Driver stop routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the drivers stop routine. It will disable the
+ * interrupts and put the device into configuration mode.
+ */
+static void xcan_chip_stop(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 ier;
+
+ /* Disable interrupts and leave the can in configuration mode */
+ ier = priv->read_reg(priv, XCAN_IER_OFFSET);
+ ier &= ~XCAN_INTR_ALL;
+ priv->write_reg(priv, XCAN_IER_OFFSET, ier);
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+/**
+ * xcan_open - Driver open routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver open routine.
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_open(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags,
+ ndev->name, ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "irq allocation for CAN failed\n");
+ goto err;
+ }
+
+ ret = clk_prepare_enable(priv->can_clk);
+ if (ret) {
+ netdev_err(ndev, "unable to enable device clock\n");
+ goto err_irq;
+ }
+
+ ret = clk_prepare_enable(priv->bus_clk);
+ if (ret) {
+ netdev_err(ndev, "unable to enable bus clock\n");
+ goto err_can_clk;
+ }
+
+ /* Set chip into reset mode */
+ ret = set_reset_mode(ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "mode resetting failed!\n");
+ goto err_bus_clk;
+ }
+
+ /* Common open */
+ ret = open_candev(ndev);
+ if (ret)
+ goto err_bus_clk;
+
+ ret = xcan_chip_start(ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "xcan_chip_start failed!\n");
+ goto err_candev;
+ }
+
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+
+err_candev:
+ close_candev(ndev);
+err_bus_clk:
+ clk_disable_unprepare(priv->bus_clk);
+err_can_clk:
+ clk_disable_unprepare(priv->can_clk);
+err_irq:
+ free_irq(ndev->irq, ndev);
+err:
+ return ret;
+}
+
+/**
+ * xcan_close - Driver close routine
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 always
+ */
+static int xcan_close(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ xcan_chip_stop(ndev);
+ clk_disable_unprepare(priv->bus_clk);
+ clk_disable_unprepare(priv->can_clk);
+ free_irq(ndev->irq, ndev);
+ close_candev(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
+ return 0;
+}
+
+/**
+ * xcan_get_berr_counter - error counter routine
+ * @ndev: Pointer to net_device structure
+ * @bec: Pointer to can_berr_counter structure
+ *
+ * This is the driver error counter routine.
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_get_berr_counter(const struct net_device *ndev,
+ struct can_berr_counter *bec)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = clk_prepare_enable(priv->can_clk);
+ if (ret)
+ goto err;
+
+ ret = clk_prepare_enable(priv->bus_clk);
+ if (ret)
+ goto err_clk;
+
+ bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK;
+ bec->rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) &
+ XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT);
+
+ clk_disable_unprepare(priv->bus_clk);
+ clk_disable_unprepare(priv->can_clk);
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(priv->can_clk);
+err:
+ return ret;
+}
+
+
+static const struct net_device_ops xcan_netdev_ops = {
+ .ndo_open = xcan_open,
+ .ndo_stop = xcan_close,
+ .ndo_start_xmit = xcan_start_xmit,
+};
+
+/**
+ * xcan_suspend - Suspend method for the driver
+ * @dev: Address of the platform_device structure
+ *
+ * Put the driver into low power mode.
+ * Return: 0 always
+ */
+static int __maybe_unused xcan_suspend(struct device *dev)
+{
+ struct platform_device *pdev = dev_get_drvdata(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ }
+
+ priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK);
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ clk_disable(priv->bus_clk);
+ clk_disable(priv->can_clk);
+
+ return 0;
+}
+
+/**
+ * xcan_resume - Resume from suspend
+ * @dev: Address of the platformdevice structure
+ *
+ * Resume operation after suspend.
+ * Return: 0 on success and failure value on error
+ */
+static int __maybe_unused xcan_resume(struct device *dev)
+{
+ struct platform_device *pdev = dev_get_drvdata(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = clk_enable(priv->bus_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+ ret = clk_enable(priv->can_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ clk_disable_unprepare(priv->bus_clk);
+ return ret;
+ }
+
+ priv->write_reg(priv, XCAN_MSR_OFFSET, 0);
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
+ 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(xcan_dev_pm_ops, xcan_suspend, xcan_resume);
+
+/**
+ * xcan_probe - Platform registration call
+ * @pdev: Handle to the platform device structure
+ *
+ * This function does all the memory allocation and registration for the CAN
+ * device.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_probe(struct platform_device *pdev)
+{
+ struct resource *res; /* IO mem resources */
+ struct net_device *ndev;
+ struct xcan_priv *priv;
+ void __iomem *addr;
+ int ret, rx_max, tx_max;
+
+ /* Get the virtual base address for the device */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(addr)) {
+ ret = PTR_ERR(addr);
+ goto err;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max);
+ if (ret < 0)
+ goto err;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth", &rx_max);
+ if (ret < 0)
+ goto err;
+
+ /* Create a CAN device instance */
+ ndev = alloc_candev(sizeof(struct xcan_priv), tx_max);
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+ priv->dev = ndev;
+ priv->can.bittiming_const = &xcan_bittiming_const;
+ priv->can.do_set_mode = xcan_do_set_mode;
+ priv->can.do_get_berr_counter = xcan_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_BERR_REPORTING;
+ priv->reg_base = addr;
+ priv->tx_max = tx_max;
+
+ /* Get IRQ for the device */
+ ndev->irq = platform_get_irq(pdev, 0);
+ ndev->flags |= IFF_ECHO; /* We support local echo */
+
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ ndev->netdev_ops = &xcan_netdev_ops;
+
+ /* Getting the CAN can_clk info */
+ priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
+ if (IS_ERR(priv->can_clk)) {
+ dev_err(&pdev->dev, "Device clock not found.\n");
+ ret = PTR_ERR(priv->can_clk);
+ goto err_free;
+ }
+ /* Check for type of CAN device */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "xlnx,zynq-can-1.0")) {
+ priv->bus_clk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(priv->bus_clk)) {
+ dev_err(&pdev->dev, "bus clock not found\n");
+ ret = PTR_ERR(priv->bus_clk);
+ goto err_free;
+ }
+ } else {
+ priv->bus_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(priv->bus_clk)) {
+ dev_err(&pdev->dev, "bus clock not found\n");
+ ret = PTR_ERR(priv->bus_clk);
+ goto err_free;
+ }
+ }
+
+ ret = clk_prepare_enable(priv->can_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable device clock\n");
+ goto err_free;
+ }
+
+ ret = clk_prepare_enable(priv->bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable bus clock\n");
+ goto err_unprepare_disable_dev;
+ }
+
+ priv->write_reg = xcan_write_reg_le;
+ priv->read_reg = xcan_read_reg_le;
+
+ if (priv->read_reg(priv, XCAN_SR_OFFSET) != XCAN_SR_CONFIG_MASK) {
+ priv->write_reg = xcan_write_reg_be;
+ priv->read_reg = xcan_read_reg_be;
+ }
+
+ priv->can.clock.freq = clk_get_rate(priv->can_clk);
+
+ netif_napi_add(ndev, &priv->napi, xcan_rx_poll, rx_max);
+
+ ret = register_candev(ndev);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret);
+ goto err_unprepare_disable_busclk;
+ }
+
+ devm_can_led_init(ndev);
+ clk_disable_unprepare(priv->bus_clk);
+ clk_disable_unprepare(priv->can_clk);
+ netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n",
+ priv->reg_base, ndev->irq, priv->can.clock.freq,
+ priv->tx_max);
+
+ return 0;
+
+err_unprepare_disable_busclk:
+ clk_disable_unprepare(priv->bus_clk);
+err_unprepare_disable_dev:
+ clk_disable_unprepare(priv->can_clk);
+err_free:
+ free_candev(ndev);
+err:
+ return ret;
+}
+
+/**
+ * xcan_remove - Unregister the device after releasing the resources
+ * @pdev: Handle to the platform device structure
+ *
+ * This function frees all the resources allocated to the device.
+ * Return: 0 always
+ */
+static int xcan_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ if (set_reset_mode(ndev) < 0)
+ netdev_err(ndev, "mode resetting failed!\n");
+
+ unregister_candev(ndev);
+ netif_napi_del(&priv->napi);
+ free_candev(ndev);
+
+ return 0;
+}
+
+/* Match table for OF platform binding */
+static struct of_device_id xcan_of_match[] = {
+ { .compatible = "xlnx,zynq-can-1.0", },
+ { .compatible = "xlnx,axi-can-1.00.a", },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, xcan_of_match);
+
+static struct platform_driver xcan_driver = {
+ .probe = xcan_probe,
+ .remove = xcan_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .pm = &xcan_dev_pm_ops,
+ .of_match_table = xcan_of_match,
+ },
+};
+
+module_platform_driver(xcan_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xilinx Inc");
+MODULE_DESCRIPTION("Xilinx CAN interface");