MIPS: TXx9: 7 segment LED support
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Mon, 20 Oct 2008 14:28:50 +0000 (23:28 +0900)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 27 Oct 2008 16:18:27 +0000 (16:18 +0000)
Add sysfs interface for 7 segment LED and implement access routine for
RBTX4939.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/txx9/generic.h
arch/mips/txx9/Kconfig
arch/mips/txx9/generic/7segled.c [new file with mode: 0644]
arch/mips/txx9/generic/Makefile
arch/mips/txx9/rbtx4939/setup.c

index 4316a3e..9cde009 100644 (file)
@@ -86,4 +86,9 @@ void txx9_iocled_init(unsigned long baseaddr,
                      int basenum, unsigned int num, int lowactive,
                      const char *color, char **deftriggers);
 
+/* 7SEG LED */
+void txx9_7segled_init(unsigned int num,
+                      void (*putc)(unsigned int pos, unsigned char val));
+int txx9_7segled_putc(unsigned int pos, char c);
+
 #endif /* __ASM_TXX9_GENERIC_H */
index 17052db..5a176ea 100644 (file)
@@ -49,6 +49,7 @@ config TOSHIBA_RBTX4939
        bool "Toshiba RBTX4939 bobard"
        depends on MACH_TX49XX
        select SOC_TX4939
+       select TXX9_7SEGLED
        help
          This Toshiba board is based on the TX4939 processor. Say Y here to
          support this machine type
@@ -86,6 +87,9 @@ config SOC_TX4939
        select HW_HAS_PCI
        select PCI_TX4927
 
+config TXX9_7SEGLED
+       bool
+
 config TOSHIBA_FPCIB0
        bool "FPCIB0 Backplane Support"
        depends on PCI && MACH_TXX9
diff --git a/arch/mips/txx9/generic/7segled.c b/arch/mips/txx9/generic/7segled.c
new file mode 100644 (file)
index 0000000..727ab21
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 7 Segment LED routines
+ * Based on RBTX49xx patch from CELF patch archive.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) Copyright TOSHIBA CORPORATION 2005-2007
+ * All Rights Reserved.
+ */
+#include <linux/sysdev.h>
+#include <linux/slab.h>
+#include <linux/map_to_7segment.h>
+#include <asm/txx9/generic.h>
+
+static unsigned int tx_7segled_num;
+static void (*tx_7segled_putc)(unsigned int pos, unsigned char val);
+
+void __init txx9_7segled_init(unsigned int num,
+                             void (*putc)(unsigned int pos, unsigned char val))
+{
+       tx_7segled_num = num;
+       tx_7segled_putc = putc;
+}
+
+static SEG7_CONVERSION_MAP(txx9_seg7map, MAP_ASCII7SEG_ALPHANUM_LC);
+
+int txx9_7segled_putc(unsigned int pos, char c)
+{
+       if (pos >= tx_7segled_num)
+               return -EINVAL;
+       c = map_to_seg7(&txx9_seg7map, c);
+       if (c < 0)
+               return c;
+       tx_7segled_putc(pos, c);
+       return 0;
+}
+
+static ssize_t ascii_store(struct sys_device *dev,
+                          struct sysdev_attribute *attr,
+                          const char *buf, size_t size)
+{
+       unsigned int ch = dev->id;
+       txx9_7segled_putc(ch, buf[0]);
+       return size;
+}
+
+static ssize_t raw_store(struct sys_device *dev,
+                        struct sysdev_attribute *attr,
+                        const char *buf, size_t size)
+{
+       unsigned int ch = dev->id;
+       tx_7segled_putc(ch, buf[0]);
+       return size;
+}
+
+static SYSDEV_ATTR(ascii, 0200, NULL, ascii_store);
+static SYSDEV_ATTR(raw, 0200, NULL, raw_store);
+
+static ssize_t map_seg7_show(struct sysdev_class *class, char *buf)
+{
+       memcpy(buf, &txx9_seg7map, sizeof(txx9_seg7map));
+       return sizeof(txx9_seg7map);
+}
+
+static ssize_t map_seg7_store(struct sysdev_class *class,
+                             const char *buf, size_t size)
+{
+       if (size != sizeof(txx9_seg7map))
+               return -EINVAL;
+       memcpy(&txx9_seg7map, buf, size);
+       return size;
+}
+
+static SYSDEV_CLASS_ATTR(map_seg7, 0600, map_seg7_show, map_seg7_store);
+
+static struct sysdev_class tx_7segled_sysdev_class = {
+       .name   = "7segled",
+};
+
+static int __init tx_7segled_init_sysfs(void)
+{
+       int error, i;
+       if (!tx_7segled_num)
+               return -ENODEV;
+       error = sysdev_class_register(&tx_7segled_sysdev_class);
+       if (error)
+               return error;
+       error = sysdev_class_create_file(&tx_7segled_sysdev_class,
+                                        &attr_map_seg7);
+       if (error)
+               return error;
+       for (i = 0; i < tx_7segled_num; i++) {
+               struct sys_device *dev;
+               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+               if (!dev) {
+                       error = -ENODEV;
+                       break;
+               }
+               dev->id = i;
+               dev->cls = &tx_7segled_sysdev_class;
+               error = sysdev_register(dev);
+               if (!error) {
+                       sysdev_create_file(dev, &attr_ascii);
+                       sysdev_create_file(dev, &attr_raw);
+               }
+       }
+       return error;
+}
+
+device_initcall(tx_7segled_init_sysfs);
index 0030d23..f2579ce 100644 (file)
@@ -10,5 +10,6 @@ obj-$(CONFIG_SOC_TX4938)      += mem_tx4927.o setup_tx4938.o irq_tx4938.o
 obj-$(CONFIG_SOC_TX4939)       += setup_tx4939.o irq_tx4939.o
 obj-$(CONFIG_TOSHIBA_FPCIB0)   += smsc_fdc37m81x.o
 obj-$(CONFIG_SPI)              += spi_eeprom.o
