All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] can/sja1000: Add/upgrade PEAK-System sja1000 driver
@ 2012-01-31 13:19 Stephane Grosjean
  2012-01-31 13:19 ` [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards Stephane Grosjean
  2012-01-31 13:19 ` [PATCH 2/2] can/sja1000: Add support of PEAK-System PCMCIA board Stephane Grosjean
  0 siblings, 2 replies; 10+ messages in thread
From: Stephane Grosjean @ 2012-01-31 13:19 UTC (permalink / raw)
  To: Oliver Hartkopp; +Cc: linux-can Mailing List, Stephane Grosjean

That serie of patches upgrades the peak_pci driver and adds the peak_pcmcia
new driver, to handle all the sja1000 PCI based from PEAK-System Technik
(http://www.peak-system.com).
These patches are planned for kernel v3.02.00 and above.

Stephane Grosjean (1):
  can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards

Stephane Grosjean (1):
  can/sja1000: Add support of PEAK-System PCMCIA board

 drivers/net/can/sja1000/Kconfig       |    9 +
 drivers/net/can/sja1000/Makefile      |    1 +
 drivers/net/can/sja1000/peak_pci.c    |  521 ++++++++++++++++++++++--
 drivers/net/can/sja1000/peak_pcmcia.c |  721 +++++++++++++++++++++++++++++++++
 4 files changed, 1212 insertions(+), 40 deletions(-)
 create mode 100644 drivers/net/can/sja1000/peak_pcmcia.c

-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 13:19 [PATCH 0/2] can/sja1000: Add/upgrade PEAK-System sja1000 driver Stephane Grosjean
@ 2012-01-31 13:19 ` Stephane Grosjean
  2012-01-31 13:25   ` Marc Kleine-Budde
  2012-01-31 22:54   ` Marc Kleine-Budde
  2012-01-31 13:19 ` [PATCH 2/2] can/sja1000: Add support of PEAK-System PCMCIA board Stephane Grosjean
  1 sibling, 2 replies; 10+ messages in thread
From: Stephane Grosjean @ 2012-01-31 13:19 UTC (permalink / raw)
  To: Oliver Hartkopp; +Cc: linux-can Mailing List, Stephane Grosjean

This patch adds the support of some new PEAK-System Technik sja1000 boards
(http://www.peak-system.com):

PCAN-PCI Express (1 or 2 channels)
PCAN-ExpressCard (1 or 2 channels)
PCAN-miniPCI (1 or 2 channels)

All of these boards are compliant with CAN specifications 2.0A (11-bit ID) and
2.0B (29-bit ID).

This patch also fixes the management of the channels list.

Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
---
 drivers/net/can/sja1000/peak_pci.c |  521 +++++++++++++++++++++++++++++++++---
 1 files changed, 481 insertions(+), 40 deletions(-)

diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index 2c7f503..02d94bd 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -1,9 +1,9 @@
 /*
  * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
  *
- * Derived from the PCAN project file driver/src/pcan_pci.c:
+ * Derived from the PCAN project files driver/src/pcan_pci.c:
  *
- * Copyright (C) 2001-2006  PEAK System-Technik GmbH
+ * Copyright (C) 2001-2012  PEAK System-Technik GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
@@ -13,12 +13,7 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -26,46 +21,117 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
-
 #include "sja1000.h"
 
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI/PCIe cards");
-MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe CAN card");
+MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
 MODULE_LICENSE("GPL v2");
 
-#define DRV_NAME  "peak_pci"
-
-struct peak_pci_chan {
-	void __iomem *cfg_base;	     /* Common for all channels */
-	struct net_device *next_dev; /* Chain of network devices */
-	u16 icr_mask;		     /* Interrupt mask for fast ack */
-};
+#define PEAK_PCI_DRV_NAME	"peak_pci"
+#define PEAK_PCI_CHAN_MAX	4
 
 #define PEAK_PCI_CAN_CLOCK	(16000000 / 2)
 
 #define PEAK_PCI_CDR		(CDR_CBP | CDR_CLKOUT_MASK)
 #define PEAK_PCI_OCR		OCR_TX0_PUSHPULL
 
-/*
- * Important PITA registers
- */
+/* PITA registers */
 #define PITA_ICR		0x00	/* Interrupt control register */
 #define PITA_GPIOICR		0x18	/* GPIO interface control register */
 #define PITA_MISC		0x1C	/* Miscellaneous register */
 
+/* GPIOICR byte access offsets */
+#define PITA_GPOUT		0x18	/* GPx output value */
+#define PITA_GPIN		0x19	/* GPx input value */
+#define PITA_GPOEN		0x1A	/* configure GPx as ouput pin */
+
+/* I2C GP bits */
+#define PITA_GPIN_SCL		0x01	/* Serial Clock Line */
+#define PITA_GPIN_SDA		0x04	/* Serial DAta line */
+
+/* LEDs control */
+#define PCA9553_1_SLAVEADDR	(0xC4 >> 1)
+
+/* PCA9553 LS0 fields values */
+enum {
+	PCA9553_LOW,
+	PCA9553_HIGHZ,
+	PCA9553_PWM0,
+	PCA9553_PWM1
+};
+
+#define PCA9553_ON		PCA9553_LOW
+#define PCA9553_OFF		PCA9553_HIGHZ
+#define PCA9553_SLOW		PCA9553_PWM0
+#define PCA9553_FAST		PCA9553_PWM1
+
+#define PCA9553_LED(c)		(1 << (c))
+#define PCA9553_LED_STATE(s, c)	((s) << ((c) << 1))
+
+#define PCA9553_LED_ON(c)	PCA9553_LED_STATE(PCA9553_ON, c)
+#define PCA9553_LED_OFF(c)	PCA9553_LED_STATE(PCA9553_OFF, c)
+#define PCA9553_LED_SLOW(c)	PCA9553_LED_STATE(PCA9553_SLOW, c)
+#define PCA9553_LED_FAST(c)	PCA9553_LED_STATE(PCA9553_FAST, c)
+#define PCA9553_LED_MASK(c)	PCA9553_LED_STATE(0x03, c)
+
+#define PCA9553_LED_OFF_ALL	(PCA9553_LED_OFF(0) | PCA9553_LED_OFF(1))
+
+#define PCA9553_LS0_INIT	0x40 /* initial value (!= from 0x00) */
+
+#define PCA9553_LS0_NONE	0x45 /* off value */
+
 #define PEAK_PCI_CFG_SIZE	0x1000	/* Size of the config PCI bar */
 #define PEAK_PCI_CHAN_SIZE	0x0400	/* Size used by the channel */
 
+/* PCI stuff */
 #define PEAK_PCI_VENDOR_ID	0x001C	/* The PCI device and vendor IDs */
 #define PEAK_PCI_DEVICE_ID	0x0001	/* for PCI/PCIe slot cards */
+#define PEAK_PCIEC_DEVICE_ID	0x0002	/* for ExpressCard slot cards */
+#define PEAK_PCIE_DEVICE_ID	0x0003	/* for nextgen PCIe slot cards */
+#define PEAK_MPCI_DEVICE_ID	0x0008	/* The miniPCI slot cards */
+
+/* PCAN-PCIeC specific (leds management) */
+struct peak_pciec_chan {
+	struct net_device *netdev;
+	unsigned long prev_rx_bytes;
+	unsigned long prev_tx_bytes;
+};
 
-static const u16 peak_pci_icr_masks[] = {0x02, 0x01, 0x40, 0x80};
+struct peak_pciec_card {
+	void __iomem *cfg_base;		/* Common for all channels */
+	void __iomem *reg_base;		/* first channel base address */
+	u8 led_cache;			/* leds state cache */
+
+	/* PCIExpressCard i2c data */
+	struct i2c_algo_bit_data i2c_bit;
+	struct i2c_adapter led_chip;
+
+	struct timer_list led_timer;	/* activity timer */
+	int chan_count;
+	struct peak_pciec_chan channel[PEAK_PCI_CHAN_MAX];
+};
+
+struct peak_pci_chan {
+	void __iomem *cfg_base;	     /* Common for all channels */
+	struct net_device *prev_dev; /* Chain of network devices */
+	u16 icr_mask;		     /* Interrupt mask for fast ack */
+	struct peak_pciec_card *pciec_card;	/* only for PCIeC */
+};
+
+static const u16 peak_pci_icr_masks[PEAK_PCI_CHAN_MAX] = {
+	0x02, 0x01, 0x40, 0x80
+};
 
 static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = {
 	{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,}
 };
 
@@ -85,20 +151,370 @@ static void peak_pci_write_reg(const struct sja1000_priv *priv,
 static void peak_pci_post_irq(const struct sja1000_priv *priv)
 {
 	struct peak_pci_chan *chan = priv->priv;
-	u16 icr;
+	u16 icr = readw(chan->cfg_base + PITA_ICR);
 
 	/* Select and clear in PITA stored interrupt */
-	icr = readw(chan->cfg_base + PITA_ICR);
 	if (icr & chan->icr_mask)
 		writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
 }
 
+static inline void pita_set_scl_highz(struct peak_pciec_card *card)
+{
+	u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SCL;
+	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
+}
+
+static inline void pita_set_sda_highz(struct peak_pciec_card *card)
+{
+	u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SDA;
+	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
+}
+
+static void peak_pciec_init_pita_gpio(struct peak_pciec_card *card)
+{
+	/* raise SCL & SDA GPIOs to high-Z */
+	pita_set_scl_highz(card);
+	pita_set_sda_highz(card);
+}
+
+static void pita_setsda(void *data, int state)
+{
+	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
+	u8 gp_out, gp_outen;
+
+	/* set output sda always to 0 */
+	gp_out = readb(card->cfg_base + PITA_GPOUT) & ~PITA_GPIN_SDA;
+	writeb(gp_out, card->cfg_base + PITA_GPOUT);
+
+	/* control output sda with GPOEN */
+	gp_outen = readb(card->cfg_base + PITA_GPOEN);
+	if (state)
+		gp_outen &= ~PITA_GPIN_SDA;
+	else
+		gp_outen |= PITA_GPIN_SDA;
+
+	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
+}
+
+static void pita_setscl(void *data, int state)
+{
+	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
+	u8 gp_out, gp_outen;
+
+	/* set output scl always to 0 */
+	gp_out = readb(card->cfg_base + PITA_GPOUT) & ~PITA_GPIN_SCL;
+	writeb(gp_out, card->cfg_base + PITA_GPOUT);
+
+	/* control output scl with GPOEN */
+	gp_outen = readb(card->cfg_base + PITA_GPOEN);
+	if (state)
+		gp_outen &= ~PITA_GPIN_SCL;
+	else
+		gp_outen |= PITA_GPIN_SCL;
+
+	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
+}
+
+static int pita_getsda(void *data)
+{
+	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
+
+	/* set tristate */
+	pita_set_sda_highz(card);
+
+	return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SDA) ? 1 : 0;
+}
+
+static int pita_getscl(void *data)
+{
+	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
+
+	/* set tristate */
+	pita_set_scl_highz(card);
+
+	return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SCL) ? 1 : 0;
+}
+
+/*
+ * write commands to the LED chip though the I2C-bus of the PCAN-PCIeC
+ */
+static int peak_pciec_write_pca9553(struct peak_pciec_card *card,
+				    u8 offset, u8 data)
+{
+	u8 buffer[2] = {
+		offset,
+		data
+	};
+	struct i2c_msg msg = {
+		.addr = PCA9553_1_SLAVEADDR,
+		.len = 2,
+		.buf = buffer,
+	};
+	int ret;
+
+	/* cache led mask */
+	if ((offset == 5) && (data == card->led_cache))
+		return 0;
+
+	ret = i2c_transfer(&card->led_chip, &msg, 1);
+	if (ret < 0)
+		return ret;
+
+	if (offset == 5)
+		card->led_cache = data;
+
+	return 0;
+}
+
+/*
+ * timer callback used to control the LEDs
+ */
+static void peak_pciec_led_timer(unsigned long arg)
+{
+	struct peak_pciec_card *card = (struct peak_pciec_card *)arg;
+	struct net_device *netdev;
+	u8 new_led = card->led_cache;
+	int i, up_count = 0;
+
+	/* first check what is to do */
+	for (i = 0; i < card->chan_count; i++) {
+		/* default is: not configured */
+		new_led &= ~PCA9553_LED_MASK(i);
+		new_led |= PCA9553_LED_ON(i);
+
+		netdev = card->channel[i].netdev;
+		if (!netdev || !(netdev->flags & IFF_UP))
+			continue;
+
+		up_count++;
+
+		/* no activity (but configured) */
+		new_led &= ~PCA9553_LED_MASK(i);
+		new_led |= PCA9553_LED_SLOW(i);
+
+		/* if bytes counters changed, set fast blinking led */
+		if (netdev->stats.rx_bytes != card->channel[i].prev_rx_bytes) {
+			card->channel[i].prev_rx_bytes = netdev->stats.rx_bytes;
+			new_led &= ~PCA9553_LED_MASK(i);
+			new_led |= PCA9553_LED_FAST(i);
+		}
+		if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
+			card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
+			new_led &= ~PCA9553_LED_MASK(i);
+			new_led |= PCA9553_LED_FAST(i);
+		}
+	}
+
+	/* check if LS0 settings changed, only update i2c if so */
+	peak_pciec_write_pca9553(card, 5, new_led);
+
+	/* restart timer (except if no more configured channels) */
+	if (up_count)
+		mod_timer(&card->led_timer, jiffies + HZ);
+}
+
+/*
+ * set LEDs blinking state
+ */
+static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
+{
+	u8 new_led = card->led_cache;
+	int i;
+
+	/* first check what is to do */
+	for (i = 0; i < card->chan_count; i++)
+		if (led_mask & PCA9553_LED(i)) {
+			new_led &= ~PCA9553_LED_MASK(i);
+			new_led |= PCA9553_LED_STATE(s, i);
+		}
+
+	/* check if LS0 settings changed, only update i2c if so */
+	peak_pciec_write_pca9553(card, 5, new_led);
+}
+
+/*
+ * start one second timer to control LEDs
+ */
+static void peak_pciec_start_led_timer(struct peak_pciec_card *card)
+{
+	if (!timer_pending(&card->led_timer))
+		mod_timer(&card->led_timer, jiffies + HZ);
+}
+
+/*
+ * stop LEDs timer
+ */
+static void peak_pciec_stop_led_timer(struct peak_pciec_card *card)
+{
+	del_timer_sync(&card->led_timer);
+}
+
+/*
+ * initialize the PCA9553 4-bit I2C-bus LED chip
+ */
+static int peak_pciec_init_leds(struct peak_pciec_card *card)
+{
+	int err;
+
+	/* prescaler for frequency 0: "SLOW" = 1 Hz = "44" */
+	err = peak_pciec_write_pca9553(card, 1, 44 / 1);
+	if (err)
+		return err;
+
+	/* duty cycle 0: 50% */
+	err = peak_pciec_write_pca9553(card, 2, 0x80);
+	if (err)
+		return err;
+
+	/* prescaler for frequency 1: "FAST" = 5 Hz */
+	err = peak_pciec_write_pca9553(card, 3, 44 / 5);
+	if (err)
+		return err;
+
+	/* duty cycle 1: 50% */
+	err = peak_pciec_write_pca9553(card, 4, 0x80);
+	if (err)
+		return err;
+
+	/* switch LEDs to initial state */
+	return peak_pciec_write_pca9553(card, 5, PCA9553_LS0_INIT);
+}
+
+/*
+ * restore LEDs state to off peak_pciec_leds_exit
+ */
+static void peak_pciec_leds_exit(struct peak_pciec_card *card)
+{
+	/* switch LEDs to off */
+	peak_pciec_write_pca9553(card, 5, PCA9553_LED_OFF_ALL);
+}
+
+/*
+ * normal write sja1000 register method overloaded to catch when controller
+ * is started or stopped, to control leds
+ */
+static void peak_pciec_write_reg(const struct sja1000_priv *priv,
+				 int port, u8 val)
+{
+	struct peak_pci_chan *chan = priv->priv;
+	struct peak_pciec_card *card = chan->pciec_card;
+	int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE;
+
+	/* sja1000 register changes control the leds state */
+	if (port == REG_MOD)
+		switch (val) {
+		case MOD_RM:
+			/* Reset Mode: set led on */
+			peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_ON);
+			break;
+		case 0x00:
+			/* Normal Mode: led slow blinking and start led timer */
+			peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_SLOW);
+			peak_pciec_start_led_timer(card);
+			break;
+		default:
+			break;
+		}
+
+	/* call base function */
+	peak_pci_write_reg(priv, port, val);
+}
+
+static struct i2c_algo_bit_data peak_pciec_i2c_bit_ops = {
+	.setsda	= pita_setsda,
+	.setscl	= pita_setscl,
+	.getsda	= pita_getsda,
+	.getscl	= pita_getscl,
+	.udelay	= 10,
+	.timeout = HZ,
+};
+
+static int peak_pciec_init(struct pci_dev *pdev, struct net_device *dev)
+{
+	struct sja1000_priv *priv = netdev_priv(dev);
+	struct peak_pci_chan *chan = priv->priv;
+	struct peak_pciec_card *card;
+	int err;
+
+	/* copy i2c object address from 1st channel */
+	if (chan->prev_dev) {
+		struct sja1000_priv *prev_priv = netdev_priv(chan->prev_dev);
+		struct peak_pci_chan *prev_chan = prev_priv->priv;
+
+		card = prev_chan->pciec_card;
+		if (!card)
+			return -ENODEV;
+
+	/* channel is the first one: do the init part */
+	} else {
+		/* create the bit banging I2C adapter structure */
+		card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
+		if (!card) {
+			dev_warn(&pdev->dev,
+				 "failed allocating memory for leds chip\n");
+			return -ENOMEM;
+		}
+
+		card->cfg_base = chan->cfg_base;
+		card->reg_base = priv->reg_base;
+
+		card->led_chip.owner = THIS_MODULE;
+		card->led_chip.dev.parent = &pdev->dev;
+		card->led_chip.algo_data = &card->i2c_bit;
+		strncpy(card->led_chip.name, "peak_i2c",
+			sizeof(card->led_chip.name));
+
+		card->i2c_bit = peak_pciec_i2c_bit_ops;
+		card->i2c_bit.udelay = 10;
+		card->i2c_bit.timeout = HZ;
+		card->i2c_bit.data = card;
+
+		peak_pciec_init_pita_gpio(card);
+
+		err = i2c_bit_add_bus(&card->led_chip);
+		if (err) {
+			dev_warn(&pdev->dev, "i2c init failed\n");
+			peak_pciec_init_pita_gpio(card);
+			kfree(card);
+			return err;
+		}
+
+		err = peak_pciec_init_leds(card);
+		if (err) {
+			dev_warn(&pdev->dev, "leds hardware init failed\n");
+			i2c_del_adapter(&card->led_chip);
+			peak_pciec_init_pita_gpio(card);
+			kfree(card);
+			return err;
+		}
+
+		/* init the timer which controls the leds */
+		init_timer(&card->led_timer);
+		card->led_timer.function = peak_pciec_led_timer;
+		card->led_timer.data = (unsigned long)card;
+	}
+
+	chan->pciec_card = card;
+	card->channel[card->chan_count++].netdev = dev;
+
+	return 0;
+}
+
+static void peak_pciec_remove(struct peak_pciec_card *card)
+{
+	peak_pciec_stop_led_timer(card);
+	peak_pciec_leds_exit(card);
+	i2c_del_adapter(&card->led_chip);
+	peak_pciec_init_pita_gpio(card);
+	kfree(card);
+}
+
 static int __devinit peak_pci_probe(struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
 	struct sja1000_priv *priv;
 	struct peak_pci_chan *chan;
-	struct net_device *dev, *dev0 = NULL;
+	struct net_device *dev;
 	void __iomem *cfg_base, *reg_base;
 	u16 sub_sys_id, icr;
 	int i, err, channels;
@@ -107,7 +523,7 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
 	if (err)
 		return err;
 
-	err = pci_request_regions(pdev, DRV_NAME);
+	err = pci_request_regions(pdev, PEAK_PCI_DRV_NAME);
 	if (err)
 		goto failure_disable_pci;
 
@@ -168,8 +584,10 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
 		chan->cfg_base = cfg_base;
 		priv->reg_base = reg_base + i * PEAK_PCI_CHAN_SIZE;
 
+		/* PCAN-ExpressCard needs some support for leds */
+		priv->write_reg = (pdev->device == PEAK_PCIEC_DEVICE_ID) ?
+				   peak_pciec_write_reg : peak_pci_write_reg;
 		priv->read_reg = peak_pci_read_reg;
-		priv->write_reg = peak_pci_write_reg;
 		priv->post_irq = peak_pci_post_irq;
 
 		priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
@@ -188,26 +606,40 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
 
 		SET_NETDEV_DEV(dev, &pdev->dev);
 
+		/* Create chain of SJA1000 devices */
+		chan->prev_dev = pci_get_drvdata(pdev);
+		pci_set_drvdata(pdev, dev);
+
+		/*
+		 * PCAN-ExpressCard needs some support for leds. This must be
+		 * done *before* register_sja1000dev() but *after* devices
+		 * linkage
+		 */
+		if (pdev->device == PEAK_PCIEC_DEVICE_ID) {
+			err = peak_pciec_init(pdev, dev);
+			if (err) {
+				dev_warn(&pdev->dev,
+					"%s channel led won't blink (err %d)\n",
+					dev->name, err);
+
+				/* handle board as a PCI card */
+				priv->write_reg = peak_pci_write_reg;
+			}
+		}
+
 		err = register_sja1000dev(dev);
 		if (err) {
 			dev_err(&pdev->dev, "failed to register device\n");
+			pci_set_drvdata(pdev, chan->prev_dev);
 			free_sja1000dev(dev);
 			goto failure_remove_channels;
 		}
 
-		/* Create chain of SJA1000 devices */
-		if (i == 0)
-			dev0 = dev;
-		else
-			chan->next_dev = dev;
-
 		dev_info(&pdev->dev,
 			 "%s at reg_base=0x%p cfg_base=0x%p irq=%d\n",
 			 dev->name, priv->reg_base, chan->cfg_base, dev->irq);
 	}
 
