LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 00/11] Eberspaecher Flexcard PMC II base support
@ 2015-03-25  9:51 Holger Dengler
  2015-03-25  9:51 ` [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support Holger Dengler
                   ` (10 more replies)
  0 siblings, 11 replies; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel; +Cc: Peter Mahler, Juergen Bubeck, Holger Dengler

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 CAN, FlexRay or Ethernet.
This patchset adds support for the common infrastructure of the carrier
board.

This series of patches apply on v4.0-rc5.

According to the comments regarding our last posting, the MFD driver
patchset has been split up into separate functional parts.

Benedikt Spranger (11):
  mfd: Eberspaecher Flexcard PMC II Carrier Board support
  mfd: flexcard: add flexcard core device
  mfd: flexcard: add device attributes
  mfd: flexcard: add clocksrc device
  mfd: flexcard: add interrupt support
  mfd: flexcard: add DMA interrupt domain
  mfd: flexcard: add UIO IRQ devices
  mfd: flexcard: add DMA device
  mfd: flexcard: add DMA ringbuffer demux driver
  clocksource: flexcard: Add basic timestamp counter support
  clocksource: flexcard: Support timestamp trigger selection

 drivers/clocksource/Kconfig         |  11 +
 drivers/clocksource/Makefile        |   1 +
 drivers/clocksource/flexcard-time.c | 279 +++++++++++++++++++++
 drivers/mfd/Kconfig                 |  20 ++
 drivers/mfd/Makefile                |   2 +
 drivers/mfd/flexcard/Makefile       |   5 +
 drivers/mfd/flexcard/attr.c         | 215 ++++++++++++++++
 drivers/mfd/flexcard/core.c         | 473 ++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/dma.c          | 286 ++++++++++++++++++++++
 drivers/mfd/flexcard/flexcard-dma.h | 207 ++++++++++++++++
 drivers/mfd/flexcard/flexcard.h     |  37 +++
 drivers/mfd/flexcard/irq.c          | 252 +++++++++++++++++++
 drivers/mfd/flexcard/irq.h          |  61 +++++
 drivers/mfd/flexcard/parser.c       | 193 +++++++++++++++
 include/linux/mfd/flexcard.h        |  76 ++++++
 include/uapi/linux/Kbuild           |   1 +
 include/uapi/linux/flexcard.h       | 141 +++++++++++
 17 files changed, 2260 insertions(+)
 create mode 100644 drivers/clocksource/flexcard-time.c
 create mode 100644 drivers/mfd/flexcard/Makefile
 create mode 100644 drivers/mfd/flexcard/attr.c
 create mode 100644 drivers/mfd/flexcard/core.c
 create mode 100644 drivers/mfd/flexcard/dma.c
 create mode 100644 drivers/mfd/flexcard/flexcard-dma.h
 create mode 100644 drivers/mfd/flexcard/flexcard.h
 create mode 100644 drivers/mfd/flexcard/irq.c
 create mode 100644 drivers/mfd/flexcard/irq.h
 create mode 100644 drivers/mfd/flexcard/parser.c
 create mode 100644 include/linux/mfd/flexcard.h
 create mode 100644 include/uapi/linux/flexcard.h

-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  7:57   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 02/11] mfd: flexcard: add flexcard core device Holger Dengler
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

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


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 02/11] mfd: flexcard: add flexcard core device
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
  2015-03-25  9:51 ` [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:06   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 03/11] mfd: flexcard: add device attributes Holger Dengler
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard PCI BAR0 contain registers for configuration but also
for informational purpose like error counter, statistical information
and some timestamps. The read-only mmap of the misc device offers the
userspace a fast access to these registers.

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/flexcard/core.c  | 107 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mfd/flexcard.h |   6 +++
 include/uapi/linux/Kbuild    |   1 +
 3 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
index 99df3d5..1e7fb0f 100644
--- a/drivers/mfd/flexcard/core.c
+++ b/drivers/mfd/flexcard/core.c
@@ -14,11 +14,16 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/flexcard.h>
+#include <linux/fs.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/flexcard.h>
 
+static DEFINE_IDA(flexcard_ida);
+
 static const char drv_name[] = "flexcard";
 
 static int flexcard_tiny_can(struct flexcard_device *priv,
@@ -104,23 +109,106 @@ static int flexcard_tiny_probe(struct flexcard_device *priv)
 	return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL, 0, NULL);
 }
 
+static int flexcard_misc_open(struct inode *inode, struct file *filp)
+{
+	struct flexcard_device *priv =
+		container_of(filp->private_data, struct flexcard_device, dev);
+	int ret;
+
+	filp->private_data = priv;
+	ret = nonseekable_open(inode, filp);
+	if (ret) {
+		dev_err(&priv->pdev->dev, "unable to open file: %d\n", ret);
+		return ret;
+	}
+
+	kref_get(&priv->ref);
+	return 0;
+}
+
+static void flexcard_dev_release(struct kref *ref)
+{
+	struct flexcard_device *priv =
+		container_of(ref, struct flexcard_device, ref);
+
+	kfree(priv);
+	dev_info(&priv->pdev->dev, "misc device release");
+}
+
+static int flexcard_misc_release(struct inode *inode, struct file *filp)
+{
+	struct flexcard_device *priv = filp->private_data;
+
+	filp->private_data = NULL;
+	kref_put(&priv->ref, flexcard_dev_release);
+
+	return 0;
+}
+
+static int flexcard_misc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct flexcard_device *priv = filp->private_data;
+	unsigned long offset, vsize, psize, addr;
+
+	if (vma->vm_flags & (VM_WRITE | VM_EXEC))
+		return -EPERM;
+
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+	vsize = vma->vm_end - vma->vm_start;
+	psize = pci_resource_len(priv->pdev, 0) - offset;
+	addr = (pci_resource_start(priv->pdev, 0) + offset) >> PAGE_SHIFT;
+
+	if (vsize > psize) {
+		dev_err(&priv->pdev->dev,
+			"requested mmap mapping too large\n");
+		return -EINVAL;
+	}
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	return io_remap_pfn_range(vma, vma->vm_start, addr, vsize,
+				  vma->vm_page_prot);
+}
+
+static const struct file_operations flexcard_misc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= flexcard_misc_open,
+	.release	= flexcard_misc_release,
+	.mmap		= flexcard_misc_mmap,
+	.llseek		= no_llseek,
+};
+
 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);
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
+	ret = ida_simple_get(&flexcard_ida, 0, 0, GFP_KERNEL);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not get new Flexcard id:%d\n", ret);
+		goto out_free;
+	}
+
+	priv->cardnr = ret;
 	pci_set_drvdata(pdev, priv);
 	priv->pdev = pdev;
+	kref_init(&priv->ref);
+
+	snprintf(priv->name, sizeof(priv->name), "flexcard%d", priv->cardnr);
+	priv->dev.minor = MISC_DYNAMIC_MINOR;
+	priv->dev.name = priv->name;
+	priv->dev.fops = &flexcard_misc_fops;
+	priv->dev.parent = &pdev->dev;
 
 	ret = pci_enable_device(pdev);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to enable device: %d\n", ret);
-		return ret;
+		goto out_put;
 	}
 
 	pci_set_master(pdev);
@@ -143,6 +231,12 @@ static int flexcard_probe(struct pci_dev *pdev,
 		goto out_unmap;
 	}
 
+	ret = misc_register(&priv->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
+		goto out_remove;
+	}
+
 	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,
@@ -150,12 +244,18 @@ static int flexcard_probe(struct pci_dev *pdev,
 
 	return 0;
 
+out_remove:
+	mfd_remove_devices(&pdev->dev);
 out_unmap:
 	iounmap(priv->conf);
 out_release:
 	pci_release_regions(pdev);
 out_disable:
 	pci_disable_device(pdev);
+out_put:
+	ida_simple_remove(&flexcard_ida, priv->cardnr);
+out_free:
+	kref_put(&priv->ref, flexcard_dev_release);
 
 	return ret;
 }
@@ -164,10 +264,13 @@ static void flexcard_remove(struct pci_dev *pdev)
 {
 	struct flexcard_device *priv = pci_get_drvdata(pdev);
 
+	misc_deregister(&priv->dev);
 	mfd_remove_devices(&pdev->dev);
 	iounmap(priv->conf);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
+	ida_simple_remove(&flexcard_ida, priv->cardnr);
+	kref_put(&priv->ref, flexcard_dev_release);
 }
 
 #define PCI_VENDOR_ID_EBEL	0x1974
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index 20d0f40..84e155c 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -19,11 +19,17 @@
 #define FLEXCARD_FR_OFFSET	0x4000
 #define FLEXCARD_FR_SIZE	0x2000
 
+#define FLEXCARD_MAX_NAME	16
+
 struct flexcard_device {
 	struct pci_dev *pdev;
 	struct fc_conf_bar __iomem *conf;
 	struct mfd_cell *cells;
 	struct resource *res;
+	struct miscdevice dev;
+	struct kref ref;
+	int cardnr;
+	char name[FLEXCARD_MAX_NAME];
 };
 
 enum flexcard_cell_id {
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 68ceb97..d5c5002 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -127,6 +127,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
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 03/11] mfd: flexcard: add device attributes
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
  2015-03-25  9:51 ` [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support Holger Dengler
  2015-03-25  9:51 ` [PATCH 02/11] mfd: flexcard: add flexcard core device Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:15   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 04/11] mfd: flexcard: add clocksrc device Holger Dengler
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

Add device attributes for common flexcard information access. The
attribiutes are read-only execpt "uid" (user ID register).
The "uid" attribute can also be used to change the user-defined ID of a
Flexcard.

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/flexcard/Makefile   |   2 +-
 drivers/mfd/flexcard/attr.c     | 215 ++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/core.c     |  11 ++
 drivers/mfd/flexcard/flexcard.h |   7 ++
 4 files changed, 234 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mfd/flexcard/attr.c
 create mode 100644 drivers/mfd/flexcard/flexcard.h

diff --git a/drivers/mfd/flexcard/Makefile b/drivers/mfd/flexcard/Makefile
index 6606ebb..101000f 100644
--- a/drivers/mfd/flexcard/Makefile
+++ b/drivers/mfd/flexcard/Makefile
@@ -1,2 +1,2 @@
 obj-$(CONFIG_MFD_FLEXCARD)	+= flexcard.o
-flexcard-objs			:= core.o
+flexcard-objs			:= core.o attr.o
diff --git a/drivers/mfd/flexcard/attr.c b/drivers/mfd/flexcard/attr.c
new file mode 100644
index 0000000..c91c884
--- /dev/null
+++ b/drivers/mfd/flexcard/attr.c
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+#include <linux/device.h>
+#include <linux/flexcard.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/mfd/flexcard.h>
+
+static ssize_t fw_version_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%02x.%02x.%02x\n", priv->conf->fc_fw_ver.maj,
+		       priv->conf->fc_fw_ver.min, priv->conf->fc_fw_ver.dev);
+}
+static DEVICE_ATTR_RO(fw_version);
+
+static ssize_t hw_version_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%02x.%02x.%02x\n", priv->conf->fc_hw_ver.maj,
+		       priv->conf->fc_hw_ver.min, priv->conf->fc_hw_ver.dev);
+}
+static DEVICE_ATTR_RO(hw_version);
+
+static ssize_t serialno_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%lld\n", priv->conf->fc_sn);
+}
+static DEVICE_ATTR_RO(serialno);
+
+static ssize_t tiny_stat_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "0x%x\n", priv->conf->tiny_stat);
+}
+static DEVICE_ATTR_RO(tiny_stat);
+
+static ssize_t can_dat_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->can_dat_cnt);
+}
+static DEVICE_ATTR_RO(can_dat);
+
+static ssize_t can_err_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->can_err_cnt);
+}
+static DEVICE_ATTR_RO(can_err);
+
+static ssize_t fc_data_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->fc_data_cnt);
+}
+static DEVICE_ATTR_RO(fc_data);
+
+static ssize_t fr_rx_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->fr_rx_cnt);
+}
+static DEVICE_ATTR_RO(fr_rx);
+
+static ssize_t fr_tx_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->fr_tx_cnt);
+}
+static DEVICE_ATTR_RO(fr_tx);
+
+static ssize_t nmv_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->nmv_cnt);
+}
+static DEVICE_ATTR_RO(nmv);
+
+static ssize_t info_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->info_cnt);
+}
+static DEVICE_ATTR_RO(info);
+
+static ssize_t stat_trg_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->stat_trg_cnt);
+}
+static DEVICE_ATTR_RO(stat_trg);
+
+static ssize_t nf_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%d\n", priv->conf->nf_cnt);
+}
+static DEVICE_ATTR_RO(nf);
+
+static ssize_t uid_store(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+	unsigned long uid;
+	int ret;
+
+	ret = kstrtou32(buf, 0, &uid);
+	if (ret)
+		return ret;
+
+	priv->conf->fc_uid = uid;
+	return count;
+}
+
+static ssize_t uid_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev->parent);
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	return sprintf(buf, "%u\n", priv->conf->fc_uid);
+}
+static DEVICE_ATTR(uid, S_IRUGO|S_IWUSR, uid_show, uid_store);
+
+static struct attribute *flexcard_misc_dev_attrs[] = {
+	&dev_attr_fw_version.attr,
+	&dev_attr_hw_version.attr,
+	&dev_attr_serialno.attr,
+	&dev_attr_tiny_stat.attr,
+	&dev_attr_can_dat.attr,
+	&dev_attr_can_err.attr,
+	&dev_attr_fc_data.attr,
+	&dev_attr_fr_rx.attr,
+	&dev_attr_fr_tx.attr,
+	&dev_attr_nmv.attr,
+	&dev_attr_info.attr,
+	&dev_attr_stat_trg.attr,
+	&dev_attr_nf.attr,
+	&dev_attr_uid.attr,
+	NULL,
+};
+
+static const struct attribute_group flexcard_misc_dev_group = {
+	.attrs = flexcard_misc_dev_attrs,
+};
+
+int flexcard_misc_add_attrs(struct device *dev)
+{
+	int ret;
+
+	ret = sysfs_create_group(&dev->kobj,
+				 &flexcard_misc_dev_group);
+
+	if (ret)
+		dev_err(dev, "failed to create sysfs attributes: %d\n", ret);
+
+	return ret;
+}
+
+void flexcard_misc_del_attrs(struct device *dev)
+{
+	sysfs_remove_group(&dev->kobj, &flexcard_misc_dev_group);
+}
diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
index 1e7fb0f..6477019 100644
--- a/drivers/mfd/flexcard/core.c
+++ b/drivers/mfd/flexcard/core.c
@@ -22,6 +22,8 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/flexcard.h>
 
+#include "flexcard.h"
+
 static DEFINE_IDA(flexcard_ida);
 
 static const char drv_name[] = "flexcard";
@@ -237,6 +239,12 @@ static int flexcard_probe(struct pci_dev *pdev,
 		goto out_remove;
 	}
 
+	ret = flexcard_misc_add_attrs(priv->dev.this_device);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
+		goto out_deregister;
+	}
+
 	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,
@@ -244,6 +252,8 @@ static int flexcard_probe(struct pci_dev *pdev,
 
 	return 0;
 
+out_deregister:
+	misc_deregister(&priv->dev);
 out_remove:
 	mfd_remove_devices(&pdev->dev);
 out_unmap:
@@ -264,6 +274,7 @@ static void flexcard_remove(struct pci_dev *pdev)
 {
 	struct flexcard_device *priv = pci_get_drvdata(pdev);
 
+	flexcard_misc_del_attrs(priv->dev.this_device);
 	misc_deregister(&priv->dev);
 	mfd_remove_devices(&pdev->dev);
 	iounmap(priv->conf);
diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
new file mode 100644
index 0000000..1fe451e
--- /dev/null
+++ b/drivers/mfd/flexcard/flexcard.h
@@ -0,0 +1,7 @@
+#ifndef __FLEXCARD_H
+#define  __FLEXCARD_H
+
+int flexcard_misc_add_attrs(struct device *dev);
+void flexcard_misc_del_attrs(struct device *dev);
+
+#endif /* __FLEXCARD_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 04/11] mfd: flexcard: add clocksrc device
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (2 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 03/11] mfd: flexcard: add device attributes Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:30   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 05/11] mfd: flexcard: add interrupt support Holger Dengler
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard offers a Flexray network synchronized counter with a
selectable resolution of 1us, 100ns or 10ns. Add an appropriate MFD-cell
to use the counter.

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/flexcard/core.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
index 6477019..c73ae5c 100644
--- a/drivers/mfd/flexcard/core.c
+++ b/drivers/mfd/flexcard/core.c
@@ -28,6 +28,29 @@ static DEFINE_IDA(flexcard_ida);
 
 static const char drv_name[] = "flexcard";
 
+static struct resource flexcard_clk_res[] = {
+	{
+		.name   = "flexcard-clksrc",
+		.start  = 0x700,
+		.end    = 0x713,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.name   = "flexcard-reset",
+		.start  = 0x144,
+		.end    = 0x147,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct mfd_cell flexcard_clk_dev[] = {
+	{
+		.id = 0,
+		.name = "flexcard-clksrc",
+		.num_resources = ARRAY_SIZE(flexcard_clk_res),
+		.resources = flexcard_clk_res,
+	},
+};
+
 static int flexcard_tiny_can(struct flexcard_device *priv,
 			     int idx, int id, u32 offset)
 {
@@ -111,6 +134,21 @@ static int flexcard_tiny_probe(struct flexcard_device *priv)
 	return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL, 0, NULL);
 }
 
+static int flexcard_clk_setup(struct flexcard_device *priv)
+{
+	struct pci_dev *pdev = priv->pdev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(flexcard_clk_res); i++)
+		flexcard_clk_res[i].parent = &pdev->resource[0];
+
+	flexcard_clk_dev[0].id = priv->cardnr;
+
+	return mfd_add_devices(&pdev->dev, 0, flexcard_clk_dev,
+			       ARRAY_SIZE(flexcard_clk_dev),
+			       &pdev->resource[0], 0, NULL);
+}
+
 static int flexcard_misc_open(struct inode *inode, struct file *filp)
 {
 	struct flexcard_device *priv =
@@ -233,6 +271,12 @@ static int flexcard_probe(struct pci_dev *pdev,
 		goto out_unmap;
 	}
 
+	ret = flexcard_clk_setup(priv);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register clksrc: %d\n", ret);
+		goto out_remove;
+	}
+
 	ret = misc_register(&priv->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 05/11] mfd: flexcard: add interrupt support
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (3 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 04/11] mfd: flexcard: add clocksrc device Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:46   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 06/11] mfd: flexcard: add DMA interrupt domain Holger Dengler
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard comprise an interrupt controller for the attached
tinys, timer, a Flexray related trigger and a second one for DMA.
Both controllers share a single IRQ line.

Add an interrupt domain for the non-DMA interrupts.

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             |   1 +
 drivers/mfd/flexcard/Makefile   |   2 +-
 drivers/mfd/flexcard/core.c     |  14 +++-
 drivers/mfd/flexcard/flexcard.h |   2 +
 drivers/mfd/flexcard/irq.c      | 167 ++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/irq.h      |  50 ++++++++++++
 include/linux/mfd/flexcard.h    |   2 +
 7 files changed, 235 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mfd/flexcard/irq.c
 create mode 100644 drivers/mfd/flexcard/irq.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3765707..f624b7f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -220,6 +220,7 @@ config MFD_DLN2
 config MFD_FLEXCARD
 	tristate "Support for Eberspaecher Flexcard PMC II Carrier Board"
 	select MFD_CORE
+	select IRQ_DOMAIN
 	depends on PCI
 	help
 	  This is the core driver for the Eberspaecher Flexcard
diff --git a/drivers/mfd/flexcard/Makefile b/drivers/mfd/flexcard/Makefile
index 101000f..4f72c9c 100644
--- a/drivers/mfd/flexcard/Makefile
+++ b/drivers/mfd/flexcard/Makefile
@@ -1,2 +1,2 @@
 obj-$(CONFIG_MFD_FLEXCARD)	+= flexcard.o
-flexcard-objs			:= core.o attr.o
+flexcard-objs			:= core.o attr.o irq.o
diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
index c73ae5c..a6f92b4 100644
--- a/drivers/mfd/flexcard/core.c
+++ b/drivers/mfd/flexcard/core.c
@@ -131,7 +131,8 @@ static int flexcard_tiny_probe(struct flexcard_device *priv)
 		offset += FLEXCARD_CAN_OFFSET;
 	}
 
-	return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL, 0, NULL);
+	return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL,
+			       0, priv->irq_domain);
 }
 
 static int flexcard_clk_setup(struct flexcard_device *priv)
@@ -265,10 +266,16 @@ static int flexcard_probe(struct pci_dev *pdev,
 		goto out_release;
 	}
 
+	ret = flexcard_setup_irq(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to setup irq controller: %d", ret);
+		goto out_unmap;
+	}
+
 	ret = flexcard_tiny_probe(priv);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to probe tinys: %d", ret);
-		goto out_unmap;
+		goto out_remove_irq;
 	}
 
 	ret = flexcard_clk_setup(priv);
@@ -300,6 +307,8 @@ out_deregister:
 	misc_deregister(&priv->dev);
 out_remove:
 	mfd_remove_devices(&pdev->dev);
+out_remove_irq:
+	flexcard_remove_irq(pdev);
 out_unmap:
 	iounmap(priv->conf);
 out_release:
@@ -321,6 +330,7 @@ static void flexcard_remove(struct pci_dev *pdev)
 	flexcard_misc_del_attrs(priv->dev.this_device);
 	misc_deregister(&priv->dev);
 	mfd_remove_devices(&pdev->dev);
+	flexcard_remove_irq(pdev);
 	iounmap(priv->conf);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
index 1fe451e..038c138 100644
--- a/drivers/mfd/flexcard/flexcard.h
+++ b/drivers/mfd/flexcard/flexcard.h
@@ -3,5 +3,7 @@
 
 int flexcard_misc_add_attrs(struct device *dev);
 void flexcard_misc_del_attrs(struct device *dev);
+int flexcard_setup_irq(struct pci_dev *pdev);
+void flexcard_remove_irq(struct pci_dev *pdev);
 
 #endif /* __FLEXCARD_H */
diff --git a/drivers/mfd/flexcard/irq.c b/drivers/mfd/flexcard/irq.c
new file mode 100644
index 0000000..fefcb24
--- /dev/null
+++ b/drivers/mfd/flexcard/irq.c
@@ -0,0 +1,167 @@
+/*
+ * Eberspaecher Flexcard PMC II Carrier Board PCI Driver - Interrupt controller
+ *
+ * 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/export.h>
+#include <linux/flexcard.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/flexcard.h>
+
+#include "irq.h"
+
+static irqreturn_t flexcard_demux(int irq, void *data)
+{
+	struct flexcard_device *priv = data;
+	u32 stat;
+	int i, cur;
+
+	stat = readl(&priv->conf->irs);
+	if (!stat)
+		return IRQ_NONE;
+
+	for (i = 0; i < NR_FLEXCARD_IRQ; i++) {
+		if (stat & flexcard_irq_tab[i].status) {
+			cur = irq_find_mapping(priv->irq_domain, i);
+			if (cur)
+				generic_handle_irq(cur);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int flexcard_req_irq(struct pci_dev *pdev)
+{
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+	int ret;
+
+	ret = pci_enable_msi(pdev);
+	if (ret) {
+		dev_warn(&pdev->dev, "could not enable MSI\n");
+		/* shared PCI irq fallback */
+		return request_irq(pdev->irq, flexcard_demux,
+				   IRQF_NO_THREAD | IRQF_SHARED,
+				   "flexcard", priv);
+	}
+	dev_info(&pdev->dev, "MSI enabled\n");
+
+	ret = request_irq(pdev->irq, flexcard_demux, IRQF_NO_THREAD,
+			  "flexcard", priv);
+	if (ret)
+		pci_disable_msi(pdev);
+
+	return ret;
+}
+
+static void flexcard_irq_ack(struct irq_data *d)
+{
+	struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+
+	if (flexcard_irq_tab[d->hwirq].reset)
+		writel(flexcard_irq_tab[d->hwirq].reset, &priv->conf->irs);
+}
+
+static void flexcard_irq_mask(struct irq_data *d)
+{
+	struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+	unsigned long flags;
+	u32 irc;
+
+	raw_spin_lock_irqsave(&priv->irq_lock, flags);
+	irc = readl(&priv->conf->irc);
+	irc &= ~flexcard_irq_tab[d->hwirq].enable;
+	writel(irc, &priv->conf->irc);
+	raw_spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static void flexcard_irq_unmask(struct irq_data *d)
+{
+	struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+	unsigned long flags;
+	u32 irc;
+
+	raw_spin_lock_irqsave(&priv->irq_lock, flags);
+	irc = readl(&priv->conf->irc);
+	irc |= flexcard_irq_tab[d->hwirq].enable;
+	writel(irc, &priv->conf->irc);
+	raw_spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static struct irq_chip flexcard_irq_chip = {
+	.name		= "flexcard_irq",
+	.irq_ack	= flexcard_irq_ack,
+	.irq_mask	= flexcard_irq_mask,
+	.irq_unmask	= flexcard_irq_unmask,
+};
+
+static int flexcard_irq_domain_map(struct irq_domain *d, unsigned int irq,
+				   irq_hw_number_t hw)
+{
+	struct flexcard_device *priv = d->host_data;
+
+	irq_set_chip_and_handler_name(irq, &flexcard_irq_chip,
+				      handle_level_irq, "flexcard");
+	irq_set_chip_data(irq, priv);
+	irq_modify_status(irq, IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops flexcard_irq_domain_ops = {
+	.map = flexcard_irq_domain_map,
+};
+
+int flexcard_setup_irq(struct pci_dev *pdev)
+{
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+	struct irq_domain *domain;
+	int ret;
+
+	/* Make sure none of the subirqs is enabled */
+	writel(0, &priv->conf->irc);
+	writel(0, &priv->conf->dma_irer);
+
+	raw_spin_lock_init(&priv->irq_lock);
+
+	domain = irq_domain_add_linear(NULL, NR_FLEXCARD_IRQ,
+				       &flexcard_irq_domain_ops, priv);
+	if (!domain) {
+		dev_err(&pdev->dev, "could not request irq domain\n");
+		return -ENODEV;
+	}
+
+	priv->irq_domain = domain;
+
+	ret = flexcard_req_irq(pdev);
+	if (ret)
+		irq_domain_remove(priv->dma_domain);
+
+	return ret;
+}
+
+void flexcard_remove_irq(struct pci_dev *pdev)
+{
+	struct flexcard_device *priv = pci_get_drvdata(pdev);
+
+	/* Disable all subirqs */
+	writel(0, &priv->conf->irc);
+	writel(0, &priv->conf->dma_irer);
+
+	free_irq(pdev->irq, priv);
+	pci_disable_msi(pdev);
+	irq_domain_remove(priv->irq_domain);
+}
diff --git a/drivers/mfd/flexcard/irq.h b/drivers/mfd/flexcard/irq.h
new file mode 100644
index 0000000..b18fb5b
--- /dev/null
+++ b/drivers/mfd/flexcard/irq.h
@@ -0,0 +1,50 @@
+#ifndef FLEXCARD_IRQ_H
+#define FLEXCARD_IRQ_H
+
+struct flexcard_irq_tab {
+	u32 enable;
+	u32 reset;
+	u32 status;
+};
+
+#define to_irq_tab(e, s) {			\
+	.enable = (1 << e),			\
+	.status = (1 << s),			\
+}
+
+#define to_irq_tab_ack(e, r, s) {		\
+	.enable = (1 << e),			\
+	.reset  = (1 << r),			\
+	.status = (1 << s),			\
+}
+
+/*
+ * Interrupt Controller Register S-Box
+ * unlike other irq controllers the FlexCard bits for enable, reset and status
+ * looks more like a cryptographic S-box. Make a const table to have a more
+ * easier access to this bits in the irqchip callback functions.
+ * The table contains the registers for PMC2-cards.
+ */
+static const struct flexcard_irq_tab flexcard_irq_tab[] = {
+	to_irq_tab_ack(28, 0, 28),	/* TIMER  */
+	to_irq_tab_ack(29, 1, 29),	/* CC1CYS */
+	to_irq_tab_ack(30, 10, 21),	/* CC2CYS */
+	to_irq_tab_ack(18, 2, 30),	/* CC3CYS */
+	to_irq_tab_ack(19, 6, 25),	/* CC4CYS */
+	to_irq_tab_ack(26, 4, 26),	/* WAKE1A */
+	to_irq_tab_ack(27, 5, 27),	/* WAKE1B */
+	to_irq_tab_ack(24, 8, 23),	/* WAKE2A */
+	to_irq_tab_ack(25, 9, 22),	/* WAKE2B */
+	to_irq_tab_ack(22, 12, 19),	/* WAKE3A */
+	to_irq_tab_ack(23, 13, 18),	/* WAKE3B */
+	to_irq_tab_ack(20, 14, 17),	/* WAKE4A */
+	to_irq_tab_ack(21, 15, 16),	/* WAKE4B */
+	to_irq_tab(15, 31),		/* CC1T0  */
+	to_irq_tab(14, 3),		/* CC2T0  */
+	to_irq_tab(16, 24),		/* CC3T0  */
+	to_irq_tab(17, 20),		/* CC4T0  */
+};
+
+#define NR_FLEXCARD_IRQ		ARRAY_SIZE(flexcard_irq_tab)
+
+#endif /* FLEXCARD_IRQ_H */
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index 84e155c..f5b789f 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -22,12 +22,14 @@
 #define FLEXCARD_MAX_NAME	16
 
 struct flexcard_device {
+	raw_spinlock_t irq_lock;
 	struct pci_dev *pdev;
 	struct fc_conf_bar __iomem *conf;
 	struct mfd_cell *cells;
 	struct resource *res;
 	struct miscdevice dev;
 	struct kref ref;
+	struct irq_domain *irq_domain;
 	int cardnr;
 	char name[FLEXCARD_MAX_NAME];
 };
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 06/11] mfd: flexcard: add DMA interrupt domain
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (4 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 05/11] mfd: flexcard: add interrupt support Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:50   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 07/11] mfd: flexcard: add UIO IRQ devices Holger Dengler
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard comprise an interrupt controller for the attached
tinys, timer, a Flexray related trigger and a second one for DMA.
Both controllers share a single IRQ line.

Add an interrupt domain for the DMA Controller interrupts.

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/flexcard/irq.c   | 95 +++++++++++++++++++++++++++++++++++++++++---
 drivers/mfd/flexcard/irq.h   | 11 +++++
 include/linux/mfd/flexcard.h | 23 +++++++++++
 3 files changed, 124 insertions(+), 5 deletions(-)

diff --git a/drivers/mfd/flexcard/irq.c b/drivers/mfd/flexcard/irq.c
index fefcb24..17e8b2c 100644
--- a/drivers/mfd/flexcard/irq.c
+++ b/drivers/mfd/flexcard/irq.c
@@ -27,11 +27,13 @@
 static irqreturn_t flexcard_demux(int irq, void *data)
 {
 	struct flexcard_device *priv = data;
-	u32 stat;
+	u32 stat, dma_stat;
 	int i, cur;
 
 	stat = readl(&priv->conf->irs);
-	if (!stat)
+	dma_stat = readl(&priv->conf->dma_irsr);
+
+	if (!stat && !dma_stat)
 		return IRQ_NONE;
 
 	for (i = 0; i < NR_FLEXCARD_IRQ; i++) {
@@ -41,6 +43,15 @@ static irqreturn_t flexcard_demux(int irq, void *data)
 				generic_handle_irq(cur);
 		}
 	}
+
+	for (i = 0; i < NR_FLEXCARD_DMA_IRQ; i++) {
+		if (dma_stat & flexcard_dma_irq_tab[i].status) {
+			cur = irq_find_mapping(priv->dma_domain, i);
+			if (cur)
+				generic_handle_irq(cur);
+		}
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -125,6 +136,63 @@ static struct irq_domain_ops flexcard_irq_domain_ops = {
 	.map = flexcard_irq_domain_map,
 };
 
+static void flexcard_dma_irq_ack(struct irq_data *d)
+{
+	struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+
+	writel(flexcard_dma_irq_tab[d->hwirq].reset, &priv->conf->dma_irsr);
+}
+
+static void flexcard_dma_irq_mask(struct irq_data *d)
+{
+	struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+	unsigned long flags;
+	u32 irer;
+
+	raw_spin_lock_irqsave(&priv->irq_lock, flags);
+	irer = readl(&priv->conf->dma_irer);
+	irer &= ~flexcard_dma_irq_tab[d->hwirq].enable;
+	writel(irer, &priv->conf->dma_irer);
+	raw_spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static void flexcard_dma_irq_unmask(struct irq_data *d)
+{
+	struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+	unsigned long flags;
+	u32 irer;
+
+	raw_spin_lock_irqsave(&priv->irq_lock, flags);
+	irer = readl(&priv->conf->dma_irer);
+	irer |= FLEXCARD_DMA_IRER_DIRE | flexcard_dma_irq_tab[d->hwirq].enable;
+	writel(irer, &priv->conf->dma_irer);
+	raw_spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static struct irq_chip flexcard_dma_irq_chip = {
+	.name		= "flexcard_dma_irq",
+	.irq_ack	= flexcard_dma_irq_ack,
+	.irq_mask	= flexcard_dma_irq_mask,
+	.irq_unmask	= flexcard_dma_irq_unmask,
+};
+
+static int flexcard_dma_irq_domain_map(struct irq_domain *d, unsigned int irq,
+				       irq_hw_number_t hw)
+{
+	struct flexcard_device *priv = d->host_data;
+
+	irq_set_chip_and_handler_name(irq, &flexcard_dma_irq_chip,
+				      handle_level_irq, "flexcard-dma");
+	irq_set_chip_data(irq, priv);
+	irq_modify_status(irq, IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops flexcard_dma_irq_domain_ops = {
+	.map = flexcard_dma_irq_domain_map,
+};
+
 int flexcard_setup_irq(struct pci_dev *pdev)
 {
 	struct flexcard_device *priv = pci_get_drvdata(pdev);
@@ -143,12 +211,27 @@ int flexcard_setup_irq(struct pci_dev *pdev)
 		dev_err(&pdev->dev, "could not request irq domain\n");
 		return -ENODEV;
 	}
-
 	priv->irq_domain = domain;
 
+	domain = irq_domain_add_linear(NULL, NR_FLEXCARD_DMA_IRQ,
+				       &flexcard_dma_irq_domain_ops, priv);
+	if (!domain) {
+		dev_err(&pdev->dev, "could not request dma irq domain\n");
+		ret = -ENODEV;
+		goto out_irq;
+	}
+	priv->dma_domain = domain;
+
 	ret = flexcard_req_irq(pdev);
 	if (ret)
-		irq_domain_remove(priv->dma_domain);
+		goto out_dma;
+
+	return 0;
+
+out_dma:
+	irq_domain_remove(priv->dma_domain);
+out_irq:
+	irq_domain_remove(priv->irq_domain);
 
 	return ret;
 }
@@ -161,7 +244,9 @@ void flexcard_remove_irq(struct pci_dev *pdev)
 	writel(0, &priv->conf->irc);
 	writel(0, &priv->conf->dma_irer);
 
+	irq_domain_remove(priv->dma_domain);
+	irq_domain_remove(priv->irq_domain);
+
 	free_irq(pdev->irq, priv);
 	pci_disable_msi(pdev);
-	irq_domain_remove(priv->irq_domain);
 }
diff --git a/drivers/mfd/flexcard/irq.h b/drivers/mfd/flexcard/irq.h
index b18fb5b..0e6fe18 100644
--- a/drivers/mfd/flexcard/irq.h
+++ b/drivers/mfd/flexcard/irq.h
@@ -1,6 +1,8 @@
 #ifndef FLEXCARD_IRQ_H
 #define FLEXCARD_IRQ_H
 
+#define FLEXCARD_DMA_IRER_DIRE		(1 << 31)
+
 struct flexcard_irq_tab {
 	u32 enable;
 	u32 reset;
@@ -47,4 +49,13 @@ static const struct flexcard_irq_tab flexcard_irq_tab[] = {
 
 #define NR_FLEXCARD_IRQ		ARRAY_SIZE(flexcard_irq_tab)
 
+static const struct flexcard_irq_tab flexcard_dma_irq_tab[] = {
+	to_irq_tab_ack(0, 0, 0),	/* DMA_C0  */
+	to_irq_tab_ack(1, 1, 1),	/* DMA_TE  */
+	to_irq_tab_ack(4, 4, 4),	/* DMA_TI  */
+	to_irq_tab_ack(5, 5, 5),	/* DMA_CBL */
+};
+
+#define NR_FLEXCARD_DMA_IRQ	ARRAY_SIZE(flexcard_dma_irq_tab)
+
 #endif /* FLEXCARD_IRQ_H */
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index f5b789f..f9b0962 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -30,6 +30,7 @@ struct flexcard_device {
 	struct miscdevice dev;
 	struct kref ref;
 	struct irq_domain *irq_domain;
+	struct irq_domain *dma_domain;
 	int cardnr;
 	char name[FLEXCARD_MAX_NAME];
 };
@@ -39,4 +40,26 @@ enum flexcard_cell_id {
 	FLEXCARD_CELL_FLEXRAY,
 };
 
+#define FLEXCARD_IRQ_CC1CCYS_OFF	0
+#define FLEXCARD_IRQ_CC2CCYS_OFF	1
+#define FLEXCARD_IRQ_CC3CCYS_OFF	2
+#define FLEXCARD_IRQ_CC4CCYS_OFF	3
+#define FLEXCARD_IRQ_WAKE4A_OFF		4
+#define FLEXCARD_IRQ_WAKE4B_OFF		5
+#define FLEXCARD_IRQ_WAKE3A_OFF		6
+#define FLEXCARD_IRQ_WAKE3B_OFF		7
+#define FLEXCARD_IRQ_WAKE2A_OFF		8
+#define FLEXCARD_IRQ_WAKE2B_OFF		9
+#define FLEXCARD_IRQ_WAKE1A_OFF		10
+#define FLEXCARD_IRQ_WAKE1B_OFF		11
+#define FLEXCARD_IRQ_CC1T0_OFF		12
+#define FLEXCARD_IRQ_CC2T0_OFF		13
+#define FLEXCARD_IRQ_CC3T0_OFF		14
+#define FLEXCARD_IRQ_CC4T0_OFF		15
+
+#define FLEXCARD_DMA_IRQ_CO		0
+#define FLEXCARD_DMA_IRQ_TE		1
+#define FLEXCARD_DMA_IRQ_TI		2
+#define FLEXCARD_DMA_IRQ_CBL		3
+
 #endif /* FLEXCARD_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 07/11] mfd: flexcard: add UIO IRQ devices
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (5 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 06/11] mfd: flexcard: add DMA interrupt domain Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:57   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 08/11] mfd: flexcard: add DMA device Holger Dengler
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

Add an UIO device for each Flexcard Flexray related trigger. The trigger
devide into:
 - Flexray cycle start (CCYS)
 - Flexray timer 0 (CCxT0)
 - Bus wakeup (WAKE)

The UIO IRQ devices can be used to synchronize an application
with these events.

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/flexcard/core.c     | 52 +++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/flexcard.h | 23 ++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
index a6f92b4..cd06854 100644
--- a/drivers/mfd/flexcard/core.c
+++ b/drivers/mfd/flexcard/core.c
@@ -19,6 +19,7 @@
 #include <linux/miscdevice.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/flexcard.h>
 
@@ -51,6 +52,42 @@ static struct mfd_cell flexcard_clk_dev[] = {
 	},
 };
 
+irq_res(CC1CCYS);
+irq_res(CC2CCYS);
+irq_res(CC3CCYS);
+irq_res(CC4CCYS);
+irq_res(WAKE4A);
+irq_res(WAKE4B);
+irq_res(WAKE3A);
+irq_res(WAKE3B);
+irq_res(WAKE2A);
+irq_res(WAKE2B);
+irq_res(WAKE1A);
+irq_res(WAKE1B);
+irq_res(CC1T0);
+irq_res(CC2T0);
+irq_res(CC3T0);
+irq_res(CC4T0);
+
+static struct mfd_cell flexcard_uio_dev[] = {
+	flexcard_irq_cell(CC3CCYS, 0),
+	flexcard_irq_cell(CC4CCYS, 1),
+	flexcard_irq_cell(WAKE4A, 2),
+	flexcard_irq_cell(WAKE4B, 3),
+	flexcard_irq_cell(WAKE3A, 4),
+	flexcard_irq_cell(WAKE3B, 5),
+	flexcard_irq_cell(WAKE2A, 6),
+	flexcard_irq_cell(WAKE2B, 7),
+	flexcard_irq_cell(WAKE1A, 8),
+	flexcard_irq_cell(WAKE1B, 9),
+	flexcard_irq_cell(CC1CCYS, 10),
+	flexcard_irq_cell(CC2CCYS, 11),
+	flexcard_irq_cell(CC1T0, 12),
+	flexcard_irq_cell(CC2T0, 13),
+	flexcard_irq_cell(CC3T0, 14),
+	flexcard_irq_cell(CC4T0, 15),
+};
+
 static int flexcard_tiny_can(struct flexcard_device *priv,
 			     int idx, int id, u32 offset)
 {
@@ -150,6 +187,15 @@ static int flexcard_clk_setup(struct flexcard_device *priv)
 			       &pdev->resource[0], 0, NULL);
 }
 
+static int flexcard_add_uio(struct flexcard_device *priv)
+{
+	struct pci_dev *pdev = priv->pdev;
+
+	return mfd_add_devices(&pdev->dev, 0, flexcard_uio_dev,
+			       ARRAY_SIZE(flexcard_uio_dev),
+			       NULL, 0, priv->irq_domain);
+}
+
 static int flexcard_misc_open(struct inode *inode, struct file *filp)
 {
 	struct flexcard_device *priv =
@@ -284,6 +330,12 @@ static int flexcard_probe(struct pci_dev *pdev,
 		goto out_remove;
 	}
 
+	ret = flexcard_add_uio(priv);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to add irq UIO devices: %d", ret);
+		goto out_remove;
+	}
+
 	ret = misc_register(&priv->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
index 038c138..0d05f78 100644
--- a/drivers/mfd/flexcard/flexcard.h
+++ b/drivers/mfd/flexcard/flexcard.h
@@ -6,4 +6,27 @@ void flexcard_misc_del_attrs(struct device *dev);
 int flexcard_setup_irq(struct pci_dev *pdev);
 void flexcard_remove_irq(struct pci_dev *pdev);
 
+#define irq_res(irq_name)						\
+	static struct resource flexcard_irq_res_##irq_name = {		\
+		.name = __stringify(fc_irq_##irq_name##_off),		\
+		.start  = FLEXCARD_IRQ_##irq_name##_OFF,		\
+		.end  = FLEXCARD_IRQ_##irq_name##_OFF,			\
+		.flags  = IORESOURCE_IRQ,				\
+	};								\
+									\
+	static struct uio_info flexcard_irq_pdata_##irq_name = {	\
+		.name   = __stringify(irq_name),			\
+		.version = "0",						\
+	}
+
+#define flexcard_irq_cell(irq_name, irq_id)				\
+	{								\
+		.id = irq_id,						\
+		.name = "uio_pdrv_genirq",				\
+		.platform_data = &flexcard_irq_pdata_##irq_name,	\
+		.pdata_size = sizeof(flexcard_irq_pdata_##irq_name),	\
+		.num_resources = 1,					\
+		.resources = &flexcard_irq_res_##irq_name		\
+	}
+
 #endif /* __FLEXCARD_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 08/11] mfd: flexcard: add DMA device
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (6 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 07/11] mfd: flexcard: add UIO IRQ devices Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  8:59   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver Holger Dengler
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard interface design split packet receive and transmit. All
received packets and card status information are multiplexed with a
Flexcard specific protocol and handled through a DMA capable ringbuffer.
The TX path has to poke each available component separate.

Add a platform device for the DMA receive channel.

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/flexcard/core.c     | 60 +++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/flexcard.h |  5 ++++
 2 files changed, 65 insertions(+)

diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
index cd06854..39d1d4d 100644
--- a/drivers/mfd/flexcard/core.c
+++ b/drivers/mfd/flexcard/core.c
@@ -52,6 +52,34 @@ static struct mfd_cell flexcard_clk_dev[] = {
 	},
 };
 
+static struct resource flexcard_dma_res[] = {
+	{
+		.name   = "flexcard-dma",
+		.start  = 0x500,
+		.end    = 0x580,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.name   = "flexcard-dma",
+		.start  = FLEXCARD_DMA_IRQ_CBL,
+		.end    = FLEXCARD_DMA_IRQ_CBL,
+		.flags  = IORESOURCE_IRQ,
+	}, {
+		.name   = "flexcard-dma",
+		.start  = FLEXCARD_DMA_IRQ_CO,
+		.end    = FLEXCARD_DMA_IRQ_CO,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell flexcard_dma_dev[] = {
+	{
+		.id = 0,
+		.name = "flexcard-dma",
+		.num_resources = ARRAY_SIZE(flexcard_dma_res),
+		.resources = flexcard_dma_res,
+	},
+};
+
 irq_res(CC1CCYS);
 irq_res(CC2CCYS);
 irq_res(CC3CCYS);
@@ -187,6 +215,32 @@ static int flexcard_clk_setup(struct flexcard_device *priv)
 			       &pdev->resource[0], 0, NULL);
 }
 
+static int flexcard_add_dma(struct flexcard_device *priv)
+{
+	struct pci_dev *pdev = priv->pdev;
+
+	/* check for a DMA capable firmware version*/
+	if (priv->conf->fc_fw_ver.maj < DMA_MIN_FW_MAJOR)
+		goto out;
+
+	if (priv->conf->fc_fw_ver.maj == DMA_MIN_FW_MAJOR) {
+		if (priv->conf->fc_fw_ver.min < DMA_MIN_FW_MINOR)
+			goto out;
+		if ((priv->conf->fc_fw_ver.min == DMA_MIN_FW_MINOR) &&
+		    (priv->conf->fc_fw_ver.dev < DMA_MIN_FW_UPDATE))
+			goto out;
+	}
+
+	return mfd_add_devices(&pdev->dev, 0, flexcard_dma_dev,
+			       ARRAY_SIZE(flexcard_dma_dev),
+			       &pdev->resource[0], 0, priv->dma_domain);
+
+out:
+	dev_info(&pdev->dev, "Firmware is not DMA capable\n");
+
+	return 0;
+}
+
 static int flexcard_add_uio(struct flexcard_device *priv)
 {
 	struct pci_dev *pdev = priv->pdev;
@@ -330,6 +384,12 @@ static int flexcard_probe(struct pci_dev *pdev,
 		goto out_remove;
 	}
 
+	ret = flexcard_add_dma(priv);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to add DMA device: %d", ret);
+		goto out_remove;
+	}
+
 	ret = flexcard_add_uio(priv);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to add irq UIO devices: %d", ret);
diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
index 0d05f78..ee6b773 100644
--- a/drivers/mfd/flexcard/flexcard.h
+++ b/drivers/mfd/flexcard/flexcard.h
@@ -1,6 +1,11 @@
 #ifndef __FLEXCARD_H
 #define  __FLEXCARD_H
 
+/* The first FW Version supporting DMA is 6.4.0 */
+#define DMA_MIN_FW_MAJOR	6
+#define DMA_MIN_FW_MINOR	4
+#define DMA_MIN_FW_UPDATE	0
+
 int flexcard_misc_add_attrs(struct device *dev);
 void flexcard_misc_del_attrs(struct device *dev);
 int flexcard_setup_irq(struct pci_dev *pdev);
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (7 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 08/11] mfd: flexcard: add DMA device Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-30  9:02   ` Lee Jones
  2015-03-25  9:51 ` [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support Holger Dengler
  2015-03-25  9:52 ` [PATCH 11/11] clocksource: flexcard: Support timestamp trigger selection Holger Dengler
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Samuel Ortiz, Lee Jones

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard interface design split packet receive and transmit. All
received packets and card status information are multiplexed with a
Flexcard specific protocol and handled through a DMA capable ringbuffer.
The TX path has to poke each available component separate.

Add a Flexcard DMA ringbuffer driver and packet demultiplexer.

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                 |   9 ++
 drivers/mfd/flexcard/Makefile       |   3 +
 drivers/mfd/flexcard/dma.c          | 286 ++++++++++++++++++++++++++++++++++++
 drivers/mfd/flexcard/flexcard-dma.h | 207 ++++++++++++++++++++++++++
 drivers/mfd/flexcard/parser.c       | 193 ++++++++++++++++++++++++
 include/linux/mfd/flexcard.h        |   5 +
 6 files changed, 703 insertions(+)
 create mode 100644 drivers/mfd/flexcard/dma.c
 create mode 100644 drivers/mfd/flexcard/flexcard-dma.h
 create mode 100644 drivers/mfd/flexcard/parser.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f624b7f..cd798a6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -228,6 +228,15 @@ config MFD_FLEXCARD
 	  can take up to 4 exchangeable physical layer boards for
 	  CAN, FlexRay or Ethernet.
 
+config MFD_FLEXCARD_DMA
+	tristate "DMA support for Eberspaecher Flexcard PMC II Carrier Board"
+	depends on MFD_FLEXCARD
+	help
+	  The Eberspaecher Flexcard PMC (PCI Mezzanine Card) II carrier
+	  board support one DMA capable receive ringbuffer for all devices.
+	  A card specific protocol is used to multiplex the received packets
+	  through the ringbuffer. Enable DMA and Packet parser.
+
 config MFD_MC13XXX
 	tristate
 	depends on (SPI_MASTER || I2C)
diff --git a/drivers/mfd/flexcard/Makefile b/drivers/mfd/flexcard/Makefile
index 4f72c9c..695ba44 100644
--- a/drivers/mfd/flexcard/Makefile
+++ b/drivers/mfd/flexcard/Makefile
@@ -1,2 +1,5 @@
 obj-$(CONFIG_MFD_FLEXCARD)	+= flexcard.o
 flexcard-objs			:= core.o attr.o irq.o
+
+obj-$(CONFIG_MFD_FLEXCARD_DMA)	+= flexcard-dma.o
+flexcard-dma-objs		:= dma.o parser.o
diff --git a/drivers/mfd/flexcard/dma.c b/drivers/mfd/flexcard/dma.c
new file mode 100644
index 0000000..ed4e2ea
--- /dev/null
+++ b/drivers/mfd/flexcard/dma.c
@@ -0,0 +1,286 @@
+/*
+ * Eberspaecher Flexcard PMC II Carrier Board PCI Driver - DMA controller
+ *
+ * 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/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/flexcard.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/flexcard.h>
+
+#include "flexcard-dma.h"
+
+static int flexcard_dma_stop(struct flexcard_dma *dma)
+{
+	void *dma_ctrl = &dma->reg->dma_ctrl;
+	void *dma_stat = &dma->reg->dma_stat;
+	int retry = 200;
+
+	writel(FLEXCARD_DMA_CTRL_STOP_REQ, dma_ctrl);
+
+	while (!(readl(dma_ctrl) & FLEXCARD_DMA_CTRL_DMA_IDLE) && retry--)
+		udelay(1);
+	if (!retry)
+		return -EBUSY;
+
+	retry = 200;
+	while ((readl(dma_stat) & FLEXCARD_DMA_STAT_BUSY) && retry--)
+		udelay(1);
+
+	return (retry) ? 0 : -EBUSY;
+}
+
+static int flexcard_dma_reset(struct flexcard_dma *dma)
+{
+	void *dma_ctrl = &dma->reg->dma_ctrl;
+	int retry = 500;
+
+	writel(FLEXCARD_DMA_CTRL_RST_DMA, dma_ctrl);
+
+	while (!(readl(dma_ctrl) & FLEXCARD_DMA_CTRL_DMA_IDLE) && retry--)
+		udelay(10);
+
+	return (retry) ? 0 : -EIO;
+}
+
+static int flexcard_dma_setup(struct flexcard_dma *dma)
+{
+	int ret;
+
+	ret = flexcard_dma_reset(dma);
+	if (ret)
+		goto out;
+
+	writel(0x0, &dma->reg->dma_rptr);
+	writel(0x0, &dma->reg->dma_wptr);
+	writel(0x0, &dma->reg->dma_ctrl);
+
+	writeq(dma->phys, &dma->reg->dma_cba);
+	writel(FLEXCARD_DMA_BUF_SIZE, &dma->reg->dma_cbs);
+out:
+	return ret;
+}
+
+static irqreturn_t flexcard_dma_isr(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	u32 avail, parsed, rptr = dma->rptr;
+
+	avail = readl(&dma->reg->dma_cblr);
+	if (!avail)
+		return IRQ_NONE;
+
+	do {
+		u32 tocp = rptr + FLEXCARD_MAX_PAKET_SIZE;
+		/*
+		 * For simplicity the parser always looks at contiguous
+		 * buffer space.
+		 *
+		 * We ensure that by copying the eventually wrapped
+		 * bytes of the next message from the bottom of the
+		 * dma buffer to the space right after the dma buffer
+		 * which has been allocated just for that reason.
+		 */
+		if (tocp > FLEXCARD_DMA_BUF_SIZE) {
+			tocp &= FLEXCARD_DMA_BUF_MASK;
+			memcpy(dma->buf + FLEXCARD_DMA_BUF_SIZE,
+			       dma->buf, tocp);
+		}
+
+		parsed = flexcard_parse_packet(dma->buf + rptr, avail, dma);
+		if (parsed > avail) {
+			dev_err(&pdev->dev, "Parser overrun\n");
+			rptr = (rptr + parsed) & FLEXCARD_DMA_BUF_MASK;
+			break;
+		}
+		avail -= parsed;
+		rptr = (rptr + parsed) & FLEXCARD_DMA_BUF_MASK;
+	} while (parsed && avail);
+
+	/* Update the read pointer in the device if we processed data */
+	if (dma->rptr != rptr) {
+		u32 *p = dma->buf + 2*FLEXCARD_DMA_BUF_SIZE - 4;
+		*p = dma->rptr = rptr;
+		writel(rptr, &dma->reg->dma_rptr);
+	} else {
+		/* This should not happen. Or can it ? */
+		dev_err(&pdev->dev, "rptr unchanged\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t flexcard_dma_ovr(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	u32 stat;
+
+	/* check overflow flag */
+	stat = readl(&dma->reg->dma_stat);
+	if (!(stat & FLEXCARD_DMA_STAT_OFL))
+		return IRQ_NONE;
+
+	dev_err(&pdev->dev, "DMA buffer overflow\n");
+
+	writel(0x0, &dma->reg->dma_rptr);
+
+	/* reset overflow flag */
+	writel(FLEXCARD_DMA_STAT_OFL, &dma->reg->dma_stat);
+
+	return IRQ_HANDLED;
+}
+
+static int flexcard_dma_resource(struct platform_device *pdev)
+{
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	dma->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!dma->reg) {
+		dev_err(&pdev->dev, "failed to map DMA register\n");
+		return -ENOMEM;
+	}
+
+	dma->irq = platform_get_irq(pdev, 0);
+	if (dma->irq < 0) {
+		dev_err(&pdev->dev, "failed to get CBL IRQ\n");
+		return -ENXIO;
+	}
+
+	dma->irq_ovr = platform_get_irq(pdev, 1);
+	if (dma->irq_ovr < 0) {
+		dev_err(&pdev->dev, "failed to get CO IRQ\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int flexcard_dma_probe(struct platform_device *pdev)
+{
+	const struct mfd_cell *cell;
+	struct flexcard_dma *dma;
+	int ret = -ENOMEM;
+
+	cell = mfd_get_cell(pdev);
+	if (!cell)
+		return -ENODEV;
+
+	dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		goto out;
+
+	platform_set_drvdata(pdev, dma);
+
+	dma->buf = dma_alloc_coherent(&pdev->dev, 2*FLEXCARD_DMA_BUF_SIZE,
+				      &dma->phys, GFP_KERNEL);
+	if (!dma->buf) {
+		dev_err(&pdev->dev, "could not allocate DMA memory\n");
+		goto out;
+	}
+
+	ret = flexcard_dma_resource(pdev);
+	if (ret)
+		goto out_free_buf;
+
+	ret = flexcard_dma_setup(dma);
+	if (ret) {
+		dev_err(&pdev->dev, "could not setup Flexcard DMA: %d\n", ret);
+		goto out_free_buf;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, dma->irq, NULL,
+					flexcard_dma_isr, IRQF_ONESHOT,
+					"flexcard-CBL", pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "could not request Flexcard DMA CBL IRQ\n");
+		goto out_free_buf;
+	}
+
+	ret = devm_request_irq(&pdev->dev, dma->irq_ovr, flexcard_dma_ovr, 0,
+			  "flexcard-CO", pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "could not request Flexcard DMA CO IRQ\n");
+		goto out_free_irq;
+	}
+
+	writel(FLEXCARD_DMA_CTRL_DMA_ENA, &dma->reg->dma_ctrl);
+	writel(0x300, &dma->reg->dma_cbcr);
+
+	dev_info(&pdev->dev, "Flexcard DMA registered");
+
+	return 0;
+
+out_free_irq:
+	writel(0x0, &dma->reg->dma_ctrl);
+out_free_buf:
+	dma_free_coherent(&pdev->dev, 2*FLEXCARD_DMA_BUF_SIZE,
+			  dma->buf, dma->phys);
+out:
+	return ret;
+}
+
+static int flexcard_dma_remove(struct platform_device *pdev)
+{
+	struct flexcard_dma *dma = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = flexcard_dma_stop(dma);
+	if (ret) {
+		dev_err(&pdev->dev, "could not stop DMA state machine\n");
+		goto out;
+	}
+
+	dma_free_coherent(&pdev->dev, 2*FLEXCARD_DMA_BUF_SIZE,
+			  dma->buf, dma->phys);
+
+out:
+	return ret;
+}
+
+static struct platform_driver flexcard_dma_driver = {
+	.probe		= flexcard_dma_probe,
+	.remove		= flexcard_dma_remove,
+	.driver		= {
+		.name   = "flexcard-dma",
+	}
+};
+
+static int __init flexcard_dma_init(void)
+{
+	return platform_driver_register(&flexcard_dma_driver);
+}
+
+static void __exit flexcard_dma_exit(void)
+{
+	platform_driver_unregister(&flexcard_dma_driver);
+}
+
+module_init(flexcard_dma_init);
+module_exit(flexcard_dma_exit);
+
+MODULE_AUTHOR("Holger Dengler <dengler@linutronix.de>");
+MODULE_AUTHOR("Benedikt Spranger <b.spranger@linutronix.de>");
+MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II DMA Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:flexcard-dma");
diff --git a/drivers/mfd/flexcard/flexcard-dma.h b/drivers/mfd/flexcard/flexcard-dma.h
new file mode 100644
index 0000000..7de1b23
--- /dev/null
+++ b/drivers/mfd/flexcard/flexcard-dma.h
@@ -0,0 +1,207 @@
+#ifndef __FLEXCARD_H
+#define  __FLEXCARD_H
+
+#define FLEXCARD_DMA_BUF_SIZE		0x200000
+#define FLEXCARD_DMA_BUF_MASK		(FLEXCARD_DMA_BUF_SIZE - 1)
+
+#define FLEXCARD_DMA_CTRL_DMA_ENA	(1 << 0)
+#define FLEXCARD_DMA_CTRL_MAN_ENA	(1 << 1)
+#define FLEXCARD_DMA_CTRL_STOP_REQ	(1 << 16)
+#define FLEXCARD_DMA_CTRL_DMA_IDLE	(1 << 17)
+#define FLEXCARD_DMA_CTRL_RST_DMA	(1 << 31)
+
+#define FLEXCARD_DMA_STAT_BUSY		(1 << 15)
+#define FLEXCARD_DMA_STAT_OFL		(1 << 31)
+
+#define FLEXCARD_MAX_PAKET_SIZE		0x200
+
+#define FLEXCARD_BUF_HEADER_LEN_SHIFT	15
+#define FLEXCARD_BUF_HEADER_LEN_MASK	0xfe
+
+#define FLEXCARD_CANIF_OFFSET		0x20
+
+struct flexcard_dma_reg __iomem {
+	u32 dma_ctrl;
+	u32 dma_stat;
+	u32 r1[2];
+	u64 dma_cba;
+	u32 dma_cbs;
+	u32 dma_txr;
+	u32 dma_irer;
+	u32 dma_irsr;
+	u32 r2[10];
+	u32 dma_cbcr;
+	u32 dma_cblr;
+	u32 r3[2];
+	u32 dma_itcr;
+	u32 dma_itr;
+	u32 r4[2];
+	u32 dma_wptr;
+	u32 dma_rptr;
+	u32 r5[2];
+} __packed;
+
+struct flexcard_dma {
+	int irq;
+	int irq_ovr;
+	u32 rptr;
+	void *buf;
+	dma_addr_t phys;
+	int nr_eray;
+	struct flexcard_dma_reg __iomem *reg;
+};
+
+enum fc_packet_type {
+	fc_packet_type_info = 1,
+	fc_packet_type_flexray_frame = 2,
+	fc_packet_type_error = 3,
+	fc_packet_type_status = 4,
+	fc_packet_type_trigger = 5,
+	fc_packet_type_tx_ack = 6,
+	fc_packet_type_nmv_vector = 7,
+	fc_packet_type_notification = 8,
+	fc_packet_type_trigger_ex = 9,
+	fc_packet_type_can = 10,
+	fc_packet_type_can_error = 11,
+};
+
+struct fc_packet {
+	__u32 type;
+	__u32 p_packet;
+	__u32 p_next_packet;
+} __packed;
+
+struct fc_info_packet {
+	__u32 current_cycle;
+	__u32 timestamp;
+	__u32 offset_rate_correction;
+	__u32 pta_ccf_count;
+	__u32 cc;
+} __packed;
+
+struct fc_flexray_frame {
+	__u32 header;
+	__u32 header_crc;
+	__u32 pdata;
+	__u32 channel;
+	__u32 frame_crc;
+	__u32 timestamp;
+	__u32 cc;
+} __packed;
+
+struct fc_error_packet {
+	__u32 flag;
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u64 additional_info;
+	__u32 cc;
+	__u32 reserved;
+} __packed;
+
+struct fc_status_packet {
+	__u32 flag;
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u32 additional_info;
+	__u32 cc;
+	__u32 reserved[2];
+} __packed;
+
+struct fc_tx_ack_packet {
+	__u32 bufferid;
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u32 header;
+	__u32 header_crc;
+	__u32 pdata;
+	__u32 channel;
+	__u32 cc;
+} __packed;
+
+struct fc_nm_vector_packet {
+	__u32 timestamp;
+	__u32 cycle_count;
+	__u32 nmv_vector_length;
+	__u32 nmv_vector[3];
+	__u32 cc;
+	__u32 reserved;
+} __packed;
+
+struct fc_notification_packet {
+	__u32 timestamp;
+	__u32 sequence_count;
+	__u32 reserved;
+} __packed;
+
+struct fc_trigger_ex_info_packet {
+	__u32 condition;
+	__u32 timestamp;
+	__u32 sequence_count;
+	__u32 reserved1;
+	__u64 performance_counter;
+	__u32 edge;
+	__u32 trigger_line;
+	__u32 reserved[4];
+} __packed;
+
+struct fc_can_packet {
+	__u32 id;
+	__u32 timestamp;
+	__u32 flags;
+	__u32 reserved;
+	__u32 cc;
+	__u8 data[8];
+} __packed;
+
+struct fc_can_error_packet {
+	__u32 type;
+	__u32 state;
+	__u32 timestamp;
+	__u32 rx_error_counter;
+	__u32 tx_error_counter;
+	__u32 cc;
+	__u32 reserved[2];
+} __packed;
+
+enum fc_can_cc_state {
+	fc_can_state_unknown = 0,
+	fc_can_state_config,
+	fc_can_state_normalActive,
+	fc_can_state_warning,
+	fc_can_state_error_passive,
+	fc_can_state_bus_off,
+};
+
+enum fc_can_error_type {
+	fc_can_error_none = 0,
+	fc_can_error_stuff,
+	fc_can_error_form,
+	fc_can_error_acknowledge,
+	fc_can_error_bit1,
+	fc_can_error_bit0,
+	fc_can_error_crc,
+	fc_can_error_parity,
+};
+
+union fc_packet_types {
+	struct fc_info_packet		info_packet;
+	struct fc_flexray_frame		flexray_frame;
+	struct fc_error_packet		error_packet;
+	struct fc_status_packet		status_packet;
+	struct fc_tx_ack_packet		tx_ack_packet;
+	struct fc_nm_vector_packet	nm_vector_packet;
+	struct fc_notification_packet	notification_packet;
+	struct fc_trigger_ex_info_packet ex_info_packet;
+	struct fc_can_packet		can_packet;
+	struct fc_can_error_packet	can_error_packet;
+};
+
+struct fc_packet_buf {
+	struct  fc_packet	header;
+	union   fc_packet_types	packet;
+} __packed;
+
+u32 flexcard_parse_packet(struct fc_packet_buf *pb, u32 avail,
+			  struct flexcard_dma *dma);
+
+#endif /* __FLEXCARD_H */
diff --git a/drivers/mfd/flexcard/parser.c b/drivers/mfd/flexcard/parser.c
new file mode 100644
index 0000000..83a6e8e
--- /dev/null
+++ b/drivers/mfd/flexcard/parser.c
@@ -0,0 +1,193 @@
+/*
+ * Eberspaecher Flexcard PMC II Carrier Board PCI Driver - packet parser/mux
+ *
+ * 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/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "flexcard-dma.h"
+
+static LIST_HEAD(rx_cb_list);
+static DEFINE_SPINLOCK(rx_cb_lock);
+
+struct fc_rx_cb {
+	struct list_head list;
+	int (*rx_cb)(void *priv, void *data, size_t len);
+	int cc;
+	void *priv;
+};
+
+int flexcard_register_rx_pkt(int cc, void *priv,
+			     int (*rx_cb)(void *priv, void *data, size_t len))
+{
+	unsigned long flags;
+	struct fc_rx_cb *cb, *next;
+
+	if (!rx_cb)
+		return -EINVAL;
+
+	cb = kmalloc(sizeof(*cb), GFP_ATOMIC);
+	if (!cb)
+		return -ENOMEM;
+
+	cb->cc = cc;
+	cb->priv = priv;
+	cb->rx_cb = rx_cb;
+
+	spin_lock_irqsave(&rx_cb_lock, flags);
+	list_for_each_entry(next, &rx_cb_list, list)
+		if (next->cc == cc)
+			goto out;
+
+	list_add_tail(&cb->list, &rx_cb_list);
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+
+	return 0;
+out:
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+	kfree(cb);
+
+	return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(flexcard_register_rx_pkt);
+
+void flexcard_unregister_rx_pkt(int cc)
+{
+	unsigned long flags;
+	struct fc_rx_cb *cur, *next;
+	int found = 0;
+
+	spin_lock_irqsave(&rx_cb_lock, flags);
+	list_for_each_entry_safe(cur, next, &rx_cb_list, list) {
+		if (cur->cc == cc) {
+			list_del(&cur->list);
+			kfree(cur);
+			found = 1;
+			break;
+		}
+	}
+
+	WARN_ON(!found);
+
+	spin_unlock_irqrestore(&rx_cb_lock, flags);
+}
+EXPORT_SYMBOL_GPL(flexcard_unregister_rx_pkt);
+
+static int flexcard_send_pkt(int cc, void *buf, size_t len)
+{
+	struct fc_rx_cb *next;
+	int ret = -ENODEV;
+
+	spin_lock(&rx_cb_lock);
+	list_for_each_entry(next, &rx_cb_list, list)
+		if (next->cc == cc)
+			ret = next->rx_cb(next->priv, buf, len);
+	spin_unlock(&rx_cb_lock);
+
+	return ret;
+}
+
+u32 flexcard_get_packet_len(u32 header)
+{
+	u32 len;
+
+	/*
+	 * header contains the number of transmitted 16bit words in bits 30-16.
+	 * if the number is odd the DMA engine padded with zero to 32bit.
+	 * calculate the number of transmitted bytes.
+	 */
+
+	len = le32_to_cpu(header);
+
+	len >>= FLEXCARD_BUF_HEADER_LEN_SHIFT;
+	len &= FLEXCARD_BUF_HEADER_LEN_MASK;
+
+	len = roundup(len, 4);
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(flexcard_get_packet_len);
+
+u32 flexcard_parse_packet(struct fc_packet_buf *pb, u32 avail,
+			  struct flexcard_dma *dma)
+{
+	u32 l, cc, len = sizeof(struct fc_packet);
+	union fc_packet_types *pt = &pb->packet;
+
+	switch (le32_to_cpu(pb->header.type)) {
+	case fc_packet_type_info:
+		len += sizeof(struct fc_info_packet);
+		cc = pt->info_packet.cc;
+		break;
+	case fc_packet_type_error:
+		len += sizeof(struct fc_error_packet);
+		cc = pt->error_packet.cc;
+		break;
+	case fc_packet_type_status:
+		len += sizeof(struct fc_status_packet);
+		cc = pt->status_packet.cc;
+
+		/* self sync status */
+		if ((dma->nr_eray == 1) && (cc == 1))
+			cc = 0;
+		break;
+	case fc_packet_type_nmv_vector:
+		len += sizeof(struct fc_nm_vector_packet);
+		cc = pt->nm_vector_packet.cc;
+		break;
+	case fc_packet_type_notification:
+		len += sizeof(struct fc_notification_packet);
+		cc = 0;
+		break;
+	case fc_packet_type_trigger_ex:
+		len += sizeof(struct fc_trigger_ex_info_packet);
+		cc = 0;
+		break;
+	case fc_packet_type_can:
+		len += sizeof(struct fc_can_packet);
+		cc = FLEXCARD_CANIF_OFFSET + pt->can_packet.cc;
+		break;
+	case fc_packet_type_can_error:
+		len += sizeof(struct fc_can_error_packet);
+		cc = FLEXCARD_CANIF_OFFSET + pt->can_error_packet.cc;
+		break;
+	case fc_packet_type_flexray_frame:
+		len += sizeof(struct fc_flexray_frame);
+		pt->flexray_frame.pdata = len;
+		l = flexcard_get_packet_len(pt->flexray_frame.header);
+		len += l;
+		cc = pt->flexray_frame.cc;
+		break;
+	case fc_packet_type_tx_ack:
+		len += sizeof(struct fc_tx_ack_packet);
+		pt->tx_ack_packet.pdata = len;
+		l = flexcard_get_packet_len(pt->tx_ack_packet.header);
+		len += l;
+		cc = pt->tx_ack_packet.cc;
+
+		/* self sync tx ack */
+		if ((dma->nr_eray == 1) && (cc == 1))
+			cc = 0;
+		break;
+	case fc_packet_type_trigger:
+	default:
+		pr_debug("pkt->type = %08x\n", pb->header.type);
+		return 0;
+	}
+
+	if (len > avail)
+		return 0;
+
+	flexcard_send_pkt(cc, pb, len);
+
+	return len;
+}
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index f9b0962..964d78c 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -62,4 +62,9 @@ enum flexcard_cell_id {
 #define FLEXCARD_DMA_IRQ_TI		2
 #define FLEXCARD_DMA_IRQ_CBL		3
 
+int flexcard_register_rx_pkt(int cc, void *priv,
+			     int (*rx_cb)(void *priv, void *data, size_t len));
+void flexcard_unregister_rx_pkt(int cc);
+u32 flexcard_get_packet_len(u32 header);
+
 #endif /* FLEXCARD_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (8 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver Holger Dengler
@ 2015-03-25  9:51 ` Holger Dengler
  2015-03-26  9:41   ` Daniel Lezcano
  2015-03-25  9:52 ` [PATCH 11/11] clocksource: flexcard: Support timestamp trigger selection Holger Dengler
  10 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Daniel Lezcano, Thomas Gleixner

From: Benedikt Spranger <b.spranger@linutronix.de>

The Eberspaecher Flexcard PMC II offers a Flexray network synchronized
counter with a selectable resolution of 1us, 100ns or 10ns. Add basic
support for the timestamp counter with 1us resolution, which is the
standard Flexray bus resolution.

Signed-off-by: Holger Dengler <dengler@linutronix.de>
Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
cc: Daniel Lezcano <daniel.lezcano@linaro.org>
cc: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/clocksource/Kconfig         |  11 ++
 drivers/clocksource/Makefile        |   1 +
 drivers/clocksource/flexcard-time.c | 235 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/flexcard.h        |   6 +
 4 files changed, 253 insertions(+)
 create mode 100644 drivers/clocksource/flexcard-time.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 68161f7..a6b9308 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -250,4 +250,15 @@ config CLKSRC_PXA
 	help
 	  This enables OST0 support available on PXA and SA-11x0
 	  platforms.
+
+config CLKSRC_FLEXCARD
+	tristate "Support for Flexcard clock function"
+	depends on MFD_FLEXCARD
+	select CLKSRC_MMIO
+	help
+	  This is the clocksource function driver for the
+	  Eberspaecher Flexcard PMC II carrier board. The
+	  Flexcard provide a Flexray synchronized counter
+	  configurable at 1, 10 or 100MHz.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 752d5c7..8bbc657 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= timer-integrator-ap.o
 obj-$(CONFIG_CLKSRC_VERSATILE)		+= versatile.o
 obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
 obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
+obj-$(CONFIG_CLKSRC_FLEXCARD)		+= flexcard-time.o
diff --git a/drivers/clocksource/flexcard-time.c b/drivers/clocksource/flexcard-time.c
new file mode 100644
index 0000000..f2efb53
--- /dev/null
+++ b/drivers/clocksource/flexcard-time.c
@@ -0,0 +1,235 @@
+/*
+ * Eberspaecher Flexcard PMC II - clocksource 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/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/posix-clock.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/flexcard.h>
+
+#define MAX_CLOCKS   16
+#define CLKSEL_OFF   0x10
+
+static dev_t flexcard_clk_devt;
+static struct class *flexcard_clk_class;
+
+struct flexcard_clk {
+	struct posix_clock clock;
+	dev_t devid;
+	struct device *dev;
+	void __iomem *ts64;
+	void __iomem *reset;
+};
+
+static int flexcard_clk_getres(struct posix_clock *pc, struct timespec *tp)
+{
+	tp->tv_sec = 0;
+	tp->tv_nsec = 1000;
+
+	return 0;
+}
+
+static int flexcard_clk_gettime(struct posix_clock *pc, struct timespec *tp)
+{
+	struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock);
+	u64 now;
+	u32 upper, rem;
+
+retry:
+	upper = readl(clk->ts64);
+	now = ((u64) upper << 32) | readl(clk->ts64 + 4);
+	if (upper != readl(clk->ts64))
+		goto retry;
+
+	tp->tv_sec = div_u64_rem(now, clk->desc.freq, &rem);
+	tp->tv_nsec = rem * 1000;
+
+	return 0;
+}
+
+static int flexcard_clk_settime(struct posix_clock *pc,
+				const struct timespec *tp)
+{
+	struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock);
+
+	/* The FlexCard clock could only be reset to 0 and not set */
+	if (tp->tv_sec || tp->tv_nsec)
+		return -EINVAL;
+
+	writel(FLEXCARD_RST_TS, clk->reset);
+
+	return 0;
+}
+
+static struct posix_clock_operations flexcard_clk_ops = {
+	.owner		= THIS_MODULE,
+	.clock_getres	= flexcard_clk_getres,
+	.clock_gettime	= flexcard_clk_gettime,
+	.clock_settime	= flexcard_clk_settime,
+};
+
+static int flexcard_clksrc_iomap(struct platform_device *pdev)
+{
+	struct flexcard_clk *clk = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	clk->ts64 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!clk->ts64)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -ENXIO;
+
+	clk->reset = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!clk->reset)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int flexcard_clksrc_probe(struct platform_device *pdev)
+{
+	const struct mfd_cell *cell;
+	struct flexcard_clk *clk;
+	int major, ret;
+
+	cell = mfd_get_cell(pdev);
+	if (!cell)
+		return -ENODEV;
+
+	if (cell->id >= MAX_CLOCKS) {
+		dev_err(&pdev->dev, "all flexcard posix clocks in use\n");
+		return -EBUSY;
+	}
+
+	clk = devm_kzalloc(&pdev->dev, sizeof(*clk), GFP_KERNEL);
+	if (!clk)
+		return -ENOMEM;
+
+	major = MAJOR(flexcard_clk_devt);
+	platform_set_drvdata(pdev, clk);
+
+	ret = flexcard_clksrc_iomap(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to map resources: %d\n", ret);
+		goto out;
+	}
+
+	clk->devid = MKDEV(major, cell->id);
+	clk->clock.ops = flexcard_clk_ops;
+
+	writel(FLEXCARD_CLK_1MHZ, clk->ts64 + CLKSEL_OFF);
+	writel(FLEXCARD_RST_TS, clk->reset);
+
+	clk->dev = device_create(flexcard_clk_class, &pdev->dev, clk->devid,
+				 clk, "flexcard_clk%d", cell->id);
+	if (IS_ERR(clk->dev)) {
+		ret = PTR_ERR(clk->dev);
+		goto out;
+	}
+
+	ret = posix_clock_register(&clk->clock, clk->devid);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"failed to register flexcard posix clock: %d\n", ret);
+		goto out_destroy;
+	}
+
+	dev_info(&pdev->dev, "flexcard posix clock %d registered", cell->id);
+
+	return 0;
+
+out_destroy:
+	device_destroy(flexcard_clk_class, clk->devid);
+out:
+	return ret;
+}
+
+static int flexcard_clksrc_remove(struct platform_device *pdev)
+{
+	struct flexcard_clk *clk = platform_get_drvdata(pdev);
+
+	posix_clock_unregister(&clk->clock);
+	device_destroy(flexcard_clk_class, clk->devid);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct platform_device_id flexcard_clksrc_id_table[] = {
+	{ "flexcard-clksrc", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, flexcard_clksrc_id_table);
+
+static struct platform_driver flexcard_clksrc_driver = {
+	.probe		= flexcard_clksrc_probe,
+	.remove		= flexcard_clksrc_remove,
+	.driver		= {
+		.name	= "flexcard-clksrc",
+	},
+	.id_table	= flexcard_clksrc_id_table,
+};
+
+static int __init flexcard_clksrc_init(void)
+{
+	int ret;
+
+	flexcard_clk_class = class_create(THIS_MODULE, "flexcard_clk");
+	if (IS_ERR(flexcard_clk_class)) {
+		pr_err("flexcard_clk: failed to allocate class\n");
+		return PTR_ERR(flexcard_clk_class);
+	}
+
+	ret = alloc_chrdev_region(&flexcard_clk_devt, 0, MAX_CLOCKS,
+				  "flexcard_clk");
+	if (ret < 0) {
+		pr_err("failed to allocate device region\n");
+		goto out;
+	}
+
+	ret = platform_driver_register(&flexcard_clksrc_driver);
+	if (ret < 0)
+		goto out_unregister;
+
+	return 0;
+
+out_unregister:
+	unregister_chrdev_region(flexcard_clk_devt, MAX_CLOCKS);
+out:
+	class_destroy(flexcard_clk_class);
+
+	return ret;
+}
+
+static void __exit flexcard_clksrc_exit(void)
+{
+	platform_driver_unregister(&flexcard_clksrc_driver);
+	unregister_chrdev_region(flexcard_clk_devt, MAX_CLOCKS);
+	class_destroy(flexcard_clk_class);
+}
+
+MODULE_AUTHOR("Holger Dengler <dengler@linutronix.de>");
+MODULE_AUTHOR("Benedikt Spranger <b.spranger@linutronix.de>");
+MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II clocksource driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(flexcard_clksrc_init);
+module_exit(flexcard_clksrc_exit);
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index 964d78c..d7ecf3d 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -19,8 +19,14 @@
 #define FLEXCARD_FR_OFFSET	0x4000
 #define FLEXCARD_FR_SIZE	0x2000
 
+#define FLEXCARD_RST_TS		0x8000
+
 #define FLEXCARD_MAX_NAME	16
 
+#define FLEXCARD_CLK_1MHZ	0
+#define FLEXCARD_CLK_10MHZ	1
+#define FLEXCARD_CLK_100MHZ	2
+
 struct flexcard_device {
 	raw_spinlock_t irq_lock;
 	struct pci_dev *pdev;
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 11/11] clocksource: flexcard: Support timestamp trigger selection
  2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
                   ` (9 preceding siblings ...)
  2015-03-25  9:51 ` [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support Holger Dengler
@ 2015-03-25  9:52 ` Holger Dengler
  10 siblings, 0 replies; 25+ messages in thread
From: Holger Dengler @ 2015-03-25  9:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Holger Dengler,
	Daniel Lezcano, Thomas Gleixner

From: Benedikt Spranger <b.spranger@linutronix.de>

The Flexcard timestamp counter can be triggered from two external
trigger inputs or an internal clock at 1 MHz, 10 Mhz or 100 MHz.
Add support for timestamp trigger selection.

Signed-off-by: Holger Dengler <dengler@linutronix.de>
Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
cc: Daniel Lezcano <daniel.lezcano@linaro.org>
cc: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/clocksource/flexcard-time.c | 50 ++++++++++++++++++++++++++++++++++---
 include/uapi/linux/flexcard.h       | 16 ++++++++++++
 2 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/drivers/clocksource/flexcard-time.c b/drivers/clocksource/flexcard-time.c
index f2efb53..101a989 100644
--- a/drivers/clocksource/flexcard-time.c
+++ b/drivers/clocksource/flexcard-time.c
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/flexcard.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/platform_device.h>
@@ -26,8 +27,10 @@ static dev_t flexcard_clk_devt;
 static struct class *flexcard_clk_class;
 
 struct flexcard_clk {
+	struct flexcard_clk_desc desc;
 	struct posix_clock clock;
 	dev_t devid;
+	u32 mul;
 	struct device *dev;
 	void __iomem *ts64;
 	void __iomem *reset;
@@ -35,8 +38,9 @@ struct flexcard_clk {
 
 static int flexcard_clk_getres(struct posix_clock *pc, struct timespec *tp)
 {
+	struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock);
 	tp->tv_sec = 0;
-	tp->tv_nsec = 1000;
+	tp->tv_nsec = clk->mul;
 
 	return 0;
 }
@@ -54,7 +58,7 @@ retry:
 		goto retry;
 
 	tp->tv_sec = div_u64_rem(now, clk->desc.freq, &rem);
-	tp->tv_nsec = rem * 1000;
+	tp->tv_nsec = rem * clk->mul;
 
 	return 0;
 }
@@ -73,11 +77,48 @@ static int flexcard_clk_settime(struct posix_clock *pc,
 	return 0;
 }
 
+static long flexcard_clk_ioctl(struct posix_clock *pc, unsigned int cmd,
+			       unsigned long arg)
+{
+	struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock);
+	struct flexcard_clk_desc desc;
+
+	if (copy_from_user(&desc, (void __user *)arg, sizeof(desc)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case FLEXCARD_CLK_1MHZ:
+		clk->desc.freq = 1000000;
+		break;
+	case FLEXCARD_CLK_10MHZ:
+		clk->desc.freq = 10000000;
+		break;
+	case FLEXCARD_CLK_100MHZ:
+		clk->desc.freq = 100000000;
+		break;
+	case FLEXCARD_CLK_EXT1:
+	case FLEXCARD_CLK_EXT2:
+		if (desc.freq < 1 || desc.freq > NSEC_PER_SEC)
+			return -EINVAL;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	clk->desc = desc;
+	clk->mul = NSEC_PER_SEC/desc.freq;
+	writel(clk->desc.type, clk->ts64 + CLKSEL_OFF);
+	writel(FLEXCARD_RST_TS, clk->reset);
+
+	return 0;
+}
+
 static struct posix_clock_operations flexcard_clk_ops = {
 	.owner		= THIS_MODULE,
 	.clock_getres	= flexcard_clk_getres,
 	.clock_gettime	= flexcard_clk_gettime,
 	.clock_settime	= flexcard_clk_settime,
+	.ioctl		= flexcard_clk_ioctl,
 };
 
 static int flexcard_clksrc_iomap(struct platform_device *pdev)
@@ -134,8 +175,11 @@ static int flexcard_clksrc_probe(struct platform_device *pdev)
 
 	clk->devid = MKDEV(major, cell->id);
 	clk->clock.ops = flexcard_clk_ops;
+	clk->desc.type = FLEXCARD_CLK_1MHZ;
+	clk->desc.freq = 1000000;
+	clk->mul = 1000;
 
-	writel(FLEXCARD_CLK_1MHZ, clk->ts64 + CLKSEL_OFF);
+	writel(clk->desc.type, clk->ts64 + CLKSEL_OFF);
 	writel(FLEXCARD_RST_TS, clk->reset);
 
 	clk->dev = device_create(flexcard_clk_class, &pdev->dev, clk->devid,
diff --git a/include/uapi/linux/flexcard.h b/include/uapi/linux/flexcard.h
index 9b73d8d..7939d94 100644
--- a/include/uapi/linux/flexcard.h
+++ b/include/uapi/linux/flexcard.h
@@ -15,6 +15,22 @@
 
 #include <linux/types.h>
 
+enum flexcard_clk_type {
+	FLEXCARD_CLK_1MHZ = 0x0,
+	FLEXCARD_CLK_10MHZ = 0x1,
+	FLEXCARD_CLK_100MHZ = 0x2,
+	FLEXCARD_CLK_EXT1 = 0x11,
+	FLEXCARD_CLK_EXT2 = 0x12,
+};
+
+struct flexcard_clk_desc {
+	enum flexcard_clk_type type;
+	__u32 freq;
+};
+
+#define FCGCLKSRC       _IOR(0xeb, 0, struct flexcard_clk_desc)
+#define FCSCLKSRC       _IOW(0xeb, 1, struct flexcard_clk_desc)
+
 struct fc_version {
 	__u8	dev;
 	__u8	min;
-- 
2.1.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support
  2015-03-25  9:51 ` [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support Holger Dengler
@ 2015-03-26  9:41   ` Daniel Lezcano
  2015-03-26 11:01     ` Holger Dengler
  0 siblings, 1 reply; 25+ messages in thread
From: Daniel Lezcano @ 2015-03-26  9:41 UTC (permalink / raw)
  To: Holger Dengler, linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Thomas Gleixner,
	John Stultz


Hi Holger,

[Cc'ed John Stultz]

On 03/25/2015 10:51 AM, Holger Dengler wrote:
> From: Benedikt Spranger <b.spranger@linutronix.de>
>
> The Eberspaecher Flexcard PMC II offers a Flexray network synchronized
> counter with a selectable resolution of 1us, 100ns or 10ns. Add basic
> support for the timestamp counter with 1us resolution, which is the
> standard Flexray bus resolution.
>
> Signed-off-by: Holger Dengler <dengler@linutronix.de>
> Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
> cc: Daniel Lezcano <daniel.lezcano@linaro.org>
> cc: Thomas Gleixner <tglx@linutronix.de>
> ---
>   drivers/clocksource/Kconfig         |  11 ++
>   drivers/clocksource/Makefile        |   1 +
>   drivers/clocksource/flexcard-time.c | 235 ++++++++++++++++++++++++++++++++++++
>   include/linux/mfd/flexcard.h        |   6 +
>   4 files changed, 253 insertions(+)
>   create mode 100644 drivers/clocksource/flexcard-time.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 68161f7..a6b9308 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -250,4 +250,15 @@ config CLKSRC_PXA
>   	help
>   	  This enables OST0 support available on PXA and SA-11x0
>   	  platforms.
> +
> +config CLKSRC_FLEXCARD
> +	tristate "Support for Flexcard clock function"

Why do you need this to be a module ?

The Kconfig policy is to have it selected by the arch Kconfig.

It should be like:

config CLKSRC_FLEXCARD
	bool
	select CLKSRC_MMIO

and then the Kconfig for MFD_FLEXCARD selects CLKSRC_FLEXCARD.

> +	depends on MFD_FLEXCARD
> +	select CLKSRC_MMIO
> +	help
> +	  This is the clocksource function driver for the
> +	  Eberspaecher Flexcard PMC II carrier board. The
> +	  Flexcard provide a Flexray synchronized counter
> +	  configurable at 1, 10 or 100MHz.
> +
>   endmenu
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 752d5c7..8bbc657 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -51,3 +51,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= timer-integrator-ap.o
>   obj-$(CONFIG_CLKSRC_VERSATILE)		+= versatile.o
>   obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
>   obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
> +obj-$(CONFIG_CLKSRC_FLEXCARD)		+= flexcard-time.o
> diff --git a/drivers/clocksource/flexcard-time.c b/drivers/clocksource/flexcard-time.c
> new file mode 100644
> index 0000000..f2efb53
> --- /dev/null
> +++ b/drivers/clocksource/flexcard-time.c
> @@ -0,0 +1,235 @@
> +/*
> + * Eberspaecher Flexcard PMC II - clocksource 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/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/platform_device.h>
> +#include <linux/posix-clock.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/flexcard.h>
> +
> +#define MAX_CLOCKS   16
> +#define CLKSEL_OFF   0x10
> +
> +static dev_t flexcard_clk_devt;
> +static struct class *flexcard_clk_class;
> +
> +struct flexcard_clk {
> +	struct posix_clock clock;
> +	dev_t devid;
> +	struct device *dev;
> +	void __iomem *ts64;
> +	void __iomem *reset;
> +};
> +
> +static int flexcard_clk_getres(struct posix_clock *pc, struct timespec *tp)
> +{
> +	tp->tv_sec = 0;
> +	tp->tv_nsec = 1000;
> +
> +	return 0;
> +}
> +
> +static int flexcard_clk_gettime(struct posix_clock *pc, struct timespec *tp)
> +{
> +	struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock);
> +	u64 now;
> +	u32 upper, rem;
> +
> +retry:
> +	upper = readl(clk->ts64);
> +	now = ((u64) upper << 32) | readl(clk->ts64 + 4);
> +	if (upper != readl(clk->ts64))
> +		goto retry;
> +
> +	tp->tv_sec = div_u64_rem(now, clk->desc.freq, &rem);
> +	tp->tv_nsec = rem * 1000;
> +
> +	return 0;
> +}
> +
> +static int flexcard_clk_settime(struct posix_clock *pc,
> +				const struct timespec *tp)
> +{
> +	struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock);
> +
> +	/* The FlexCard clock could only be reset to 0 and not set */
> +	if (tp->tv_sec || tp->tv_nsec)
> +		return -EINVAL;
> +
> +	writel(FLEXCARD_RST_TS, clk->reset);
> +
> +	return 0;
> +}
> +
> +static struct posix_clock_operations flexcard_clk_ops = {
> +	.owner		= THIS_MODULE,
> +	.clock_getres	= flexcard_clk_getres,
> +	.clock_gettime	= flexcard_clk_gettime,
> +	.clock_settime	= flexcard_clk_settime,
> +};
> +
> +static int flexcard_clksrc_iomap(struct platform_device *pdev)
> +{
> +	struct flexcard_clk *clk = platform_get_drvdata(pdev);
> +	struct resource *res;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENXIO;
> +
> +	clk->ts64 = devm_ioremap(&pdev->dev, res->start, resource_size(res));
> +	if (!clk->ts64)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!res)
> +		return -ENXIO;
> +
> +	clk->reset = devm_ioremap(&pdev->dev, res->start, resource_size(res));
> +	if (!clk->reset)
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +static int flexcard_clksrc_probe(struct platform_device *pdev)
> +{
> +	const struct mfd_cell *cell;
> +	struct flexcard_clk *clk;
> +	int major, ret;
> +
> +	cell = mfd_get_cell(pdev);
> +	if (!cell)
> +		return -ENODEV;
> +
> +	if (cell->id >= MAX_CLOCKS) {
> +		dev_err(&pdev->dev, "all flexcard posix clocks in use\n");
> +		return -EBUSY;
> +	}
> +
> +	clk = devm_kzalloc(&pdev->dev, sizeof(*clk), GFP_KERNEL);
> +	if (!clk)
> +		return -ENOMEM;
> +
> +	major = MAJOR(flexcard_clk_devt);
> +	platform_set_drvdata(pdev, clk);
> +
> +	ret = flexcard_clksrc_iomap(pdev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to map resources: %d\n", ret);
> +		goto out;
> +	}
> +
> +	clk->devid = MKDEV(major, cell->id);
> +	clk->clock.ops = flexcard_clk_ops;
> +
> +	writel(FLEXCARD_CLK_1MHZ, clk->ts64 + CLKSEL_OFF);
> +	writel(FLEXCARD_RST_TS, clk->reset);
> +
> +	clk->dev = device_create(flexcard_clk_class, &pdev->dev, clk->devid,
> +				 clk, "flexcard_clk%d", cell->id);
> +	if (IS_ERR(clk->dev)) {
> +		ret = PTR_ERR(clk->dev);
> +		goto out;
> +	}
> +
> +	ret = posix_clock_register(&clk->clock, clk->devid);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"failed to register flexcard posix clock: %d\n", ret);
> +		goto out_destroy;
> +	}
> +
> +	dev_info(&pdev->dev, "flexcard posix clock %d registered", cell->id);
> +
> +	return 0;
> +
> +out_destroy:
> +	device_destroy(flexcard_clk_class, clk->devid);
> +out:
> +	return ret;
> +}
> +
> +static int flexcard_clksrc_remove(struct platform_device *pdev)
> +{
> +	struct flexcard_clk *clk = platform_get_drvdata(pdev);
> +
> +	posix_clock_unregister(&clk->clock);
> +	device_destroy(flexcard_clk_class, clk->devid);
> +	platform_set_drvdata(pdev, NULL);
> +
> +	return 0;
> +}
> +
> +static const struct platform_device_id flexcard_clksrc_id_table[] = {
> +	{ "flexcard-clksrc", 0 },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(platform, flexcard_clksrc_id_table);
> +
> +static struct platform_driver flexcard_clksrc_driver = {
> +	.probe		= flexcard_clksrc_probe,
> +	.remove		= flexcard_clksrc_remove,
> +	.driver		= {
> +		.name	= "flexcard-clksrc",
> +	},
> +	.id_table	= flexcard_clksrc_id_table,
> +};
> +
> +static int __init flexcard_clksrc_init(void)
> +{
> +	int ret;
> +
> +	flexcard_clk_class = class_create(THIS_MODULE, "flexcard_clk");
> +	if (IS_ERR(flexcard_clk_class)) {
> +		pr_err("flexcard_clk: failed to allocate class\n");
> +		return PTR_ERR(flexcard_clk_class);
> +	}
> +
> +	ret = alloc_chrdev_region(&flexcard_clk_devt, 0, MAX_CLOCKS,
> +				  "flexcard_clk");
> +	if (ret < 0) {
> +		pr_err("failed to allocate device region\n");
> +		goto out;
> +	}
> +
> +	ret = platform_driver_register(&flexcard_clksrc_driver);
> +	if (ret < 0)
> +		goto out_unregister;
> +
> +	return 0;
> +
> +out_unregister:
> +	unregister_chrdev_region(flexcard_clk_devt, MAX_CLOCKS);
> +out:
> +	class_destroy(flexcard_clk_class);
> +
> +	return ret;
> +}
> +
> +static void __exit flexcard_clksrc_exit(void)
> +{
> +	platform_driver_unregister(&flexcard_clksrc_driver);
> +	unregister_chrdev_region(flexcard_clk_devt, MAX_CLOCKS);
> +	class_destroy(flexcard_clk_class);
> +}
> +
> +MODULE_AUTHOR("Holger Dengler <dengler@linutronix.de>");
> +MODULE_AUTHOR("Benedikt Spranger <b.spranger@linutronix.de>");
> +MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II clocksource driver");
> +MODULE_LICENSE("GPL v2");
> +
> +module_init(flexcard_clksrc_init);
> +module_exit(flexcard_clksrc_exit);
> diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
> index 964d78c..d7ecf3d 100644
> --- a/include/linux/mfd/flexcard.h
> +++ b/include/linux/mfd/flexcard.h
> @@ -19,8 +19,14 @@
>   #define FLEXCARD_FR_OFFSET	0x4000
>   #define FLEXCARD_FR_SIZE	0x2000
>
> +#define FLEXCARD_RST_TS		0x8000
> +
>   #define FLEXCARD_MAX_NAME	16
>
> +#define FLEXCARD_CLK_1MHZ	0
> +#define FLEXCARD_CLK_10MHZ	1
> +#define FLEXCARD_CLK_100MHZ	2
> +
>   struct flexcard_device {
>   	raw_spinlock_t irq_lock;
>   	struct pci_dev *pdev;
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support
  2015-03-26  9:41   ` Daniel Lezcano
@ 2015-03-26 11:01     ` Holger Dengler
  2015-03-26 16:34       ` John Stultz
  0 siblings, 1 reply; 25+ messages in thread
From: Holger Dengler @ 2015-03-26 11:01 UTC (permalink / raw)
  To: Daniel Lezcano, linux-kernel
  Cc: Peter Mahler, Juergen Bubeck, Benedikt Spranger, Thomas Gleixner,
	John Stultz

Hi Daniel,

On 03/26/2015 10:41 AM, Daniel Lezcano wrote:
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 68161f7..a6b9308 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -250,4 +250,15 @@ config CLKSRC_PXA
>>       help
>>         This enables OST0 support available on PXA and SA-11x0
>>         platforms.
>> +
>> +config CLKSRC_FLEXCARD
>> +    tristate "Support for Flexcard clock function"
> 
> Why do you need this to be a module ?
> 
> The Kconfig policy is to have it selected by the arch Kconfig.
> 
> It should be like:
> 
> config CLKSRC_FLEXCARD
>     bool
>     select CLKSRC_MMIO

The Flexcard PMC II, which provides this clocksrc functionality, is a
PCI card. According to the PMC specs, this card-type is hot-plugable. So
this clocksrc is not SoC-related, it's also hot-plugable.
Therefore a module-capable driver seems a good solution for me.

> 
> and then the Kconfig for MFD_FLEXCARD selects CLKSRC_FLEXCARD.
> 

Ok, this could be an option to enable the clocksrc feature by default,
if MFD_FLEXCARD is selected.

>> +    depends on MFD_FLEXCARD
>> +    select CLKSRC_MMIO
>> +    help
>> +      This is the clocksource function driver for the
>> +      Eberspaecher Flexcard PMC II carrier board. The
>> +      Flexcard provide a Flexray synchronized counter
>> +      configurable at 1, 10 or 100MHz.
>> +
>>   endmenu

-- 
Kind regards,
Holger Dengler

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support
  2015-03-26 11:01     ` Holger Dengler
@ 2015-03-26 16:34       ` John Stultz
  2015-03-27 12:27         ` Holger Dengler
  0 siblings, 1 reply; 25+ messages in thread
From: John Stultz @ 2015-03-26 16:34 UTC (permalink / raw)
  To: Holger Dengler
  Cc: Daniel Lezcano, lkml, Peter Mahler, Juergen Bubeck,
	Benedikt Spranger, Thomas Gleixner

On Thu, Mar 26, 2015 at 4:01 AM, Holger Dengler <dengler@linutronix.de> wrote:
> On 03/26/2015 10:41 AM, Daniel Lezcano wrote:
>>
>> config CLKSRC_FLEXCARD
>>     bool
>>     select CLKSRC_MMIO
>
> The Flexcard PMC II, which provides this clocksrc functionality, is a
> PCI card. According to the PMC specs, this card-type is hot-plugable. So
> this clocksrc is not SoC-related, it's also hot-plugable.
> Therefore a module-capable driver seems a good solution for me.
>
>>
>> and then the Kconfig for MFD_FLEXCARD selects CLKSRC_FLEXCARD.
>>
>
> Ok, this could be an option to enable the clocksrc feature by default,
> if MFD_FLEXCARD is selected.

Yea, I think this would be preferred. If the user already selects
something to get device functionality, lets not make them search
around in other menus to find another config option to enable all the
capabilities.

thanks
-john

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support
  2015-03-26 16:34       ` John Stultz
@ 2015-03-27 12:27         ` Holger Dengler
  0 siblings, 0 replies; 25+ messages in thread
From: Holger Dengler @ 2015-03-27 12:27 UTC (permalink / raw)
  To: John Stultz
  Cc: Daniel Lezcano, lkml, Peter Mahler, Juergen Bubeck,
	Benedikt Spranger, Thomas Gleixner

Hi John,

On 03/26/2015 05:34 PM, John Stultz wrote:
> On Thu, Mar 26, 2015 at 4:01 AM, Holger Dengler <dengler@linutronix.de> wrote:
>> On 03/26/2015 10:41 AM, Daniel Lezcano wrote:
>>>
>>> config CLKSRC_FLEXCARD
>>>     bool
>>>     select CLKSRC_MMIO
>>
>> The Flexcard PMC II, which provides this clocksrc functionality, is a
>> PCI card. According to the PMC specs, this card-type is hot-plugable. So
>> this clocksrc is not SoC-related, it's also hot-plugable.
>> Therefore a module-capable driver seems a good solution for me.
>>
>>>
>>> and then the Kconfig for MFD_FLEXCARD selects CLKSRC_FLEXCARD.
>>>
>>
>> Ok, this could be an option to enable the clocksrc feature by default,
>> if MFD_FLEXCARD is selected.
> 
> Yea, I think this would be preferred. If the user already selects
> something to get device functionality, lets not make them search
> around in other menus to find another config option to enable all the
> capabilities.

We integrated the "MFD_FLEXCARD selects CLKSRC_FLEXCARD". If we get some
responces as well for the other parts of this patchset, we'll resend it
with the modifications.

> 
> thanks
> -john
> 

Kind regards,
Holger Dengler
--
phone: +49 7556 45 218 94; fax: +49 7556 91 98 86

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support
  2015-03-25  9:51 ` [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support Holger Dengler
@ 2015-03-30  7:57   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  7:57 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz



> 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>

When you're providing a patch-set such as this, where all of the
patches spread across the various subsystems are related, it's better
to just send the whole thing to everyone.  Adding maintainers in this
way means that some of us are now missing come context.  More
importantly I'm missing [PATCH 00/11].

After looking the cover-letter up on the interweb, I notice this:

"According to the comments regarding our last posting, the MFD driver
patchset has been split up into separate functional parts."

Where did your last posting go?  I can't seem to look it up, either on
the MLs or via Google.  Who asked you to split up the MFD patches?  Do
you have a link to any previous conversation surrounding this set?

> ---
>  drivers/mfd/Kconfig           |  10 +++
>  drivers/mfd/Makefile          |   2 +
>  drivers/mfd/flexcard/Makefile |   2 +

This is worrying.  What makes flexcard special enough to require a
directory?  There are currently no other directories in drivers/mfd.

>  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/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

Full email addresses of the authors please.

> + * 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>

Alphabetical.

> +static const char drv_name[] = "flexcard";

I've never really liked these.  Just use "flexcard" where required.

[...]

> +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;

You need to make this more easily/instantly readable.  Insert a
comment explaining what's happening and consider renaming the local
variable to something more friendly/explanatory.

[...]

> 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

Are these used anywhere else except core.c?  If not, please move them
into there.  Same with any other variable/struct/define which is used
in only a single file.

> +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 */

[...]

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/11] mfd: flexcard: add flexcard core device
  2015-03-25  9:51 ` [PATCH 02/11] mfd: flexcard: add flexcard core device Holger Dengler
@ 2015-03-30  8:06   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:06 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> The Flexcard PCI BAR0 contain registers for configuration but also
> for informational purpose like error counter, statistical information
> and some timestamps. The read-only mmap of the misc device offers the
> userspace a fast access to these registers.

This code looks like it belongs in drivers/misc.

</review>

> 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/flexcard/core.c  | 107 ++++++++++++++++++++++++++++++++++++++++++-
>  include/linux/mfd/flexcard.h |   6 +++
>  include/uapi/linux/Kbuild    |   1 +
>  3 files changed, 112 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
> index 99df3d5..1e7fb0f 100644
> --- a/drivers/mfd/flexcard/core.c
> +++ b/drivers/mfd/flexcard/core.c
> @@ -14,11 +14,16 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/flexcard.h>
> +#include <linux/fs.h>
> +#include <linux/kref.h>
> +#include <linux/miscdevice.h>
>  #include <linux/pci.h>
>  #include <linux/platform_device.h>
>  #include <linux/mfd/core.h>
>  #include <linux/mfd/flexcard.h>
>  
> +static DEFINE_IDA(flexcard_ida);
> +
>  static const char drv_name[] = "flexcard";
>  
>  static int flexcard_tiny_can(struct flexcard_device *priv,
> @@ -104,23 +109,106 @@ static int flexcard_tiny_probe(struct flexcard_device *priv)
>  	return mfd_add_devices(&pdev->dev, 0, priv->cells, nr, NULL, 0, NULL);
>  }
>  
> +static int flexcard_misc_open(struct inode *inode, struct file *filp)
> +{
> +	struct flexcard_device *priv =
> +		container_of(filp->private_data, struct flexcard_device, dev);
> +	int ret;
> +
> +	filp->private_data = priv;
> +	ret = nonseekable_open(inode, filp);
> +	if (ret) {
> +		dev_err(&priv->pdev->dev, "unable to open file: %d\n", ret);
> +		return ret;
> +	}
> +
> +	kref_get(&priv->ref);
> +	return 0;
> +}
> +
> +static void flexcard_dev_release(struct kref *ref)
> +{
> +	struct flexcard_device *priv =
> +		container_of(ref, struct flexcard_device, ref);
> +
> +	kfree(priv);
> +	dev_info(&priv->pdev->dev, "misc device release");
> +}
> +
> +static int flexcard_misc_release(struct inode *inode, struct file *filp)
> +{
> +	struct flexcard_device *priv = filp->private_data;
> +
> +	filp->private_data = NULL;
> +	kref_put(&priv->ref, flexcard_dev_release);
> +
> +	return 0;
> +}
> +
> +static int flexcard_misc_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +	struct flexcard_device *priv = filp->private_data;
> +	unsigned long offset, vsize, psize, addr;
> +
> +	if (vma->vm_flags & (VM_WRITE | VM_EXEC))
> +		return -EPERM;
> +
> +	offset = vma->vm_pgoff << PAGE_SHIFT;
> +	vsize = vma->vm_end - vma->vm_start;
> +	psize = pci_resource_len(priv->pdev, 0) - offset;
> +	addr = (pci_resource_start(priv->pdev, 0) + offset) >> PAGE_SHIFT;
> +
> +	if (vsize > psize) {
> +		dev_err(&priv->pdev->dev,
> +			"requested mmap mapping too large\n");
> +		return -EINVAL;
> +	}
> +
> +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> +
> +	return io_remap_pfn_range(vma, vma->vm_start, addr, vsize,
> +				  vma->vm_page_prot);
> +}
> +
> +static const struct file_operations flexcard_misc_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= flexcard_misc_open,
> +	.release	= flexcard_misc_release,
> +	.mmap		= flexcard_misc_mmap,
> +	.llseek		= no_llseek,
> +};
> +
>  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);
> +	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>  	if (!priv)
>  		return -ENOMEM;
>  
> +	ret = ida_simple_get(&flexcard_ida, 0, 0, GFP_KERNEL);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "could not get new Flexcard id:%d\n", ret);
> +		goto out_free;
> +	}
> +
> +	priv->cardnr = ret;
>  	pci_set_drvdata(pdev, priv);
>  	priv->pdev = pdev;
> +	kref_init(&priv->ref);
> +
> +	snprintf(priv->name, sizeof(priv->name), "flexcard%d", priv->cardnr);
> +	priv->dev.minor = MISC_DYNAMIC_MINOR;
> +	priv->dev.name = priv->name;
> +	priv->dev.fops = &flexcard_misc_fops;
> +	priv->dev.parent = &pdev->dev;
>  
>  	ret = pci_enable_device(pdev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "unable to enable device: %d\n", ret);
> -		return ret;
> +		goto out_put;
>  	}
>  
>  	pci_set_master(pdev);
> @@ -143,6 +231,12 @@ static int flexcard_probe(struct pci_dev *pdev,
>  		goto out_unmap;
>  	}
>  
> +	ret = misc_register(&priv->dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
> +		goto out_remove;
> +	}
> +
>  	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,
> @@ -150,12 +244,18 @@ static int flexcard_probe(struct pci_dev *pdev,
>  
>  	return 0;
>  
> +out_remove:
> +	mfd_remove_devices(&pdev->dev);
>  out_unmap:
>  	iounmap(priv->conf);
>  out_release:
>  	pci_release_regions(pdev);
>  out_disable:
>  	pci_disable_device(pdev);
> +out_put:
> +	ida_simple_remove(&flexcard_ida, priv->cardnr);
> +out_free:
> +	kref_put(&priv->ref, flexcard_dev_release);
>  
>  	return ret;
>  }
> @@ -164,10 +264,13 @@ static void flexcard_remove(struct pci_dev *pdev)
>  {
>  	struct flexcard_device *priv = pci_get_drvdata(pdev);
>  
> +	misc_deregister(&priv->dev);
>  	mfd_remove_devices(&pdev->dev);
>  	iounmap(priv->conf);
>  	pci_release_regions(pdev);
>  	pci_disable_device(pdev);
> +	ida_simple_remove(&flexcard_ida, priv->cardnr);
> +	kref_put(&priv->ref, flexcard_dev_release);
>  }
>  
>  #define PCI_VENDOR_ID_EBEL	0x1974
> diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
> index 20d0f40..84e155c 100644
> --- a/include/linux/mfd/flexcard.h
> +++ b/include/linux/mfd/flexcard.h
> @@ -19,11 +19,17 @@
>  #define FLEXCARD_FR_OFFSET	0x4000
>  #define FLEXCARD_FR_SIZE	0x2000
>  
> +#define FLEXCARD_MAX_NAME	16
> +
>  struct flexcard_device {
>  	struct pci_dev *pdev;
>  	struct fc_conf_bar __iomem *conf;
>  	struct mfd_cell *cells;
>  	struct resource *res;
> +	struct miscdevice dev;
> +	struct kref ref;
> +	int cardnr;
> +	char name[FLEXCARD_MAX_NAME];
>  };
>  
>  enum flexcard_cell_id {
> diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
> index 68ceb97..d5c5002 100644
> --- a/include/uapi/linux/Kbuild
> +++ b/include/uapi/linux/Kbuild
> @@ -127,6 +127,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

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 03/11] mfd: flexcard: add device attributes
  2015-03-25  9:51 ` [PATCH 03/11] mfd: flexcard: add device attributes Holger Dengler
@ 2015-03-30  8:15   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:15 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> Add device attributes for common flexcard information access. The
> attribiutes are read-only execpt "uid" (user ID register).
> The "uid" attribute can also be used to change the user-defined ID of a
> Flexcard.
> 
> 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/flexcard/Makefile   |   2 +-
>  drivers/mfd/flexcard/attr.c     | 215 ++++++++++++++++++++++++++++++++++++++++
>  drivers/mfd/flexcard/core.c     |  11 ++

I suggest this too should be part of the 'misc' driver and I wouldn't
split out attr fn()s into a separate file.

</review>

>  drivers/mfd/flexcard/flexcard.h |   7 ++
>  4 files changed, 234 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/mfd/flexcard/attr.c
>  create mode 100644 drivers/mfd/flexcard/flexcard.h
> 
> diff --git a/drivers/mfd/flexcard/Makefile b/drivers/mfd/flexcard/Makefile
> index 6606ebb..101000f 100644
> --- a/drivers/mfd/flexcard/Makefile
> +++ b/drivers/mfd/flexcard/Makefile
> @@ -1,2 +1,2 @@
>  obj-$(CONFIG_MFD_FLEXCARD)	+= flexcard.o
> -flexcard-objs			:= core.o
> +flexcard-objs			:= core.o attr.o
> diff --git a/drivers/mfd/flexcard/attr.c b/drivers/mfd/flexcard/attr.c
> new file mode 100644
> index 0000000..c91c884
> --- /dev/null
> +++ b/drivers/mfd/flexcard/attr.c
> @@ -0,0 +1,215 @@
> +/*
> + * 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.
> + */
> +#include <linux/device.h>
> +#include <linux/flexcard.h>
> +#include <linux/kref.h>
> +#include <linux/miscdevice.h>
> +#include <linux/pci.h>
> +#include <linux/mfd/flexcard.h>
> +
> +static ssize_t fw_version_show(struct device *dev,
> +			       struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%02x.%02x.%02x\n", priv->conf->fc_fw_ver.maj,
> +		       priv->conf->fc_fw_ver.min, priv->conf->fc_fw_ver.dev);
> +}
> +static DEVICE_ATTR_RO(fw_version);
> +
> +static ssize_t hw_version_show(struct device *dev,
> +			       struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%02x.%02x.%02x\n", priv->conf->fc_hw_ver.maj,
> +		       priv->conf->fc_hw_ver.min, priv->conf->fc_hw_ver.dev);
> +}
> +static DEVICE_ATTR_RO(hw_version);
> +
> +static ssize_t serialno_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%lld\n", priv->conf->fc_sn);
> +}
> +static DEVICE_ATTR_RO(serialno);
> +
> +static ssize_t tiny_stat_show(struct device *dev,
> +			      struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "0x%x\n", priv->conf->tiny_stat);
> +}
> +static DEVICE_ATTR_RO(tiny_stat);
> +
> +static ssize_t can_dat_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->can_dat_cnt);
> +}
> +static DEVICE_ATTR_RO(can_dat);
> +
> +static ssize_t can_err_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->can_err_cnt);
> +}
> +static DEVICE_ATTR_RO(can_err);
> +
> +static ssize_t fc_data_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->fc_data_cnt);
> +}
> +static DEVICE_ATTR_RO(fc_data);
> +
> +static ssize_t fr_rx_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->fr_rx_cnt);
> +}
> +static DEVICE_ATTR_RO(fr_rx);
> +
> +static ssize_t fr_tx_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->fr_tx_cnt);
> +}
> +static DEVICE_ATTR_RO(fr_tx);
> +
> +static ssize_t nmv_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->nmv_cnt);
> +}
> +static DEVICE_ATTR_RO(nmv);
> +
> +static ssize_t info_show(struct device *dev,
> +			 struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->info_cnt);
> +}
> +static DEVICE_ATTR_RO(info);
> +
> +static ssize_t stat_trg_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->stat_trg_cnt);
> +}
> +static DEVICE_ATTR_RO(stat_trg);
> +
> +static ssize_t nf_show(struct device *dev,
> +		       struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%d\n", priv->conf->nf_cnt);
> +}
> +static DEVICE_ATTR_RO(nf);
> +
> +static ssize_t uid_store(struct device *dev, struct device_attribute *attr,
> +			 const char *buf, size_t count)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +	unsigned long uid;
> +	int ret;
> +
> +	ret = kstrtou32(buf, 0, &uid);
> +	if (ret)
> +		return ret;
> +
> +	priv->conf->fc_uid = uid;
> +	return count;
> +}
> +
> +static ssize_t uid_show(struct device *dev,
> +			struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev->parent);
> +	struct flexcard_device *priv = pci_get_drvdata(pdev);
> +
> +	return sprintf(buf, "%u\n", priv->conf->fc_uid);
> +}
> +static DEVICE_ATTR(uid, S_IRUGO|S_IWUSR, uid_show, uid_store);
> +
> +static struct attribute *flexcard_misc_dev_attrs[] = {
> +	&dev_attr_fw_version.attr,
> +	&dev_attr_hw_version.attr,
> +	&dev_attr_serialno.attr,
> +	&dev_attr_tiny_stat.attr,
> +	&dev_attr_can_dat.attr,
> +	&dev_attr_can_err.attr,
> +	&dev_attr_fc_data.attr,
> +	&dev_attr_fr_rx.attr,
> +	&dev_attr_fr_tx.attr,
> +	&dev_attr_nmv.attr,
> +	&dev_attr_info.attr,
> +	&dev_attr_stat_trg.attr,
> +	&dev_attr_nf.attr,
> +	&dev_attr_uid.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group flexcard_misc_dev_group = {
> +	.attrs = flexcard_misc_dev_attrs,
> +};
> +
> +int flexcard_misc_add_attrs(struct device *dev)
> +{
> +	int ret;
> +
> +	ret = sysfs_create_group(&dev->kobj,
> +				 &flexcard_misc_dev_group);
> +
> +	if (ret)
> +		dev_err(dev, "failed to create sysfs attributes: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +void flexcard_misc_del_attrs(struct device *dev)
> +{
> +	sysfs_remove_group(&dev->kobj, &flexcard_misc_dev_group);
> +}
> diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
> index 1e7fb0f..6477019 100644
> --- a/drivers/mfd/flexcard/core.c
> +++ b/drivers/mfd/flexcard/core.c
> @@ -22,6 +22,8 @@
>  #include <linux/mfd/core.h>
>  #include <linux/mfd/flexcard.h>
>  
> +#include "flexcard.h"
> +
>  static DEFINE_IDA(flexcard_ida);
>  
>  static const char drv_name[] = "flexcard";
> @@ -237,6 +239,12 @@ static int flexcard_probe(struct pci_dev *pdev,
>  		goto out_remove;
>  	}
>  
> +	ret = flexcard_misc_add_attrs(priv->dev.this_device);
> +	if (ret) {
> +		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
> +		goto out_deregister;
> +	}
> +
>  	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,
> @@ -244,6 +252,8 @@ static int flexcard_probe(struct pci_dev *pdev,
>  
>  	return 0;
>  
> +out_deregister:
> +	misc_deregister(&priv->dev);
>  out_remove:
>  	mfd_remove_devices(&pdev->dev);
>  out_unmap:
> @@ -264,6 +274,7 @@ static void flexcard_remove(struct pci_dev *pdev)
>  {
>  	struct flexcard_device *priv = pci_get_drvdata(pdev);
>  
> +	flexcard_misc_del_attrs(priv->dev.this_device);
>  	misc_deregister(&priv->dev);
>  	mfd_remove_devices(&pdev->dev);
>  	iounmap(priv->conf);
> diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
> new file mode 100644
> index 0000000..1fe451e
> --- /dev/null
> +++ b/drivers/mfd/flexcard/flexcard.h
> @@ -0,0 +1,7 @@
> +#ifndef __FLEXCARD_H
> +#define  __FLEXCARD_H
> +
> +int flexcard_misc_add_attrs(struct device *dev);
> +void flexcard_misc_del_attrs(struct device *dev);
> +
> +#endif /* __FLEXCARD_H */

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 04/11] mfd: flexcard: add clocksrc device
  2015-03-25  9:51 ` [PATCH 04/11] mfd: flexcard: add clocksrc device Holger Dengler
@ 2015-03-30  8:30   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:30 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> The Flexcard offers a Flexray network synchronized counter with a
> selectable resolution of 1us, 100ns or 10ns. Add an appropriate MFD-cell
> to use the counter.
> 
> 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/flexcard/core.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
> index 6477019..c73ae5c 100644
> --- a/drivers/mfd/flexcard/core.c
> +++ b/drivers/mfd/flexcard/core.c
> @@ -28,6 +28,29 @@ static DEFINE_IDA(flexcard_ida);
>  
>  static const char drv_name[] = "flexcard";
>  
> +static struct resource flexcard_clk_res[] = {
> +	{
> +		.name   = "flexcard-clksrc",
> +		.start  = 0x700,

We normally define these with a friendly name.

> +		.end    = 0x713,

Then use "NEW_DEFINE + 0x13" here.

> +		.flags  = IORESOURCE_MEM,
> +	}, {
> +		.name   = "flexcard-reset",
> +		.start  = 0x144,
> +		.end    = 0x147,
> +		.flags  = IORESOURCE_MEM,
> +	},
> +};
> +
> +static struct mfd_cell flexcard_clk_dev[] = {
> +	{
> +		.id = 0,

You define this here.

> +		.name = "flexcard-clksrc",
> +		.num_resources = ARRAY_SIZE(flexcard_clk_res),
> +		.resources = flexcard_clk_res,
> +	},
> +};
> +

[...]

> +static int flexcard_clk_setup(struct flexcard_device *priv)
> +{
> +	struct pci_dev *pdev = priv->pdev;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(flexcard_clk_res); i++)
> +		flexcard_clk_res[i].parent = &pdev->resource[0];

You're already providing &pdev->resource[0] as the (5th) 'mem_base'
parameter of mfd_add_devices() where the core will populate .parent
for you.  No need to also hand-roll it here.

> +	flexcard_clk_dev[0].id = priv->cardnr;

Then override it here?

> +	return mfd_add_devices(&pdev->dev, 0, flexcard_clk_dev,
> +			       ARRAY_SIZE(flexcard_clk_dev),
> +			       &pdev->resource[0], 0, NULL);

Why do you have to register the clock as a seperate mfd_add_devices()
call?  How many MFD core devices are on this h/w?

> +}
> +
>  static int flexcard_misc_open(struct inode *inode, struct file *filp)
>  {
>  	struct flexcard_device *priv =
> @@ -233,6 +271,12 @@ static int flexcard_probe(struct pci_dev *pdev,
>  		goto out_unmap;
>  	}
>  
> +	ret = flexcard_clk_setup(priv);
> +	if (ret) {
> +		dev_err(&pdev->dev, "unable to register clksrc: %d\n", ret);
> +		goto out_remove;
> +	}
> +
>  	ret = misc_register(&priv->dev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 05/11] mfd: flexcard: add interrupt support
  2015-03-25  9:51 ` [PATCH 05/11] mfd: flexcard: add interrupt support Holger Dengler
@ 2015-03-30  8:46   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:46 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> The Flexcard comprise an interrupt controller for the attached
> tinys, timer, a Flexray related trigger and a second one for DMA.
> Both controllers share a single IRQ line.
> 
> Add an interrupt domain for the non-DMA interrupts.
> 
> 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             |   1 +
>  drivers/mfd/flexcard/Makefile   |   2 +-
>  drivers/mfd/flexcard/core.c     |  14 +++-
>  drivers/mfd/flexcard/flexcard.h |   2 +
>  drivers/mfd/flexcard/irq.c      | 167 ++++++++++++++++++++++++++++++++++++++++
>  drivers/mfd/flexcard/irq.h      |  50 ++++++++++++
>  include/linux/mfd/flexcard.h    |   2 +
>  7 files changed, 235 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/mfd/flexcard/irq.c
>  create mode 100644 drivers/mfd/flexcard/irq.h

[...]

> diff --git a/drivers/mfd/flexcard/irq.h b/drivers/mfd/flexcard/irq.h
> new file mode 100644
> index 0000000..b18fb5b
> --- /dev/null
> +++ b/drivers/mfd/flexcard/irq.h
> @@ -0,0 +1,50 @@
> +#ifndef FLEXCARD_IRQ_H
> +#define FLEXCARD_IRQ_H
> +
> +struct flexcard_irq_tab {
> +	u32 enable;
> +	u32 reset;
> +	u32 status;
> +};
> +
> +#define to_irq_tab(e, s) {			\
> +	.enable = (1 << e),			\
> +	.status = (1 << s),			\
> +}
> +
> +#define to_irq_tab_ack(e, r, s) {		\
> +	.enable = (1 << e),			\
> +	.reset  = (1 << r),			\
> +	.status = (1 << s),			\
> +}
> +
> +/*
> + * Interrupt Controller Register S-Box
> + * unlike other irq controllers the FlexCard bits for enable, reset and status
> + * looks more like a cryptographic S-box. Make a const table to have a more
> + * easier access to this bits in the irqchip callback functions.
> + * The table contains the registers for PMC2-cards.
> + */
> +static const struct flexcard_irq_tab flexcard_irq_tab[] = {
> +	to_irq_tab_ack(28, 0, 28),	/* TIMER  */
> +	to_irq_tab_ack(29, 1, 29),	/* CC1CYS */
> +	to_irq_tab_ack(30, 10, 21),	/* CC2CYS */
> +	to_irq_tab_ack(18, 2, 30),	/* CC3CYS */
> +	to_irq_tab_ack(19, 6, 25),	/* CC4CYS */
> +	to_irq_tab_ack(26, 4, 26),	/* WAKE1A */
> +	to_irq_tab_ack(27, 5, 27),	/* WAKE1B */
> +	to_irq_tab_ack(24, 8, 23),	/* WAKE2A */
> +	to_irq_tab_ack(25, 9, 22),	/* WAKE2B */
> +	to_irq_tab_ack(22, 12, 19),	/* WAKE3A */
> +	to_irq_tab_ack(23, 13, 18),	/* WAKE3B */
> +	to_irq_tab_ack(20, 14, 17),	/* WAKE4A */
> +	to_irq_tab_ack(21, 15, 16),	/* WAKE4B */
> +	to_irq_tab(15, 31),		/* CC1T0  */
> +	to_irq_tab(14, 3),		/* CC2T0  */
> +	to_irq_tab(16, 24),		/* CC3T0  */
> +	to_irq_tab(17, 20),		/* CC4T0  */
> +};
> +
> +#define NR_FLEXCARD_IRQ		ARRAY_SIZE(flexcard_irq_tab)

Is everything in this header used over multiple source files, or only
irq.c?  If the latter, then please move them into irq.c.

> +#endif /* FLEXCARD_IRQ_H */
> diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
> index 84e155c..f5b789f 100644
> --- a/include/linux/mfd/flexcard.h
> +++ b/include/linux/mfd/flexcard.h
> @@ -22,12 +22,14 @@
>  #define FLEXCARD_MAX_NAME	16
>  
>  struct flexcard_device {
> +	raw_spinlock_t irq_lock;
>  	struct pci_dev *pdev;
>  	struct fc_conf_bar __iomem *conf;
>  	struct mfd_cell *cells;
>  	struct resource *res;
>  	struct miscdevice dev;
>  	struct kref ref;
> +	struct irq_domain *irq_domain;
>  	int cardnr;
>  	char name[FLEXCARD_MAX_NAME];
>  };

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 06/11] mfd: flexcard: add DMA interrupt domain
  2015-03-25  9:51 ` [PATCH 06/11] mfd: flexcard: add DMA interrupt domain Holger Dengler
@ 2015-03-30  8:50   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:50 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> The Flexcard comprise an interrupt controller for the attached
> tinys, timer, a Flexray related trigger and a second one for DMA.
> Both controllers share a single IRQ line.
> 
> Add an interrupt domain for the DMA Controller interrupts.
> 
> 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/flexcard/irq.c   | 95 +++++++++++++++++++++++++++++++++++++++++---
>  drivers/mfd/flexcard/irq.h   | 11 +++++
>  include/linux/mfd/flexcard.h | 23 +++++++++++
>  3 files changed, 124 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mfd/flexcard/irq.c b/drivers/mfd/flexcard/irq.c
> index fefcb24..17e8b2c 100644
> --- a/drivers/mfd/flexcard/irq.c
> +++ b/drivers/mfd/flexcard/irq.c
> @@ -27,11 +27,13 @@
>  static irqreturn_t flexcard_demux(int irq, void *data)
>  {
>  	struct flexcard_device *priv = data;
> -	u32 stat;
> +	u32 stat, dma_stat;
>  	int i, cur;
>  
>  	stat = readl(&priv->conf->irs);
> -	if (!stat)
> +	dma_stat = readl(&priv->conf->dma_irsr);
> +
> +	if (!stat && !dma_stat)
>  		return IRQ_NONE;
>  
>  	for (i = 0; i < NR_FLEXCARD_IRQ; i++) {
> @@ -41,6 +43,15 @@ static irqreturn_t flexcard_demux(int irq, void *data)
>  				generic_handle_irq(cur);
>  		}
>  	}
> +
> +	for (i = 0; i < NR_FLEXCARD_DMA_IRQ; i++) {
> +		if (dma_stat & flexcard_dma_irq_tab[i].status) {
> +			cur = irq_find_mapping(priv->dma_domain, i);
> +			if (cur)
> +				generic_handle_irq(cur);
> +		}
> +	}

You might only want to do the top if (stat) and only the second if
(dma_stat).

[...]

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 07/11] mfd: flexcard: add UIO IRQ devices
  2015-03-25  9:51 ` [PATCH 07/11] mfd: flexcard: add UIO IRQ devices Holger Dengler
@ 2015-03-30  8:57   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:57 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> Add an UIO device for each Flexcard Flexray related trigger. The trigger
> devide into:
>  - Flexray cycle start (CCYS)
>  - Flexray timer 0 (CCxT0)
>  - Bus wakeup (WAKE)
> 
> The UIO IRQ devices can be used to synchronize an application
> with these events.
> 
> 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/flexcard/core.c     | 52 +++++++++++++++++++++++++++++++++++++++++
>  drivers/mfd/flexcard/flexcard.h | 23 ++++++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
> index a6f92b4..cd06854 100644
> --- a/drivers/mfd/flexcard/core.c
> +++ b/drivers/mfd/flexcard/core.c
> @@ -19,6 +19,7 @@
>  #include <linux/miscdevice.h>
>  #include <linux/pci.h>
>  #include <linux/platform_device.h>
> +#include <linux/uio_driver.h>
>  #include <linux/mfd/core.h>
>  #include <linux/mfd/flexcard.h>
>  
> @@ -51,6 +52,42 @@ static struct mfd_cell flexcard_clk_dev[] = {
>  	},
>  };
>  
> +irq_res(CC1CCYS);
> +irq_res(CC2CCYS);
> +irq_res(CC3CCYS);
> +irq_res(CC4CCYS);
> +irq_res(WAKE4A);
> +irq_res(WAKE4B);
> +irq_res(WAKE3A);
> +irq_res(WAKE3B);
> +irq_res(WAKE2A);
> +irq_res(WAKE2B);
> +irq_res(WAKE1A);
> +irq_res(WAKE1B);
> +irq_res(CC1T0);
> +irq_res(CC2T0);
> +irq_res(CC3T0);
> +irq_res(CC4T0);

flexcard_irq_resource();

> +static struct mfd_cell flexcard_uio_dev[] = {
> +	flexcard_irq_cell(CC3CCYS, 0),
> +	flexcard_irq_cell(CC4CCYS, 1),
> +	flexcard_irq_cell(WAKE4A, 2),
> +	flexcard_irq_cell(WAKE4B, 3),
> +	flexcard_irq_cell(WAKE3A, 4),
> +	flexcard_irq_cell(WAKE3B, 5),
> +	flexcard_irq_cell(WAKE2A, 6),
> +	flexcard_irq_cell(WAKE2B, 7),
> +	flexcard_irq_cell(WAKE1A, 8),
> +	flexcard_irq_cell(WAKE1B, 9),
> +	flexcard_irq_cell(CC1CCYS, 10),
> +	flexcard_irq_cell(CC2CCYS, 11),
> +	flexcard_irq_cell(CC1T0, 12),
> +	flexcard_irq_cell(CC2T0, 13),
> +	flexcard_irq_cell(CC3T0, 14),
> +	flexcard_irq_cell(CC4T0, 15),
> +};
> +
>  static int flexcard_tiny_can(struct flexcard_device *priv,
>  			     int idx, int id, u32 offset)
>  {
> @@ -150,6 +187,15 @@ static int flexcard_clk_setup(struct flexcard_device *priv)
>  			       &pdev->resource[0], 0, NULL);
>  }
>  
> +static int flexcard_add_uio(struct flexcard_device *priv)
> +{
> +	struct pci_dev *pdev = priv->pdev;
> +
> +	return mfd_add_devices(&pdev->dev, 0, flexcard_uio_dev,
> +			       ARRAY_SIZE(flexcard_uio_dev),
> +			       NULL, 0, priv->irq_domain);

Again, any reason why you have yet another call do mfd_add_devices()?

> +}
> +
>  static int flexcard_misc_open(struct inode *inode, struct file *filp)
>  {
>  	struct flexcard_device *priv =
> @@ -284,6 +330,12 @@ static int flexcard_probe(struct pci_dev *pdev,
>  		goto out_remove;
>  	}
>  
> +	ret = flexcard_add_uio(priv);

Not sure you need a special function just to call mfd_add_devices().

> +	if (ret) {
> +		dev_err(&pdev->dev, "unable to add irq UIO devices: %d", ret);
> +		goto out_remove;
> +	}
> +
>  	ret = misc_register(&priv->dev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret);
> diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
> index 038c138..0d05f78 100644
> --- a/drivers/mfd/flexcard/flexcard.h
> +++ b/drivers/mfd/flexcard/flexcard.h
> @@ -6,4 +6,27 @@ void flexcard_misc_del_attrs(struct device *dev);
>  int flexcard_setup_irq(struct pci_dev *pdev);
>  void flexcard_remove_irq(struct pci_dev *pdev);
>  
> +#define irq_res(irq_name)						\
> +	static struct resource flexcard_irq_res_##irq_name = {		\
> +		.name = __stringify(fc_irq_##irq_name##_off),		\
> +		.start  = FLEXCARD_IRQ_##irq_name##_OFF,		\
> +		.end  = FLEXCARD_IRQ_##irq_name##_OFF,			\
> +		.flags  = IORESOURCE_IRQ,				\
> +	};								\
> +									\
> +	static struct uio_info flexcard_irq_pdata_##irq_name = {	\
> +		.name   = __stringify(irq_name),			\
> +		.version = "0",						\
> +	}
> +
> +#define flexcard_irq_cell(irq_name, irq_id)				\
> +	{								\
> +		.id = irq_id,						\
> +		.name = "uio_pdrv_genirq",				\
> +		.platform_data = &flexcard_irq_pdata_##irq_name,	\
> +		.pdata_size = sizeof(flexcard_irq_pdata_##irq_name),	\
> +		.num_resources = 1,					\
> +		.resources = &flexcard_irq_res_##irq_name		\
> +	}

Any reason these aren't in the *.c file?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 08/11] mfd: flexcard: add DMA device
  2015-03-25  9:51 ` [PATCH 08/11] mfd: flexcard: add DMA device Holger Dengler
@ 2015-03-30  8:59   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  8:59 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> The Flexcard interface design split packet receive and transmit. All
> received packets and card status information are multiplexed with a
> Flexcard specific protocol and handled through a DMA capable ringbuffer.
> The TX path has to poke each available component separate.
> 
> Add a platform device for the DMA receive channel.
> 
> 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/flexcard/core.c     | 60 +++++++++++++++++++++++++++++++++++++++++
>  drivers/mfd/flexcard/flexcard.h |  5 ++++
>  2 files changed, 65 insertions(+)
> 
> diff --git a/drivers/mfd/flexcard/core.c b/drivers/mfd/flexcard/core.c
> index cd06854..39d1d4d 100644
> --- a/drivers/mfd/flexcard/core.c
> +++ b/drivers/mfd/flexcard/core.c
> @@ -52,6 +52,34 @@ static struct mfd_cell flexcard_clk_dev[] = {
>  	},
>  };
>  
> +static struct resource flexcard_dma_res[] = {
> +	{
> +		.name   = "flexcard-dma",
> +		.start  = 0x500,
> +		.end    = 0x580,

Better to define these.

> +		.flags  = IORESOURCE_MEM,
> +	}, {
> +		.name   = "flexcard-dma",
> +		.start  = FLEXCARD_DMA_IRQ_CBL,
> +		.end    = FLEXCARD_DMA_IRQ_CBL,
> +		.flags  = IORESOURCE_IRQ,
> +	}, {
> +		.name   = "flexcard-dma",
> +		.start  = FLEXCARD_DMA_IRQ_CO,
> +		.end    = FLEXCARD_DMA_IRQ_CO,
> +		.flags  = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct mfd_cell flexcard_dma_dev[] = {
> +	{
> +		.id = 0,

Why do you need this for a single device?

> +		.name = "flexcard-dma",
> +		.num_resources = ARRAY_SIZE(flexcard_dma_res),
> +		.resources = flexcard_dma_res,
> +	},
> +};
> +
>  irq_res(CC1CCYS);
>  irq_res(CC2CCYS);
>  irq_res(CC3CCYS);
> @@ -187,6 +215,32 @@ static int flexcard_clk_setup(struct flexcard_device *priv)
>  			       &pdev->resource[0], 0, NULL);
>  }
>  
> +static int flexcard_add_dma(struct flexcard_device *priv)
> +{
> +	struct pci_dev *pdev = priv->pdev;
> +
> +	/* check for a DMA capable firmware version*/
> +	if (priv->conf->fc_fw_ver.maj < DMA_MIN_FW_MAJOR)
> +		goto out;
> +
> +	if (priv->conf->fc_fw_ver.maj == DMA_MIN_FW_MAJOR) {
> +		if (priv->conf->fc_fw_ver.min < DMA_MIN_FW_MINOR)
> +			goto out;
> +		if ((priv->conf->fc_fw_ver.min == DMA_MIN_FW_MINOR) &&
> +		    (priv->conf->fc_fw_ver.dev < DMA_MIN_FW_UPDATE))
> +			goto out;
> +	}
> +
> +	return mfd_add_devices(&pdev->dev, 0, flexcard_dma_dev,
> +			       ARRAY_SIZE(flexcard_dma_dev),
> +			       &pdev->resource[0], 0, priv->dma_domain);
> +

Another call?

> +out:
> +	dev_info(&pdev->dev, "Firmware is not DMA capable\n");
> +
> +	return 0;
> +}
> +
>  static int flexcard_add_uio(struct flexcard_device *priv)
>  {
>  	struct pci_dev *pdev = priv->pdev;
> @@ -330,6 +384,12 @@ static int flexcard_probe(struct pci_dev *pdev,
>  		goto out_remove;
>  	}
>  
> +	ret = flexcard_add_dma(priv);
> +	if (ret) {
> +		dev_err(&pdev->dev, "unable to add DMA device: %d", ret);
> +		goto out_remove;
> +	}
> +
>  	ret = flexcard_add_uio(priv);
>  	if (ret) {
>  		dev_err(&pdev->dev, "unable to add irq UIO devices: %d", ret);
> diff --git a/drivers/mfd/flexcard/flexcard.h b/drivers/mfd/flexcard/flexcard.h
> index 0d05f78..ee6b773 100644
> --- a/drivers/mfd/flexcard/flexcard.h
> +++ b/drivers/mfd/flexcard/flexcard.h
> @@ -1,6 +1,11 @@
>  #ifndef __FLEXCARD_H
>  #define  __FLEXCARD_H
>  
> +/* The first FW Version supporting DMA is 6.4.0 */
> +#define DMA_MIN_FW_MAJOR	6
> +#define DMA_MIN_FW_MINOR	4
> +#define DMA_MIN_FW_UPDATE	0
> +
>  int flexcard_misc_add_attrs(struct device *dev);
>  void flexcard_misc_del_attrs(struct device *dev);
>  int flexcard_setup_irq(struct pci_dev *pdev);

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver
  2015-03-25  9:51 ` [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver Holger Dengler
@ 2015-03-30  9:02   ` Lee Jones
  0 siblings, 0 replies; 25+ messages in thread
From: Lee Jones @ 2015-03-30  9:02 UTC (permalink / raw)
  To: Holger Dengler
  Cc: linux-kernel, Peter Mahler, Juergen Bubeck, Benedikt Spranger,
	Samuel Ortiz

On Wed, 25 Mar 2015, Holger Dengler wrote:

> From: Benedikt Spranger <b.spranger@linutronix.de>
> 
> The Flexcard interface design split packet receive and transmit. All
> received packets and card status information are multiplexed with a
> Flexcard specific protocol and handled through a DMA capable ringbuffer.
> The TX path has to poke each available component separate.
> 
> Add a Flexcard DMA ringbuffer driver and packet demultiplexer.

These are not MFD devices.

> 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                 |   9 ++
>  drivers/mfd/flexcard/Makefile       |   3 +
>  drivers/mfd/flexcard/dma.c          | 286 ++++++++++++++++++++++++++++++++++++

drivers/dma?

>  drivers/mfd/flexcard/flexcard-dma.h | 207 ++++++++++++++++++++++++++
>  drivers/mfd/flexcard/parser.c       | 193 ++++++++++++++++++++++++

drivers/pci?

>  include/linux/mfd/flexcard.h        |   5 +
>  6 files changed, 703 insertions(+)
>  create mode 100644 drivers/mfd/flexcard/dma.c
>  create mode 100644 drivers/mfd/flexcard/flexcard-dma.h
>  create mode 100644 drivers/mfd/flexcard/parser.c

</review>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2015-03-30  9:02 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-25  9:51 [PATCH 00/11] Eberspaecher Flexcard PMC II base support Holger Dengler
2015-03-25  9:51 ` [PATCH 01/11] mfd: Eberspaecher Flexcard PMC II Carrier Board support Holger Dengler
2015-03-30  7:57   ` Lee Jones
2015-03-25  9:51 ` [PATCH 02/11] mfd: flexcard: add flexcard core device Holger Dengler
2015-03-30  8:06   ` Lee Jones
2015-03-25  9:51 ` [PATCH 03/11] mfd: flexcard: add device attributes Holger Dengler
2015-03-30  8:15   ` Lee Jones
2015-03-25  9:51 ` [PATCH 04/11] mfd: flexcard: add clocksrc device Holger Dengler
2015-03-30  8:30   ` Lee Jones
2015-03-25  9:51 ` [PATCH 05/11] mfd: flexcard: add interrupt support Holger Dengler
2015-03-30  8:46   ` Lee Jones
2015-03-25  9:51 ` [PATCH 06/11] mfd: flexcard: add DMA interrupt domain Holger Dengler
2015-03-30  8:50   ` Lee Jones
2015-03-25  9:51 ` [PATCH 07/11] mfd: flexcard: add UIO IRQ devices Holger Dengler
2015-03-30  8:57   ` Lee Jones
2015-03-25  9:51 ` [PATCH 08/11] mfd: flexcard: add DMA device Holger Dengler
2015-03-30  8:59   ` Lee Jones
2015-03-25  9:51 ` [PATCH 09/11] mfd: flexcard: add DMA ringbuffer demux driver Holger Dengler
2015-03-30  9:02   ` Lee Jones
2015-03-25  9:51 ` [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support Holger Dengler
2015-03-26  9:41   ` Daniel Lezcano
2015-03-26 11:01     ` Holger Dengler
2015-03-26 16:34       ` John Stultz
2015-03-27 12:27         ` Holger Dengler
2015-03-25  9:52 ` [PATCH 11/11] clocksource: flexcard: Support timestamp trigger selection Holger Dengler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).