+obj-$(CONFIG_TXX9_7SEGLED)     += 7segled.o
 
 EXTRA_CFLAGS += -Werror
index 9855d7b..c885177 100644 (file)
@@ -239,6 +239,32 @@ static inline void rbtx4939_led_setup(void)
 }
 #endif
 
+static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
+{
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+       unsigned long flags;
+       local_irq_save(flags);
+       /* bit7: reserved for LED class */
+       led_val[pos] = (led_val[pos] & 0x80) | (val & 0x7f);
+       val = led_val[pos];
+       local_irq_restore(flags);
+#endif
+       writeb(val, rbtx4939_7seg_addr(pos / 4, pos % 4));
+}
+
+static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
+{
+       /* convert from map_to_seg7() notation */
+       val = (val & 0x88) |
+               ((val & 0x40) >> 6) |
+               ((val & 0x20) >> 4) |
+               ((val & 0x10) >> 2) |
+               ((val & 0x04) << 2) |
+               ((val & 0x02) << 4) |
+               ((val & 0x01) << 6);
+       __rbtx4939_7segled_putc(pos, val);
+}
+
 static void __init rbtx4939_arch_init(void)
 {
        rbtx4939_pci_setup();
@@ -269,6 +295,8 @@ static void __init rbtx4939_device_init(void)
 
 static void __init rbtx4939_setup(void)
 {
+       int i;
+
        rbtx4939_ebusc_setup();
        /* always enable ATA0 */
        txx9_set64(&tx4939_ccfgptr->pcfg, TX4939_PCFG_ATA0MODE);
@@ -279,6 +307,9 @@ static void __init rbtx4939_setup(void)
 
        _machine_restart = rbtx4939_machine_restart;
 
+       txx9_7segled_init(RBTX4939_MAX_7SEGLEDS, rbtx4939_7segled_putc);
+       for (i = 0; i < RBTX4939_MAX_7SEGLEDS; i++)
+               txx9_7segled_putc(i, '-');
        pr_info("RBTX4939 (Rev %02x) --- FPGA(Rev %02x) DIPSW:%02x,%02x\n",
                readb(rbtx4939_board_rev_addr), readb(rbtx4939_ioc_rev_addr),
                readb(rbtx4939_udipsw_addr), readb(rbtx4939_bdipsw_addr));