-	pci_set_drvdata(pdev, dev0);
-
 	/* Enable interrupts */
 	writew(icr, cfg_base + PITA_ICR + 2);
 
@@ -217,14 +649,18 @@ failure_remove_channels:
 	/* Disable interrupts */
 	writew(0x0, cfg_base + PITA_ICR + 2);
 
-	for (dev = dev0; dev; dev = chan->next_dev) {
+	chan = NULL;
+	for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
 		unregister_sja1000dev(dev);
 		free_sja1000dev(dev);
 		priv = netdev_priv(dev);
 		chan = priv->priv;
-		dev = chan->next_dev;
 	}
 
+	/* free any PCIeC resources too */
+	if (chan && chan->pciec_card)
+		peak_pciec_remove(chan->pciec_card);
+
 	pci_iounmap(pdev, reg_base);
 
 failure_unmap_cfg_base:
@@ -241,7 +677,7 @@ failure_disable_pci:
 
 static void __devexit peak_pci_remove(struct pci_dev *pdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev); /* First device */
+	struct net_device *dev = pci_get_drvdata(pdev); /* Last device */
 	struct sja1000_priv *priv = netdev_priv(dev);
 	struct peak_pci_chan *chan = priv->priv;
 	void __iomem *cfg_base = chan->cfg_base;
