From ff238a4df84428befc55d49f58864dfc47ff853d Mon Sep 17 00:00:00 2001 From: Todd Doucet Date: Wed, 3 Feb 2010 17:06:33 -0500 Subject: Kernel as received from Digi for their Wi-Mx51 SoC running on their CCWMX51JS carrier board. --- drivers/fims/can/fim_can.c | 1483 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1483 insertions(+) create mode 100644 drivers/fims/can/fim_can.c (limited to 'drivers/fims/can/fim_can.c') diff --git a/drivers/fims/can/fim_can.c b/drivers/fims/can/fim_can.c new file mode 100644 index 000000000000..f71eae26357b --- /dev/null +++ b/drivers/fims/can/fim_can.c @@ -0,0 +1,1483 @@ +/* -*- linux-c -*- + * + * drivers/fims/fim_can.c + * + * Copyright (C) 2008-2009 by Digi International Inc. + * All rights reserved. + * + * 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. + * + * !Revision: $Revision: 1.2 $ + * !Author: Luis Galdos, Hector Oron + * !Descr: + * !References: Based on the virtual CAN driver (Copyright (c) 2002-2007 + * Volkswagen Group Electronic Research) + * All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Header files for the CAN-stack */ +#include +#include +#include + +/* For registering the FIM-driver */ +#include +#include + +/* If the driver is being to be loaded as a built-in driver, then include the header */ +#if !defined(MODULE) +#include "fim_can.h" +extern const unsigned char fim_can_firmware[]; +#define FIM_CAN_FIRMWARE_FILE (NULL) +#define FIM_CAN_FIRMWARE_CODE fim_can_firmware +#else +const unsigned char *fim_can_firmware = NULL; +#define FIM_CAN_FIRMWARE_FILE "fim_can.bin" +#define FIM_CAN_FIRMWARE_CODE (NULL) +#endif + +/* Driver informations */ +#define DRIVER_VERSION "1.2" +#define DRIVER_AUTHOR "Luis Galdos, Hector Oron" +#define DRIVER_DESC "FIM CAN bus driver" +#define FIM_DRIVER_NAME "fim-can" +#define FIM_DRIVER_FIRMWARE_NAME "fim_can.bin" +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +/* Module parameter for selection the FIMs */ +NS921X_FIM_NUMBERS_PARAM(fims_number); + +#define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] fim-can: " fmt, ## args) +#define printk_info(fmt, args...) printk(KERN_INFO "fim-can: " fmt, ## args) +#define printk_dbg(fmt, args...) printk(KERN_DEBUG "fim-can: " fmt, ## args) + +#if 0 +#define FIM_CAN_DEBUG +#endif + +#ifdef FIM_CAN_DEBUG +# define printk_debug(fmt, args...) printk(KERN_DEBUG "fim-can: " fmt, ## args) +#else +# define printk_debug(fmt, args...) do { } while (0) +#endif + +#define FIM_PRIVATE_BUFFER ((void *)0xffffffff) + +/* Available commands for the PIC */ +#define FIM_CAN_CMD_TX 0x00 +#define FIM_CAN_CMD_SHUTDOWN 0x40 +#define FIM_CAN_CMD_CONFIG 0x41 +#define FIM_CAN_CMD_FILTER(i) (0x80 + i) +#define FIM_CAN_ERR_FILTER(i) (i > 0x87 || i < 0x80) +#define FIM_CAN_NR_FILTERS (8) + +/* Default timing values (see Net+OS driver: nacbus.c) */ +#define FIM_CAN_DEFAULT_SJW (7) +#define FIM_CAN_DEFAULT_PROPSEG (8) +#define FIM_CAN_DEFAULT_PHASE1 (8) +#define FIM_CAN_DEFAULT_PHASE2 (8) +#define FIM_CAN_DEFAULT_BITRATE CAN_BITRATE_DEFAULT + +/* Maximal values from the Net+OS driver */ +#define FIM_CAN_MAX_BITRATE (1000000) + +#define CAN_BUS_RECESSIVE (0xffffffff) +#define CAN_BUS_DOMINANT (0x00000000) + +/* Status register according to the FIM-firmware specification (page 9) */ +#define FIM_CAN_BUSSTATE_REG 0 +#define FIM_CAN_TXERRCNT_REG 1 +#define FIM_CAN_RXERRCNT_REG 2 +#define FIM_CAN_FATALERR_REG 3 + +/* Control bits of the bus state register */ +#define FIM_CAN_BUSSTATE_ERRPAS 0x01 +#define FIM_CAN_BUSSTATE_OFF 0x02 + +/* Control bits of the fatal error register */ +#define FIM_CAN_FATAL_CONTROLLER 0x01 +#define FIM_CAN_FATAL_CMDERR 0x40 +#define FIM_CAN_FATAL_HW 0x41 +#define FIM_CAN_FATAL_FILTER 0x42 +#define FIM_CAN_FATAL_CONFIG 0x43 + +/* Interrupts from the FIM to the ARM (see can_defs.inc) */ +#define FIM_CAN_INT_RESET (0x01) +#define FIM_CAN_INT_CMD_ERR (0x45) +#define FIM_CAN_INT_HW_FAILURE (0x41) +#define FIM_CAN_INT_FILTER_ERR (0x42) +#define FIM_CAN_INT_CFG_ERR (0x43) + +/* + * Macros for the configuration of the DMA-channel + */ +#define FIM_CAN_DMA_BUFFER_SIZE (256) +#define FIM_CAN_DMA_BUFFERS (60) + +/* + * @XXX: Remove this ugly macro and use a structure for the PIC-message according + * to the specification, page 8 (Transmit message) + */ +#define FIRST_DATA_BYTE_IN_MESSAGE (3) + +/* + * GPIO configuration + */ +#define FIM_CAN_MAX_GPIOS (2) + +/* Structure for setting the ID-filters */ +#define FIM_CAN_FILTER_SIZE (8) +struct fim_can_filter_t { + u8 code; + u8 filter[FIM_CAN_FILTER_SIZE]; +}; + +/* + * Initializing some needed variables. This is important step + * as CAN driver might not work upon this values + */ +static struct can_bittiming_const fim_bittiming_const = { + .tseg1_min = 1, + .tseg1_max = 200, + .tseg2_min = 1, + .tseg2_max = 200, + .sjw_max = 40, + .brp_min = 1, + .brp_max = 2048, + .brp_inc = 1, +}; + +/* + * This structure provides the interface for configuring the timing parameters of + * the CAN-controller. + */ +struct fim_can_timing_t { + u8 code; + u16 sjw; + u16 cspl; + u16 cp2pl; + u16 csi; + u16 cp2i; + u16 csp; +} __attribute__ ((packed)); + +/* + * Structure for sending the shutdown command to the FIM + * This command is required before stopping the FIM, otherwise a transmitted + * frame can be corrupted + */ +struct fim_can_shutdown_t { + u8 code; +}; + +/* + * Structure for sending user-data to the controller + * @XXX: The maximal frame length is just an arbitrary value (can be modified) + */ +#define FIM_CAN_FRAME_LENGTH 128 +struct fim_can_txframe { + u16 crc; + u32 bytepos; + u32 bitcnt; + u32 bitstuff; + u32 last5; + u32 stuffed; + u32 len; + u32 result; + u8 buffer[FIM_CAN_FRAME_LENGTH]; +}; + +/* @FIXME: Use the generic structure for the CAN-frames from */ +struct fim_can_rxframe { + u8 id[4]; + u8 ctrl; + u8 data[8]; +} __attribute__ ((packed)); + +struct fim_can_t { + struct can_priv can; + int index; + struct fim_driver fim; + struct semaphore sem; + struct net_device *dev; + int reg; + struct fim_gpio_t gpios[FIM_CAN_MAX_GPIOS]; + struct clk *cpu_clk; + int opened; + spinlock_t lock; +}; + +/* Function prototypes */ +static int fim_can_send_skb(struct fim_can_t *port, unsigned char *data, int len, + struct sk_buff *skb); +static int fim_can_send_buffer(struct fim_can_t *port, unsigned char *data, int len); +static int fim_can_restart_fim(struct fim_can_t *port); +static int fim_can_start_fim(struct fim_can_t *port); +static int fim_can_stop_fim(struct fim_can_t *port); + +/* Debug function for dumping the CAN-frames for the FIM-firmware */ +#if defined(FIM_CAN_DEBUG) +#define fim_can_dump_frame(f, m) fim_can_do_dump_frame(f, m) +#else +#define fim_can_dump_frame(f, m) do { } while (0) +#endif +inline static void fim_can_do_dump_frame(struct fim_can_txframe *frame, char *marke) +{ + int cnt; + char buffer[512]; + unsigned int pos; + int len; + unsigned char *data; + + len = 3 + (frame->stuffed + 7) / 8; + data = (unsigned char *)(frame->buffer); + pos = 0; + for (cnt = 0; cnt < len; cnt++) + pos += snprintf(buffer + pos, sizeof(buffer), "0x%02x ", *(data + cnt)); + + printk_debug("%s buffer : %s\n", marke, buffer); + printk_debug("%s infos :\n\ +\tCRC : 0x%x\n\ +\tbytePos : 0x%x\n\ +\tbitCount : 0x%x\n\ +\tbitStuff : 0x%x\n\ +\tlast 5 : 0x%x\n\ +\tstuffed count : 0x%x\n", + marke, + frame->crc, + frame->bytepos, + frame->bitcnt, + frame->bitstuff, + frame->last5, + frame->stuffed); +} + +/* Debug function for dumping the CAN-timing parameters */ +#if defined(FIM_CAN_DEBUG) +#define fim_can_dump_timing(cfg, s, p, y, b) fim_can_do_dump_timing(cfg, s, p, y, b) +#else +#define fim_can_dump_timing(cfg, s, p, y, b) do { } while (0) +#endif + +/* Print the timing values for the controller */ +inline static void fim_can_do_dump_timing(struct fim_can_timing_t *cfg, + unsigned int sjw, unsigned int sample_point, + unsigned int sync_period, unsigned int bitrate) +{ + printk_debug("SJW %u | Sample point %u | Sync period %u | Bitrate %u\n\ +\tSJW : 0x%04x\n\ +\tCSPL : 0x%04x\n\ +\tCP2PL : 0x%04x\n\ +\tCSI : 0x%04x\n\ +\tCP2I : 0x%04x\n\ +\tCSP : 0x%04x\n\ +", + sjw, + sample_point, + sync_period, + bitrate, + cfg->sjw, + cfg->cspl, + cfg->cp2pl, + cfg->csi, + cfg->cp2i, + cfg->csp); +} + +inline static void fim_can_parse_filter(struct fim_can_filter_t *flt, canid_t id, + canid_t mask) +{ + flt->filter[0] = (id >> 24); + flt->filter[1] = (mask >> 24); + flt->filter[2] = (id >> 16); + flt->filter[3] = (mask >> 16); + flt->filter[4] = (id >> 8); + flt->filter[5] = (mask >> 8); + flt->filter[6] = id; + flt->filter[7] = mask; +} + +/* Calculate the latency times for the passed bitrate */ +static int fim_can_calculate_latency(u32 bitrate, u16 *rx, u16 *tx) +{ + int ret; + + if (bitrate <= 0 || bitrate > FIM_CAN_MAX_BITRATE) + return -ERANGE; + + /* + * In the future we will probably need different latency times for the + * bitrates. Let us keep this function for this purpose. + */ +#define FIM_CAN_RXIRQ_LATENCY (1) +#define FIM_CAN_TXIRQ_LATENCY (100) + *rx = FIM_CAN_RXIRQ_LATENCY; + *tx = FIM_CAN_TXIRQ_LATENCY; + ret = 0; + + return ret; +} + +static int fim_can_shutdown(struct fim_can_t *port) +{ + struct fim_buffer_t buf; + struct fim_can_shutdown_t cmd; + + cmd.code = FIM_CAN_CMD_SHUTDOWN; + + buf.private = FIM_PRIVATE_BUFFER; + buf.length = sizeof(struct fim_can_shutdown_t); + buf.data = (unsigned char *)&cmd; + + return 0; +} + +/* Configures all timing values */ +static void fim_can_fill_timing(struct fim_can_t *port, struct fim_can_timing_t *tim, + u16 sjw, u16 sample_point, u16 sync_period) +{ + unsigned int ten_per; + u16 larx, latx; + struct can_bittiming *bt; + + bt = &port->can.bittiming; + printk_debug("New timing: %u bps | sjw %u | sample %u | sync %u | clock %u\n", + bt->bitrate, + sjw, + sample_point, + sync_period, + bt->clock); + + if (fim_can_calculate_latency(bt->bitrate, &larx, &latx)) { + printk_err("Failed latency calculation for rate %u\n", bt->bitrate); + return; + } + + /* Calculate how many clocks are in the ten percent of the bit rate */ + ten_per = (clk_get_rate(port->cpu_clk) + (5 * bt->bitrate)) / (10 * bt->bitrate); + printk_debug("Ten percent by %i Bps is aprox. %i\n", bt->bitrate, ten_per); + + tim->sjw = (sjw * ten_per + 5) / 10; + tim->cspl = (sample_point * ten_per + 5) / 10; + tim->cp2pl = (((100 - sample_point) * ten_per) + 5) / 10; + tim->csi = larx; + tim->cp2i = latx; + tim->csp = ((sync_period * ten_per) + 5) / 10; + + printk_debug("sjw: %d \tcspl: %d \tcp2pl: %d \tcsi: %d \tcp2i: %d \tcsp: %d\n", + tim->sjw, tim->cspl, tim->cp2pl, + tim->csi, tim->cp2i, tim->csp); +} + +/* Configure the filter for accepting all the incoming messages */ +inline static void fim_can_filter_accept(struct fim_can_filter_t *filter) +{ + memset(filter->filter, 0x00, FIM_CAN_FILTER_SIZE); +} + +/* Configure the filter for rejecting all the incoming messages */ +inline static void fim_can_filter_reject(struct fim_can_filter_t *filter) +{ + memset(filter->filter, 0x20, FIM_CAN_FILTER_SIZE); +} + +/* + * This function inits the CAN-controller according to its specification. + * Unfortunately the firmware expects the configuration data and the filters in + * only ONE message. For this reason we need a separated function only for the + * init-configuration + */ +static int fim_can_set_init_config(struct fim_can_t *port) +{ + struct fim_can_timing_t cfg; + struct fim_can_filter_t filters[FIM_CAN_NR_FILTERS]; + int cnt, retval; + unsigned char *ptr; + unsigned char data[sizeof(struct fim_can_timing_t) + (FIM_CAN_NR_FILTERS * 8)]; + struct can_bittiming *bt; + + /* Init the timing parameters */ + cfg.code = FIM_CAN_CMD_CONFIG; + bt = &port->can.bittiming; + + if (bt->bitrate == 0) { + printk("Sorry, bitrate required for\n"); + return -EINVAL; + } + + /* We must use the default bit rates for our FIM-firmware */ + if (!bt->sjw) + bt->sjw = FIM_CAN_DEFAULT_SJW; + if (!bt->prop_seg) + bt->prop_seg = FIM_CAN_DEFAULT_PROPSEG; + + if (!bt->phase_seg1) + bt->phase_seg1 = FIM_CAN_DEFAULT_PHASE1; + + if (!bt->phase_seg2) + bt->phase_seg2 = FIM_CAN_DEFAULT_PHASE2; + + fim_can_fill_timing(port, &cfg, + bt->sjw, + bt->prop_seg + bt->phase_seg1 + 1, + bt->phase_seg2); + + fim_can_do_dump_timing(&cfg, + bt->sjw, + bt->prop_seg + bt->phase_seg1 + 1, + bt->phase_seg2, + bt->bitrate); + + /* Not init the filter with the default values */ + for (cnt = 0; cnt < FIM_CAN_NR_FILTERS; cnt++) + fim_can_filter_accept(&filters[cnt]); + + /* Now setup the init message */ + memcpy(data, &cfg, sizeof(struct fim_can_timing_t)); + ptr = data + sizeof(struct fim_can_timing_t); + for (cnt = 0; cnt < FIM_CAN_NR_FILTERS; cnt++) + memcpy(ptr, filters[cnt].filter, FIM_CAN_FILTER_SIZE); + + retval = fim_can_send_buffer(port, data, sizeof(data)); + if (retval) + printk_err("Couldn't send the init config.\n"); + + return retval; +} + +/* + * Implement the interface for chaning the state of the CAN-controller. The user + * have access to this function over the sysfs attributes: + * echo 2 > sys/class/net/can0/can_restart : mode = 1 (CAN_MODE_START) + * + */ +static int fim_can_set_mode(struct net_device *dev, enum can_mode mode) +{ + struct fim_can_t *port; + struct fim_driver *fim; + int retval; + + port = netdev_priv(dev); + fim = &port->fim; + + printk_debug("Set mode command %x called (FIM %i)\n", mode, fim->picnr); + + if (!port->opened) { + printk_err("CAN-port %i was not opened up now\n", fim->picnr); + return -ERESTARTSYS; + } + + /* + * The different modes can be set using the sysfs attributes: + * start : /sys/class/net/can0/can_restart + */ + switch (mode) { + case CAN_MODE_START: + printk_dbg("FIM%i: Starting the controller\n", fim->picnr); + retval = fim_can_restart_fim(port); + break; + case CAN_MODE_STOP: + printk_dbg("FIM%i: Stopping the controller\n", fim->picnr); + retval = fim_can_stop_fim(port); + break; + default: + retval = -EOPNOTSUPP; + break; + } + + return retval; +} + +/* + * Read the status registers of the FIM for obtaining the status information. + */ +static int fim_can_get_state(struct net_device *dev, enum can_state *state) +{ + struct fim_can_t *port; + struct fim_driver *fim; + int retval; + unsigned int bus, fatal; + + port = netdev_priv(dev); + fim = &port->fim; + printk_debug("Get state called (FIM %i)\n", fim->picnr); + + retval = fim_get_exp_reg(fim, FIM_CAN_BUSSTATE_REG, &bus); + if (retval) { + printk_err("Reading the bus state register (%i)\n", retval); + goto exit_all; + } + + retval = fim_get_exp_reg(fim, FIM_CAN_FATALERR_REG, &fatal); + if (retval) { + printk_err("Reading the fatal error register (%i)\n", retval); + goto exit_all; + } + + /* @XXX: Are we using the correct flag for informing about the error? */ + if (fatal) { + *state = CAN_STATE_BUS_OFF; + goto exit_all; + } + + /* Check the current status of the BUS */ + if (port->can.state == CAN_STATE_STOPPED) { + printk_debug("Controller was stopped\n"); + *state = CAN_STATE_STOPPED; + } else if (bus & FIM_CAN_BUSSTATE_OFF) { + printk_debug("Current Bus state seems to be OFF\n"); + *state = CAN_STATE_BUS_OFF; + } else if (bus & FIM_CAN_BUSSTATE_ERRPAS) { + printk_debug("Bus seems to be in the passive error state\n"); + *state = CAN_STATE_BUS_PASSIVE; + } else + *state = CAN_STATE_ACTIVE; + + retval = 0; + +exit_all: + return retval; +} + +/* Return zero if the FIM was successful stopped */ +static int fim_can_stop_fim(struct fim_can_t *port) +{ + int retval; + struct fim_driver *fim; + + if (!port) + return -ENODEV; + + /* + * We will disable the IRQ anyway (otherwise is too dangerous having the + * active interrupt) + */ + retval = 0; + fim = &port->fim; + if (fim_is_running(fim)) { + retval = fim_send_stop(fim); + printk_debug("%s: Disabling interrupt\n",__func__); + fim_disable_irq(fim); + } + + return retval; +} + +/* + * This function will download the firmware, start and reconfigure the CAN-controller + * For starting the FIM we assume that it was already stopped! + */ +static int fim_can_start_fim(struct fim_can_t *port) +{ + struct fim_driver *fim; + int retval; + + if (!port) + return -ENODEV; + + fim = &port->fim; + if (fim_is_running(fim)) { + printk_debug("The FIM %i is already running\n", fim->picnr); + return 0; + } + + /* + * The function for downloading the firmware will stop the FIM if + * its still running + */ + retval = fim_download_firmware(fim); + if (retval) + return -EAGAIN; + + retval = fim_send_start(fim); + if (retval) + return -EAGAIN; + + printk_debug("Enable interrupt\n"); + fim_enable_irq(fim); + + /* + * Disable the interrupt if an error is detected, otherwise the system + * can hang up + */ + retval = fim_can_set_init_config(port); + if (retval) { + printk_debug("%s: Disabling interrupt\n",__func__); + fim_disable_irq(fim); + return retval; + } + + return retval; +} + +/* + * This function restart the FIM + * It includes the reconfiguration of the CAN-port too (it will send the init + * configuration to the port too) + */ +static int fim_can_restart_fim(struct fim_can_t *port) +{ + int retval; + + if (!port) + return -ENODEV; + + /* First try to stop the FIM */ + retval = fim_can_stop_fim(port); + if (retval) + return retval; + + return fim_can_start_fim(port); +} + +/* + * This function is called when the interface is going up (ifconfig up) + * Only enable the interrupt and restart the netdev queue. + */ +static int fim_can_open(struct net_device *dev) +{ + struct fim_can_t *port; + struct fim_driver *fim; + int retval; + + /* So, lets start the PIC with our default data */ + port = netdev_priv(dev); + fim = &port->fim; + printk_debug("Open function called (FIM %i)\n", fim->picnr); + + /* Always set the CAN-interface to the active state! */ + retval = fim_can_restart_fim(port); + if (!retval) { + netif_start_queue(dev); + port->can.state = CAN_STATE_ACTIVE; + port->opened = 1; + } + + return retval; +} + +/* + * This function is called when the interface is going down (ifconfig down) + * Disable the IRQ and the netif queue. + */ +static int fim_can_stop(struct net_device *dev) +{ + struct fim_can_t *port; + struct fim_driver *fim; + int retval = 0; + + port = netdev_priv(dev); + fim = &port->fim; + printk_debug("Close function called (FIM %i)\n", fim->picnr); + + /* Paranoic sanity check */ + if (!port->opened) + return 0; + + netif_stop_queue(dev); + can_close_cleanup(dev); + port->can.state = CAN_STATE_STOPPED; + port->opened = 0; + + /* Transmit a shutdown command to the FIM before stopping it */ + if (fim_is_running(fim)) { + retval = fim_can_shutdown(port); + if (retval) { + printk_err("Unable to shutdown the FIM %i\n", fim->picnr); + goto err_exit; + } + + /* + * The below delay is arbitrary and should give the FIM some time + * for processing the last CAN-frame on the bus + */ + udelay(1000); + + /* Check if need to stop the FIM */ + printk_debug("%s: Disabling interrupt\n", __func__); + fim_disable_irq(fim); + fim_send_stop(fim); + } + +err_exit: + return retval; +} + +/* + * This function will save the SKB-pointer inside the FIM-buffer. By this way + * is possible to free the SKB inside the TX-callback + */ +static int fim_can_send_skb(struct fim_can_t *port, unsigned char *data, int len, + struct sk_buff *skb) +{ + struct fim_buffer_t buf; + + buf.private = skb; + buf.length = len; + buf.data = data; + return fim_send_buffer(&port->fim, &buf); +} + +/* + * This function will mask the FIM-buffer so that in the TX-callback we can + * know that it doesn't contain any important information for us + */ +static int fim_can_send_buffer(struct fim_can_t *port, unsigned char *data, int len) +{ + struct fim_buffer_t buf; + + buf.private = FIM_PRIVATE_BUFFER; + buf.length = len; + buf.data = data; + return fim_send_buffer(&port->fim, &buf); +} + +/* + * Write one bit to the frame, update the CRC, and bit stuff if we have + * 5 consecutive bits all of the same value. + */ +#define LOWEST_FIVE_BITS_MASK (0x1f) +static void fim_can_write_stuffbit(struct fim_can_txframe *frame, unsigned bit) +{ + bit &= 1; + + frame->buffer[frame->bytepos] = (frame->buffer[frame->bytepos] << 1) | bit; + frame->last5 = ((frame->last5 << 1) | bit) & LOWEST_FIVE_BITS_MASK; + frame->bitcnt++; + frame->stuffed++; + + if (frame->bitcnt == 8) { + frame->bytepos += 1; + frame->bitcnt = 0; + } + + if (frame->bitstuff && ((frame->last5 == LOWEST_FIVE_BITS_MASK) || + (frame->last5 == 0))) + fim_can_write_stuffbit(frame, ~frame->last5); +} + +/* + * Real CAN polynomial is 0xc599, but this value used used + * do to the way the algorithm works. The high bit is + * xor'ed in the first line. + */ +#define CAN_CRC_POLYNOMIAL_LESS_HIGH_BIT (0x4599) +inline static void fim_can_add_crc(struct fim_can_txframe *frame, unsigned short bit) +{ + unsigned short crcnxt; + + frame->crc <<= 1; + crcnxt = ((frame->crc & 0x8000) != 0) ^ (bit); + frame->crc &= 0x7ffe; + if (crcnxt) + frame->crc ^= CAN_CRC_POLYNOMIAL_LESS_HIGH_BIT; +} + +inline static void fim_can_frame_writeone(struct fim_can_txframe *frame, u32 bit) +{ + fim_can_add_crc(frame, bit); + fim_can_write_stuffbit(frame, bit); +} + +/* + * Write one or more bits to the frame. + */ +inline static void fim_can_frame_write(struct fim_can_txframe *frame, unsigned int data, + int bits) +{ + int idx; + for (idx = bits - 1; idx >= 0; idx--) + fim_can_frame_writeone(frame, (data & (1 << idx)) != 0); +} + +inline static void fim_can_frame_stop_stuff(struct fim_can_txframe *frame) +{ + frame->bitstuff = 0; +} + +inline static void fim_can_frame_start(struct fim_can_txframe *frame) +{ + frame->crc = 0; + frame->bytepos = FIRST_DATA_BYTE_IN_MESSAGE; + + frame->last5 = CAN_BUS_RECESSIVE; + frame->bitcnt = 0; + frame->bitstuff = 1; + frame->stuffed = 0; + fim_can_frame_writeone(frame, CAN_BUS_DOMINANT); +} + +inline static void fim_can_frame_stop(struct fim_can_txframe *frame) +{ + frame->buffer[frame->bytepos] <<= (8 - frame->bitcnt); + frame->buffer[frame->bytepos] |= (0xFF >> frame->bitcnt); +} + +/* + * Function that checks if the CAN-controller registered an error + * If an error is detected, then a error frame will be passed to the socket-layer + * Return zero if no error was detected, otherwise an value different than zero + */ +static int fim_can_check_error(struct net_device *dev) +{ + struct sk_buff *skb; + struct fim_can_t *port; + struct fim_driver *fim; + struct can_frame *cf; + unsigned int bus, fatal; + struct net_device_stats *stats; + + port = netdev_priv(dev); + fim = &port->fim; + fim_get_exp_reg(fim, FIM_CAN_BUSSTATE_REG, &bus); + fim_get_exp_reg(fim, FIM_CAN_FATALERR_REG, &fatal); + + if ((!bus) && (!fatal)) + return 0; + + printk_debug("Calling the error handling function (Bus 0x%x)\n", bus); + + /* Stop the FIM if it's running */ + if (fim_is_running(fim)) { + printk_debug("%s: Disabling interrupt\n",__func__); + fim_disable_irq(fim); + fim_send_stop(fim); + } + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (!skb) { + printk_err("Couldn't create the ERROR frame\n"); + goto end_exit; + } + + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0x00, sizeof(struct can_frame)); + cf->can_id = CAN_ERR_FLAG; + cf->can_dlc = CAN_ERR_DLC; + + /* + * These are the possible errors defined in the FIM-CAN specification + * The corresponding error flags are under: include/linux/can/error.h + */ + if (bus & FIM_CAN_BUSSTATE_OFF) + cf->can_id |= CAN_ERR_BUSOFF; + + /* @XXX: This seems to be the correct flags for our controller, or? */ + if (bus & FIM_CAN_BUSSTATE_ERRPAS) { + cf->can_id |= CAN_ERR_BUSERROR; + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; + port->can.can_stats.error_passive++; + } + + /* Pass the error frame to the socket layer */ + netif_rx(skb); + + dev->last_rx = jiffies; + stats = dev->get_stats(dev); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + +end_exit: + return 1; +} + +static int fim_can_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fim_can_t *port; + struct net_device_stats *stats; + struct can_frame *cf; + struct fim_can_txframe frame; + u8 dlc, cnt; + int retval; + canid_t id; + + port = netdev_priv(dev); + spin_lock(&port->lock); + netif_stop_queue(dev); + spin_unlock(&port->lock); + + stats = dev->get_stats(dev); + cf = (struct can_frame *)skb->data; + + id = cf->can_id; + dlc = cf->can_dlc; + + /* + * Check for the bus state before sending the data + * @FIXME: The controller fails if its state is the error passive + */ + if (fim_can_check_error(dev)) { + printk_debug("Bus OFF or unknown error. Aborting Xmit %p\n", skb); + stats->tx_dropped++; + spin_lock(&port->lock); + dev_kfree_skb(skb); + netif_wake_queue(dev); + spin_unlock(&port->lock); + return NETDEV_TX_OK; + } + + /* Reset our frame first */ + memset(&frame, 0x0, sizeof(struct fim_can_txframe)); + + fim_can_frame_start(&frame); + fim_can_dump_frame(&frame, "START"); + + /* Check for the extended ID (18 bits length) */ + if (id & CAN_EFF_FLAG) + fim_can_frame_write(&frame, id, 18); + else + fim_can_frame_write(&frame, id, 11); + + fim_can_dump_frame(&frame, "ID"); + + /* Check if we have a RTR message */ + if (id & CAN_RTR_FLAG) + fim_can_frame_write(&frame, 1, 1); + else + fim_can_frame_write(&frame, 0, 1); + fim_can_dump_frame(&frame, "RTR"); + + /* Write the identifier bit which is dominant in the standard frame */ + fim_can_frame_write(&frame, 0, 1); + fim_can_dump_frame(&frame, "IDE"); + + /* Write the R0 bit */ + fim_can_frame_write(&frame, 0, 1); + fim_can_dump_frame(&frame, "RESERVE"); + + /* Write the control field (data length passed by the user) */ + fim_can_frame_write(&frame, dlc, 4); + fim_can_dump_frame(&frame, "CONTROL"); + + /* + * Now write the data bytes (maximal eight bytes) + * According to the CAN-specification, don't add the data bytes to the frame + * although the data length code is greter than zero + */ + for (cnt = 0; cnt < (dlc & 0x0F) && !(id & CAN_RTR_FLAG); cnt++) + fim_can_frame_write(&frame, cf->data[cnt], 8); + + fim_can_dump_frame(&frame, "DATA"); + + /* Write the CRC */ + fim_can_frame_write(&frame, frame.crc, 15); + fim_can_dump_frame(&frame, "CRC"); + + /* Stop the bit stuffing for this frame */ + fim_can_frame_stop_stuff(&frame); + + /* Write the CRC delimiter, CRC ACK and ACK delimiter */ + fim_can_frame_write(&frame, CAN_BUS_RECESSIVE, 3); + fim_can_dump_frame(&frame, "CRC/ACK"); + + fim_can_frame_stop(&frame); + + /* + * Set the first three byte of the frame as described in the specification + * (see page 8, transmit message structure) + */ + frame.buffer[0] = FIM_CAN_CMD_TX; + frame.buffer[1] = ((id & CAN_EFF_FLAG) ? 18 : 11) + 1; + frame.buffer[2] = frame.stuffed; + fim_can_dump_frame(&frame, "END"); + + printk_debug("Sending a new SKB %p\n", skb); + retval = fim_can_send_skb(port, frame.buffer, 3 + (frame.stuffed + 7) / 8, skb); + if (retval) { + stats->tx_fifo_errors++; + stats->tx_dropped++; + printk_err("Couldn't send a frame with the ID 0x%X\n", id); + goto exit_free_skb; + } + + stats->tx_bytes += dlc; + stats->tx_packets++; + dev->trans_start = jiffies; + +exit_free_skb: + return NETDEV_TX_OK; +} + +/* + * Only errors are being generated by the firmware + * If an error ocurrs the FIM must be resetted (it hangs up in a endless loop) + */ +static void fim_can_isr(struct fim_driver *driver, int irq, unsigned char code, + unsigned int rx_fifo) +{ + struct net_device *dev; + struct fim_can_t *port; + + printk_debug("FIM IRQ %x | %08x\n", code, rx_fifo); + + port = driver->driver_data; + dev = port->dev; + + if (code && code != FIM_CAN_INT_RESET) { + printk_debug("%s: Disabling interrupt\n",__func__); + fim_disable_irq(driver); + fim_send_stop(driver); + } + + switch (code) { + case FIM_CAN_INT_CMD_ERR: + printk_err("Command error (FIM %i)\n", driver->picnr); + break; + case FIM_CAN_INT_HW_FAILURE: + printk_err("HW failure (FIM %i). Please restart the controller.\n", + driver->picnr); + break; + case FIM_CAN_INT_FILTER_ERR: + printk_err("Filter error (FIM %i)\n", driver->picnr); + break; + case FIM_CAN_INT_CFG_ERR: + printk_err("Config error (FIM %i)\n", driver->picnr); + break; + default: + break; + } + + /* + * Check if we have a stop condition of the CAN-controller + * If we need to stop the controller, restart the netif-queue anyway, then + * otherwise we will have problems when freeing the SKBs + */ + if (code && code != FIM_CAN_INT_RESET) { + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } +} + +static void fim_can_tx_isr(struct fim_driver *driver, int irq, + struct fim_buffer_t *pdata) +{ + struct fim_can_t *port; + struct fim_buffer_t *buf; + struct net_device *dev; + unsigned long flags; + struct sk_buff *skb; + + port = driver->driver_data; + buf = pdata->private; + dev = port->dev; + skb = pdata->private; + + spin_lock_irqsave(&port->lock, flags); + printk_debug("TX callback | SKB %p | dev %p\n", skb, dev); + + /* + * @FIXME: If we remove this delay, then we will not catch the errors + * that can ocurrs during the frame transmission + */ + udelay(200); + + /* Restart the TX-queue if it was stopped for some reason */ + if (fim_can_check_error(dev)) + printk_debug("The udelay is working correctly\n"); + + /* + * Check if we have a SKB to free + * IMPORTANT: Allways free the SKB, otherwise we will have a memory leak, + * although in the template CAN-drivers they are not freeing the SKB + */ + if (skb && skb != FIM_PRIVATE_BUFFER) { + printk_debug("Freeing the SKB %p\n", skb); + dev_kfree_skb_irq(skb); + } + + /* + * Although we had a failure, we must restart the TX-queue, otherwise + * we will have a kernel panic when freeing the SKBs + */ + if (dev && netif_queue_stopped(dev)) { + printk_debug("Restarting the netif-queue\n"); + netif_wake_queue(dev); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * This function is called when the FIM has a new CAN-frame for us + * According to the configured filters we will receive only the filtered messages + */ +static void fim_can_rx_isr(struct fim_driver *driver, int irq, + struct fim_buffer_t *pdata) +{ + struct sk_buff *skb; + struct fim_can_t *port; + struct net_device *dev; + struct can_frame *cf; + struct net_device_stats *stats; + struct fim_can_rxframe *rx; + + /* Set our internal data */ + rx = (struct fim_can_rxframe *)pdata->data; + port = driver->driver_data; + dev = port->dev; + + printk_debug("New CAN-frame (%i bytes) | ID 0x%02x%02x%02x%02x\n", + pdata->length, rx->id[3], rx->id[2], rx->id[1], rx->id[0]); + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (!skb) { + printk_err("No memory available? Dropping a CAN-frame!\n"); + return; + } + + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0x00, sizeof(struct can_frame)); + + /* Start processing the arrived frame */ + + /* Set the CAN-ID corresponding to the FIM-controller specification */ + if (rx->id[0] & 0x80) + cf->can_id |= CAN_RTR_FLAG; + + if (rx->id[0] & 0x40) + cf->can_id |= CAN_EFF_FLAG; + + /* Remove the control bits and set to the correct ID */ + rx->id[0] &= 0x1F; + if (cf->can_id & CAN_EFF_FLAG) + cf->can_id |= rx->id[3] + (rx->id[2] << 8) + (rx->id[1] << 16) + + (rx->id[0] << 24); + else + cf->can_id |= (rx->id[1] >> 2) + (rx->id[0] << 6); + + /* Copy the data */ + cf->can_dlc = rx->ctrl & 0x0F; + memcpy(cf->data, rx->data, cf->can_dlc); + + /* Pass the data to the sockets-layer */ + netif_rx(skb); + + /* Update the device statics */ + stats = dev->get_stats(dev); + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; +} + +static int unregister_fim_can(struct fim_can_t *port) +{ + struct fim_gpio_t gpios[FIM_CAN_MAX_GPIOS]; + int cnt; + struct fim_driver *fim; + + if (!port || !port->reg) + return -ENODEV; + + //unregister_netdev(port->dev); + unregister_candev(port->dev); + free_candev(port->dev); + + /* Activate the interrupt (@BUG in the IRQ-subsystem?) */ + fim = &port->fim; + + printk_debug("%s: Disabling interrupt\n", __func__); + fim_disable_irq(fim); + + /* Stop the FIM first */ + if (!fim_is_running(fim)) + fim_send_stop(fim); + + printk_debug("Going to unregister the FIM %i (running %i)\n", + fim->picnr, fim_is_running(fim)); + fim_unregister_driver(fim); + + /* And free the GPIOs */ + memcpy(gpios, port->gpios, sizeof(struct fim_gpio_t) * FIM_CAN_MAX_GPIOS); + for (cnt = 0; cnt < FIM_CAN_MAX_GPIOS; cnt++) { + + if (gpios[cnt].nr != FIM_GPIO_DONT_USE) { + printk_debug("Freeing the GPIO %i\n", gpios[cnt].nr); + gpio_free(gpios[cnt].nr); + } + } + + /* Free the obtained clock */ + if (!IS_ERR(port->cpu_clk)) + clk_put(port->cpu_clk); + + port->reg = 0; + + return 0; +} + +/* + * IMPORTANT: First register the FIM-driver, and at last the CAN-device, then + * it will automatically start with the bit time configuration. + */ +static int register_fim_can(struct device *devi, int picnr, struct fim_gpio_t gpios[], + int bitrate) +{ + int retval, cnt; + int func; + struct net_device *dev; + struct fim_can_t *port; + struct fim_dma_cfg_t dma_cfg; + + /* Now create the net device */ + dev = alloc_candev(sizeof(struct fim_can_t)); + if (!dev) { + printk_err("Couldn't alloc a new CAN device\n"); + return -ENOMEM; + } + + /* Set our port structure as private data */ + port = netdev_priv(dev); + port->dev = dev; + + /* Get a reference to the SYS clock for setting the baudrate */ + if (IS_ERR(port->cpu_clk = clk_get(&dev->dev, "systemclock"))) { + printk_err("Couldn't get the SYS clock.\n"); + goto err_free_candev; + } + + /* Request the corresponding GPIOs (@XXX: Check the returned values) */ + for (cnt=0; cnt < FIM_CAN_MAX_GPIOS; cnt++) { + if (gpios[cnt].nr == FIM_LAST_GPIO) + break; + if (gpios[cnt].nr == FIM_GPIO_DONT_USE) + continue; + printk_debug("Requesting the GPIO %i (Function %i)\n", + gpios[cnt].nr, gpios[cnt].func); + retval = gpio_request(gpios[cnt].nr, FIM_DRIVER_NAME); + if (!retval) { + func = gpios[cnt].func; + gpio_configure_ns921x_unlocked(gpios[cnt].nr, + NS921X_GPIO_INPUT, + NS921X_GPIO_DONT_INVERT, + func, + NS921X_GPIO_ENABLE_PULLUP); + } else { + /* Free the already requested GPIOs */ + printk_err("Couldn't request the GPIO %i\n", gpios[cnt].nr); + while (cnt) + gpio_free(gpios[--cnt].nr); + goto err_free_candev; + } + } + + /* Now try to register the FIM-driver */ + port->fim.picnr = picnr; + port->fim.driver.name = FIM_DRIVER_NAME; + port->fim.fim_isr = fim_can_isr; + port->fim.dma_tx_isr = fim_can_tx_isr; + port->fim.dma_rx_isr = fim_can_rx_isr; + port->fim.driver_data = port; + + /* Specific DMA configuration for the CAN-controller */ + dma_cfg.rxnr = FIM_CAN_DMA_BUFFERS; + dma_cfg.txnr = FIM_CAN_DMA_BUFFERS; + dma_cfg.rxsz = FIM_CAN_DMA_BUFFER_SIZE; + dma_cfg.txsz = FIM_CAN_DMA_BUFFER_SIZE; + port->fim.dma_cfg = &dma_cfg; + + /* Check if have a firmware code for using to */ + port->fim.fw_name = FIM_CAN_FIRMWARE_FILE; + port->fim.fw_code = FIM_CAN_FIRMWARE_CODE; + retval = fim_register_driver(&port->fim); + if (retval) { + printk_err("Couldn't register the FIM %i CAN driver.\n", picnr); + goto err_free_gpios; + } + + /* Stop the FIM then it will be started in the open-function */ + fim_send_stop(&port->fim); + + /* Configure the net device with the default values */ + dev->flags |= IFF_ECHO; + dev->open = fim_can_open; + dev->stop = fim_can_stop; + dev->hard_start_xmit = fim_can_xmit; + + /* Special attributes for the CAN-stack */ + port->can.do_get_state = fim_can_get_state; + port->can.do_set_mode = fim_can_set_mode; + + port->can.bittiming.clock = clk_get_rate(port->cpu_clk); + printk_debug("CPU clock is %luHz\n", clk_get_rate(port->cpu_clk)); + + /* + * @TODO: Set the correct maximal BRP for the controller. + * DEFAULT_MAX_BRP 64 + * DEFAULT_MAX_SJW 4 + */ + port->can.bittiming_const = &fim_bittiming_const; + if (!port->can.bittiming_const) { + printk_debug("bittiming_const is not initialized.\n"); + goto err_unreg_fim; + } + + /* + * Only store the passed bitrate. The corresponding timing parameters + * will be setup in the function that sends the configuration to the FIM. + * (Luis Galdos) + */ + port->can.bittiming.bitrate = bitrate; + + /* Now register the new CAN-net device */ + retval = register_candev(dev); + if (retval) { + printk_err("Registering the net device for the FIM %i\n", picnr); + goto err_unreg_fim; + } + + spin_lock_init(&port->lock); + port->dev = dev; + memcpy(port->gpios, gpios, sizeof(struct fim_gpio_t) * FIM_CAN_MAX_GPIOS); + port->reg = 1; + dev_set_drvdata(devi, port); + + return 0; + +err_unreg_fim: + fim_unregister_driver(&port->fim); + +err_free_gpios: + for (cnt = 0; cnt < FIM_CAN_MAX_GPIOS; cnt++) { + + if (gpios[cnt].nr != FIM_GPIO_DONT_USE) { + printk_debug("Freeing the GPIO %i\n", gpios[cnt].nr); + gpio_free(gpios[cnt].nr); + } + } + +err_free_candev: + free_candev(dev); + + return -EINVAL; +} + +static __init int fim_can_probe(struct platform_device *pdev) +{ + int nrpics; + int retval; + struct fim_gpio_t gpios[FIM_CAN_MAX_GPIOS]; + struct fim_can_platform_data *pdata; + int bitrate; + + printk_debug("Starting the FIM CAN bus driver.\n"); + + pdata = pdev->dev.platform_data; + if (!pdata) + return -ENODEV; + + /* If no bitrate passed, then use the default bitrate */ + bitrate = pdata->fim_can_bitrate ? pdata->fim_can_bitrate : + FIM_CAN_DEFAULT_BITRATE; + + /* Sanity check for the passed bit rate */ + if (bitrate <= 0 || bitrate > FIM_CAN_MAX_BITRATE) { + printk_err("Invalid bit rate %i (max. rate is %i)\n", + bitrate, FIM_CAN_MAX_BITRATE); + return -EINVAL; + } + + /* Get the number of available PICs from the FIM-core */ + nrpics = fim_number_pics(); + + if (fim_check_device_id(fims_number, pdata->fim_nr)) { +#if defined(MODULE) + printk_dbg("Skipping FIM%i (not selected)\n", pdata->fim_nr); +#else + printk_err("Invalid FIM number '%i' in platform data\n", pdata->fim_nr); +#endif + return -ENODEV; + } + + /* + * Start with the registration of the CAN-ports + */ + gpios[0].nr = pdata->rx_gpio_nr; + gpios[0].func = pdata->rx_gpio_func; + gpios[1].nr = pdata->tx_gpio_nr; + gpios[1].func = pdata->tx_gpio_func; + printk_debug("%s: GPIO RX: %d | GPIO TX: %d \n", __func__, + gpios[0].nr, gpios[1].nr ); + + /* XXX SDIO code approach */ + retval = register_fim_can(&pdev->dev, pdata->fim_nr, gpios, bitrate); + + return retval; +} + +static __devexit int fim_can_remove(struct platform_device *pdev) +{ + struct fim_can_t *port; + + port = dev_get_drvdata(&pdev->dev); + if (!port) { + printk_err("remove: NULL pointer found!\n"); + return -ENODEV; + } + + unregister_fim_can(port); + + return 0; +} + +static struct platform_driver fim_can_platform_driver = { + .probe = fim_can_probe, + .remove = __devexit_p(fim_can_remove), + .driver = { + .owner = THIS_MODULE, + .name = FIM_DRIVER_NAME, + }, +}; + +/* + * This is the function that will be called when the module is loaded + * into the kernel space + */ +static __init int fim_can_init(void) +{ + printk_info(DRIVER_DESC " " DRIVER_VERSION "\n"); + + /* Check for the passed number parameter */ + if (fim_check_numbers_param(fims_number)) { + printk_err("Invalid number '%i' of FIMs to handle\n", fims_number); + return -EINVAL; + } + + return platform_driver_register(&fim_can_platform_driver); +} + +static __exit void fim_can_exit(void) +{ + printk_info("Removing the FIM CAN driver\n"); + platform_driver_unregister(&fim_can_platform_driver); +} + +module_init(fim_can_init); +module_exit(fim_can_exit); -- cgit v1.2.3