[PATCH linux dev-4.7 2/4] misc: Add partial Aspeed LPC Host Interface Control (HIC) driver

Andrew Jeffery andrew at aj.id.au
Thu Nov 10 12:35:54 AEDT 2016


Exposes some of the LPC controller's host interface control registers in
sysfs, specifically HICR5-HICR8, HICR9-HICRA.  At the moment the
resource range also covers the SNPWADR and SNPWDR (LPC Snoop registers),
but they are not exposed in sysfs.

Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
---
 drivers/misc/Kconfig      |   7 ++
 drivers/misc/Makefile     |   1 +
 drivers/misc/aspeed-hic.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 drivers/misc/aspeed-hic.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 27327f44a709..1c5b9b2b26aa 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -58,6 +58,13 @@ config ASPEED_SCRSIO
 	  Select this if you wish to expose to userspace the SuperIO scratch
 	  registers in the LPC control space on an Aspeed BMC SoC.
 
+config ASPEED_HIC
+	bool "Support for Aspeed LPC Host Interface Control Registers"
+	depends on ARCH_ASPEED || COMPILE_TEST
+	help
+	  Select this if you wish to expose to userspace the LPC Host Interface
+	  Control Registers on an Aspeed BMC SoC.
+
 config ATMEL_TCLIB
 	bool "Atmel AT32/AT91 Timer/Counter Library"
 	depends on (AVR32 || ARCH_AT91)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 0bcd6ff61a12..b49051932471 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_AD525X_DPOT)	+= ad525x_dpot.o
 obj-$(CONFIG_AD525X_DPOT_I2C)	+= ad525x_dpot-i2c.o
 obj-$(CONFIG_AD525X_DPOT_SPI)	+= ad525x_dpot-spi.o
+obj-$(CONFIG_ASPEED_HIC)	+= aspeed-hic.o
 obj-$(CONFIG_ASPEED_SCRSIO)	+= aspeed-scrsio.o
 obj-$(CONFIG_INTEL_MID_PTI)	+= pti.o
 obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
diff --git a/drivers/misc/aspeed-hic.c b/drivers/misc/aspeed-hic.c
new file mode 100644
index 000000000000..d26b9daab126
--- /dev/null
+++ b/drivers/misc/aspeed-hic.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2016 IBM Corporation
+ *
+ * Andrew Jeffery <andrew at aj.id.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define LPC_HICR5		0x0
+#define LPC_HICR6		0x4
+#define LPC_HICR7		0x8
+#define LPC_HICR8		0xc
+#define LPC_HICR9		0x18
+#define LPC_HICRA		0x1c
+
+struct aspeed_hic {
+	void __iomem *hicr5;
+};
+
+static ssize_t hic_store(void __iomem *base, int reg, const char *buf,
+		size_t len)
+{
+	int r;
+	u32 value;
+
+	r = kstrtou32(buf, 0, &value);
+	if (r)
+		return r;
+
+	iowrite32(value, base + reg);
+
+	return len;
+}
+
+ssize_t hic_show(void __iomem *base, int reg, char *buf)
+{
+	u32 value = ioread32(base + reg);
+
+	return scnprintf(buf, PAGE_SIZE, "0x%08x\n", value);
+}
+
+static ssize_t hicr5_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_store(hic->hicr5, LPC_HICR5, buf, len);
+}
+
+static ssize_t hicr5_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_show(hic->hicr5, LPC_HICR5, buf);
+}
+DEVICE_ATTR_RW(hicr5);
+
+static ssize_t hicr6_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_store(hic->hicr5, LPC_HICR6, buf, len);
+}
+
+static ssize_t hicr6_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_show(hic->hicr5, LPC_HICR6, buf);
+}
+DEVICE_ATTR_RW(hicr6);
+
+static ssize_t hicr7_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_store(hic->hicr5, LPC_HICR7, buf, len);
+}
+
+static ssize_t hicr7_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_show(hic->hicr5, LPC_HICR7, buf);
+}
+DEVICE_ATTR_RW(hicr7);
+
+static ssize_t hicr8_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_store(hic->hicr5, LPC_HICR8, buf, len);
+}
+
+static ssize_t hicr8_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_show(hic->hicr5, LPC_HICR8, buf);
+}
+DEVICE_ATTR_RW(hicr8);
+
+static ssize_t hicr9_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_store(hic->hicr5, LPC_HICR9, buf, len);
+}
+
+static ssize_t hicr9_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_show(hic->hicr5, LPC_HICR9, buf);
+}
+DEVICE_ATTR_RW(hicr9);
+
+static ssize_t hicra_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_store(hic->hicr5, LPC_HICRA, buf, len);
+}
+
+static ssize_t hicra_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct aspeed_hic *hic = dev_get_drvdata(dev);
+
+	return hic_show(hic->hicr5, LPC_HICRA, buf);
+}
+DEVICE_ATTR_RW(hicra);
+
+static struct attribute *hic_attrs[] = {
+	&dev_attr_hicr5.attr,
+	&dev_attr_hicr6.attr,
+	&dev_attr_hicr7.attr,
+	&dev_attr_hicr8.attr,
+	&dev_attr_hicr9.attr,
+	&dev_attr_hicra.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(hic);
+
+static int __init aspeed_hic_probe(struct platform_device *pdev)
+{
+	struct aspeed_hic *hic;
+	struct resource *res;
+
+	hic = devm_kzalloc(&pdev->dev, sizeof(*hic), GFP_KERNEL);
+	if (!hic)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hic->hicr5 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hic->hicr5))
+		return PTR_ERR(hic->hicr5);
+
+	dev_set_drvdata(&pdev->dev, hic);
+
+	return sysfs_create_groups(&pdev->dev.kobj, hic_groups);
+}
+
+static const struct of_device_id aspeed_hic_of_match[] = {
+	{ .compatible = "aspeed,ast2400-hic"},
+	{ .compatible = "aspeed,ast2500-hic"},
+};
+
+static struct platform_driver aspeed_hic_driver = {
+	.driver = {
+		.name = "aspeed_hic",
+		.of_match_table = aspeed_hic_of_match,
+	},
+};
+module_platform_driver_probe(aspeed_hic_driver, aspeed_hic_probe);
+
+MODULE_AUTHOR("Andrew Jeffery <andrew at aj.id.au>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Aspeed LPC Host Interface Controller");
-- 
2.9.3



More information about the openbmc mailing list