[dev-4.7 patch 3/5] misc (aspeed) introduce Aspeed SoC peci driver

vadimp at mellanox.com vadimp at mellanox.com
Wed Aug 10 17:03:11 AEST 2016


From: Vadim Pasternak <vadimp at mellanox.com>

The Kconfig controlling compilation of this code is:
drivers/misc/aspeed/Kconfig:config ASPEED_PECI

Porting peci driver from 3.18 to 4.7.

Signed-off-by: Vadim Pasternak <vadimp at mellanox.com>
---
 drivers/misc/Kconfig              |   1 +
 drivers/misc/aspeed/Kconfig       |  12 +
 drivers/misc/aspeed/Makefile      |   5 +
 drivers/misc/aspeed/aspeed-peci.c | 569 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 587 insertions(+)
 create mode 100644 drivers/misc/aspeed/Kconfig
 create mode 100644 drivers/misc/aspeed/Makefile
 create mode 100644 drivers/misc/aspeed/aspeed-peci.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4617ddc..bdf63da 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -821,4 +821,5 @@ source "drivers/misc/mic/Kconfig"
 source "drivers/misc/genwqe/Kconfig"
 source "drivers/misc/echo/Kconfig"
 source "drivers/misc/cxl/Kconfig"
+source "drivers/misc/aspeed/Kconfig"
 endmenu