@@ -255,9 +691,14 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
 		dev_info(&pdev->dev, "removing device %s\n", dev->name);
 		unregister_sja1000dev(dev);
 		free_sja1000dev(dev);
-		dev = chan->next_dev;
-		if (!dev)
+		dev = chan->prev_dev;
+
+		/* do that only for first channel */
+		if (!dev) {
+			if (chan->pciec_card)
+				peak_pciec_remove(chan->pciec_card);
 			break;
+		}
 		priv = netdev_priv(dev);
 		chan = priv->priv;
 	}
@@ -271,7 +712,7 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
 }
 
 static struct pci_driver peak_pci_driver = {
-	.name = DRV_NAME,
+	.name = PEAK_PCI_DRV_NAME,
 	.id_table = peak_pci_tbl,
 	.probe = peak_pci_probe,
 	.remove = __devexit_p(peak_pci_remove),
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] can/sja1000: Add support of PEAK-System PCMCIA board
  2012-01-31 13:19 [PATCH 0/2] can/sja1000: Add/upgrade PEAK-System sja1000 driver Stephane Grosjean
  2012-01-31 13:19 ` [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards Stephane Grosjean
@ 2012-01-31 13:19 ` Stephane Grosjean
  1 sibling, 0 replies; 10+ messages in thread
From: Stephane Grosjean @ 2012-01-31 13:19 UTC (permalink / raw)
  To: Oliver Hartkopp; +Cc: linux-can Mailing List, Stephane Grosjean

