Add base support for TS-5500 in arch/x86/platform/ts5500 and documentation in
Documentation/ABI/testing/sysfs-platform-ts5500.

Signed-off-by: Vivien Didelot <[email protected]>
---
 Documentation/ABI/testing/sysfs-platform-ts5500 |   46 ++++
 MAINTAINERS                                     |    7 +
 arch/x86/Kconfig                                |    2 +
 arch/x86/platform/Makefile                      |    1 +
 arch/x86/platform/ts5500/Kconfig                |    7 +
 arch/x86/platform/ts5500/Makefile               |    1 +
 arch/x86/platform/ts5500/ts5500.c               |  296 +++++++++++++++++++++++
 7 files changed, 360 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-platform-ts5500
 create mode 100644 arch/x86/platform/ts5500/Kconfig
 create mode 100644 arch/x86/platform/ts5500/Makefile
 create mode 100644 arch/x86/platform/ts5500/ts5500.c

diff --git a/Documentation/ABI/testing/sysfs-platform-ts5500 
b/Documentation/ABI/testing/sysfs-platform-ts5500
new file mode 100644
index 0000000..c870564
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-ts5500
@@ -0,0 +1,46 @@
+What:          /sys/devices/platform/ts5500/id
+Date:          July 2011
+KernelVersion: 2.6.39
+Contact:       "Savoir-faire Linux, Inc." <[email protected]>
+Description:
+               Product ID of the TS board. TS-5500 ID is 0x60.
+
+What:          /sys/devices/platform/ts5500/sram
+Date:          July 2011
+KernelVersion: 2.6.39
+Contact:       "Savoir-faire Linux, Inc." <[email protected]>
+Description:
+               Say if the SRAM feature is present. If it is enabled, it will
+               display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/ereset
+Date:          July 2011
+KernelVersion: 2.6.39
+Contact:       "Savoir-faire Linux, Inc." <[email protected]>
+Description:
+               Say if an external reset is present. If it is present, it will
+               display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/jp{1,2,3,4,5,6}
+Date:          July 2011
+KernelVersion: 2.6.39
+Contact:       "Savoir-faire Linux, Inc." <[email protected]>
+Description:
+               Show the state of a plugged jumper. If it is present, it will
+               display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/adc
+Date:          July 2011
+KernelVersion: 2.6.39
+Contact:       "Savoir-faire Linux, Inc." <[email protected]>
+Description:
+               Say if the Analogic to Digital Converter is present. If it is
+               enabled, it will display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/rs485
+Date:          July 2011
+KernelVersion: 2.6.39
+Contact:       "Savoir-faire Linux, Inc." <[email protected]>
+Description:
+               Say if the RS485 feature is present. If it is enabled, it
+               will display "1", otherwise "0".
\ No newline at end of file
diff --git a/MAINTAINERS b/MAINTAINERS
index 187282d..be8ce4b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6134,6 +6134,13 @@ W:       http://tcp-lp-mod.sourceforge.net/
 S:     Maintained
 F:     net/ipv4/tcp_lp.c
 
+TECHNOLOGIC SYSTEMS TS5500 MACHINE SUPPORT
+M:     Savoir-faire Linux Inc. <[email protected]>
+S:     Maintained
+F:  arch/x86/platform/ts5500/Kconfig
+F:  arch/x86/platform/ts5500/Makefile
+F:  arch/x86/platform/ts5500/ts5500.c
+
 TEGRA SUPPORT
 M:     Colin Cross <[email protected]>
 M:     Erik Gilling <[email protected]>
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index da34972..cd4bf1a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2079,6 +2079,8 @@ config OLPC_XO1
        ---help---
          Add support for non-essential features of the OLPC XO-1 laptop.
 
+source "arch/x86/platform/ts5500/Kconfig"
+
 endif # X86_32
 
 config AMD_NB
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 021eee9..1bdc038 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -8,3 +8,4 @@ obj-y   += scx200/
 obj-y  += sfi/
 obj-y  += visws/
 obj-y  += uv/
