advice on using ddelinux
Korbinian Ederer
korbinian.ederer at in.tum.de
Tue Aug 26 13:54:37 CEST 2014
Hello together,
I just started to play with ddelinux... My Goal is to build an d_can
driver for l4re.
I tried to collect the important parts from the Makefiles of pkg/anghk
and the ddelinux examples to write my own for d_can.
when i Try to build my "puzzle" ;) i get following error:
fiasco/src/l4/pkg/d_can/d_can/d_can.c:42:27: fatal error:
linux/can/dev.h: No such file or directory
this leads me to the fear that there's no can/dev.h in ddelinux...
My questions at this point are:
-Am I working in the right direction or did I misunderstand the concept
of ddelinux?
-If not, what would be the right procedure?
Thanks
Korbinian Ederer
PS: Sorry for the large appendix, but I think it's important for the
problem.
my pkg folder structure looks like this:
l4/pkg/d_can:
-./Control
-./Makefile
-d_can/:
-./d_can.c
-./d_dcan.h
-./d_can_platform.c
-./Kconfig
-./Makefile
The contents of the files:
l4/pkg/d_can/Control:
/provides: d_can//
//requires: dde-linux26 dde-linux26_net/
/
/
l4/pkg/d_can/Makefile:/
//
//PKGDIR ?= .//
//L4DIR ?= $(PKGDIR)/../..//
//
//include $(L4DIR)/mk/Makeconf//
//-include $(PKGDIR_OBJ)/Makeconf//
//
//#ifeq ($(CONFIG_DDE26),y)//
//TARGET = d_can//
//#endif//
//
//include $(L4DIR)/mk/subdir.mk/
l4/d_can/d_can/d_can.c:
//*
* CAN bus driver for Bosch D_CAN controller
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Anil Kumar Ch <anilkumar at ti.com>
*
* Borrowed from C_CAN driver
* Copyright (C) 2010 ST Microelectronics
* - Bhupesh Sharma <bhupesh.sharma at st.com>
*
* Borrowed heavily from the C_CAN driver originally written by:
* Copyright (C) 2007
* - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer at pengutronix.de>
* - Simon Kallweit, intefo AG <simon.kallweit at intefo.ch>
*
* Bosch D_CAN controller is compliant to CAN protocol version 2.0 part
A and B.
* Bosch D_CAN user manual can be obtained from:
* http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
* d_can_users_manual_111.pdf
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include "d_can.h"
/* TI D_CAN module registers */
#define D_CAN_CTL 0x0 /* CAN control register */
#define D_CAN_ES 0x4 /* Error and status */
#define D_CAN_PARITYERR_EOI 0x4 /* Parity error EOI */
#define D_CAN_ERRC 0x8 /* Error counter */
#define D_CAN_BTR 0xC /* Bit timing */
#define D_CAN_INT 0x10 /* Interrupt register */
#define D_CAN_TEST 0x14 /* Test register */
#define D_CAN_PERR 0x1C /* Parity Error Code */
#define D_CAN_ABOTR 0x80 /* Auto-Bus-On Time */
#define D_CAN_TXRQ_X 0x84 /* Transmission Request X */
#define D_CAN_TXRQ(n) (0x88 + ((n) * 4)) /* Transmission request */
#define D_CAN_NWDAT_X 0x98 /* New data X register */
#define D_CAN_NWDAT(n) (0x9C + ((n) * 4)) /* New data */
#define D_CAN_INTPND_X 0xAC /* Interrupt Pending X */
#define D_CAN_INTPND(n) (0xB0 + ((n) * 4)) /* Interrupt Pending */
#define D_CAN_MSGVAL_X 0xC0 /* Message Valid X */
#define D_CAN_MSGVAL(n) (0xC4 + ((n) * 4)) /* Message Valid */
#define D_CAN_INTMUX(n) (0xD8 + ((n) * 4)) /* Interrupt
Multiplexer */
#define D_CAN_IFCMD(n) (0x100 + ((n) * 0x20)) /* Command */
#define D_CAN_IFMSK(n) (0x104 + ((n) * 0x20)) /* Mask */
#define D_CAN_IFARB(n) (0x108 + ((n) * 0x20)) /* Arbitration */
#define D_CAN_IFMCTL(n) (0x10c + ((n) * 0x20)) /* Message ctl */
#define D_CAN_IFDATA(n) (0x110 + ((n) * 0x20)) /* DATA A */
#define D_CAN_IFDATB(n) (0x114 + ((n) * 0x20)) /* DATA B */
#define D_CAN_IF3OBS 0x140 /* IF3 Observation */
#define D_CAN_IF3UPD(n) (0x160 + ((n) * 4)) /* Update enable */
#define D_CAN_TIOC 0x1E0 /* CAN TX IO Control */
#define D_CAN_RIOC 0x1E4 /* CAN RX IO Control */
/* Control register Bit fields */
#define D_CAN_CTL_WUBA BIT(26) /* Automatic wake-up on bus
activity */
#define D_CAN_CTL_PDR BIT(24) /* Request for local low power
mode */
#define D_CAN_CTL_DE3 BIT(20) /* Enable DMA request line for
IF3 */
#define D_CAN_CTL_DE2 BIT(19) /* Enable DMA request line for
IF2 */
#define D_CAN_CTL_DE1 BIT(18) /* Enable DMA request line for
IF1 */
#define D_CAN_CTL_IE1 BIT(17) /* Interrupt line 1 enable */
#define D_CAN_CTL_INITDBG BIT(16) /* Init state for debug access */
#define D_CAN_CTL_SWR BIT(15) /* S/W reset enable */
#define D_CAN_CTL_PMD (0xF << 10) /* Parity on/off */
#define D_CAN_CTL_ABO BIT(9) /* Auto bus on enable */
#define D_CAN_CTL_IDS BIT(8) /* Interruption debug support
enable */
#define D_CAN_CTL_TEST BIT(7) /* Test mode enable */
#define D_CAN_CTL_CCE BIT(6) /* Configuration change enable */
#define D_CAN_CTL_DISABLE_AR BIT(5) /* Disable automatic
retransmission */
#define D_CAN_CTL_ENABLE_AR (0 << 5)
#define D_CAN_CTL_EIE BIT(3) /* Error interrupt enable */
#define D_CAN_CTL_SIE BIT(2) /* Status change int enable */
#define D_CAN_CTL_IE0 BIT(1) /* Interrupt line 0 enable */
#define D_CAN_CTL_INIT BIT(0) /* D_CAN initialization mode */
/* D_CAN Error and Status and Parity Error EOI reg bit fields */
#define D_CAN_ES_PDA BIT(10) /* Local power-down ACK */
#define D_CAN_ES_WUP BIT(9) /* Wkae up pending */
#define D_CAN_ES_PER BIT(8) /* Parity error detected */
#define D_CAN_ES_BOFF BIT(7) /* Bus off state */
#define D_CAN_ES_EWARN BIT(6) /* Warning state */
#define D_CAN_ES_EPASS BIT(5) /* Error passive state */
#define D_CAN_ES_RXOK BIT(4) /* Received a msg successfully */
#define D_CAN_ES_TXOK BIT(3) /* Transmitted a msg successfully */
#define D_CAN_ES_LEC_MASK 0x7 /* Last error code */
/* Parity error reg bit fields */
#define D_CAN_PEEOI BIT(8) /* EOI indication for parity error */
/* Error counter reg bit fields */
#define D_CAN_ERRC_RP_SHIFT 15
#define D_CAN_ERRC_RP_MASK BIT(15) /* Receive error passive */
#define D_CAN_ERRC_REC_SHIFT 8
#define D_CAN_ERRC_REC_MASK (0x7F << 8) /* Receive err counter */
#define D_CAN_ERRC_TEC_SHIFT 0
#define D_CAN_ERRC_TEC_MASK (0xFF << 0) /* Transmit err counter */
/* Bit timing reg bit fields */
#define D_CAN_BTR_BRPE_SHIFT 16
#define D_CAN_BTR_BRPE_MASK (0xF << 16) /* Baud rate prescaler ext */
#define D_CAN_BTR_TSEG2_SHIFT 12
#define D_CAN_BTR_TSEG2_MASK (0x7 << 12) /* Time seg after smpl
point */
#define D_CAN_BTR_TSEG1_SHIFT 8
#define D_CAN_BTR_TSEG1_MASK (0xF << 8) /* Time seg before smpl
point */
#define D_CAN_BTR_SJW_SHIFT 6
#define D_CAN_BTR_SJW_MASK (0x3 << 6) /* Syncronization jump width */
#define D_CAN_BTR_BRP_SHIFT 0
#define D_CAN_BTR_BRP_MASK (0x3F << 0) /* Baud rate prescaler */
/* D_CAN Test register bit fields */
#define D_CAN_TEST_RDA BIT(9) /* RAM direct access enable */
#define D_CAN_TEST_EXL BIT(8) /* External loopback mode */
#define D_CAN_TEST_RX BIT(7) /* Monitors the reveive pin */
#define D_CAN_TEST_TX (0x3 << 5) /* Control of CAN_TX pin */
#define D_CAN_TEST_LBACK BIT(4) /* Loopback mode */
#define D_CAN_TEST_SILENT BIT(3) /* Silent mdoe */
/* D_CAN Parity error reg bit fields */
#define D_CAN_PERR_WN_MASK (0x7 << 8) /* Parity error word nuber */
#define D_CAN_PERR_MN_MASK 0xFF /* Parity error msg object */
/* D_CAN X registers bit fields */
#define D_CAN_BIT_FIELD(n) (0x3 << (2 * n)) /* X reg's bit field 1
mask */
/* D_CAN IF command reg bit fields */
#define D_CAN_IF_CMD_WR BIT(23) /* Write/read */
#define D_CAN_IF_CMD_MASK BIT(22) /* Access to mask bits */
#define D_CAN_IF_CMD_ARB BIT(21) /* Access to arbitration bits */
#define D_CAN_IF_CMD_CONTROL BIT(20) /* Acess to control bits */
#define D_CAN_IF_CMD_CIP BIT(19) /* Clear int pending */
#define D_CAN_IF_CMD_TXRQST BIT(18) /* Access transmission request */
#define D_CAN_IF_CMD_DATAA BIT(17) /* Access to Data Bytes 0-3 */
#define D_CAN_IF_CMD_DATAB BIT(16) /* Access to Data Bytes 4-7 */
#define D_CAN_IF_CMD_BUSY BIT(15) /* Busy flag */
#define D_CAN_IF_CMD_DAM BIT(14) /* Activation of DMA */
#define D_CAN_IF_CMD_MN_MASK 0xFF /* No. of msg's used for DMA T/F */
#define D_CAN_IF_CMD_ALL (D_CAN_IF_CMD_MASK | D_CAN_IF_CMD_ARB | \
D_CAN_IF_CMD_CONTROL | D_CAN_IF_CMD_TXRQST | \
D_CAN_IF_CMD_DATAA | D_CAN_IF_CMD_DATAB)
/* D_CAN IF mask reg bit fields */
#define D_CAN_IF_MASK_MX BIT(31) /* Mask Extended Identifier */
#define D_CAN_IF_MASK_MD BIT(30) /* Mask Message direction */
/* D_CAN IF Arbitration */
#define D_CAN_IF_ARB_MSGVAL BIT(31) /* Message Vaild */
#define D_CAN_IF_ARB_MSGXTD BIT(30) /* Extended Identifier 0-11
1-29 */
#define D_CAN_IF_ARB_DIR_XMIT BIT(29) /* Message direction 0-R 1-T */
/* D_CAN IF Message control */
#define D_CAN_IF_MCTL_NEWDAT BIT(15) /* New data available */
#define D_CAN_IF_MCTL_MSGLST BIT(14) /* Message lost, only for
receive */
#define D_CAN_IF_MCTL_CLR_MSGLST (0 << 14)
#define D_CAN_IF_MCTL_INTPND BIT(13) /* Interrupt pending */
#define D_CAN_IF_MCTL_UMASK BIT(12) /* Use acceptance mask */
#define D_CAN_IF_MCTL_TXIE BIT(11) /* Transmit int enable */
#define D_CAN_IF_MCTL_RXIE BIT(10) /* Receive int enable */
#define D_CAN_IF_MCTL_RMTEN BIT(9) /* Remote enable */
#define D_CAN_IF_MCTL_TXRQST BIT(8) /* Transmit request */
#define D_CAN_IF_MCTL_EOB BIT(7) /* Data frames */
#define D_CAN_IF_MCTL_DLC_MASK 0xF /* Data length code */
/* D_CAN IF3 Observation reg bit fields */
#define D_CAN_IF3OBS_UP BIT(15) /* Update data status */
#define D_CAN_IF3OBS_SDB BIT(12) /* DataB read out status */
#define D_CAN_IF3OBS_SDA BIT(11) /* DataA read out status */
#define D_CAN_IF3OBS_SC BIT(10) /* Contol bits read out status */
#define D_CAN_IF3OBS_SA BIT(9) /* Arbitration read out status */
#define D_CAN_IF3OBS_SM BIT(8) /* Mask bits read out status */
#define D_CAN_IF3OBS_DB BIT(4) /* Data B read observation */
#define D_CAN_IF3OBS_DA BIT(3) /* Data A read observation */
#define D_CAN_IF3OBS_CTL BIT(2) /* Control read observation */
#define D_CAN_IF3OBS_ARB BIT(1) /* Arbitration data read
observation */
#define D_CAN_IF3OBS_MASK BIT(0) /* Mask data read observation */
/* D_CAN TX I/O reg bit fields */
#define D_CAN_TIOC_PU BIT(18) /* CAN_TX pull up/down select */
#define D_CAN_TIOC_PD BIT(17) /* CAN_TX pull disable */
#define D_CAN_TIOC_OD BIT(16) /* CAN_TX open drain enable */
#define D_CAN_TIOC_FUNC BIT(3) /* CAN_TX function */
#define D_CAN_TIOC_DIR BIT(2) /* CAN_TX data direction */
#define D_CAN_TIOC_OUT BIT(1) /* CAN_TX data out write */
#define D_CAN_TIOC_IN BIT(0) /* CAN_TX data in */
/* D_CAN RX I/O reg bit fields */
#define D_CAN_RIOC_PU BIT(18) /* CAN_RX pull up/down select */
#define D_CAN_RIOC_PD BIT(17) /* CAN_RX pull disable */
#define D_CAN_RIOC_OD BIT(16) /* CAN_RX open drain enable */
#define D_CAN_RIOC_FUNC BIT(3) /* CAN_RX function */
#define D_CAN_RIOC_DIR BIT(2) /* CAN_RX data direction */
#define D_CAN_RIOC_OUT BIT(1) /* CAN_RX data out write */
#define D_CAN_RTIOC_IN BIT(0) /* CAN_RX data in */
#define D_CAN_SET_REG 0xFFFFFFFF
#define D_CAN_CANMID_IDE BIT(31) /* Extended frame format */
#define D_CAN_CANMID_AME BIT(30) /* Acceptance mask enable */
#define D_CAN_CANMID_AAM BIT(29) /* Auto answer mode */
/*
* IF register masks:
*/
#define IFX_WRITE_IDR(x) ((x) & 0x1FFFFFFF)
#define IFX_CMD_BITS(x) ((x) & 0xFFFFFF00)
#define IFX_CMD_MSG_NUMBER(x) ((x) & 0xFF)
/* Message objects split */
#define D_CAN_NUM_MSG_OBJECTS 64
#define D_CAN_NUM_RX_MSG_OBJECTS 32
#define D_CAN_NUM_TX_MSG_OBJECTS 32
#define D_CAN_MSG_OBJ_RX_FIRST 1
#define D_CAN_MSG_OBJ_RX_LAST (D_CAN_MSG_OBJ_RX_FIRST + \
D_CAN_NUM_RX_MSG_OBJECTS - 1)
#define D_CAN_MSG_OBJ_TX_FIRST (D_CAN_MSG_OBJ_RX_LAST + 1)
#define D_CAN_MSG_OBJ_TX_LAST (D_CAN_MSG_OBJ_TX_FIRST + \
D_CAN_NUM_TX_MSG_OBJECTS - 1)
#define D_CAN_MSG_OBJ_RX_SPLIT 17
#define D_CAN_MSG_OBJ_RX_LOW_LAST (D_CAN_MSG_OBJ_RX_SPLIT - 1)
#define D_CAN_NEXT_MSG_OBJ_MASK (D_CAN_NUM_TX_MSG_OBJECTS - 1)
/* status interrupt */
#define STATUS_INTERRUPT 0x8000
/* global interrupt masks */
#define ENABLE_ALL_INTERRUPTS 1
#define DISABLE_ALL_INTERRUPTS 0
/* minimum timeout for checking BUSY status */
#define MIN_TIMEOUT_VALUE 6
/* Wait for ~1 sec for INIT bit */
#define D_CAN_WAIT_COUNT 100
#define D_CAN_IF_RX_NUM 0
#define D_CAN_IF_TX_NUM 1
#define D_CAN_GET_XREG_NUM(priv, reg) (__ffs(d_can_read(priv, reg))/4)
/* CAN Bittiming constants as per D_CAN specs */
static struct can_bittiming_const d_can_bittiming_const = {
.name = D_CAN_DRV_NAME,
.tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
.tseg1_max = 16,
.tseg2_min = 1, /* Time segment 2 = phase_seg2 */
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/
.brp_inc = 1,
};
/* d_can last error code (lec) values */
enum d_can_lec_type {
LEC_NO_ERROR = 0,
LEC_STUFF_ERROR,
LEC_FORM_ERROR,
LEC_ACK_ERROR,
LEC_BIT1_ERROR,
LEC_BIT0_ERROR,
LEC_CRC_ERROR,
LEC_UNUSED,
};
/*
* d_can error types:
* Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
*/
enum d_can_bus_error_types {
D_CAN_NO_ERROR = 0,
D_CAN_BUS_OFF,
D_CAN_ERROR_WARNING,
D_CAN_ERROR_PASSIVE,
};
static inline void d_can_write(struct d_can_priv *priv, u32 reg, u32 val)
{
__raw_writel(val, priv->base + reg);
}
static inline u32 d_can_read(struct d_can_priv *priv, int reg)
{
return __raw_readl(priv->base + reg);
}
static inline void d_can_set_bit(struct d_can_priv *priv, int reg,
u32 bit_mask)
{
d_can_write(priv, reg, d_can_read(priv, reg) | bit_mask);
}
static inline u32 d_can_get_bit(struct d_can_priv *priv, int reg,
u32 bit_mask)
{
return (d_can_read(priv, reg) & bit_mask) ? 1 : 0;
}
static inline void d_can_clear_bit(struct d_can_priv *priv, int reg,
u32 bit_mask)
{
d_can_write(priv, reg, d_can_read(priv, reg) & ~bit_mask);
}
static inline int get_tx_next_msg_obj(const struct d_can_priv *priv)
{
return (priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) +
D_CAN_MSG_OBJ_TX_FIRST;
}
static inline int get_tx_echo_msg_obj(const struct d_can_priv *priv)
{
return (priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) +
D_CAN_MSG_OBJ_TX_FIRST;
}
/*
* API for enabling and disabling the multiple interrupts
* of the DCAN module like error interrupt, status interrupt
* error enable/disable for instance zero and one and etc.
*/
static void d_can_interrupts(struct d_can_priv *priv, int enable)
{
unsigned int cntrl_save = d_can_read(priv, D_CAN_CTL);
if (enable)
cntrl_save |= (D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
D_CAN_CTL_IE0);
else
cntrl_save &= ~(D_CAN_CTL_IE1 | D_CAN_CTL_SIE |
D_CAN_CTL_EIE | D_CAN_CTL_IE0);
d_can_write(priv, D_CAN_CTL, cntrl_save);
}
static inline int d_can_msg_obj_is_busy(struct d_can_priv *priv, int iface)
{
int count = MIN_TIMEOUT_VALUE;
while (count && (d_can_read(priv, D_CAN_IFCMD(iface)) &
D_CAN_IF_CMD_BUSY)) {
count--;
udelay(1);
}
if (!count)
return 1;
return 0;
}
static inline void d_can_object_get(struct net_device *dev,
int iface, int objno, int mask)
{
struct d_can_priv *priv = netdev_priv(dev);
d_can_write(priv, D_CAN_IFCMD(iface), IFX_CMD_BITS(mask) |
IFX_CMD_MSG_NUMBER(objno));
/*
* As per specs, after writing the message object number in the
* IF command register the transfer b/w interface register and
* message RAM must be complete in 12 CAN-CLK period.
*/
if (d_can_msg_obj_is_busy(priv, iface))
netdev_err(dev, "timed out in object get\n");
}
static inline void d_can_object_put(struct net_device *dev,
int iface, int objno, int mask)
{
struct d_can_priv *priv = netdev_priv(dev);
d_can_write(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_WR |
IFX_CMD_BITS(mask) | IFX_CMD_MSG_NUMBER(objno));
/*
* As per specs, after writing the message object number in the
* IF command register the transfer b/w interface register and
* message RAM must be complete in 12 CAN-CLK period.
*/
if (d_can_msg_obj_is_busy(priv, iface))
netdev_err(dev, "timed out in object put\n");
}
static void d_can_write_msg_object(struct net_device *dev,
int iface, struct can_frame *frame, int objno)
{
int i;
unsigned int id;
u32 dataA = 0;
u32 dataB = 0;
u32 flags = 0;
struct d_can_priv *priv = netdev_priv(dev);
if (!(frame->can_id & CAN_RTR_FLAG))
flags |= D_CAN_IF_ARB_DIR_XMIT;
if (frame->can_id & CAN_EFF_FLAG) {
id = frame->can_id & CAN_EFF_MASK;
flags |= D_CAN_IF_ARB_MSGXTD;
} else
id = ((frame->can_id & CAN_SFF_MASK) << 18);
flags |= D_CAN_IF_ARB_MSGVAL;
d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags);
for (i = 0; i < frame->can_dlc; i++) {
if (frame->can_dlc <= 4)
dataA |= (frame->data[i] << (8 * i));
else {
if (i < 4)
dataA |= (frame->data[i] << (8 * i));
else
dataB |= (frame->data[i] << (8 * (i - 4)));
}
}
/* DATA write to Message object registers DATAA and DATAB */
if (frame->can_dlc <= 4)
d_can_write(priv, D_CAN_IFDATA(iface), dataA);
else {
d_can_write(priv, D_CAN_IFDATB(iface), dataB);
d_can_write(priv, D_CAN_IFDATA(iface), dataA);
}
/* enable TX interrupt for this message object */
d_can_write(priv, D_CAN_IFMCTL(iface),
D_CAN_IF_MCTL_TXIE | D_CAN_IF_MCTL_EOB |
D_CAN_IF_MCTL_TXRQST | D_CAN_IF_MCTL_NEWDAT |
frame->can_dlc);
/* Put message data into message RAM */
d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL);
}
/*
* Mark that this particular message object is received and clearing
* the interrupt pending register value.
*/
static inline void d_can_mark_rx_msg_obj(struct net_device *dev,
int iface, int ctrl_mask, int obj)
{
struct d_can_priv *priv = netdev_priv(dev);
d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask
& ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND));
d_can_object_put(dev, iface, obj, D_CAN_IF_CMD_CONTROL);
}
static inline void d_can_activate_all_lower_rx_msg_objs(struct
net_device *dev,
int iface, int ctrl_mask)
{
int i;
struct d_can_priv *priv = netdev_priv(dev);
for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_MSG_OBJ_RX_LOW_LAST; i++) {
d_can_write(priv, D_CAN_IFMCTL(iface),
ctrl_mask & ~(D_CAN_IF_MCTL_MSGLST |
D_CAN_IF_MCTL_INTPND | D_CAN_IF_MCTL_NEWDAT));
d_can_object_put(dev, iface, i, D_CAN_IF_CMD_CONTROL);
}
}
static inline void d_can_activate_rx_msg_obj(struct net_device *dev,
int iface, int ctrl_mask,
int obj)
{
struct d_can_priv *priv = netdev_priv(dev);
d_can_write(priv, D_CAN_IFMCTL(iface),
ctrl_mask & ~(D_CAN_IF_MCTL_MSGLST |
D_CAN_IF_MCTL_INTPND | D_CAN_IF_MCTL_NEWDAT));
d_can_object_put(dev, iface, obj, D_CAN_IF_CMD_CONTROL);
}
static void d_can_handle_lost_msg_obj(struct net_device *dev,
int iface, int objno)
{
struct d_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb;
struct can_frame *frame;
netdev_err(dev, "msg lost in buffer %d\n", objno);
d_can_object_get(dev, iface, objno, D_CAN_IF_CMD_ALL &
~D_CAN_IF_CMD_TXRQST);
d_can_write(priv, D_CAN_IFMCTL(iface), D_CAN_IF_MCTL_CLR_MSGLST);
d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
/* create an error msg */
skb = alloc_can_err_skb(dev, &frame);
if (unlikely(!skb))
return;
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);
}
static int d_can_read_msg_object(struct net_device *dev, int iface, int
ctrl)
{
int i;
u32 dataA = 0;
u32 dataB = 0;
unsigned int arb_val;
unsigned int mctl_val;
struct d_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb;
struct can_frame *frame;
skb = alloc_can_skb(dev, &frame);
if (!skb) {
stats->rx_dropped++;
return -ENOMEM;
}
frame->can_dlc = get_can_dlc(ctrl & 0x0F);
arb_val = d_can_read(priv, D_CAN_IFARB(iface));
mctl_val = d_can_read(priv, D_CAN_IFMCTL(iface));
if (arb_val & D_CAN_IF_ARB_MSGXTD)
frame->can_id = (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id = (arb_val >> 18) & CAN_SFF_MASK;
if (mctl_val & D_CAN_IF_MCTL_RMTEN)
frame->can_id |= CAN_RTR_FLAG;
else {
dataA = d_can_read(priv, D_CAN_IFDATA(iface));
dataB = d_can_read(priv, D_CAN_IFDATB(iface));
for (i = 0; i < frame->can_dlc; i++) {
/* Writing MO higher 4 data bytes to skb */
if (frame->can_dlc <= 4)
frame->data[i] = dataA >> (8 * i);
else {
if (i < 4)
frame->data[i] = dataA >> (8 * i);
else
frame->data[i] = dataB >> (8 * (i-4));
}
}
}
netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
return 0;
}
static void d_can_setup_receive_object(struct net_device *dev, int iface,
int objno, unsigned int mask,
unsigned int id, unsigned int mcont)
{
struct d_can_priv *priv = netdev_priv(dev);
d_can_write(priv, D_CAN_IFMSK(iface), IFX_WRITE_IDR(mask));
d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) |
D_CAN_IF_ARB_MSGVAL);
d_can_write(priv, D_CAN_IFMCTL(iface), mcont);
d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL &
~D_CAN_IF_CMD_TXRQST);
netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
}
static void d_can_inval_msg_object(struct net_device *dev, int iface,
int objno)
{
struct d_can_priv *priv = netdev_priv(dev);
d_can_write(priv, D_CAN_IFARB(iface), 0);
d_can_write(priv, D_CAN_IFMCTL(iface), 0);
d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ARB |
D_CAN_IF_CMD_CONTROL);
netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
}
static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, int
objno)
{
u32 txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
/*
* as transmission request register's bit n-1 corresponds to
* message object n, we need to handle the same properly.
*/
if (d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)) &
(1 << (objno - D_CAN_MSG_OBJ_TX_FIRST)))
return 1;
return 0;
}
static netdev_tx_t d_can_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
u32 msg_obj_no;
struct d_can_priv *priv = netdev_priv(dev);
struct can_frame *frame = (struct can_frame *)skb->data;
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 */
d_can_write_msg_object(dev, D_CAN_IF_TX_NUM, frame, msg_obj_no);
can_put_echo_skb(skb, dev, msg_obj_no - D_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
*/
priv->tx_next++;
if (d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) == 0))
netif_stop_queue(dev);
return NETDEV_TX_OK;
}
static int d_can_set_bittiming(struct net_device *dev)
{
struct d_can_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
u32 can_btc;
can_btc = ((bt->phase_seg2 - 1) & 0x7) << D_CAN_BTR_TSEG2_SHIFT;
can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1)
& 0xF) << D_CAN_BTR_TSEG1_SHIFT;
can_btc |= ((bt->sjw - 1) & 0x3) << D_CAN_BTR_SJW_SHIFT;
/* Ten bits contains the BRP, 6 bits for BRP and upper 4 bits for
brpe*/
can_btc |= ((bt->brp - 1) & 0x3F) << D_CAN_BTR_BRP_SHIFT;
can_btc |= ((((bt->brp - 1) >> 6) & 0xF) << D_CAN_BTR_BRPE_SHIFT);
d_can_write(priv, D_CAN_BTR, can_btc);
netdev_info(dev, "setting CAN BT = %#x\n", can_btc);
return 0;
}
/*
* Configure D_CAN message objects for Tx and Rx purposes:
* D_CAN provides a total of 64 message objects that can be configured
* either for Tx or Rx purposes. In this driver first 32 message objects
* are used as a reception FIFO and the reception FIFO is signified by the
* EoB bit being SET. The remaining 32 message objects are kept aside for
* Tx purposes. See user guide document for further details on configuring
* message objects.
*/
static void d_can_configure_msg_objects(struct net_device *dev)
{
unsigned int i;
/* first invalidate all message objects */
for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_NUM_MSG_OBJECTS; i++)
d_can_inval_msg_object(dev, D_CAN_IF_RX_NUM, i);
/* setup receive message objects */
for (i = D_CAN_MSG_OBJ_RX_FIRST; i < D_CAN_MSG_OBJ_RX_LAST; i++)
d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, i, 0, 0,
(D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK) &
~D_CAN_IF_MCTL_EOB);
/* Last object EoB bit should be 1 for terminate */
d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, D_CAN_MSG_OBJ_RX_LAST,
0, 0, D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK |
D_CAN_IF_MCTL_EOB);
}
static void d_can_test_mode(struct net_device *dev)
{
struct d_can_priv *priv = netdev_priv(dev);
/* Test mode is enabled in this step & the specific TEST bits
* are enabled accordingly */
d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE |
D_CAN_CTL_IE1 | D_CAN_CTL_IE0 | D_CAN_CTL_TEST);
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
/* silent mode : bus-monitoring mode */
d_can_write(priv, D_CAN_TEST, D_CAN_TEST_SILENT);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* loopback mode : useful for self-test function */
d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK);
} else {
/* loopback + silent mode : useful for hot self-test */
d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK |
D_CAN_TEST_SILENT);
}
}
/*
* Configure D_CAN chip:
* - enable/disable auto-retransmission
* - set operating mode
* - configure message objects
*/
static void d_can_init(struct net_device *dev)
{
struct d_can_priv *priv = netdev_priv(dev);
u32 cnt;
netdev_dbg(dev, "resetting d_can ...\n");
d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_SWR);
/* Enter initialization mode by setting the Init bit */
d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
/* enable automatic retransmission */
d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_ENABLE_AR);
/* Set the Configure Change Enable ( CCE) bit */
d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_CCE);
/* Wait for the Init bit to get set */
cnt = D_CAN_WAIT_COUNT;
while (!d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) && cnt != 0) {
--cnt;
udelay(10);
}
/* set bittiming params */
d_can_set_bittiming(dev);
d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT | D_CAN_CTL_CCE);
/* Wait for the Init bit to get clear */
cnt = D_CAN_WAIT_COUNT;
while (d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) && cnt != 0) {
--cnt;
udelay(10);
}
if (!priv->test_mode) {
/* normal mode*/
d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | D_CAN_CTL_IE1 |
D_CAN_CTL_IE0);
} else
d_can_test_mode(dev);
/* Enable TX and RX I/O Control pins */
d_can_write(priv, D_CAN_TIOC, D_CAN_TIOC_FUNC);
d_can_write(priv, D_CAN_RIOC, D_CAN_RIOC_FUNC);
/* configure message objects */
d_can_configure_msg_objects(dev);
/* set a LEC value so that we can check for updates later */
d_can_write(priv, D_CAN_ES, LEC_UNUSED);
}
static void d_can_start(struct net_device *dev)
{
struct d_can_priv *priv = netdev_priv(dev);
/* basic d_can initialization */
d_can_init(dev);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* reset tx helper pointers */
priv->tx_next = priv->tx_echo = 0;
/* enable status change, error and module interrupts */
d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS);
}
static void d_can_stop(struct net_device *dev)
{
struct d_can_priv *priv = netdev_priv(dev);
/* disable all interrupts */
d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
/* set the state as STOPPED */
priv->can.state = CAN_STATE_STOPPED;
}
static int d_can_set_mode(struct net_device *dev, enum can_mode mode)
{
switch (mode) {
case CAN_MODE_START:
d_can_start(dev);
netif_wake_queue(dev);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int d_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
unsigned int reg_err_counter;
struct d_can_priv *priv = netdev_priv(dev);
reg_err_counter = d_can_read(priv, D_CAN_ERRC);
bec->rxerr = (reg_err_counter & D_CAN_ERRC_REC_MASK) >>
D_CAN_ERRC_REC_SHIFT;
bec->txerr = reg_err_counter & D_CAN_ERRC_TEC_MASK;
return 0;
}
/*
* 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 package, stop looking for more.
*/
static void d_can_do_tx(struct net_device *dev)
{
u32 msg_obj_no;
struct d_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
u32 txrq_x_reg_val;
u32 txrq_reg_val;
for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
msg_obj_no = get_tx_echo_msg_obj(priv);
txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
txrq_reg_val = d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val));
if (!(txrq_reg_val & (1 << (msg_obj_no -
D_CAN_MSG_OBJ_TX_FIRST)))) {
can_get_echo_skb(dev,
msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
stats->tx_bytes += d_can_read(priv,
D_CAN_IFMCTL(D_CAN_IF_TX_NUM))
& D_CAN_IF_MCTL_DLC_MASK;
stats->tx_packets++;
d_can_inval_msg_object(dev, D_CAN_IF_TX_NUM,
msg_obj_no);
} else
break;
}
/* restart queue if wrap-up or if queue stalled on last pkt */
if (((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) != 0)
|| ((priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) == 0))
netif_wake_queue(dev);
}
/*
* theory of operation:
*
* d_can core saves a received CAN message into the first free message
* object it finds free (starting with the lowest). Bits NEWDAT and
* INTPND are set for this message object indicating that a new message
* has arrived. To work-around this issue, we keep two groups of message
* objects whose partitioning is defined by D_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
* D_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
* D_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
* D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
* only this message object.
*/
static int d_can_do_rx_poll(struct net_device *dev, int quota)
{
struct d_can_priv *priv = netdev_priv(dev);
unsigned int msg_obj, mctrl_reg_val;
u32 num_rx_pkts = 0;
u32 intpnd_x_reg_val;
u32 intpnd_reg_val;
for (msg_obj = D_CAN_MSG_OBJ_RX_FIRST; msg_obj <= D_CAN_MSG_OBJ_RX_LAST
&& quota > 0; msg_obj++) {
intpnd_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X);
intpnd_reg_val = d_can_read(priv,
D_CAN_INTPND(intpnd_x_reg_val));
/*
* as interrupt pending register's bit n-1 corresponds to
* message object n, we need to handle the same properly.
*/
if (intpnd_reg_val & (1 << (msg_obj - 1))) {
d_can_object_get(dev, D_CAN_IF_RX_NUM, msg_obj,
D_CAN_IF_CMD_ALL &
~D_CAN_IF_CMD_TXRQST);
mctrl_reg_val = d_can_read(priv,
D_CAN_IFMCTL(D_CAN_IF_RX_NUM));
if (!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT))
continue;
/* read the data from the message object */
d_can_read_msg_object(dev, D_CAN_IF_RX_NUM,
mctrl_reg_val);
if (mctrl_reg_val & D_CAN_IF_MCTL_EOB)
d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM,
D_CAN_MSG_OBJ_RX_LAST, 0, 0,
D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK
| D_CAN_IF_MCTL_EOB);
if (mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) {
d_can_handle_lost_msg_obj(dev, D_CAN_IF_RX_NUM,
msg_obj);
num_rx_pkts++;
quota--;
continue;
}
if (msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST)
d_can_mark_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
mctrl_reg_val, msg_obj);
else if (msg_obj > D_CAN_MSG_OBJ_RX_LOW_LAST)
/* activate this msg obj */
d_can_activate_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
mctrl_reg_val, msg_obj);
else if (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST)
/* activate all lower message objects */
d_can_activate_all_lower_rx_msg_objs(dev,
D_CAN_IF_RX_NUM, mctrl_reg_val);
num_rx_pkts++;
quota--;
}
}
return num_rx_pkts;
}
static inline int d_can_has_handle_berr(struct d_can_priv *priv)
{
return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
(priv->current_status & LEC_UNUSED);
}
static int d_can_handle_state_change(struct net_device *dev,
enum d_can_bus_error_types error_type)
{
unsigned int reg_err_counter;
unsigned int rx_err_passive;
struct d_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
struct can_berr_counter bec;
/* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf);
if (unlikely(!skb))
return 0;
d_can_get_berr_counter(dev, &bec);
reg_err_counter = d_can_read(priv, D_CAN_ERRC);
rx_err_passive = (reg_err_counter & D_CAN_ERRC_RP_MASK) >>
D_CAN_ERRC_RP_SHIFT;
switch (error_type) {
case D_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 :
CAN_ERR_CRTL_RX_WARNING;
cf->data[6] = bec.txerr;
cf->data[7] = bec.rxerr;
break;
case D_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;
if (bec.txerr > 127)
cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
cf->data[6] = bec.txerr;
cf->data[7] = bec.rxerr;
break;
case D_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
*/
d_can_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;
return 1;
}
static int d_can_handle_bus_err(struct net_device *dev,
enum d_can_lec_type lec_type)
{
struct d_can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
/*
* early exit if no lec update or no error.
* no lec update means that no CAN bus event has been detected
* since CPU wrote 0x7 value to status reg.
*/
if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
return 0;
/* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf);
if (unlikely(!skb))
return 0;
/*
* 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;
switch (lec_type) {
case LEC_STUFF_ERROR:
netdev_dbg(dev, "stuff error\n");
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
case LEC_FORM_ERROR:
netdev_dbg(dev, "form error\n");
cf->data[2] |= CAN_ERR_PROT_FORM;
break;
case LEC_ACK_ERROR:
netdev_dbg(dev, "ack error\n");
cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
CAN_ERR_PROT_LOC_ACK_DEL);
break;
case LEC_BIT1_ERROR:
netdev_dbg(dev, "bit1 error\n");
cf->data[2] |= CAN_ERR_PROT_BIT1;
break;
case LEC_BIT0_ERROR:
netdev_dbg(dev, "bit0 error\n");
cf->data[2] |= CAN_ERR_PROT_BIT0;
break;
case LEC_CRC_ERROR:
netdev_dbg(dev, "CRC error\n");
cf->data[2] |= (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 */
d_can_write(priv, D_CAN_ES, LEC_UNUSED);
netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
return 1;
}
static int d_can_poll(struct napi_struct *napi, int quota)
{
int lec_type = 0;
int work_done = 0;
struct net_device *dev = napi->dev;
struct d_can_priv *priv = netdev_priv(dev);
if (!priv->irqstatus)
goto end;
/* status events have the highest priority */
if (priv->irqstatus == STATUS_INTERRUPT) {
priv->current_status = d_can_read(priv, D_CAN_ES);
/* handle Tx/Rx events */
if (priv->current_status & D_CAN_ES_TXOK)
d_can_write(priv, D_CAN_ES,
priv->current_status & ~D_CAN_ES_TXOK);
if (priv->current_status & D_CAN_ES_RXOK)
d_can_write(priv, D_CAN_ES,
priv->current_status & ~D_CAN_ES_RXOK);
/* handle state changes */
if ((priv->current_status & D_CAN_ES_EWARN) &&
(!(priv->last_status & D_CAN_ES_EWARN))) {
netdev_dbg(dev, "entered error warning state\n");
work_done += d_can_handle_state_change(dev,
D_CAN_ERROR_WARNING);
}
if ((priv->current_status & D_CAN_ES_EPASS) &&
(!(priv->last_status & D_CAN_ES_EPASS))) {
netdev_dbg(dev, "entered error passive state\n");
work_done += d_can_handle_state_change(dev,
D_CAN_ERROR_PASSIVE);
}
if ((priv->current_status & D_CAN_ES_BOFF) &&
(!(priv->last_status & D_CAN_ES_BOFF))) {
netdev_dbg(dev, "entered bus off state\n");
work_done += d_can_handle_state_change(dev,
D_CAN_BUS_OFF);
}
/* handle bus recovery events */
if ((!(priv->current_status & D_CAN_ES_BOFF)) &&
(priv->last_status & D_CAN_ES_BOFF)) {
netdev_dbg(dev, "left bus off state\n");
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
if ((!(priv->current_status & D_CAN_ES_EPASS)) &&
(priv->last_status & D_CAN_ES_EPASS)) {
netdev_dbg(dev, "left error passive state\n");
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
priv->last_status = priv->current_status;
/* handle lec errors on the bus */
lec_type = d_can_has_handle_berr(priv);
if (lec_type)
work_done += d_can_handle_bus_err(dev, lec_type);
} else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&
(priv->irqstatus <= D_CAN_MSG_OBJ_RX_LAST)) {
/* handle events corresponding to receive message objects */
work_done += d_can_do_rx_poll(dev, (quota - work_done));
} else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&
(priv->irqstatus <= D_CAN_MSG_OBJ_TX_LAST)) {
/* handle events corresponding to transmit message objects */
d_can_do_tx(dev);
}
end:
if (work_done < quota) {
napi_complete(napi);
/* enable all IRQs */
d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS);
}
return work_done;
}
static irqreturn_t d_can_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct d_can_priv *priv = netdev_priv(dev);
priv->irqstatus = d_can_read(priv, D_CAN_INT);
if (!priv->irqstatus)
return IRQ_NONE;
/* disable all interrupts and schedule the NAPI */
d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
napi_schedule(&priv->napi);
return IRQ_HANDLED;
}
static int d_can_open(struct net_device *ndev)
{
int err;
struct d_can_priv *priv = netdev_priv(ndev);
/* Open common can device */
err = open_candev(ndev);
if (err) {
netdev_err(ndev, "open_candev() failed %d\n", err);
return err;
}
/* register interrupt handler for Message Object (MO)
* and Error + status change (ES) */
err = request_irq(ndev->irq, &d_can_isr, IRQF_SHARED, ndev->name,
ndev);
if (err) {
netdev_err(ndev, "failed to request MO_ES interrupt\n");
goto exit_close_candev;
}
/* register interrupt handler for only Message Object */
err = request_irq(priv->irq_obj, &d_can_isr, IRQF_SHARED, ndev->name,
ndev);
if (err) {
netdev_err(ndev, "failed to request MO interrupt\n");
goto exit_free_irq;
}
/* start the d_can controller */
d_can_start(ndev);
napi_enable(&priv->napi);
netif_start_queue(ndev);
return 0;
exit_free_irq:
free_irq(ndev->irq, ndev);
exit_close_candev:
close_candev(ndev);
return err;
}
static int d_can_close(struct net_device *ndev)
{
struct d_can_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev);
napi_disable(&priv->napi);
d_can_stop(ndev);
free_irq(ndev->irq, ndev);
free_irq(priv->irq_obj, ndev);
close_candev(ndev);
return 0;
}
struct net_device *alloc_d_can_dev(int num_objs)
{
struct net_device *dev;
struct d_can_priv *priv;
dev = alloc_candev(sizeof(struct d_can_priv), num_objs/2);
if (!dev)
return NULL;
priv = netdev_priv(dev);
netif_napi_add(dev, &priv->napi, d_can_poll, num_objs/2);
priv->dev = dev;
priv->can.bittiming_const = &d_can_bittiming_const;
priv->can.do_set_mode = d_can_set_mode;
priv->can.do_get_berr_counter = d_can_get_berr_counter;
priv->can.ctrlmode_supported = (CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_3_SAMPLES);
return dev;
}
EXPORT_SYMBOL_GPL(alloc_d_can_dev);
void free_d_can_dev(struct net_device *dev)
{
free_candev(dev);
}
EXPORT_SYMBOL_GPL(free_d_can_dev);
static const struct net_device_ops d_can_netdev_ops = {
.ndo_open = d_can_open,
.ndo_stop = d_can_close,
.ndo_start_xmit = d_can_start_xmit,
};
int register_d_can_dev(struct net_device *dev)
{
/* we support local echo */
dev->flags |= IFF_ECHO;
dev->netdev_ops = &d_can_netdev_ops;
return register_candev(dev);
}
EXPORT_SYMBOL_GPL(register_d_can_dev);
void unregister_d_can_dev(struct net_device *dev)
{
struct d_can_priv *priv = netdev_priv(dev);
/* disable all interrupts */
d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
unregister_candev(dev);
}
EXPORT_SYMBOL_GPL(unregister_d_can_dev);
MODULE_AUTHOR("Anil Kumar Ch <anilkumar at ti.com>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(D_CAN_VERSION);
MODULE_DESCRIPTION(D_CAN_DRV_DESC);/
l4/pkg/d_can/d_can/d_can.h:
//*
* CAN bus driver for Bosch D_CAN controller
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Anil Kumar Ch <anilkumar at ti.com>
*
* Borrowed from C_CAN driver
* Copyright (C) 2010 ST Microelectronics
* - Bhupesh Sharma <bhupesh.sharma at st.com>
*
* Borrowed heavily from the C_CAN driver originally written by:
* Copyright (C) 2007
* - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer at pengutronix.de>
* - Simon Kallweit, intefo AG <simon.kallweit at intefo.ch>
*
* Bosch D_CAN controller is compliant to CAN protocol version 2.0 part
A and B.
* Bosch D_CAN user manual can be obtained from:
* http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
* d_can_users_manual_111.pdf
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef D_CAN_H
#define D_CAN_H
#define D_CAN_DRV_NAME "d_can"
#define D_CAN_VERSION "1.0"
#define D_CAN_DRV_DESC "CAN bus driver for Bosch D_CAN controller " \
D_CAN_VERSION
/* d_can private data structure */
struct d_can_priv {
struct can_priv can; /* must be the first member */
struct napi_struct napi;
struct net_device *dev;
int current_status;
int last_status;
unsigned int irqstatus;
void __iomem *base;
u32 napi_weight;
struct clk *fck;
struct clk *ick;
bool test_mode;
unsigned int irq; /* device IRQ number, for all MO and ES */
unsigned int irq_obj; /* device IRQ number for only Msg Object */
unsigned int irq_parity; /* device IRQ number for parity error */
unsigned long irq_flags; /* for request_irq() */
unsigned int tx_next;
unsigned int tx_echo;
unsigned int rx_next;
void *priv; /* for board-specific data */
};
struct net_device *alloc_d_can_dev(int);
void free_d_can_dev(struct net_device *dev);
int register_d_can_dev(struct net_device *dev);
void unregister_d_can_dev(struct net_device *dev);
#endif /* D_CAN_H *//
l4/pkg/d_can/d_can/d_can_platform.c:
/
/*
* Platform CAN bus driver for Bosch D_CAN controller
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Anil Kumar Ch <anilkumar at ti.com>
*
* Borrowed from C_CAN driver
* Copyright (C) 2010 ST Microelectronics
* - Bhupesh Sharma <bhupesh.sharma at st.com>
*
* Borrowed heavily from the C_CAN driver originally written by:
* Copyright (C) 2007
* - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer at pengutronix.de>
* - Simon Kallweit, intefo AG <simon.kallweit at intefo.ch>
*
* Bosch D_CAN controller is compliant to CAN protocol version 2.0 part
A and B.
* Bosch D_CAN user manual can be obtained from:
* http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
* d_can_users_manual_111.pdf
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Your platform definitions should specify module ram offsets and
interrupt
* number to use as follows:
*
* static struct d_can_platform_data am33xx_evm_d_can_pdata = {
* .d_can_offset = 0,
* .d_can_ram_offset = 0x1000,
* .num_of_msg_objs = 64,
* .dma_support = true,
* .test_mode_enable = false,
* .parity_check = false,
* .version = 0x1,
* .hw_raminit = d_can_hw_raminit,
* };
*
* Please see include/linux/can/platform/d_can.h for description of
* above fields.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/can/platform/d_can.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/can/dev.h>
#include "d_can.h"
static int __devinit d_can_plat_probe(struct platform_device *pdev)
{
int ret = 0;
void __iomem *addr;
struct net_device *ndev;
struct d_can_priv *priv;
struct resource *mem;
struct d_can_platform_data *pdata;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
goto exit;
}
/* allocate the d_can device */
ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
if (!ndev) {
ret = -ENOMEM;
dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
goto exit;
}
priv = netdev_priv(ndev);
priv->fck = clk_get(&pdev->dev, pdata->fck_name);
if (IS_ERR(priv->fck)) {
dev_err(&pdev->dev, "%s is not found\n", pdata->fck_name);
ret = -ENODEV;
goto exit_free_ndev;
}
clk_enable(priv->fck);
priv->ick = clk_get(&pdev->dev, pdata->ick_name);
if (IS_ERR(priv->ick)) {
dev_err(&pdev->dev, "%s is not found\n", pdata->ick_name);
ret = -ENODEV;
goto exit_free_fck;
}
clk_enable(priv->ick);
/* get the platform data */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
ret = -ENODEV;
dev_err(&pdev->dev, "No mem resource\n");
goto exit_free_clks;
}
if (!request_mem_region(mem->start, resource_size(mem),
D_CAN_DRV_NAME)) {
dev_err(&pdev->dev, "resource unavailable\n");
ret = -EBUSY;
goto exit_free_clks;
}
addr = ioremap(mem->start, resource_size(mem));
if (!addr) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto exit_release_mem;
}
/* IRQ specific to Error and status & can be used for Message Object */
ndev->irq = platform_get_irq_byname(pdev, "int0");
if (!ndev->irq) {
dev_err(&pdev->dev, "No irq0 resource\n");
goto exit_iounmap;
}
/* IRQ specific for Message Object */
priv->irq_obj = platform_get_irq_byname(pdev, "int1");
if (!priv->irq_obj) {
dev_err(&pdev->dev, "No irq1 resource\n");
goto exit_iounmap;
}
priv->base = addr;
priv->can.clock.freq = clk_get_rate(priv->fck);
priv->test_mode = pdata->test_mode_enable;
platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
ret = register_d_can_dev(ndev);
if (ret) {
dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
D_CAN_DRV_NAME, ret);
goto exit_free_device;
}
dev_info(&pdev->dev, "%s device registered (irq=%d, irq_obj=%d)\n",
D_CAN_DRV_NAME, ndev->irq, priv->irq_obj);
return 0;
exit_free_device:
platform_set_drvdata(pdev, NULL);
exit_iounmap:
iounmap(addr);
exit_release_mem:
release_mem_region(mem->start, resource_size(mem));
exit_free_clks:
clk_disable(priv->ick);
clk_put(priv->ick);
exit_free_fck:
clk_disable(priv->fck);
clk_put(priv->fck);
exit_free_ndev:
free_d_can_dev(ndev);
exit:
dev_err(&pdev->dev, "probe failed\n");
return ret;
}
static int __devexit d_can_plat_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct d_can_priv *priv = netdev_priv(ndev);
struct resource *mem;
unregister_d_can_dev(ndev);
platform_set_drvdata(pdev, NULL);
free_d_can_dev(ndev);
iounmap(priv->base);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, resource_size(mem));
clk_disable(priv->ick);
clk_disable(priv->fck);
clk_put(priv->ick);
clk_put(priv->fck);
return 0;
}
static struct platform_driver d_can_plat_driver = {
.driver = {
.name = D_CAN_DRV_NAME,
.owner = THIS_MODULE,
},
.probe = d_can_plat_probe,
.remove = __devexit_p(d_can_plat_remove),
};
static int __init d_can_plat_init(void)
{
printk(KERN_INFO D_CAN_DRV_DESC "\n");
return platform_driver_register(&d_can_plat_driver);
}
module_init(d_can_plat_init);
static void __exit d_can_plat_exit(void)
{
printk(KERN_INFO D_CAN_DRV_DESC " unloaded\n");
platform_driver_unregister(&d_can_plat_driver);
}
module_exit(d_can_plat_exit);
MODULE_AUTHOR("Anil Kumar Ch <anilkumar at ti.com>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(D_CAN_VERSION);
MODULE_DESCRIPTION(D_CAN_DRV_DESC);/
l4/pkg/d_can/d_can/Makefile:
/PKGDIR ?= ..
L4DIR ?= $(PKGDIR)/../..
DDE_SYSTEMS = x86 arm
TARGET = d_can
SRC_C = d_can.c d_can_platform.c
REQUIRES_LIBS = slab ddekit dde-linux26 dde-linux26_net libio l4util
l4re_c-util
ifeq ($(ARCH), arm)
DEFINES += -D__LINUX_ARM_ARCH__=6
ARCH_DIR = arch/arm
endif
include $(PKGDIR)/../dde/linux26/Makeconf
#include $(PKGDIR_OBJ)/Makeconf
include $(L4DIR)/mk/prog.mk
#
# Makefile for the Bosch D_CAN controller drivers.
#
obj-$(CONFIG_CAN_D_CAN) += d_can.o
obj-$(CONFIG_CAN_D_CAN_PLATFORM) += d_can_platform.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
/
l4/pkg/D-can/d_can/Kconfig:
/menuconfig CAN_D_CAN
tristate "Bosch D_CAN devices"
depends on CAN_DEV && HAS_IOMEM
if CAN_D_CAN
config CAN_D_CAN_PLATFORM
tristate "Generic Platform Bus based D_CAN driver"
---help---
This driver adds support for the D_CAN chips connected to
the "platform bus" (Linux abstraction for directly to the
processor attached devices) which can be found on am335x
and dm814x boards from TI (http://www.ti.com).
endif/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://os.inf.tu-dresden.de/pipermail/l4-hackers/attachments/20140826/4bbbf59c/attachment.html>
More information about the l4-hackers
mailing list