diff --git a/drivers/misc/aspeed/Kconfig b/drivers/misc/aspeed/Kconfig
new file mode 100644
index 0000000..dedce9c
--- /dev/null
+++ b/drivers/misc/aspeed/Kconfig
@@ -0,0 +1,12 @@
+menu "ASPEED devices support"
+
+config ASPEED_PECI
+	tristate "Aspeed PECI driver"
+	depends on I2C
+	default n
+	help
+	  This option enables Aspeed PECI driver support.
+
+	  If unsure, say N.
+
+endmenu
diff --git a/drivers/misc/aspeed/Makefile b/drivers/misc/aspeed/Makefile
new file mode 100644
index 0000000..e502851
--- /dev/null
+++ b/drivers/misc/aspeed/Makefile
@@ -0,0 +1,5 @@
+
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := \
+        -I$(srctree)/arch/arm/mach-aspeed/include
+
+obj-$(CONFIG_ASPEED_PECI) += aspeed-peci.o
diff --git a/drivers/misc/aspeed/aspeed-peci.c b/drivers/misc/aspeed/aspeed-peci.c
new file mode 100644
index 0000000..4350bc4
--- /dev/null
+++ b/drivers/misc/aspeed/aspeed-peci.c
@@ -0,0 +1,569 @@
+/*
+ *  driver/misc/aspeed/aspeed_peci.c
+ *
+ *  ASPEED PECI controller driver
+ *
+ *  Copyright (C) 2012-2020  ASPEED Technology Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  History:
+ *   2013.01.30: Initial version [Ryan Chen]
+ *   2016.08.06: Porting to kernel 4.7 [Vadim Pasternak vadimp at mellanox.com]
+ */
+
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/configfs.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <asm/mach-types.h>
+#include <mach/reset.h>
+
+/*AST PECI Register Definition */
+#define AST_PECI_CTRL		0x00
+#define AST_PECI_TIMING		0x04
+#define AST_PECI_CMD		0x08
+#define AST_PECI_CMD_CTRL	0x0C
+#define AST_PECI_EXP_FCS	0x10
+#define AST_PECI_CAP_FCS	0x14
+#define AST_PECI_INT_CTRL	0x18
+#define AST_PECI_INT_STS	0x1C
+#define AST_PECI_W_DATA0	0x20
+#define AST_PECI_W_DATA1	0x24
+#define AST_PECI_W_DATA2	0x28
+#define AST_PECI_W_DATA3	0x2c
+#define AST_PECI_R_DATA0	0x30
+#define AST_PECI_R_DATA1	0x34
+#define AST_PECI_R_DATA2	0x38
+#define AST_PECI_R_DATA3	0x3c
+#define AST_PECI_W_DATA4	0x40
+#define AST_PECI_W_DATA5	0x44
+#define AST_PECI_W_DATA6	0x48
+#define AST_PECI_W_DATA7	0x4c
+#define AST_PECI_R_DATA4	0x50
+#define AST_PECI_R_DATA5	0x54
+#define AST_PECI_R_DATA6	0x58
+#define AST_PECI_R_DATA7	0x5c
+
+
+/* AST_PECI_CTRL - 0x00 : Control Register */
+#define PECI_CTRL_SAMPLING_MASK		(0xf << 16)
+#define PECI_CTRL_SAMPLING(x)		(x << 16)
+#define PECI_CTRL_READ_MODE_MASK	(0xf << 12)
+#define PECI_CTRL_CONT_MODE		(1 << 16)
+#define PECI_CTRL_DBG_MODE		(2 << 16)
+#define PECI_CTRL_CLK_SOURCE		(0x1 << 11) /*0: 24Mhz, 1: MCLK */
+#define PECI_CTRL_CLK_DIV_MASK		(0x3 << 8)
+#define PECI_CTRL_CLK_DIV(x)		(x << 8)
+#define PECI_CTRL_INVERT_OUT		(0x1 << 7)
+#define PECI_CTRL_INVERT_IN		(0x1 << 6)
+#define PECI_CTRL_BUS_CONTENT_EN	(0x1 << 5)
+#define PECI_CTRL_PECI_EN		(0x1 << 4)
+#define PECI_CTRL_PECI_CLK_EN		(0x1)
+
+/* AST_PECI_TIMING - 0x04 : Timing Negotiation */
+#define PECI_TIMING_MESSAGE_GET(x)	((x & 0xff00) >> 8)
+#define PECI_TIMING_MESSAGE(x)		(x << 8)
+#define PECI_TIMING_ADDRESS_GET(x)	(x & 0xff)
+#define PECI_TIMING_ADDRESS(x)		(x)
+
+/* AST_PECI_CMD	- 0x08 : Command Register */
+#define PECI_CMD_PIN_MON		(0x1 << 31)
+#define PECI_CMD_STS			(0xf << 24)
+#define PECI_CMD_FIRE			(0x1)
+
+/* AST_PECI_LEN	- 0x0C : Read/Write Length Register */
+#define PECI_AW_FCS_EN			(0x1 << 31)
+#define PECI_READ_LEN_MASK		(0xff << 16)
+#define PECI_READ_LEN(x)		(x << 16)
+#define PECI_WRITE_LEN_MASK		(0xff << 8)
+#define PECI_WRITE_LEN(x)		(x << 8)
+#define PECI_TAGET_ADDR_MASK		(0xff)
+#define PECI_TAGET_ADDR(x)		(x)
+
+
+/* AST_PECI_EXP_FCS	- 0x10 : Expected FCS Data Register  */
+#define PECI_PROGRAM_AW_FCS		(0xf << 24)
+#define PECI_EXPECT_READ_FCS		(0xf << 16)
+#define PECI_EXPECT_AW_FCS_AUTO		(0xf << 8)
+#define PECI_EXPECT_WRITE_FCS		(0xf)
+
+/* AST_PECI_CAP_FCS	- 0x14 : Captured FCS Data Register */
+#define PECI_CAPTURE_READ_FCS(x)	((x & 0xff) >> 16)
+#define PECI_CAPTURE_WRITE_FCS		(0xff)
+
+/* AST_PECI_INT_CTRL/ STS  - 0x18/0x1c  : Interrupt Register */
+#define PECI_INT_TIMING_RESULT_MASK	(0x3 << 30)
+#define PECI_INT_TIMEOUT		(0x1 << 4)
+#define PECI_INT_CONNECT		(0x1 << 3)
+#define PECI_INT_W_FCS_BAD		(0x1 << 2)
+#define PECI_INT_W_FCS_ABORT		(0x1 << 1)
+#define PECI_INT_CMD_DONE			(0x1)
+
+#define AUTO_GEN_AWFCS		1
+#define DISABLE_ENGINE		0
+#define ENABLE_RX_ENGINE	(1 << 0)
+#define ENABLE_TX_ENGINE	(1 << 1)
+#define LEFT_CHANNEL_HIGH	(1 << 16)
+#define DELAY_CLOCK_CYCLE	(1 << 17)
+
+struct timing_negotiation {
+	u8		msg_timing;
+	u8		addr_timing;
+};
+
+struct xfer_msg {
+	u8		client_addr;
+	u8		tx_len;
+	u8		rx_len;
+	u8		tx_fcs;
+	u8		rx_fcs;
+	u8		fcs_en;
+	u8		sw_fcs;
+	u8		*tx_buf;
+	u8		*rx_buf;
+	u32		sts;
+};
+
+#define PECI_DEVICE "/dev/aspeed-peci"
+#define PECIIOC_BASE 'P'
+#define AST_PECI_IOCRTIMING _IOR(PECIIOC_BASE, 0, struct timing_negotiation*)
+#define AST_PECI_IOCWTIMING _IOW(PECIIOC_BASE, 1, struct timing_negotiation*)
+#define AST_PECI_IOCXFER _IOWR(PECIIOC_BASE, 2, struct xfer_msg*)
+
+static struct aspeed_peci_data {
+	struct device		*misc_dev;
+	void __iomem		*reg_base;
+	int			irq;
+	int			open_count;
+	struct completion	xfer_complete;
+	u32			sts;
+	struct mutex		lock;
+} aspeed_peci;
+
+static inline void aspeed_peci_write(u32 val, u32 reg)
+{
+	dev_dbg(aspeed_peci.misc_dev, "write offset: %x, val: %x\n", reg, val);
+	writel(val, aspeed_peci.reg_base + reg);
+}
+
+static inline u32 aspeed_peci_read(u32 reg)
+{
+	u32 val = readl(aspeed_peci.reg_base + reg);
+
+	dev_dbg(aspeed_peci.misc_dev, "read offset: %x, val: %x\n", reg, val);
+
+	return val;
+}
+
+static long
+aspeed_peci_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct xfer_msg msg;
+	struct timing_negotiation tim_ng;
+	u32 peci_head;
+	int i = 0;
+	long ret = 0;
+
+	u32 *tx_buf0 = (u32 *) (aspeed_peci.reg_base + AST_PECI_W_DATA0);
+	u32 *tx_buf1 = (u32 *) (aspeed_peci.reg_base + AST_PECI_W_DATA4);
+	u32 *rx_buf0 = (u32 *) (aspeed_peci.reg_base + AST_PECI_R_DATA0);
+	u32 *rx_buf1 = (u32 *) (aspeed_peci.reg_base + AST_PECI_R_DATA4);
+	u32 rx_data = 0;
+
+	dev_dbg(aspeed_peci.misc_dev, "aspeed_peci_ioctl cmd %x\n", cmd);
+
+	switch (cmd) {
+	case AST_PECI_IOCRTIMING:
+		tim_ng.msg_timing = PECI_TIMING_MESSAGE_GET(
+					aspeed_peci_read(AST_PECI_TIMING));
+		tim_ng.addr_timing = PECI_TIMING_ADDRESS_GET(
+					aspeed_peci_read(AST_PECI_TIMING));
+		if (copy_to_user(argp, &tim_ng,
+				 sizeof(struct timing_negotiation)))
+			ret = -EFAULT;
+		break;
+
+	case AST_PECI_IOCWTIMING:
+		if (copy_from_user(&tim_ng, argp,
+				   sizeof(struct timing_negotiation)))
+			ret = -EFAULT;
+		else
+			aspeed_peci_write(
+				PECI_TIMING_MESSAGE(tim_ng.msg_timing) |
+				PECI_TIMING_ADDRESS(tim_ng.addr_timing),
+				AST_PECI_TIMING);
+
+		break;
+
+	case AST_PECI_IOCXFER:
+		/* Check cmd operation sts */
+		while (aspeed_peci_read(AST_PECI_CMD) & PECI_CMD_FIRE)
+			dev_dbg(aspeed_peci.misc_dev, "wait for free\n");
+
+		if (copy_from_user(&msg, argp, sizeof(struct xfer_msg))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (msg.fcs_en)
+			peci_head = PECI_TAGET_ADDR(msg.client_addr) |
+						PECI_WRITE_LEN(msg.tx_len) |
+						PECI_READ_LEN(msg.rx_len) |
+						PECI_AW_FCS_EN;
+		else
+			peci_head = PECI_TAGET_ADDR(msg.client_addr) |
+						PECI_WRITE_LEN(msg.tx_len) |
+						PECI_READ_LEN(msg.rx_len);
+
+		aspeed_peci_write(peci_head, AST_PECI_CMD_CTRL);
+
+		for (i = 0; i < msg.tx_len; i++) {
+			if (i < 16) {
+				if (i % 4 == 0)
+					tx_buf0[i / 4] = 0;
+				tx_buf0[i/4] |= (msg.tx_buf[i] << ((i%4) * 8));
+			} else {
+				if (i % 4 == 0)
+					tx_buf1[i / 4] = 0;
+				tx_buf1[i/4] |= (msg.tx_buf[i] << ((i%4) * 8));
+			}
+		}
+
+#ifdef CONFIG_AST_PECI_DEBUG
+		aspeed_peci_read(AST_PECI_W_DATA0);
+		aspeed_peci_read(AST_PECI_W_DATA1);
+		aspeed_peci_read(AST_PECI_W_DATA2);
+		aspeed_peci_read(AST_PECI_W_DATA3);
+		aspeed_peci_read(AST_PECI_W_DATA4);
+		aspeed_peci_read(AST_PECI_W_DATA5);
+		aspeed_peci_read(AST_PECI_W_DATA6);
+		aspeed_peci_read(AST_PECI_W_DATA7);
+#endif
+		init_completion(&aspeed_peci.xfer_complete);
+		/* Fire Command */
+		aspeed_peci_write(PECI_CMD_FIRE, AST_PECI_CMD);
+
+		ret = wait_for_completion_interruptible_timeout(
+					&aspeed_peci.xfer_complete, 30 * HZ);
+
+		if (ret == 0)
+			dev_err(aspeed_peci.misc_dev, "peci controller timed out\n");
+
+		for (i = 0; i < msg.rx_len; i++) {
+			if (i < 16) {
+				switch (i % 4) {
+				case 0:
+					rx_data = rx_buf0[i/4];
+					msg.rx_buf[i] = rx_data & 0xff;
+					break;
+
+				case 1:
+					msg.rx_buf[i] = (rx_data & 0xff00)
+							>> 8;
+					break;
+
+				case 2:
+					msg.rx_buf[i] = (rx_data & 0xff0000)
+							>> 16;
+					break;
+
+				case 3:
+					msg.rx_buf[i] = (rx_data & 0xff000000)
+							>> 24;
+					break;
+				}
+			} else {
+				switch (i % 4) {
+				case 0:
+					rx_data = rx_buf1[i/4];
+					msg.rx_buf[i] = rx_data & 0xff;
+					break;
+
+				case 1:
+					msg.rx_buf[i] = (rx_data & 0xff00)
+							>> 8;
+					break;
+				case 2:
+					msg.rx_buf[i] = (rx_data & 0xff0000)
+							>> 16;
+					break;
+
+				case 3:
+					msg.rx_buf[i] = (rx_data & 0xff000000)
+							>> 24;
+					break;
+				}
+			}
+		}
+
+#ifdef CONFIG_AST_PECI_DEBUG
+		aspeed_peci_read(AST_PECI_R_DATA0);
+		aspeed_peci_read(AST_PECI_R_DATA1);
+		aspeed_peci_read(AST_PECI_R_DATA2);
+		aspeed_peci_read(AST_PECI_R_DATA3);
+		aspeed_peci_read(AST_PECI_R_DATA4);
+		aspeed_peci_read(AST_PECI_R_DATA5);
+		aspeed_peci_read(AST_PECI_R_DATA6);
+		aspeed_peci_read(AST_PECI_R_DATA7);
+#endif
+		dev_dbg(aspeed_peci.misc_dev, "rx_buf:");
+		for (i = 0; i < msg.rx_len; i++)
+			dev_dbg(aspeed_peci.misc_dev, "%x ", msg.rx_buf[i]);
+		dev_dbg(aspeed_peci.misc_dev, "\n");
+
+		msg.sts = aspeed_peci.sts;
+		msg.rx_fcs = PECI_CAPTURE_READ_FCS(
+					aspeed_peci_read(AST_PECI_CAP_FCS));
+		if (copy_to_user(argp, &msg, sizeof(struct xfer_msg)))
+			ret = -EFAULT;
+		break;
+
+	default:
+		dev_err(aspeed_peci.misc_dev,
+			"aspeed_peci_ioctl command fail\n");
+		ret = -ENOTTY;
+		break;
+	}
+
+	return ret;
+}
+
+static int aspeed_peci_open(struct inode *inode, struct file *file)
+{
+	/* Flush input queue on first open */
+	if (aspeed_peci.open_count)
+		return -1;
+
+	aspeed_peci.open_count++;
+
+
+	return 0;
+}
+
+static int aspeed_peci_release(struct inode *inode, struct file *file)
+{
+	aspeed_peci.open_count--;
+
+	return 0;
+}
+
+static irqreturn_t aspeed_peci_handler(int this_irq, void *dev_id)
+{
+	struct aspeed_peci_data *peci_data = dev_id;
+
+	aspeed_peci.sts = (0x1f & aspeed_peci_read(AST_PECI_INT_STS));
+
+	switch (aspeed_peci.sts) {
+	case PECI_INT_TIMEOUT:
+		dev_info(peci_data->misc_dev, "PECI_INT_TIMEOUT\n");
+		aspeed_peci_write(PECI_INT_TIMEOUT, AST_PECI_INT_STS);
+		break;
+
+	case PECI_INT_CONNECT:
+		dev_info(peci_data->misc_dev, "PECI_INT_CONNECT\n");
+		aspeed_peci_write(PECI_INT_CONNECT, AST_PECI_INT_STS);
+		break;
+
+	case PECI_INT_W_FCS_BAD:
+		dev_info(peci_data->misc_dev, "PECI_INT_W_FCS_BAD\n");
+		aspeed_peci_write(PECI_INT_W_FCS_BAD, AST_PECI_INT_STS);
+		break;
+
+	case PECI_INT_W_FCS_ABORT:
+		dev_info(peci_data->misc_dev, "PECI_INT_W_FCS_ABORT\n");
+		aspeed_peci_write(PECI_INT_W_FCS_ABORT, AST_PECI_INT_STS);
+		break;
+
+	case PECI_INT_CMD_DONE:
+		dev_info(peci_data->misc_dev, "PECI_INT_CMD_DONE\n");
+		aspeed_peci_write(PECI_INT_CMD_DONE, AST_PECI_INT_STS);
+		aspeed_peci_write(0, AST_PECI_CMD);
+		break;
+
+	default:
+		dev_info(peci_data->misc_dev, "no one handle\n");
+		break;
+
+	}
+
+	complete(&aspeed_peci.xfer_complete);
+
+	return IRQ_HANDLED;
+
+}
+
+static void aspeed_peci_ctrl_init(void)
+{
+	aspeed_peci_write(PECI_CTRL_SAMPLING(8) |
+			  PECI_CTRL_PECI_CLK_EN, AST_PECI_CTRL);
+
+	/* iming Setting : should 4 times of peci clk period 64 = 16 * 4 */
+	aspeed_peci_write(PECI_TIMING_MESSAGE(64) | PECI_TIMING_ADDRESS(64),
+			  AST_PECI_TIMING);
+
+	/* peci Spec wide speed rangs [2kbps~2Mbps]
+	 * ampling 8/16, READ mode : Point Sampling , CLK source : 24Mhz , DIV
+	 * by 8 : 3 --> CLK is 3Mhz
+	 * peci CTRL Enable
+	 */
+	aspeed_peci_write(PECI_CTRL_SAMPLING(8) | PECI_CTRL_CLK_DIV(3) |
+			  PECI_CTRL_PECI_EN | PECI_CTRL_PECI_CLK_EN,
+			  AST_PECI_CTRL);
+
+	/* Clear Interrupt */
+	aspeed_peci_write(PECI_INT_TIMEOUT | PECI_INT_CONNECT |
+			  PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT |
+			  PECI_INT_CMD_DONE, AST_PECI_INT_STS);
+
+
+	/* peci Negotiation Selection , interrupt enable.
+	 * Set nego mode :  1st bit of addr negotiation
+	 */
+	aspeed_peci_write(PECI_INT_TIMEOUT | PECI_INT_CONNECT |
+			  PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT |
+			  PECI_INT_CMD_DONE, AST_PECI_INT_CTRL);
+}
+
+static const struct file_operations aspeed_peci_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.unlocked_ioctl = aspeed_peci_ioctl,
+	.open		= aspeed_peci_open,
+	.release	= aspeed_peci_release,
+};
+
+struct miscdevice aspeed_peci_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "aspeed-peci",
+	.fops = &aspeed_peci_fops,
+};
+
+static int aspeed_peci_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret = 0;
+
+	if (!of_device_is_compatible(pdev->dev.of_node,
+				     "aspeed,aspeed2500-peci"))
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n");
+		ret = -ENOENT;
+		goto out;
+	}
+
+	aspeed_peci.reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (!aspeed_peci.reg_base) {
+		ret = -EIO;
+		goto out_region;
+	}
+
+	aspeed_peci.irq = platform_get_irq(pdev, 0);
+	if (aspeed_peci.irq < 0) {
+		dev_err(&pdev->dev, "no irq specified\n");
+		ret = -ENOENT;
+		goto out_region;
+	}
+
+	ret = devm_request_irq(&pdev->dev, aspeed_peci.irq,
+			       aspeed_peci_handler, 0, "aspeed-peci",
+			       &aspeed_peci);
+
+	if (ret) {
+		dev_info(&pdev->dev, "PECI: Failed request irq %d\n",
+			 aspeed_peci.irq);
+		goto out_region;
+	}
+
+	ret = misc_register(&aspeed_peci_misc);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"aspeed_peci : failed to request interrupt\n");
+		goto out_region;
+	}
+
+	aspeed_peci.misc_dev = &pdev->dev;
+	platform_set_drvdata(pdev, &aspeed_peci);
+
+	/* Reset PECI controller */
+	aspeed_toggle_scu_reset(SCU_RESET_PECI, 3);
+
+	aspeed_peci_ctrl_init();
+	dev_info(&pdev->dev, "aspeed_peci: driver successfully loaded.\n");
+
+	return 0;
+
+out_region:
+	release_mem_region(res->start, res->end - res->start + 1);
+out:
+	dev_warn(&pdev->dev, "aspeed_peci: driver init failed (ret=%d)!\n",
+		  ret);
+	return ret;
+}
+
+static int aspeed_peci_remove(struct platform_device *pdev)
+{
+	misc_deregister(&aspeed_peci_misc);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+aspeed_peci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	dev_info(&pdev->dev, "aspeed_peci_suspend : TODO\n");
+	return 0;
+}
+
+static int aspeed_peci_resume(struct platform_device *pdev)
+{
+	aspeed_peci_ctrl_init();
+
+	return 0;
+}
+
+#else
+#define aspeed_peci_suspend        NULL
+#define aspeed_peci_resume         NULL
+#endif
+
+static const struct of_device_id aspeed_peci_of_table[] = {
+	{ .compatible = "aspeed,aspeed2500-peci", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, aspeed_peci_of_table);
+
+static struct platform_driver aspeed_peci_driver = {
+	.probe		= aspeed_peci_probe,
+	.remove		= aspeed_peci_remove,
+	.suspend        = aspeed_peci_suspend,
+	.resume         = aspeed_peci_resume,
+	.driver         = {
+		.name   = KBUILD_MODNAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = aspeed_peci_of_table,
+	},
+};
+
+module_platform_driver(aspeed_peci_driver);
+
+MODULE_AUTHOR("Ryan Chen <ryan_chen at aspeedtech.com>");
+MODULE_DESCRIPTION("AST PECI driver");
+MODULE_LICENSE("GPL");
-- 
2.1.4



More information about the openbmc mailing list