This patch adds the support of the PCAN-PC Card (PCMCIA) board from
PEAK-System Technik (http://www.peak-system.com). The PCAN-PC Card board is
sja1000 based and exists in 1 or 2 channels and is compliant with CAN
specifications 2.0A (11-bit ID) and 2.0B (29-bit ID).

Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
---
 drivers/net/can/sja1000/Kconfig       |    9 +
 drivers/net/can/sja1000/Makefile      |    1 +
 drivers/net/can/sja1000/peak_pcmcia.c |  721 +++++++++++++++++++++++++++++++++
 3 files changed, 731 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/sja1000/peak_pcmcia.c

diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 36e9d59..0c8309b 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -35,6 +35,15 @@ config CAN_EMS_PCMCIA
 	  This driver is for the one or two channel CPC-CARD cards from
 	  EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
 
+config CAN_PEAK_PCMCIA
+	tristate "PEAK PCAN PC-Card"
+	depends on PCMCIA
+	---help---
+	  This driver is for the PCAN PC-Card PCMCIA adapter (1 or 2 channels)
+	  from PEAK Systems (http://www.peak-system.com). To compile this
+	  driver as a module, choose M here: the module will be called
+	  peak_pcmcia.
+
 config CAN_EMS_PCI
 	tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
 	depends on PCI
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 0604f24..b3d05cb 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PEAK_PCMCIA) += peak_pcmcia.o
 obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
 obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
 obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
new file mode 100644
index 0000000..6ba58c2
--- /dev/null
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -0,0 +1,721 @@
+/*
+ * CAN driver for PEAK-System PCAN-PC Card
+ * Derived from the PCAN project file driver/src/pcan_pccard.c
+ *
+ * Copyright (C) 2006-2009 PEAK System-Technik GmbH
+ * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include "sja1000.h"
+
+/* PEAK-System PCMCIA driver name */
+#define PCC_NAME "peak_pcmcia"
+
+MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
+MODULE_DESCRIPTION("CAN driver for PEAK-System PCAN-PC Cards");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN-PC Card");
+
+#define PCC_CHAN_MAX		2
+
+#define PCC_CAN_CLOCK		(16000000 / 2)
+
+#define PCC_MANF_ID		0x0377
+#define PCC_CARD_ID		0x0001
+
+#define PCC_CHAN_SIZE		0x20
+#define PCC_CHAN_OFF(c)		((c) * PCC_CHAN_SIZE)
+#define PCC_COMN_OFF		(PCC_CHAN_OFF(PCC_CHAN_MAX))
+#define PCC_COMN_SIZE		0x40
+
+/* common area registers */
+#define PCC_CCR			0x00
+#define PCC_CSR			0x02
+#define PCC_CPR			0x04
+#define PCC_SPI_DIR		0x06
+#define PCC_SPI_DOR		0x08
+#define PCC_SPI_ADR		0x0a
+#define PCC_SPI_IR		0x0c
+#define PCC_FW_MAJOR		0x10
+#define PCC_FW_MINOR		0x12
+
+/* CCR bits */
+#define PCC_CCR_CLK_16		0x00
+#define PCC_CCR_CLK_10		0x01
+#define PCC_CCR_CLK_21		0x02
+#define PCC_CCR_CLK_8		0x03
+#define PCC_CCR_CLK_MASK	PCC_CCR_CLK_8
+
+#define PCC_CCR_RST_CHAN(c)	(0x01 << ((c) + 2))
+#define PCC_CCR_RST_ALL		(PCC_CCR_RST_CHAN(0) | PCC_CCR_RST_CHAN(1))
+#define PCC_CCR_RST_MASK	PCC_CCR_RST_ALL
+
+/* led selection bits */
+#define PCC_LED(c)		(1 << (c))
+#define PCC_LED_ALL		(PCC_LED(0) | PCC_LED(1))
+
+/* led state value */
+#define PCC_LED_ON		0x00
+#define PCC_LED_FAST		0x01
+#define PCC_LED_SLOW		0x02
+#define PCC_LED_OFF		0x03
+
+#define PCC_CCR_LED_CHAN(s, c)	((s) << (((c) + 2) << 1))
+
+#define PCC_CCR_LED_ON_CHAN(c)		PCC_CCR_LED_CHAN(PCC_LED_ON, c)
+#define PCC_CCR_LED_FAST_CHAN(c)	PCC_CCR_LED_CHAN(PCC_LED_FAST, c)
+#define PCC_CCR_LED_SLOW_CHAN(c)	PCC_CCR_LED_CHAN(PCC_LED_SLOW, c)
+#define PCC_CCR_LED_OFF_CHAN(c)		PCC_CCR_LED_CHAN(PCC_LED_OFF, c)
+#define PCC_CCR_LED_MASK_CHAN(c)	PCC_CCR_LED_OFF_CHAN(c)
+#define PCC_CCR_LED_OFF_ALL		(PCC_CCR_LED_OFF_CHAN(0) | \
+					 PCC_CCR_LED_OFF_CHAN(1))
+#define PCC_CCR_LED_MASK		PCC_CCR_LED_OFF_ALL
+
+#define PCC_CCR_INIT	(PCC_CCR_CLK_16 | PCC_CCR_RST_ALL | PCC_CCR_LED_OFF_ALL)
+
+/* CSR bits */
+#define PCC_CSR_SPI_BUSY		0x04
+
+#define PCC_SPI_MAX_BUSY_WAIT_MS	3	/* time waiting for spi !busy */
+
+/* max count of reading the SPI status register waiting for a change */
+#define PCC_WRITE_MAX_LOOP		1000
+
+/* max nb of int handled by that isr in one shot (prevent from infinite loop) */
+#define PCC_ISR_MAX_LOOP		10
+
+/* EEPROM chip instruction set */
+/* note: EEPROM Read/Write instructions include A8 bit */
+#define PCC_EEP_WRITE(a)	(0x02 | (((a) & 0x100) >> 5))
+#define PCC_EEP_READ(a)		(0x03 | (((a) & 0x100) >> 5))
+#define PCC_EEP_WRDI		0x04	/* EEPROM Write Disable */
+#define PCC_EEP_RDSR		0x05	/* EEPROM Read Status Register */
+#define PCC_EEP_WREN		0x06	/* EEPROM Write Enable */
+
+/* EEPROM Status Register bits */
+#define PCC_EEP_SR_WEN		0x02	/* EEPROM SR Write Enable bit */
+#define PCC_EEP_SR_WIP		0x01	/* EEPROM SR Write In Progress bit */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode, push-pull and the correct polarity.
+ */
+#define PCC_OCR			(OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define PCC_CDR			(CDR_CBP | CDR_CLKOUT_MASK)
+
+struct pcan_channel {
+	struct net_device *netdev;
+	unsigned long prev_rx_bytes;
+	unsigned long prev_tx_bytes;
+};
+
+/* PCAN-PC Card private structure */
+struct pcan_pccard {
+	struct pcmcia_device *pdev;
+	int chan_count;
+	struct pcan_channel channel[PCC_CHAN_MAX];
+	u8 ccr;
+	void __iomem *ioport_addr;
+	struct timer_list led_timer;
+};
+
+static struct pcmcia_device_id pcan_table[] = {
+	PCMCIA_DEVICE_MANF_CARD(PCC_MANF_ID, PCC_CARD_ID),
+	PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, pcan_table);
+
+static void pcan_set_leds(struct pcan_pccard *card, u8 mask, u8 state);
+
+/*
+ * start timer which controls leds state
+ */
+static void pcan_start_led_timer(struct pcan_pccard *card)
+{
+	if (!timer_pending(&card->led_timer))
+		mod_timer(&card->led_timer, jiffies + HZ);
+}
+
+/*
+ * stop the timer which controls leds state
+ */
+static void pcan_stop_led_timer(struct pcan_pccard *card)
+{
+	del_timer_sync(&card->led_timer);
+}
+
+/*
+ * read a sja1000 register
+ */
+static u8 pcan_read_canreg(const struct sja1000_priv *priv, int port)
+{
+	return ioread8(priv->reg_base + port);
+}
+
+/*
+ * write a sja1000 register
+ */
+static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v)
+{
+	struct pcan_pccard *card = priv->priv;
+	int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;
+
+	/* sja1000 register changes control the leds state */
+	if (port == REG_MOD)
+		switch (v) {
+		case MOD_RM:
+			/* Reset Mode: set led on */
+			pcan_set_leds(card, PCC_LED(c), PCC_LED_ON);
+			break;
+		case 0x00:
+			/* Normal Mode: led slow blinking and start led timer */
+			pcan_set_leds(card, PCC_LED(c), PCC_LED_SLOW);
+			pcan_start_led_timer(card);
+			break;
+		default:
+			break;
+		}
+
+	iowrite8(v, priv->reg_base + port);
+}
+
+/*
+ * read a register from the common area
+ */
+static u8 pcan_read_reg(struct pcan_pccard *card, int port)
+{
+	return ioread8(card->ioport_addr + PCC_COMN_OFF + port);
+}
+
+/*
+ * write a register into the common area
+ */
+static void pcan_write_reg(struct pcan_pccard *card, int port, u8 v)
+{
+	/* cache ccr value */
+	if (port == PCC_CCR) {
+		if (card->ccr == v)
+			return;
+		card->ccr = v;
+	}
+
+	iowrite8(v, card->ioport_addr + PCC_COMN_OFF + port);
+}
+
+/*
+ * wait for SPI engine while it is busy
+ */
+static int pcan_wait_spi_busy(struct pcan_pccard *card)
+{
+	unsigned long timeout = jiffies +
+				msecs_to_jiffies(PCC_SPI_MAX_BUSY_WAIT_MS) + 1;
+
+	/* be sure to read status at least once after sleeping */
+	while (pcan_read_reg(card, PCC_CSR) & PCC_CSR_SPI_BUSY) {
+		if (jiffies >= timeout)
+			return -EBUSY;
+		schedule();
+	}
+
+	return 0;
+}
+
+/*
+ * write data in device eeprom
+ */
+static int pcan_write_eeprom(struct pcan_pccard *card, u16 addr, u8 v)
+{
+	u8 status;
+	int err, i;
+
+	/* write instruction enabling write */
+	pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WREN);
+	err = pcan_wait_spi_busy(card);
+	if (err)
+		goto we_spi_err;
+
+	/* wait until write enabled */
+	for (i = 0; i < PCC_WRITE_MAX_LOOP; i++) {
+		/* write instruction reading the status register */
+		pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_RDSR);
+		err = pcan_wait_spi_busy(card);
+		if (err)
+			goto we_spi_err;
+
+		/* get status register value and check write enable bit */
+		status = pcan_read_reg(card, PCC_SPI_DIR);
+		if (status & PCC_EEP_SR_WEN)
+			break;
+	}
+
+	if (i >= PCC_WRITE_MAX_LOOP) {
+		dev_err(&card->pdev->dev,
+			"stop waiting to be allowed to write in eeprom\n");
+		return -EIO;
+	}
+
+	/* set address and data */
+	pcan_write_reg(card, PCC_SPI_ADR, addr & 0xff);
+	pcan_write_reg(card, PCC_SPI_DOR, v);
+
+	/*
+	 * write instruction with bit[3] set according to address value:
+	 * if addr refers to upper half of the memory array: bit[3] = 1
+	 */
+	pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WRITE(addr));
+	err = pcan_wait_spi_busy(card);
+	if (err)
+		goto we_spi_err;
+
+	/* wait while write in progress */
+	for (i = 0; i < PCC_WRITE_MAX_LOOP; i++) {
+		/* write instruction reading the status register */
+		pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_RDSR);
+		err = pcan_wait_spi_busy(card);
+		if (err)
+			goto we_spi_err;
+
+		/* get status register value and check write in progress bit */
+		status = pcan_read_reg(card, PCC_SPI_DIR);
+		if (!(status & PCC_EEP_SR_WIP))
+			break;
+	}
+
+	if (i >= PCC_WRITE_MAX_LOOP) {
+		dev_err(&card->pdev->dev,
+			"stop waiting for write in eeprom to complete\n");
+		return -EIO;
+	}
+
+	/* write instruction disabling write */
+	pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WRDI);
+	err = pcan_wait_spi_busy(card);
+	if (err)
+		goto we_spi_err;
+
+	return 0;
+
+we_spi_err:
+	dev_err(&card->pdev->dev,
+		"stop waiting (spi engine always busy) err %d\n", err);
+
+	return err;
+}
+
+static void pcan_set_leds(struct pcan_pccard *card, u8 led_mask, u8 state)
+{
+	u8 ccr = card->ccr;
+	int i;
+
+	for (i = 0; i < card->chan_count; i++)
+		if (led_mask & PCC_LED(i)) {
+			/* clear corresponding led bits in ccr */
+			ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
+			/* then set new bits */
+			ccr |= PCC_CCR_LED_CHAN(state, i);
+		}
+
+	/* real write only if something has changed in ccr */
+	pcan_write_reg(card, PCC_CCR, ccr);
+}
+
+/*
+ * enable/disable CAN connectors power
+ */
+static inline void pcan_set_can_power(struct pcan_pccard *card, int onoff)
+{
+	int err = pcan_write_eeprom(card, 0, (onoff) ? 1 : 0);
+	if (err)
+		dev_err(&card->pdev->dev,
+			"failed setting power %s to can connectors (err %d)\n",
+			(onoff) ? "on" : "off", err);
+}
+
+/*
+ * set leds state according to channel activity
+ */
+static void pcan_led_timer(unsigned long arg)
+{
+	struct pcan_pccard *card = (struct pcan_pccard *)arg;
+	struct net_device *netdev;
+	u8 ccr = card->ccr;
+	int i, up_count = 0;
+
+	for (i = 0; i < card->chan_count; i++) {
+		/* default is: not configured */
+		ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
+		ccr |= PCC_CCR_LED_ON_CHAN(i);
+
+		netdev = card->channel[i].netdev;
+		if (!netdev || !(netdev->flags & IFF_UP))
+			continue;
+
+		up_count++;
+
+		/* no activity (but configured) */
+		ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
+		ccr |= PCC_CCR_LED_SLOW_CHAN(i);
+
+		/* if bytes counters changed, set fast blinking led */
+		if (netdev->stats.rx_bytes != card->channel[i].prev_rx_bytes) {
+			card->channel[i].prev_rx_bytes = netdev->stats.rx_bytes;
+			ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
+			ccr |= PCC_CCR_LED_FAST_CHAN(i);
+		}
+		if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
+			card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
+			ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
+			ccr |= PCC_CCR_LED_FAST_CHAN(i);
+		}
+	}
+
+	/* write the new leds state */
+	pcan_write_reg(card, PCC_CCR, ccr);
+
+	/* restart timer (except if no more configured channels) */
+	if (up_count)
+		mod_timer(&card->led_timer, jiffies + HZ);
+}
+
+/*
+ * interrupt service routine
+ */
+static irqreturn_t pcan_isr(int irq, void *dev_id)
+{
+	struct pcan_pccard *card = dev_id;
+	int irq_handled;
+
+	/* prevent from infinite loop */
+	for (irq_handled = 0; irq_handled < PCC_ISR_MAX_LOOP; irq_handled++) {
+		/* handle shared interrupt and next pass */
+		int nothing_to_handle = 1;
+		int i;
+
+		/* check interrupt for each channel */
+		for (i = 0; i < card->chan_count; i++) {
+			/* be sure the netdevice always exists */
+			struct net_device *netdev = card->channel[i].netdev;
+			if (!netdev)
+				continue;
+
+			/*
+			 * if some interrupt from the controller handled,
+			 * should check whether all have been handled or if have
+			 * been stopped because of SJA1000_MAX_IRQ
+			 */
+			if (sja1000_interrupt(irq, netdev) == IRQ_HANDLED)
+				nothing_to_handle = 0;
+		}
+
+		if (nothing_to_handle)
+			break;
+	}
+
+	return (irq_handled) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * free all resources used by the channels and switch off leds and can power
+ */
+static void pcan_free_channels(struct pcan_pccard *card)
+{
+	int i;
+	u8 led_mask = 0;
+
+	for (i = 0; i < card->chan_count; i++) {
+		struct net_device *netdev;
+		char name[IFNAMSIZ];
+
+		led_mask |= PCC_LED(i);
+
+		netdev = card->channel[i].netdev;
+		if (!netdev)
+			continue;
+
+		strncpy(name, netdev->name, IFNAMSIZ);
+		unregister_sja1000dev(netdev);
+		free_sja1000dev(netdev);
+
+		dev_info(&card->pdev->dev, "%s removed\n", name);
+	}
+
+	if (pcmcia_dev_present(card->pdev)) {
+		pcan_set_leds(card, led_mask, PCC_LED_OFF);
+		pcan_set_can_power(card, 0);
+	}
+
+	ioport_unmap(card->ioport_addr);
+}
+
+/*
+ * check if a CAN controller is present at the specified location
+ */
+static inline int pcan_check_channel(struct sja1000_priv *priv)
+{
+	/* make sure SJA1000 is in reset mode */
+	pcan_write_canreg(priv, REG_MOD, 1);
+	pcan_write_canreg(priv, REG_CDR, CDR_PELICAN);
+
+	/* read reset-values */
+	if (pcan_read_canreg(priv, REG_CDR) == CDR_PELICAN)
+		return 1;
+
+	return 0;
+}
+
+static int pcan_add_channels(struct pcan_pccard *card)
+{
+	struct pcmcia_device *pdev = card->pdev;
+	int i, err;
+	u8 ccr = PCC_CCR_INIT;
+
+	/* init common registers (reset channels and leds off) */
+	card->ccr = ~ccr;
+	pcan_write_reg(card, PCC_CCR, ccr);
+
+	/* wait 2ms before unresetting channels */
+	mdelay(2);
+
+	ccr &= ~PCC_CCR_RST_ALL;
+	pcan_write_reg(card, PCC_CCR, ccr);
+
+	/* create one network device per channel detected */
+	for (i = 0; i < ARRAY_SIZE(card->channel); i++) {
+		struct net_device *netdev;
+		struct sja1000_priv *priv;
+
+		netdev = alloc_sja1000dev(0);
+		if (!netdev) {
+			err = -ENOMEM;
+			break;
+		}
+
+		/* update linkages */
+		priv = netdev_priv(netdev);
+		priv->priv = card;
+		SET_NETDEV_DEV(netdev, &pdev->dev);
+
+		priv->irq_flags = IRQF_SHARED;
+		netdev->irq = pdev->irq;
+		priv->reg_base = card->ioport_addr + PCC_CHAN_OFF(i);
+
+		/* check if channel is present */
+		if (!pcan_check_channel(priv)) {
+			dev_err(&pdev->dev, "channel %d not present\n", i);
+			free_sja1000dev(netdev);
+			continue;
+		}
+
+		priv->read_reg  = pcan_read_canreg;
+		priv->write_reg = pcan_write_canreg;
+		priv->can.clock.freq = PCC_CAN_CLOCK;
+		priv->ocr = PCC_OCR;
+		priv->cdr = PCC_CDR;
+
+		/* Neither a slave device distributes the clock */
+		if (i > 0)
+			priv->cdr |= CDR_CLK_OFF;
+
+		priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
+
+		/* register SJA1000 device */
+		err = register_sja1000dev(netdev);
+		if (err) {
+			free_sja1000dev(netdev);
+			continue;
+		}
+
+		card->channel[i].netdev = netdev;
+		card->chan_count++;
+
+		/* set corresponding led on in the new ccr */
+		ccr &= ~PCC_CCR_LED_OFF_CHAN(i);
+
+		dev_info(&pdev->dev,
+			"registered %s on channel %d at 0x%p irq %d\n",
+			netdev->name, i, priv->reg_base, pdev->irq);
+	}
+
+	/* write new ccr (change leds state) */
+	pcan_write_reg(card, PCC_CCR, ccr);
+
+	return err;
+}
+
+static int pcan_conf_check(struct pcmcia_device *pdev, void *priv_data)
+{
+	pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+	pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; /* only */
+	pdev->io_lines = 10;
+
+	/* This reserves IO space but doesn't actually enable it */
+	return pcmcia_request_io(pdev);
+}
+
+/*
+ * free all resources used by the device
+ */
+static void pcan_free(struct pcmcia_device *pdev)
+{
+	if (!pdev->priv)
+		return;
+
+	pcan_stop_led_timer(pdev->priv);
+	free_irq(pdev->irq, pdev->priv);
+	pcan_free_channels(pdev->priv);
+
+	kfree(pdev->priv);
+	pdev->priv = NULL;
+}
+
+/*
+ * setup PCMCIA socket and probe for PEAK-System PC-CARD
+ */
+static int __devinit pcan_probe(struct pcmcia_device *pdev)
+{
+	struct pcan_pccard *card;
+	int err;
+
+	pdev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
+	err = pcmcia_loop_config(pdev, pcan_conf_check, NULL);
+	if (err) {
+		dev_err(&pdev->dev, "pcmcia_loop_config() error %d\n", err);
+		goto probe_err_1;
+	}
+
+	dev_info(&pdev->dev, "new PEAK-System pcmcia card detected: %s %s:\n",
+		pdev->prod_id[0] ? pdev->prod_id[0] : "PEAK-System",
+		pdev->prod_id[1] ? pdev->prod_id[1] : "PCAN-PC Card");
+
+	if (!pdev->irq) {
+		dev_err(&pdev->dev, "no irq assigned\n");
+		err = -ENODEV;
+		goto probe_err_1;
+	}
+
+	err = pcmcia_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pcmcia_enable_device failed err=%d\n",
+			err);
+		goto probe_err_1;
+	}
+
+	card = kzalloc(sizeof(struct pcan_pccard), GFP_KERNEL);
+	if (!card) {
+		dev_err(&pdev->dev, "couldn't allocated card memory\n");
+		err = -ENOMEM;
+		goto probe_err_2;
+	}
+
+	card->pdev = pdev;
+	pdev->priv = card;
+
+	/* sja1000 api uses iomem */
+	card->ioport_addr = ioport_map(pdev->resource[0]->start,
+					resource_size(pdev->resource[0]));
+	if (!card->ioport_addr) {
+		err = -ENOMEM;
+		goto probe_err_3;
+	}
+
+	/* display firware version */
+	dev_info(&pdev->dev, "firmware %d.%d\n",
+		pcan_read_reg(card, PCC_FW_MAJOR),
+		pcan_read_reg(card, PCC_FW_MINOR));
+
+	/* detect available channels */
+	pcan_add_channels(card);
+	if (!card->chan_count) {
+		ioport_unmap(card->ioport_addr);
+		goto probe_err_3;
+	}
+
+	/* init the timer which controls the leds */
+	init_timer(&card->led_timer);
+	card->led_timer.function = pcan_led_timer;
+	card->led_timer.data = (unsigned long)card;
+
+	/* request the given irq */
+	err = request_irq(pdev->irq, &pcan_isr, IRQF_SHARED, PCC_NAME, card);
+	if (err)
+		goto probe_err_4;
+
+	/* power on the connectors */
+	pcan_set_can_power(card, 1);
+
+	return 0;
+
+probe_err_4:
+	/* unregister can devices from network */
+	pcan_free_channels(card);
+
+probe_err_3:
+	kfree(card);
+	pdev->priv = NULL;
+
+probe_err_2:
+	pcmcia_disable_device(pdev);
+
+probe_err_1:
+	return err;
+}
+
+/*
+ * release claimed resources
+ */
+static void pcan_remove(struct pcmcia_device *pdev)
+{
+	pcan_free(pdev);
+	pcmcia_disable_device(pdev);
+}
+
+static struct pcmcia_driver pcan_driver = {
+	.name = PCC_NAME,
+	.probe = pcan_probe,
+	.remove = pcan_remove,
+	.id_table = pcan_table,
+};
+
+static int __init pcan_init(void)
+{
+	return pcmcia_register_driver(&pcan_driver);
+}
+module_init(pcan_init);
+
+static void __exit pcan_exit(void)
+{
+	pcmcia_unregister_driver(&pcan_driver);
+}
+module_exit(pcan_exit);
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 13:19 ` [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards Stephane Grosjean
@ 2012-01-31 13:25   ` Marc Kleine-Budde
  2012-01-31 15:01     ` Stephane Grosjean
  2012-01-31 22:54   ` Marc Kleine-Budde
  1 sibling, 1 reply; 10+ messages in thread
