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

From: Holger Dengler
Date: Wed Mar 25 2015 - 05:55:22 EST


From: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx>

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@xxxxxxxxxxxxx>
Signed-off-by: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx>
cc: Samuel Ortiz <sameo@xxxxxxxxxxxxxxx>
cc: Lee Jones <lee.jones@xxxxxxxxxx>
---
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@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..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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/