2021-04-08 01:57:42

by Min Li

[permalink] [raw]
Subject: [PATCH net-next v3 1/2] mfd: Add Renesas Synchronization Management Unit (SMU) support

From: Min Li <[email protected]>

Add support for ClockMatrix(TM) and 82P33xxx families of timing
and synchronization devices. The access interface can be either
SPI or I2C. Currently, it will create 2 types of MFD devices,
which are to be used by the corresponding rsmu character device
driver and the PTP hardware clock driver, respectively.

Signed-off-by: Min Li <[email protected]>
---
drivers/mfd/Kconfig | 28 ++
drivers/mfd/Makefile | 3 +
drivers/mfd/rsmu_i2c.c | 349 +++++++++++++++++
drivers/mfd/rsmu_private.h | 32 ++
drivers/mfd/rsmu_spi.c | 376 ++++++++++++++++++
include/linux/mfd/idt82p33_reg.h | 116 ++++++
include/linux/mfd/idt8a340_reg.h | 817 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/rsmu.h | 54 +++
8 files changed, 1775 insertions(+)
create mode 100644 drivers/mfd/rsmu_i2c.c
create mode 100644 drivers/mfd/rsmu_private.h
create mode 100644 drivers/mfd/rsmu_spi.c
create mode 100644 include/linux/mfd/idt82p33_reg.h
create mode 100644 include/linux/mfd/idt8a340_reg.h
create mode 100644 include/linux/mfd/rsmu.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 21a131d..63b18b3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2172,5 +2172,33 @@ config MFD_INTEL_M10_BMC
additional drivers must be enabled in order to use the functionality
of the device.

+config MFD_RSMU_I2C
+ tristate "Renesas Synchronization Management Unit with I2C"
+ depends on I2C && OF
+ depends on MFD_RSMU_SPI=n
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Support for the Renesas synchronization management unit, such as
+ Clockmatrix and 82P33XXX series. This option supports I2C as
+ the control interface.
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
+config MFD_RSMU_SPI
+ tristate "Renesas Synchronization Management Unit with SPI"
+ depends on SPI && OF
+ select MFD_CORE
+ help
+ Support for the Renesas synchronization management unit, such as
+ Clockmatrix and 82P33XXX series. This option supports SPI as
+ the control interface.
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4f6d2b8..4ab32ef 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -271,3 +271,6 @@ obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o

obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
+
+obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o
+obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o
diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c
new file mode 100644
index 0000000..2349f6d
--- /dev/null
+++ b/drivers/mfd/rsmu_i2c.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Multi-function driver for the IDT ClockMatrix(TM) and 82P33xxx families of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rsmu.h>
+#include "rsmu_private.h"
+
+/*
+ * 16-bit register address: the lower 8 bits of the register address come
+ * from the offset addr byte and the upper 8 bits come from the page register.
+ */
+#define RSMU_CM_PAGE_ADDR 0xFD
+#define RSMU_CM_PAGE_WINDOW 256
+
+/*
+ * 15-bit register address: the lower 7 bits of the register address come
+ * from the offset addr byte and the upper 8 bits come from the page register.
+ */
+#define RSMU_SABRE_PAGE_ADDR 0x7F
+#define RSMU_SABRE_PAGE_WINDOW 128
+
+static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg);
+static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg);
+
+/* Current mfd device index */
+static atomic_t rsmu_ndevs = ATOMIC_INIT(0);
+
+/* Platform data */
+static struct rsmu_pdata rsmu_pdata[RSMU_MAX_MFD_DEV];
+
+/* clockmatrix phc devices */
+static struct mfd_cell rsmu_cm_pdev[RSMU_MAX_MFD_DEV] = {
+ [0] = {
+ .name = "idtcm-ptp0",
+ .of_compatible = "renesas,idtcm-ptp0",
+ },
+ [1] = {
+ .name = "idtcm-ptp1",
+ .of_compatible = "renesas,idtcm-ptp1",
+ },
+ [2] = {
+ .name = "idtcm-ptp2",
+ .of_compatible = "renesas,idtcm-ptp2",
+ },
+ [3] = {
+ .name = "idtcm-ptp3",
+ .of_compatible = "renesas,idtcm-ptp3",
+ },
+};
+
+/* sabre phc devices */
+static struct mfd_cell rsmu_sabre_pdev[RSMU_MAX_MFD_DEV] = {
+ [0] = {
+ .name = "idt82p33-ptp0",
+ .of_compatible = "renesas,idt82p33-ptp0",
+ },
+ [1] = {
+ .name = "idt82p33-ptp1",
+ .of_compatible = "renesas,idt82p33-ptp1",
+ },
+ [2] = {
+ .name = "idt82p33-ptp2",
+ .of_compatible = "renesas,idt82p33-ptp2",
+ },
+ [3] = {
+ .name = "idt82p33-ptp3",
+ .of_compatible = "renesas,idt82p33-ptp3",
+ },
+};
+
+/* rsmu character devices */
+static struct mfd_cell rsmu_cdev[RSMU_MAX_MFD_DEV] = {
+ [0] = {
+ .name = "rsmu-cdev0",
+ .of_compatible = "renesas,rsmu-cdev0",
+ },
+ [1] = {
+ .name = "rsmu-cdev1",
+ .of_compatible = "renesas,rsmu-cdev1",
+ },
+ [2] = {
+ .name = "rsmu-cdev2",
+ .of_compatible = "renesas,rsmu-cdev2",
+ },
+ [3] = {
+ .name = "rsmu-cdev3",
+ .of_compatible = "renesas,rsmu-cdev3",
+ },
+};
+
+static const struct regmap_range_cfg rsmu_cm_range_cfg[] = {
+ {
+ .range_min = 0,
+ .range_max = 0xD000,
+ .selector_reg = RSMU_CM_PAGE_ADDR,
+ .selector_mask = 0xFF,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = RSMU_CM_PAGE_WINDOW,
+ }
+};
+
+static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = {
+ {
+ .range_min = 0,
+ .range_max = 0x400,
+ .selector_reg = RSMU_SABRE_PAGE_ADDR,
+ .selector_mask = 0xFF,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = RSMU_SABRE_PAGE_WINDOW,
+ }
+};
+
+static const struct regmap_config rsmu_regmap_configs[] = {
+ [RSMU_CM] = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xD000,
+ .ranges = rsmu_cm_range_cfg,
+ .num_ranges = ARRAY_SIZE(rsmu_cm_range_cfg),
+ .volatile_reg = rsmu_cm_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ .can_multi_write = true,
+ },
+ [RSMU_SABRE] = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x400,
+ .ranges = rsmu_sabre_range_cfg,
+ .num_ranges = ARRAY_SIZE(rsmu_sabre_range_cfg),
+ .volatile_reg = rsmu_sabre_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ .can_multi_write = true,
+ },
+};
+
+static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RSMU_CM_PAGE_ADDR:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RSMU_SABRE_PAGE_ADDR:
+ return false;
+ default:
+ return true;
+ }
+}
+
+int rsmu_read(struct device *dev, u16 reg, u8 *buf, u16 size)
+{
+ struct rsmu_dev *rsmu = dev_get_drvdata(dev);
+
+ return regmap_bulk_read(rsmu->regmap, reg, buf, size);
+}
+EXPORT_SYMBOL_GPL(rsmu_read);
+
+int rsmu_write(struct device *dev, u16 reg, u8 *buf, u16 size)
+{
+ struct rsmu_dev *rsmu = dev_get_drvdata(dev);
+
+ return regmap_bulk_write(rsmu->regmap, reg, buf, size);
+}
+EXPORT_SYMBOL_GPL(rsmu_write);
+
+static int rsmu_mfd_init(struct rsmu_dev *rsmu, struct mfd_cell *mfd,
+ struct rsmu_pdata *pdata)
+{
+ int ret;
+
+ mfd->platform_data = pdata;
+ mfd->pdata_size = sizeof(struct rsmu_pdata);
+
+ ret = mfd_add_devices(rsmu->dev, -1, mfd, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ dev_err(rsmu->dev, "mfd_add_devices failed with %s\n",
+ mfd->name);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int rsmu_dev_init(struct rsmu_dev *rsmu)
+{
+ struct rsmu_pdata *pdata;
+ struct mfd_cell *pmfd;
+ struct mfd_cell *cmfd;
+ int ret;
+
+ /* Initialize regmap */
+ rsmu->regmap = devm_regmap_init_i2c(rsmu->client,
+ &rsmu_regmap_configs[rsmu->type]);
+ if (IS_ERR(rsmu->regmap)) {
+ ret = PTR_ERR(rsmu->regmap);
+ dev_err(rsmu->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Initialize device index */
+ rsmu->index = atomic_read(&rsmu_ndevs);
+ if (rsmu->index >= RSMU_MAX_MFD_DEV)
+ return -ENODEV;
+
+ /* Initialize platform data */
+ pdata = &rsmu_pdata[rsmu->index];
+ pdata->lock = &rsmu->lock;
+ pdata->type = rsmu->type;
+ pdata->index = rsmu->index;
+
+ /* Initialize MFD devices */
+ cmfd = &rsmu_cdev[rsmu->index];
+ if (rsmu->type == RSMU_CM)
+ pmfd = &rsmu_cm_pdev[rsmu->index];
+ else if (rsmu->type == RSMU_SABRE)
+ pmfd = &rsmu_sabre_pdev[rsmu->index];
+ else
+ return -EINVAL;
+
+ ret = rsmu_mfd_init(rsmu, pmfd, pdata);
+ if (ret)
+ return ret;
+
+ ret = rsmu_mfd_init(rsmu, cmfd, pdata);
+ if (ret)
+ return ret;
+
+ atomic_inc(&rsmu_ndevs);
+ return 0;
+}
+
+static int rsmu_dt_init(struct rsmu_dev *rsmu)
+{
+ struct device_node *np = rsmu->dev->of_node;
+
+ rsmu->type = RSMU_NONE;
+ if (of_device_is_compatible(np, "idt,8a34000")) {
+ rsmu->type = RSMU_CM;
+ } else if (of_device_is_compatible(np, "idt,82p33810")) {
+ rsmu->type = RSMU_SABRE;
+ } else {
+ dev_err(rsmu->dev, "unknown RSMU device\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rsmu_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct rsmu_dev *rsmu;
+ int ret;
+
+ rsmu = devm_kzalloc(&client->dev, sizeof(struct rsmu_dev),
+ GFP_KERNEL);
+ if (rsmu == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, rsmu);
+ mutex_init(&rsmu->lock);
+ rsmu->dev = &client->dev;
+ rsmu->client = client;
+
+ ret = rsmu_dt_init(rsmu);
+ if (ret)
+ return ret;
+
+ mutex_lock(&rsmu->lock);
+ ret = rsmu_dev_init(rsmu);
+ mutex_unlock(&rsmu->lock);
+
+ if (ret == 0)
+ dev_info(rsmu->dev, "Probe %s successful\n",
+ rsmu_name(rsmu->type));
+
+ return ret;
+}
+
+static int rsmu_remove(struct i2c_client *client)
+{
+ struct rsmu_dev *rsmu = i2c_get_clientdata(client);
+
+ mfd_remove_devices(&client->dev);
+ mutex_destroy(&rsmu->lock);
+ atomic_dec(&rsmu_ndevs);
+
+ return 0;
+}
+
+static const struct i2c_device_id rsmu_id[] = {
+ { "8a34000", 0 },
+ { "82p33810", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rsmu_id);
+
+static const struct of_device_id rsmu_of_match[] = {
+ {.compatible = "idt,8a34000", },
+ {.compatible = "idt,82p33810", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rsmu_of_match);
+
+static struct i2c_driver rsmu_driver = {
+ .driver = {
+ .name = "rsmu-i2c",
+ .of_match_table = of_match_ptr(rsmu_of_match),
+ },
+ .probe = rsmu_probe,
+ .remove = rsmu_remove,
+ .id_table = rsmu_id,
+};
+
+static int __init rsmu_init(void)
+{
+ return i2c_add_driver(&rsmu_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(rsmu_init);
+
+static void __exit rsmu_exit(void)
+{
+ i2c_del_driver(&rsmu_driver);
+}
+module_exit(rsmu_exit);
+
+MODULE_DESCRIPTION("Renesas SMU I2C multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/rsmu_private.h b/drivers/mfd/rsmu_private.h
new file mode 100644
index 0000000..8841a24
--- /dev/null
+++ b/drivers/mfd/rsmu_private.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Multi-function 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 __RSMU_MFD_PRIVATE_H
+#define __RSMU_MFD_PRIVATE_H
+
+#include <linux/mfd/rsmu.h>
+
+/* Maximum number of mfd devices */
+#define RSMU_MAX_MFD_DEV 4
+
+struct rsmu_dev {
+ struct device *dev;
+ void *client;
+ struct regmap *regmap;
+ struct mutex lock;
+ enum rsmu_type type;
+ u8 index;
+ u16 page;
+};
+
+enum rsmu_mfd_type {
+ RSMU_MFD_PTP = 0,
+ RSMU_MFD_CDEV = 1,
+ RSMU_MFD_NUM = 2,
+};
+#endif /* __LINUX_MFD_RSMU_H */
diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c
new file mode 100644
index 0000000..a9fbe04
--- /dev/null
+++ b/drivers/mfd/rsmu_spi.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Multi-function driver for the IDT ClockMatrix(TM) and 82P33xxx families of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rsmu.h>
+#include "rsmu_private.h"
+
+/*
+ * 16-bit register address: the lower 7 bits of the register address come
+ * from the offset addr byte and the upper 9 bits come from the page register.
+ */
+#define RSMU_CM_PAGE_ADDR 0x7C
+#define RSMU_SABRE_PAGE_ADDR 0x7F
+#define RSMU_HIGHER_ADDR_MASK 0xFF80
+#define RSMU_HIGHER_ADDR_SHIFT 7
+#define RSMU_LOWER_ADDR_MASK 0x7F
+
+/* Current mfd device index */
+static atomic_t rsmu_ndevs = ATOMIC_INIT(0);
+
+/* Platform data */
+static struct rsmu_pdata rsmu_pdata[RSMU_MAX_MFD_DEV];
+
+/* clockmatrix phc devices */
+static struct mfd_cell rsmu_cm_pdev[RSMU_MAX_MFD_DEV] = {
+ [0] = {
+ .name = "idtcm-ptp0",
+ .of_compatible = "renesas,idtcm-ptp0",
+ },
+ [1] = {
+ .name = "idtcm-ptp1",
+ .of_compatible = "renesas,idtcm-ptp1",
+ },
+ [2] = {
+ .name = "idtcm-ptp2",
+ .of_compatible = "renesas,idtcm-ptp2",
+ },
+ [3] = {
+ .name = "idtcm-ptp3",
+ .of_compatible = "renesas,idtcm-ptp3",
+ },
+};
+
+/* sabre phc devices */
+static struct mfd_cell rsmu_sabre_pdev[RSMU_MAX_MFD_DEV] = {
+ [0] = {
+ .name = "idt82p33-ptp0",
+ .of_compatible = "renesas,idt82p33-ptp0",
+ },
+ [1] = {
+ .name = "idt82p33-ptp1",
+ .of_compatible = "renesas,idt82p33-ptp1",
+ },
+ [2] = {
+ .name = "idt82p33-ptp2",
+ .of_compatible = "renesas,idt82p33-ptp2",
+ },
+ [3] = {
+ .name = "idt82p33-ptp3",
+ .of_compatible = "renesas,idt82p33-ptp3",
+ },
+};
+
+/* rsmu character devices */
+static struct mfd_cell rsmu_cdev[RSMU_MAX_MFD_DEV] = {
+ [0] = {
+ .name = "rsmu-cdev0",
+ .of_compatible = "renesas,rsmu-cdev0",
+ },
+ [1] = {
+ .name = "rsmu-cdev1",
+ .of_compatible = "renesas,rsmu-cdev1",
+ },
+ [2] = {
+ .name = "rsmu-cdev2",
+ .of_compatible = "renesas,rsmu-cdev2",
+ },
+ [3] = {
+ .name = "rsmu-cdev3",
+ .of_compatible = "renesas,rsmu-cdev3",
+ },
+};
+
+static int rsmu_read_device(struct rsmu_dev *rsmu, u8 reg, u8 *buf, u16 bytes)
+{
+ struct spi_device *client = rsmu->client;
+ struct spi_transfer xfer = {0};
+ struct spi_message msg;
+ u8 cmd[256] = {0};
+ u8 rsp[256] = {0};
+ int ret;
+
+ cmd[0] = reg | 0x80;
+ xfer.rx_buf = rsp;
+ xfer.len = bytes + 1;
+ xfer.tx_buf = cmd;
+ xfer.bits_per_word = client->bits_per_word;
+ xfer.speed_hz = client->max_speed_hz;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ ret = spi_sync(client, &msg);
+ if (ret >= 0)
+ memcpy(buf, &rsp[1], xfer.len-1);
+
+ return ret;
+}
+
+static int rsmu_write_device(struct rsmu_dev *rsmu, u8 reg, u8 *buf, u16 bytes)
+{
+ struct spi_device *client = rsmu->client;
+ struct spi_transfer xfer = {0};
+ struct spi_message msg;
+ u8 cmd[256] = {0};
+ int ret = -1;
+
+ cmd[0] = reg;
+ memcpy(&cmd[1], buf, bytes);
+
+ xfer.len = bytes + 1;
+ xfer.tx_buf = cmd;
+ xfer.bits_per_word = client->bits_per_word;
+ xfer.speed_hz = client->max_speed_hz;
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ ret = spi_sync(client, &msg);
+ return ret;
+}
+
+static int rsmu_write_page_register(struct rsmu_dev *rsmu, u16 reg)
+{
+ u8 buf[2];
+ u16 bytes;
+ u16 page;
+ u8 preg;
+ int err;
+
+ switch (rsmu->type) {
+ case RSMU_CM:
+ preg = RSMU_CM_PAGE_ADDR;
+ page = reg & RSMU_HIGHER_ADDR_MASK;
+ buf[0] = (u8)(page & 0xff);
+ buf[1] = (u8)((page >> 8) & 0xff);
+ bytes = 2;
+ break;
+ case RSMU_SABRE:
+ preg = RSMU_SABRE_PAGE_ADDR;
+ page = reg >> RSMU_HIGHER_ADDR_SHIFT;
+ buf[0] = (u8)(page & 0xff);
+ bytes = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rsmu->page == page)
+ return 0;
+
+ err = rsmu_write_device(rsmu, preg, buf, bytes);
+
+ if (err) {
+ rsmu->page = 0xffff;
+ dev_err(rsmu->dev,
+ "failed to set page offset 0x%x\n", page);
+ } else {
+ rsmu->page = page;
+ }
+
+ return err;
+}
+
+int rsmu_read(struct device *dev, u16 reg, u8 *buf, u16 size)
+{
+ struct rsmu_dev *rsmu = dev_get_drvdata(dev);
+ u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK);
+ int err;
+
+ err = rsmu_write_page_register(rsmu, reg);
+ if (err)
+ return err;
+
+ err = rsmu_read_device(rsmu, addr, buf, size);
+ if (err)
+ dev_err(rsmu->dev,
+ "failed to read offset address 0x%x\n", addr);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(rsmu_read);
+
+int rsmu_write(struct device *dev, u16 reg, u8 *buf, u16 size)
+{
+ struct rsmu_dev *rsmu = dev_get_drvdata(dev);
+ u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK);
+ int err;
+
+ err = rsmu_write_page_register(rsmu, reg);
+ if (err)
+ return err;
+
+ err = rsmu_write_device(rsmu, addr, buf, size);
+ if (err)
+ dev_err(rsmu->dev,
+ "failed to write offset address 0x%x\n", addr);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(rsmu_write);
+
+static int rsmu_mfd_init(struct rsmu_dev *rsmu, struct mfd_cell *mfd,
+ struct rsmu_pdata *pdata)
+{
+ int ret;
+
+ mfd->platform_data = pdata;
+ mfd->pdata_size = sizeof(struct rsmu_pdata);
+
+ ret = mfd_add_devices(rsmu->dev, -1, mfd, 1, NULL, 0, NULL);
+ if (ret < 0) {
+ dev_err(rsmu->dev, "mfd_add_devices failed with %s\n",
+ mfd->name);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int rsmu_dev_init(struct rsmu_dev *rsmu)
+{
+ struct rsmu_pdata *pdata;
+ struct mfd_cell *pmfd;
+ struct mfd_cell *cmfd;
+ int ret;
+
+ /* Initialize device index */
+ rsmu->index = atomic_read(&rsmu_ndevs);
+ if (rsmu->index >= RSMU_MAX_MFD_DEV)
+ return -ENODEV;
+
+ /* Initialize platform data */
+ pdata = &rsmu_pdata[rsmu->index];
+ pdata->lock = &rsmu->lock;
+ pdata->type = rsmu->type;
+ pdata->index = rsmu->index;
+
+ /* Initialize MFD devices */
+ cmfd = &rsmu_cdev[rsmu->index];
+ if (rsmu->type == RSMU_CM)
+ pmfd = &rsmu_cm_pdev[rsmu->index];
+ else if (rsmu->type == RSMU_SABRE)
+ pmfd = &rsmu_sabre_pdev[rsmu->index];
+ else
+ return -EINVAL;
+
+ ret = rsmu_mfd_init(rsmu, pmfd, pdata);
+ if (ret)
+ return ret;
+
+ ret = rsmu_mfd_init(rsmu, cmfd, pdata);
+ if (ret)
+ return ret;
+
+ atomic_inc(&rsmu_ndevs);
+ return 0;
+}
+
+static int rsmu_dt_init(struct rsmu_dev *rsmu)
+{
+ struct device_node *np = rsmu->dev->of_node;
+
+ rsmu->type = RSMU_NONE;
+ if (of_device_is_compatible(np, "idt,8a34000")) {
+ rsmu->type = RSMU_CM;
+ } else if (of_device_is_compatible(np, "idt,82p33810")) {
+ rsmu->type = RSMU_SABRE;
+ } else {
+ dev_err(rsmu->dev, "unknown RSMU device\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rsmu_probe(struct spi_device *client)
+{
+ struct rsmu_dev *rsmu;
+ int ret;
+
+ rsmu = devm_kzalloc(&client->dev, sizeof(struct rsmu_dev), GFP_KERNEL);
+ if (rsmu == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(client, rsmu);
+ mutex_init(&rsmu->lock);
+ rsmu->dev = &client->dev;
+ rsmu->client = client;
+
+ ret = rsmu_dt_init(rsmu);
+ if (ret)
+ return ret;
+
+ mutex_lock(&rsmu->lock);
+ ret = rsmu_dev_init(rsmu);
+ mutex_unlock(&rsmu->lock);
+
+ if (ret == 0)
+ dev_info(rsmu->dev, "Probe %s successful\n",
+ rsmu_name(rsmu->type));
+
+ return ret;
+}
+
+static int rsmu_remove(struct spi_device *client)
+{
+ struct rsmu_dev *rsmu = spi_get_drvdata(client);
+
+ mfd_remove_devices(&client->dev);
+ mutex_destroy(&rsmu->lock);
+ atomic_dec(&rsmu_ndevs);
+
+ return 0;
+}
+
+static const struct spi_device_id rsmu_id[] = {
+ { "8a34000", 0 },
+ { "82p33810", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, rsmu_id);
+
+static const struct of_device_id rsmu_of_match[] = {
+ {.compatible = "idt,8a34000", },
+ {.compatible = "idt,82p33810", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rsmu_of_match);
+
+static struct spi_driver rsmu_driver = {
+ .driver = {
+ .name = "rsmu-spi",
+ .of_match_table = of_match_ptr(rsmu_of_match),
+ },
+ .probe = rsmu_probe,
+ .remove = rsmu_remove,
+ .id_table = rsmu_id,
+};
+
+static int __init rsmu_init(void)
+{
+ return spi_register_driver(&rsmu_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(rsmu_init);
+
+static void __exit rsmu_exit(void)
+{
+ spi_unregister_driver(&rsmu_driver);
+}
+module_exit(rsmu_exit);
+
+MODULE_DESCRIPTION("Renesas SMU SPI multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/idt82p33_reg.h b/include/linux/mfd/idt82p33_reg.h
new file mode 100644
index 0000000..50872b0
--- /dev/null
+++ b/include/linux/mfd/idt82p33_reg.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* idt82p33_reg.h
+ *
+ * Register Map - AN888_SMUforIEEE_SynchEther_82P33xxx_RevH.pdf
+ *
+ */
+#ifndef HAVE_IDT82P33_REG
+#define HAVE_IDT82P33_REG
+
+/* Register address */
+#define REG_ADDR(page, offset) (((page) << 0x7) | ((offset) & 0x7f))
+
+#define PAGE_ADDR 0x7F
+
+#define DPLL1_TOD_CNFG 0x134
+#define DPLL2_TOD_CNFG 0x1B4
+
+#define DPLL1_TOD_STS 0x10B
+#define DPLL2_TOD_STS 0x18B
+
+#define DPLL1_TOD_TRIGGER 0x115
+#define DPLL2_TOD_TRIGGER 0x195
+
+#define DPLL1_OPERATING_MODE_CNFG 0x120
+#define DPLL2_OPERATING_MODE_CNFG 0x1A0
+
+#define DPLL1_HOLDOVER_FREQ_CNFG 0x12C
+#define DPLL2_HOLDOVER_FREQ_CNFG 0x1AC
+
+#define DPLL1_PHASE_OFFSET_CNFG 0x143
+#define DPLL2_PHASE_OFFSET_CNFG 0x1C3
+
+#define DPLL1_SYNC_EDGE_CNFG 0x140
+#define DPLL2_SYNC_EDGE_CNFG 0x1C0
+
+#define DPLL1_INPUT_MODE_CNFG 0x116
+#define DPLL2_INPUT_MODE_CNFG 0x196
+
+#define DPLL1_OPERATING_STS 0x102
+#define DPLL2_OPERATING_STS 0x182
+
+#define DPLL1_CURRENT_FREQ_STS 0x103
+#define DPLL2_CURRENT_FREQ_STS 0x183
+
+#define REG_SOFT_RESET 0X381
+
+#define 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)
+
+/* 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)
+
+/* Bit definitions for DPLL_OPERATING_STS register */
+#define OPERATING_STS_MASK (0x7)
+#define 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)
+
+/* 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,
+};
+
+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,
+};
+
+/** @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
+};
+
+#endif
diff --git a/include/linux/mfd/idt8a340_reg.h b/include/linux/mfd/idt8a340_reg.h
new file mode 100644
index 0000000..e8868cd
--- /dev/null
+++ b/include/linux/mfd/idt8a340_reg.h
@@ -0,0 +1,817 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* idt8a340_reg.h
+ *
+ * Originally generated by regen.tcl on Thu Feb 14 19:23:44 PST 2019
+ * https://github.com/richardcochran/regen
+ *
+ * Hand modified to include some HW registers.
+ * Based on 4.8.0, SCSR rev C commit a03c7ae5
+ */
+#ifndef HAVE_IDT8A340_REG
+#define HAVE_IDT8A340_REG
+
+#define PAGE_ADDR_BASE 0x0000
+#define PAGE_ADDR 0x00fc
+
+#define HW_REVISION 0x8180
+#define REV_ID 0x007a
+
+#define HW_DPLL_0 (0x8a00)
+#define HW_DPLL_1 (0x8b00)
+#define HW_DPLL_2 (0x8c00)
+#define HW_DPLL_3 (0x8d00)
+#define HW_DPLL_4 (0x8e00)
+#define HW_DPLL_5 (0x8f00)
+#define HW_DPLL_6 (0x9000)
+#define HW_DPLL_7 (0x9100)
+
+#define HW_DPLL_TOD_SW_TRIG_ADDR__0 (0x080)
+#define HW_DPLL_TOD_CTRL_1 (0x089)
+#define HW_DPLL_TOD_CTRL_2 (0x08A)
+#define HW_DPLL_TOD_OVR__0 (0x098)
+#define HW_DPLL_TOD_OUT_0__0 (0x0B0)
+
+#define HW_Q0_Q1_CH_SYNC_CTRL_0 (0xa740)
+#define HW_Q0_Q1_CH_SYNC_CTRL_1 (0xa741)
+#define HW_Q2_Q3_CH_SYNC_CTRL_0 (0xa742)
+#define HW_Q2_Q3_CH_SYNC_CTRL_1 (0xa743)
+#define HW_Q4_Q5_CH_SYNC_CTRL_0 (0xa744)
+#define HW_Q4_Q5_CH_SYNC_CTRL_1 (0xa745)
+#define HW_Q6_Q7_CH_SYNC_CTRL_0 (0xa746)
+#define HW_Q6_Q7_CH_SYNC_CTRL_1 (0xa747)
+#define HW_Q8_CH_SYNC_CTRL_0 (0xa748)
+#define HW_Q8_CH_SYNC_CTRL_1 (0xa749)
+#define HW_Q9_CH_SYNC_CTRL_0 (0xa74a)
+#define HW_Q9_CH_SYNC_CTRL_1 (0xa74b)
+#define HW_Q10_CH_SYNC_CTRL_0 (0xa74c)
+#define HW_Q10_CH_SYNC_CTRL_1 (0xa74d)
+#define HW_Q11_CH_SYNC_CTRL_0 (0xa74e)
+#define HW_Q11_CH_SYNC_CTRL_1 (0xa74f)
+
+#define SYNC_SOURCE_DPLL0_TOD_PPS 0x14
+#define SYNC_SOURCE_DPLL1_TOD_PPS 0x15
+#define SYNC_SOURCE_DPLL2_TOD_PPS 0x16
+#define SYNC_SOURCE_DPLL3_TOD_PPS 0x17
+
+#define SYNCTRL1_MASTER_SYNC_RST BIT(7)
+#define SYNCTRL1_MASTER_SYNC_TRIG BIT(5)
+#define SYNCTRL1_TOD_SYNC_TRIG BIT(4)
+#define SYNCTRL1_FBDIV_FRAME_SYNC_TRIG BIT(3)
+#define SYNCTRL1_FBDIV_SYNC_TRIG BIT(2)
+#define SYNCTRL1_Q1_DIV_SYNC_TRIG BIT(1)
+#define SYNCTRL1_Q0_DIV_SYNC_TRIG BIT(0)
+
+#define HW_Q8_CTRL_SPARE (0xa7d4)
+#define HW_Q11_CTRL_SPARE (0xa7ec)
+
+/**
+ * Select FOD5 as sync_trigger for Q8 divider.
+ * Transition from logic zero to one
+ * sets trigger to sync Q8 divider.
+ *
+ * Unused when FOD4 is driving Q8 divider (normal operation).
+ */
+#define Q9_TO_Q8_SYNC_TRIG BIT(1)
+
+/**
+ * Enable FOD5 as driver for clock and sync for Q8 divider.
+ * Enable fanout buffer for FOD5.
+ *
+ * Unused when FOD4 is driving Q8 divider (normal operation).
+ */
+#define Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK (BIT(0) | BIT(2))
+
+/**
+ * Select FOD6 as sync_trigger for Q11 divider.
+ * Transition from logic zero to one
+ * sets trigger to sync Q11 divider.
+ *
+ * Unused when FOD7 is driving Q11 divider (normal operation).
+ */
+#define Q10_TO_Q11_SYNC_TRIG BIT(1)
+
+/**
+ * Enable FOD6 as driver for clock and sync for Q11 divider.
+ * Enable fanout buffer for FOD6.
+ *
+ * Unused when FOD7 is driving Q11 divider (normal operation).
+ */
+#define Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK (BIT(0) | BIT(2))
+
+#define RESET_CTRL 0xc000
+#define SM_RESET 0x0012
+#define SM_RESET_CMD 0x5A
+
+#define GENERAL_STATUS 0xc014
+#define BOOT_STATUS 0x0000
+#define HW_REV_ID 0x000A
+#define BOND_ID 0x000B
+#define HW_CSR_ID 0x000C
+#define HW_IRQ_ID 0x000E
+
+#define MAJ_REL 0x0010
+#define MIN_REL 0x0011
+#define HOTFIX_REL 0x0012
+
+#define PIPELINE_ID 0x0014
+#define BUILD_ID 0x0018
+
+#define JTAG_DEVICE_ID 0x001c
+#define PRODUCT_ID 0x001e
+
+#define OTP_SCSR_CONFIG_SELECT 0x0022
+
+#define STATUS 0xc03c
+#define DPLL0_STATUS 0x0018
+#define DPLL1_STATUS 0x0019
+#define DPLL2_STATUS 0x001a
+#define DPLL3_STATUS 0x001b
+#define DPLL4_STATUS 0x001c
+#define DPLL5_STATUS 0x001d
+#define DPLL6_STATUS 0x001e
+#define DPLL7_STATUS 0x001f
+#define DPLL_SYS_STATUS 0x0020
+#define DPLL_SYS_APLL_STATUS 0x0021
+#define DPLL0_FILTER_STATUS 0x0044
+#define DPLL1_FILTER_STATUS 0x004c
+#define DPLL2_FILTER_STATUS 0x0054
+#define DPLL3_FILTER_STATUS 0x005c
+#define DPLL4_FILTER_STATUS 0x0064
+#define DPLL5_FILTER_STATUS 0x006c
+#define DPLL6_FILTER_STATUS 0x0074
+#define DPLL7_FILTER_STATUS 0x007c
+#define DPLLSYS_FILTER_STATUS 0x0084
+#define USER_GPIO0_TO_7_STATUS 0x008a
+#define USER_GPIO8_TO_15_STATUS 0x008b
+
+#define GPIO_USER_CONTROL 0xc160
+#define GPIO0_TO_7_OUT 0x0000
+#define GPIO8_TO_15_OUT 0x0001
+
+#define STICKY_STATUS_CLEAR 0xc164
+
+#define GPIO_TOD_NOTIFICATION_CLEAR 0xc16c
+
+#define ALERT_CFG 0xc188
+
+#define SYS_DPLL_XO 0xc194
+
+#define SYS_APLL 0xc19c
+
+#define INPUT_0 0xc1b0
+
+#define INPUT_1 0xc1c0
+
+#define INPUT_2 0xc1d0
+
+#define INPUT_3 0xc200
+
+#define INPUT_4 0xc210
+
+#define INPUT_5 0xc220
+
+#define INPUT_6 0xc230
+
+#define INPUT_7 0xc240
+
+#define INPUT_8 0xc250
+
+#define INPUT_9 0xc260
+
+#define INPUT_10 0xc280
+
+#define INPUT_11 0xc290
+
+#define INPUT_12 0xc2a0
+
+#define INPUT_13 0xc2b0
+
+#define INPUT_14 0xc2c0
+
+#define INPUT_15 0xc2d0
+
+#define REF_MON_0 0xc2e0
+
+#define REF_MON_1 0xc2ec
+
+#define REF_MON_2 0xc300
+
+#define REF_MON_3 0xc30c
+
+#define REF_MON_4 0xc318
+
+#define REF_MON_5 0xc324
+
+#define REF_MON_6 0xc330
+
+#define REF_MON_7 0xc33c
+
+#define REF_MON_8 0xc348
+
+#define REF_MON_9 0xc354
+
+#define REF_MON_10 0xc360
+
+#define REF_MON_11 0xc36c
+
+#define REF_MON_12 0xc380
+
+#define REF_MON_13 0xc38c
+
+#define REF_MON_14 0xc398
+
+#define REF_MON_15 0xc3a4
+
+#define DPLL_0 0xc3b0
+#define DPLL_CTRL_REG_0 0x0002
+#define DPLL_CTRL_REG_1 0x0003
+#define DPLL_CTRL_REG_2 0x0004
+#define DPLL_TOD_SYNC_CFG 0x0031
+#define DPLL_COMBO_SLAVE_CFG_0 0x0032
+#define DPLL_COMBO_SLAVE_CFG_1 0x0033
+#define DPLL_SLAVE_REF_CFG 0x0034
+#define DPLL_REF_MODE 0x0035
+#define DPLL_PHASE_MEASUREMENT_CFG 0x0036
+#define DPLL_MODE 0x0037
+
+#define DPLL_1 0xc400
+
+#define DPLL_2 0xc438
+
+#define DPLL_3 0xc480
+
+#define DPLL_4 0xc4b8
+
+#define DPLL_5 0xc500
+
+#define DPLL_6 0xc538
+
+#define DPLL_7 0xc580
+
+#define SYS_DPLL 0xc5b8
+
+#define DPLL_CTRL_0 0xc600
+#define DPLL_CTRL_DPLL_MANU_REF_CFG 0x0001
+#define DPLL_CTRL_DPLL_FOD_FREQ 0x001c
+#define DPLL_CTRL_COMBO_MASTER_CFG 0x003a
+
+#define DPLL_CTRL_1 0xc63c
+
+#define DPLL_CTRL_2 0xc680
+
+#define DPLL_CTRL_3 0xc6bc
+
+#define DPLL_CTRL_4 0xc700
+
+#define DPLL_CTRL_5 0xc73c
+
+#define DPLL_CTRL_6 0xc780
+
+#define DPLL_CTRL_7 0xc7bc
+
+#define SYS_DPLL_CTRL 0xc800
+
+#define DPLL_PHASE_0 0xc818
+
+/* Signed 42-bit FFO in units of 2^(-53) */
+#define DPLL_WR_PHASE 0x0000
+
+#define DPLL_PHASE_1 0xc81c
+
+#define DPLL_PHASE_2 0xc820
+
+#define DPLL_PHASE_3 0xc824
+
+#define DPLL_PHASE_4 0xc828
+
+#define DPLL_PHASE_5 0xc82c
+
+#define DPLL_PHASE_6 0xc830
+
+#define DPLL_PHASE_7 0xc834
+
+#define DPLL_FREQ_0 0xc838
+
+/* Signed 42-bit FFO in units of 2^(-53) */
+#define DPLL_WR_FREQ 0x0000
+
+#define DPLL_FREQ_1 0xc840
+
+#define DPLL_FREQ_2 0xc848
+
+#define DPLL_FREQ_3 0xc850
+
+#define DPLL_FREQ_4 0xc858
+
+#define DPLL_FREQ_5 0xc860
+
+#define DPLL_FREQ_6 0xc868
+
+#define DPLL_FREQ_7 0xc870
+
+#define DPLL_PHASE_PULL_IN_0 0xc880
+#define PULL_IN_OFFSET 0x0000 /* Signed 32 bit */
+#define PULL_IN_SLOPE_LIMIT 0x0004 /* Unsigned 24 bit */
+#define PULL_IN_CTRL 0x0007
+
+#define DPLL_PHASE_PULL_IN_1 0xc888
+
+#define DPLL_PHASE_PULL_IN_2 0xc890
+
+#define DPLL_PHASE_PULL_IN_3 0xc898
+
+#define DPLL_PHASE_PULL_IN_4 0xc8a0
+
+#define DPLL_PHASE_PULL_IN_5 0xc8a8
+
+#define DPLL_PHASE_PULL_IN_6 0xc8b0
+
+#define DPLL_PHASE_PULL_IN_7 0xc8b8
+
+#define GPIO_CFG 0xc8c0
+#define GPIO_CFG_GBL 0x0000
+
+#define GPIO_0 0xc8c2
+#define GPIO_DCO_INC_DEC 0x0000
+#define GPIO_OUT_CTRL_0 0x0001
+#define GPIO_OUT_CTRL_1 0x0002
+#define GPIO_TOD_TRIG 0x0003
+#define GPIO_DPLL_INDICATOR 0x0004
+#define GPIO_LOS_INDICATOR 0x0005
+#define GPIO_REF_INPUT_DSQ_0 0x0006
+#define GPIO_REF_INPUT_DSQ_1 0x0007
+#define GPIO_REF_INPUT_DSQ_2 0x0008
+#define GPIO_REF_INPUT_DSQ_3 0x0009
+#define GPIO_MAN_CLK_SEL_0 0x000a
+#define GPIO_MAN_CLK_SEL_1 0x000b
+#define GPIO_MAN_CLK_SEL_2 0x000c
+#define GPIO_SLAVE 0x000d
+#define GPIO_ALERT_OUT_CFG 0x000e
+#define GPIO_TOD_NOTIFICATION_CFG 0x000f
+#define GPIO_CTRL 0x0010
+
+#define GPIO_1 0xc8d4
+
+#define GPIO_2 0xc8e6
+
+#define GPIO_3 0xc900
+
+#define GPIO_4 0xc912
+
+#define GPIO_5 0xc924
+
+#define GPIO_6 0xc936
+
+#define GPIO_7 0xc948
+
+#define GPIO_8 0xc95a
+
+#define GPIO_9 0xc980
+
+#define GPIO_10 0xc992
+
+#define GPIO_11 0xc9a4
+
+#define GPIO_12 0xc9b6
+
+#define GPIO_13 0xc9c8
+
+#define GPIO_14 0xc9da
+
+#define GPIO_15 0xca00
+
+#define OUT_DIV_MUX 0xca12
+
+#define OUTPUT_0 0xca14
+/* FOD frequency output divider value */
+#define OUT_DIV 0x0000
+#define OUT_DUTY_CYCLE_HIGH 0x0004
+#define OUT_CTRL_0 0x0008
+#define OUT_CTRL_1 0x0009
+/* Phase adjustment in FOD cycles */
+#define OUT_PHASE_ADJ 0x000c
+
+#define OUTPUT_1 0xca24
+
+#define OUTPUT_2 0xca34
+
+#define OUTPUT_3 0xca44
+
+#define OUTPUT_4 0xca54
+
+#define OUTPUT_5 0xca64
+
+#define OUTPUT_6 0xca80
+
+#define OUTPUT_7 0xca90
+
+#define OUTPUT_8 0xcaa0
+
+#define OUTPUT_9 0xcab0
+
+#define OUTPUT_10 0xcac0
+
+#define OUTPUT_11 0xcad0
+
+#define SERIAL 0xcae0
+
+#define PWM_ENCODER_0 0xcb00
+
+#define PWM_ENCODER_1 0xcb08
+
+#define PWM_ENCODER_2 0xcb10
+
+#define PWM_ENCODER_3 0xcb18
+
+#define PWM_ENCODER_4 0xcb20
+
+#define PWM_ENCODER_5 0xcb28
+
+#define PWM_ENCODER_6 0xcb30
+
+#define PWM_ENCODER_7 0xcb38
+
+#define PWM_DECODER_0 0xcb40
+
+#define PWM_DECODER_1 0xcb48
+
+#define PWM_DECODER_2 0xcb50
+
+#define PWM_DECODER_3 0xcb58
+
+#define PWM_DECODER_4 0xcb60
+
+#define PWM_DECODER_5 0xcb68
+
+#define PWM_DECODER_6 0xcb70
+
+#define PWM_DECODER_7 0xcb80
+
+#define PWM_DECODER_8 0xcb88
+
+#define PWM_DECODER_9 0xcb90
+
+#define PWM_DECODER_10 0xcb98
+
+#define PWM_DECODER_11 0xcba0
+
+#define PWM_DECODER_12 0xcba8
+
+#define PWM_DECODER_13 0xcbb0
+
+#define PWM_DECODER_14 0xcbb8
+
+#define PWM_DECODER_15 0xcbc0
+
+#define PWM_USER_DATA 0xcbc8
+
+#define TOD_0 0xcbcc
+
+/* Enable TOD counter, output channel sync and even-PPS mode */
+#define TOD_CFG 0x0000
+
+#define TOD_1 0xcbce
+
+#define TOD_2 0xcbd0
+
+#define TOD_3 0xcbd2
+
+
+#define TOD_WRITE_0 0xcc00
+/* 8-bit subns, 32-bit ns, 48-bit seconds */
+#define TOD_WRITE 0x0000
+/* Counter increments after TOD write is completed */
+#define TOD_WRITE_COUNTER 0x000c
+/* TOD write trigger configuration */
+#define TOD_WRITE_SELECT_CFG_0 0x000d
+/* TOD write trigger selection */
+#define TOD_WRITE_CMD 0x000f
+
+#define TOD_WRITE_1 0xcc10
+
+#define TOD_WRITE_2 0xcc20
+
+#define TOD_WRITE_3 0xcc30
+
+#define TOD_READ_PRIMARY_0 0xcc40
+/* 8-bit subns, 32-bit ns, 48-bit seconds */
+#define TOD_READ_PRIMARY 0x0000
+/* Counter increments after TOD write is completed */
+#define TOD_READ_PRIMARY_COUNTER 0x000b
+/* Read trigger configuration */
+#define TOD_READ_PRIMARY_SEL_CFG_0 0x000c
+/* Read trigger selection */
+#define TOD_READ_PRIMARY_CMD 0x000e
+
+#define TOD_READ_PRIMARY_1 0xcc50
+
+#define TOD_READ_PRIMARY_2 0xcc60
+
+#define TOD_READ_PRIMARY_3 0xcc80
+
+#define TOD_READ_SECONDARY_0 0xcc90
+
+#define TOD_READ_SECONDARY_1 0xcca0
+
+#define TOD_READ_SECONDARY_2 0xccb0
+
+#define TOD_READ_SECONDARY_3 0xccc0
+
+#define OUTPUT_TDC_CFG 0xccd0
+
+#define OUTPUT_TDC_0 0xcd00
+
+#define OUTPUT_TDC_1 0xcd08
+
+#define OUTPUT_TDC_2 0xcd10
+
+#define OUTPUT_TDC_3 0xcd18
+
+#define INPUT_TDC 0xcd20
+
+#define SCRATCH 0xcf50
+
+#define EEPROM 0xcf68
+
+#define OTP 0xcf70
+
+#define BYTE 0xcf80
+
+/* Bit definitions for the MAJ_REL register */
+#define MAJOR_SHIFT (1)
+#define MAJOR_MASK (0x7f)
+#define PR_BUILD BIT(0)
+
+/* Bit definitions for the USER_GPIO0_TO_7_STATUS register */
+#define GPIO0_LEVEL BIT(0)
+#define GPIO1_LEVEL BIT(1)
+#define GPIO2_LEVEL BIT(2)
+#define GPIO3_LEVEL BIT(3)
+#define GPIO4_LEVEL BIT(4)
+#define GPIO5_LEVEL BIT(5)
+#define GPIO6_LEVEL BIT(6)
+#define GPIO7_LEVEL BIT(7)
+
+/* Bit definitions for the USER_GPIO8_TO_15_STATUS register */
+#define GPIO8_LEVEL BIT(0)
+#define GPIO9_LEVEL BIT(1)
+#define GPIO10_LEVEL BIT(2)
+#define GPIO11_LEVEL BIT(3)
+#define GPIO12_LEVEL BIT(4)
+#define GPIO13_LEVEL BIT(5)
+#define GPIO14_LEVEL BIT(6)
+#define GPIO15_LEVEL BIT(7)
+
+/* Bit definitions for the GPIO0_TO_7_OUT register */
+#define GPIO0_DRIVE_LEVEL BIT(0)
+#define GPIO1_DRIVE_LEVEL BIT(1)
+#define GPIO2_DRIVE_LEVEL BIT(2)
+#define GPIO3_DRIVE_LEVEL BIT(3)
+#define GPIO4_DRIVE_LEVEL BIT(4)
+#define GPIO5_DRIVE_LEVEL BIT(5)
+#define GPIO6_DRIVE_LEVEL BIT(6)
+#define GPIO7_DRIVE_LEVEL BIT(7)
+
+/* Bit definitions for the GPIO8_TO_15_OUT register */
+#define GPIO8_DRIVE_LEVEL BIT(0)
+#define GPIO9_DRIVE_LEVEL BIT(1)
+#define GPIO10_DRIVE_LEVEL BIT(2)
+#define GPIO11_DRIVE_LEVEL BIT(3)
+#define GPIO12_DRIVE_LEVEL BIT(4)
+#define GPIO13_DRIVE_LEVEL BIT(5)
+#define GPIO14_DRIVE_LEVEL BIT(6)
+#define GPIO15_DRIVE_LEVEL BIT(7)
+
+/* Bit definitions for the DPLL_TOD_SYNC_CFG register */
+#define TOD_SYNC_SOURCE_SHIFT (1)
+#define TOD_SYNC_SOURCE_MASK (0x3)
+#define TOD_SYNC_EN BIT(0)
+
+/* Bit definitions for the DPLL_MODE register */
+#define WRITE_TIMER_MODE BIT(6)
+#define PLL_MODE_SHIFT (3)
+#define PLL_MODE_MASK (0x7)
+#define STATE_MODE_SHIFT (0)
+#define STATE_MODE_MASK (0x7)
+
+/* Bit definitions for the GPIO_CFG_GBL register */
+#define SUPPLY_MODE_SHIFT (0)
+#define SUPPLY_MODE_MASK (0x3)
+
+/* Bit definitions for the GPIO_DCO_INC_DEC register */
+#define INCDEC_DPLL_INDEX_SHIFT (0)
+#define INCDEC_DPLL_INDEX_MASK (0x7)
+
+/* Bit definitions for the GPIO_OUT_CTRL_0 register */
+#define CTRL_OUT_0 BIT(0)
+#define CTRL_OUT_1 BIT(1)
+#define CTRL_OUT_2 BIT(2)
+#define CTRL_OUT_3 BIT(3)
+#define CTRL_OUT_4 BIT(4)
+#define CTRL_OUT_5 BIT(5)
+#define CTRL_OUT_6 BIT(6)
+#define CTRL_OUT_7 BIT(7)
+
+/* Bit definitions for the GPIO_OUT_CTRL_1 register */
+#define CTRL_OUT_8 BIT(0)
+#define CTRL_OUT_9 BIT(1)
+#define CTRL_OUT_10 BIT(2)
+#define CTRL_OUT_11 BIT(3)
+#define CTRL_OUT_12 BIT(4)
+#define CTRL_OUT_13 BIT(5)
+#define CTRL_OUT_14 BIT(6)
+#define CTRL_OUT_15 BIT(7)
+
+/* Bit definitions for the GPIO_TOD_TRIG register */
+#define TOD_TRIG_0 BIT(0)
+#define TOD_TRIG_1 BIT(1)
+#define TOD_TRIG_2 BIT(2)
+#define TOD_TRIG_3 BIT(3)
+
+/* Bit definitions for the GPIO_DPLL_INDICATOR register */
+#define IND_DPLL_INDEX_SHIFT (0)
+#define IND_DPLL_INDEX_MASK (0x7)
+
+/* Bit definitions for the GPIO_LOS_INDICATOR register */
+#define REFMON_INDEX_SHIFT (0)
+#define REFMON_INDEX_MASK (0xf)
+/* Active level of LOS indicator, 0=low 1=high */
+#define ACTIVE_LEVEL BIT(4)
+
+/* Bit definitions for the GPIO_REF_INPUT_DSQ_0 register */
+#define DSQ_INP_0 BIT(0)
+#define DSQ_INP_1 BIT(1)
+#define DSQ_INP_2 BIT(2)
+#define DSQ_INP_3 BIT(3)
+#define DSQ_INP_4 BIT(4)
+#define DSQ_INP_5 BIT(5)
+#define DSQ_INP_6 BIT(6)
+#define DSQ_INP_7 BIT(7)
+
+/* Bit definitions for the GPIO_REF_INPUT_DSQ_1 register */
+#define DSQ_INP_8 BIT(0)
+#define DSQ_INP_9 BIT(1)
+#define DSQ_INP_10 BIT(2)
+#define DSQ_INP_11 BIT(3)
+#define DSQ_INP_12 BIT(4)
+#define DSQ_INP_13 BIT(5)
+#define DSQ_INP_14 BIT(6)
+#define DSQ_INP_15 BIT(7)
+
+/* Bit definitions for the GPIO_REF_INPUT_DSQ_2 register */
+#define DSQ_DPLL_0 BIT(0)
+#define DSQ_DPLL_1 BIT(1)
+#define DSQ_DPLL_2 BIT(2)
+#define DSQ_DPLL_3 BIT(3)
+#define DSQ_DPLL_4 BIT(4)
+#define DSQ_DPLL_5 BIT(5)
+#define DSQ_DPLL_6 BIT(6)
+#define DSQ_DPLL_7 BIT(7)
+
+/* Bit definitions for the GPIO_REF_INPUT_DSQ_3 register */
+#define DSQ_DPLL_SYS BIT(0)
+#define GPIO_DSQ_LEVEL BIT(1)
+
+/* Bit definitions for the GPIO_TOD_NOTIFICATION_CFG register */
+#define DPLL_TOD_SHIFT (0)
+#define DPLL_TOD_MASK (0x3)
+#define TOD_READ_SECONDARY BIT(2)
+#define GPIO_ASSERT_LEVEL BIT(3)
+
+/* Bit definitions for the GPIO_CTRL register */
+#define GPIO_FUNCTION_EN BIT(0)
+#define GPIO_CMOS_OD_MODE BIT(1)
+#define GPIO_CONTROL_DIR BIT(2)
+#define GPIO_PU_PD_MODE BIT(3)
+#define GPIO_FUNCTION_SHIFT (4)
+#define GPIO_FUNCTION_MASK (0xf)
+
+/* Bit definitions for the OUT_CTRL_1 register */
+#define OUT_SYNC_DISABLE BIT(7)
+#define SQUELCH_VALUE BIT(6)
+#define SQUELCH_DISABLE BIT(5)
+#define PAD_VDDO_SHIFT (2)
+#define PAD_VDDO_MASK (0x7)
+#define PAD_CMOSDRV_SHIFT (0)
+#define PAD_CMOSDRV_MASK (0x3)
+
+/* Bit definitions for the TOD_CFG register */
+#define TOD_EVEN_PPS_MODE BIT(2)
+#define TOD_OUT_SYNC_ENABLE BIT(1)
+#define TOD_ENABLE BIT(0)
+
+/* Bit definitions for the TOD_WRITE_SELECT_CFG_0 register */
+#define WR_PWM_DECODER_INDEX_SHIFT (4)
+#define WR_PWM_DECODER_INDEX_MASK (0xf)
+#define WR_REF_INDEX_SHIFT (0)
+#define WR_REF_INDEX_MASK (0xf)
+
+/* Bit definitions for the TOD_WRITE_CMD register */
+#define TOD_WRITE_SELECTION_SHIFT (0)
+#define TOD_WRITE_SELECTION_MASK (0xf)
+/* 4.8.7 */
+#define TOD_WRITE_TYPE_SHIFT (4)
+#define TOD_WRITE_TYPE_MASK (0x3)
+
+/* Bit definitions for the TOD_READ_PRIMARY_SEL_CFG_0 register */
+#define RD_PWM_DECODER_INDEX_SHIFT (4)
+#define RD_PWM_DECODER_INDEX_MASK (0xf)
+#define RD_REF_INDEX_SHIFT (0)
+#define RD_REF_INDEX_MASK (0xf)
+
+/* Bit definitions for the TOD_READ_PRIMARY_CMD register */
+#define TOD_READ_TRIGGER_MODE BIT(4)
+#define TOD_READ_TRIGGER_SHIFT (0)
+#define TOD_READ_TRIGGER_MASK (0xf)
+
+/* Bit definitions for the DPLL_CTRL_COMBO_MASTER_CFG register */
+#define COMBO_MASTER_HOLD BIT(0)
+
+/* Bit definitions for DPLL_SYS_STATUS register */
+#define DPLL_SYS_STATE_MASK (0xf)
+
+/* Bit definitions for SYS_APLL_STATUS register */
+#define SYS_APLL_LOSS_LOCK_LIVE_MASK BIT(0)
+#define SYS_APLL_LOSS_LOCK_LIVE_LOCKED 0
+#define SYS_APLL_LOSS_LOCK_LIVE_UNLOCKED 1
+
+/* Bit definitions for the DPLL0_STATUS register */
+#define DPLL_STATE_MASK (0xf)
+#define DPLL_STATE_SHIFT (0x0)
+
+/* Values of DPLL_N.DPLL_MODE.PLL_MODE */
+enum pll_mode {
+ PLL_MODE_MIN = 0,
+ PLL_MODE_NORMAL = PLL_MODE_MIN,
+ PLL_MODE_WRITE_PHASE = 1,
+ PLL_MODE_WRITE_FREQUENCY = 2,
+ PLL_MODE_GPIO_INC_DEC = 3,
+ PLL_MODE_SYNTHESIS = 4,
+ PLL_MODE_PHASE_MEASUREMENT = 5,
+ PLL_MODE_DISABLED = 6,
+ PLL_MODE_MAX = PLL_MODE_DISABLED,
+};
+
+enum hw_tod_write_trig_sel {
+ HW_TOD_WR_TRIG_SEL_MIN = 0,
+ HW_TOD_WR_TRIG_SEL_MSB = HW_TOD_WR_TRIG_SEL_MIN,
+ HW_TOD_WR_TRIG_SEL_RESERVED = 1,
+ HW_TOD_WR_TRIG_SEL_TOD_PPS = 2,
+ HW_TOD_WR_TRIG_SEL_IRIGB_PPS = 3,
+ HW_TOD_WR_TRIG_SEL_PWM_PPS = 4,
+ HW_TOD_WR_TRIG_SEL_GPIO = 5,
+ HW_TOD_WR_TRIG_SEL_FOD_SYNC = 6,
+ WR_TRIG_SEL_MAX = HW_TOD_WR_TRIG_SEL_FOD_SYNC,
+};
+
+enum scsr_read_trig_sel {
+ /* CANCEL CURRENT TOD READ; MODULE BECOMES IDLE - NO TRIGGER OCCURS */
+ SCSR_TOD_READ_TRIG_SEL_DISABLE = 0,
+ /* TRIGGER IMMEDIATELY */
+ SCSR_TOD_READ_TRIG_SEL_IMMEDIATE = 1,
+ /* TRIGGER ON RISING EDGE OF INTERNAL TOD PPS SIGNAL */
+ SCSR_TOD_READ_TRIG_SEL_TODPPS = 2,
+ /* TRGGER ON RISING EDGE OF SELECTED REFERENCE INPUT */
+ SCSR_TOD_READ_TRIG_SEL_REFCLK = 3,
+ /* TRIGGER ON RISING EDGE OF SELECTED PWM DECODER 1PPS OUTPUT */
+ SCSR_TOD_READ_TRIG_SEL_PWMPPS = 4,
+ SCSR_TOD_READ_TRIG_SEL_RESERVED = 5,
+ /* TRIGGER WHEN WRITE FREQUENCY EVENT OCCURS */
+ SCSR_TOD_READ_TRIG_SEL_WRITEFREQUENCYEVENT = 6,
+ /* TRIGGER ON SELECTED GPIO */
+ SCSR_TOD_READ_TRIG_SEL_GPIO = 7,
+ SCSR_TOD_READ_TRIG_SEL_MAX = SCSR_TOD_READ_TRIG_SEL_GPIO,
+};
+
+/* Values STATUS.DPLL_SYS_STATUS.DPLL_SYS_STATE */
+enum dpll_state {
+ DPLL_STATE_MIN = 0,
+ DPLL_STATE_FREERUN = DPLL_STATE_MIN,
+ DPLL_STATE_LOCKACQ = 1,
+ DPLL_STATE_LOCKREC = 2,
+ DPLL_STATE_LOCKED = 3,
+ DPLL_STATE_HOLDOVER = 4,
+ DPLL_STATE_OPEN_LOOP = 5,
+ DPLL_STATE_MAX = DPLL_STATE_OPEN_LOOP,
+};
+
+/* 4.8.7 only */
+enum scsr_tod_write_trig_sel {
+ SCSR_TOD_WR_TRIG_SEL_DISABLE = 0,
+ SCSR_TOD_WR_TRIG_SEL_IMMEDIATE = 1,
+ SCSR_TOD_WR_TRIG_SEL_REFCLK = 2,
+ SCSR_TOD_WR_TRIG_SEL_PWMPPS = 3,
+ SCSR_TOD_WR_TRIG_SEL_TODPPS = 4,
+ SCSR_TOD_WR_TRIG_SEL_SYNCFOD = 5,
+ SCSR_TOD_WR_TRIG_SEL_GPIO = 6,
+ SCSR_TOD_WR_TRIG_SEL_MAX = SCSR_TOD_WR_TRIG_SEL_GPIO,
+};
+
+/* 4.8.7 only */
+enum scsr_tod_write_type_sel {
+ SCSR_TOD_WR_TYPE_SEL_ABSOLUTE = 0,
+ SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS = 1,
+ SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS = 2,
+ SCSR_TOD_WR_TYPE_SEL_MAX = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS,
+};
+#endif
diff --git a/include/linux/mfd/rsmu.h b/include/linux/mfd/rsmu.h
new file mode 100644
index 0000000..843dd6c
--- /dev/null
+++ b/include/linux/mfd/rsmu.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Multi-function 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 __LINUX_MFD_RSMU_H
+#define __LINUX_MFD_RSMU_H
+
+/* We only support Clockmatrix and Sabre now */
+enum rsmu_type {
+ RSMU_CM = 0,
+ RSMU_SABRE = 1,
+ RSMU_NONE = 2,
+};
+
+/**
+ *
+ * struct rsmu_pdata - platform data structure for MFD cell devices.
+ *
+ * @lock: Mutex used by cell devices to make sure a series of requests
+ * are not interrupted.
+ *
+ * @type: RSMU device type.
+ *
+ * @index: Device index.
+ */
+struct rsmu_pdata {
+ enum rsmu_type type;
+ struct mutex *lock;
+ u8 index;
+};
+
+static inline char *rsmu_name(enum rsmu_type type)
+{
+ switch (type) {
+ case RSMU_CM:
+ return "ClockMatrix";
+ case RSMU_SABRE:
+ return "Sabre";
+ default:
+ return "Unknown SMU";
+ }
+}
+
+/**
+ * NOTE: the functions below are not intended for use outside
+ * of the IDT synchronization management unit drivers
+ */
+extern int rsmu_write(struct device *dev, u16 reg, u8 *buf, u16 size);
+extern int rsmu_read(struct device *dev, u16 reg, u8 *buf, u16 size);
+#endif /* __LINUX_MFD_RSMU_H */
--
2.7.4


2021-04-08 01:58:35

by Min Li

[permalink] [raw]
Subject: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

From: Min Li <[email protected]>

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 <[email protected]>
---
Change log
-rebase change to linux-next tree
-remove uncessary condition checks suggested by Greg
-fix compile error for x86_64
-register device through misc_register suggested by Greg
-change to use module_platform_device to register driver
-remove empty open and release functions
-more informational comment for struct rsmu_cdev

drivers/misc/Kconfig | 9 ++
drivers/misc/Makefile | 2 +
drivers/misc/rsmu_cdev.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/rsmu_cdev.h | 74 +++++++++++++++
drivers/misc/rsmu_cm.c | 166 +++++++++++++++++++++++++++++++++
drivers/misc/rsmu_sabre.c | 133 ++++++++++++++++++++++++++
include/uapi/linux/rsmu.h | 64 +++++++++++++
7 files changed, 679 insertions(+)
create mode 100644 drivers/misc/rsmu_cdev.c
create mode 100644 drivers/misc/rsmu_cdev.h
create mode 100644 drivers/misc/rsmu_cm.c
create mode 100644 drivers/misc/rsmu_sabre.c
create mode 100644 include/uapi/linux/rsmu.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f532c59..49b523a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -445,6 +445,15 @@ 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 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
+ 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 99b6f15..21b8ed4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,5 @@ obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
+rsmu-objs := rsmu_cdev.o rsmu_cm.o rsmu_sabre.o
+obj-$(CONFIG_RSMU) += rsmu.o
diff --git a/drivers/misc/rsmu_cdev.c b/drivers/misc/rsmu_cdev.c
new file mode 100644
index 0000000..8e5c49b
--- /dev/null
+++ b/drivers/misc/rsmu_cdev.c
@@ -0,0 +1,231 @@
+// 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) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+#include "rsmu_cdev.h"
+
+static struct rsmu_ops *ops_array[] = {
+ [RSMU_CM] = &cm_ops,
+ [RSMU_SABRE] = &sabre_ops,
+};
+
+static int
+rsmu_set_combomode(struct rsmu_cdev *rsmu, void __user *arg)
+{
+ struct rsmu_ops *ops = rsmu->ops;
+ struct rsmu_combomode mode;
+ int err;
+
+ if (copy_from_user(&mode, arg, sizeof(mode)))
+ return -EFAULT;
+
+ if (ops->set_combomode == NULL)
+ return -ENOTSUPP;
+
+ mutex_lock(rsmu->lock);
+ err = ops->set_combomode(rsmu, mode.dpll, mode.mode);
+ mutex_unlock(rsmu->lock);
+
+ return err;
+}
+
+static int
+rsmu_get_dpll_state(struct rsmu_cdev *rsmu, void __user *arg)
+{
+ struct rsmu_ops *ops = rsmu->ops;
+ struct rsmu_get_state state_request;
+ u8 state;
+ int err;
+
+ if (copy_from_user(&state_request, arg, sizeof(state_request)))
+ return -EFAULT;
+
+ if (ops->get_dpll_state == NULL)
+ return -ENOTSUPP;
+
+ mutex_lock(rsmu->lock);
+ err = ops->get_dpll_state(rsmu, state_request.dpll, &state);
+ mutex_unlock(rsmu->lock);
+
+ 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_ops *ops = rsmu->ops;
+ struct rsmu_get_ffo ffo_request;
+ int err;
+
+ if (copy_from_user(&ffo_request, arg, sizeof(ffo_request)))
+ return -EFAULT;
+
+ if (ops->get_dpll_ffo == NULL)
+ return -ENOTSUPP;
+
+ mutex_lock(rsmu->lock);
+ err = ops->get_dpll_ffo(rsmu, ffo_request.dpll, &ffo_request);
+ mutex_unlock(rsmu->lock);
+
+ 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 */
+ dev_err(rsmu->dev, "Undefined RSMU IOCTL");
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static long rsmu_compat_ioctl(struct file *fptr, unsigned int cmd,
+ unsigned long data)
+{
+ return rsmu_ioctl(fptr, cmd, data);
+}
+
+static const struct file_operations rsmu_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = rsmu_ioctl,
+ .compat_ioctl = rsmu_compat_ioctl,
+};
+
+static int rsmu_init_ops(struct rsmu_cdev *rsmu)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ops_array); i++)
+ if (ops_array[i]->type == rsmu->type)
+ break;
+
+ if (i == ARRAY_SIZE(ops_array))
+ return -EINVAL;
+
+ rsmu->ops = ops_array[i];
+ return 0;
+}
+
+static int
+rsmu_probe(struct platform_device *pdev)
+{
+ struct rsmu_pdata *pdata = dev_get_platdata(&pdev->dev);
+ struct rsmu_cdev *rsmu;
+ int err;
+
+ rsmu = devm_kzalloc(&pdev->dev, sizeof(*rsmu), GFP_KERNEL);
+ if (!rsmu)
+ return -ENOMEM;
+
+ rsmu->dev = &pdev->dev;
+ rsmu->mfd = pdev->dev.parent;
+ rsmu->type = pdata->type;
+ rsmu->lock = pdata->lock;
+ rsmu->index = pdata->index;
+
+ /* Save driver private data */
+ platform_set_drvdata(pdev, rsmu);
+
+ /* Initialize and register the miscdev */
+ rsmu->miscdev.minor = MISC_DYNAMIC_MINOR;
+ rsmu->miscdev.fops = &rsmu_fops;
+ snprintf(rsmu->name, sizeof(rsmu->name), "rsmu%d", rsmu->index);
+ rsmu->miscdev.name = rsmu->name;
+ err = misc_register(&rsmu->miscdev);
+ if (err) {
+ dev_err(rsmu->dev, "Unable to register device\n");
+ return -ENODEV;
+ }
+
+ err = rsmu_init_ops(rsmu);
+ if (err) {
+ dev_err(rsmu->dev, "Unknown SMU type %d", rsmu->type);
+ return err;
+ }
+
+ dev_info(rsmu->dev, "Probe %s successful\n", rsmu->name);
+ return 0;
+}
+
+static int
+rsmu_remove(struct platform_device *pdev)
+{
+ struct rsmu_cdev *rsmu = platform_get_drvdata(pdev);
+
+ misc_deregister(&rsmu->miscdev);
+
+ return 0;
+}
+
+static const struct platform_device_id rsmu_id_table[] = {
+ { "rsmu-cdev0", },
+ { "rsmu-cdev1", },
+ { "rsmu-cdev2", },
+ { "rsmu-cdev3", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, rsmu_id_table);
+
+static struct platform_driver rsmu_driver = {
+ .driver = {
+ .name = "rsmu",
+ },
+ .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/drivers/misc/rsmu_cdev.h b/drivers/misc/rsmu_cdev.h
new file mode 100644
index 0000000..fe1d923
--- /dev/null
+++ b/drivers/misc/rsmu_cdev.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * This driver is developed for the IDT ClockMatrix(TM) of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+#ifndef __LINUX_RSMU_CDEV_H
+#define __LINUX_RSMU_CDEV_H
+
+#include <linux/miscdevice.h>
+
+struct rsmu_ops;
+
+/**
+ * struct rsmu_cdev - Driver data for RSMU character device
+ * @name: rsmu device name as rsmu[index]
+ * @dev: pointer to device
+ * @mfd: pointer to MFD device
+ * @miscdev: character device handle
+ * @lock: mutex to protect operations from being interrupted
+ * @type: rsmu device type, passed through platform data
+ * @ops: rsmu device methods
+ * @index: rsmu device index, passed through platform data
+ */
+struct rsmu_cdev {
+ char name[16];
+ struct device *dev;
+ struct device *mfd;
+ struct miscdevice miscdev;
+ struct mutex *lock;
+ enum rsmu_type type;
+ struct rsmu_ops *ops;
+ u8 index;
+};
+
+extern struct rsmu_ops cm_ops;
+extern struct rsmu_ops sabre_ops;
+
+struct rsmu_ops {
+ enum rsmu_type type;
+ int (*set_combomode)(struct rsmu_cdev *rsmu, u8 dpll, u8 mode);
+ int (*get_dpll_state)(struct rsmu_cdev *rsmu, u8 dpll, u8 *state);
+ int (*get_dpll_ffo)(struct rsmu_cdev *rsmu, u8 dpll,
+ struct rsmu_get_ffo *ffo);
+};
+
+/**
+ * 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,
+};
+#endif
diff --git a/drivers/misc/rsmu_cm.c b/drivers/misc/rsmu_cm.c
new file mode 100644
index 0000000..d5af624
--- /dev/null
+++ b/drivers/misc/rsmu_cm.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This driver is developed for the IDT ClockMatrix(TM) of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/mfd/idt8a340_reg.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+#include <asm/unaligned.h>
+
+#include "rsmu_cdev.h"
+
+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 = rsmu_read(rsmu->mfd, 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 rsmu_write(rsmu->mfd, 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 = rsmu_read(rsmu->mfd,
+ 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 = rsmu_read(rsmu->mfd, 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;
+}
+
+struct rsmu_ops cm_ops = {
+ .type = RSMU_CM,
+ .set_combomode = rsmu_cm_set_combomode,
+ .get_dpll_state = rsmu_cm_get_dpll_state,
+ .get_dpll_ffo = rsmu_cm_get_dpll_ffo,
+};
diff --git a/drivers/misc/rsmu_sabre.c b/drivers/misc/rsmu_sabre.c
new file mode 100644
index 0000000..ca32b2f
--- /dev/null
+++ b/drivers/misc/rsmu_sabre.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This driver is developed for the IDT 82P33XXX series of
+ * timing and synchronization devices.
+ *
+ * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/mfd/idt82p33_reg.h>
+#include <linux/mfd/rsmu.h>
+#include <uapi/linux/rsmu.h>
+#include <asm/unaligned.h>
+
+#include "rsmu_cdev.h"
+
+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 = DPLL1_OPERATING_MODE_CNFG;
+ break;
+ case 1:
+ dpll_ctrl_n = DPLL2_OPERATING_MODE_CNFG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mode >= E_COMBOMODE_MAX)
+ return -EINVAL;
+
+ err = rsmu_read(rsmu->mfd, dpll_ctrl_n, &cfg, sizeof(cfg));
+ if (err)
+ return err;
+
+ cfg &= ~(COMBO_MODE_MASK << COMBO_MODE_SHIFT);
+ cfg |= mode << COMBO_MODE_SHIFT;
+
+ return rsmu_write(rsmu->mfd, 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 = DPLL1_OPERATING_STS;
+ break;
+ case 1:
+ dpll_sts_n = DPLL2_OPERATING_STS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = rsmu_read(rsmu->mfd, dpll_sts_n, &cfg, sizeof(cfg));
+ if (err)
+ return err;
+
+ switch (cfg & OPERATING_STS_MASK) {
+ case DPLL_STATE_FREERUN:
+ *state = E_SRVLOUNQUALIFIEDSTATE;
+ break;
+ case DPLL_STATE_PRELOCKED2:
+ case DPLL_STATE_PRELOCKED:
+ *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_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 = DPLL1_HOLDOVER_FREQ_CNFG;
+ break;
+ case 1:
+ dpll_freq_n = DPLL2_HOLDOVER_FREQ_CNFG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = rsmu_read(rsmu->mfd, 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 * 168615, 1000);
+
+ return 0;
+}
+
+struct rsmu_ops sabre_ops = {
+ .type = RSMU_SABRE,
+ .set_combomode = rsmu_sabre_set_combomode,
+ .get_dpll_state = rsmu_sabre_get_dpll_state,
+ .get_dpll_ffo = rsmu_sabre_get_dpll_ffo,
+};
diff --git a/include/uapi/linux/rsmu.h b/include/uapi/linux/rsmu.h
new file mode 100644
index 0000000..02c9e38
--- /dev/null
+++ b/include/uapi/linux/rsmu.h
@@ -0,0 +1,64 @@
+/* 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 '?'
+
+/**
+ * @Description
+ * ioctl to set SMU combo mode.
+ *
+ * @Parameters
+ * pointer to struct rsmu_combomode that contains dpll combomode setting
+ */
+#define RSMU_SET_COMBOMODE _IOW(RSMU_MAGIC, 1, struct rsmu_combomode)
+
+/**
+ * @Description
+ * ioctl to get SMU dpll state.
+ *
+ * @Parameters
+ * pointer to struct rsmu_get_state that contains dpll state
+ */
+#define RSMU_GET_STATE _IOR(RSMU_MAGIC, 2, struct rsmu_get_state)
+
+/**
+ * @Description
+ * ioctl to get SMU dpll ffo.
+ *
+ * @Parameters
+ * pointer to struct rsmu_get_ffo that contains dpll ffo in ppqt
+ */
+#define RSMU_GET_FFO _IOR(RSMU_MAGIC, 3, struct rsmu_get_ffo)
+#endif /* __UAPI_LINUX_RSMU_CDEV_H */
--
2.7.4

2021-04-08 06:24:10

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

On Wed, Apr 07, 2021 at 09:50:50PM -0400, [email protected] wrote:
> From: Min Li <[email protected]>
>
> 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 <[email protected]>
> ---
> Change log
> -rebase change to linux-next tree
> -remove uncessary condition checks suggested by Greg
> -fix compile error for x86_64
> -register device through misc_register suggested by Greg
> -change to use module_platform_device to register driver
> -remove empty open and release functions
> -more informational comment for struct rsmu_cdev
>
> drivers/misc/Kconfig | 9 ++
> drivers/misc/Makefile | 2 +
> drivers/misc/rsmu_cdev.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/misc/rsmu_cdev.h | 74 +++++++++++++++
> drivers/misc/rsmu_cm.c | 166 +++++++++++++++++++++++++++++++++
> drivers/misc/rsmu_sabre.c | 133 ++++++++++++++++++++++++++

Again, please make this only one file.

thanks,

greg k-h

2021-04-08 07:09:28

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCH net-next v3 1/2] mfd: Add Renesas Synchronization Management Unit (SMU) support

On Wed, 07 Apr 2021, [email protected] wrote:

> From: Min Li <[email protected]>
>
> Add support for ClockMatrix(TM) and 82P33xxx families of timing
> and synchronization devices. The access interface can be either
> SPI or I2C. Currently, it will create 2 types of MFD devices,
> which are to be used by the corresponding rsmu character device
> driver and the PTP hardware clock driver, respectively.
>
> Signed-off-by: Min Li <[email protected]>
> ---

If this is v3, there should be a changelog here.

> drivers/mfd/Kconfig | 28 ++
> drivers/mfd/Makefile | 3 +
> drivers/mfd/rsmu_i2c.c | 349 +++++++++++++++++
> drivers/mfd/rsmu_private.h | 32 ++
> drivers/mfd/rsmu_spi.c | 376 ++++++++++++++++++
> include/linux/mfd/idt82p33_reg.h | 116 ++++++
> include/linux/mfd/idt8a340_reg.h | 817 +++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/rsmu.h | 54 +++
> 8 files changed, 1775 insertions(+)
> create mode 100644 drivers/mfd/rsmu_i2c.c
> create mode 100644 drivers/mfd/rsmu_private.h
> create mode 100644 drivers/mfd/rsmu_spi.c
> create mode 100644 include/linux/mfd/idt82p33_reg.h
> create mode 100644 include/linux/mfd/idt8a340_reg.h
> create mode 100644 include/linux/mfd/rsmu.h

--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog

2021-04-08 17:29:13

by Min Li

[permalink] [raw]
Subject: RE: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

>
> Again, please make this only one file.
>
Hi Greg, the 2 boards have some same named registers in idt82p33_reg.h and idt8a340_reg.h
so if I put them all in the same file, there will be name conflicts.

2021-04-08 17:40:25

by Min Li

[permalink] [raw]
Subject: RE: [PATCH net-next v3 1/2] mfd: Add Renesas Synchronization Management Unit (SMU) support

>
> If this is v3, there should be a changelog here.
>
Hi Lee

There is no change in v3 for MFD part of code, v3 is only for misc part.
But I have to format 2 patches together and that is why mfd part got v3 as well.
But it is actually identical to v2

2021-04-08 17:54:54

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

On Thu, Apr 08, 2021 at 05:26:40PM +0000, Min Li wrote:
> >
> > Again, please make this only one file.
> >
> Hi Greg, the 2 boards have some same named registers in idt82p33_reg.h and idt8a340_reg.h
> so if I put them all in the same file, there will be name conflicts.

That does not make sense, this is only one kernel module, with one .h
file in this patch, I do not see those other files you are talking
about...

And if you have named registers that are identical, and yet you only
work on one device, that feels like a design flaw somewhere :)

thanks,

greg k-h

2021-04-08 18:06:08

by Min Li

[permalink] [raw]
Subject: RE: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

>
> That does not make sense, this is only one kernel module, with one .h file in
> this patch, I do not see those other files you are talking about...
>
> And if you have named registers that are identical, and yet you only work on
> one device, that feels like a design flaw somewhere :)
>

Hi Greg, the register files are in the 1/2 patch for the mfd part of the change.
The reason they have same named register is because they are all synchronization
devices and they share some similar features

2021-04-08 18:13:51

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

On Thu, Apr 08, 2021 at 06:01:42PM +0000, Min Li wrote:
> >
> > That does not make sense, this is only one kernel module, with one .h file in
> > this patch, I do not see those other files you are talking about...
> >
> > And if you have named registers that are identical, and yet you only work on
> > one device, that feels like a design flaw somewhere :)
> >
>
> Hi Greg, the register files are in the 1/2 patch for the mfd part of the change.
> The reason they have same named register is because they are all synchronization
> devices and they share some similar features

But what does that have to do with the misc device?

totally confused,

greg k-h

2021-04-08 19:00:15

by Min Li

[permalink] [raw]
Subject: RE: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

>
> But what does that have to do with the misc device?
>

Hi Greg, MFD driver is the start of everything. Once MFD driver is loading, it will spawn 2 devices,
one is for phc driver, which is under /driver/ptp and the other one is for this misc driver.
Both PHC and misc drivers are operating on the same device.
They are both calling exported functions from mfd drivers to access the device through i2c/spi
and the register definitions are located in include/Linux/mfd/idt8a340_reg.h or idt82p33_reg.h
depending on which device was found by mfd driver through device tree node.

2021-04-09 06:45:16

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH net-next v3 2/2] misc: Add Renesas Synchronization Management Unit (SMU) support

On Thu, Apr 08, 2021 at 06:59:19PM +0000, Min Li wrote:
> >
> > But what does that have to do with the misc device?
> >
>
> Hi Greg, MFD driver is the start of everything. Once MFD driver is loading, it will spawn 2 devices,
> one is for phc driver, which is under /driver/ptp and the other one is for this misc driver.
> Both PHC and misc drivers are operating on the same device.
> They are both calling exported functions from mfd drivers to access the device through i2c/spi
> and the register definitions are located in include/Linux/mfd/idt8a340_reg.h or idt82p33_reg.h
> depending on which device was found by mfd driver through device tree node.

I don't think it's a good idea to have the same defines with different
values in different files, that's just a problem waiting to happen...

good luck!

greg k-h

2021-04-09 10:17:10

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCH net-next v3 1/2] mfd: Add Renesas Synchronization Management Unit (SMU) support

On Thu, 08 Apr 2021, Min Li wrote:

> >
> > If this is v3, there should be a changelog here.
> >
> Hi Lee
>
> There is no change in v3 for MFD part of code, v3 is only for misc part.
> But I have to format 2 patches together and that is why mfd part got v3 as well.
> But it is actually identical to v2

Then you need to mention that in the change log.

What changed from v1 => v2?

--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog

2021-04-09 13:58:30

by Min Li

[permalink] [raw]
Subject: RE: [PATCH net-next v3 1/2] mfd: Add Renesas Synchronization Management Unit (SMU) support

>
> Then you need to mention that in the change log.
>
> What changed from v1 => v2?
>

Please look it up by the latest patch I sent over yesterday. It is under the Signed-off-by

---
-rebase change to linux-next tree
-add log to inform driver loading success

2021-04-11 18:57:06

by Min Li

[permalink] [raw]
Subject: RE: [PATCH net-next v3 1/2] mfd: Add Renesas Synchronization Management Unit (SMU) support

>
> Then you need to mention that in the change log.
>
> What changed from v1 => v2?
>
Please see my latest [PATCH next v2] and it has the following change log

Signed-off-by: Min Li <[email protected]>
---
-rebase change to linux-next tree
-add log to inform driver loading success