From: Marc Kleine-Budde @ 2012-01-31 13:25 UTC (permalink / raw)
  To: Stephane Grosjean; +Cc: Oliver Hartkopp, linux-can Mailing List

[-- Attachment #1: Type: text/plain, Size: 841 bytes --]

On 01/31/2012 02:19 PM, Stephane Grosjean wrote:
> This patch adds the support of some new PEAK-System Technik sja1000 boards
> (http://www.peak-system.com):
> 
> PCAN-PCI Express (1 or 2 channels)
> PCAN-ExpressCard (1 or 2 channels)
> PCAN-miniPCI (1 or 2 channels)
> 
> All of these boards are compliant with CAN specifications 2.0A (11-bit ID) and
> 2.0B (29-bit ID).
> 
> This patch also fixes the management of the channels list.

Without looking further at the patch, please make it a seperate patch. A
detailed review will follow.


Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 13:25   ` Marc Kleine-Budde
@ 2012-01-31 15:01     ` Stephane Grosjean
  2012-01-31 15:16       ` Wolfgang Grandegger
  2012-01-31 16:55       ` Marc Kleine-Budde
  0 siblings, 2 replies; 10+ messages in thread
From: Stephane Grosjean @ 2012-01-31 15:01 UTC (permalink / raw)
  To: Marc Kleine-Budde; +Cc: Oliver Hartkopp, linux-can Mailing List

Hi Marc,

What do you mean please? You want me to post 4 patches? One for each new 
board, plus one for the channels list management? For 2 of the 3 boards, 
this is as simple as adding a line into the device ids table, excepting 
the ExpressCard for which I added the management of the funky leds.
Thanks for any clarification.

Stéphane


Le 31/01/2012 14:25, Marc Kleine-Budde a écrit :
> On 01/31/2012 02:19 PM, Stephane Grosjean wrote:
>> This patch adds the support of some new PEAK-System Technik sja1000 boards
>> (http://www.peak-system.com):
>>
>> PCAN-PCI Express (1 or 2 channels)
>> PCAN-ExpressCard (1 or 2 channels)
>> PCAN-miniPCI (1 or 2 channels)
>>
>> All of these boards are compliant with CAN specifications 2.0A (11-bit ID) and
>> 2.0B (29-bit ID).
>>
>> This patch also fixes the management of the channels list.
> Without looking further at the patch, please make it a seperate patch. A
> detailed review will follow.
>
>
> Marc
>
--
PEAK-System Technik GmbH, Otto-Roehm-Strasse 69, D-64293 Darmstadt 
Geschaeftsleitung: A.Gach/U.Wilhelm,St.Nr.:007/241/13586 FA Darmstadt 
HRB-9183 Darmstadt, Ust.IdNr.:DE 202220078, WEE-Reg.-Nr.: DE39305391 
Tel.+49 (0)6151-817320 / Fax:+49 (0)6151-817329, info@peak-system.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 15:01     ` Stephane Grosjean
@ 2012-01-31 15:16       ` Wolfgang Grandegger
  2012-01-31 15:26         ` Stephane Grosjean
  2012-02-02 16:33         ` Stephane Grosjean
  2012-01-31 16:55       ` Marc Kleine-Budde
  1 sibling, 2 replies; 10+ messages in thread
From: Wolfgang Grandegger @ 2012-01-31 15:16 UTC (permalink / raw)
  To: s.grosjean; +Cc: Marc Kleine-Budde, Oliver Hartkopp, linux-can Mailing List

On 01/31/2012 04:01 PM, Stephane Grosjean wrote:
> Hi Marc,
> 
> What do you mean please? You want me to post 4 patches? One for each new
> board, plus one for the channels list management? For 2 of the 3 boards,
> this is as simple as adding a line into the device ids table, excepting
> the ExpressCard for which I added the management of the funky leds.
> Thanks for any clarification.

I think he wants two separate patches, instead a series of patches. One
patch for peak_pci and another for peak_pcmcia. Which does make sense as
they do not belong together.

Wolfgang.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 15:16       ` Wolfgang Grandegger
@ 2012-01-31 15:26         ` Stephane Grosjean
  2012-02-02 16:33         ` Stephane Grosjean
  1 sibling, 0 replies; 10+ messages in thread
From: Stephane Grosjean @ 2012-01-31 15:26 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: Marc Kleine-Budde, Oliver Hartkopp, linux-can Mailing List

I thought my serie of patches concerned the can/sja1000 subdir...
But ok I see, I'll do these two distinct patches then will post that 
stuff again soon.

Stéphane.

Le 31/01/2012 16:16, Wolfgang Grandegger a écrit :
> On 01/31/2012 04:01 PM, Stephane Grosjean wrote:
>> Hi Marc,
>>
>> What do you mean please? You want me to post 4 patches? One for each new
>> board, plus one for the channels list management? For 2 of the 3 boards,
>> this is as simple as adding a line into the device ids table, excepting
>> the ExpressCard for which I added the management of the funky leds.
>> Thanks for any clarification.
> I think he wants two separate patches, instead a series of patches. One
> patch for peak_pci and another for peak_pcmcia. Which does make sense as
> they do not belong together.
>
> Wolfgang.
--
PEAK-System Technik GmbH, Otto-Roehm-Strasse 69, D-64293 Darmstadt 
Geschaeftsleitung: A.Gach/U.Wilhelm,St.Nr.:007/241/13586 FA Darmstadt 
HRB-9183 Darmstadt, Ust.IdNr.:DE 202220078, WEE-Reg.-Nr.: DE39305391 
Tel.+49 (0)6151-817320 / Fax:+49 (0)6151-817329, info@peak-system.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 15:01     ` Stephane Grosjean
  2012-01-31 15:16       ` Wolfgang Grandegger
@ 2012-01-31 16:55       ` Marc Kleine-Budde
  1 sibling, 0 replies; 10+ messages in thread
From: Marc Kleine-Budde @ 2012-01-31 16:55 UTC (permalink / raw)
  To: s.grosjean; +Cc: Oliver Hartkopp, linux-can Mailing List

[-- Attachment #1: Type: text/plain, Size: 975 bytes --]

On 01/31/2012 04:01 PM, Stephane Grosjean wrote:
> Hi Marc,
> 
> What do you mean please? You want me to post 4 patches? One for each new
> board, plus one for the channels list management? For 2 of the 3 boards,
> this is as simple as adding a line into the device ids table, excepting
> the ExpressCard for which I added the management of the funky leds.
> Thanks for any clarification.

[...]

Your patch states to fix a problem:

>>> This patch also fixes the management of the channels list.
>> Without looking further at the patch, please make it a seperate patch. A
>> detailed review will follow.

It would be better to fix the problem before adding new features.

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 13:19 ` [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards Stephane Grosjean
  2012-01-31 13:25   ` Marc Kleine-Budde
@ 2012-01-31 22:54   ` Marc Kleine-Budde
  1 sibling, 0 replies; 10+ messages in thread
From: Marc Kleine-Budde @ 2012-01-31 22:54 UTC (permalink / raw)
  To: Stephane Grosjean; +Cc: Oliver Hartkopp, linux-can Mailing List

[-- Attachment #1: Type: text/plain, Size: 22146 bytes --]

On 01/31/2012 02:19 PM, Stephane Grosjean wrote:
> This patch adds the support of some new PEAK-System Technik sja1000 boards
> (http://www.peak-system.com):
> 
> PCAN-PCI Express (1 or 2 channels)
> PCAN-ExpressCard (1 or 2 channels)
> PCAN-miniPCI (1 or 2 channels)
> 
> All of these boards are compliant with CAN specifications 2.0A (11-bit ID) and
> 2.0B (29-bit ID).
> 
> This patch also fixes the management of the channels list.
> 
> Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
> ---
>  drivers/net/can/sja1000/peak_pci.c |  521 +++++++++++++++++++++++++++++++++---
>  1 files changed, 481 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
> index 2c7f503..02d94bd 100644
> --- a/drivers/net/can/sja1000/peak_pci.c
> +++ b/drivers/net/can/sja1000/peak_pci.c
> @@ -1,9 +1,9 @@
>  /*
>   * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
>   *
> - * Derived from the PCAN project file driver/src/pcan_pci.c:
> + * Derived from the PCAN project files driver/src/pcan_pci.c:
>   *
> - * Copyright (C) 2001-2006  PEAK System-Technik GmbH
> + * Copyright (C) 2001-2012  PEAK System-Technik GmbH
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the version 2 of the GNU General Public License
> @@ -13,12 +13,7 @@
>   * but WITHOUT ANY WARRANTY; without even the implied warranty of
>   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>   * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software Foundation,
> - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>   */
> -
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/interrupt.h>
> @@ -26,46 +21,117 @@
>  #include <linux/delay.h>
>  #include <linux/pci.h>
>  #include <linux/io.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-algo-bit.h>
>  #include <linux/can.h>
>  #include <linux/can/dev.h>
> -
>  #include "sja1000.h"
>  
>  MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
> -MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI/PCIe cards");
> -MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe CAN card");
> +MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
> +MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
>  MODULE_LICENSE("GPL v2");
>  
> -#define DRV_NAME  "peak_pci"
> -
> -struct peak_pci_chan {
> -	void __iomem *cfg_base;	     /* Common for all channels */
> -	struct net_device *next_dev; /* Chain of network devices */
> -	u16 icr_mask;		     /* Interrupt mask for fast ack */
> -};
> +#define PEAK_PCI_DRV_NAME	"peak_pci"
> +#define PEAK_PCI_CHAN_MAX	4
>  
>  #define PEAK_PCI_CAN_CLOCK	(16000000 / 2)
>  
>  #define PEAK_PCI_CDR		(CDR_CBP | CDR_CLKOUT_MASK)
>  #define PEAK_PCI_OCR		OCR_TX0_PUSHPULL
>  
> -/*
> - * Important PITA registers
> - */
> +/* PITA registers */
>  #define PITA_ICR		0x00	/* Interrupt control register */
>  #define PITA_GPIOICR		0x18	/* GPIO interface control register */
>  #define PITA_MISC		0x1C	/* Miscellaneous register */
>  
> +/* GPIOICR byte access offsets */
> +#define PITA_GPOUT		0x18	/* GPx output value */
> +#define PITA_GPIN		0x19	/* GPx input value */
> +#define PITA_GPOEN		0x1A	/* configure GPx as ouput pin */
> +
> +/* I2C GP bits */
> +#define PITA_GPIN_SCL		0x01	/* Serial Clock Line */
> +#define PITA_GPIN_SDA		0x04	/* Serial DAta line */
> +
> +/* LEDs control */
> +#define PCA9553_1_SLAVEADDR	(0xC4 >> 1)
> +
> +/* PCA9553 LS0 fields values */
> +enum {
> +	PCA9553_LOW,
> +	PCA9553_HIGHZ,
> +	PCA9553_PWM0,
> +	PCA9553_PWM1
> +};
> +
> +#define PCA9553_ON		PCA9553_LOW
> +#define PCA9553_OFF		PCA9553_HIGHZ
> +#define PCA9553_SLOW		PCA9553_PWM0
> +#define PCA9553_FAST		PCA9553_PWM1
> +
> +#define PCA9553_LED(c)		(1 << (c))
> +#define PCA9553_LED_STATE(s, c)	((s) << ((c) << 1))
> +
> +#define PCA9553_LED_ON(c)	PCA9553_LED_STATE(PCA9553_ON, c)
> +#define PCA9553_LED_OFF(c)	PCA9553_LED_STATE(PCA9553_OFF, c)
> +#define PCA9553_LED_SLOW(c)	PCA9553_LED_STATE(PCA9553_SLOW, c)
> +#define PCA9553_LED_FAST(c)	PCA9553_LED_STATE(PCA9553_FAST, c)
> +#define PCA9553_LED_MASK(c)	PCA9553_LED_STATE(0x03, c)
> +
> +#define PCA9553_LED_OFF_ALL	(PCA9553_LED_OFF(0) | PCA9553_LED_OFF(1))
> +
> +#define PCA9553_LS0_INIT	0x40 /* initial value (!= from 0x00) */
> +
> +#define PCA9553_LS0_NONE	0x45 /* off value */
> +
>  #define PEAK_PCI_CFG_SIZE	0x1000	/* Size of the config PCI bar */
>  #define PEAK_PCI_CHAN_SIZE	0x0400	/* Size used by the channel */
>  
> +/* PCI stuff */
>  #define PEAK_PCI_VENDOR_ID	0x001C	/* The PCI device and vendor IDs */
>  #define PEAK_PCI_DEVICE_ID	0x0001	/* for PCI/PCIe slot cards */
> +#define PEAK_PCIEC_DEVICE_ID	0x0002	/* for ExpressCard slot cards */
> +#define PEAK_PCIE_DEVICE_ID	0x0003	/* for nextgen PCIe slot cards */
> +#define PEAK_MPCI_DEVICE_ID	0x0008	/* The miniPCI slot cards */
> +
> +/* PCAN-PCIeC specific (leds management) */
> +struct peak_pciec_chan {
> +	struct net_device *netdev;
> +	unsigned long prev_rx_bytes;
> +	unsigned long prev_tx_bytes;
> +};
>  
> -static const u16 peak_pci_icr_masks[] = {0x02, 0x01, 0x40, 0x80};
> +struct peak_pciec_card {
> +	void __iomem *cfg_base;		/* Common for all channels */
> +	void __iomem *reg_base;		/* first channel base address */
> +	u8 led_cache;			/* leds state cache */
> +
> +	/* PCIExpressCard i2c data */
> +	struct i2c_algo_bit_data i2c_bit;
> +	struct i2c_adapter led_chip;
> +
> +	struct timer_list led_timer;	/* activity timer */
> +	int chan_count;
> +	struct peak_pciec_chan channel[PEAK_PCI_CHAN_MAX];
> +};
> +
> +struct peak_pci_chan {
> +	void __iomem *cfg_base;	     /* Common for all channels */
> +	struct net_device *prev_dev; /* Chain of network devices */
> +	u16 icr_mask;		     /* Interrupt mask for fast ack */

Use tabs instead of spaces to align the comments.

> +	struct peak_pciec_card *pciec_card;	/* only for PCIeC */
> +};
> +
> +static const u16 peak_pci_icr_masks[PEAK_PCI_CHAN_MAX] = {
> +	0x02, 0x01, 0x40, 0x80
> +};
>  
>  static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = {
>  	{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
> +	{PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
> +	{PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
> +	{PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
>  	{0,}
>  };
>  
> @@ -85,20 +151,370 @@ static void peak_pci_write_reg(const struct sja1000_priv *priv,
>  static void peak_pci_post_irq(const struct sja1000_priv *priv)
>  {
>  	struct peak_pci_chan *chan = priv->priv;
> -	u16 icr;
> +	u16 icr = readw(chan->cfg_base + PITA_ICR);
>  
>  	/* Select and clear in PITA stored interrupt */
> -	icr = readw(chan->cfg_base + PITA_ICR);
>  	if (icr & chan->icr_mask)
>  		writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
>  }
>  
> +static inline void pita_set_scl_highz(struct peak_pciec_card *card)
> +{
> +	u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SCL;
> +	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
> +}
> +
> +static inline void pita_set_sda_highz(struct peak_pciec_card *card)
> +{
> +	u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SDA;
> +	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
> +}
> +
> +static void peak_pciec_init_pita_gpio(struct peak_pciec_card *card)
> +{
> +	/* raise SCL & SDA GPIOs to high-Z */
> +	pita_set_scl_highz(card);
> +	pita_set_sda_highz(card);
> +}
> +
> +static void pita_setsda(void *data, int state)
> +{
> +	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
> +	u8 gp_out, gp_outen;
> +
> +	/* set output sda always to 0 */
> +	gp_out = readb(card->cfg_base + PITA_GPOUT) & ~PITA_GPIN_SDA;
> +	writeb(gp_out, card->cfg_base + PITA_GPOUT);
> +
> +	/* control output sda with GPOEN */
> +	gp_outen = readb(card->cfg_base + PITA_GPOEN);
> +	if (state)
> +		gp_outen &= ~PITA_GPIN_SDA;
> +	else
> +		gp_outen |= PITA_GPIN_SDA;
> +
> +	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
> +}
> +
> +static void pita_setscl(void *data, int state)
> +{
> +	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
> +	u8 gp_out, gp_outen;
> +
> +	/* set output scl always to 0 */
> +	gp_out = readb(card->cfg_base + PITA_GPOUT) & ~PITA_GPIN_SCL;
> +	writeb(gp_out, card->cfg_base + PITA_GPOUT);
> +
> +	/* control output scl with GPOEN */
> +	gp_outen = readb(card->cfg_base + PITA_GPOEN);
> +	if (state)
> +		gp_outen &= ~PITA_GPIN_SCL;
> +	else
> +		gp_outen |= PITA_GPIN_SCL;
> +
> +	writeb(gp_outen, card->cfg_base + PITA_GPOEN);
> +}
> +
> +static int pita_getsda(void *data)
> +{
> +	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
> +
> +	/* set tristate */
> +	pita_set_sda_highz(card);
> +
> +	return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SDA) ? 1 : 0;
> +}
> +
> +static int pita_getscl(void *data)
> +{
> +	struct peak_pciec_card *card = (struct peak_pciec_card *)data;
> +
> +	/* set tristate */
> +	pita_set_scl_highz(card);
> +
> +	return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SCL) ? 1 : 0;
> +}
> +
> +/*
> + * write commands to the LED chip though the I2C-bus of the PCAN-PCIeC
> + */
> +static int peak_pciec_write_pca9553(struct peak_pciec_card *card,
> +				    u8 offset, u8 data)
> +{
> +	u8 buffer[2] = {
> +		offset,
> +		data
> +	};
> +	struct i2c_msg msg = {
> +		.addr = PCA9553_1_SLAVEADDR,
> +		.len = 2,
> +		.buf = buffer,
> +	};
> +	int ret;
> +
> +	/* cache led mask */
> +	if ((offset == 5) && (data == card->led_cache))
> +		return 0;
> +
> +	ret = i2c_transfer(&card->led_chip, &msg, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (offset == 5)
> +		card->led_cache = data;
> +
> +	return 0;
> +}
> +
> +/*
> + * timer callback used to control the LEDs
> + */
> +static void peak_pciec_led_timer(unsigned long arg)
> +{
> +	struct peak_pciec_card *card = (struct peak_pciec_card *)arg;
> +	struct net_device *netdev;
> +	u8 new_led = card->led_cache;
> +	int i, up_count = 0;
> +
> +	/* first check what is to do */
> +	for (i = 0; i < card->chan_count; i++) {
> +		/* default is: not configured */
> +		new_led &= ~PCA9553_LED_MASK(i);
> +		new_led |= PCA9553_LED_ON(i);
> +
> +		netdev = card->channel[i].netdev;
> +		if (!netdev || !(netdev->flags & IFF_UP))
> +			continue;
> +
> +		up_count++;
> +
> +		/* no activity (but configured) */
> +		new_led &= ~PCA9553_LED_MASK(i);
> +		new_led |= PCA9553_LED_SLOW(i);
> +
> +		/* if bytes counters changed, set fast blinking led */
> +		if (netdev->stats.rx_bytes != card->channel[i].prev_rx_bytes) {
> +			card->channel[i].prev_rx_bytes = netdev->stats.rx_bytes;
> +			new_led &= ~PCA9553_LED_MASK(i);
> +			new_led |= PCA9553_LED_FAST(i);
> +		}
> +		if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
> +			card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
> +			new_led &= ~PCA9553_LED_MASK(i);
> +			new_led |= PCA9553_LED_FAST(i);
> +		}
> +	}
> +
> +	/* check if LS0 settings changed, only update i2c if so */
> +	peak_pciec_write_pca9553(card, 5, new_led);
> +
> +	/* restart timer (except if no more configured channels) */
> +	if (up_count)
> +		mod_timer(&card->led_timer, jiffies + HZ);
> +}
> +
> +/*
> + * set LEDs blinking state
> + */
> +static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
> +{
> +	u8 new_led = card->led_cache;
> +	int i;
> +
> +	/* first check what is to do */
> +	for (i = 0; i < card->chan_count; i++)
> +		if (led_mask & PCA9553_LED(i)) {
> +			new_led &= ~PCA9553_LED_MASK(i);
> +			new_led |= PCA9553_LED_STATE(s, i);
> +		}
> +
> +	/* check if LS0 settings changed, only update i2c if so */
> +	peak_pciec_write_pca9553(card, 5, new_led);
> +}
> +
> +/*
> + * start one second timer to control LEDs
> + */
> +static void peak_pciec_start_led_timer(struct peak_pciec_card *card)
> +{
> +	if (!timer_pending(&card->led_timer))
> +		mod_timer(&card->led_timer, jiffies + HZ);
> +}
> +
> +/*
> + * stop LEDs timer
> + */
> +static void peak_pciec_stop_led_timer(struct peak_pciec_card *card)
> +{
> +	del_timer_sync(&card->led_timer);
> +}
> +
> +/*
> + * initialize the PCA9553 4-bit I2C-bus LED chip
> + */
> +static int peak_pciec_init_leds(struct peak_pciec_card *card)
> +{
> +	int err;
> +
> +	/* prescaler for frequency 0: "SLOW" = 1 Hz = "44" */
> +	err = peak_pciec_write_pca9553(card, 1, 44 / 1);
> +	if (err)
> +		return err;
> +
> +	/* duty cycle 0: 50% */
> +	err = peak_pciec_write_pca9553(card, 2, 0x80);
> +	if (err)
> +		return err;
> +
> +	/* prescaler for frequency 1: "FAST" = 5 Hz */
> +	err = peak_pciec_write_pca9553(card, 3, 44 / 5);
> +	if (err)
> +		return err;
> +
> +	/* duty cycle 1: 50% */
> +	err = peak_pciec_write_pca9553(card, 4, 0x80);
> +	if (err)
> +		return err;
> +
> +	/* switch LEDs to initial state */
> +	return peak_pciec_write_pca9553(card, 5, PCA9553_LS0_INIT);
> +}
> +
> +/*
> + * restore LEDs state to off peak_pciec_leds_exit
> + */
> +static void peak_pciec_leds_exit(struct peak_pciec_card *card)
> +{
> +	/* switch LEDs to off */
> +	peak_pciec_write_pca9553(card, 5, PCA9553_LED_OFF_ALL);
> +}
> +
> +/*
> + * normal write sja1000 register method overloaded to catch when controller
> + * is started or stopped, to control leds
> + */
> +static void peak_pciec_write_reg(const struct sja1000_priv *priv,
> +				 int port, u8 val)
> +{
> +	struct peak_pci_chan *chan = priv->priv;
> +	struct peak_pciec_card *card = chan->pciec_card;
> +	int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE;
> +
> +	/* sja1000 register changes control the leds state */
> +	if (port == REG_MOD)
> +		switch (val) {
> +		case MOD_RM:
> +			/* Reset Mode: set led on */
> +			peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_ON);
> +			break;
> +		case 0x00:
> +			/* Normal Mode: led slow blinking and start led timer */
> +			peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_SLOW);
> +			peak_pciec_start_led_timer(card);
> +			break;
> +		default:
> +			break;
> +		}
> +
> +	/* call base function */
> +	peak_pci_write_reg(priv, port, val);
> +}
> +
> +static struct i2c_algo_bit_data peak_pciec_i2c_bit_ops = {
> +	.setsda	= pita_setsda,
> +	.setscl	= pita_setscl,
> +	.getsda	= pita_getsda,
> +	.getscl	= pita_getscl,
> +	.udelay	= 10,
> +	.timeout = HZ,
> +};
> +
> +static int peak_pciec_init(struct pci_dev *pdev, struct net_device *dev)
> +{
> +	struct sja1000_priv *priv = netdev_priv(dev);
> +	struct peak_pci_chan *chan = priv->priv;
> +	struct peak_pciec_card *card;
> +	int err;
> +
> +	/* copy i2c object address from 1st channel */
> +	if (chan->prev_dev) {
> +		struct sja1000_priv *prev_priv = netdev_priv(chan->prev_dev);
> +		struct peak_pci_chan *prev_chan = prev_priv->priv;
> +
> +		card = prev_chan->pciec_card;
> +		if (!card)
> +			return -ENODEV;
> +
> +	/* channel is the first one: do the init part */
> +	} else {
> +		/* create the bit banging I2C adapter structure */
> +		card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
> +		if (!card) {
> +			dev_warn(&pdev->dev,
> +				 "failed allocating memory for leds chip\n");
> +			return -ENOMEM;
> +		}
> +
> +		card->cfg_base = chan->cfg_base;
> +		card->reg_base = priv->reg_base;
> +
> +		card->led_chip.owner = THIS_MODULE;
> +		card->led_chip.dev.parent = &pdev->dev;
> +		card->led_chip.algo_data = &card->i2c_bit;
> +		strncpy(card->led_chip.name, "peak_i2c",
> +			sizeof(card->led_chip.name));
> +
> +		card->i2c_bit = peak_pciec_i2c_bit_ops;
> +		card->i2c_bit.udelay = 10;
> +		card->i2c_bit.timeout = HZ;
> +		card->i2c_bit.data = card;
> +
> +		peak_pciec_init_pita_gpio(card);
> +
> +		err = i2c_bit_add_bus(&card->led_chip);
> +		if (err) {
> +			dev_warn(&pdev->dev, "i2c init failed\n");
> +			peak_pciec_init_pita_gpio(card);
> +			kfree(card);
> +			return err;
> +		}
> +
> +		err = peak_pciec_init_leds(card);
> +		if (err) {
> +			dev_warn(&pdev->dev, "leds hardware init failed\n");
> +			i2c_del_adapter(&card->led_chip);
> +			peak_pciec_init_pita_gpio(card);
> +			kfree(card);
> +			return err;

Can you switch this code to goto style error handling, please?

> +		}
> +
> +		/* init the timer which controls the leds */
> +		init_timer(&card->led_timer);
> +		card->led_timer.function = peak_pciec_led_timer;
> +		card->led_timer.data = (unsigned long)card;
> +	}
> +
> +	chan->pciec_card = card;
> +	card->channel[card->chan_count++].netdev = dev;
> +
> +	return 0;
> +}
> +
> +static void peak_pciec_remove(struct peak_pciec_card *card)
> +{
> +	peak_pciec_stop_led_timer(card);
> +	peak_pciec_leds_exit(card);
> +	i2c_del_adapter(&card->led_chip);
> +	peak_pciec_init_pita_gpio(card);
> +	kfree(card);
> +}
> +
>  static int __devinit peak_pci_probe(struct pci_dev *pdev,
>  				    const struct pci_device_id *ent)
>  {
>  	struct sja1000_priv *priv;
>  	struct peak_pci_chan *chan;
> -	struct net_device *dev, *dev0 = NULL;
> +	struct net_device *dev;
>  	void __iomem *cfg_base, *reg_base;
>  	u16 sub_sys_id, icr;
>  	int i, err, channels;
> @@ -107,7 +523,7 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
>  	if (err)
>  		return err;
>  
> -	err = pci_request_regions(pdev, DRV_NAME);
> +	err = pci_request_regions(pdev, PEAK_PCI_DRV_NAME);
>  	if (err)
>  		goto failure_disable_pci;
>  
> @@ -168,8 +584,10 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
>  		chan->cfg_base = cfg_base;
>  		priv->reg_base = reg_base + i * PEAK_PCI_CHAN_SIZE;
>  
> +		/* PCAN-ExpressCard needs some support for leds */
> +		priv->write_reg = (pdev->device == PEAK_PCIEC_DEVICE_ID) ?
> +				   peak_pciec_write_reg : peak_pci_write_reg;
>  		priv->read_reg = peak_pci_read_reg;
> -		priv->write_reg = peak_pci_write_reg;
>  		priv->post_irq = peak_pci_post_irq;
>  
>  		priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
> @@ -188,26 +606,40 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
>  
>  		SET_NETDEV_DEV(dev, &pdev->dev);
>  
> +		/* Create chain of SJA1000 devices */
> +		chan->prev_dev = pci_get_drvdata(pdev);
> +		pci_set_drvdata(pdev, dev);
> +
> +		/*
> +		 * PCAN-ExpressCard needs some support for leds. This must be
> +		 * done *before* register_sja1000dev() but *after* devices
> +		 * linkage
> +		 */
> +		if (pdev->device == PEAK_PCIEC_DEVICE_ID) {
> +			err = peak_pciec_init(pdev, dev);
> +			if (err) {
> +				dev_warn(&pdev->dev,
> +					"%s channel led won't blink (err %d)\n",
> +					dev->name, err);
> +
> +				/* handle board as a PCI card */

I read the code and understand why you can handle a PCIe card like a PCI
card. The PCIe card has additional support for the LEDs, this should be
refleced in the comment.

> +				priv->write_reg = peak_pci_write_reg;
> +			}
> +		}
> +
>  		err = register_sja1000dev(dev);
>  		if (err) {
>  			dev_err(&pdev->dev, "failed to register device\n");
> +			pci_set_drvdata(pdev, chan->prev_dev);
>  			free_sja1000dev(dev);
>  			goto failure_remove_channels;
>  		}
>  
> -		/* Create chain of SJA1000 devices */
> -		if (i == 0)
> -			dev0 = dev;
> -		else
> -			chan->next_dev = dev;
> -
>  		dev_info(&pdev->dev,
>  			 "%s at reg_base=0x%p cfg_base=0x%p irq=%d\n",
>  			 dev->name, priv->reg_base, chan->cfg_base, dev->irq);
>  	}
>  
> -	pci_set_drvdata(pdev, dev0);
> -
>  	/* Enable interrupts */
>  	writew(icr, cfg_base + PITA_ICR + 2);
>  
> @@ -217,14 +649,18 @@ failure_remove_channels:
>  	/* Disable interrupts */
>  	writew(0x0, cfg_base + PITA_ICR + 2);
>  
> -	for (dev = dev0; dev; dev = chan->next_dev) {
> +	chan = NULL;
> +	for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
>  		unregister_sja1000dev(dev);
>  		free_sja1000dev(dev);
>  		priv = netdev_priv(dev);
>  		chan = priv->priv;
> -		dev = chan->next_dev;
>  	}
>  
> +	/* free any PCIeC resources too */
> +	if (chan && chan->pciec_card)
> +		peak_pciec_remove(chan->pciec_card);
> +
>  	pci_iounmap(pdev, reg_base);
>  
>  failure_unmap_cfg_base:
> @@ -241,7 +677,7 @@ failure_disable_pci:
>  
>  static void __devexit peak_pci_remove(struct pci_dev *pdev)
>  {
> -	struct net_device *dev = pci_get_drvdata(pdev); /* First device */
> +	struct net_device *dev = pci_get_drvdata(pdev); /* Last device */
>  	struct sja1000_priv *priv = netdev_priv(dev);
>  	struct peak_pci_chan *chan = priv->priv;
>  	void __iomem *cfg_base = chan->cfg_base;
> @@ -255,9 +691,14 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
>  		dev_info(&pdev->dev, "removing device %s\n", dev->name);
>  		unregister_sja1000dev(dev);
>  		free_sja1000dev(dev);
> -		dev = chan->next_dev;
> -		if (!dev)
> +		dev = chan->prev_dev;
> +
> +		/* do that only for first channel */
> +		if (!dev) {
> +			if (chan->pciec_card)
> +				peak_pciec_remove(chan->pciec_card);
>  			break;
> +		}
>  		priv = netdev_priv(dev);
>  		chan = priv->priv;
>  	}
> @@ -271,7 +712,7 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
>  }
>  
>  static struct pci_driver peak_pci_driver = {
> -	.name = DRV_NAME,
> +	.name = PEAK_PCI_DRV_NAME,
>  	.id_table = peak_pci_tbl,
>  	.probe = peak_pci_probe,
>  	.remove = __devexit_p(peak_pci_remove),

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards
  2012-01-31 15:16       ` Wolfgang Grandegger
  2012-01-31 15:26         ` Stephane Grosjean
@ 2012-02-02 16:33         ` Stephane Grosjean
  1 sibling, 0 replies; 10+ messages in thread
From: Stephane Grosjean @ 2012-02-02 16:33 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: Marc Kleine-Budde, linux-can Mailing List

Hi,

I've got one question about some new patch(es) I'd like to post in the 
drivers/net/can/sja1000 subdir too, about a pcmcia driver.
According to which commit should I create this new patch?
I mean, I recently posted a patch to change the above Kconfig 
description. Will the new patch's Kconfig include these modifications or 
should I wait for some ack or else?..

Regards,

Stéphane

Le 31/01/2012 16:16, Wolfgang Grandegger a écrit :
> On 01/31/2012 04:01 PM, Stephane Grosjean wrote:
>> Hi Marc,
>>
>> What do you mean please? You want me to post 4 patches? One for each new
>> board, plus one for the channels list management? For 2 of the 3 boards,
>> this is as simple as adding a line into the device ids table, excepting
>> the ExpressCard for which I added the management of the funky leds.
>> Thanks for any clarification.
> I think he wants two separate patches, instead a series of patches. One
> patch for peak_pci and another for peak_pcmcia. Which does make sense as
> they do not belong together.
>
> Wolfgang.
--
PEAK-System Technik GmbH, Otto-Roehm-Strasse 69, D-64293 Darmstadt 
Geschaeftsleitung: A.Gach/U.Wilhelm,St.Nr.:007/241/13586 FA Darmstadt 
HRB-9183 Darmstadt, Ust.IdNr.:DE 202220078, WEE-Reg.-Nr.: DE39305391 
Tel.+49 (0)6151-817320 / Fax:+49 (0)6151-817329, info@peak-system.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-02-02 16:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-31 13:19 [PATCH 0/2] can/sja1000: Add/upgrade PEAK-System sja1000 driver Stephane Grosjean
2012-01-31 13:19 ` [PATCH 1/2] can/sja1000: Add PEAK-System PCIe/PCIeC and miniPCI boards Stephane Grosjean
2012-01-31 13:25   ` Marc Kleine-Budde
2012-01-31 15:01     ` Stephane Grosjean
2012-01-31 15:16       ` Wolfgang Grandegger
2012-01-31 15:26         ` Stephane Grosjean
2012-02-02 16:33         ` Stephane Grosjean
2012-01-31 16:55       ` Marc Kleine-Budde
2012-01-31 22:54   ` Marc Kleine-Budde
2012-01-31 13:19 ` [PATCH 2/2] can/sja1000: Add support of PEAK-System PCMCIA board Stephane Grosjean

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.