diff options
Diffstat (limited to 'target/linux/coldfire/patches/077-mcfv4e_flexcan.patch')
-rw-r--r-- | target/linux/coldfire/patches/077-mcfv4e_flexcan.patch | 1376 |
1 files changed, 0 insertions, 1376 deletions
diff --git a/target/linux/coldfire/patches/077-mcfv4e_flexcan.patch b/target/linux/coldfire/patches/077-mcfv4e_flexcan.patch deleted file mode 100644 index ae7aefd649..0000000000 --- a/target/linux/coldfire/patches/077-mcfv4e_flexcan.patch +++ /dev/null @@ -1,1376 +0,0 @@ -From c44de58d0972d05851512ba8cbd928b7adef5187 Mon Sep 17 00:00:00 2001 -From: Kurt Mahan <kmahan@freescale.com> -Date: Tue, 8 Jul 2008 17:11:33 -0600 -Subject: [PATCH] Add FlexCAN support. - -LTIBName: mcfv4e-flexcan -Signed-off-by: Kurt Mahan <kmahan@freescale.com> -Signed-off-by: Huan Wang <b18965@freescale.com> ---- - drivers/net/can/Kconfig | 13 ++ - drivers/net/can/Makefile | 1 + - drivers/net/can/flexcan/Makefile | 5 + - drivers/net/can/flexcan/flexcan.c | 378 +++++++++++++++++++++++++++++++++ - drivers/net/can/flexcan/flexcan.h | 148 +++++++++++++ - drivers/net/can/flexcan/mcf548x_can.c | 213 ++++++++++++++++++ - include/asm-m68k/m5485sim.h | 2 + - include/linux/can/dev.h | 62 ++++++ - include/linux/can/ioctl.h | 152 +++++++++++++ - include/linux/can/version.h | 22 ++ - net/can/Makefile | 3 + - net/can/dev.c | 292 +++++++++++++++++++++++++ - 12 files changed, 1291 insertions(+), 0 deletions(-) - create mode 100644 drivers/net/can/flexcan/Makefile - create mode 100644 drivers/net/can/flexcan/flexcan.c - create mode 100644 drivers/net/can/flexcan/flexcan.h - create mode 100644 drivers/net/can/flexcan/mcf548x_can.c - create mode 100644 include/linux/can/dev.h - create mode 100644 include/linux/can/ioctl.h - create mode 100644 include/linux/can/version.h - create mode 100644 net/can/dev.c - ---- a/drivers/net/can/Kconfig -+++ b/drivers/net/can/Kconfig -@@ -12,6 +12,19 @@ config CAN_VCAN - This driver can also be built as a module. If so, the module - will be called vcan. - -+config CAN_FLEXCAN -+ tristate "Support for Freescale FLEXCAN based chips" -+ depends on CAN && (PPC || M68K || M68KNOMMU) -+ ---help--- -+ Say Y here if you want to support for Freescale FlexCAN. -+ -+config CAN_MCF547X_8X -+ tristate "Freescale MCF547X/MCF548X onboard CAN controller" -+ depends on CAN_FLEXCAN && (M547X || M548X) -+ ---help--- -+ Say Y here if you want to support for Freescale MCF547x/MCF548x -+ onboard dualCAN controller. -+ - config CAN_DEBUG_DEVICES - bool "CAN devices debugging messages" - depends on CAN ---- a/drivers/net/can/Makefile -+++ b/drivers/net/can/Makefile -@@ -3,3 +3,4 @@ - # - - obj-$(CONFIG_CAN_VCAN) += vcan.o -+obj-$(CONFIG_CAN_FLEXCAN) += flexcan/ ---- /dev/null -+++ b/drivers/net/can/flexcan/Makefile -@@ -0,0 +1,5 @@ -+ -+obj-$(CONFIG_CAN_MCF547X_8X) += flexcan-mcf548x.o -+ -+flexcan-mcf548x-objs := flexcan.o mcf548x_can.o -+ ---- /dev/null -+++ b/drivers/net/can/flexcan/flexcan.c -@@ -0,0 +1,378 @@ -+/* -+ * flexcan.c -+ * -+ * DESCRIPTION: -+ * CAN bus driver for the alone generic (as possible as) FLEXCAN controller. -+ * -+ * AUTHOR: -+ * Andrey Volkov <avolkov@varma-el.com> -+ * -+ * COPYRIGHT: -+ * 2005-2006, Varma Electronics Oy -+ * -+ * LICENCE: -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * HISTORY: -+ * 2008-06-23 Support for MCF548x's FlexCAN -+ * Huan, Wang <b18965@freescale.com> -+ */ -+ -+ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <linux/netdevice.h> -+#include <linux/if_arp.h> -+#include <linux/if_ether.h> -+#include <linux/can.h> -+#include <linux/list.h> -+#include <linux/io.h> -+ -+#include <linux/can/dev.h> -+#include <linux/can/error.h> -+#include "flexcan.h" -+#include <asm/coldfire.h> -+#include <asm/m5485sim.h> -+#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */ -+RCSID("$Id$"); -+ -+struct flexcan_priv { -+ struct can_priv can; -+ volatile unsigned long flags; -+ u8 shadow_statflg; -+ u8 shadow_canrier; -+ u8 cur_pri; -+ u8 tx_active; -+ -+ struct list_head tx_head; -+ struct napi_struct napi; -+ struct net_device *dev; -+}; -+ -+ -+static int flexcan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct can_frame *frame = (struct can_frame *)skb->data; -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ int i, len; -+ int txbuf = 0; -+ u32 can_id, can_ext, tmp, tmp1; -+ -+ /* Transmission inactive */ -+ regs->cantxfg[txbuf].can_dlc = MB_CNT_CODE(0x08); -+ -+ can_ext = frame->can_id; -+ if (can_ext & CAN_EFF_FLAG) { -+ /* Frame format is extended */ -+ regs->cantxfg[txbuf].can_dlc |= (1 << 21); -+ regs->cantxfg[txbuf].can_dlc |= (1 << 22); -+ can_id = frame->can_id & MB_ID_EXT; -+ if (frame->can_id & CAN_RTR_FLAG) -+ regs->cantxfg[txbuf].can_dlc |= (1 << 20); -+ -+ tmp = (can_id & CAN_SFF_MASK) << 18; -+ tmp1 = can_id >> 11; -+ can_id = tmp | tmp1; -+ regs->cantxfg[txbuf].can_id = can_id; -+ } else { -+ /* Frame format is standard */ -+ can_id = frame->can_id & MB_ID_EXT; -+ if (frame->can_id & CAN_RTR_FLAG) -+ regs->cantxfg[txbuf].can_dlc |= (1 << 20); -+ -+ regs->cantxfg[txbuf].can_id = can_id << 18; -+ } -+ -+ len = 8; -+ for (i = 0; i < len; i++) -+ regs->cantxfg[txbuf].data[i] = frame->data[i]; -+ -+ regs->cantxfg[txbuf].can_dlc |= len << 16; -+ /* Transmission active */ -+ regs->cantxfg[txbuf].can_dlc |= MB_CNT_CODE(0x0c); -+ kfree_skb(skb); -+ return NETDEV_TX_OK; -+} -+ -+static void flexcan_tx_timeout(struct net_device *dev) -+{ -+ struct sk_buff *skb; -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ struct can_frame *frame; -+ int length = 8; -+ -+ /* Diable the interrupts */ -+ regs->imask = IMASK_BUFF_DISABLE_ALL; -+ -+ skb = dev_alloc_skb(sizeof(struct can_frame)); -+ if (!skb) { -+ if (printk_ratelimit()) -+ dev_notice(ND2D(dev), "TIMEOUT packet dropped.\n"); -+ return; -+ } -+ frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); -+ -+ frame->can_dlc = length; -+ -+ skb->dev = dev; -+ skb->protocol = __constant_htons(ETH_P_CAN); -+ skb->pkt_type = PACKET_BROADCAST; -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ -+ netif_rx(skb); -+} -+ -+static irqreturn_t flexcan_isr(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ struct net_device_stats *stats = dev->get_stats(dev); -+ struct sk_buff *skb; -+ struct can_frame *frame; -+ u32 iflags, oflags; -+ int i, k; -+ int retval = 1; -+ -+ iflags = regs->iflag; -+ oflags = iflags; -+ for (i = 0; i < 16; i++) { -+ if (iflags & (0x01 << i)) { -+ struct flexcan_mb *mb = ®s->cantxfg[i]; -+ int ctrl = mb->can_dlc; -+ int code = (ctrl >> 24) & 0x0f; -+ int length = (ctrl >> 16) & 0x0f; -+ u32 tmp, tmp1; -+ -+ if (code < 8 && (length > 0)) { -+ /* receive frame */ -+ skb = dev_alloc_skb(sizeof(struct can_frame)); -+ if (!skb) -+ dev_notice(ND2D(dev), -+ "Packets dropped.\n"); -+ skb->dev = dev; -+ frame = (struct can_frame *)skb_put(skb, -+ sizeof(struct can_frame)); -+ -+ frame->can_id &= 0x0; -+ frame->can_dlc = length; -+ tmp1 = mb->can_id & MB_ID_EXT; -+ if (ctrl & MB_CNT_IDE) { -+ tmp = tmp1; -+ tmp = (tmp >> 18) & CAN_SFF_MASK; -+ frame->can_id = (tmp1 << 11) | tmp; -+ frame->can_id &= CAN_EFF_MASK; -+ frame->can_id |= CAN_EFF_FLAG; -+ if (ctrl & MB_CNT_RTR) -+ frame->can_id |= CAN_RTR_FLAG; -+ } else { -+ frame->can_id = tmp1 >> 18; -+ if (ctrl & MB_CNT_RTR) -+ frame->can_id |= CAN_RTR_FLAG; -+ } -+ -+ for (k = 0; k < 8; k++) -+ frame->data[k] = mb->data[k]; -+ -+ mb->can_dlc &= MB_CODE_MASK; -+ mb->can_dlc |= MB_CNT_CODE(0x04); -+ -+ stats->rx_packets++; -+ stats->rx_bytes += frame->can_dlc; -+ skb->dev = dev; -+ skb->protocol = __constant_htons(ETH_P_CAN); -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ -+ retval = netif_rx(skb); -+ if (retval == NET_RX_DROP) -+ dev_notice(ND2D(dev), -+ "Packets dropped.\n"); -+ } else { -+ /* transmit frame */ -+ mb->can_dlc = MB_CNT_CODE(0x04); -+ } -+ } -+ } -+ regs->iflag = oflags; -+ -+ return IRQ_HANDLED; -+} -+ -+static int flexcan_do_set_bit_time(struct net_device *dev, -+ struct can_bittime *bt) -+{ -+ struct flexcan_priv *priv = netdev_priv(dev); -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ int ret = 0; -+ u32 reg; -+ -+ if (bt->type != CAN_BITTIME_STD) -+ return -EINVAL; -+ -+ spin_lock_irq(&priv->can.irq_lock); -+ -+ reg = CANCTRL_PRESDIV(bt->std.brp) | CANCTRL_PSEG1(bt->std.phase_seg1 -+ - 1) | CANCTRL_PSEG2(bt->std.phase_seg2 - 1); -+ regs->canctrl &= CANCTRL_BITTIME; -+ regs->canctrl |= (reg | CANCTRL_SAMP(bt->std.sam) | -+ CANCTRL_PROPSEG(bt->std.prop_seg - 1)); -+ -+ spin_unlock_irq(&priv->can.irq_lock); -+ return ret; -+} -+ -+ -+static int flexcan_open(struct net_device *dev) -+{ -+ int ret, i, j; -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ -+#if defined(CONFIG_M547X_8X) -+ MCF_PAR_TIMER = MCF_PAR_TIMER | 0x28; -+ MCF_PAR_TIMER = MCF_PAR_TIMER & 0xf8; -+ MCF_PAR_DSPI = MCF_PAR_DSPI | 0x0a00; -+ MCF_PAR_FECI2CIRQ = MCF_PAR_FECI2CIRQ | 0x0283; -+ MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) & 0x0f; -+ MCF_PAR_PSCn(2) = MCF_PAR_PSCn(2) | 0x50; -+#endif -+ -+ regs->canmcr |= CANMCR_SOFTRST; -+ regs->canmcr |= CANMCR_MDIS; -+ udelay(10); -+ -+ if ((regs->canmcr & CANMCR_SOFTRST) != 0x0) { -+ dev_err(ND2D(dev), "Failed to softreset can module.\n"); -+ return -1; -+ } -+ -+ /* Enable error and bus off interrupt */ -+ regs->canctrl |= (CANCTRL_RJW(3) | CANCTRL_ERRMSK | -+ CANCTRL_BOFFMSK); -+ -+ /* Set lowest buffer transmitted first */ -+ regs->canctrl |= CANCTRL_LBUF; -+ -+ for (i = 0; i < 16; i++) { -+ regs->cantxfg[i].can_dlc = 0; -+ regs->cantxfg[i].can_id = 0; -+ for (j = 0; j < 8; j++) -+ regs->cantxfg[i].data[j] = 0; -+ -+ /* Put MB into rx queue */ -+ regs->cantxfg[i].can_dlc = MB_CNT_CODE(0x04); -+ } -+ -+ /* acceptance mask/acceptance code (accept everything) */ -+ regs->rxgmask = 0x00000000; -+ regs->rx14mask = 0x00000000; -+ regs->rx15mask = 0x00000000; -+ /* extended frame */ -+ regs->cantxfg[14].can_dlc |= 0x600000; -+ /* Enable flexcan module */ -+ regs->canmcr &= ~CANMCR_MDIS; -+ /* Synchronize with the can bus */ -+ regs->canmcr &= ~CANMCR_HALT; -+ -+#if defined(CONFIG_M547X_8X) -+ for (i = 0; i < 2; i++) { -+ MCF_ICR(ISC_CANn_MBOR(i)) = 0x33; -+ MCF_ICR(ISC_CANn_ERR(i)) = 0x33; -+ MCF_ICR(ISC_CANn_BUSOFF(i)) = 0x33; -+ } -+ -+ ret = request_irq(dev->irq + 64, flexcan_isr, IRQF_DISABLED, -+ dev->name, dev); -+ ret = request_irq(dev->irq + 1 + 64, flexcan_isr, IRQF_DISABLED, -+ dev->name, dev); -+ ret = request_irq(dev->irq + 2 + 64, flexcan_isr, IRQF_DISABLED, -+ dev->name, dev); -+ if (ret < 0) { -+ printk(KERN_ERR "%s - failed to attach interrupt.\n", -+ dev->name); -+ return ret; -+ } -+#endif -+ -+ /* Enable all interrupts */ -+ regs->imask = IMASK_BUFF_ENABLE_ALL; -+ netif_start_queue(dev); -+ return 0; -+} -+ -+static int flexcan_close(struct net_device *dev) -+{ -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ -+ netif_stop_queue(dev); -+ -+ /* Disable all interrupts */ -+ regs->imask = IMASK_BUFF_DISABLE_ALL; -+ free_irq(dev->irq + 64, dev); -+ free_irq(dev->irq + 1 + 64, dev); -+ free_irq(dev->irq + 2 + 64, dev); -+ -+ /* Disable module */ -+ regs->canmcr |= CANMCR_MDIS; -+ return 0; -+} -+ -+int register_flexcandev(struct net_device *dev, int clock_src) -+{ -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ -+ regs->canmcr &= ~CANMCR_MDIS; -+ udelay(100); -+ regs->canmcr |= (CANMCR_FRZ | CANMCR_HALT); -+ return register_netdev(dev); -+} -+EXPORT_SYMBOL(register_flexcandev); -+ -+void unregister_flexcandev(struct net_device *dev) -+{ -+ struct flexcan_regs *regs = (struct flexcan_regs *)dev->base_addr; -+ -+ regs->canmcr |= (CANMCR_FRZ | CANMCR_HALT); -+ regs->canmcr |= CANMCR_MDIS; -+ -+ unregister_netdev(dev); -+} -+EXPORT_SYMBOL(unregister_flexcandev); -+ -+struct net_device *alloc_flexcandev(void) -+{ -+ struct net_device *dev; -+ struct flexcan_priv *priv; -+ -+ dev = alloc_candev(sizeof(struct flexcan_priv)); -+ if (!dev) -+ return NULL; -+ -+ priv = netdev_priv(dev); -+ priv->dev = dev; -+ dev->open = flexcan_open; -+ dev->stop = flexcan_close; -+ dev->hard_start_xmit = flexcan_hard_start_xmit; -+ dev->tx_timeout = flexcan_tx_timeout; -+ dev->flags |= IFF_NOARP; -+ priv->can.do_set_bit_time = flexcan_do_set_bit_time; -+ return dev; -+} -+EXPORT_SYMBOL(alloc_flexcandev); -+ -+MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("CAN port driver for flexcan based chip"); ---- /dev/null -+++ b/drivers/net/can/flexcan/flexcan.h -@@ -0,0 +1,148 @@ -+/* -+ * flexcan.h -+ * -+ * DESCRIPTION: -+ * Definitions of consts/structs to drive the Freescale FLEXCAN. -+ * -+ */ -+ -+#ifndef __FLEXCAN_H__ -+#define __FLEXCAN_H__ -+ -+#include <linux/autoconf.h> -+#include <linux/types.h> -+ -+/* FLEXCAN module configuration register (CANMCR) bits */ -+#define CANMCR_MDIS 0x80000000 -+#define CANMCR_FRZ 0x40000000 -+#define CANMCR_HALT 0x10000000 -+#define CANMCR_SOFTRST 0x02000000 -+#define CANMCR_FRZACK 0x01000000 -+#define CANMCR_SUPV 0x00800000 -+#define CANMCR_MAXMB(x) ((x)&0x0f) -+ -+/* FLEXCAN control register (CANCTRL) bits */ -+#define CANCTRL_PRESDIV(x) (((x)&0xff)<<24) -+#define CANCTRL_RJW(x) (((x)&0x03)<<22) -+#define CANCTRL_PSEG1(x) (((x)&0x07)<<19) -+#define CANCTRL_PSEG2(x) (((x)&0x07)<<16) -+#define CANCTRL_BOFFMSK 0x00008000 -+#define CANCTRL_ERRMSK 0x00004000 -+#define CANCTRL_LPB 0x00001000 -+#define CANCTRL_SAMP(x) (((x)&0x1)<<7) -+#define CANCTRL_BOFFREC 0x00000040 -+#define CANCTRL_TSYNC 0x00000020 -+#define CANCTRL_LBUF 0x00000010 -+#define CANCTRL_LOM 0x00000008 -+#define CANCTRL_PROPSEG(x) ((x)&0x07) -+#define CANCTRL_BITTIME 0x00c0d078 -+ -+/* FLEXCAN error counter register (ERRCNT) bits */ -+#define ERRCNT_REXECTR(x) (((x)&0xff)<<8) -+#define ERRCNT_TXECTR(x) ((x)&0xff) -+ -+/* FLEXCAN error and status register (ERRSTAT) bits */ -+#define ERRSTAT_BITERR(x) (((x)&0x03)<<14) -+#define ERRSTAT_ACKERR 0x00002000 -+#define ERRSTAT_CRCERR 0x00001000 -+#define ERRSTAT_FRMERR 0x00000800 -+#define ERRSTAT_STFERR 0x00000400 -+#define ERRSTAT_TXWRN 0x00000200 -+#define ERRSTAT_RXWRN 0x00000100 -+#define ERRSTAT_IDLE 0x00000080 -+#define ERRSTAT_TXRX 0x00000040 -+#define ERRSTAT_FLTCONF(x) (((x)&0x03)<<4) -+#define ERRSTAT_BOFFINT 0x00000004 -+#define ERRSTAT_ERRINT 0x00000002 -+ -+/* FLEXCAN interrupt mask register (IMASK) bits */ -+#define IMASK_BUF15M 0x8000 -+#define IMASK_BUF14M 0x4000 -+#define IMASK_BUF13M 0x2000 -+#define IMASK_BUF12M 0x1000 -+#define IMASK_BUF11M 0x0800 -+#define IMASK_BUF10M 0x0400 -+#define IMASK_BUF9M 0x0200 -+#define IMASK_BUF8M 0x0100 -+#define IMASK_BUF7M 0x0080 -+#define IMASK_BUF6M 0x0040 -+#define IMASK_BUF5M 0x0020 -+#define IMASK_BUF4M 0x0010 -+#define IMASK_BUF3M 0x0008 -+#define IMASK_BUF2M 0x0004 -+#define IMASK_BUF1M 0x0002 -+#define IMASK_BUF0M 0x0001 -+#define IMASK_BUFnM(x) (0x1<<(x)) -+#define IMASK_BUFF_ENABLE_ALL 0xffff -+#define IMASK_BUFF_DISABLE_ALL 0x0000 -+ -+/* FLEXCAN interrupt flag register (IFLAG) bits */ -+#define IFLAG_BUF15M 0x8000 -+#define IFLAG_BUF14M 0x4000 -+#define IFLAG_BUF13M 0x2000 -+#define IFLAG_BUF12M 0x1000 -+#define IFLAG_BUF11M 0x0800 -+#define IFLAG_BUF10M 0x0400 -+#define IFLAG_BUF9M 0x0200 -+#define IFLAG_BUF8M 0x0100 -+#define IFLAG_BUF7M 0x0080 -+#define IFLAG_BUF6M 0x0040 -+#define IFLAG_BUF5M 0x0020 -+#define IFLAG_BUF4M 0x0010 -+#define IFLAG_BUF3M 0x0008 -+#define IFLAG_BUF2M 0x0004 -+#define IFLAG_BUF1M 0x0002 -+#define IFLAG_BUF0M 0x0001 -+#define IFLAG_BUFnM(x) (0x1<<(x)) -+#define IFLAG_BUFF_SET_ALL 0xffff -+#define IFLAG_BUFF_DISABLE_ALL 0x0000 -+ -+/* FLEXCAN message buffers */ -+#define MB_CNT_CODE(x) (((x)&0x0f)<<24) -+#define MB_CNT_SRR 0x00400000 -+#define MB_CNT_IDE 0x00200000 -+#define MB_CNT_RTR 0x00100000 -+#define MB_CNT_LENGTH(x) (((x)&0x0f)<<16) -+#define MB_CNT_TIMESTAMP(x) ((x)&0xffff) -+ -+#define MB_ID_STD ((0x7ff)<<18) -+#define MB_ID_EXT 0x1fffffff -+#define MB_CODE_MASK 0xf0ffffff -+ -+/* Structure of the message buffer */ -+struct flexcan_mb { -+ u32 can_dlc; -+ u32 can_id; -+ u8 data[8]; -+}; -+ -+/* Structure of the hardware registers */ -+struct flexcan_regs { -+ u32 canmcr; -+ u32 canctrl; -+ u32 timer; -+ u32 reserved1; -+ u32 rxgmask; -+ u32 rx14mask; -+ u32 rx15mask; -+ u32 errcnt; -+ u32 errstat; -+ u32 reserved2; -+ u32 imask; -+ u32 reserved3; -+ u32 iflag; -+ u32 reserved4[19]; -+ struct flexcan_mb cantxfg[16]; -+}; -+ -+struct flexcan_platform_data { -+ u8 clock_src; /* FLEXCAN clock source CRIN or SYSCLK */ -+ u32 clock_frq; /* can ref. clock, in Hz */ -+}; -+ -+struct net_device *alloc_flexcandev(void); -+ -+extern int register_flexcandev(struct net_device *dev, int clock_src); -+extern void unregister_flexcandev(struct net_device *dev); -+ -+#endif /* __FLEXCAN_H__ */ ---- /dev/null -+++ b/drivers/net/can/flexcan/mcf548x_can.c -@@ -0,0 +1,213 @@ -+/* -+ * DESCRIPTION: -+ * CAN bus driver for the Freescale MCF548x embedded CPU. -+ * -+ * AUTHOR: -+ * Andrey Volkov <avolkov@varma-el.com> -+ * -+ * COPYRIGHT: -+ * 2004-2005, Varma Electronics Oy -+ * -+ * LICENCE: -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * HISTORY: -+ * 2008-06-23 support for MCF548x's FlexCAN -+ * Huan, Wang <b18965@freescale.com> -+ * 2005-02-03 created -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/netdevice.h> -+#include <linux/can.h> -+#include <linux/can/dev.h> -+#include <linux/io.h> -+ -+#include "flexcan.h" -+#include <asm/coldfire.h> -+#include <asm/m5485sim.h> -+#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */ -+ -+RCSID("$Id$"); -+ -+#define PDEV_MAX 2 -+ -+struct platform_device *pdev[PDEV_MAX]; -+ -+static int __devinit mcf548x_can_probe(struct platform_device *pdev) -+{ -+ struct resource *mem; -+ struct net_device *dev; -+ struct flexcan_platform_data *pdata = pdev->dev.platform_data; -+ struct can_priv *can; -+ u32 mem_size; -+ int ret = -ENODEV; -+ -+ if (!pdata) -+ return ret; -+ -+ dev = alloc_flexcandev(); -+ if (!dev) -+ return -ENOMEM; -+ can = netdev_priv(dev); -+ -+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ -+ dev->irq = platform_get_irq(pdev, 0); -+ if (!mem || !dev->irq) -+ goto req_error; -+ -+ mem_size = mem->end - mem->start + 1; -+ if (!request_mem_region(mem->start, mem_size, pdev->dev.driver->name)) { -+ dev_err(&pdev->dev, "resource unavailable\n"); -+ goto req_error; -+ } -+ SET_NETDEV_DEV(dev, &pdev->dev); -+ -+ dev->base_addr = (unsigned long)ioremap_nocache(mem->start, mem_size); -+ if (!dev->base_addr) { -+ dev_err(&pdev->dev, "failed to map can port\n"); -+ ret = -ENOMEM; -+ goto fail_map; -+ } -+ can->can_sys_clock = pdata->clock_frq; -+ platform_set_drvdata(pdev, dev); -+ ret = register_flexcandev(dev, pdata->clock_src); -+ if (ret >= 0) { -+ dev_info(&pdev->dev, "probe for port 0x%lX done\n", -+ dev->base_addr); -+ return ret; -+ } -+ -+ iounmap((unsigned long *)dev->base_addr); -+fail_map: -+ release_mem_region(mem->start, mem_size); -+req_error: -+ free_candev(dev); -+ dev_err(&pdev->dev, "probe failed\n"); -+ return ret; -+} -+ -+static int __devexit mcf548x_can_remove(struct platform_device *pdev) -+{ -+ struct net_device *dev = platform_get_drvdata(pdev); -+ struct resource *mem; -+ -+ platform_set_drvdata(pdev, NULL); -+ unregister_flexcandev(dev); -+ iounmap((unsigned long *)dev->base_addr); -+ -+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ release_mem_region(mem->start, mem->end - mem->start + 1); -+ free_candev(dev); -+ return 0; -+} -+ -+static struct platform_driver mcf548x_can_driver = { -+ .driver = { -+ .name = "mcf548x-flexcan", -+ }, -+ .probe = mcf548x_can_probe, -+ .remove = __devexit_p(mcf548x_can_remove), -+}; -+ -+static struct resource mcf548x_can0_resources[] = { -+ [0] = { -+ .start = MCF_MBAR + 0x0000A000, -+ .end = MCF_MBAR + 0x0000A7FF, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = 49, -+ .end = 49, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static struct resource mcf548x_can1_resources[] = { -+ [0] = { -+ .start = MCF_MBAR + 0x0000A800, -+ .end = MCF_MBAR + 0x0000AFFF, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = 55, -+ .end = 55, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+ -+static int __init mcf548x_of_to_pdev(void) -+{ -+ unsigned int i; -+ int err = -ENODEV; -+ struct flexcan_platform_data pdata; -+ -+ pdev[0] = platform_device_register_simple("mcf548x-flexcan", 0, -+ mcf548x_can0_resources, 2); -+ if (IS_ERR(pdev[0])) { -+ err = PTR_ERR(pdev[0]); -+ return err; -+ } -+ pdev[1] = platform_device_register_simple("mcf548x-flexcan", 1, -+ mcf548x_can1_resources, 2); -+ if (IS_ERR(pdev[1])) { -+ err = PTR_ERR(pdev[1]); -+ return err; -+ } -+ -+ /* FlexCAN clock */ -+ pdata.clock_frq = 100000000; -+ -+ for (i = 0; i < PDEV_MAX; i++) { -+ err = platform_device_add_data(pdev[i], &pdata, sizeof(pdata)); -+ if (err) -+ return err; -+ } -+ return err; -+} -+ -+int __init mcf548x_can_init(void) -+{ -+ int err = mcf548x_of_to_pdev(); -+ -+ if (err) { -+ printk(KERN_ERR "%s init failed with err=%d\n", -+ mcf548x_can_driver.driver.name, err); -+ return err; -+ } -+ -+ return platform_driver_register(&mcf548x_can_driver); -+} -+ -+void __exit mcf548x_can_exit(void) -+{ -+ int i; -+ platform_driver_unregister(&mcf548x_can_driver); -+ for (i = 0; i < PDEV_MAX; i++) -+ platform_device_unregister(pdev[i]); -+} -+ -+module_init(mcf548x_can_init); -+module_exit(mcf548x_can_exit); -+ -+MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); -+MODULE_DESCRIPTION("Freescale MCF548x CAN driver"); -+MODULE_LICENSE("GPL v2"); ---- a/include/asm-m68k/m5485sim.h -+++ b/include/asm-m68k/m5485sim.h -@@ -186,6 +186,8 @@ - #define MCF_PAR_PCIBR MCF_REG16(0x000A4A) - #define MCF_PAR_PSCn(x) MCF_REG08(0x000A4F-((x)&0x3)) - #define MCF_PAR_FECI2CIRQ MCF_REG16(0x000A44) -+#define MCF_PAR_DSPI MCF_REG16(0x000A50) -+#define MCF_PAR_TIMER MCF_REG08(0X000A52) - #define MCF_EPPAR MCF_REG16(0x000F00) - #define MCF_EPIER MCF_REG08(0x000F05) - #define MCF_EPFR MCF_REG08(0x000F0C) ---- /dev/null -+++ b/include/linux/can/dev.h -@@ -0,0 +1,62 @@ -+/* -+ * linux/can/dev.h -+ * -+ * Definitions for CAN controller network devices lib (work in progress) -+ * -+ * * * $Id$ -+ * -+ * Author: Andrey Volkov <avolkov@varma-el.com> -+ * Copyright (c) 2006 Varma Electronics Oy -+ * -+ */ -+ -+#ifndef CAN_DEVICE_H -+#define CAN_DEVICE_H -+ -+#include <linux/version.h> -+#include <linux/can/error.h> -+#include <linux/can/ioctl.h> -+ -+struct can_priv { -+ struct can_device_stats can_stats; -+ -+ /* can-bus oscillator frequency, in Hz, -+ BE CAREFUL! SOME CONTROLLERS (LIKE SJA1000) -+ FOOLISH ABOUT THIS FRQ (for sja1000 as ex. this -+ clock must be xtal clock divided by 2). */ -+ u32 can_sys_clock; -+ -+ /* by default max_brp is equal 64, -+ but for a Freescale TouCAN, as ex., it can be 255*/ -+ u32 max_brp; -+ /* For the mostly all controllers, max_sjw is equal 4, but -+ some, hmm, CAN implementations hardwared it to 1 */ -+ u8 max_sjw; -+ -+ u32 baudrate; /* in bauds */ -+ struct can_bittime bit_time; -+ -+ spinlock_t irq_lock; -+ /* Please hold this lock when touching net_stats/can_stats*/ -+ spinlock_t stats_lock; -+ -+ can_state_t state; -+ can_mode_t mode; -+ can_ctrlmode_t ctrlmode; -+ -+ int (*do_set_bit_time)(struct net_device *dev, struct can_bittime *br); -+ int (*do_get_state) (struct net_device *dev, can_state_t *state); -+ int (*do_set_mode) (struct net_device *dev, can_mode_t mode); -+ int (*do_set_ctrlmode)(struct net_device *dev, can_ctrlmode_t ctrlmode); -+ int (*do_get_ctrlmode)(struct net_device *dev, can_ctrlmode_t *ctrlmode); -+}; -+ -+#define ND2D(_ndev) (_ndev->dev.parent) -+ -+struct net_device *alloc_candev(int sizeof_priv); -+void free_candev(struct net_device *dev); -+ -+int can_calc_bit_time(struct can_priv *can, u32 baudrate, -+ struct can_bittime_std *bit_time); -+ -+#endif /* CAN_DEVICE_H */ ---- /dev/null -+++ b/include/linux/can/ioctl.h -@@ -0,0 +1,152 @@ -+/* -+ * linux/can/ioctl.h -+ * -+ * Definitions for CAN controller setup (work in progress) -+ * -+ * $Id$ -+ * -+ * Send feedback to <socketcan-users@lists.berlios.de> -+ * -+ */ -+ -+#ifndef CAN_IOCTL_H -+#define CAN_IOCTL_H -+ -+#include <linux/sockios.h> -+ -+ -+/* max. 16 private ioctls */ -+ -+#define SIOCSCANBAUDRATE (SIOCDEVPRIVATE+0) -+#define SIOCGCANBAUDRATE (SIOCDEVPRIVATE+1) -+ -+#define SIOCSCANCUSTOMBITTIME (SIOCDEVPRIVATE+2) -+#define SIOCGCANCUSTOMBITTIME (SIOCDEVPRIVATE+3) -+ -+#define SIOCSCANMODE (SIOCDEVPRIVATE+4) -+#define SIOCGCANMODE (SIOCDEVPRIVATE+5) -+ -+#define SIOCSCANCTRLMODE (SIOCDEVPRIVATE+6) -+#define SIOCGCANCTRLMODE (SIOCDEVPRIVATE+7) -+ -+#define SIOCSCANFILTER (SIOCDEVPRIVATE+8) -+#define SIOCGCANFILTER (SIOCDEVPRIVATE+9) -+ -+#define SIOCGCANSTATE (SIOCDEVPRIVATE+10) -+#define SIOCGCANSTATS (SIOCDEVPRIVATE+11) -+ -+#define SIOCSCANERRORCONFIG (SIOCDEVPRIVATE+12) -+#define SIOCGCANERRORCONFIG (SIOCDEVPRIVATE+13) -+ -+/* parameters for ioctls */ -+ -+/* SIOC[SG]CANBAUDRATE */ -+/* baudrate for CAN-controller in bits per second. */ -+/* 0 = Scan for baudrate (Autobaud) */ -+ -+typedef __u32 can_baudrate_t; -+ -+ -+/* SIOC[SG]CANCUSTOMBITTIME */ -+ -+typedef enum CAN_BITTIME_TYPE { -+ CAN_BITTIME_STD, -+ CAN_BITTIME_BTR -+} can_bittime_type_t; -+ -+/* TSEG1 of controllers usually is a sum of synch_seg (always 1), -+ * prop_seg and phase_seg1, TSEG2 = phase_seg2 */ -+ -+struct can_bittime_std { -+ __u32 brp; /* baud rate prescaler */ -+ __u8 prop_seg; /* from 1 to 8 */ -+ __u8 phase_seg1; /* from 1 to 8 */ -+ __u8 phase_seg2; /* from 1 to 8 */ -+ __u8 sjw:7; /* from 1 to 4 */ -+ __u8 sam:1; /* 1 - enable triple sampling */ -+}; -+ -+struct can_bittime_btr { -+ __u8 btr0; -+ __u8 btr1; -+}; -+ -+struct can_bittime { -+ can_bittime_type_t type; -+ union { -+ struct can_bittime_std std; -+ struct can_bittime_btr btr; -+ }; -+}; -+ -+#define CAN_BAUDRATE_UNCONFIGURED ((__u32) 0xFFFFFFFFU) -+#define CAN_BAUDRATE_UNKNOWN 0 -+ -+/* SIOC[SG]CANMODE */ -+ -+typedef __u32 can_mode_t; -+ -+#define CAN_MODE_STOP 0 -+#define CAN_MODE_START 1 -+#define CAN_MODE_SLEEP 2 -+ -+ -+/* SIOC[SG]CANCTRLMODE */ -+ -+typedef __u32 can_ctrlmode_t; -+ -+#define CAN_CTRLMODE_LOOPBACK 0x1 -+#define CAN_CTRLMODE_LISTENONLY 0x2 -+ -+ -+/* SIOCGCANFILTER */ -+ -+typedef __u32 can_filter_t; -+ -+/* filter modes (may vary due to controller specific capabilities) */ -+#define CAN_FILTER_CAPAB 0 /* get filter type capabilities -+ (32 Bit value) */ -+#define CAN_FILTER_MASK_VALUE 1 /* easy bit filter (see struct can_filter) */ -+#define CAN_FILTER_SFF_BITMASK 2 /* bitfield with 2048 bit SFF filter */ -+ /* filters 3 - 31 currently undefined */ -+ -+#define CAN_FILTER_MAX 31 /* max. filter type value */ -+ -+ -+/* SIOCGCANSTATE */ -+ -+typedef __u32 can_state_t; -+ -+#define CAN_STATE_ACTIVE 0 -+#define CAN_STATE_BUS_WARNING 1 -+#define CAN_STATE_BUS_PASSIVE 2 -+#define CAN_STATE_BUS_OFF 3 -+#define CAN_STATE_SCANNING_BAUDRATE 4 -+#define CAN_STATE_STOPPED 5 -+#define CAN_STATE_SLEEPING 6 -+ -+ -+/* SIOCGCANSTATS */ -+ -+struct can_device_stats { -+ int error_warning; -+ int data_overrun; -+ int wakeup; -+ int bus_error; -+ int error_passive; -+ int arbitration_lost; -+ int restarts; -+ int bus_error_at_init; -+}; -+ -+/* SIOC[SG]CANERRORCONFIG */ -+ -+typedef enum CAN_ERRCFG_TYPE { -+ CAN_ERRCFG_MASK, -+ CAN_ERRCFG_BUSERR, -+ CAN_ERRCFG_BUSOFF -+} can_errcfg_type_t; -+ -+/* tbd */ -+ -+#endif /* CAN_IOCTL_H */ ---- /dev/null -+++ b/include/linux/can/version.h -@@ -0,0 +1,22 @@ -+/* -+ * linux/can/version.h -+ * -+ * Version information for the CAN network layer implementation -+ -+ * Author: Urs Thuermann <urs.thuermann@volkswagen.de> -+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research -+ * All rights reserved. -+ * -+ * Send feedback to <socketcan-users@lists.berlios.de> -+ * -+ */ -+ -+#ifndef CAN_VERSION_H -+#define CAN_VERSION_H -+ -+#define RCSID(s) asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \ -+ ".string \"" s "\"\n\t.previous\n") -+ -+RCSID("$Id$"); -+ -+#endif /* CAN_VERSION_H */ ---- a/net/can/Makefile -+++ b/net/can/Makefile -@@ -10,3 +10,6 @@ can-raw-objs := raw.o - - obj-$(CONFIG_CAN_BCM) += can-bcm.o - can-bcm-objs := bcm.o -+ -+obj-$(CONFIG_CAN) += candev.o -+candev-objs := dev.o ---- /dev/null -+++ b/net/can/dev.c -@@ -0,0 +1,292 @@ -+/* -+ * $Id$ -+ * -+ * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix -+ * Copyright (C) 2006 Andrey Volkov, Varma Electronics -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the version 2 of the GNU General Public License -+ * as published by the Free Software Foundation -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <linux/if_arp.h> -+#include <linux/can.h> -+#include <linux/can/dev.h> -+ -+MODULE_DESCRIPTION("CAN netdevice library"); -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Marc Kleine-Budde <mkl@pengutronix.de>, " -+ "Andrey Volkov <avolkov@varma-el.com>"); -+ -+/* -+ Abstract: -+ Baud rate calculated with next formula: -+ baud = frq/(brp*(1 + prop_seg+ phase_seg1 + phase_seg2)) -+ -+ This calc function based on work of Florian Hartwich and Armin Bassemi -+ "The Configuration of the CAN Bit Timing" -+ (http://www.semiconductors.bosch.de/pdf/CiA99Paper.pdf) -+ -+ Parameters: -+ [in] -+ bit_time_nsec - expected bit time in nanosecs -+ -+ [out] -+ bit_time - calculated time segments, for meaning of -+ each field read CAN standard. -+*/ -+ -+#define DEFAULT_MAX_BRP 64U -+#define DEFAULT_MAX_SJW 4U -+ -+/* All below values in tq units */ -+#define MAX_BIT_TIME 25U -+#define MIN_BIT_TIME 8U -+#define MAX_PROP_SEG 8U -+#define MAX_PHASE_SEG1 8U -+#define MAX_PHASE_SEG2 8U -+ -+int can_calc_bit_time(struct can_priv *can, u32 baudrate, -+ struct can_bittime_std *bit_time) -+{ -+ int best_error = -1; /* Ariphmetic error */ -+ int df, best_df = -1; /* oscillator's tolerance range */ -+ u32 quanta; /*in tq units*/ -+ u32 brp, phase_seg1, phase_seg2, sjw, prop_seg; -+ u32 brp_min, brp_max, brp_expected; -+ u64 tmp; -+ -+ /* baudrate range [1baud,1Mbaud] */ -+ if (baudrate == 0 || baudrate > 1000000UL) -+ return -EINVAL; -+ -+ tmp = (u64)can->can_sys_clock*1000; -+ do_div(tmp, baudrate); -+ brp_expected = (u32)tmp; -+ -+ brp_min = brp_expected / (1000 * MAX_BIT_TIME); -+ if (brp_min == 0) -+ brp_min = 1; -+ if (brp_min > can->max_brp) -+ return -ERANGE; -+ -+ brp_max = (brp_expected + 500 * MIN_BIT_TIME) / (1000 * MIN_BIT_TIME); -+ if (brp_max == 0) -+ brp_max = 1; -+ if (brp_max > can->max_brp) -+ brp_max = can->max_brp; -+ -+ for (brp = brp_min; brp <= brp_max; brp++) { -+ quanta = brp_expected / (brp * 1000); -+ if (quanta < MAX_BIT_TIME && quanta * brp * 1000 != -+ brp_expected) -+ quanta++; -+ if (quanta < MIN_BIT_TIME || quanta > MAX_BIT_TIME) -+ continue; -+ -+ phase_seg2 = min((quanta - 3) / 2, MAX_PHASE_SEG2); -+ for (sjw = can->max_sjw; sjw > 0; sjw--) { -+ for (; phase_seg2 > sjw; phase_seg2--) { -+ u32 err1, err2; -+ phase_seg1 = phase_seg2 % 2 ? -+ phase_seg2-1 : phase_seg2; -+ prop_seg = quanta-1 - phase_seg2 - phase_seg1; -+ /* -+ * FIXME: support of longer lines -+ * (i.e. bigger prop_seg) is more prefered -+ * than support of cheap oscillators -+ * (i.e. bigger df/phase_seg1/phase_seg2) -+ * */ -+ -+ if (prop_seg < phase_seg1) -+ continue; -+ if (prop_seg > MAX_PROP_SEG) -+ goto next_brp; -+ -+ err1 = phase_seg1 * brp * 500 * 1000 / -+ (13 * brp_expected - phase_seg2 * -+ brp * 1000); -+ err2 = sjw * brp * 50 * 1000 / brp_expected; -+ -+ df = min(err1, err2); -+ if (df >= best_df) { -+ unsigned error = abs(brp_expected * 10 / -+ (brp * (1 + prop_seg + -+ phase_seg1 + -+ phase_seg2)) - 10000); -+ -+ if (error > 10 || error > best_error) -+ continue; -+ -+ if (error == best_error && prop_seg < -+ bit_time->prop_seg) -+ continue; -+ -+ best_error = error; -+ best_df = df; -+ bit_time->brp = brp; -+ bit_time->prop_seg = prop_seg; -+ bit_time->phase_seg1 = phase_seg1; -+ bit_time->phase_seg2 = phase_seg2; -+ bit_time->sjw = sjw; -+ bit_time->sam = -+ (bit_time->phase_seg1 > 3); -+ } -+ } -+ } -+next_brp: ; -+ } -+ -+ if (best_error < 0) -+ return -EDOM; -+ return 0; -+} -+EXPORT_SYMBOL(can_calc_bit_time); -+ -+static int can_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -+{ -+ struct can_priv *can = netdev_priv(dev); -+ struct can_bittime *bt = (struct can_bittime *)&ifr->ifr_ifru; -+ ulong *baudrate = (ulong *)&ifr->ifr_ifru; -+ int ret = -EOPNOTSUPP; -+ -+ dev_dbg(ND2D(dev), "(%s) 0x%08x %p\n", __func__, cmd, &ifr->ifr_ifru); -+ -+ switch (cmd) { -+ case SIOCSCANBAUDRATE: -+ if (can->do_set_bit_time) { -+ struct can_bittime bit_time; -+ ret = can_calc_bit_time(can, *baudrate, &bit_time.std); -+ if (ret != 0) -+ break; -+ bit_time.type = CAN_BITTIME_STD; -+ ret = can->do_set_bit_time(dev, &bit_time); -+ if (!ret) { -+ can->baudrate = *baudrate; -+ can->bit_time = bit_time; -+ } -+ } -+ break; -+ case SIOCGCANBAUDRATE: -+ *baudrate = can->baudrate; -+ ret = 0; -+ break; -+ case SIOCSCANCUSTOMBITTIME: -+ if (can->do_set_bit_time) { -+ ret = can->do_set_bit_time(dev, bt); -+ if (!ret) { -+ can->bit_time = *bt; -+ if (bt->type == CAN_BITTIME_STD && bt->std.brp) { -+ can->baudrate = can->can_sys_clock / -+ (bt->std.brp * (1 + bt->std.prop_seg + -+ bt->std.phase_seg1 + -+ bt->std.phase_seg2)); -+ } else -+ can->baudrate = CAN_BAUDRATE_UNKNOWN; -+ } -+ } -+ break; -+ case SIOCGCANCUSTOMBITTIME: -+ *bt = can->bit_time; -+ ret = 0; -+ break; -+ case SIOCSCANMODE: -+ if (can->do_set_mode) { -+ can_mode_t mode = -+ *((can_mode_t *)(&ifr->ifr_ifru)); -+ if (mode == CAN_MODE_START && -+ can->baudrate == CAN_BAUDRATE_UNCONFIGURED) { -+ dev_info(ND2D(dev), "Impossible to start \ -+ on UNKNOWN speed\n"); -+ ret = EINVAL; -+ } else -+ return can->do_set_mode(dev, mode); -+ } -+ break; -+ case SIOCGCANMODE: -+ *((can_mode_t *)(&ifr->ifr_ifru)) = can->mode; -+ ret = 0; -+ break; -+ case SIOCSCANCTRLMODE: -+ if (can->do_set_ctrlmode) { -+ can_ctrlmode_t ctrlmode = -+ *((can_ctrlmode_t *)(&ifr->ifr_ifru)); -+ return can->do_set_ctrlmode(dev, ctrlmode); -+ } -+ break; -+ case SIOCGCANCTRLMODE: -+ *((can_ctrlmode_t *)(&ifr->ifr_ifru)) = can->ctrlmode; -+ ret = 0; -+ break; -+ case SIOCSCANFILTER: -+ break; -+ case SIOCGCANFILTER: -+ break; -+ case SIOCGCANSTATE: -+ if (can->do_get_state) -+ return can->do_get_state(dev, -+ (can_state_t *)(&ifr->ifr_ifru)); -+ break; -+ case SIOCGCANSTATS: -+ *((struct can_device_stats *)(&ifr->ifr_ifru)) = can->can_stats; -+ ret = 0; -+ break; -+ } -+ -+ return ret; -+} -+ -+static void can_setup(struct net_device *dev) -+{ -+ dev->type = ARPHRD_CAN; -+ dev->mtu = sizeof(struct can_frame); -+ dev->do_ioctl = can_ioctl; -+ dev->hard_header_len = 0; -+ dev->addr_len = 0; -+ dev->tx_queue_len = 10; -+ -+ /* New-style flags. */ -+ dev->flags = IFF_NOARP; -+ dev->features = NETIF_F_NO_CSUM; -+} -+ -+/* -+ * Function alloc_candev -+ * Allocates and sets up an CAN device -+ */ -+struct net_device *alloc_candev(int sizeof_priv) -+{ -+ struct net_device *dev; -+ struct can_priv *priv; -+ -+ dev = alloc_netdev(sizeof_priv, "can%d", can_setup); -+ if (!dev) -+ return NULL; -+ -+ priv = netdev_priv(dev); -+ -+ priv->baudrate = CAN_BAUDRATE_UNCONFIGURED; -+ priv->max_brp = DEFAULT_MAX_BRP; -+ priv->max_sjw = DEFAULT_MAX_SJW; -+ spin_lock_init(&priv->irq_lock); -+ -+ return dev; -+} -+EXPORT_SYMBOL(alloc_candev); -+ -+void free_candev(struct net_device *dev) -+{ -+ free_netdev(dev); -+} -+EXPORT_SYMBOL(free_candev); |