Messages in this thread Patch in this message | | | From | Holger Dengler <> | Subject | [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support | Date | Wed, 25 Mar 2015 10:51:50 +0100 |
| |
From: Benedikt Spranger <b.spranger@linutronix.de>
The Eberspaecher Flexcard PMC II is a PMC (PCI Mezzanine Card) II carrier board. The carrier board can take up to 4 exchangeable physical layer boards for e.g. CAN, FlexRay or Ethernet.
Signed-off-by: Holger Dengler <dengler@linutronix.de> Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de> cc: Samuel Ortiz <sameo@linux.intel.com> cc: Lee Jones <lee.jones@linaro.org> --- drivers/mfd/Kconfig | 10 +++ drivers/mfd/Makefile | 2 + drivers/mfd/flexcard/Makefile | 2 + drivers/mfd/flexcard/core.c | 193 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/flexcard.h | 34 ++++++++ include/uapi/linux/flexcard.h | 125 +++++++++++++++++++++++++++ 6 files changed, 366 insertions(+) create mode 100644 drivers/mfd/flexcard/Makefile create mode 100644 drivers/mfd/flexcard/core.c create mode 100644 include/linux/mfd/flexcard.h create mode 100644 include/uapi/linux/flexcard.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 38356e3..3765707 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -217,6 +217,16 @@ config MFD_DLN2 etc. must be enabled in order to use the functionality of the device. +config MFD_FLEXCARD + tristate "Support for Eberspaecher Flexcard PMC II Carrier Board" + select MFD_CORE + depends on PCI + help + This is the core driver for the Eberspaecher Flexcard + PMC (PCI Mezzanine Card) II carrier board. This carrier board + can take up to 4 exchangeable physical layer boards for + CAN, FlexRay or Ethernet. + config MFD_MC13XXX tristate depends on (SPI_MASTER || I2C) diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 19f3d74..d7d5432 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -181,3 +181,5 @@ obj-$(CONFIG_MFD_RT5033) += rt5033.o intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o + +obj-$(CONFIG_MFD_FLEXCARD) += flexcard/ diff --git a/drivers/mfd/flexcard/Makefile b/drivers/mfd/flexcard/Makefile new file mode 100644 index 0000000..6606ebb --- /dev/null +++ b/drivers/mfd/flexcard/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MFD_FLEXCARD) += flexcard.o +flexcard-objs := core.o diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c new file mode 100644 index 0000000..99df3d5 --- /dev/null +++ b/drivers/mfd/flexcard/core.c @@ -0,0 +1,193 @@ +/* + * Eberspaecher Flexcard PMC II Carrier Board PCI Driver + * + * Copyright (c) 2014,2015 Linutronix GmbH + * Author: Holger Dengler + * Benedikt Spranger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/flexcard.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/flexcard.h> + +static const char drv_name[] = "flexcard"; + +static int flexcard_tiny_can(struct flexcard_device *priv, + int idx, int id, u32 offset) +{ + struct mfd_cell *cell = &priv->cells[idx]; + struct resource *res = &priv->res[idx]; + struct pci_dev *pci = priv->pdev; + + cell->name = "flexcard-dcan"; + cell->resources = res; + cell->num_resources = 1; + cell->id = id; + + res->name = "flexcard-dcan"; + res->flags = IORESOURCE_MEM; + res->parent = &pci->resource[1]; + res->start = pci->resource[1].start + offset; + res->end = res->start + FLEXCARD_CAN_SIZE - 1; + + return 0; +} + +static int flexcard_tiny_flexray(struct flexcard_device *priv, + int idx, int id, u32 offset) +{ + struct mfd_cell *cell = &priv->cells[idx]; + struct resource *res = &priv->res[idx]; + struct pci_dev *pci = priv->pdev; + + cell->name = "flexcard-eray"; + cell->resources = res; + cell->num_resources = 1; + cell->id = id; + + res->name = "flexcard-eray"; + res->flags = IORESOURCE_MEM; + res->parent = &pci->resource[1]; + res->start = pci->resource[1].start + offset; + res->end = res->start + FLEXCARD_FR_SIZE - 1; + + return 0; +} + +static int flexcard_tiny_probe(struct flexcard_device *priv) +{ + u32 fc_slic0 = priv->conf->fc_slic[0]; + struct pci_dev *pdev = priv->pdev; + u8 nr_can, nr_fr, nr; + u32 offset = 0; + int i, ret; + + nr_can = (fc_slic0 >> 4) & 0xf; + nr_fr = fc_slic0 & 0xf; + nr = nr_can + nr_fr; + + dev_info(&pdev->dev, "tinys: CAN: %d FR: %d", nr_can, nr_fr); + + priv->cells = devm_kzalloc(&pdev->dev, nr * sizeof(struct mfd_cell), + GFP_KERNEL); + if (!priv->cells) + return -ENOMEM; + + priv->res = devm_kzalloc(&pdev->dev, nr * sizeof(struct resource), + GFP_KERNEL); + if (!priv->res) + return -ENOMEM; + + for (i = 0; i < nr_fr; i++) { + ret = flexcard_tiny_flexray(priv, i, i, offset); + if (ret) + return ret; + offset += FLEXCARD_FR_OFFSET; + } + + for (i = 0; i < nr_can; i++) { + ret = flexcard_tiny_can(priv, nr_fr + i, i, offset); + if (ret) + return ret; + offset += FLEXCARD_CAN_OFFSET; + } + + return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL, 0, NULL); +} + +static int flexcard_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct flexcard_device *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + priv->pdev = pdev; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "unable to enable device: %d\n", ret); + return ret; + } + + pci_set_master(pdev); + ret = pci_request_regions(pdev, drv_name); + if (ret) { + dev_err(&pdev->dev, "unable to request regions: %d\n", ret); + goto out_disable; + } + + priv->conf = pci_ioremap_bar(pdev, 0); + if (!priv->conf) { + dev_err(&pdev->dev, "unable to remap configuration regs\n"); + ret = -ENOMEM; + goto out_release; + } + + ret = flexcard_tiny_probe(priv); + if (ret) { + dev_err(&pdev->dev, "unable to probe tinys: %d", ret); + goto out_unmap; + } + + dev_info(&pdev->dev, "HW %02x.%02x.%02x FW %02x.%02x.%02x\n", + priv->conf->fc_hw_ver.maj, priv->conf->fc_hw_ver.min, + priv->conf->fc_hw_ver.dev, priv->conf->fc_fw_ver.maj, + priv->conf->fc_fw_ver.min, priv->conf->fc_fw_ver.dev); + + return 0; + +out_unmap: + iounmap(priv->conf); +out_release: + pci_release_regions(pdev); +out_disable: + pci_disable_device(pdev); + + return ret; +} + +static void flexcard_remove(struct pci_dev *pdev) +{ + struct flexcard_device *priv = pci_get_drvdata(pdev); + + mfd_remove_devices(&pdev->dev); + iounmap(priv->conf); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +#define PCI_VENDOR_ID_EBEL 0x1974 + +static const struct pci_device_id flexcard_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_EBEL, 0x0009), }, + { } +}; +MODULE_DEVICE_TABLE(pci, flexcard_pci_ids); + +static struct pci_driver flexcard_driver = { + .name = drv_name, + .id_table = flexcard_pci_ids, + .probe = flexcard_probe, + .remove = flexcard_remove, +}; + +module_pci_driver(flexcard_driver); + +MODULE_AUTHOR("Holger Dengler <dengler@linutronix.de>"); +MODULE_AUTHOR("Benedikt Spranger <b.spranger@linutronix.de>"); +MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II Carrier Board Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h new file mode 100644 index 0000000..20d0f40 --- /dev/null +++ b/include/linux/mfd/flexcard.h @@ -0,0 +1,34 @@ +/* + * Common Definitions for Eberspaecher Flexcard PMC II + * + * Copyright (c) 2014,2015 Linutronix GmbH + * Author: Holger Dengler + * Benedikt Spranger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef FLEXCARD_H +#define FLEXCARD_H + +#define FLEXCARD_CAN_OFFSET 0x2000 +#define FLEXCARD_CAN_SIZE 0x2000 + +#define FLEXCARD_FR_OFFSET 0x4000 +#define FLEXCARD_FR_SIZE 0x2000 + +struct flexcard_device { + struct pci_dev *pdev; + struct fc_conf_bar __iomem *conf; + struct mfd_cell *cells; + struct resource *res; +}; + +enum flexcard_cell_id { + FLEXCARD_CELL_CAN, + FLEXCARD_CELL_FLEXRAY, +}; + +#endif /* FLEXCARD_H */ diff --git a/include/uapi/linux/flexcard.h b/include/uapi/linux/flexcard.h new file mode 100644 index 0000000..9b73d8d --- /dev/null +++ b/include/uapi/linux/flexcard.h @@ -0,0 +1,125 @@ +/* + * Eberspaecher Flexcard PMC II Carrier Board PCI Driver - device attributes + * + * Copyright (c) 2014,2015 Linutronix GmbH + * Author: Holger Dengler + * Benedikt Spranger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _LINUX_FLEXCARD_H +#define _LINUX_FLEXCARD_H + +#include <linux/types.h> + +struct fc_version { + __u8 dev; + __u8 min; + __u8 maj; + __u8 reserved; +} __packed; + +/* PCI BAR 0: Flexcard configuration */ +struct fc_conf_bar { + __u32 r1; /* 000 */ + struct fc_version fc_fw_ver; /* 004 */ + struct fc_version fc_hw_ver; /* 008 */ + __u32 r2[3]; /* 00c */ + __u64 fc_sn; /* 018 */ + __u32 fc_uid; /* 020 */ + __u32 r3[7]; /* 024 */ + __u32 fc_lic[6]; /* 040 */ + __u32 fc_slic[6]; /* 058 */ + __u32 trig_ctrl1; /* 070 */ + __u32 r4; /* 074 */ + __u32 trig_ctrl2; /* 078 */ + __u32 r5[22]; /* 07c */ + __u32 amreg; /* 0d4 */ + __u32 tiny_stat; /* 0d8 */ + __u32 r6[5]; /* 0dc */ + __u32 can_dat_cnt; /* 0f0 */ + __u32 can_err_cnt; /* 0f4 */ + __u32 fc_data_cnt; /* 0f8 */ + __u32 r7; /* 0fc */ + __u32 fc_rocr; /* 100 */ + __u32 r8; /* 104 */ + __u32 pg_ctrl; /* 108 */ + __u32 pg_term; /* 10c */ + __u32 r9; /* 110 */ + __u32 irs; /* 114 */ + __u32 fr_tx_cnt; /* 118 */ + __u32 irc; /* 11c */ + __u64 pcnt; /* 120 */ + __u32 r10; /* 128 */ + __u32 nmv_cnt; /* 12c */ + __u32 info_cnt; /* 130 */ + __u32 stat_trg_cnt; /* 134 */ + __u32 r11; /* 138 */ + __u32 fr_rx_cnt; /* 13c */ + __u32 fc_ts; /* 140 */ + __u32 fc_reset; /* 144 */ + __u32 trig_sc_ctrl; /* 148 */ + __u32 trig_ctrl; /* 14c */ + __u32 r12; /* 150 */ + __u32 tirqir; /* 154 */ + __u32 pccr1; /* 158 */ + __u32 pccr2; /* 15c */ + __u32 r13[4]; /* 160 */ + __u32 fc_nfctrl; /* 170 */ + __u32 nf_cnt; /* 174 */ + __u32 r14; /* 178 */ + __u32 pl_ctrl; /* 17c */ + __u32 r15[0xe0]; /* 180 */ + __u32 dma_ctrl; /* 500 */ + __u32 dma_stat; /* 504 */ + __u32 r16[2]; /* 508 */ + __u64 dma_cba; /* 510 */ + __u32 dma_cbs; /* 518 */ + __u32 dma_txr; /* 51c */ + __u32 dma_irer; /* 520 */ + __u32 dma_irsr; /* 524 */ + __u32 r17[10]; /* 528 */ + __u32 dma_cbcr; /* 550 */ + __u32 dma_cblr; /* 554 */ + __u32 r18[2]; /* 558 */ + __u32 dma_itcr; /* 560 */ + __u32 dma_itr; /* 564 */ + __u32 r19[2]; /* 568 */ + __u32 dma_wptr; /* 570 */ + __u32 dma_rptr; /* 574 */ + __u32 r20[0x62]; /* 578 */ + __u32 ts_high; /* 700 */ + __u32 ts_low; /* 704 */ + __u32 r21[2]; /* 708 */ + __u32 clk_src; /* 710 */ + __u32 r22[0x7b]; /* 714 */ + __u32 faddr; /* 900 */ + __u32 fwdat; /* 904 */ + __u32 fctrl; /* 908 */ + __u32 frdat; /* 90c */ + __u32 bwdat[16]; /* 910 */ + __u32 brdat[16]; /* 950 */ + __u32 r23[28]; /* 990 */ + __u32 fwmode; /* a00 */ + __u32 recond; /* a04 */ + __u32 wdtctrl; /* a08 */ + __u32 imgsel; /* a0c */ + __u32 actimg; /* a10 */ + __u32 updimginf; /* a14 */ + __u32 r24[0x32]; /* a18 */ + __u32 factory_image_info[8]; /* ae0 */ + __u32 app_image0_info[8]; /* b00 */ + __u32 app_image1_info[8]; /* b20 */ + __u32 app_image2_info[8]; /* b40 */ + __u32 app_image3_info[8]; /* b60 */ + __u32 app_image4_info[8]; /* b80 */ + __u32 app_image5_info[8]; /* ba0 */ + __u32 app_image6_info[8]; /* bc0 */ + __u32 app_image7_info[8]; /* be0 */ + __u32 r25[0x100]; /* c00 */ +} __packed; + +#endif /* _LINUX_FLEXCARD_H */ -- 2.1.4
| |