aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/can/sja1000
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/can/sja1000')
-rw-r--r--drivers/net/can/sja1000/Kconfig59
-rw-r--r--drivers/net/can/sja1000/Makefile2
-rw-r--r--drivers/net/can/sja1000/ems_pci.c30
-rw-r--r--drivers/net/can/sja1000/ems_pcmcia.c25
-rw-r--r--drivers/net/can/sja1000/kvaser_pci.c30
-rw-r--r--drivers/net/can/sja1000/peak_pci.c552
-rw-r--r--drivers/net/can/sja1000/peak_pcmcia.c744
-rw-r--r--drivers/net/can/sja1000/plx_pci.c111
-rw-r--r--drivers/net/can/sja1000/sja1000.c227
-rw-r--r--drivers/net/can/sja1000/sja1000.h69
-rw-r--r--drivers/net/can/sja1000/sja1000_isa.c40
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c223
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c201
-rw-r--r--drivers/net/can/sja1000/tscan1.c8
14 files changed, 1731 insertions, 590 deletions
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 36e9d594069..1e65cb6c259 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_SJA1000
@@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM
the "platform bus" (Linux abstraction for directly to the
processor attached devices). Which can be found on various
boards from Phytec (http://www.phytec.de) like the PCM027,
- PCM038.
-
-config CAN_SJA1000_OF_PLATFORM
- tristate "Generic OF Platform Bus based SJA1000 driver"
- depends on PPC_OF
- ---help---
- This driver adds support for the SJA1000 chips connected to
- the OpenFirmware "platform bus" found on embedded systems with
- OpenFirmware bindings, e.g. if you have a PowerPC based system
- you may want to enable this option.
+ PCM038. It also provides the OpenFirmware "platform bus" found
+ on embedded systems with OpenFirmware bindings, e.g. if you
+ have a PowerPC based system you may want to enable this option.
config CAN_EMS_PCMCIA
tristate "EMS CPC-CARD Card"
@@ -43,18 +36,40 @@ config CAN_EMS_PCI
CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
(http://www.ems-wuensche.de).
+config CAN_PEAK_PCMCIA
+ tristate "PEAK PCAN-PC Card"
+ depends on PCMCIA
+ depends on HAS_IOPORT_MAP
+ ---help---
+ This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)
+ from PEAK-System (http://www.peak-system.com). To compile this
+ driver as a module, choose M here: the module will be called
+ peak_pcmcia.
+
config CAN_PEAK_PCI
- tristate "PEAK PCAN PCI/PCIe Cards"
+ tristate "PEAK PCAN-PCI/PCIe/miniPCI Cards"
depends on PCI
---help---
- This driver is for the PCAN PCI/PCIe cards (1, 2, 3 or 4 channels)
- from PEAK Systems (http://www.peak-system.com).
+ This driver is for the PCAN-PCI/PCIe/miniPCI cards
+ (1, 2, 3 or 4 channels) from PEAK-System Technik
+ (http://www.peak-system.com).
+
+config CAN_PEAK_PCIEC
+ bool "PEAK PCAN-ExpressCard Cards"
+ depends on CAN_PEAK_PCI
+ select I2C
+ select I2C_ALGOBIT
+ default y
+ ---help---
+ Say Y here if you want to use a PCAN-ExpressCard from PEAK-System
+ Technik. This will also automatically select I2C and I2C_ALGO
+ configuration options.
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
depends on PCI
---help---
- This driver is for the the PCIcanx and PCIcan cards (1, 2 or
+ This driver is for the PCIcanx and PCIcan cards (1, 2 or
4 channel) from Kvaser (http://www.kvaser.com).
config CAN_PLX_PCI
@@ -71,16 +86,18 @@ config CAN_PLX_PCI
- esd CAN-PCIe/2000
- Marathon CAN-bus-PCI card (http://www.marathon.ru/)
- TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+ - IXXAT Automation PC-I 04/PCI card (http://www.ixxat.com/)
+ - Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card (http://www.connecttech.com)
config CAN_TSCAN1
tristate "TS-CAN1 PC104 boards"
depends on ISA
help
- This driver is for Technologic Systems' TSCAN-1 PC104 boards.
- http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
- The driver supports multiple boards and automatically configures them:
- PLD IO base addresses are read from jumpers JP1 and JP2,
- IRQ numbers are read from jumpers JP4 and JP5,
- SJA1000 IO base addresses are chosen heuristically (first that works).
+ This driver is for Technologic Systems' TSCAN-1 PC104 boards.
+ http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
+ The driver supports multiple boards and automatically configures them:
+ PLD IO base addresses are read from jumpers JP1 and JP2,
+ IRQ numbers are read from jumpers JP4 and JP5,
+ SJA1000 IO base addresses are chosen heuristically (first that works).
endif
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 0604f240c8b..531d5fcc97e 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -5,10 +5,10 @@
obj-$(CONFIG_CAN_SJA1000) += sja1000.o
obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
-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/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 36f4f9780c3..fd13dbf07d9 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -13,8 +13,7 @@
* 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.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -168,12 +167,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
unsigned char res;
/* Make sure SJA1000 is in reset mode */
- priv->write_reg(priv, REG_MOD, 1);
+ priv->write_reg(priv, SJA1000_MOD, 1);
- priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- res = priv->read_reg(priv, REG_CDR);
+ res = priv->read_reg(priv, SJA1000_CDR);
if (res == CDR_PELICAN)
return 1;
@@ -207,7 +206,6 @@ static void ems_pci_del_card(struct pci_dev *pdev)
kfree(card);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
}
static void ems_pci_card_reset(struct ems_pci_card *card)
@@ -220,8 +218,8 @@ static void ems_pci_card_reset(struct ems_pci_card *card)
* Probe PCI device for EMS CAN signature and register each available
* CAN channel to SJA1000 Socket-CAN subsystem.
*/
-static int __devinit ems_pci_add_card(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int ems_pci_add_card(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct net_device *dev;
@@ -238,7 +236,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
/* Allocating card structures to hold addresses, ... */
card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
if (card == NULL) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
@@ -326,6 +323,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
if (card->version == 1)
/* reset int flag of pita */
@@ -371,16 +369,4 @@ static struct pci_driver ems_pci_driver = {
.remove = ems_pci_del_card,
};
-static int __init ems_pci_init(void)
-{
- return pci_register_driver(&ems_pci_driver);
-}
-
-static void __exit ems_pci_exit(void)
-{
- pci_unregister_driver(&ems_pci_driver);
-}
-
-module_init(ems_pci_init);
-module_exit(ems_pci_exit);
-
+module_pci_driver(ems_pci_driver);
diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
index 075a5457a19..381de998d2f 100644
--- a/drivers/net/can/sja1000/ems_pcmcia.c
+++ b/drivers/net/can/sja1000/ems_pcmcia.c
@@ -126,11 +126,11 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)
{
/* Make sure SJA1000 is in reset mode */
- ems_pcmcia_write_reg(priv, REG_MOD, 1);
- ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN);
+ ems_pcmcia_write_reg(priv, SJA1000_MOD, 1);
+ ems_pcmcia_write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- if (ems_pcmcia_read_reg(priv, REG_CDR) == CDR_PELICAN)
+ if (ems_pcmcia_read_reg(priv, SJA1000_CDR) == CDR_PELICAN)
return 1;
return 0;
@@ -166,8 +166,7 @@ static void ems_pcmcia_del_card(struct pcmcia_device *pdev)
* Probe PCI device for EMS CAN signature and register each available
* CAN channel to SJA1000 Socket-CAN subsystem.
*/
-static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
- unsigned long base)
+static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base)
{
struct sja1000_priv *priv;
struct net_device *dev;
@@ -212,6 +211,7 @@ static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
priv = netdev_priv(dev);
priv->priv = card;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
priv->irq_flags = IRQF_SHARED;
dev->irq = pdev->irq;
@@ -256,7 +256,7 @@ failure_cleanup:
/*
* Setup PCMCIA socket and probe for EMS CPC-CARD
*/
-static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev)
+static int ems_pcmcia_probe(struct pcmcia_device *dev)
{
int csval;
@@ -317,15 +317,4 @@ static struct pcmcia_driver ems_pcmcia_driver = {
.remove = ems_pcmcia_remove,
.id_table = ems_pcmcia_tbl,
};
-
-static int __init ems_pcmcia_init(void)
-{
- return pcmcia_register_driver(&ems_pcmcia_driver);
-}
-module_init(ems_pcmcia_init);
-
-static void __exit ems_pcmcia_exit(void)
-{
- pcmcia_unregister_driver(&ems_pcmcia_driver);
-}
-module_exit(ems_pcmcia_exit);
+module_pcmcia_driver(ems_pcmcia_driver);
diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index ed004cebd31..23b8e1324e2 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -26,8 +26,7 @@
* 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.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -159,9 +158,9 @@ static int number_of_sja1000_chip(void __iomem *base_addr)
for (i = 0; i < MAX_NO_OF_CHANNELS; i++) {
/* reset chip */
iowrite8(MOD_RM, base_addr +
- (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+ (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD);
status = ioread8(base_addr +
- (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+ (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD);
/* check reset bit */
if (!(status & MOD_RM))
break;
@@ -271,6 +270,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
priv->reg_base, board->conf_addr, dev->irq);
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = channel;
/* Register SJA1000 device */
err = register_sja1000dev(dev);
@@ -290,8 +290,8 @@ failure:
return err;
}
-static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int kvaser_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
int err;
struct net_device *master_dev = NULL;
@@ -379,7 +379,7 @@ failure:
}
-static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev)
+static void kvaser_pci_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -387,25 +387,13 @@ static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
}
static struct pci_driver kvaser_pci_driver = {
.name = DRV_NAME,
.id_table = kvaser_pci_tbl,
.probe = kvaser_pci_init_one,
- .remove = __devexit_p(kvaser_pci_remove_one),
+ .remove = kvaser_pci_remove_one,
};
-static int __init kvaser_pci_init(void)
-{
- return pci_register_driver(&kvaser_pci_driver);
-}
-
-static void __exit kvaser_pci_exit(void)
-{
- pci_unregister_driver(&kvaser_pci_driver);
-}
-
-module_init(kvaser_pci_init);
-module_exit(kvaser_pci_exit);
+module_pci_driver(kvaser_pci_driver);
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index 214795945bc..564933ae218 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
*
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
@@ -13,10 +14,6 @@
* 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>
@@ -26,22 +23,27 @@
#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_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN miniPCIe/cPCI PC/104+ PCI/104e CAN Cards");
MODULE_LICENSE("GPL v2");
#define DRV_NAME "peak_pci"
+struct peak_pciec_card;
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 LEDs */
};
#define PEAK_PCI_CAN_CLOCK (16000000 / 2)
@@ -61,16 +63,468 @@ struct peak_pci_chan {
#define PEAK_PCI_VENDOR_ID 0x001C /* The PCI device and vendor IDs */
#define PEAK_PCI_DEVICE_ID 0x0001 /* for PCI/PCIe slot cards */
-
-static const u16 peak_pci_icr_masks[] = {0x02, 0x01, 0x40, 0x80};
+#define PEAK_PCIEC_DEVICE_ID 0x0002 /* for ExpressCard slot cards */
+#define PEAK_PCIE_DEVICE_ID 0x0003 /* for nextgen PCIe slot cards */
+#define PEAK_CPCI_DEVICE_ID 0x0004 /* for nextgen cPCI slot cards */
+#define PEAK_MPCI_DEVICE_ID 0x0005 /* for nextgen miniPCI slot cards */
+#define PEAK_PC_104P_DEVICE_ID 0x0006 /* PCAN-PC/104+ cards */
+#define PEAK_PCI_104E_DEVICE_ID 0x0007 /* PCAN-PCI/104 Express cards */
+#define PEAK_MPCIE_DEVICE_ID 0x0008 /* The miniPCIe slot cards */
+
+#define PEAK_PCI_CHAN_MAX 4
+
+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_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_MPCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_PC_104P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_PCI_104E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_CPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+#ifdef CONFIG_CAN_PEAK_PCIEC
+ {PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+#endif
{0,}
};
MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
+#ifdef CONFIG_CAN_PEAK_PCIEC
+/*
+ * PCAN-ExpressCard needs I2C bit-banging configuration option.
+ */
+
+/* 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 */
+
+#define PCA9553_1_SLAVEADDR (0xC4 >> 1)
+
+/* PCA9553 LS0 fields values */
+enum {
+ PCA9553_LOW,
+ PCA9553_HIGHZ,
+ PCA9553_PWM0,
+ PCA9553_PWM1
+};
+
+/* LEDs control */
+#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) */
+
+struct peak_pciec_chan {
+ struct net_device *netdev;
+ unsigned long prev_rx_bytes;
+ unsigned long prev_tx_bytes;
+};
+
+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 delayed_work led_work; /* led delayed work */
+ int chan_count;
+ struct peak_pciec_chan channel[PEAK_PCI_CHAN_MAX];
+};
+
+/* "normal" pci register write callback is overloaded for leds control */
+static void peak_pci_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val);
+
+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;
+}
+
+/*
+ * delayed work callback used to control the LEDs
+ */
+static void peak_pciec_led_work(struct work_struct *work)
+{
+ struct peak_pciec_card *card =
+ container_of(work, struct peak_pciec_card, led_work.work);
+ 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)
+ schedule_delayed_work(&card->led_work, 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 delayed work to control LEDs
+ */
+static void peak_pciec_start_led_work(struct peak_pciec_card *card)
+{
+ schedule_delayed_work(&card->led_work, HZ);
+}
+
+/*
+ * stop LEDs delayed work
+ */
+static void peak_pciec_stop_led_work(struct peak_pciec_card *card)
+{
+ cancel_delayed_work_sync(&card->led_work);
+}
+
+/*
+ * 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 == SJA1000_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_work(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_probe(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)
+ 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_err(&pdev->dev, "i2c init failed\n");
+ goto pciec_init_err_1;
+ }
+
+ err = peak_pciec_init_leds(card);
+ if (err) {
+ dev_err(&pdev->dev, "leds hardware init failed\n");
+ goto pciec_init_err_2;
+ }
+
+ INIT_DELAYED_WORK(&card->led_work, peak_pciec_led_work);
+ /* PCAN-ExpressCard needs its own callback for leds */
+ priv->write_reg = peak_pciec_write_reg;
+ }
+
+ chan->pciec_card = card;
+ card->channel[card->chan_count++].netdev = dev;
+
+ return 0;
+
+pciec_init_err_2:
+ i2c_del_adapter(&card->led_chip);
+
+pciec_init_err_1:
+ peak_pciec_init_pita_gpio(card);
+ kfree(card);
+
+ return err;
+}
+
+static void peak_pciec_remove(struct peak_pciec_card *card)
+{
+ peak_pciec_stop_led_work(card);
+ peak_pciec_leds_exit(card);
+ i2c_del_adapter(&card->led_chip);
+ peak_pciec_init_pita_gpio(card);
+ kfree(card);
+}
+
+#else /* CONFIG_CAN_PEAK_PCIEC */
+
+/*
+ * Placebo functions when PCAN-ExpressCard support is not selected
+ */
+static inline int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
+{
+ return -ENODEV;
+}
+
+static inline void peak_pciec_remove(struct peak_pciec_card *card)
+{
+}
+#endif /* CONFIG_CAN_PEAK_PCIEC */
+
static u8 peak_pci_read_reg(const struct sja1000_priv *priv, int port)
{
return readb(priv->reg_base + (port << 2));
@@ -93,12 +547,11 @@ static void peak_pci_post_irq(const struct sja1000_priv *priv)
writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
}
-static int __devinit peak_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int 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;
+ struct net_device *dev, *prev_dev;
void __iomem *cfg_base, *reg_base;
u16 sub_sys_id, icr;
int i, err, channels;
@@ -134,12 +587,14 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
cfg_base = pci_iomap(pdev, 0, PEAK_PCI_CFG_SIZE);
if (!cfg_base) {
dev_err(&pdev->dev, "failed to map PCI resource #0\n");
+ err = -ENOMEM;
goto failure_release_regions;
}
reg_base = pci_iomap(pdev, 1, PEAK_PCI_CHAN_SIZE * channels);
if (!reg_base) {
dev_err(&pdev->dev, "failed to map PCI resource #1\n");
+ err = -ENOMEM;
goto failure_unmap_cfg_base;
}
@@ -187,18 +642,33 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
icr |= chan->icr_mask;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
+
+ /* Create chain of SJA1000 devices */
+ chan->prev_dev = pci_get_drvdata(pdev);
+ pci_set_drvdata(pdev, dev);
+
+ /*
+ * PCAN-ExpressCard needs some additional i2c init.
+ * This must be done *before* register_sja1000dev() but
+ * *after* devices linkage
+ */
+ if (pdev->device == PEAK_PCIEC_DEVICE_ID) {
+ err = peak_pciec_probe(pdev, dev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed to probe device (err %d)\n",
+ err);
+ goto failure_free_dev;
+ }
+ }
err = register_sja1000dev(dev);
if (err) {
dev_err(&pdev->dev, "failed to register device\n");
- free_sja1000dev(dev);
- goto failure_remove_channels;
+ goto failure_free_dev;
}
- /* Create chain of SJA1000 devices */
- chan->prev_dev = pci_get_drvdata(pdev);
- pci_set_drvdata(pdev, 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);
@@ -209,17 +679,28 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev,
return 0;
+failure_free_dev:
+ pci_set_drvdata(pdev, chan->prev_dev);
+ free_sja1000dev(dev);
+
failure_remove_channels:
/* Disable interrupts */
writew(0x0, cfg_base + PITA_ICR + 2);
- for (dev = pci_get_drvdata(pdev); dev; dev = chan->prev_dev) {
- unregister_sja1000dev(dev);
- free_sja1000dev(dev);
+ chan = NULL;
+ for (dev = pci_get_drvdata(pdev); dev; dev = prev_dev) {
priv = netdev_priv(dev);
chan = priv->priv;
+ prev_dev = chan->prev_dev;
+
+ unregister_sja1000dev(dev);
+ free_sja1000dev(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:
@@ -234,7 +715,7 @@ failure_disable_pci:
return err;
}
-static void __devexit peak_pci_remove(struct pci_dev *pdev)
+static void peak_pci_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev); /* Last device */
struct sja1000_priv *priv = netdev_priv(dev);
@@ -247,12 +728,19 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
/* Loop over all registered devices */
while (1) {
+ struct net_device *prev_dev = chan->prev_dev;
+
dev_info(&pdev->dev, "removing device %s\n", dev->name);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
- dev = chan->prev_dev;
- if (!dev)
+ dev = prev_dev;
+
+ if (!dev) {
+ /* do that only for first channel */
+ if (chan->pciec_card)
+ peak_pciec_remove(chan->pciec_card);
break;
+ }
priv = netdev_priv(dev);
chan = priv->priv;
}
@@ -261,25 +749,13 @@ static void __devexit peak_pci_remove(struct pci_dev *pdev)
pci_iounmap(pdev, cfg_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
-
- pci_set_drvdata(pdev, NULL);
}
static struct pci_driver peak_pci_driver = {
.name = DRV_NAME,
.id_table = peak_pci_tbl,
.probe = peak_pci_probe,
- .remove = __devexit_p(peak_pci_remove),
+ .remove = peak_pci_remove,
};
-static int __init peak_pci_init(void)
-{
- return pci_register_driver(&peak_pci_driver);
-}
-module_init(peak_pci_init);
-
-static void __exit peak_pci_exit(void)
-{
- pci_unregister_driver(&peak_pci_driver);
-}
-module_exit(peak_pci_exit);
+module_pci_driver(peak_pci_driver);
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
new file mode 100644
index 00000000000..dd56133cc46
--- /dev/null
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * CAN driver for PEAK-System PCAN-PC Card
+ * Derived from the PCAN project file driver/src/pcan_pccard.c
+ * Copyright (C) 2006-2010 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
+ * 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"
+
+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");
+
+/* PEAK-System PCMCIA driver name */
+#define PCC_NAME "peak_pcmcia"
+
+#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
+
+/* time waiting for SPI busy (prevent from infinite loop) */
+#define PCC_SPI_MAX_BUSY_WAIT_MS 3
+
+/* max count of reading the SPI status register waiting for a change */
+/* (prevent from infinite loop) */
+#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;
+ u8 fw_major;
+ u8 fw_minor;
+ 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 == SJA1000_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);
+}
+
+/*
+ * check whether the card is present by checking its fw version numbers
+ * against values read at probing time.
+ */
+static inline int pcan_pccard_present(struct pcan_pccard *card)
+{
+ return ((pcan_read_reg(card, PCC_FW_MAJOR) == card->fw_major) &&
+ (pcan_read_reg(card, PCC_FW_MINOR) == card->fw_minor));
+}
+
+/*
+ * 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 (time_after(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;
+
+ err = pcan_write_eeprom(card, 0, !!onoff);
+ 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;
+ int i, up_count = 0;
+ u8 ccr;
+
+ ccr = card->ccr;
+ 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 loop */
+ int nothing_to_handle = 1;
+ int i;
+
+ /* check interrupt for each channel */
+ for (i = 0; i < card->chan_count; i++) {
+ struct net_device *netdev;
+
+ /*
+ * check whether the card is present before calling
+ * sja1000_interrupt() to speed up hotplug detection
+ */
+ if (!pcan_pccard_present(card)) {
+ /* card unplugged during isr */
+ return IRQ_NONE;
+ }
+
+ /*
+ * should check whether all or SJA1000_MAX_IRQ
+ * interrupts have been handled: loop again to be sure.
+ */
+ netdev = card->channel[i].netdev;
+ if (netdev &&
+ 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);
+ }
+
+ /* do it only if device not removed */
+ if (pcan_pccard_present(card)) {
+ pcan_set_leds(card, led_mask, PCC_LED_OFF);
+ pcan_set_can_power(card, 0);
+ }
+}
+
+/*
+ * check if a CAN controller is present at the specified location
+ */
+static inline int pcan_channel_present(struct sja1000_priv *priv)
+{
+ /* make sure SJA1000 is in reset mode */
+ pcan_write_canreg(priv, SJA1000_MOD, 1);
+ pcan_write_canreg(priv, SJA1000_CDR, CDR_PELICAN);
+
+ /* read reset-values */
+ if (pcan_read_canreg(priv, SJA1000_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 = 0;
+ 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);
+ netdev->dev_id = i;
+
+ 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_channel_present(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,
+ "%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)
+{
+ struct pcan_pccard *card = pdev->priv;
+
+ if (!card)
+ return;
+
+ free_irq(pdev->irq, card);
+ pcan_stop_led_timer(card);
+
+ pcan_free_channels(card);
+
+ ioport_unmap(card->ioport_addr);
+
+ kfree(card);
+ pdev->priv = NULL;
+}
+
+/*
+ * setup PCMCIA socket and probe for PEAK-System PC-CARD
+ */
+static int 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;
+ }
+
+ 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) {
+ 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) {
+ dev_err(&pdev->dev, "couldn't map io port into io memory\n");
+ err = -ENOMEM;
+ goto probe_err_3;
+ }
+ card->fw_major = pcan_read_reg(card, PCC_FW_MAJOR);
+ card->fw_minor = pcan_read_reg(card, PCC_FW_MINOR);
+
+ /* display board name and firware version */
+ dev_info(&pdev->dev, "PEAK-System pcmcia card %s fw %d.%d\n",
+ pdev->prod_id[1] ? pdev->prod_id[1] : "PCAN-PC Card",
+ card->fw_major, card->fw_minor);
+
+ /* detect available channels */
+ pcan_add_channels(card);
+ if (!card->chan_count) {
+ err = -ENOMEM;
+ goto probe_err_4;
+ }
+
+ /* 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) {
+ dev_err(&pdev->dev, "couldn't request irq%d\n", pdev->irq);
+ goto probe_err_5;
+ }
+
+ /* power on the connectors */
+ pcan_set_can_power(card, 1);
+
+ return 0;
+
+probe_err_5:
+ /* unregister can devices from network */
+ pcan_free_channels(card);
+
+probe_err_4:
+ ioport_unmap(card->ioport_addr);
+
+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,
+};
+module_pcmcia_driver(pcan_driver);
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index c7f3d4ea116..ec39b7cb228 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -16,8 +16,7 @@
* 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.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -43,7 +42,10 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
"TEWS TECHNOLOGIES TPMC810, "
"esd CAN-PCI/CPCI/PCI104/200, "
"esd CAN-PCI/PMC/266, "
- "esd CAN-PCIe/2000")
+ "esd CAN-PCIe/2000, "
+ "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), "
+ "IXXAT PC-I 04/PCI, "
+ "ELCUS CAN-200-PCI")
MODULE_LICENSE("GPL v2");
#define PLX_PCI_MAX_CHAN 2
@@ -121,11 +123,23 @@ struct plx_pci_card {
#define ESD_PCI_SUB_SYS_ID_PCIE2000 0x0200
#define ESD_PCI_SUB_SYS_ID_PCI104200 0x0501
+#define CAN200PCI_DEVICE_ID 0x9030
+#define CAN200PCI_VENDOR_ID 0x10b5
+#define CAN200PCI_SUB_DEVICE_ID 0x0301
+#define CAN200PCI_SUB_VENDOR_ID 0xe1c5
+
+#define IXXAT_PCI_VENDOR_ID 0x10b5
+#define IXXAT_PCI_DEVICE_ID 0x9050
+#define IXXAT_PCI_SUB_SYS_ID 0x2540
+
#define MARATHON_PCI_DEVICE_ID 0x2715
#define TEWS_PCI_VENDOR_ID 0x1498
#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A
+#define CTI_PCI_VENDOR_ID 0x12c4
+#define CTI_PCI_DEVICE_ID_CRG001 0x0900
+
static void plx_pci_reset_common(struct pci_dev *pdev);
static void plx_pci_reset_marathon(struct pci_dev *pdev);
static void plx9056_pci_reset_common(struct pci_dev *pdev);
@@ -153,7 +167,7 @@ struct plx_pci_card_info {
void (*reset_func)(struct pci_dev *pdev);
};
-static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_adlink = {
"Adlink PCI-7841/cPCI-7841", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
@@ -161,7 +175,7 @@ static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
/* based on PLX9052 */
};
-static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_adlink_se = {
"Adlink PCI-7841/cPCI-7841 SE", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
@@ -169,7 +183,7 @@ static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
/* based on PLX9052 */
};
-static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_esd200 = {
"esd CAN-PCI/CPCI/PCI104/200", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} },
@@ -177,7 +191,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = {
/* based on PLX9030/9050 */
};
-static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_esd266 = {
"esd CAN-PCI/PMC/266", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} },
@@ -185,7 +199,7 @@ static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = {
/* based on PLX9056 */
};
-static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_esd2000 = {
"esd CAN-PCIe/2000", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} },
@@ -193,7 +207,15 @@ static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = {
/* based on PEX8311 */
};
-static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_ixxat = {
+ "IXXAT PC-I 04/PCI", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x200, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9050 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_marathon = {
"Marathon CAN-bus-PCI", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
@@ -201,7 +223,7 @@ static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
/* based on PLX9052 */
};
-static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+static struct plx_pci_card_info plx_pci_card_info_tews = {
"TEWS TECHNOLOGIES TPMC810", 2,
PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
{0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
@@ -209,6 +231,22 @@ static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
/* based on PLX9030 */
};
+static struct plx_pci_card_info plx_pci_card_info_cti = {
+ "Connect Tech Inc. CANpro/104-Plus Opto (CRG001)", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9030 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_elcus = {
+ "Eclus CAN-200-PCI", 2,
+ PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+ {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {3, 0x00, 0x80} },
+ &plx_pci_reset_common
+ /* based on PLX9030 */
+};
+
static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
{
/* Adlink PCI-7841/cPCI-7841 */
@@ -267,6 +305,13 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
(kernel_ulong_t)&plx_pci_card_info_esd2000
},
{
+ /* IXXAT PC-I 04/PCI card */
+ IXXAT_PCI_VENDOR_ID, IXXAT_PCI_DEVICE_ID,
+ PCI_ANY_ID, IXXAT_PCI_SUB_SYS_ID,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_ixxat
+ },
+ {
/* Marathon CAN-bus-PCI card */
PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
PCI_ANY_ID, PCI_ANY_ID,
@@ -280,6 +325,20 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
0, 0,
(kernel_ulong_t)&plx_pci_card_info_tews
},
+ {
+ /* Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card */
+ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ CTI_PCI_VENDOR_ID, CTI_PCI_DEVICE_ID_CRG001,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_cti
+ },
+ {
+ /* Elcus CAN-200-PCI */
+ CAN200PCI_VENDOR_ID, CAN200PCI_DEVICE_ID,
+ CAN200PCI_SUB_VENDOR_ID, CAN200PCI_SUB_DEVICE_ID,
+ 0, 0,
+ (kernel_ulong_t)&plx_pci_card_info_elcus
+ },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
@@ -309,20 +368,20 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
*/
if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
REG_CR_BASICCAN_INITIAL &&
- (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
- (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+ (priv->read_reg(priv, SJA1000_SR) == REG_SR_BASICCAN_INITIAL) &&
+ (priv->read_reg(priv, SJA1000_IR) == REG_IR_BASICCAN_INITIAL))
flag = 1;
/* Bring the SJA1000 into the PeliCAN mode*/
- priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/*
* Check registers after reset in the PeliCAN mode.
* See states on p. 23 of the Datasheet.
*/
- if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
- priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
- priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+ if (priv->read_reg(priv, SJA1000_MOD) == REG_MOD_PELICAN_INITIAL &&
+ priv->read_reg(priv, SJA1000_SR) == REG_SR_PELICAN_INITIAL &&
+ priv->read_reg(priv, SJA1000_IR) == REG_IR_PELICAN_INITIAL)
return flag;
return 0;
@@ -438,15 +497,14 @@ static void plx_pci_del_card(struct pci_dev *pdev)
kfree(card);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
}
/*
* Probe PLX90xx based device for the SJA1000 chips and register each
* available CAN channel to SJA1000 Socket-CAN subsystem.
*/
-static int __devinit plx_pci_add_card(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int plx_pci_add_card(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct sja1000_priv *priv;
struct net_device *dev;
@@ -469,7 +527,6 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
/* Allocate card structures to hold addresses, ... */
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
@@ -530,6 +587,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
priv->cdr = ci->cdr;
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = i;
/* Register SJA1000 device */
err = register_sja1000dev(dev);
@@ -589,15 +647,4 @@ static struct pci_driver plx_pci_driver = {
.remove = plx_pci_del_card,
};
-static int __init plx_pci_init(void)
-{
- return pci_register_driver(&plx_pci_driver);
-}
-
-static void __exit plx_pci_exit(void)
-{
- pci_unregister_driver(&plx_pci_driver);
-}
-
-module_init(plx_pci_init);
-module_exit(plx_pci_exit);
+module_pci_driver(plx_pci_driver);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 04a3f1b756a..f31499a32d7 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -60,6 +60,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include "sja1000.h"
@@ -69,7 +70,7 @@ MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver");
-static struct can_bittiming_const sja1000_bittiming_const = {
+static const struct can_bittiming_const sja1000_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 1,
.tseg1_max = 16,
@@ -90,18 +91,22 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
* the write_reg() operation - especially on SMP systems.
*/
spin_lock_irqsave(&priv->cmdreg_lock, flags);
- priv->write_reg(priv, REG_CMR, val);
- priv->read_reg(priv, REG_SR);
+ priv->write_reg(priv, SJA1000_CMR, val);
+ priv->read_reg(priv, SJA1000_SR);
spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
}
+static int sja1000_is_absent(struct sja1000_priv *priv)
+{
+ return (priv->read_reg(priv, SJA1000_MOD) == 0xFF);
+}
+
static int sja1000_probe_chip(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) {
- printk(KERN_INFO "%s: probing @0x%lX failed\n",
- DRV_NAME, dev->base_addr);
+ if (priv->reg_base && sja1000_is_absent(priv)) {
+ netdev_err(dev, "probing failed\n");
return 0;
}
return -1;
@@ -110,11 +115,11 @@ static int sja1000_probe_chip(struct net_device *dev)
static void set_reset_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- unsigned char status = priv->read_reg(priv, REG_MOD);
+ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i;
/* disable interrupts */
- priv->write_reg(priv, REG_IER, IRQ_OFF);
+ priv->write_reg(priv, SJA1000_IER, IRQ_OFF);
for (i = 0; i < 100; i++) {
/* check reset bit */
@@ -123,18 +128,19 @@ static void set_reset_mode(struct net_device *dev)
return;
}
- priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */
+ /* reset chip */
+ priv->write_reg(priv, SJA1000_MOD, MOD_RM);
udelay(10);
- status = priv->read_reg(priv, REG_MOD);
+ status = priv->read_reg(priv, SJA1000_MOD);
}
- dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n");
+ netdev_err(dev, "setting SJA1000 into reset mode failed!\n");
}
static void set_normal_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- unsigned char status = priv->read_reg(priv, REG_MOD);
+ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i;
for (i = 0; i < 100; i++) {
@@ -143,20 +149,25 @@ static void set_normal_mode(struct net_device *dev)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
- priv->write_reg(priv, REG_IER, IRQ_ALL);
+ priv->write_reg(priv, SJA1000_IER, IRQ_ALL);
else
- priv->write_reg(priv, REG_IER,
+ priv->write_reg(priv, SJA1000_IER,
IRQ_ALL & ~IRQ_BEI);
return;
}
/* set chip to normal mode */
- priv->write_reg(priv, REG_MOD, 0x00);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ priv->write_reg(priv, SJA1000_MOD, MOD_LOM);
+ else
+ priv->write_reg(priv, SJA1000_MOD, 0x00);
+
udelay(10);
- status = priv->read_reg(priv, REG_MOD);
+
+ status = priv->read_reg(priv, SJA1000_MOD);
}
- dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n");
+ netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
}
static void sja1000_start(struct net_device *dev)
@@ -168,9 +179,9 @@ static void sja1000_start(struct net_device *dev)
set_reset_mode(dev);
/* Clear error counters and error code capture */
- priv->write_reg(priv, REG_TXERR, 0x0);
- priv->write_reg(priv, REG_RXERR, 0x0);
- priv->read_reg(priv, REG_ECC);
+ priv->write_reg(priv, SJA1000_TXERR, 0x0);
+ priv->write_reg(priv, SJA1000_RXERR, 0x0);
+ priv->read_reg(priv, SJA1000_ECC);
/* leave reset mode */
set_normal_mode(dev);
@@ -178,11 +189,6 @@ static void sja1000_start(struct net_device *dev)
static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
{
- struct sja1000_priv *priv = netdev_priv(dev);
-
- if (!priv->open_time)
- return -EINVAL;
-
switch (mode) {
case CAN_MODE_START:
sja1000_start(dev);
@@ -209,11 +215,10 @@ static int sja1000_set_bittiming(struct net_device *dev)
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
- dev_info(dev->dev.parent,
- "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
+ netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
- priv->write_reg(priv, REG_BTR0, btr0);
- priv->write_reg(priv, REG_BTR1, btr1);
+ priv->write_reg(priv, SJA1000_BTR0, btr0);
+ priv->write_reg(priv, SJA1000_BTR1, btr1);
return 0;
}
@@ -223,8 +228,8 @@ static int sja1000_get_berr_counter(const struct net_device *dev,
{
struct sja1000_priv *priv = netdev_priv(dev);
- bec->txerr = priv->read_reg(priv, REG_TXERR);
- bec->rxerr = priv->read_reg(priv, REG_RXERR);
+ bec->txerr = priv->read_reg(priv, SJA1000_TXERR);
+ bec->rxerr = priv->read_reg(priv, SJA1000_RXERR);
return 0;
}
@@ -242,20 +247,20 @@ static void chipset_init(struct net_device *dev)
struct sja1000_priv *priv = netdev_priv(dev);
/* set clock divider and output control register */
- priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
/* set acceptance filter (accept all) */
- priv->write_reg(priv, REG_ACCC0, 0x00);
- priv->write_reg(priv, REG_ACCC1, 0x00);
- priv->write_reg(priv, REG_ACCC2, 0x00);
- priv->write_reg(priv, REG_ACCC3, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC0, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC1, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC2, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC3, 0x00);
- priv->write_reg(priv, REG_ACCM0, 0xFF);
- priv->write_reg(priv, REG_ACCM1, 0xFF);
- priv->write_reg(priv, REG_ACCM2, 0xFF);
- priv->write_reg(priv, REG_ACCM3, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
- priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
+ priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
}
/*
@@ -284,21 +289,21 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
id = cf->can_id;
if (id & CAN_RTR_FLAG)
- fi |= FI_RTR;
+ fi |= SJA1000_FI_RTR;
if (id & CAN_EFF_FLAG) {
- fi |= FI_FF;
- dreg = EFF_BUF;
- priv->write_reg(priv, REG_FI, fi);
- priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
- priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8));
- priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5);
- priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3);
+ fi |= SJA1000_FI_FF;
+ dreg = SJA1000_EFF_BUF;
+ priv->write_reg(priv, SJA1000_FI, fi);
+ priv->write_reg(priv, SJA1000_ID1, (id & 0x1fe00000) >> 21);
+ priv->write_reg(priv, SJA1000_ID2, (id & 0x001fe000) >> 13);
+ priv->write_reg(priv, SJA1000_ID3, (id & 0x00001fe0) >> 5);
+ priv->write_reg(priv, SJA1000_ID4, (id & 0x0000001f) << 3);
} else {
- dreg = SFF_BUF;
- priv->write_reg(priv, REG_FI, fi);
- priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3);
- priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5);
+ dreg = SJA1000_SFF_BUF;
+ priv->write_reg(priv, SJA1000_FI, fi);
+ priv->write_reg(priv, SJA1000_ID1, (id & 0x000007f8) >> 3);
+ priv->write_reg(priv, SJA1000_ID2, (id & 0x00000007) << 5);
}
for (i = 0; i < dlc; i++)
@@ -306,7 +311,10 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
can_put_echo_skb(skb, dev, 0);
- sja1000_write_cmdreg(priv, CMD_TR);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ sja1000_write_cmdreg(priv, CMD_TR | CMD_AT);
+ else
+ sja1000_write_cmdreg(priv, CMD_TR);
return NETDEV_TX_OK;
}
@@ -327,25 +335,25 @@ static void sja1000_rx(struct net_device *dev)
if (skb == NULL)
return;
- fi = priv->read_reg(priv, REG_FI);
+ fi = priv->read_reg(priv, SJA1000_FI);
- if (fi & FI_FF) {
+ if (fi & SJA1000_FI_FF) {
/* extended frame format (EFF) */
- dreg = EFF_BUF;
- id = (priv->read_reg(priv, REG_ID1) << (5 + 16))
- | (priv->read_reg(priv, REG_ID2) << (5 + 8))
- | (priv->read_reg(priv, REG_ID3) << 5)
- | (priv->read_reg(priv, REG_ID4) >> 3);
+ dreg = SJA1000_EFF_BUF;
+ id = (priv->read_reg(priv, SJA1000_ID1) << 21)
+ | (priv->read_reg(priv, SJA1000_ID2) << 13)
+ | (priv->read_reg(priv, SJA1000_ID3) << 5)
+ | (priv->read_reg(priv, SJA1000_ID4) >> 3);
id |= CAN_EFF_FLAG;
} else {
/* standard frame format (SFF) */
- dreg = SFF_BUF;
- id = (priv->read_reg(priv, REG_ID1) << 3)
- | (priv->read_reg(priv, REG_ID2) >> 5);
+ dreg = SJA1000_SFF_BUF;
+ id = (priv->read_reg(priv, SJA1000_ID1) << 3)
+ | (priv->read_reg(priv, SJA1000_ID2) >> 5);
}
cf->can_dlc = get_can_dlc(fi & 0x0F);
- if (fi & FI_RTR) {
+ if (fi & SJA1000_FI_RTR) {
id |= CAN_RTR_FLAG;
} else {
for (i = 0; i < cf->can_dlc; i++)
@@ -361,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+
+ can_led_event(dev, CAN_LED_EVENT_RX);
}
static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
@@ -378,7 +388,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (isrc & IRQ_DOI) {
/* data overrun interrupt */
- dev_dbg(dev->dev.parent, "data overrun interrupt\n");
+ netdev_dbg(dev, "data overrun interrupt\n");
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
@@ -388,7 +398,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (isrc & IRQ_EI) {
/* error warning interrupt */
- dev_dbg(dev->dev.parent, "error warning interrupt\n");
+ netdev_dbg(dev, "error warning interrupt\n");
if (status & SR_BS) {
state = CAN_STATE_BUS_OFF;
@@ -404,7 +414,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
priv->can.can_stats.bus_error++;
stats->rx_errors++;
- ecc = priv->read_reg(priv, REG_ECC);
+ ecc = priv->read_reg(priv, SJA1000_ECC);
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -429,7 +439,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
}
if (isrc & IRQ_EPI) {
/* error passive interrupt */
- dev_dbg(dev->dev.parent, "error passive interrupt\n");
+ netdev_dbg(dev, "error passive interrupt\n");
if (status & SR_ES)
state = CAN_STATE_ERROR_PASSIVE;
else
@@ -437,8 +447,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
}
if (isrc & IRQ_ALI) {
/* arbitration lost interrupt */
- dev_dbg(dev->dev.parent, "arbitration lost interrupt\n");
- alc = priv->read_reg(priv, REG_ALC);
+ netdev_dbg(dev, "arbitration lost interrupt\n");
+ alc = priv->read_reg(priv, SJA1000_ALC);
priv->can.can_stats.arbitration_lost++;
stats->tx_errors++;
cf->can_id |= CAN_ERR_LOSTARB;
@@ -447,8 +457,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
state == CAN_STATE_ERROR_PASSIVE)) {
- uint8_t rxerr = priv->read_reg(priv, REG_RXERR);
- uint8_t txerr = priv->read_reg(priv, REG_TXERR);
+ uint8_t rxerr = priv->read_reg(priv, SJA1000_RXERR);
+ uint8_t txerr = priv->read_reg(priv, SJA1000_TXERR);
cf->can_id |= CAN_ERR_CRTL;
if (state == CAN_STATE_ERROR_WARNING) {
priv->can.can_stats.error_warning++;
@@ -483,32 +493,48 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
uint8_t isrc, status;
int n = 0;
- /* Shared interrupts and IRQ off? */
- if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
- return IRQ_NONE;
-
if (priv->pre_irq)
priv->pre_irq(priv);
- while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
- n++;
- status = priv->read_reg(priv, REG_SR);
+ /* Shared interrupts and IRQ off? */
+ if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
+ goto out;
+
+ while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
+ (n < SJA1000_MAX_IRQ)) {
+
+ status = priv->read_reg(priv, SJA1000_SR);
+ /* check for absent controller due to hw unplug */
+ if (status == 0xFF && sja1000_is_absent(priv))
+ goto out;
if (isrc & IRQ_WUI)
- dev_warn(dev->dev.parent, "wakeup interrupt\n");
+ netdev_warn(dev, "wakeup interrupt\n");
if (isrc & IRQ_TI) {
- /* transmission complete interrupt */
- stats->tx_bytes += priv->read_reg(priv, REG_FI) & 0xf;
- stats->tx_packets++;
- can_get_echo_skb(dev, 0);
+ /* transmission buffer released */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
+ !(status & SR_TCS)) {
+ stats->tx_errors++;
+ can_free_echo_skb(dev, 0);
+ } else {
+ /* transmission complete */
+ stats->tx_bytes +=
+ priv->read_reg(priv, SJA1000_FI) & 0xf;
+ stats->tx_packets++;
+ can_get_echo_skb(dev, 0);
+ }
netif_wake_queue(dev);
+ can_led_event(dev, CAN_LED_EVENT_TX);
}
if (isrc & IRQ_RI) {
/* receive interrupt */
while (status & SR_RBS) {
sja1000_rx(dev);
- status = priv->read_reg(priv, REG_SR);
+ status = priv->read_reg(priv, SJA1000_SR);
+ /* check for absent controller */
+ if (status == 0xFF && sja1000_is_absent(priv))
+ goto out;
}
}
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
@@ -516,13 +542,14 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
if (sja1000_err(dev, isrc, status))
break;
}
+ n++;
}
-
+out:
if (priv->post_irq)
priv->post_irq(priv);
if (n >= SJA1000_MAX_IRQ)
- dev_dbg(dev->dev.parent, "%d messages handled in ISR", n);
+ netdev_dbg(dev, "%d messages handled in ISR", n);
return (n) ? IRQ_HANDLED : IRQ_NONE;
}
@@ -553,7 +580,8 @@ static int sja1000_open(struct net_device *dev)
/* init and start chi */
sja1000_start(dev);
- priv->open_time = jiffies;
+
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
netif_start_queue(dev);
@@ -572,7 +600,7 @@ static int sja1000_close(struct net_device *dev)
close_candev(dev);
- priv->open_time = 0;
+ can_led_event(dev, CAN_LED_EVENT_STOP);
return 0;
}
@@ -595,7 +623,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
priv->can.do_set_mode = sja1000_set_mode;
priv->can.do_get_berr_counter = sja1000_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
- CAN_CTRLMODE_BERR_REPORTING;
+ CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_ONE_SHOT;
spin_lock_init(&priv->cmdreg_lock);
@@ -613,13 +642,16 @@ void free_sja1000dev(struct net_device *dev)
EXPORT_SYMBOL_GPL(free_sja1000dev);
static const struct net_device_ops sja1000_netdev_ops = {
- .ndo_open = sja1000_open,
- .ndo_stop = sja1000_close,
- .ndo_start_xmit = sja1000_start_xmit,
+ .ndo_open = sja1000_open,
+ .ndo_stop = sja1000_close,
+ .ndo_start_xmit = sja1000_start_xmit,
+ .ndo_change_mtu = can_change_mtu,
};
int register_sja1000dev(struct net_device *dev)
{
+ int ret;
+
if (!sja1000_probe_chip(dev))
return -ENODEV;
@@ -629,7 +661,12 @@ int register_sja1000dev(struct net_device *dev)
set_reset_mode(dev);
chipset_init(dev);
- return register_candev(dev);
+ ret = register_candev(dev);
+
+ if (!ret)
+ devm_can_led_init(dev);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(register_sja1000dev);
diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h
index 23fff06875f..9d46398f815 100644
--- a/drivers/net/can/sja1000/sja1000.h
+++ b/drivers/net/can/sja1000/sja1000.h
@@ -54,46 +54,46 @@
#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
-#define REG_MOD 0x00
-#define REG_CMR 0x01
-#define REG_SR 0x02
-#define REG_IR 0x03
-#define REG_IER 0x04
-#define REG_ALC 0x0B
-#define REG_ECC 0x0C
-#define REG_EWL 0x0D
-#define REG_RXERR 0x0E
-#define REG_TXERR 0x0F
-#define REG_ACCC0 0x10
-#define REG_ACCC1 0x11
-#define REG_ACCC2 0x12
-#define REG_ACCC3 0x13
-#define REG_ACCM0 0x14
-#define REG_ACCM1 0x15
-#define REG_ACCM2 0x16
-#define REG_ACCM3 0x17
-#define REG_RMC 0x1D
-#define REG_RBSA 0x1E
+#define SJA1000_MOD 0x00
+#define SJA1000_CMR 0x01
+#define SJA1000_SR 0x02
+#define SJA1000_IR 0x03
+#define SJA1000_IER 0x04
+#define SJA1000_ALC 0x0B
+#define SJA1000_ECC 0x0C
+#define SJA1000_EWL 0x0D
+#define SJA1000_RXERR 0x0E
+#define SJA1000_TXERR 0x0F
+#define SJA1000_ACCC0 0x10
+#define SJA1000_ACCC1 0x11
+#define SJA1000_ACCC2 0x12
+#define SJA1000_ACCC3 0x13
+#define SJA1000_ACCM0 0x14
+#define SJA1000_ACCM1 0x15
+#define SJA1000_ACCM2 0x16
+#define SJA1000_ACCM3 0x17
+#define SJA1000_RMC 0x1D
+#define SJA1000_RBSA 0x1E
/* Common registers - manual section 6.5 */
-#define REG_BTR0 0x06
-#define REG_BTR1 0x07
-#define REG_OCR 0x08
-#define REG_CDR 0x1F
+#define SJA1000_BTR0 0x06
+#define SJA1000_BTR1 0x07
+#define SJA1000_OCR 0x08
+#define SJA1000_CDR 0x1F
-#define REG_FI 0x10
-#define SFF_BUF 0x13
-#define EFF_BUF 0x15
+#define SJA1000_FI 0x10
+#define SJA1000_SFF_BUF 0x13
+#define SJA1000_EFF_BUF 0x15
-#define FI_FF 0x80
-#define FI_RTR 0x40
+#define SJA1000_FI_FF 0x80
+#define SJA1000_FI_RTR 0x40
-#define REG_ID1 0x11
-#define REG_ID2 0x12
-#define REG_ID3 0x13
-#define REG_ID4 0x14
+#define SJA1000_ID1 0x11
+#define SJA1000_ID2 0x12
+#define SJA1000_ID3 0x13
+#define SJA1000_ID4 0x14
-#define CAN_RAM 0x20
+#define SJA1000_CAN_RAM 0x20
/* mode register */
#define MOD_RM 0x01
@@ -152,7 +152,6 @@
*/
struct sja1000_priv {
struct can_priv can; /* must be the first member */
- int open_time;
struct sk_buff *echo_skb;
/* the lower-layer is responsible for appropriate locking */
diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c
index 90c5c2dfd2f..014695d7e6a 100644
--- a/drivers/net/can/sja1000/sja1000_isa.c
+++ b/drivers/net/can/sja1000/sja1000_isa.c
@@ -11,8 +11,7 @@
* 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
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -42,11 +41,12 @@ MODULE_LICENSE("GPL v2");
static unsigned long port[MAXDEV];
static unsigned long mem[MAXDEV];
-static int __devinitdata irq[MAXDEV];
-static int __devinitdata clk[MAXDEV];
-static unsigned char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static unsigned char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
-static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static int irq[MAXDEV];
+static int clk[MAXDEV];
+static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
+static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
+static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static spinlock_t indirect_lock[MAXDEV]; /* lock for indirect access mode */
module_param_array(port, ulong, NULL, S_IRUGO);
MODULE_PARM_DESC(port, "I/O port number");
@@ -102,22 +102,29 @@ static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
int reg)
{
- unsigned long base = (unsigned long)priv->reg_base;
+ unsigned long flags, base = (unsigned long)priv->reg_base;
+ u8 readval;
+ spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
outb(reg, base);
- return inb(base + 1);
+ readval = inb(base + 1);
+ spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
+
+ return readval;
}
static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
int reg, u8 val)
{
- unsigned long base = (unsigned long)priv->reg_base;
+ unsigned long flags, base = (unsigned long)priv->reg_base;
+ spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
outb(reg, base);
outb(val, base + 1);
+ spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
}
-static int __devinit sja1000_isa_probe(struct platform_device *pdev)
+static int sja1000_isa_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sja1000_priv *priv;
@@ -170,6 +177,7 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev)
if (iosize == SJA1000_IOSIZE_INDIRECT) {
priv->read_reg = sja1000_isa_port_read_reg_indirect;
priv->write_reg = sja1000_isa_port_write_reg_indirect;
+ spin_lock_init(&indirect_lock[idx]);
} else {
priv->read_reg = sja1000_isa_port_read_reg;
priv->write_reg = sja1000_isa_port_write_reg;
@@ -197,8 +205,9 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev)
else
priv->cdr = CDR_DEFAULT;
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
+ dev->dev_id = idx;
err = register_sja1000dev(dev);
if (err) {
@@ -223,14 +232,13 @@ static int __devinit sja1000_isa_probe(struct platform_device *pdev)
return err;
}
-static int __devexit sja1000_isa_remove(struct platform_device *pdev)
+static int sja1000_isa_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_sja1000dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
if (mem[idx]) {
iounmap(priv->reg_base);
@@ -248,7 +256,7 @@ static int __devexit sja1000_isa_remove(struct platform_device *pdev)
static struct platform_driver sja1000_isa_driver = {
.probe = sja1000_isa_probe,
- .remove = __devexit_p(sja1000_isa_remove),
+ .remove = sja1000_isa_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
deleted file mode 100644
index f2683eb6a3d..00000000000
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
- *
- * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.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.
- *
- * 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.
- */
-
-/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
- * bus found on embedded PowerPC systems. You need a SJA1000 CAN node
- * definition in your flattened device tree source (DTS) file similar to:
- *
- * can@3,100 {
- * compatible = "nxp,sja1000";
- * reg = <3 0x100 0x80>;
- * interrupts = <2 0>;
- * interrupt-parent = <&mpic>;
- * nxp,external-clock-frequency = <16000000>;
- * };
- *
- * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further
- * information.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/can/dev.h>
-
-#include <linux/of_platform.h>
-#include <asm/prom.h>
-
-#include "sja1000.h"
-
-#define DRV_NAME "sja1000_of_platform"
-
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
-MODULE_LICENSE("GPL v2");
-
-#define SJA1000_OFP_CAN_CLOCK (16000000 / 2)
-
-#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN
-#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF)
-
-static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
-{
- return in_8(priv->reg_base + reg);
-}
-
-static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
- int reg, u8 val)
-{
- out_8(priv->reg_base + reg, val);
-}
-
-static int __devexit sja1000_ofp_remove(struct platform_device *ofdev)
-{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
- struct sja1000_priv *priv = netdev_priv(dev);
- struct device_node *np = ofdev->dev.of_node;
- struct resource res;
-
- dev_set_drvdata(&ofdev->dev, NULL);
-
- unregister_sja1000dev(dev);
- free_sja1000dev(dev);
- iounmap(priv->reg_base);
- irq_dispose_mapping(dev->irq);
-
- of_address_to_resource(np, 0, &res);
- release_mem_region(res.start, resource_size(&res));
-
- return 0;
-}
-
-static int __devinit sja1000_ofp_probe(struct platform_device *ofdev)
-{
- struct device_node *np = ofdev->dev.of_node;
- struct net_device *dev;
- struct sja1000_priv *priv;
- struct resource res;
- const u32 *prop;
- int err, irq, res_size, prop_size;
- void __iomem *base;
-
- err = of_address_to_resource(np, 0, &res);
- if (err) {
- dev_err(&ofdev->dev, "invalid address\n");
- return err;
- }
-
- res_size = resource_size(&res);
-
- if (!request_mem_region(res.start, res_size, DRV_NAME)) {
- dev_err(&ofdev->dev, "couldn't request %pR\n", &res);
- return -EBUSY;
- }
-
- base = ioremap_nocache(res.start, res_size);
- if (!base) {
- dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
- err = -ENOMEM;
- goto exit_release_mem;
- }
-
- irq = irq_of_parse_and_map(np, 0);
- if (irq == NO_IRQ) {
- dev_err(&ofdev->dev, "no irq found\n");
- err = -ENODEV;
- goto exit_unmap_mem;
- }
-
- dev = alloc_sja1000dev(0);
- if (!dev) {
- err = -ENOMEM;
- goto exit_dispose_irq;
- }
-
- priv = netdev_priv(dev);
-
- priv->read_reg = sja1000_ofp_read_reg;
- priv->write_reg = sja1000_ofp_write_reg;
-
- prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->can.clock.freq = *prop / 2;
- else
- priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
-
- prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->ocr |= *prop & OCR_MODE_MASK;
- else
- priv->ocr |= OCR_MODE_NORMAL; /* default */
-
- prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
- else
- priv->ocr |= OCR_TX0_PULLDOWN; /* default */
-
- prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
- if (prop && (prop_size == sizeof(u32)) && *prop) {
- u32 divider = priv->can.clock.freq * 2 / *prop;
-
- if (divider > 1)
- priv->cdr |= divider / 2 - 1;
- else
- priv->cdr |= CDR_CLKOUT_MASK;
- } else {
- priv->cdr |= CDR_CLK_OFF; /* default */
- }
-
- prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
- if (!prop)
- priv->cdr |= CDR_CBP; /* default */
-
- priv->irq_flags = IRQF_SHARED;
- priv->reg_base = base;
-
- dev->irq = irq;
-
- dev_info(&ofdev->dev,
- "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
- priv->reg_base, dev->irq, priv->can.clock.freq,
- priv->ocr, priv->cdr);
-
- dev_set_drvdata(&ofdev->dev, dev);
- SET_NETDEV_DEV(dev, &ofdev->dev);
-
- err = register_sja1000dev(dev);
- if (err) {
- dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
- DRV_NAME, err);
- goto exit_free_sja1000;
- }
-
- return 0;
-
-exit_free_sja1000:
- free_sja1000dev(dev);
-exit_dispose_irq:
- irq_dispose_mapping(irq);
-exit_unmap_mem:
- iounmap(base);
-exit_release_mem:
- release_mem_region(res.start, res_size);
-
- return err;
-}
-
-static struct of_device_id __devinitdata sja1000_ofp_table[] = {
- {.compatible = "nxp,sja1000"},
- {},
-};
-MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
-
-static struct platform_driver sja1000_ofp_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .of_match_table = sja1000_ofp_table,
- },
- .probe = sja1000_ofp_probe,
- .remove = __devexit_p(sja1000_ofp_remove),
-};
-
-module_platform_driver(sja1000_ofp_driver);
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index 4f50145f648..95a844a7ee7 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -12,8 +12,7 @@
* 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
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
@@ -27,13 +26,18 @@
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include "sja1000.h"
#define DRV_NAME "sja1000_platform"
+#define SP_CAN_CLOCK (16000000 / 2)
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
+MODULE_ALIAS("platform:" DRV_NAME);
MODULE_LICENSE("GPL v2");
static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
@@ -66,57 +70,16 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
iowrite8(val, priv->reg_base + reg * 4);
}
-static int sp_probe(struct platform_device *pdev)
+static void sp_populate(struct sja1000_priv *priv,
+ struct sja1000_platform_data *pdata,
+ unsigned long resource_mem_flags)
{
- int err;
- void __iomem *addr;
- struct net_device *dev;
- struct sja1000_priv *priv;
- struct resource *res_mem, *res_irq;
- struct sja1000_platform_data *pdata;
-
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data provided!\n");
- err = -ENODEV;
- goto exit;
- }
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_mem || !res_irq) {
- err = -ENODEV;
- goto exit;
- }
-
- if (!request_mem_region(res_mem->start, resource_size(res_mem),
- DRV_NAME)) {
- err = -EBUSY;
- goto exit;
- }
-
- addr = ioremap_nocache(res_mem->start, resource_size(res_mem));
- if (!addr) {
- err = -ENOMEM;
- goto exit_release;
- }
-
- dev = alloc_sja1000dev(0);
- if (!dev) {
- err = -ENOMEM;
- goto exit_iounmap;
- }
- priv = netdev_priv(dev);
-
- dev->irq = res_irq->start;
- priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED);
- priv->reg_base = addr;
/* The CAN clock frequency is half the oscillator clock frequency */
priv->can.clock.freq = pdata->osc_freq / 2;
priv->ocr = pdata->ocr;
priv->cdr = pdata->cdr;
- switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+ switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) {
case IORESOURCE_MEM_32BIT:
priv->read_reg = sp_read_reg32;
priv->write_reg = sp_write_reg32;
@@ -131,8 +94,126 @@ static int sp_probe(struct platform_device *pdev)
priv->write_reg = sp_write_reg8;
break;
}
+}
+
+static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
+{
+ int err;
+ u32 prop;
+
+ err = of_property_read_u32(of, "reg-io-width", &prop);
+ if (err)
+ prop = 1; /* 8 bit is default */
+
+ switch (prop) {
+ case 4:
+ priv->read_reg = sp_read_reg32;
+ priv->write_reg = sp_write_reg32;
+ break;
+ case 2:
+ priv->read_reg = sp_read_reg16;
+ priv->write_reg = sp_write_reg16;
+ break;
+ case 1: /* fallthrough */
+ default:
+ priv->read_reg = sp_read_reg8;
+ priv->write_reg = sp_write_reg8;
+ }
- dev_set_drvdata(&pdev->dev, dev);
+ err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
+ if (!err)
+ priv->can.clock.freq = prop / 2;
+ else
+ priv->can.clock.freq = SP_CAN_CLOCK; /* default */
+
+ err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
+ if (!err)
+ priv->ocr |= prop & OCR_MODE_MASK;
+ else
+ priv->ocr |= OCR_MODE_NORMAL; /* default */
+
+ err = of_property_read_u32(of, "nxp,tx-output-config", &prop);
+ if (!err)
+ priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+ else
+ priv->ocr |= OCR_TX0_PULLDOWN; /* default */
+
+ err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop);
+ if (!err && prop) {
+ u32 divider = priv->can.clock.freq * 2 / prop;
+
+ if (divider > 1)
+ priv->cdr |= divider / 2 - 1;
+ else
+ priv->cdr |= CDR_CLKOUT_MASK;
+ } else {
+ priv->cdr |= CDR_CLK_OFF; /* default */
+ }
+
+ if (!of_property_read_bool(of, "nxp,no-comparator-bypass"))
+ priv->cdr |= CDR_CBP; /* default */
+}
+
+static int sp_probe(struct platform_device *pdev)
+{
+ int err, irq = 0;
+ void __iomem *addr;
+ struct net_device *dev;
+ struct sja1000_priv *priv;
+ struct resource *res_mem, *res_irq = NULL;
+ struct sja1000_platform_data *pdata;
+ struct device_node *of = pdev->dev.of_node;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata && !of) {
+ dev_err(&pdev->dev, "No platform data provided!\n");
+ return -ENODEV;
+ }
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mem)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res_mem->start,
+ resource_size(res_mem), DRV_NAME))
+ return -EBUSY;
+
+ addr = devm_ioremap_nocache(&pdev->dev, res_mem->start,
+ resource_size(res_mem));
+ if (!addr)
+ return -ENOMEM;
+
+ if (of)
+ irq = irq_of_parse_and_map(of, 0);
+ else
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!irq && !res_irq)
+ return -ENODEV;
+
+ dev = alloc_sja1000dev(0);
+ if (!dev)
+ return -ENOMEM;
+ priv = netdev_priv(dev);
+
+ if (res_irq) {
+ irq = res_irq->start;
+ priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+ if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
+ priv->irq_flags |= IRQF_SHARED;
+ } else {
+ priv->irq_flags = IRQF_SHARED;
+ }
+
+ dev->irq = irq;
+ priv->reg_base = addr;
+
+ if (of)
+ sp_populate_of(priv, of);
+ else
+ sp_populate(priv, pdata, res_mem->flags);
+
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_sja1000dev(dev);
@@ -148,40 +229,32 @@ static int sp_probe(struct platform_device *pdev)
exit_free:
free_sja1000dev(dev);
- exit_iounmap:
- iounmap(addr);
- exit_release:
- release_mem_region(res_mem->start, resource_size(res_mem));
- exit:
return err;
}
static int sp_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
- struct sja1000_priv *priv = netdev_priv(dev);
- struct resource *res;
+ struct net_device *dev = platform_get_drvdata(pdev);
unregister_sja1000dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
-
- if (priv->reg_base)
- iounmap(priv->reg_base);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
free_sja1000dev(dev);
return 0;
}
+static struct of_device_id sp_of_table[] = {
+ {.compatible = "nxp,sja1000"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sp_of_table);
+
static struct platform_driver sp_driver = {
.probe = sp_probe,
.remove = sp_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = sp_of_table,
},
};
diff --git a/drivers/net/can/sja1000/tscan1.c b/drivers/net/can/sja1000/tscan1.c
index 9756099a883..76513dd780c 100644
--- a/drivers/net/can/sja1000/tscan1.c
+++ b/drivers/net/can/sja1000/tscan1.c
@@ -71,7 +71,7 @@ MODULE_LICENSE("GPL");
#define TSCAN1_SJA1000_XTAL 16000000
/* SJA1000 IO base addresses */
-static const unsigned short tscan1_sja1000_addresses[] __devinitconst = {
+static const unsigned short tscan1_sja1000_addresses[] = {
0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320
};
@@ -88,7 +88,7 @@ static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
}
/* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */
-static int __devinit tscan1_probe(struct device *dev, unsigned id)
+static int tscan1_probe(struct device *dev, unsigned id)
{
struct net_device *netdev;
struct sja1000_priv *priv;
@@ -171,7 +171,7 @@ static int __devinit tscan1_probe(struct device *dev, unsigned id)
return -ENXIO;
}
-static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/)
+static int tscan1_remove(struct device *dev, unsigned id /*unused*/)
{
struct net_device *netdev;
struct sja1000_priv *priv;
@@ -197,7 +197,7 @@ static int __devexit tscan1_remove(struct device *dev, unsigned id /*unused*/)
static struct isa_driver tscan1_isa_driver = {
.probe = tscan1_probe,
- .remove = __devexit_p(tscan1_remove),
+ .remove = tscan1_remove,
.driver = {
.name = "tscan1",
},