+obj-y  += ts5500/
diff --git a/arch/x86/platform/ts5500/Kconfig b/arch/x86/platform/ts5500/Kconfig
new file mode 100644
index 0000000..6428ca5
--- /dev/null
+++ b/arch/x86/platform/ts5500/Kconfig
@@ -0,0 +1,7 @@
+config TS5500
+       bool "Technologic Systems TS-5500 Single Board Computer support"
+       depends on MELAN
+       help
+         Add support for the Technologic Systems TS-5500 platform features.
+
+         If you have a TS-5500, say Y here.
diff --git a/arch/x86/platform/ts5500/Makefile 
b/arch/x86/platform/ts5500/Makefile
new file mode 100644
index 0000000..0a689a7
--- /dev/null
+++ b/arch/x86/platform/ts5500/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_TS5500)                   += ts5500.o
diff --git a/arch/x86/platform/ts5500/ts5500.c 
b/arch/x86/platform/ts5500/ts5500.c
new file mode 100644
index 0000000..0135dbd
--- /dev/null
+++ b/arch/x86/platform/ts5500/ts5500.c
@@ -0,0 +1,296 @@
+/*
+ * Technologic Systems TS-5500 board - SBC info layer
+ *
+ * Copyright (c) 2010-2011 Savoir-faire Linux Inc.
+ *     Alexandre Savard <[email protected]>
+ *     Jonas Fonseca <[email protected]>
+ *     Vivien Didelot <[email protected]>
+ *
+ * Portions originate from ts_sbcinfo.c (c) Technologic Systems
+ *     Liberty Young <[email protected]>
+ *
+ * These functions add sysfs platform entries to display information about
+ * the Technologic Systems TS-5500 Single Board Computer (SBC).
+ *
+ * For further information about sysfs entries, see
+ * Documentation/ABI/testing/sysfs-platform-ts5500
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <asm/processor.h>
+
+/* Hardware info for pre-detection */
+#define AMD_ELAN_FAMILY                        4
+#define AMD_ELAN_SC520                 9
+
+/* Product code register */
+#define TS5500_PRODUCT_CODE_REG                0x74
+#define TS5500_PRODUCT_CODE            0x60    /* TS-5500 product code */
+
+/* SRAM/RS-485/ADC options, and RS-485 RTS/Automatic RS-485 flags register */
+#define TS5500_SRAM_RS485_ADC_REG      0x75
+#define TS5500_SRAM_OPT                        0x01    /* SRAM option */
+#define TS5500_RS485_OPT               0x02    /* RS-485 option */
+#define TS5500_ADC_OPT                 0x04    /* A/D converter option */
+#define TS5500_RS485_RTS_FLAG          0x40    /* RTS for RS-485 */
+#define TS5500_RS485_AUTO_FLAG         0x80    /* Automatic RS-485 */
+
+/* External Reset/Industrial Temperature Range options register */
+#define TS5500_ERESET_ITR_REG          0x76
+#define TS5500_ERESET_OPT              0x01    /*  External Reset option */
+#define TS5500_ITR_OPT                 0x02    /* Indust. Temp. Range option */
+
+/* LED/Jumpers register */
+#define TS5500_LED_JMPRS_REG           0x77
+#define TS5500_LED_FLAG                        0x01    /* LED flag */
+#define TS5500_JP1                     0x02    /* Automatic CMOS */
+#define TS5500_JP2                     0x04    /* Enable Serial Console */
+#define TS5500_JP3                     0x08    /* Write Enable Drive A */
+#define TS5500_JP4                     0x10    /* Fast Console (115K baud) */
+#define TS5500_JP5                     0x20    /* User Jumper */
+#define TS5500_JP6                     0x40    /* Console on COM1 (req. JP2) */
+#define TS5500_JP7                     0x80    /* Undocumented (Unused) */
+
+/**
+ * struct ts5500_sbc - TS-5500 SBC main structure
+ * @lock:              Read/Write mutex.
+ * @board_id:          Board name.
+ * @sram:              Check SRAM option.
+ * @rs485:             Check RS-485 option.
+ * @adc:               Check Analogic/Digital converter option.
+ * @ereset:            Check External Reset option.
+ * @itr:               Check Industrial Temperature Range option.
+ * @jumpers:           States of jumpers 1-7.
+ */
+struct ts5500_sbc {
+       struct mutex            lock;
+       int                     board_id;
+       bool                    sram;
+       bool                    rs485;
+       bool                    adc;
+       bool                    ereset;
+       bool                    itr;
+       u8                      jumpers;
+};
+
+/* Current platform */
+struct ts5500_sbc *ts5500;
+
+/**
+ * ts5500_pre_detect() - check for TS-5500 specific features
+ *
+ * It is not safe to read ID register if we are not sure that it's a TS SBC.
+ * Since TS SBCs don't have DMI support, it is safer to check for a TS-5500
+ * specific feature such as the processor.
+ */
+static int ts5500_pre_detect(void)
+{
+       /* Check for AMD ElanSC520 Microcontroller */
+       if (!(cpu_info.x86_vendor == X86_VENDOR_AMD &&
+             cpu_info.x86 == AMD_ELAN_FAMILY &&
+             cpu_info.x86_model == AMD_ELAN_SC520))
+               return -ENODEV;
+
+       return 0;
+}
+
+/**
+ * ts5500_detect_config() - detect the TS board
+ * @sbc:               Structure where to store the detected board's details.
+ */
+static int ts5500_detect_config(struct ts5500_sbc *sbc)
+{
+       u8 tmp;
+       int ret = 0;
+
+       if (!request_region(TS5500_PRODUCT_CODE_REG, 4, "ts5500"))
+               return -EBUSY;
+
+       mutex_lock(&ts5500->lock);
+       tmp = inb(TS5500_PRODUCT_CODE_REG);
+       if (tmp != TS5500_PRODUCT_CODE) {
+               pr_err("This platform is not a TS-5500 (found ID 0x%x)\n", tmp);
+               ret = -ENODEV;
+               goto error;
+       }
+       sbc->board_id = tmp;
+
+       tmp = inb(TS5500_SRAM_RS485_ADC_REG);
+       ts5500->sram = !!(tmp & TS5500_SRAM_OPT);
+       ts5500->rs485 = !!(tmp & TS5500_RS485_OPT);
+       ts5500->adc = !!(tmp & TS5500_ADC_OPT);
+
+       tmp = inb(TS5500_ERESET_ITR_REG);
+       ts5500->ereset = !!(tmp & TS5500_ERESET_OPT);
+       ts5500->itr = !!(tmp & TS5500_ITR_OPT);
+
+       tmp = inb(TS5500_LED_JMPRS_REG);
+       sbc->jumpers = tmp & 0xFE;      /* All bits except the first (LED) */
+
+error:
+       mutex_unlock(&ts5500->lock);
+       release_region(TS5500_PRODUCT_CODE_REG, 4);
+       return ret;
+}
+
+#define TS5500_IS_JP_SET(sbc, jmp) (!!(sbc->jumpers & TS5500_JP##jmp))
+
+static struct platform_device *ts5500_devices[] __initdata = {
+};
+
+static ssize_t ts5500_show_id(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%x\n", sbc->board_id);
+}
+
+static ssize_t ts5500_show_sram(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", sbc->sram);
+}
+
+static ssize_t ts5500_show_rs485(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", sbc->rs485);
+}
+
+static ssize_t ts5500_show_adc(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", sbc->adc);
+}
+
+static ssize_t ts5500_show_ereset(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", sbc->ereset);
+}
+
+static ssize_t ts5500_show_itr(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", sbc->itr);
+}
+
+#define TS5500_SHOW_JP(jp)                                             \
+       static ssize_t ts5500_show_jp##jp(struct device *dev,           \
+                                         struct device_attribute *attr,\
+                                         char *buf)                    \
+       {                                                               \
+               struct ts5500_sbc *sbc = dev_get_drvdata(dev);          \
+               return sprintf(buf, "%d\n", TS5500_IS_JP_SET(sbc, jp)); \
+       }
+
+TS5500_SHOW_JP(1)
+TS5500_SHOW_JP(2)
+TS5500_SHOW_JP(3)
+TS5500_SHOW_JP(4)
+TS5500_SHOW_JP(5)
+TS5500_SHOW_JP(6)
+
+static DEVICE_ATTR(id, S_IRUGO, ts5500_show_id, NULL);
+static DEVICE_ATTR(sram, S_IRUGO, ts5500_show_sram, NULL);
+static DEVICE_ATTR(rs485, S_IRUGO, ts5500_show_rs485, NULL);
+static DEVICE_ATTR(adc, S_IRUGO, ts5500_show_adc, NULL);
+static DEVICE_ATTR(ereset, S_IRUGO, ts5500_show_ereset, NULL);
+static DEVICE_ATTR(itr, S_IRUGO, ts5500_show_itr, NULL);
+static DEVICE_ATTR(jp1, S_IRUGO, ts5500_show_jp1, NULL);
+static DEVICE_ATTR(jp2, S_IRUGO, ts5500_show_jp2, NULL);
+static DEVICE_ATTR(jp3, S_IRUGO, ts5500_show_jp3, NULL);
+static DEVICE_ATTR(jp4, S_IRUGO, ts5500_show_jp4, NULL);
+static DEVICE_ATTR(jp5, S_IRUGO, ts5500_show_jp5, NULL);
+static DEVICE_ATTR(jp6, S_IRUGO, ts5500_show_jp6, NULL);
+
+static struct attribute *ts5500_attributes[] = {
+       &dev_attr_id.attr,
+       &dev_attr_sram.attr,
+       &dev_attr_rs485.attr,
+       &dev_attr_adc.attr,
+       &dev_attr_ereset.attr,
+       &dev_attr_itr.attr,
+       &dev_attr_jp1.attr,
+       &dev_attr_jp2.attr,
+       &dev_attr_jp3.attr,
+       &dev_attr_jp4.attr,
+       &dev_attr_jp5.attr,
+       &dev_attr_jp6.attr,
+       NULL
+};
+
+static const struct attribute_group ts5500_attr_group = {
+       .attrs = ts5500_attributes
+};
+
+static int __init ts5500_init(void)
+{
+       int ret;
+       struct platform_device *pdev;
+
+       /* Firstly, check specific TS-5500 hardware, such as CPU. */
+       ret = ts5500_pre_detect();
+       if (ret)
+               return ret;
+
+       ts5500 = kzalloc(sizeof(struct ts5500_sbc), GFP_KERNEL);
+       if (!ts5500)
+               return -ENOMEM;
+       mutex_init(&ts5500->lock);
+
+       ret = ts5500_detect_config(ts5500);
+       if (ret)
+               goto release_mem;
+
+       pdev = platform_device_register_simple("ts5500", -1, NULL, 0);
+       if (IS_ERR(pdev)) {
+               ret = PTR_ERR(pdev);
+               goto release_mem;
+       }
+       platform_set_drvdata(pdev, ts5500);
+
+       ret = platform_add_devices(ts5500_devices, ARRAY_SIZE(ts5500_devices));
+       if (ret)
+               goto release_pdev;
+
+       ret = sysfs_create_group(&pdev->dev.kobj,
+                                &ts5500_attr_group);
+       if (ret)
+               goto release_pdev;
+
+       return 0;
+
+release_pdev:
+       platform_device_unregister(pdev);
+release_mem:
+       kfree(ts5500);
+
+       return ret;
+}
+postcore_initcall(ts5500_init);
+
+MODULE_AUTHOR("Jonas Fonseca <[email protected]>");
+MODULE_AUTHOR("Alexandre Savard <[email protected]>");
+MODULE_AUTHOR("Vivien Didelot <[email protected]>");
+MODULE_DESCRIPTION("Technologic Systems TS-5500 Board's platform driver");
+MODULE_LICENSE("GPL");
-- 
1.7.6

--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" 
in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to