MIPS: TXx9: Add SRAMC support

Add a sysdev to access SRAM in TXx9 SoCs via sysfs.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index 7f91012..3b7d77d 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -24,6 +24,7 @@
 #include <linux/serial_core.h>
 #include <linux/mtd/physmap.h>
 #include <linux/leds.h>
+#include <linux/sysdev.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/reboot.h>
@@ -912,3 +913,86 @@
 		platform_device_put(pdev);
 #endif
 }
+
+static struct sysdev_class txx9_sramc_sysdev_class;
+
+struct txx9_sramc_sysdev {
+	struct sys_device dev;
+	struct bin_attribute bindata_attr;
+	void __iomem *base;
+};
+
+static ssize_t txx9_sram_read(struct kobject *kobj,
+			      struct bin_attribute *bin_attr,
+			      char *buf, loff_t pos, size_t size)
+{
+	struct txx9_sramc_sysdev *dev = bin_attr->private;
+	size_t ramsize = bin_attr->size;
+
+	if (pos >= ramsize)
+		return 0;
+	if (pos + size > ramsize)
+		size = ramsize - pos;
+	memcpy_fromio(buf, dev->base + pos, size);
+	return size;
+}
+
+static ssize_t txx9_sram_write(struct kobject *kobj,
+			       struct bin_attribute *bin_attr,
+			       char *buf, loff_t pos, size_t size)
+{
+	struct txx9_sramc_sysdev *dev = bin_attr->private;
+	size_t ramsize = bin_attr->size;
+
+	if (pos >= ramsize)
+		return 0;
+	if (pos + size > ramsize)
+		size = ramsize - pos;
+	memcpy_toio(dev->base + pos, buf, size);
+	return size;
+}
+
+void __init txx9_sramc_init(struct resource *r)
+{
+	struct txx9_sramc_sysdev *dev;
+	size_t size;
+	int err;
+
+	if (!txx9_sramc_sysdev_class.name) {
+		txx9_sramc_sysdev_class.name = "txx9_sram";
+		err = sysdev_class_register(&txx9_sramc_sysdev_class);
+		if (err) {
+			txx9_sramc_sysdev_class.name = NULL;
+			return;
+		}
+	}
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return;
+	size = resource_size(r);
+	dev->base = ioremap(r->start, size);
+	if (!dev->base)
+		goto exit;
+	dev->dev.cls = &txx9_sramc_sysdev_class;
+	dev->bindata_attr.attr.name = "bindata";
+	dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR;
+	dev->bindata_attr.read = txx9_sram_read;
+	dev->bindata_attr.write = txx9_sram_write;
+	dev->bindata_attr.size = size;
+	dev->bindata_attr.private = dev;
+	err = sysdev_register(&dev->dev);
+	if (err)
+		goto exit;
+	err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr);
+	if (err) {
+		sysdev_unregister(&dev->dev);
+		goto exit;
+	}
+	return;
+exit:
+	if (dev) {
+		if (dev->base)
+			iounmap(dev->base);
+		kfree(dev);
+	}
+}