can: janz-ican3: add support for CAL/CANopen firmware

In our department we are using some older Janz ICAN3-modules in our dekstop
pcs. There we have slightly different carrier boards than the janz-cmodio
supported in the kernel sources, called CAN-PCI2 with two submodules. But the
pci configuration regions are identical. So extending the supported pci devices
to the corresponding device ids is sufficient to get the drivers working.

* The old ICAN3-modules with firmware 1.28 need more then 250ms for the restart
  after reset. I've increased the timeout to 500ms.
* The janz_ican3 module uses the raw can services of the Janz-firmware, this
  means firmware must be ICANOS/2. Our ICAN3-modules are equipped with
  CAL/CANopen-firmware, so I must use the appropriate commands for the layer
  management services.

Te driver detects the firmware after module reset and selects the commands
matching the firmware. This affects the bus on/off-command
(ican3_set_bus_state) and the configuration of the bittiming
(ican3_set_bittiming). For better diagnostics the detected firmware string is
presented as sysfs attribute (fwinfo).

Signed-off-by: Andreas Gröger <andreas24groeger@gmail.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Andreas Gröger 2015-05-05 20:08:34 +02:00 committed by Marc Kleine-Budde
parent 0d1802ef8f
commit 844e0edf42
3 changed files with 101 additions and 37 deletions

View File

@ -8,3 +8,12 @@ Description:
Default: 1 (termination active)
Reading: get actual termination state
Writing: set actual termination state (0=no termination, 1=termination active)
What: /sys/class/net/<iface>/fwinfo
Date: May 2015
KernelVersion: 3.19
Contact: Andreas Gröger <andreas24groeger@gmail.com>
Description:
Firmware stamp of ican3 module
Read-only: 32 byte string identification of the ICAN3 module
(known values: "JANZ-ICAN3 ICANOS 1.xx", "JANZ-ICAN3 CAL/CANopen 1.xx")

View File

@ -267,6 +267,10 @@ static void cmodio_pci_remove(struct pci_dev *dev)
static const struct pci_device_id cmodio_pci_ids[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0201 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0202 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0201 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0202 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);

View File

