[PATCH 01/12] mfd: Eberspaecher Flexcard PMC II Carrier Board support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux PCI]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux