sending again - DNS of kernel.org is currently broken.
sorry of you receive this mail twice

On 09/08/2011 10:07 PM, Wolfgang Grandegger wrote:
> This patch adds the "peak_pci" driver for the PCAN PCI/PCIe cards (1, 2, 3
> or 4 channels) from PEAK Systems (http://www.peak-system.com).
> 
> Signed-off-by: Wolfgang Grandegger <[email protected]>

Looks good - Add my Acked-by

Marc

> ---
> 
> I have tested this patch on my 2 channel PEAK PCI card. Thomas, or somebody
> else with a PEAK PCAN PCI/PCIe card at hand, it would be nice if you could
> test it on your 4 channel card and add your "Tested-by".
> 
> Thanks,
> 
> Wolfgang. 
> 
>  drivers/net/can/sja1000/Kconfig    |    7 +
>  drivers/net/can/sja1000/Makefile   |    1 +
>  drivers/net/can/sja1000/peak_pci.c |  293 
> ++++++++++++++++++++++++++++++++++++
>  3 files changed, 301 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/sja1000/peak_pci.c
> 
> diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
> index 6fdc031..72b637d 100644
> --- a/drivers/net/can/sja1000/Kconfig
> +++ b/drivers/net/can/sja1000/Kconfig
> @@ -37,6 +37,13 @@ config CAN_EMS_PCI
>         CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
>         (http://www.ems-wuensche.de).
>  
> +config CAN_PEAK_PCI
> +     tristate "PEAK PCAN PCI/PCIe 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).
> +
>  config CAN_KVASER_PCI
>       tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
>       depends on PCI
> diff --git a/drivers/net/can/sja1000/Makefile 
> b/drivers/net/can/sja1000/Makefile
> index 2c591eb..428f5cf 100644
> --- a/drivers/net/can/sja1000/Makefile
> +++ b/drivers/net/can/sja1000/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
>  obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
>  obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
>  obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
> +obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
>  obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
>  obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
>  
> diff --git a/drivers/net/can/sja1000/peak_pci.c 
> b/drivers/net/can/sja1000/peak_pci.c
> new file mode 100644
> index 0000000..23d865d
> --- /dev/null
> +++ b/drivers/net/can/sja1000/peak_pci.c
> @@ -0,0 +1,293 @@
> +/*
> + * Copyright (C) 2007, 2011 Wolfgang Grandegger <[email protected]>
> + *
> + * Derived from the PCAN project file driver/src/pcan_pci.c:
> + *
> + * Copyright (C) 2001-2006  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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/netdevice.h>
> +#include <linux/delay.h>
> +#include <linux/pci.h>
> +#include <linux/io.h>
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +
> +#include "sja1000.h"
> +
> +MODULE_AUTHOR("Wolfgang Grandegger <[email protected]>");
> +MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI/PCIe cards");
> +MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe CAN card");
> +MODULE_LICENSE("GPL v2");
> +
> +#define DRV_NAME  "peak_pci"
> +
> +struct peak_pci_chan {
> +     void __iomem *cfg_base;      /* Common for all channels */
> +     struct net_device *next_dev; /* Chain of network devices */
> +     u16 icr_mask;                /* Interrupt mask for fast ack */
> +};
> +
> +#define PEAK_PCI_CAN_CLOCK   (16000000 / 2)
> +
> +#define PEAK_PCI_CDR         (CDR_CBP | CDR_CLKOUT_MASK)
> +#define PEAK_PCI_OCR         OCR_TX0_PUSHPULL
> +
> +/*
> + * Important PITA registers
> + */
> +#define PITA_ICR             0x00    /* Interrupt control register */
> +#define PITA_GPIOICR         0x18    /* GPIO interface control register */
> +#define PITA_MISC            0x1C    /* Miscellaneous register */
> +
> +#define PEAK_PCI_CFG_SIZE    0x1000  /* Size of the config PCI bar */
> +#define PEAK_PCI_CHAN_SIZE   0x0400  /* Size used by the channel */
> +
> +#define PEAK_PCI_VENDOR_ID   0x001C  /* The PCI device and vendor IDs */
> +#define PEAK_PCI_DEVICE_ID   0x0001  /* for PCI / PCIe slot cards */
> +#define PEAK_PCIE_DEVICE_ID  0x0002  /* for PCIExpress cards */
> +
> +static const u16 peak_pci_icr_masks[] = {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,},
> +     {0,}
> +};
> +
> +MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
> +
> +static u8 peak_pci_read_reg(const struct sja1000_priv *priv, int port)
> +{
> +     return readb(priv->reg_base + (port << 2));
> +}
> +
> +static void peak_pci_write_reg(const struct sja1000_priv *priv,
> +                            int port, u8 val)
> +{
> +     writeb(val, priv->reg_base + (port << 2));
> +}
> +
> +static void peak_pci_post_irq(const struct sja1000_priv *priv)
> +{
> +     struct peak_pci_chan *chan = priv->priv;
> +     u16 icr;
> +
> +     /* Select and clear in PITA stored interrupt */
> +     icr = readw(chan->cfg_base + PITA_ICR);
> +     if (icr & chan->icr_mask)
> +             writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
> +}
> +
> +static int __devinit peak_pci_probe(struct pci_dev *pdev,
> +                                 const struct pci_device_id *ent)
> +{
> +     struct sja1000_priv *priv;
> +     struct peak_pci_chan *chan;
> +     struct net_device *dev, *dev0 = NULL;
> +     void __iomem *cfg_base, *reg_base;
> +     u16 sub_sys_id, icr;
> +     int i, err, channels;
> +
> +     err = pci_enable_device(pdev);
> +     if (err)
> +             return err;
> +
> +     err = pci_request_regions(pdev, DRV_NAME);
> +     if (err)
> +             goto failure_disable_pci;
> +
> +     err = pci_read_config_word(pdev, 0x2e, &sub_sys_id);
> +     if (err)
> +             goto failure_release_regions;
> +
> +     dev_dbg(&pdev->dev, "probing device %04x:%04x:%04x\n",
> +             pdev->vendor, pdev->device, sub_sys_id);
> +
> +     err = pci_write_config_word(pdev, 0x44, 0);
> +     if (err)
> +             goto failure_release_regions;
> +
> +     if (sub_sys_id >= 12)
> +             channels = 4;
> +     else if (sub_sys_id >= 10)
> +             channels = 3;
> +     else if (sub_sys_id >= 4)
> +             channels = 2;
> +     else
> +             channels = 1;
> +
> +     cfg_base = pci_iomap(pdev, 0, PEAK_PCI_CFG_SIZE);
> +     if (!cfg_base) {
> +             dev_err(&pdev->dev, "failed to map PCI resource #0\n");
> +             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");
> +             goto failure_unmap_cfg_base;
> +     }
> +
> +     /* Set GPIO control register */
> +     writew(0x0005, cfg_base + PITA_GPIOICR + 2);
> +     /* Enable all channels of this card */
> +     writeb(0x00, cfg_base + PITA_GPIOICR);
> +     /* Toggle reset */
> +     writeb(0x05, cfg_base + PITA_MISC + 3);
> +     mdelay(5);
> +     /* Leave parport mux mode */
> +     writeb(0x04, cfg_base + PITA_MISC + 3);
> +
> +     icr = readw(cfg_base + PITA_ICR + 2);
> +
> +     for (i = 0; i < channels; i++) {
> +             dev = alloc_sja1000dev(sizeof(struct peak_pci_chan));
> +             if (!dev) {
> +                     err = -ENOMEM;
> +                     goto failure_remove_channels;
> +             }
> +
> +             priv = netdev_priv(dev);
> +             chan = priv->priv;
> +
> +             chan->cfg_base = cfg_base;
> +             priv->reg_base = reg_base + i * PEAK_PCI_CHAN_SIZE;
> +
> +             priv->read_reg = peak_pci_read_reg;
> +             priv->write_reg = peak_pci_write_reg;
> +             priv->post_irq = peak_pci_post_irq;
> +
> +             priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
> +             priv->ocr = PEAK_PCI_OCR;
> +             priv->cdr = PEAK_PCI_CDR;
> +             /* Neither a slave nor a single device distributes the clock */
> +             if (channels == 1 || i > 0)
> +                     priv->cdr |= CDR_CLK_OFF;
> +
> +             /* Setup interrupt handling */
> +             priv->irq_flags = IRQF_SHARED;
> +             dev->irq = pdev->irq;
> +
> +             chan->icr_mask = peak_pci_icr_masks[i];
> +             icr |= chan->icr_mask;
> +
> +             SET_NETDEV_DEV(dev, &pdev->dev);
> +
> +             err = register_sja1000dev(dev);
> +             if (err) {
> +                     dev_err(&pdev->dev, "failed to register device\n");
> +                     free_sja1000dev(dev);
> +                     goto failure_remove_channels;
> +             }
> +
> +             /* Create chain of SJA1000 devices */
> +             if (i == 0)
> +                     dev0 = dev;
> +             else
> +                     chan->next_dev = dev;
> +
> +             dev_info(&pdev->dev,
> +                      "%s at reg_base=0x%p cfg_base=0x%p irq=%d\n",
> +                      dev->name, priv->reg_base, chan->cfg_base, dev->irq);
> +     }
> +
> +     pci_set_drvdata(pdev, dev0);
> +
> +     /* Enable interrupts */
> +     writew(icr, cfg_base + PITA_ICR + 2);
> +
> +     return 0;
> +
> +failure_remove_channels:
> +     /* Disable interrupts */
> +     writew(0x0, cfg_base + PITA_ICR + 2);
> +
> +     for (dev = dev0; dev; dev = chan->next_dev) {
> +             unregister_sja1000dev(dev);
> +             free_sja1000dev(dev);
> +             priv = netdev_priv(dev);
> +             chan = priv->priv;
> +             dev = chan->next_dev;
> +     }
> +
> +     pci_iounmap(pdev, reg_base);
> +
> +failure_unmap_cfg_base:
> +     pci_iounmap(pdev, cfg_base);
> +
> +failure_release_regions:
> +     pci_release_regions(pdev);
> +
> +failure_disable_pci:
> +     pci_disable_device(pdev);
> +
> +     return err;
> +}
> +
> +static void __devexit peak_pci_remove(struct pci_dev *pdev)
> +{
> +     struct net_device *dev = pci_get_drvdata(pdev); /* First device */
> +     struct sja1000_priv *priv = netdev_priv(dev);
> +     struct peak_pci_chan *chan = priv->priv;
> +     void __iomem *cfg_base = chan->cfg_base;
> +     void __iomem *reg_base = priv->reg_base;
> +
> +     /* Disable interrupts */
> +     writew(0x0, cfg_base + PITA_ICR + 2);
> +
> +     /* Loop over all registered devices */
> +     while (1) {
> +             dev_info(&pdev->dev, "removing device %s\n", dev->name);
> +             unregister_sja1000dev(dev);
> +             free_sja1000dev(dev);
> +             dev = chan->next_dev;
> +             if (!dev)
> +                     break;
> +             priv = netdev_priv(dev);
> +             chan = priv->priv;
> +     }
> +
> +     pci_iounmap(pdev, reg_base);
> +     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),
> +};
> +
> +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);


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

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to