@ -40,6 +40,7 @@
#define MSYNC_PEER 0x00 /* ICAN only */
#define MSYNC_LOCL 0x01 /* host only */
#define TARGET_RUNNING 0x02
#define FIRMWARE_STAMP 0x60 /* big endian firmware stamp */
#define MSYNC_RB0 0x01
#define MSYNC_RB1 0x02
@ -83,6 +84,7 @@
#define MSG_COFFREQ 0x42
#define MSG_CONREQ 0x43
#define MSG_CCONFREQ 0x47
#define MSG_LMTS 0xb4
/*
* Janz ICAN3 CAN Inquiry Message Types
@ -165,6 +167,12 @@
/* SJA1000 Clock Input */
#define ICAN3_CAN_CLOCK 8000000
/* Janz ICAN3 firmware types */
enum ican3_fwtype {
ICAN3_FWTYPE_ICANOS,
ICAN3_FWTYPE_CAL_CANOPEN,
};
/* Driver Name */
#define DRV_NAME "janz-ican3"
@ -215,6 +223,10 @@ struct ican3_dev {
struct completion buserror_comp;
struct can_berr_counter bec;
/* firmware type */
enum ican3_fwtype fwtype;
char fwinfo[32];
/* old and new style host interface */
unsigned int iftype;
@ -750,13 +762,61 @@ static int ican3_set_id_filter(struct ican3_dev *mod, bool accept)
*/
static int ican3_set_bus_state(struct ican3_dev *mod, bool on)
{
struct can_bittiming *bt = &mod->can.bittiming;
struct ican3_msg msg;
u8 btr0, btr1;
int res;
/* This algorithm was stolen from drivers/net/can/sja1000/sja1000.c */
/* The bittiming register command for the ICAN3 just sets the bit timing */
/* registers on the SJA1000 chip directly */
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
(((bt->phase_seg2 - 1) & 0x7) << 4);
if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
if (mod->fwtype == ICAN3_FWTYPE_ICANOS) {
if (on) {
/* set bittiming */
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_CBTRREQ;
msg.len = cpu_to_le16(4);
msg.data[0] = 0x00;
msg.data[1] = 0x00;
msg.data[2] = btr0;
msg.data[3] = btr1;
res = ican3_send_msg(mod, &msg);
if (res)
return res;
}
/* can-on/off request */
memset(&msg, 0, sizeof(msg));
msg.spec = on ? MSG_CONREQ : MSG_COFFREQ;
msg.len = cpu_to_le16(0);
return ican3_send_msg(mod, &msg);
} else if (mod->fwtype == ICAN3_FWTYPE_CAL_CANOPEN) {
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_LMTS;
if (on) {
msg.len = cpu_to_le16(4);
msg.data[0] = 0;
msg.data[1] = 0;
msg.data[2] = btr0;
msg.data[3] = btr1;
} else {
msg.len = cpu_to_le16(2);
msg.data[0] = 1;
msg.data[1] = 0;
}
return ican3_send_msg(mod, &msg);
}
return -ENOTSUPP;
}
static int ican3_set_termination(struct ican3_dev *mod, bool on)
@ -1402,7 +1462,7 @@ static int ican3_reset_module(struct ican3_dev *mod)
return 0;
msleep(10);
} while (time_before(jiffies, start + HZ / 4));
} while (time_before(jiffies, start + HZ / 2));
netdev_err(mod->ndev, "failed to reset CAN module\n");
return -ETIMEDOUT;
@ -1427,6 +1487,17 @@ static int ican3_startup_module(struct ican3_dev *mod)
return ret;
}
/* detect firmware */
memcpy_fromio(mod->fwinfo, mod->dpm + FIRMWARE_STAMP, sizeof(mod->fwinfo) - 1);
if (strncmp(mod->fwinfo, "JANZ-ICAN3", 10)) {
netdev_err(mod->ndev, "ICAN3 not detected (found %s)\n", mod->fwinfo);
return -ENODEV;
}
if (strstr(mod->fwinfo, "CAL/CANopen"))
mod->fwtype = ICAN3_FWTYPE_CAL_CANOPEN;
else
mod->fwtype = ICAN3_FWTYPE_ICANOS;
/* re-enable interrupts so we can send messages */
iowrite8(1 << mod->num, &mod->ctrl->int_enable);
@ -1615,36 +1686,6 @@ static const struct can_bittiming_const ican3_bittiming_const = {
.brp_inc = 1,
};
/*
* This routine was stolen from drivers/net/can/sja1000/sja1000.c
*
* The bittiming register command for the ICAN3 just sets the bit timing
* registers on the SJA1000 chip directly
*/
static int ican3_set_bittiming(struct net_device *ndev)
{
struct ican3_dev *mod = netdev_priv(ndev);
struct can_bittiming *bt = &mod->can.bittiming;
struct ican3_msg msg;
u8 btr0, btr1;
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
(((bt->phase_seg2 - 1) & 0x7) << 4);
if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_CBTRREQ;
msg.len = cpu_to_le16(4);
msg.data[0] = 0x00;
msg.data[1] = 0x00;
msg.data[2] = btr0;
msg.data[3] = btr1;
return ican3_send_msg(mod, &msg);
}
static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
{
struct ican3_dev *mod = netdev_priv(ndev);
@ -1730,11 +1771,22 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
return count;
}
static ssize_t ican3_sysfs_show_fwinfo(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
return scnprintf(buf, PAGE_SIZE, "%s\n", mod->fwinfo);
}
static DEVICE_ATTR(termination, S_IWUSR | S_IRUGO, ican3_sysfs_show_term,
ican3_sysfs_set_term);
static DEVICE_ATTR(fwinfo, S_IRUSR | S_IRUGO, ican3_sysfs_show_fwinfo, NULL);
static struct attribute *ican3_sysfs_attrs[] = {
&dev_attr_termination.attr,
&dev_attr_fwinfo.attr,
NULL,
};
@ -1794,7 +1846,6 @@ static int ican3_probe(struct platform_device *pdev)
mod->can.clock.freq = ICAN3_CAN_CLOCK;
mod->can.bittiming_const = &ican3_bittiming_const;
mod->can.do_set_bittiming = ican3_set_bittiming;
mod->can.do_set_mode = ican3_set_mode;
mod->can.do_get_berr_counter = ican3_get_berr_counter;
mod->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES
@ -1866,7 +1917,7 @@ static int ican3_probe(struct platform_device *pdev)
goto out_free_irq;
}
dev_info(dev, "module %d: registered CAN device\n", pdata->modno);
netdev_info(mod->ndev, "module %d: registered CAN device\n", pdata->modno);
return 0;
out_free_irq: