linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h
@ 2021-09-15 18:47 min.li.xe
  2021-09-15 18:47 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: min.li.xe @ 2021-09-15 18:47 UTC (permalink / raw)
  To: arnd, gregkh, derek.kiernan, dragan.cvetic
  Cc: linux-kernel, lee.jones, Min Li

From: Min Li <min.li.xe@renesas.com>

Signed-off-by: Min Li <min.li.xe@renesas.com>
---
Change log
-resolve name conflicts so that rsmu misc driver can be in one c file suggested by Greg

 include/linux/mfd/idt82p33_reg.h | 148 ++++++++++++++++++++-------------------
 1 file changed, 75 insertions(+), 73 deletions(-)

diff --git a/include/linux/mfd/idt82p33_reg.h b/include/linux/mfd/idt82p33_reg.h
index 129a6c0..ded0ab8 100644
--- a/include/linux/mfd/idt82p33_reg.h
+++ b/include/linux/mfd/idt82p33_reg.h
@@ -7,106 +7,108 @@
 #ifndef HAVE_IDT82P33_REG
 #define HAVE_IDT82P33_REG
 
+#define SABRE_REG_ADDR(page, offset) (((page) << 0x7) | ((offset) & 0x7f))
+
 /* Register address */
-#define DPLL1_TOD_CNFG 0x134
-#define DPLL2_TOD_CNFG 0x1B4
+#define SABRE_DPLL1_TOD_CNFG 0x134
+#define SABRE_DPLL2_TOD_CNFG 0x1B4
 
-#define DPLL1_TOD_STS 0x10B
-#define DPLL2_TOD_STS 0x18B
+#define SABRE_DPLL1_TOD_STS 0x10B
+#define SABRE_DPLL2_TOD_STS 0x18B
 
-#define DPLL1_TOD_TRIGGER 0x115
-#define DPLL2_TOD_TRIGGER 0x195
+#define SABRE_DPLL1_TOD_TRIGGER 0x115
+#define SABRE_DPLL2_TOD_TRIGGER 0x195
 
-#define DPLL1_OPERATING_MODE_CNFG 0x120
-#define DPLL2_OPERATING_MODE_CNFG 0x1A0
+#define SABRE_DPLL1_OPERATING_MODE_CNFG 0x120
+#define SABRE_DPLL2_OPERATING_MODE_CNFG 0x1A0
 
-#define DPLL1_HOLDOVER_FREQ_CNFG 0x12C
-#define DPLL2_HOLDOVER_FREQ_CNFG 0x1AC
+#define SABRE_DPLL1_HOLDOVER_FREQ_CNFG 0x12C
+#define SABRE_DPLL2_HOLDOVER_FREQ_CNFG 0x1AC
 
-#define DPLL1_PHASE_OFFSET_CNFG 0x143
-#define DPLL2_PHASE_OFFSET_CNFG 0x1C3
+#define SABRE_DPLL1_PHASE_OFFSET_CNFG 0x143
+#define SABRE_DPLL2_PHASE_OFFSET_CNFG 0x1C3
 
-#define DPLL1_SYNC_EDGE_CNFG 0x140
-#define DPLL2_SYNC_EDGE_CNFG 0x1C0
+#define SABRE_DPLL1_SYNC_EDGE_CNFG 0x140
+#define SABRE_DPLL2_SYNC_EDGE_CNFG 0x1C0
 
-#define DPLL1_INPUT_MODE_CNFG 0x116
-#define DPLL2_INPUT_MODE_CNFG 0x196
+#define SABRE_DPLL1_INPUT_MODE_CNFG 0x116
+#define SABRE_DPLL2_INPUT_MODE_CNFG 0x196
 
-#define DPLL1_OPERATING_STS 0x102
-#define DPLL2_OPERATING_STS 0x182
+#define SABRE_DPLL1_OPERATING_STS 0x102
+#define SABRE_DPLL2_OPERATING_STS 0x182
 
-#define DPLL1_CURRENT_FREQ_STS 0x103
-#define DPLL2_CURRENT_FREQ_STS 0x183
+#define SABRE_DPLL1_CURRENT_FREQ_STS 0x103
+#define SABRE_DPLL2_CURRENT_FREQ_STS 0x183
 
-#define REG_SOFT_RESET 0X381
+#define SABRE_REG_SOFT_RESET 0X381
 
-#define OUT_MUX_CNFG(outn) REG_ADDR(0x6, (0xC * (outn)))
+#define SABRE_OUT_MUX_CNFG(outn) REG_ADDR(0x6, (0xC * (outn)))
 
 /* Register bit definitions */
-#define SYNC_TOD BIT(1)
-#define PH_OFFSET_EN BIT(7)
-#define SQUELCH_ENABLE BIT(5)
+#define SABRE_SYNC_TOD BIT(1)
+#define SABRE_PH_OFFSET_EN BIT(7)
+#define SABRE_SQUELCH_ENABLE BIT(5)
 
 /* Bit definitions for the DPLL_MODE register */
-#define PLL_MODE_SHIFT		(0)
-#define PLL_MODE_MASK		(0x1F)
-#define COMBO_MODE_EN		BIT(5)
-#define COMBO_MODE_SHIFT	(6)
-#define COMBO_MODE_MASK		(0x3)
+#define SABRE_PLL_MODE_SHIFT		(0)
+#define SABRE_PLL_MODE_MASK		(0x1F)
+#define SABRE_COMBO_MODE_EN		BIT(5)
+#define SABRE_COMBO_MODE_SHIFT	(6)
+#define SABRE_COMBO_MODE_MASK		(0x3)
 
 /* Bit definitions for DPLL_OPERATING_STS register */
-#define OPERATING_STS_MASK	(0x7)
-#define OPERATING_STS_SHIFT	(0x0)
+#define SABRE_OPERATING_STS_MASK	(0x7)
+#define SABRE_OPERATING_STS_SHIFT	(0x0)
 
 /* Bit definitions for DPLL_TOD_TRIGGER register */
-#define READ_TRIGGER_MASK	(0xF)
-#define READ_TRIGGER_SHIFT	(0x0)
-#define WRITE_TRIGGER_MASK	(0xF0)
-#define WRITE_TRIGGER_SHIFT	(0x4)
+#define SABRE_READ_TRIGGER_MASK	(0xF)
+#define SABRE_READ_TRIGGER_SHIFT	(0x0)
+#define SABRE_WRITE_TRIGGER_MASK	(0xF0)
+#define SABRE_WRITE_TRIGGER_SHIFT	(0x4)
 
 /* Bit definitions for REG_SOFT_RESET register */
-#define SOFT_RESET_EN		BIT(7)
-
-enum pll_mode {
-	PLL_MODE_MIN = 0,
-	PLL_MODE_AUTOMATIC = PLL_MODE_MIN,
-	PLL_MODE_FORCE_FREERUN = 1,
-	PLL_MODE_FORCE_HOLDOVER = 2,
-	PLL_MODE_FORCE_LOCKED = 4,
-	PLL_MODE_FORCE_PRE_LOCKED2 = 5,
-	PLL_MODE_FORCE_PRE_LOCKED = 6,
-	PLL_MODE_FORCE_LOST_PHASE = 7,
-	PLL_MODE_DCO = 10,
-	PLL_MODE_WPH = 18,
-	PLL_MODE_MAX = PLL_MODE_WPH,
+#define SABRE_SOFT_RESET_EN		BIT(7)
+
+enum sabre_pll_mode {
+	SABRE_PLL_MODE_MIN = 0,
+	SABRE_PLL_MODE_AUTOMATIC = SABRE_PLL_MODE_MIN,
+	SABRE_PLL_MODE_FORCE_FREERUN = 1,
+	SABRE_PLL_MODE_FORCE_HOLDOVER = 2,
+	SABRE_PLL_MODE_FORCE_LOCKED = 4,
+	SABRE_PLL_MODE_FORCE_PRE_LOCKED2 = 5,
+	SABRE_PLL_MODE_FORCE_PRE_LOCKED = 6,
+	SABRE_PLL_MODE_FORCE_LOST_PHASE = 7,
+	SABRE_PLL_MODE_DCO = 10,
+	SABRE_PLL_MODE_WPH = 18,
+	SABRE_PLL_MODE_MAX = SABRE_PLL_MODE_WPH,
 };
 
-enum hw_tod_trig_sel {
-	HW_TOD_TRIG_SEL_MIN = 0,
-	HW_TOD_TRIG_SEL_NO_WRITE = HW_TOD_TRIG_SEL_MIN,
-	HW_TOD_TRIG_SEL_NO_READ = HW_TOD_TRIG_SEL_MIN,
-	HW_TOD_TRIG_SEL_SYNC_SEL = 1,
-	HW_TOD_TRIG_SEL_IN12 = 2,
-	HW_TOD_TRIG_SEL_IN13 = 3,
-	HW_TOD_TRIG_SEL_IN14 = 4,
-	HW_TOD_TRIG_SEL_TOD_PPS = 5,
-	HW_TOD_TRIG_SEL_TIMER_INTERVAL = 6,
-	HW_TOD_TRIG_SEL_MSB_PHASE_OFFSET_CNFG = 7,
-	HW_TOD_TRIG_SEL_MSB_HOLDOVER_FREQ_CNFG = 8,
-	HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG = 9,
-	HW_TOD_RD_TRIG_SEL_LSB_TOD_STS = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
-	WR_TRIG_SEL_MAX = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
+enum sabre_hw_tod_trig_sel {
+	SABRE_HW_TOD_TRIG_SEL_MIN = 0,
+	SABRE_HW_TOD_TRIG_SEL_NO_WRITE = SABRE_HW_TOD_TRIG_SEL_MIN,
+	SABRE_HW_TOD_TRIG_SEL_NO_READ = SABRE_HW_TOD_TRIG_SEL_MIN,
+	SABRE_HW_TOD_TRIG_SEL_SYNC_SEL = 1,
+	SABRE_HW_TOD_TRIG_SEL_IN12 = 2,
+	SABRE_HW_TOD_TRIG_SEL_IN13 = 3,
+	SABRE_HW_TOD_TRIG_SEL_IN14 = 4,
+	SABRE_HW_TOD_TRIG_SEL_TOD_PPS = 5,
+	SABRE_HW_TOD_TRIG_SEL_TIMER_INTERVAL = 6,
+	SABRE_HW_TOD_TRIG_SEL_MSB_PHASE_OFFSET_CNFG = 7,
+	SABRE_HW_TOD_TRIG_SEL_MSB_HOLDOVER_FREQ_CNFG = 8,
+	SABRE_HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG = 9,
+	SABRE_HW_TOD_RD_TRIG_SEL_LSB_TOD_STS = SABRE_HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
+	SABRE_WR_TRIG_SEL_MAX = SABRE_HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
 };
 
 /** @brief Enumerated type listing DPLL operational modes */
-enum dpll_state {
-	DPLL_STATE_FREERUN = 1,
-	DPLL_STATE_HOLDOVER = 2,
-	DPLL_STATE_LOCKED = 4,
-	DPLL_STATE_PRELOCKED2 = 5,
-	DPLL_STATE_PRELOCKED = 6,
-	DPLL_STATE_LOSTPHASE = 7,
-	DPLL_STATE_MAX
+enum sabre_dpll_state {
+	SABRE_DPLL_STATE_FREERUN = 1,
+	SABRE_DPLL_STATE_HOLDOVER = 2,
+	SABRE_DPLL_STATE_LOCKED = 4,
+	SABRE_DPLL_STATE_PRELOCKED2 = 5,
+	SABRE_DPLL_STATE_PRELOCKED = 6,
+	SABRE_DPLL_STATE_LOSTPHASE = 7,
+	SABRE_DPLL_STATE_MAX
 };
 
 #endif
-- 
2.7.4


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

* [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-15 18:47 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
@ 2021-09-15 18:47 ` min.li.xe
  2021-09-16  5:25   ` Greg KH
  2021-09-16 11:31   ` kernel test robot
  2021-09-16  5:23 ` [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h Greg KH
  2021-09-16  5:24 ` Greg KH
  2 siblings, 2 replies; 16+ messages in thread
From: min.li.xe @ 2021-09-15 18:47 UTC (permalink / raw)
  To: arnd, gregkh, derek.kiernan, dragan.cvetic
  Cc: linux-kernel, lee.jones, Min Li

From: Min Li <min.li.xe@renesas.com>

This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
of timing and synchronization devices.It will be used by Renesas PTP Clock
Manager for Linux (pcm4l) software to provide support to GNSS assisted
partial timing support (APTS) and other networking timing functions.

Current version provides kernel API's to support the following functions
-set combomode to enable SYNCE clock support
-read dpll's state to determine if the dpll is locked to the GNSS channel
-read dpll's ffo (fractional frequency offset) in ppqt

Signed-off-by: Min Li <min.li.xe@renesas.com>
---
Change log
-simply design by using only one c file suggested by Greg

 drivers/misc/Kconfig      |   8 +
 drivers/misc/Makefile     |   1 +
 drivers/misc/rsmu.c       | 536 ++++++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/rsmu.h |  66 ++++++
 4 files changed, 611 insertions(+)
 create mode 100644 drivers/misc/rsmu.c
 create mode 100644 include/uapi/linux/rsmu.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 85ba901..6dc36f9 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -469,6 +469,14 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config RSMU
+	tristate "Renesas Synchronization Management Unit (SMU)"
+	help
+	  This option enables support for RSMU (Renesas Synchronization
+	  Management Unit) driver. It will be used by Renesas PTP Clock Manager
+	  for Linux (pcm4l) software to provide support for GNSS assisted
+	  partial timing support (APTS) and other networking timing functions.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a086197..a66e3b7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE)		+= uacce/
 obj-$(CONFIG_XILINX_SDFEC)	+= xilinx_sdfec.o
 obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
 obj-$(CONFIG_HI6421V600_IRQ)	+= hi6421v600-irq.o
+obj-$(CONFIG_RSMU)		+= rsmu.o
diff --git a/drivers/misc/rsmu.c b/drivers/misc/rsmu.c
new file mode 100644
index 0000000..6981cb3
--- /dev/null
+++ b/drivers/misc/rsmu.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
+ * of timing and synchronization devices. It will be used by Renesas PTP Clock
+ * Manager for Linux (pcm4l) software to provide support to GNSS assisted
+ * partial timing support (APTS) and other networking timing functions.
+ *
+ * Please note it must work with Renesas MFD driver to access device through
+ * I2C/SPI.
+ *
+ * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/idt8a340_reg.h>
+#include <linux/mfd/idt82p33_reg.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+
+static DEFINE_IDA(rsmu_cdev_map);
+
+/**
+ * struct rsmu_cdev - Driver data for RSMU character device
+ * @name: rsmu device name as rsmu[index]
+ * @dev: pointer to platform device
+ * @miscdev: character device handle
+ * @regmap: I2C/SPI regmap handle
+ * @lock: mutex to protect operations from being interrupted
+ * @type: rsmu device type, passed through platform data
+ * @index: rsmu device index
+ */
+struct rsmu_cdev {
+	char name[16];
+	struct device *dev;
+	struct miscdevice miscdev;
+	struct regmap *regmap;
+	struct mutex *lock;
+	enum rsmu_type type;
+	int index;
+};
+
+/**
+ * Enumerated type listing DPLL combination modes
+ */
+enum rsmu_dpll_combomode {
+	E_COMBOMODE_CURRENT = 0,
+	E_COMBOMODE_FASTAVG,
+	E_COMBOMODE_SLOWAVG,
+	E_COMBOMODE_HOLDOVER,
+	E_COMBOMODE_MAX
+};
+
+/**
+ * An id used to identify the respective child class states.
+ */
+enum rsmu_class_state {
+	E_SRVLOINITIALSTATE = 0,
+	E_SRVLOUNQUALIFIEDSTATE = 1,
+	E_SRVLOLOCKACQSTATE = 2,
+	E_SRVLOFREQUENCYLOCKEDSTATE = 3,
+	E_SRVLOTIMELOCKEDSTATE = 4,
+	E_SRVLOHOLDOVERINSPECSTATE = 5,
+	E_SRVLOHOLDOVEROUTOFSPECSTATE = 6,
+	E_SRVLOFREERUNSTATE = 7,
+	E_SRVNUMBERLOSTATES = 8,
+	E_SRVLOSTATEINVALID = 9,
+};
+
+/*======================== Sabre functions start ==========================*/
+static int rsmu_sabre_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = SABRE_DPLL1_OPERATING_MODE_CNFG;
+		break;
+	case 1:
+		dpll_ctrl_n = SABRE_DPLL2_OPERATING_MODE_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	cfg &= ~(SABRE_COMBO_MODE_MASK << SABRE_COMBO_MODE_SHIFT);
+	cfg |= mode << SABRE_COMBO_MODE_SHIFT;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+}
+
+static int rsmu_sabre_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u16 dpll_sts_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_sts_n = SABRE_DPLL1_OPERATING_STS;
+		break;
+	case 1:
+		dpll_sts_n = SABRE_DPLL2_OPERATING_STS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_sts_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & SABRE_OPERATING_STS_MASK) {
+	case SABRE_DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_PRELOCKED2:
+	case SABRE_DPLL_STATE_PRELOCKED:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case SABRE_DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_sabre_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				   struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_freq_n;
+	int err;
+
+	/*
+	 * IDTDpll_GetCurrentDpllFreqOffset retrieves the FFO integrator only.
+	 * In order to get Proportional + Integrator, use the holdover FFO with
+	 * the filter bandwidth 0.5 Hz set by TCS file.
+	 */
+	switch (dpll) {
+	case 0:
+		dpll_freq_n = SABRE_DPLL1_HOLDOVER_FREQ_CNFG;
+		break;
+	case 1:
+		dpll_freq_n = SABRE_DPLL2_HOLDOVER_FREQ_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_freq_n, buf, 5);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 39);
+
+	/* FCW unit is 77760 / ( 1638400 * 2^48) = 1.68615121864946 * 10^-16 */
+	ffo->ffo = div_s64(fcw * 2107689, 12500);
+
+	return 0;
+}
+/*======================== Sabre functions end ==========================*/
+
+/*======================== Clockmatrix functions start ==================*/
+static int rsmu_cm_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = DPLL_CTRL_0;
+		break;
+	case 1:
+		dpll_ctrl_n = DPLL_CTRL_1;
+		break;
+	case 2:
+		dpll_ctrl_n = DPLL_CTRL_2;
+		break;
+	case 3:
+		dpll_ctrl_n = DPLL_CTRL_3;
+		break;
+	case 4:
+		dpll_ctrl_n = DPLL_CTRL_4;
+		break;
+	case 5:
+		dpll_ctrl_n = DPLL_CTRL_5;
+		break;
+	case 6:
+		dpll_ctrl_n = DPLL_CTRL_6;
+		break;
+	case 7:
+		dpll_ctrl_n = DPLL_CTRL_7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+			       &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	/* Only need to enable/disable COMBO_MODE_HOLD. */
+	if (mode)
+		cfg |= COMBO_MASTER_HOLD;
+	else
+		cfg &= ~COMBO_MASTER_HOLD;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+				 &cfg, sizeof(cfg));
+}
+
+static int rsmu_cm_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u8 cfg;
+	int err;
+
+	/* 8 is sys dpll */
+	if (dpll > 8)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + DPLL0_STATUS + dpll, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & DPLL_STATE_MASK) {
+	case DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case DPLL_STATE_LOCKACQ:
+	case DPLL_STATE_LOCKREC:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_cm_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_filter_status;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_filter_status = DPLL0_FILTER_STATUS;
+		break;
+	case 1:
+		dpll_filter_status = DPLL1_FILTER_STATUS;
+		break;
+	case 2:
+		dpll_filter_status = DPLL2_FILTER_STATUS;
+		break;
+	case 3:
+		dpll_filter_status = DPLL3_FILTER_STATUS;
+		break;
+	case 4:
+		dpll_filter_status = DPLL4_FILTER_STATUS;
+		break;
+	case 5:
+		dpll_filter_status = DPLL5_FILTER_STATUS;
+		break;
+	case 6:
+		dpll_filter_status = DPLL6_FILTER_STATUS;
+		break;
+	case 7:
+		dpll_filter_status = DPLL7_FILTER_STATUS;
+		break;
+	case 8:
+		dpll_filter_status = DPLLSYS_FILTER_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + dpll_filter_status, buf, 6);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 47);
+
+	/* FCW unit is 2 ^ -53 = 1.1102230246251565404236316680908e-16 */
+	ffo->ffo = fcw * 111;
+
+	return 0;
+}
+/*======================== Clockmatrix functions end ==================*/
+
+static int
+rsmu_set_combomode(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_combomode mode;
+	int err;
+
+	if (copy_from_user(&mode, arg, sizeof(mode)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err)
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_state(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_state state_request;
+	u8 state;
+	int err;
+
+	if (copy_from_user(&state_request, arg, sizeof(state_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	state_request.state = state;
+	if (copy_to_user(arg, &state_request, sizeof(state_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_ffo(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_ffo ffo_request;
+	int err;
+
+	if (copy_from_user(&ffo_request, arg, sizeof(ffo_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	if (copy_to_user(arg, &ffo_request, sizeof(ffo_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static struct rsmu_cdev *file2rsmu(struct file *file)
+{
+	return container_of(file->private_data, struct rsmu_cdev, miscdev);
+}
+
+static long
+rsmu_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
+{
+	struct rsmu_cdev *rsmu = file2rsmu(fptr);
+	void __user *arg = (void __user *)data;
+	int err = 0;
+
+	switch (cmd) {
+	case RSMU_SET_COMBOMODE:
+		err = rsmu_set_combomode(rsmu, arg);
+		break;
+	case RSMU_GET_STATE:
+		err = rsmu_get_dpll_state(rsmu, arg);
+		break;
+	case RSMU_GET_FFO:
+		err = rsmu_get_dpll_ffo(rsmu, arg);
+		break;
+	default:
+		/* Should not get here */
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static const struct file_operations rsmu_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = rsmu_ioctl,
+};
+
+static int
+rsmu_probe(struct platform_device *pdev)
+{
+	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct rsmu_cdev *rsmu;
+	int err;
+
+	rsmu = devm_kzalloc(&pdev->dev, sizeof(*rsmu), GFP_KERNEL);
+	if (!rsmu)
+		return -ENOMEM;
+
+	/* Save driver private data */
+	platform_set_drvdata(pdev, rsmu);
+
+	rsmu->dev = &pdev->dev;
+	rsmu->type = ddata->type;
+	rsmu->lock = &ddata->lock;
+	rsmu->regmap = ddata->regmap;
+	rsmu->index = ida_simple_get(&rsmu_cdev_map, 0, MINORMASK + 1, GFP_KERNEL);
+	if (rsmu->index < 0) {
+		dev_err(rsmu->dev, "Unable to get index %d\n", rsmu->index);
+		return rsmu->index;
+	}
+	snprintf(rsmu->name, sizeof(rsmu->name), "rsmu%d", rsmu->index);
+
+	/* Initialize and register the miscdev */
+	rsmu->miscdev.minor = MISC_DYNAMIC_MINOR;
+	rsmu->miscdev.fops = &rsmu_fops;
+	rsmu->miscdev.name = rsmu->name;
+	err = misc_register(&rsmu->miscdev);
+	if (err) {
+		dev_err(rsmu->dev, "Unable to register device\n");
+		ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int
+rsmu_remove(struct platform_device *pdev)
+{
+	struct rsmu_cdev *rsmu = platform_get_drvdata(pdev);
+
+	misc_deregister(&rsmu->miscdev);
+	ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+
+	return 0;
+}
+
+static const struct platform_device_id rsmu_id_table[] = {
+	{ "8a3400x-cdev", RSMU_CM},
+	{ "82p33x1x-cdev", RSMU_SABRE},
+	{}
+};
+MODULE_DEVICE_TABLE(platform, rsmu_id_table);
+
+static struct platform_driver rsmu_driver = {
+	.driver = {
+		.name = "rsmu-cdev",
+	},
+	.probe = rsmu_probe,
+	.remove =  rsmu_remove,
+	.id_table = rsmu_id_table,
+};
+
+module_platform_driver(rsmu_driver);
+
+MODULE_DESCRIPTION("Renesas SMU character device driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/rsmu.h b/include/uapi/linux/rsmu.h
new file mode 100644
index 0000000..e1cd43a
--- /dev/null
+++ b/include/uapi/linux/rsmu.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Driver for the IDT ClockMatrix(TM) and 82p33xxx families of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#ifndef __UAPI_LINUX_RSMU_CDEV_H
+#define __UAPI_LINUX_RSMU_CDEV_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Set dpll combomode */
+struct rsmu_combomode {
+	__u8 dpll;
+	__u8 mode;
+};
+
+/* Get dpll state */
+struct rsmu_get_state {
+	__u8 dpll;
+	__u8 state;
+};
+
+/* Get dpll ffo (fractional frequency offset) in ppqt */
+struct rsmu_get_ffo {
+	__u8 dpll;
+	__s64 ffo;
+};
+
+/*
+ * RSMU IOCTL List
+ */
+#define RSMU_MAGIC '?'
+
+/**
+ * struct rsmu_combomode
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @mode: combomode setting, see enum rsmu_dpll_combomode
+ *
+ * ioctl to set SMU combo mode.Combo mode provides physical layer frequency
+ * support from the Ethernet Equipment Clock to the PTP clock
+ */
+#define RSMU_SET_COMBOMODE  _IOW(RSMU_MAGIC, 1, struct rsmu_combomode)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @state: dpll state, see enum rsmu_class_state
+ *
+ * ioctl to get SMU dpll state. Application can call this API to tell if
+ * SMU is locked to the GNSS signal
+ */
+#define RSMU_GET_STATE  _IOR(RSMU_MAGIC, 2, struct rsmu_get_state)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @ffo: dpll's ffo (fractional frequency offset) in ppqt
+ *
+ * ioctl to get SMU dpll ffo (fractional frequency offset).
+ */
+#define RSMU_GET_FFO  _IOR(RSMU_MAGIC, 3, struct rsmu_get_ffo)
+#endif /* __UAPI_LINUX_RSMU_CDEV_H */
-- 
2.7.4


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

* Re: [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h
  2021-09-15 18:47 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
  2021-09-15 18:47 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
@ 2021-09-16  5:23 ` Greg KH
  2021-09-16  5:24 ` Greg KH
  2 siblings, 0 replies; 16+ messages in thread
From: Greg KH @ 2021-09-16  5:23 UTC (permalink / raw)
  To: min.li.xe; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

On Wed, Sep 15, 2021 at 02:47:08PM -0400, min.li.xe@renesas.com wrote:
> From: Min Li <min.li.xe@renesas.com>
> 
> Signed-off-by: Min Li <min.li.xe@renesas.com>

As I said before, I can not take patches without any changelog text :(

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

* Re: [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h
  2021-09-15 18:47 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
  2021-09-15 18:47 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
  2021-09-16  5:23 ` [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h Greg KH
@ 2021-09-16  5:24 ` Greg KH
  2021-09-16 14:49   ` Min Li
  2 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2021-09-16  5:24 UTC (permalink / raw)
  To: min.li.xe; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

On Wed, Sep 15, 2021 at 02:47:08PM -0400, min.li.xe@renesas.com wrote:
> From: Min Li <min.li.xe@renesas.com>
> 
> Signed-off-by: Min Li <min.li.xe@renesas.com>
> ---
> Change log
> -resolve name conflicts so that rsmu misc driver can be in one c file suggested by Greg
> 
>  include/linux/mfd/idt82p33_reg.h | 148 ++++++++++++++++++++-------------------
>  1 file changed, 75 insertions(+), 73 deletions(-)
> 
> diff --git a/include/linux/mfd/idt82p33_reg.h b/include/linux/mfd/idt82p33_reg.h
> index 129a6c0..ded0ab8 100644
> --- a/include/linux/mfd/idt82p33_reg.h
> +++ b/include/linux/mfd/idt82p33_reg.h
> @@ -7,106 +7,108 @@
>  #ifndef HAVE_IDT82P33_REG
>  #define HAVE_IDT82P33_REG
>  
> +#define SABRE_REG_ADDR(page, offset) (((page) << 0x7) | ((offset) & 0x7f))
> +
>  /* Register address */
> -#define DPLL1_TOD_CNFG 0x134
> -#define DPLL2_TOD_CNFG 0x1B4
> +#define SABRE_DPLL1_TOD_CNFG 0x134
> +#define SABRE_DPLL2_TOD_CNFG 0x1B4
>  
> -#define DPLL1_TOD_STS 0x10B
> -#define DPLL2_TOD_STS 0x18B
> +#define SABRE_DPLL1_TOD_STS 0x10B
> +#define SABRE_DPLL2_TOD_STS 0x18B
>  
> -#define DPLL1_TOD_TRIGGER 0x115
> -#define DPLL2_TOD_TRIGGER 0x195
> +#define SABRE_DPLL1_TOD_TRIGGER 0x115
> +#define SABRE_DPLL2_TOD_TRIGGER 0x195
>  
> -#define DPLL1_OPERATING_MODE_CNFG 0x120
> -#define DPLL2_OPERATING_MODE_CNFG 0x1A0
> +#define SABRE_DPLL1_OPERATING_MODE_CNFG 0x120
> +#define SABRE_DPLL2_OPERATING_MODE_CNFG 0x1A0
>  
> -#define DPLL1_HOLDOVER_FREQ_CNFG 0x12C
> -#define DPLL2_HOLDOVER_FREQ_CNFG 0x1AC
> +#define SABRE_DPLL1_HOLDOVER_FREQ_CNFG 0x12C
> +#define SABRE_DPLL2_HOLDOVER_FREQ_CNFG 0x1AC
>  
> -#define DPLL1_PHASE_OFFSET_CNFG 0x143
> -#define DPLL2_PHASE_OFFSET_CNFG 0x1C3
> +#define SABRE_DPLL1_PHASE_OFFSET_CNFG 0x143
> +#define SABRE_DPLL2_PHASE_OFFSET_CNFG 0x1C3
>  
> -#define DPLL1_SYNC_EDGE_CNFG 0x140
> -#define DPLL2_SYNC_EDGE_CNFG 0x1C0
> +#define SABRE_DPLL1_SYNC_EDGE_CNFG 0x140
> +#define SABRE_DPLL2_SYNC_EDGE_CNFG 0x1C0
>  
> -#define DPLL1_INPUT_MODE_CNFG 0x116
> -#define DPLL2_INPUT_MODE_CNFG 0x196
> +#define SABRE_DPLL1_INPUT_MODE_CNFG 0x116
> +#define SABRE_DPLL2_INPUT_MODE_CNFG 0x196
>  
> -#define DPLL1_OPERATING_STS 0x102
> -#define DPLL2_OPERATING_STS 0x182
> +#define SABRE_DPLL1_OPERATING_STS 0x102
> +#define SABRE_DPLL2_OPERATING_STS 0x182
>  
> -#define DPLL1_CURRENT_FREQ_STS 0x103
> -#define DPLL2_CURRENT_FREQ_STS 0x183
> +#define SABRE_DPLL1_CURRENT_FREQ_STS 0x103
> +#define SABRE_DPLL2_CURRENT_FREQ_STS 0x183
>  
> -#define REG_SOFT_RESET 0X381
> +#define SABRE_REG_SOFT_RESET 0X381
>  
> -#define OUT_MUX_CNFG(outn) REG_ADDR(0x6, (0xC * (outn)))
> +#define SABRE_OUT_MUX_CNFG(outn) REG_ADDR(0x6, (0xC * (outn)))
>  
>  /* Register bit definitions */
> -#define SYNC_TOD BIT(1)
> -#define PH_OFFSET_EN BIT(7)
> -#define SQUELCH_ENABLE BIT(5)
> +#define SABRE_SYNC_TOD BIT(1)
> +#define SABRE_PH_OFFSET_EN BIT(7)
> +#define SABRE_SQUELCH_ENABLE BIT(5)
>  
>  /* Bit definitions for the DPLL_MODE register */
> -#define PLL_MODE_SHIFT		(0)
> -#define PLL_MODE_MASK		(0x1F)
> -#define COMBO_MODE_EN		BIT(5)
> -#define COMBO_MODE_SHIFT	(6)
> -#define COMBO_MODE_MASK		(0x3)
> +#define SABRE_PLL_MODE_SHIFT		(0)
> +#define SABRE_PLL_MODE_MASK		(0x1F)
> +#define SABRE_COMBO_MODE_EN		BIT(5)
> +#define SABRE_COMBO_MODE_SHIFT	(6)
> +#define SABRE_COMBO_MODE_MASK		(0x3)
>  
>  /* Bit definitions for DPLL_OPERATING_STS register */
> -#define OPERATING_STS_MASK	(0x7)
> -#define OPERATING_STS_SHIFT	(0x0)
> +#define SABRE_OPERATING_STS_MASK	(0x7)
> +#define SABRE_OPERATING_STS_SHIFT	(0x0)
>  
>  /* Bit definitions for DPLL_TOD_TRIGGER register */
> -#define READ_TRIGGER_MASK	(0xF)
> -#define READ_TRIGGER_SHIFT	(0x0)
> -#define WRITE_TRIGGER_MASK	(0xF0)
> -#define WRITE_TRIGGER_SHIFT	(0x4)
> +#define SABRE_READ_TRIGGER_MASK	(0xF)
> +#define SABRE_READ_TRIGGER_SHIFT	(0x0)
> +#define SABRE_WRITE_TRIGGER_MASK	(0xF0)
> +#define SABRE_WRITE_TRIGGER_SHIFT	(0x4)
>  
>  /* Bit definitions for REG_SOFT_RESET register */
> -#define SOFT_RESET_EN		BIT(7)
> -
> -enum pll_mode {
> -	PLL_MODE_MIN = 0,
> -	PLL_MODE_AUTOMATIC = PLL_MODE_MIN,
> -	PLL_MODE_FORCE_FREERUN = 1,
> -	PLL_MODE_FORCE_HOLDOVER = 2,
> -	PLL_MODE_FORCE_LOCKED = 4,
> -	PLL_MODE_FORCE_PRE_LOCKED2 = 5,
> -	PLL_MODE_FORCE_PRE_LOCKED = 6,
> -	PLL_MODE_FORCE_LOST_PHASE = 7,
> -	PLL_MODE_DCO = 10,
> -	PLL_MODE_WPH = 18,
> -	PLL_MODE_MAX = PLL_MODE_WPH,
> +#define SABRE_SOFT_RESET_EN		BIT(7)
> +
> +enum sabre_pll_mode {
> +	SABRE_PLL_MODE_MIN = 0,
> +	SABRE_PLL_MODE_AUTOMATIC = SABRE_PLL_MODE_MIN,
> +	SABRE_PLL_MODE_FORCE_FREERUN = 1,
> +	SABRE_PLL_MODE_FORCE_HOLDOVER = 2,
> +	SABRE_PLL_MODE_FORCE_LOCKED = 4,
> +	SABRE_PLL_MODE_FORCE_PRE_LOCKED2 = 5,
> +	SABRE_PLL_MODE_FORCE_PRE_LOCKED = 6,
> +	SABRE_PLL_MODE_FORCE_LOST_PHASE = 7,
> +	SABRE_PLL_MODE_DCO = 10,
> +	SABRE_PLL_MODE_WPH = 18,
> +	SABRE_PLL_MODE_MAX = SABRE_PLL_MODE_WPH,
>  };
>  
> -enum hw_tod_trig_sel {
> -	HW_TOD_TRIG_SEL_MIN = 0,
> -	HW_TOD_TRIG_SEL_NO_WRITE = HW_TOD_TRIG_SEL_MIN,
> -	HW_TOD_TRIG_SEL_NO_READ = HW_TOD_TRIG_SEL_MIN,
> -	HW_TOD_TRIG_SEL_SYNC_SEL = 1,
> -	HW_TOD_TRIG_SEL_IN12 = 2,
> -	HW_TOD_TRIG_SEL_IN13 = 3,
> -	HW_TOD_TRIG_SEL_IN14 = 4,
> -	HW_TOD_TRIG_SEL_TOD_PPS = 5,
> -	HW_TOD_TRIG_SEL_TIMER_INTERVAL = 6,
> -	HW_TOD_TRIG_SEL_MSB_PHASE_OFFSET_CNFG = 7,
> -	HW_TOD_TRIG_SEL_MSB_HOLDOVER_FREQ_CNFG = 8,
> -	HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG = 9,
> -	HW_TOD_RD_TRIG_SEL_LSB_TOD_STS = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
> -	WR_TRIG_SEL_MAX = HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
> +enum sabre_hw_tod_trig_sel {
> +	SABRE_HW_TOD_TRIG_SEL_MIN = 0,
> +	SABRE_HW_TOD_TRIG_SEL_NO_WRITE = SABRE_HW_TOD_TRIG_SEL_MIN,
> +	SABRE_HW_TOD_TRIG_SEL_NO_READ = SABRE_HW_TOD_TRIG_SEL_MIN,
> +	SABRE_HW_TOD_TRIG_SEL_SYNC_SEL = 1,
> +	SABRE_HW_TOD_TRIG_SEL_IN12 = 2,
> +	SABRE_HW_TOD_TRIG_SEL_IN13 = 3,
> +	SABRE_HW_TOD_TRIG_SEL_IN14 = 4,
> +	SABRE_HW_TOD_TRIG_SEL_TOD_PPS = 5,
> +	SABRE_HW_TOD_TRIG_SEL_TIMER_INTERVAL = 6,
> +	SABRE_HW_TOD_TRIG_SEL_MSB_PHASE_OFFSET_CNFG = 7,
> +	SABRE_HW_TOD_TRIG_SEL_MSB_HOLDOVER_FREQ_CNFG = 8,
> +	SABRE_HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG = 9,
> +	SABRE_HW_TOD_RD_TRIG_SEL_LSB_TOD_STS = SABRE_HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
> +	SABRE_WR_TRIG_SEL_MAX = SABRE_HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
>  };
>  
>  /** @brief Enumerated type listing DPLL operational modes */
> -enum dpll_state {
> -	DPLL_STATE_FREERUN = 1,
> -	DPLL_STATE_HOLDOVER = 2,
> -	DPLL_STATE_LOCKED = 4,
> -	DPLL_STATE_PRELOCKED2 = 5,
> -	DPLL_STATE_PRELOCKED = 6,
> -	DPLL_STATE_LOSTPHASE = 7,
> -	DPLL_STATE_MAX
> +enum sabre_dpll_state {
> +	SABRE_DPLL_STATE_FREERUN = 1,
> +	SABRE_DPLL_STATE_HOLDOVER = 2,
> +	SABRE_DPLL_STATE_LOCKED = 4,
> +	SABRE_DPLL_STATE_PRELOCKED2 = 5,
> +	SABRE_DPLL_STATE_PRELOCKED = 6,
> +	SABRE_DPLL_STATE_LOSTPHASE = 7,
> +	SABRE_DPLL_STATE_MAX
>  };
>  
>  #endif
> -- 
> 2.7.4
> 

Wait, how can this patch on its own not break things?  Are there no
in-kernel users of these symbols today?  If not, why is this file in
here?

confused,

greg k-h

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

* Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-15 18:47 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
@ 2021-09-16  5:25   ` Greg KH
  2021-09-16 15:33     ` Min Li
  2021-09-16 11:31   ` kernel test robot
  1 sibling, 1 reply; 16+ messages in thread
From: Greg KH @ 2021-09-16  5:25 UTC (permalink / raw)
  To: min.li.xe; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

On Wed, Sep 15, 2021 at 02:47:09PM -0400, min.li.xe@renesas.com wrote:
> From: Min Li <min.li.xe@renesas.com>
> 
> This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
> of timing and synchronization devices.It will be used by Renesas PTP Clock
> Manager for Linux (pcm4l) software to provide support to GNSS assisted
> partial timing support (APTS) and other networking timing functions.

Where is that software?

Why is this new api not a standard one?

What is the standard here?

What do other devices do and why is this a new api?

> Current version provides kernel API's to support the following functions
> -set combomode to enable SYNCE clock support
> -read dpll's state to determine if the dpll is locked to the GNSS channel
> -read dpll's ffo (fractional frequency offset) in ppqt

Why do all of these have to be in the kernel at all?

thanks,

greg k-h

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

* Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-15 18:47 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
  2021-09-16  5:25   ` Greg KH
@ 2021-09-16 11:31   ` kernel test robot
  1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2021-09-16 11:31 UTC (permalink / raw)
  To: min.li.xe, arnd, gregkh, derek.kiernan, dragan.cvetic
  Cc: kbuild-all, linux-kernel, lee.jones, Min Li

[-- Attachment #1: Type: text/plain, Size: 2485 bytes --]

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on char-misc/char-misc-testing]
[also build test WARNING on soc/for-next linus/master v5.15-rc1 next-20210916]
[cannot apply to lee-mfd/for-mfd-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/min-li-xe-renesas-com/mfd-rsmu-Resolve-naming-conflict-between-idt8a340_reg-h-and-idt82p33_reg-h/20210916-024925
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git d06246ebd7738bbfc581b887bc24a102450a323f
config: openrisc-randconfig-r034-20210916 (attached as .config)
compiler: or1k-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/dfbca4a07f1f8ca11b5993215ee233f7f28c1519
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review min-li-xe-renesas-com/mfd-rsmu-Resolve-naming-conflict-between-idt8a340_reg-h-and-idt82p33_reg-h/20210916-024925
        git checkout dfbca4a07f1f8ca11b5993215ee233f7f28c1519
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross ARCH=openrisc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/misc/rsmu.c:54: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
    * Enumerated type listing DPLL combination modes
   drivers/misc/rsmu.c:65: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
    * An id used to identify the respective child class states.


vim +54 drivers/misc/rsmu.c

    52	
    53	/**
  > 54	 * Enumerated type listing DPLL combination modes
    55	 */
    56	enum rsmu_dpll_combomode {
    57		E_COMBOMODE_CURRENT = 0,
    58		E_COMBOMODE_FASTAVG,
    59		E_COMBOMODE_SLOWAVG,
    60		E_COMBOMODE_HOLDOVER,
    61		E_COMBOMODE_MAX
    62	};
    63	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 34362 bytes --]

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

* RE: [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h
  2021-09-16  5:24 ` Greg KH
@ 2021-09-16 14:49   ` Min Li
  0 siblings, 0 replies; 16+ messages in thread
From: Min Li @ 2021-09-16 14:49 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

> >
> 
> Wait, how can this patch on its own not break things?  Are there no
> in-kernel users of these symbols today?  If not, why is this file in
> here?
> 
> confused,
> 
> greg k-h

Yes, it is standalone now but it would be used by this driver and another PHC driver that I will submit later.

This file provides register definitions and belongs to the MFD change I submitted before. The MFD driver will spawn 2 devices

1) ptp hardware clock device
2) This RSMU misc device

The plan is 

1) submit mfd change
2) submit misc change
3) submit phc change

Min




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

* RE: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16  5:25   ` Greg KH
@ 2021-09-16 15:33     ` Min Li
  2021-09-16 15:39       ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Min Li @ 2021-09-16 15:33 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones



> -----Original Message-----
> From: Greg KH <gregkh@linuxfoundation.org>
> Sent: September 16, 2021 1:26 AM
> To: Min Li <min.li.xe@renesas.com>
> Cc: arnd@arndb.de; derek.kiernan@xilinx.com; dragan.cvetic@xilinx.com;
> linux-kernel@vger.kernel.org; lee.jones@linaro.or
> Subject: Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization
> Management Unit (SMU) support
> 
> On Wed, Sep 15, 2021 at 02:47:09PM -0400, min.li.xe@renesas.com wrote:
> > From: Min Li <min.li.xe@renesas.com>
> >
> > This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx
> > families of timing and synchronization devices.It will be used by
> > Renesas PTP Clock Manager for Linux (pcm4l) software to provide
> > support to GNSS assisted partial timing support (APTS) and other
> networking timing functions.
> 
> Where is that software?

https://www.renesas.com/us/en/software-tool/ptp-clock-manager-linux

> 
> Why is this new api not a standard one?
> 

There is no actual standard for the GNSS assisted partial timing support (APTS)
In terms of Linux kernel API

> What is the standard here?
> 
> What do other devices do and why is this a new api?
> 

There is really no standard for APTS and different company has its own hw/sw solutions

> > Current version provides kernel API's to support the following
> > functions -set combomode to enable SYNCE clock support -read dpll's
> > state to determine if the dpll is locked to the GNSS channel -read
> > dpll's ffo (fractional frequency offset) in ppqt
> 
> Why do all of these have to be in the kernel at all?
> 

Because all these API's need spi/i2c accesses to the RSMU card and spi/i2c accesses have been
abstracted to the MFD driver in kernel

> thanks,
> 
> greg k-h

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

* Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 15:33     ` Min Li
@ 2021-09-16 15:39       ` Greg KH
  2021-09-16 15:54         ` Min Li
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2021-09-16 15:39 UTC (permalink / raw)
  To: Min Li; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

On Thu, Sep 16, 2021 at 03:33:06PM +0000, Min Li wrote:
> 
> 
> > -----Original Message-----
> > From: Greg KH <gregkh@linuxfoundation.org>
> > Sent: September 16, 2021 1:26 AM
> > To: Min Li <min.li.xe@renesas.com>
> > Cc: arnd@arndb.de; derek.kiernan@xilinx.com; dragan.cvetic@xilinx.com;
> > linux-kernel@vger.kernel.org; lee.jones@linaro.or
> > Subject: Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization
> > Management Unit (SMU) support
> > 
> > On Wed, Sep 15, 2021 at 02:47:09PM -0400, min.li.xe@renesas.com wrote:
> > > From: Min Li <min.li.xe@renesas.com>
> > >
> > > This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx
> > > families of timing and synchronization devices.It will be used by
> > > Renesas PTP Clock Manager for Linux (pcm4l) software to provide
> > > support to GNSS assisted partial timing support (APTS) and other
> > networking timing functions.
> > 
> > Where is that software?
> 
> https://www.renesas.com/us/en/software-tool/ptp-clock-manager-linux

Please put that link in the changelog comment and in the .c code as well
so that people know where to find it.

> > 
> > Why is this new api not a standard one?
> > 
> 
> There is no actual standard for the GNSS assisted partial timing support (APTS)
> In terms of Linux kernel API

Then make one!  :)

> > What is the standard here?
> > 
> > What do other devices do and why is this a new api?
> > 
> 
> There is really no standard for APTS and different company has its own hw/sw solutions

But userspace has to all deal with this in a standard way somehow,
right?  What libraries and apis do they interact with there?

> > > Current version provides kernel API's to support the following
> > > functions -set combomode to enable SYNCE clock support -read dpll's
> > > state to determine if the dpll is locked to the GNSS channel -read
> > > dpll's ffo (fractional frequency offset) in ppqt
> > 
> > Why do all of these have to be in the kernel at all?
> > 
> 
> Because all these API's need spi/i2c accesses to the RSMU card and spi/i2c accesses have been
> abstracted to the MFD driver in kernel

Why not just do this all from userspace then?  You can have spi/i2c
userspace code, right?  Why does this have to be a kernel driver?

thanks,

greg k-h

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

* RE: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 15:39       ` Greg KH
@ 2021-09-16 15:54         ` Min Li
  2021-09-16 16:05           ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Min Li @ 2021-09-16 15:54 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

> 
> Please put that link in the changelog comment and in the .c code as well so
> that people know where to find it.
> 
> > >
> > > Why is this new api not a standard one?
> > >
> >
> > There is no actual standard for the GNSS assisted partial timing
> > support (APTS) In terms of Linux kernel API
> 
> Then make one!  :)

Yes it is on our roadmap to do that for next release

> 
> > > What is the standard here?
> > >
> > > What do other devices do and why is this a new api?
> > >
> >
> > There is really no standard for APTS and different company has its own
> > hw/sw solutions
> 
> But userspace has to all deal with this in a standard way somehow, right?
> What libraries and apis do they interact with there?

So far there is none. Some companies just use userspace driver and don't bother
kernel

> 
> > > > Current version provides kernel API's to support the following
> > > > functions -set combomode to enable SYNCE clock support -read
> > > > dpll's state to determine if the dpll is locked to the GNSS
> > > > channel -read dpll's ffo (fractional frequency offset) in ppqt
> > >
> > > Why do all of these have to be in the kernel at all?
> > >
> >
> > Because all these API's need spi/i2c accesses to the RSMU card and
> > spi/i2c accesses have been abstracted to the MFD driver in kernel
> 
> Why not just do this all from userspace then?  You can have spi/i2c
> userspace code, right?  Why does this have to be a kernel driver?
> 
We used to do everything in userspace. But since PHC (ptp hardware clock) came along, we decided
to move the driver part to kernel. Please take a look at drivers/ptp/ptp_clockmatrix.c for reference.
Recently, we have some functions like APTS that doesn't belong to PTP or anything else so we have to split those functions
to RSMU misc driver and i2c/spi bus accesses to RSMU MFD driver.


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

* Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 15:54         ` Min Li
@ 2021-09-16 16:05           ` Greg KH
  2021-09-16 17:01             ` Min Li
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2021-09-16 16:05 UTC (permalink / raw)
  To: Min Li; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

On Thu, Sep 16, 2021 at 03:54:52PM +0000, Min Li wrote:
> > 
> > Please put that link in the changelog comment and in the .c code as well so
> > that people know where to find it.
> > 
> > > >
> > > > Why is this new api not a standard one?
> > > >
> > >
> > > There is no actual standard for the GNSS assisted partial timing
> > > support (APTS) In terms of Linux kernel API
> > 
> > Then make one!  :)
> 
> Yes it is on our roadmap to do that for next release

Please do it for this kernel api, otherwise you have to support this for
the next 20+ years as-is :(

> > Why not just do this all from userspace then?  You can have spi/i2c
> > userspace code, right?  Why does this have to be a kernel driver?
> > 
> We used to do everything in userspace. But since PHC (ptp hardware clock) came along, we decided
> to move the driver part to kernel. Please take a look at drivers/ptp/ptp_clockmatrix.c for reference.
> Recently, we have some functions like APTS that doesn't belong to PTP or anything else so we have to split those functions
> to RSMU misc driver and i2c/spi bus accesses to RSMU MFD driver.

I still do not understand why this has to be a kernel driver, sorry.
What exactly forces it to be that way?

thanks,

greg k-h

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

* RE: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 16:05           ` Greg KH
@ 2021-09-16 17:01             ` Min Li
  2021-09-16 17:22               ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Min Li @ 2021-09-16 17:01 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones



> -----Original Message-----
> From: Greg KH <gregkh@linuxfoundation.org>
> Sent: September 16, 2021 12:05 PM
> To: Min Li <min.li.xe@renesas.com>
> Cc: arnd@arndb.de; derek.kiernan@xilinx.com; dragan.cvetic@xilinx.com;
> linux-kernel@vger.kernel.org; lee.jones@linaro.or
> Subject: Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization
> Management Unit (SMU) support
> 
> On Thu, Sep 16, 2021 at 03:54:52PM +0000, Min Li wrote:
> > >
> > > Please put that link in the changelog comment and in the .c code as
> > > well so that people know where to find it.
> > >
> > > > >
> > > > > Why is this new api not a standard one?
> > > > >
> > > >
> > > > There is no actual standard for the GNSS assisted partial timing
> > > > support (APTS) In terms of Linux kernel API
> > >
> > > Then make one!  :)
> >
> > Yes it is on our roadmap to do that for next release
> 
> Please do it for this kernel api, otherwise you have to support this for the
> next 20+ years as-is :(
> 

In that case, I would have to get back to you in a few months. If you are rejecting this
change due to this reason. Please tell me explicitly so that I can copy paste to my manager
and that would be it. Thanks 

> > > Why not just do this all from userspace then?  You can have spi/i2c
> > > userspace code, right?  Why does this have to be a kernel driver?
> > >
> > We used to do everything in userspace. But since PHC (ptp hardware
> > clock) came along, we decided to move the driver part to kernel. Please
> take a look at drivers/ptp/ptp_clockmatrix.c for reference.
> > Recently, we have some functions like APTS that doesn't belong to PTP
> > or anything else so we have to split those functions to RSMU misc driver
> and i2c/spi bus accesses to RSMU MFD driver.
> 
> I still do not understand why this has to be a kernel driver, sorry.
> What exactly forces it to be that way?
> 
That is our management decision since everyone is trying to move their driver to Linux kernel
to contribute so that we don't have to release the driver to each customer separately. The customer
can just grab the driver from linux

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

* Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 17:01             ` Min Li
@ 2021-09-16 17:22               ` Greg KH
  0 siblings, 0 replies; 16+ messages in thread
From: Greg KH @ 2021-09-16 17:22 UTC (permalink / raw)
  To: Min Li; +Cc: arnd, derek.kiernan, dragan.cvetic, linux-kernel, lee.jones

On Thu, Sep 16, 2021 at 05:01:10PM +0000, Min Li wrote:
> 
> 
> > -----Original Message-----
> > From: Greg KH <gregkh@linuxfoundation.org>
> > Sent: September 16, 2021 12:05 PM
> > To: Min Li <min.li.xe@renesas.com>
> > Cc: arnd@arndb.de; derek.kiernan@xilinx.com; dragan.cvetic@xilinx.com;
> > linux-kernel@vger.kernel.org; lee.jones@linaro.or
> > Subject: Re: [PATCH misc v2 2/2] misc: Add Renesas Synchronization
> > Management Unit (SMU) support
> > 
> > On Thu, Sep 16, 2021 at 03:54:52PM +0000, Min Li wrote:
> > > >
> > > > Please put that link in the changelog comment and in the .c code as
> > > > well so that people know where to find it.
> > > >
> > > > > >
> > > > > > Why is this new api not a standard one?
> > > > > >
> > > > >
> > > > > There is no actual standard for the GNSS assisted partial timing
> > > > > support (APTS) In terms of Linux kernel API
> > > >
> > > > Then make one!  :)
> > >
> > > Yes it is on our roadmap to do that for next release
> > 
> > Please do it for this kernel api, otherwise you have to support this for the
> > next 20+ years as-is :(
> > 
> 
> In that case, I would have to get back to you in a few months. If you are rejecting this
> change due to this reason. Please tell me explicitly so that I can copy paste to my manager
> and that would be it. Thanks 

Please come up with a unified api that will work with all devices of
this type, and not a one-off ioctl with random structures in it that are
directly tied to the hardware.

> > > > Why not just do this all from userspace then?  You can have spi/i2c
> > > > userspace code, right?  Why does this have to be a kernel driver?
> > > >
> > > We used to do everything in userspace. But since PHC (ptp hardware
> > > clock) came along, we decided to move the driver part to kernel. Please
> > take a look at drivers/ptp/ptp_clockmatrix.c for reference.
> > > Recently, we have some functions like APTS that doesn't belong to PTP
> > > or anything else so we have to split those functions to RSMU misc driver
> > and i2c/spi bus accesses to RSMU MFD driver.
> > 
> > I still do not understand why this has to be a kernel driver, sorry.
> > What exactly forces it to be that way?
> > 
> That is our management decision since everyone is trying to move their driver to Linux kernel
> to contribute so that we don't have to release the driver to each customer separately. The customer
> can just grab the driver from linux

Don't use the kernel as your distribution method for things that should
not belong in the kernel.  There is no need for creating and maintain
kernel modules for drivers that do not need to be drivers at all.  That
feels like you would be doing extra work here.  Writing a simple
userspace library for this that works for all kernel versions would be
much easier.

thanks,

greg k-h

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

* [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 16:11 min.li.xe
@ 2021-09-16 16:11 ` min.li.xe
  0 siblings, 0 replies; 16+ messages in thread
From: min.li.xe @ 2021-09-16 16:11 UTC (permalink / raw)
  To: arnd, gregkh, derek.kiernan, dragan.cvetic
  Cc: linux-kernel, lee.jones, Min Li

From: Min Li <min.li.xe@renesas.com>

This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
of timing and synchronization devices.It will be used by Renesas PTP Clock
Manager for Linux (pcm4l) software to provide support to GNSS assisted
partial timing support (APTS) and other networking timing functions.

Current version provides kernel API's to support the following functions
-set combomode to enable SYNCE clock support
-read dpll's state to determine if the dpll is locked to the GNSS channel
-read dpll's ffo (fractional frequency offset) in ppqt

Signed-off-by: Min Li <min.li.xe@renesas.com>
---
Change log
-simply design by using only one c file suggested by Greg
-add pcm4l link for reference

 drivers/misc/Kconfig      |  11 +
 drivers/misc/Makefile     |   1 +
 drivers/misc/rsmu.c       | 539 ++++++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/rsmu.h |  66 ++++++
 4 files changed, 617 insertions(+)
 create mode 100644 drivers/misc/rsmu.c
 create mode 100644 include/uapi/linux/rsmu.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 85ba901..c0a1746 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -469,6 +469,17 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config RSMU
+	tristate "Renesas Synchronization Management Unit (SMU)"
+	help
+	  This option enables support for RSMU (Renesas Synchronization
+	  Management Unit) driver. It will be used by Renesas PTP Clock Manager
+	  for Linux (pcm4l) software to provide support for GNSS assisted
+	  partial timing support (APTS) and other networking timing functions.
+
+	  For pcm4l, please refer the following link for more details
+	  https://www.renesas.com/us/en/software-tool/ptp-clock-manager-linux
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a086197..a66e3b7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE)		+= uacce/
 obj-$(CONFIG_XILINX_SDFEC)	+= xilinx_sdfec.o
 obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
 obj-$(CONFIG_HI6421V600_IRQ)	+= hi6421v600-irq.o
+obj-$(CONFIG_RSMU)		+= rsmu.o
diff --git a/drivers/misc/rsmu.c b/drivers/misc/rsmu.c
new file mode 100644
index 0000000..2d938f8
--- /dev/null
+++ b/drivers/misc/rsmu.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
+ * of timing and synchronization devices. It will be used by Renesas PTP Clock
+ * Manager for Linux (pcm4l) software to provide support to GNSS assisted
+ * partial timing support (APTS) and other networking timing functions.
+ *
+ * Please note it must work with Renesas MFD driver to access device through
+ * I2C/SPI. 
+ * 
+ * For pcm4l, please refer the following link for more details
+ * https://www.renesas.com/us/en/software-tool/ptp-clock-manager-linux
+ *
+ * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/idt8a340_reg.h>
+#include <linux/mfd/idt82p33_reg.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+
+static DEFINE_IDA(rsmu_cdev_map);
+
+/*
+ * struct rsmu_cdev - Driver data for RSMU character device
+ * @name: rsmu device name as rsmu[index]
+ * @dev: pointer to platform device
+ * @miscdev: character device handle
+ * @regmap: I2C/SPI regmap handle
+ * @lock: mutex to protect operations from being interrupted
+ * @type: rsmu device type, passed through platform data
+ * @index: rsmu device index
+ */
+struct rsmu_cdev {
+	char name[16];
+	struct device *dev;
+	struct miscdevice miscdev;
+	struct regmap *regmap;
+	struct mutex *lock;
+	enum rsmu_type type;
+	int index;
+};
+
+/*
+ * Enumerated type listing DPLL combination modes
+ */
+enum rsmu_dpll_combomode {
+	E_COMBOMODE_CURRENT = 0,
+	E_COMBOMODE_FASTAVG,
+	E_COMBOMODE_SLOWAVG,
+	E_COMBOMODE_HOLDOVER,
+	E_COMBOMODE_MAX
+};
+
+/*
+ * An id used to identify the respective child class states.
+ */
+enum rsmu_class_state {
+	E_SRVLOINITIALSTATE = 0,
+	E_SRVLOUNQUALIFIEDSTATE = 1,
+	E_SRVLOLOCKACQSTATE = 2,
+	E_SRVLOFREQUENCYLOCKEDSTATE = 3,
+	E_SRVLOTIMELOCKEDSTATE = 4,
+	E_SRVLOHOLDOVERINSPECSTATE = 5,
+	E_SRVLOHOLDOVEROUTOFSPECSTATE = 6,
+	E_SRVLOFREERUNSTATE = 7,
+	E_SRVNUMBERLOSTATES = 8,
+	E_SRVLOSTATEINVALID = 9,
+};
+
+/*======================== Sabre functions start ==========================*/
+static int rsmu_sabre_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = SABRE_DPLL1_OPERATING_MODE_CNFG;
+		break;
+	case 1:
+		dpll_ctrl_n = SABRE_DPLL2_OPERATING_MODE_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	cfg &= ~(SABRE_COMBO_MODE_MASK << SABRE_COMBO_MODE_SHIFT);
+	cfg |= mode << SABRE_COMBO_MODE_SHIFT;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+}
+
+static int rsmu_sabre_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u16 dpll_sts_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_sts_n = SABRE_DPLL1_OPERATING_STS;
+		break;
+	case 1:
+		dpll_sts_n = SABRE_DPLL2_OPERATING_STS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_sts_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & SABRE_OPERATING_STS_MASK) {
+	case SABRE_DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_PRELOCKED2:
+	case SABRE_DPLL_STATE_PRELOCKED:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case SABRE_DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_sabre_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				   struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_freq_n;
+	int err;
+
+	/*
+	 * IDTDpll_GetCurrentDpllFreqOffset retrieves the FFO integrator only.
+	 * In order to get Proportional + Integrator, use the holdover FFO with
+	 * the filter bandwidth 0.5 Hz set by TCS file.
+	 */
+	switch (dpll) {
+	case 0:
+		dpll_freq_n = SABRE_DPLL1_HOLDOVER_FREQ_CNFG;
+		break;
+	case 1:
+		dpll_freq_n = SABRE_DPLL2_HOLDOVER_FREQ_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_freq_n, buf, 5);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 39);
+
+	/* FCW unit is 77760 / ( 1638400 * 2^48) = 1.68615121864946 * 10^-16 */
+	ffo->ffo = div_s64(fcw * 2107689, 12500);
+
+	return 0;
+}
+/*======================== Sabre functions end ==========================*/
+
+/*======================== Clockmatrix functions start ==================*/
+static int rsmu_cm_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = DPLL_CTRL_0;
+		break;
+	case 1:
+		dpll_ctrl_n = DPLL_CTRL_1;
+		break;
+	case 2:
+		dpll_ctrl_n = DPLL_CTRL_2;
+		break;
+	case 3:
+		dpll_ctrl_n = DPLL_CTRL_3;
+		break;
+	case 4:
+		dpll_ctrl_n = DPLL_CTRL_4;
+		break;
+	case 5:
+		dpll_ctrl_n = DPLL_CTRL_5;
+		break;
+	case 6:
+		dpll_ctrl_n = DPLL_CTRL_6;
+		break;
+	case 7:
+		dpll_ctrl_n = DPLL_CTRL_7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+			       &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	/* Only need to enable/disable COMBO_MODE_HOLD. */
+	if (mode)
+		cfg |= COMBO_MASTER_HOLD;
+	else
+		cfg &= ~COMBO_MASTER_HOLD;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+				 &cfg, sizeof(cfg));
+}
+
+static int rsmu_cm_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u8 cfg;
+	int err;
+
+	/* 8 is sys dpll */
+	if (dpll > 8)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + DPLL0_STATUS + dpll, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & DPLL_STATE_MASK) {
+	case DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case DPLL_STATE_LOCKACQ:
+	case DPLL_STATE_LOCKREC:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_cm_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_filter_status;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_filter_status = DPLL0_FILTER_STATUS;
+		break;
+	case 1:
+		dpll_filter_status = DPLL1_FILTER_STATUS;
+		break;
+	case 2:
+		dpll_filter_status = DPLL2_FILTER_STATUS;
+		break;
+	case 3:
+		dpll_filter_status = DPLL3_FILTER_STATUS;
+		break;
+	case 4:
+		dpll_filter_status = DPLL4_FILTER_STATUS;
+		break;
+	case 5:
+		dpll_filter_status = DPLL5_FILTER_STATUS;
+		break;
+	case 6:
+		dpll_filter_status = DPLL6_FILTER_STATUS;
+		break;
+	case 7:
+		dpll_filter_status = DPLL7_FILTER_STATUS;
+		break;
+	case 8:
+		dpll_filter_status = DPLLSYS_FILTER_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + dpll_filter_status, buf, 6);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 47);
+
+	/* FCW unit is 2 ^ -53 = 1.1102230246251565404236316680908e-16 */
+	ffo->ffo = fcw * 111;
+
+	return 0;
+}
+/*======================== Clockmatrix functions end ==================*/
+
+static int
+rsmu_set_combomode(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_combomode mode;
+	int err;
+
+	if (copy_from_user(&mode, arg, sizeof(mode)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err)
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_state(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_state state_request;
+	u8 state;
+	int err;
+
+	if (copy_from_user(&state_request, arg, sizeof(state_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	state_request.state = state;
+	if (copy_to_user(arg, &state_request, sizeof(state_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_ffo(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_ffo ffo_request;
+	int err;
+
+	if (copy_from_user(&ffo_request, arg, sizeof(ffo_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	if (copy_to_user(arg, &ffo_request, sizeof(ffo_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static struct rsmu_cdev *file2rsmu(struct file *file)
+{
+	return container_of(file->private_data, struct rsmu_cdev, miscdev);
+}
+
+static long
+rsmu_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
+{
+	struct rsmu_cdev *rsmu = file2rsmu(fptr);
+	void __user *arg = (void __user *)data;
+	int err = 0;
+
+	switch (cmd) {
+	case RSMU_SET_COMBOMODE:
+		err = rsmu_set_combomode(rsmu, arg);
+		break;
+	case RSMU_GET_STATE:
+		err = rsmu_get_dpll_state(rsmu, arg);
+		break;
+	case RSMU_GET_FFO:
+		err = rsmu_get_dpll_ffo(rsmu, arg);
+		break;
+	default:
+		/* Should not get here */
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static const struct file_operations rsmu_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = rsmu_ioctl,
+};
+
+static int
+rsmu_probe(struct platform_device *pdev)
+{
+	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct rsmu_cdev *rsmu;
+	int err;
+
+	rsmu = devm_kzalloc(&pdev->dev, sizeof(*rsmu), GFP_KERNEL);
+	if (!rsmu)
+		return -ENOMEM;
+
+	/* Save driver private data */
+	platform_set_drvdata(pdev, rsmu);
+
+	rsmu->dev = &pdev->dev;
+	rsmu->type = ddata->type;
+	rsmu->lock = &ddata->lock;
+	rsmu->regmap = ddata->regmap;
+	rsmu->index = ida_simple_get(&rsmu_cdev_map, 0, MINORMASK + 1, GFP_KERNEL);
+	if (rsmu->index < 0) {
+		dev_err(rsmu->dev, "Unable to get index %d\n", rsmu->index);
+		return rsmu->index;
+	}
+	snprintf(rsmu->name, sizeof(rsmu->name), "rsmu%d", rsmu->index);
+
+	/* Initialize and register the miscdev */
+	rsmu->miscdev.minor = MISC_DYNAMIC_MINOR;
+	rsmu->miscdev.fops = &rsmu_fops;
+	rsmu->miscdev.name = rsmu->name;
+	err = misc_register(&rsmu->miscdev);
+	if (err) {
+		dev_err(rsmu->dev, "Unable to register device\n");
+		ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int
+rsmu_remove(struct platform_device *pdev)
+{
+	struct rsmu_cdev *rsmu = platform_get_drvdata(pdev);
+
+	misc_deregister(&rsmu->miscdev);
+	ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+
+	return 0;
+}
+
+static const struct platform_device_id rsmu_id_table[] = {
+	{ "8a3400x-cdev", RSMU_CM},
+	{ "82p33x1x-cdev", RSMU_SABRE},
+	{}
+};
+MODULE_DEVICE_TABLE(platform, rsmu_id_table);
+
+static struct platform_driver rsmu_driver = {
+	.driver = {
+		.name = "rsmu-cdev",
+	},
+	.probe = rsmu_probe,
+	.remove =  rsmu_remove,
+	.id_table = rsmu_id_table,
+};
+
+module_platform_driver(rsmu_driver);
+
+MODULE_DESCRIPTION("Renesas SMU character device driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/rsmu.h b/include/uapi/linux/rsmu.h
new file mode 100644
index 0000000..e1cd43a
--- /dev/null
+++ b/include/uapi/linux/rsmu.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Driver for the IDT ClockMatrix(TM) and 82p33xxx families of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#ifndef __UAPI_LINUX_RSMU_CDEV_H
+#define __UAPI_LINUX_RSMU_CDEV_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Set dpll combomode */
+struct rsmu_combomode {
+	__u8 dpll;
+	__u8 mode;
+};
+
+/* Get dpll state */
+struct rsmu_get_state {
+	__u8 dpll;
+	__u8 state;
+};
+
+/* Get dpll ffo (fractional frequency offset) in ppqt */
+struct rsmu_get_ffo {
+	__u8 dpll;
+	__s64 ffo;
+};
+
+/*
+ * RSMU IOCTL List
+ */
+#define RSMU_MAGIC '?'
+
+/**
+ * struct rsmu_combomode
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @mode: combomode setting, see enum rsmu_dpll_combomode
+ *
+ * ioctl to set SMU combo mode.Combo mode provides physical layer frequency
+ * support from the Ethernet Equipment Clock to the PTP clock
+ */
+#define RSMU_SET_COMBOMODE  _IOW(RSMU_MAGIC, 1, struct rsmu_combomode)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @state: dpll state, see enum rsmu_class_state
+ *
+ * ioctl to get SMU dpll state. Application can call this API to tell if
+ * SMU is locked to the GNSS signal
+ */
+#define RSMU_GET_STATE  _IOR(RSMU_MAGIC, 2, struct rsmu_get_state)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @ffo: dpll's ffo (fractional frequency offset) in ppqt
+ *
+ * ioctl to get SMU dpll ffo (fractional frequency offset).
+ */
+#define RSMU_GET_FFO  _IOR(RSMU_MAGIC, 3, struct rsmu_get_ffo)
+#endif /* __UAPI_LINUX_RSMU_CDEV_H */
-- 
2.7.4


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

* [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-16 15:41 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
@ 2021-09-16 15:41 ` min.li.xe
  0 siblings, 0 replies; 16+ messages in thread
From: min.li.xe @ 2021-09-16 15:41 UTC (permalink / raw)
  To: arnd, gregkh, derek.kiernan, dragan.cvetic
  Cc: linux-kernel, lee.jones, Min Li

From: Min Li <min.li.xe@renesas.com>

This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
of timing and synchronization devices.It will be used by Renesas PTP Clock
Manager for Linux (pcm4l) software to provide support to GNSS assisted
partial timing support (APTS) and other networking timing functions.

Current version provides kernel API's to support the following functions
-set combomode to enable SYNCE clock support
-read dpll's state to determine if the dpll is locked to the GNSS channel
-read dpll's ffo (fractional frequency offset) in ppqt

Signed-off-by: Min Li <min.li.xe@renesas.com>
---
Change log
-simply design by using only one c file suggested by Greg

 drivers/misc/Kconfig      |   8 +
 drivers/misc/Makefile     |   1 +
 drivers/misc/rsmu.c       | 536 ++++++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/rsmu.h |  66 ++++++
 4 files changed, 611 insertions(+)
 create mode 100644 drivers/misc/rsmu.c
 create mode 100644 include/uapi/linux/rsmu.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 85ba901..6dc36f9 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -469,6 +469,14 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config RSMU
+	tristate "Renesas Synchronization Management Unit (SMU)"
+	help
+	  This option enables support for RSMU (Renesas Synchronization
+	  Management Unit) driver. It will be used by Renesas PTP Clock Manager
+	  for Linux (pcm4l) software to provide support for GNSS assisted
+	  partial timing support (APTS) and other networking timing functions.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a086197..a66e3b7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE)		+= uacce/
 obj-$(CONFIG_XILINX_SDFEC)	+= xilinx_sdfec.o
 obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
 obj-$(CONFIG_HI6421V600_IRQ)	+= hi6421v600-irq.o
+obj-$(CONFIG_RSMU)		+= rsmu.o
diff --git a/drivers/misc/rsmu.c b/drivers/misc/rsmu.c
new file mode 100644
index 0000000..bbea940
--- /dev/null
+++ b/drivers/misc/rsmu.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
+ * of timing and synchronization devices. It will be used by Renesas PTP Clock
+ * Manager for Linux (pcm4l) software to provide support to GNSS assisted
+ * partial timing support (APTS) and other networking timing functions.
+ *
+ * Please note it must work with Renesas MFD driver to access device through
+ * I2C/SPI.
+ *
+ * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/idt8a340_reg.h>
+#include <linux/mfd/idt82p33_reg.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+
+static DEFINE_IDA(rsmu_cdev_map);
+
+/*
+ * struct rsmu_cdev - Driver data for RSMU character device
+ * @name: rsmu device name as rsmu[index]
+ * @dev: pointer to platform device
+ * @miscdev: character device handle
+ * @regmap: I2C/SPI regmap handle
+ * @lock: mutex to protect operations from being interrupted
+ * @type: rsmu device type, passed through platform data
+ * @index: rsmu device index
+ */
+struct rsmu_cdev {
+	char name[16];
+	struct device *dev;
+	struct miscdevice miscdev;
+	struct regmap *regmap;
+	struct mutex *lock;
+	enum rsmu_type type;
+	int index;
+};
+
+/*
+ * Enumerated type listing DPLL combination modes
+ */
+enum rsmu_dpll_combomode {
+	E_COMBOMODE_CURRENT = 0,
+	E_COMBOMODE_FASTAVG,
+	E_COMBOMODE_SLOWAVG,
+	E_COMBOMODE_HOLDOVER,
+	E_COMBOMODE_MAX
+};
+
+/*
+ * An id used to identify the respective child class states.
+ */
+enum rsmu_class_state {
+	E_SRVLOINITIALSTATE = 0,
+	E_SRVLOUNQUALIFIEDSTATE = 1,
+	E_SRVLOLOCKACQSTATE = 2,
+	E_SRVLOFREQUENCYLOCKEDSTATE = 3,
+	E_SRVLOTIMELOCKEDSTATE = 4,
+	E_SRVLOHOLDOVERINSPECSTATE = 5,
+	E_SRVLOHOLDOVEROUTOFSPECSTATE = 6,
+	E_SRVLOFREERUNSTATE = 7,
+	E_SRVNUMBERLOSTATES = 8,
+	E_SRVLOSTATEINVALID = 9,
+};
+
+/*======================== Sabre functions start ==========================*/
+static int rsmu_sabre_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = SABRE_DPLL1_OPERATING_MODE_CNFG;
+		break;
+	case 1:
+		dpll_ctrl_n = SABRE_DPLL2_OPERATING_MODE_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	cfg &= ~(SABRE_COMBO_MODE_MASK << SABRE_COMBO_MODE_SHIFT);
+	cfg |= mode << SABRE_COMBO_MODE_SHIFT;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+}
+
+static int rsmu_sabre_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u16 dpll_sts_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_sts_n = SABRE_DPLL1_OPERATING_STS;
+		break;
+	case 1:
+		dpll_sts_n = SABRE_DPLL2_OPERATING_STS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_sts_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & SABRE_OPERATING_STS_MASK) {
+	case SABRE_DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_PRELOCKED2:
+	case SABRE_DPLL_STATE_PRELOCKED:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case SABRE_DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_sabre_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				   struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_freq_n;
+	int err;
+
+	/*
+	 * IDTDpll_GetCurrentDpllFreqOffset retrieves the FFO integrator only.
+	 * In order to get Proportional + Integrator, use the holdover FFO with
+	 * the filter bandwidth 0.5 Hz set by TCS file.
+	 */
+	switch (dpll) {
+	case 0:
+		dpll_freq_n = SABRE_DPLL1_HOLDOVER_FREQ_CNFG;
+		break;
+	case 1:
+		dpll_freq_n = SABRE_DPLL2_HOLDOVER_FREQ_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_freq_n, buf, 5);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 39);
+
+	/* FCW unit is 77760 / ( 1638400 * 2^48) = 1.68615121864946 * 10^-16 */
+	ffo->ffo = div_s64(fcw * 2107689, 12500);
+
+	return 0;
+}
+/*======================== Sabre functions end ==========================*/
+
+/*======================== Clockmatrix functions start ==================*/
+static int rsmu_cm_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = DPLL_CTRL_0;
+		break;
+	case 1:
+		dpll_ctrl_n = DPLL_CTRL_1;
+		break;
+	case 2:
+		dpll_ctrl_n = DPLL_CTRL_2;
+		break;
+	case 3:
+		dpll_ctrl_n = DPLL_CTRL_3;
+		break;
+	case 4:
+		dpll_ctrl_n = DPLL_CTRL_4;
+		break;
+	case 5:
+		dpll_ctrl_n = DPLL_CTRL_5;
+		break;
+	case 6:
+		dpll_ctrl_n = DPLL_CTRL_6;
+		break;
+	case 7:
+		dpll_ctrl_n = DPLL_CTRL_7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+			       &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	/* Only need to enable/disable COMBO_MODE_HOLD. */
+	if (mode)
+		cfg |= COMBO_MASTER_HOLD;
+	else
+		cfg &= ~COMBO_MASTER_HOLD;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+				 &cfg, sizeof(cfg));
+}
+
+static int rsmu_cm_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u8 cfg;
+	int err;
+
+	/* 8 is sys dpll */
+	if (dpll > 8)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + DPLL0_STATUS + dpll, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & DPLL_STATE_MASK) {
+	case DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case DPLL_STATE_LOCKACQ:
+	case DPLL_STATE_LOCKREC:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_cm_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_filter_status;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_filter_status = DPLL0_FILTER_STATUS;
+		break;
+	case 1:
+		dpll_filter_status = DPLL1_FILTER_STATUS;
+		break;
+	case 2:
+		dpll_filter_status = DPLL2_FILTER_STATUS;
+		break;
+	case 3:
+		dpll_filter_status = DPLL3_FILTER_STATUS;
+		break;
+	case 4:
+		dpll_filter_status = DPLL4_FILTER_STATUS;
+		break;
+	case 5:
+		dpll_filter_status = DPLL5_FILTER_STATUS;
+		break;
+	case 6:
+		dpll_filter_status = DPLL6_FILTER_STATUS;
+		break;
+	case 7:
+		dpll_filter_status = DPLL7_FILTER_STATUS;
+		break;
+	case 8:
+		dpll_filter_status = DPLLSYS_FILTER_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + dpll_filter_status, buf, 6);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 47);
+
+	/* FCW unit is 2 ^ -53 = 1.1102230246251565404236316680908e-16 */
+	ffo->ffo = fcw * 111;
+
+	return 0;
+}
+/*======================== Clockmatrix functions end ==================*/
+
+static int
+rsmu_set_combomode(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_combomode mode;
+	int err;
+
+	if (copy_from_user(&mode, arg, sizeof(mode)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err)
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_state(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_state state_request;
+	u8 state;
+	int err;
+
+	if (copy_from_user(&state_request, arg, sizeof(state_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	state_request.state = state;
+	if (copy_to_user(arg, &state_request, sizeof(state_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_ffo(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_ffo ffo_request;
+	int err;
+
+	if (copy_from_user(&ffo_request, arg, sizeof(ffo_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	if (copy_to_user(arg, &ffo_request, sizeof(ffo_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static struct rsmu_cdev *file2rsmu(struct file *file)
+{
+	return container_of(file->private_data, struct rsmu_cdev, miscdev);
+}
+
+static long
+rsmu_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
+{
+	struct rsmu_cdev *rsmu = file2rsmu(fptr);
+	void __user *arg = (void __user *)data;
+	int err = 0;
+
+	switch (cmd) {
+	case RSMU_SET_COMBOMODE:
+		err = rsmu_set_combomode(rsmu, arg);
+		break;
+	case RSMU_GET_STATE:
+		err = rsmu_get_dpll_state(rsmu, arg);
+		break;
+	case RSMU_GET_FFO:
+		err = rsmu_get_dpll_ffo(rsmu, arg);
+		break;
+	default:
+		/* Should not get here */
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static const struct file_operations rsmu_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = rsmu_ioctl,
+};
+
+static int
+rsmu_probe(struct platform_device *pdev)
+{
+	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct rsmu_cdev *rsmu;
+	int err;
+
+	rsmu = devm_kzalloc(&pdev->dev, sizeof(*rsmu), GFP_KERNEL);
+	if (!rsmu)
+		return -ENOMEM;
+
+	/* Save driver private data */
+	platform_set_drvdata(pdev, rsmu);
+
+	rsmu->dev = &pdev->dev;
+	rsmu->type = ddata->type;
+	rsmu->lock = &ddata->lock;
+	rsmu->regmap = ddata->regmap;
+	rsmu->index = ida_simple_get(&rsmu_cdev_map, 0, MINORMASK + 1, GFP_KERNEL);
+	if (rsmu->index < 0) {
+		dev_err(rsmu->dev, "Unable to get index %d\n", rsmu->index);
+		return rsmu->index;
+	}
+	snprintf(rsmu->name, sizeof(rsmu->name), "rsmu%d", rsmu->index);
+
+	/* Initialize and register the miscdev */
+	rsmu->miscdev.minor = MISC_DYNAMIC_MINOR;
+	rsmu->miscdev.fops = &rsmu_fops;
+	rsmu->miscdev.name = rsmu->name;
+	err = misc_register(&rsmu->miscdev);
+	if (err) {
+		dev_err(rsmu->dev, "Unable to register device\n");
+		ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int
+rsmu_remove(struct platform_device *pdev)
+{
+	struct rsmu_cdev *rsmu = platform_get_drvdata(pdev);
+
+	misc_deregister(&rsmu->miscdev);
+	ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+
+	return 0;
+}
+
+static const struct platform_device_id rsmu_id_table[] = {
+	{ "8a3400x-cdev", RSMU_CM},
+	{ "82p33x1x-cdev", RSMU_SABRE},
+	{}
+};
+MODULE_DEVICE_TABLE(platform, rsmu_id_table);
+
+static struct platform_driver rsmu_driver = {
+	.driver = {
+		.name = "rsmu-cdev",
+	},
+	.probe = rsmu_probe,
+	.remove =  rsmu_remove,
+	.id_table = rsmu_id_table,
+};
+
+module_platform_driver(rsmu_driver);
+
+MODULE_DESCRIPTION("Renesas SMU character device driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/rsmu.h b/include/uapi/linux/rsmu.h
new file mode 100644
index 0000000..e1cd43a
--- /dev/null
+++ b/include/uapi/linux/rsmu.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Driver for the IDT ClockMatrix(TM) and 82p33xxx families of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#ifndef __UAPI_LINUX_RSMU_CDEV_H
+#define __UAPI_LINUX_RSMU_CDEV_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Set dpll combomode */
+struct rsmu_combomode {
+	__u8 dpll;
+	__u8 mode;
+};
+
+/* Get dpll state */
+struct rsmu_get_state {
+	__u8 dpll;
+	__u8 state;
+};
+
+/* Get dpll ffo (fractional frequency offset) in ppqt */
+struct rsmu_get_ffo {
+	__u8 dpll;
+	__s64 ffo;
+};
+
+/*
+ * RSMU IOCTL List
+ */
+#define RSMU_MAGIC '?'
+
+/**
+ * struct rsmu_combomode
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @mode: combomode setting, see enum rsmu_dpll_combomode
+ *
+ * ioctl to set SMU combo mode.Combo mode provides physical layer frequency
+ * support from the Ethernet Equipment Clock to the PTP clock
+ */
+#define RSMU_SET_COMBOMODE  _IOW(RSMU_MAGIC, 1, struct rsmu_combomode)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @state: dpll state, see enum rsmu_class_state
+ *
+ * ioctl to get SMU dpll state. Application can call this API to tell if
+ * SMU is locked to the GNSS signal
+ */
+#define RSMU_GET_STATE  _IOR(RSMU_MAGIC, 2, struct rsmu_get_state)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @ffo: dpll's ffo (fractional frequency offset) in ppqt
+ *
+ * ioctl to get SMU dpll ffo (fractional frequency offset).
+ */
+#define RSMU_GET_FFO  _IOR(RSMU_MAGIC, 3, struct rsmu_get_ffo)
+#endif /* __UAPI_LINUX_RSMU_CDEV_H */
-- 
2.7.4


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

* [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support
  2021-09-15 18:11 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
@ 2021-09-15 18:11 ` min.li.xe
  0 siblings, 0 replies; 16+ messages in thread
From: min.li.xe @ 2021-09-15 18:11 UTC (permalink / raw)
  To: arnd, gregkh, derek.kiernan, dragan.cvetic; +Cc: linux-kernel, Min Li

From: Min Li <min.li.xe@renesas.com>

This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
of timing and synchronization devices.It will be used by Renesas PTP Clock
Manager for Linux (pcm4l) software to provide support to GNSS assisted
partial timing support (APTS) and other networking timing functions.

Current version provides kernel API's to support the following functions
-set combomode to enable SYNCE clock support
-read dpll's state to determine if the dpll is locked to the GNSS channel
-read dpll's ffo (fractional frequency offset) in ppqt

Signed-off-by: Min Li <min.li.xe@renesas.com>
---
Change log
-simply design by using only one c file suggested by Greg

 drivers/misc/Kconfig      |   8 +
 drivers/misc/Makefile     |   1 +
 drivers/misc/rsmu.c       | 536 ++++++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/rsmu.h |  66 ++++++
 4 files changed, 611 insertions(+)
 create mode 100644 drivers/misc/rsmu.c
 create mode 100644 include/uapi/linux/rsmu.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 85ba901..6dc36f9 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -469,6 +469,14 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config RSMU
+	tristate "Renesas Synchronization Management Unit (SMU)"
+	help
+	  This option enables support for RSMU (Renesas Synchronization
+	  Management Unit) driver. It will be used by Renesas PTP Clock Manager
+	  for Linux (pcm4l) software to provide support for GNSS assisted
+	  partial timing support (APTS) and other networking timing functions.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a086197..a66e3b7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE)		+= uacce/
 obj-$(CONFIG_XILINX_SDFEC)	+= xilinx_sdfec.o
 obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
 obj-$(CONFIG_HI6421V600_IRQ)	+= hi6421v600-irq.o
+obj-$(CONFIG_RSMU)		+= rsmu.o
diff --git a/drivers/misc/rsmu.c b/drivers/misc/rsmu.c
new file mode 100644
index 0000000..6981cb3
--- /dev/null
+++ b/drivers/misc/rsmu.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This driver is developed for the IDT ClockMatrix(TM) and 82P33xxx families
+ * of timing and synchronization devices. It will be used by Renesas PTP Clock
+ * Manager for Linux (pcm4l) software to provide support to GNSS assisted
+ * partial timing support (APTS) and other networking timing functions.
+ *
+ * Please note it must work with Renesas MFD driver to access device through
+ * I2C/SPI.
+ *
+ * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/idt8a340_reg.h>
+#include <linux/mfd/idt82p33_reg.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+
+static DEFINE_IDA(rsmu_cdev_map);
+
+/**
+ * struct rsmu_cdev - Driver data for RSMU character device
+ * @name: rsmu device name as rsmu[index]
+ * @dev: pointer to platform device
+ * @miscdev: character device handle
+ * @regmap: I2C/SPI regmap handle
+ * @lock: mutex to protect operations from being interrupted
+ * @type: rsmu device type, passed through platform data
+ * @index: rsmu device index
+ */
+struct rsmu_cdev {
+	char name[16];
+	struct device *dev;
+	struct miscdevice miscdev;
+	struct regmap *regmap;
+	struct mutex *lock;
+	enum rsmu_type type;
+	int index;
+};
+
+/**
+ * Enumerated type listing DPLL combination modes
+ */
+enum rsmu_dpll_combomode {
+	E_COMBOMODE_CURRENT = 0,
+	E_COMBOMODE_FASTAVG,
+	E_COMBOMODE_SLOWAVG,
+	E_COMBOMODE_HOLDOVER,
+	E_COMBOMODE_MAX
+};
+
+/**
+ * An id used to identify the respective child class states.
+ */
+enum rsmu_class_state {
+	E_SRVLOINITIALSTATE = 0,
+	E_SRVLOUNQUALIFIEDSTATE = 1,
+	E_SRVLOLOCKACQSTATE = 2,
+	E_SRVLOFREQUENCYLOCKEDSTATE = 3,
+	E_SRVLOTIMELOCKEDSTATE = 4,
+	E_SRVLOHOLDOVERINSPECSTATE = 5,
+	E_SRVLOHOLDOVEROUTOFSPECSTATE = 6,
+	E_SRVLOFREERUNSTATE = 7,
+	E_SRVNUMBERLOSTATES = 8,
+	E_SRVLOSTATEINVALID = 9,
+};
+
+/*======================== Sabre functions start ==========================*/
+static int rsmu_sabre_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = SABRE_DPLL1_OPERATING_MODE_CNFG;
+		break;
+	case 1:
+		dpll_ctrl_n = SABRE_DPLL2_OPERATING_MODE_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	cfg &= ~(SABRE_COMBO_MODE_MASK << SABRE_COMBO_MODE_SHIFT);
+	cfg |= mode << SABRE_COMBO_MODE_SHIFT;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n, &cfg, sizeof(cfg));
+}
+
+static int rsmu_sabre_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u16 dpll_sts_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_sts_n = SABRE_DPLL1_OPERATING_STS;
+		break;
+	case 1:
+		dpll_sts_n = SABRE_DPLL2_OPERATING_STS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_sts_n, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & SABRE_OPERATING_STS_MASK) {
+	case SABRE_DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_PRELOCKED2:
+	case SABRE_DPLL_STATE_PRELOCKED:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case SABRE_DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case SABRE_DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_sabre_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				   struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_freq_n;
+	int err;
+
+	/*
+	 * IDTDpll_GetCurrentDpllFreqOffset retrieves the FFO integrator only.
+	 * In order to get Proportional + Integrator, use the holdover FFO with
+	 * the filter bandwidth 0.5 Hz set by TCS file.
+	 */
+	switch (dpll) {
+	case 0:
+		dpll_freq_n = SABRE_DPLL1_HOLDOVER_FREQ_CNFG;
+		break;
+	case 1:
+		dpll_freq_n = SABRE_DPLL2_HOLDOVER_FREQ_CNFG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_freq_n, buf, 5);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 39);
+
+	/* FCW unit is 77760 / ( 1638400 * 2^48) = 1.68615121864946 * 10^-16 */
+	ffo->ffo = div_s64(fcw * 2107689, 12500);
+
+	return 0;
+}
+/*======================== Sabre functions end ==========================*/
+
+/*======================== Clockmatrix functions start ==================*/
+static int rsmu_cm_set_combomode(struct rsmu_cdev *rsmu, u8 dpll, u8 mode)
+{
+	u16 dpll_ctrl_n;
+	u8 cfg;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_ctrl_n = DPLL_CTRL_0;
+		break;
+	case 1:
+		dpll_ctrl_n = DPLL_CTRL_1;
+		break;
+	case 2:
+		dpll_ctrl_n = DPLL_CTRL_2;
+		break;
+	case 3:
+		dpll_ctrl_n = DPLL_CTRL_3;
+		break;
+	case 4:
+		dpll_ctrl_n = DPLL_CTRL_4;
+		break;
+	case 5:
+		dpll_ctrl_n = DPLL_CTRL_5;
+		break;
+	case 6:
+		dpll_ctrl_n = DPLL_CTRL_6;
+		break;
+	case 7:
+		dpll_ctrl_n = DPLL_CTRL_7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode >= E_COMBOMODE_MAX)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+			       &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	/* Only need to enable/disable COMBO_MODE_HOLD. */
+	if (mode)
+		cfg |= COMBO_MASTER_HOLD;
+	else
+		cfg &= ~COMBO_MASTER_HOLD;
+
+	return regmap_bulk_write(rsmu->regmap, dpll_ctrl_n + DPLL_CTRL_COMBO_MASTER_CFG,
+				 &cfg, sizeof(cfg));
+}
+
+static int rsmu_cm_get_dpll_state(struct rsmu_cdev *rsmu, u8 dpll, u8 *state)
+{
+	u8 cfg;
+	int err;
+
+	/* 8 is sys dpll */
+	if (dpll > 8)
+		return -EINVAL;
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + DPLL0_STATUS + dpll, &cfg, sizeof(cfg));
+	if (err)
+		return err;
+
+	switch (cfg & DPLL_STATE_MASK) {
+	case DPLL_STATE_FREERUN:
+		*state = E_SRVLOUNQUALIFIEDSTATE;
+		break;
+	case DPLL_STATE_LOCKACQ:
+	case DPLL_STATE_LOCKREC:
+		*state = E_SRVLOLOCKACQSTATE;
+		break;
+	case DPLL_STATE_LOCKED:
+		*state = E_SRVLOTIMELOCKEDSTATE;
+		break;
+	case DPLL_STATE_HOLDOVER:
+		*state = E_SRVLOHOLDOVERINSPECSTATE;
+		break;
+	default:
+		*state = E_SRVLOSTATEINVALID;
+		break;
+	}
+
+	return 0;
+}
+
+static int rsmu_cm_get_dpll_ffo(struct rsmu_cdev *rsmu, u8 dpll,
+				struct rsmu_get_ffo *ffo)
+{
+	u8 buf[8] = {0};
+	s64 fcw = 0;
+	u16 dpll_filter_status;
+	int err;
+
+	switch (dpll) {
+	case 0:
+		dpll_filter_status = DPLL0_FILTER_STATUS;
+		break;
+	case 1:
+		dpll_filter_status = DPLL1_FILTER_STATUS;
+		break;
+	case 2:
+		dpll_filter_status = DPLL2_FILTER_STATUS;
+		break;
+	case 3:
+		dpll_filter_status = DPLL3_FILTER_STATUS;
+		break;
+	case 4:
+		dpll_filter_status = DPLL4_FILTER_STATUS;
+		break;
+	case 5:
+		dpll_filter_status = DPLL5_FILTER_STATUS;
+		break;
+	case 6:
+		dpll_filter_status = DPLL6_FILTER_STATUS;
+		break;
+	case 7:
+		dpll_filter_status = DPLL7_FILTER_STATUS;
+		break;
+	case 8:
+		dpll_filter_status = DPLLSYS_FILTER_STATUS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	err = regmap_bulk_read(rsmu->regmap, STATUS + dpll_filter_status, buf, 6);
+	if (err)
+		return err;
+
+	/* Convert to frequency control word */
+	fcw = sign_extend64(get_unaligned_le64(buf), 47);
+
+	/* FCW unit is 2 ^ -53 = 1.1102230246251565404236316680908e-16 */
+	ffo->ffo = fcw * 111;
+
+	return 0;
+}
+/*======================== Clockmatrix functions end ==================*/
+
+static int
+rsmu_set_combomode(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_combomode mode;
+	int err;
+
+	if (copy_from_user(&mode, arg, sizeof(mode)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_set_combomode(rsmu, mode.dpll, mode.mode);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err)
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_state(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_state state_request;
+	u8 state;
+	int err;
+
+	if (copy_from_user(&state_request, arg, sizeof(state_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_state(rsmu, state_request.dpll, &state);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	state_request.state = state;
+	if (copy_to_user(arg, &state_request, sizeof(state_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static int
+rsmu_get_dpll_ffo(struct rsmu_cdev *rsmu, void __user *arg)
+{
+	struct rsmu_get_ffo ffo_request;
+	int err;
+
+	if (copy_from_user(&ffo_request, arg, sizeof(ffo_request)))
+		return -EFAULT;
+
+	mutex_lock(rsmu->lock);
+	switch (rsmu->type) {
+	case RSMU_CM:
+		err = rsmu_cm_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	case RSMU_SABRE:
+		err = rsmu_sabre_get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+	mutex_unlock(rsmu->lock);
+
+	if (err) {
+		dev_err(rsmu->dev, "%s failed with %d", __func__, err);
+		return err;
+	}
+
+	if (copy_to_user(arg, &ffo_request, sizeof(ffo_request)))
+		return -EFAULT;
+
+	return err;
+}
+
+static struct rsmu_cdev *file2rsmu(struct file *file)
+{
+	return container_of(file->private_data, struct rsmu_cdev, miscdev);
+}
+
+static long
+rsmu_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
+{
+	struct rsmu_cdev *rsmu = file2rsmu(fptr);
+	void __user *arg = (void __user *)data;
+	int err = 0;
+
+	switch (cmd) {
+	case RSMU_SET_COMBOMODE:
+		err = rsmu_set_combomode(rsmu, arg);
+		break;
+	case RSMU_GET_STATE:
+		err = rsmu_get_dpll_state(rsmu, arg);
+		break;
+	case RSMU_GET_FFO:
+		err = rsmu_get_dpll_ffo(rsmu, arg);
+		break;
+	default:
+		/* Should not get here */
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static const struct file_operations rsmu_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = rsmu_ioctl,
+};
+
+static int
+rsmu_probe(struct platform_device *pdev)
+{
+	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct rsmu_cdev *rsmu;
+	int err;
+
+	rsmu = devm_kzalloc(&pdev->dev, sizeof(*rsmu), GFP_KERNEL);
+	if (!rsmu)
+		return -ENOMEM;
+
+	/* Save driver private data */
+	platform_set_drvdata(pdev, rsmu);
+
+	rsmu->dev = &pdev->dev;
+	rsmu->type = ddata->type;
+	rsmu->lock = &ddata->lock;
+	rsmu->regmap = ddata->regmap;
+	rsmu->index = ida_simple_get(&rsmu_cdev_map, 0, MINORMASK + 1, GFP_KERNEL);
+	if (rsmu->index < 0) {
+		dev_err(rsmu->dev, "Unable to get index %d\n", rsmu->index);
+		return rsmu->index;
+	}
+	snprintf(rsmu->name, sizeof(rsmu->name), "rsmu%d", rsmu->index);
+
+	/* Initialize and register the miscdev */
+	rsmu->miscdev.minor = MISC_DYNAMIC_MINOR;
+	rsmu->miscdev.fops = &rsmu_fops;
+	rsmu->miscdev.name = rsmu->name;
+	err = misc_register(&rsmu->miscdev);
+	if (err) {
+		dev_err(rsmu->dev, "Unable to register device\n");
+		ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int
+rsmu_remove(struct platform_device *pdev)
+{
+	struct rsmu_cdev *rsmu = platform_get_drvdata(pdev);
+
+	misc_deregister(&rsmu->miscdev);
+	ida_simple_remove(&rsmu_cdev_map, rsmu->index);
+
+	return 0;
+}
+
+static const struct platform_device_id rsmu_id_table[] = {
+	{ "8a3400x-cdev", RSMU_CM},
+	{ "82p33x1x-cdev", RSMU_SABRE},
+	{}
+};
+MODULE_DEVICE_TABLE(platform, rsmu_id_table);
+
+static struct platform_driver rsmu_driver = {
+	.driver = {
+		.name = "rsmu-cdev",
+	},
+	.probe = rsmu_probe,
+	.remove =  rsmu_remove,
+	.id_table = rsmu_id_table,
+};
+
+module_platform_driver(rsmu_driver);
+
+MODULE_DESCRIPTION("Renesas SMU character device driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/rsmu.h b/include/uapi/linux/rsmu.h
new file mode 100644
index 0000000..e1cd43a
--- /dev/null
+++ b/include/uapi/linux/rsmu.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Driver for the IDT ClockMatrix(TM) and 82p33xxx families of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#ifndef __UAPI_LINUX_RSMU_CDEV_H
+#define __UAPI_LINUX_RSMU_CDEV_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* Set dpll combomode */
+struct rsmu_combomode {
+	__u8 dpll;
+	__u8 mode;
+};
+
+/* Get dpll state */
+struct rsmu_get_state {
+	__u8 dpll;
+	__u8 state;
+};
+
+/* Get dpll ffo (fractional frequency offset) in ppqt */
+struct rsmu_get_ffo {
+	__u8 dpll;
+	__s64 ffo;
+};
+
+/*
+ * RSMU IOCTL List
+ */
+#define RSMU_MAGIC '?'
+
+/**
+ * struct rsmu_combomode
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @mode: combomode setting, see enum rsmu_dpll_combomode
+ *
+ * ioctl to set SMU combo mode.Combo mode provides physical layer frequency
+ * support from the Ethernet Equipment Clock to the PTP clock
+ */
+#define RSMU_SET_COMBOMODE  _IOW(RSMU_MAGIC, 1, struct rsmu_combomode)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @state: dpll state, see enum rsmu_class_state
+ *
+ * ioctl to get SMU dpll state. Application can call this API to tell if
+ * SMU is locked to the GNSS signal
+ */
+#define RSMU_GET_STATE  _IOR(RSMU_MAGIC, 2, struct rsmu_get_state)
+
+/**
+ * struct rsmu_get_state
+ * @dpll: dpll index (Digital Phase Lock Loop)
+ * @ffo: dpll's ffo (fractional frequency offset) in ppqt
+ *
+ * ioctl to get SMU dpll ffo (fractional frequency offset).
+ */
+#define RSMU_GET_FFO  _IOR(RSMU_MAGIC, 3, struct rsmu_get_ffo)
+#endif /* __UAPI_LINUX_RSMU_CDEV_H */
-- 
2.7.4


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

end of thread, other threads:[~2021-09-16 17:52 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-15 18:47 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
2021-09-15 18:47 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
2021-09-16  5:25   ` Greg KH
2021-09-16 15:33     ` Min Li
2021-09-16 15:39       ` Greg KH
2021-09-16 15:54         ` Min Li
2021-09-16 16:05           ` Greg KH
2021-09-16 17:01             ` Min Li
2021-09-16 17:22               ` Greg KH
2021-09-16 11:31   ` kernel test robot
2021-09-16  5:23 ` [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h Greg KH
2021-09-16  5:24 ` Greg KH
2021-09-16 14:49   ` Min Li
  -- strict thread matches above, loose matches on Subject: below --
2021-09-16 16:11 min.li.xe
2021-09-16 16:11 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
2021-09-16 15:41 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
2021-09-16 15:41 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe
2021-09-15 18:11 [PATCH misc v2 1/2] mfd: rsmu: Resolve naming conflict between idt8a340_reg.h and idt82p33_reg.h min.li.xe
2021-09-15 18:11 ` [PATCH misc v2 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support min.li.xe

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