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: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx> Signed-off-by: Holger Dengler <dengler@xxxxxxxxxxxxx> cc: Lee Jones <lee.jones@xxxxxxxxxx> --- drivers/mfd/Kconfig | 10 ++ drivers/mfd/Makefile | 2 + drivers/mfd/flexcard_core.c | 218 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/flexcard.h | 103 ++++++++++++++++++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/flexcard.h | 64 +++++++++++++ 6 files changed, 398 insertions(+) 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 c6df644..a5a12da 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -299,6 +299,16 @@ config MFD_EXYNOS_LPASS Select this option to enable support for Samsung Exynos Low Power Audio Subsystem. +config MFD_FLEXCARD + tristate "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 9834e66..843e57c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o +flexcard-objs := flexcard_core.o +obj-$(CONFIG_MFD_FLEXCARD) += flexcard.o diff --git a/drivers/mfd/flexcard_core.c b/drivers/mfd/flexcard_core.c new file mode 100644 index 0000000..e580971 --- /dev/null +++ b/drivers/mfd/flexcard_core.c @@ -0,0 +1,218 @@ +/* + * Eberspächer Flexcard PMC II Carrier Board PCI Driver + * + * Copyright (c) 2014 - 2016, Linutronix GmbH + * Author: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx> + * Holger Dengler <dengler@xxxxxxxxxxxxx> + * + * 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/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> + +#include <linux/mfd/core.h> +#include <linux/mfd/flexcard.h> + +#define FLEXCARD_CAN_OFFSET 0x2000 +#define FLEXCARD_CAN_SIZE 0x2000 + +#define FLEXCARD_FR_OFFSET 0x4000 +#define FLEXCARD_FR_SIZE 0x2000 + +enum flexcard_cell_id { + FLEXCARD_CELL_CAN, + FLEXCARD_CELL_FLEXRAY, +}; + +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; + + if (res->end > pci->resource[1].end) + return -EINVAL; + + 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; + + if (res->end > pci->resource[1].end) + return -EINVAL; + + return 0; +} + +static int flexcard_tiny_probe(struct flexcard_device *priv) +{ + struct pci_dev *pdev = priv->pdev; + u32 fc_slic0, offset = 0; + u8 nr_can, nr_fr, nr; + int i, ret; + + /* + * Reading FC_LIC[0] register to determine the number of CAN and + * FlexRay Devices + */ + fc_slic0 = readl(&priv->bar0->conf.fc_slic[0]); + 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; + union { + struct fc_version ver; + u32 reg; + } fw_ver, hw_ver; + + 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, "flexcard"); + if (ret) { + dev_err(&pdev->dev, "unable to request regions: %d\n", ret); + goto out_disable; + } + + priv->bar0 = pci_ioremap_bar(pdev, 0); + if (!priv->bar0) { + dev_err(&pdev->dev, "unable to remap bar0 regs\n"); + ret = -ENOMEM; + goto out_release; + } + fw_ver.reg = readl(&priv->bar0->conf.fc_fw_ver); + hw_ver.reg = readl(&priv->bar0->conf.fc_hw_ver); + + 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", + hw_ver.ver.maj, hw_ver.ver.min, hw_ver.ver.dev, + fw_ver.ver.maj, fw_ver.ver.min, fw_ver.ver.dev); + + return 0; + +out_unmap: + iounmap(priv->bar0); +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->bar0); + 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 = "flexcard", + .id_table = flexcard_pci_ids, + .probe = flexcard_probe, + .remove = flexcard_remove, +}; + +module_pci_driver(flexcard_driver); + +MODULE_AUTHOR("Holger Dengler <dengler@xxxxxxxxxxxxx>"); +MODULE_AUTHOR("Benedikt Spranger <b.spranger@xxxxxxxxxxxxx>"); +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..362b909 --- /dev/null +++ b/include/linux/mfd/flexcard.h @@ -0,0 +1,103 @@ +/* + * Eberspächer Flexcard PMC II Carrier Board PCI Driver - device attributes + * + * Copyright (c) 2014 - 2016, Linutronix GmbH + * Author: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx> + * Holger Dengler <dengler@xxxxxxxxxxxxx> + * + * 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_MFD_FLEXCARD_H +#define _LINUX_MFD_FLEXCARD_H + +#include <uapi/linux/flexcard.h> + +/* PCI BAR 0: Flexcard DMA register */ +struct fc_bar0_dma { + __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 */ +} __packed; + +/* PCI BAR 0: Flexcard clock register */ +struct fc_bar0_time { + __u32 ts_high; /* 700 */ + __u32 ts_low; /* 704 */ + __u32 r21[2]; /* 708 */ + __u32 clk_src; /* 710 */ +} __packed; + +struct fc_bar0_nf { + __u32 fc_nfctrl; /* 170 */ + __u32 nf_cnt; /* 174 */ +} __packed; + +/* PCI BAR 0: Flexcard register */ +struct fc_bar0 { + struct fc_bar0_conf conf; /* 000-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 */ + struct fc_bar0_nf nf; /* 170-174 */ + __u32 r14; /* 178 */ + struct fc_bar0_dma dma; /* 500-574 */ + __u32 r20[0x62]; /* 578 */ + struct fc_bar0_time time; /* 700-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; + +struct flexcard_device { + struct pci_dev *pdev; + struct fc_bar0 __iomem *bar0; + struct mfd_cell *cells; + struct resource *res; +}; + +#endif /* _LINUX_FLEXCARD_H */ diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index cd2be1c..46dc3c1 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -131,6 +131,7 @@ header-y += filter.h header-y += firewire-cdev.h header-y += firewire-constants.h header-y += flat.h +header-y += flexcard.h header-y += fou.h header-y += fs.h header-y += fsl_hypervisor.h diff --git a/include/uapi/linux/flexcard.h b/include/uapi/linux/flexcard.h new file mode 100644 index 0000000..4e9f07b4 --- /dev/null +++ b/include/uapi/linux/flexcard.h @@ -0,0 +1,64 @@ +/* + * Eberspächer Flexcard PMC II Carrier Board PCI Driver - device attributes + * + * Copyright (c) 2014,2016 Linutronix GmbH + * Author: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx> + * Holger Dengler <dengler@xxxxxxxxxxxxx> + * + * 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 _UAPI_LINUX_FLEXCARD_H +#define _UAPI_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_bar0_conf { + __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 */ +} __packed; + +#endif /* _UAPI_LINUX_FLEXCARD_H */ -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html