summaryrefslogtreecommitdiffstats
path: root/arch/mips/txx9/generic/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/txx9/generic/setup.c')
-rw-r--r--arch/mips/txx9/generic/setup.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index 118d716f783..1ea06553a1e 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/mtd/physmap.h>
+#include <linux/leds.h>
#include <asm/bootinfo.h>
#include <asm/time.h>
#include <asm/reboot.h>
@@ -649,3 +650,113 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
platform_device_put(pdev);
#endif
}
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static DEFINE_SPINLOCK(txx9_iocled_lock);
+
+#define TXX9_IOCLED_MAXLEDS 8
+
+struct txx9_iocled_data {
+ struct gpio_chip chip;
+ u8 cur_val;
+ void __iomem *mmioaddr;
+ struct gpio_led_platform_data pdata;
+ struct gpio_led leds[TXX9_IOCLED_MAXLEDS];
+ char names[TXX9_IOCLED_MAXLEDS][32];
+};
+
+static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct txx9_iocled_data *data =
+ container_of(chip, struct txx9_iocled_data, chip);
+ return data->cur_val & (1 << offset);
+}
+
+static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct txx9_iocled_data *data =
+ container_of(chip, struct txx9_iocled_data, chip);
+ unsigned long flags;
+ spin_lock_irqsave(&txx9_iocled_lock, flags);
+ if (value)
+ data->cur_val |= 1 << offset;
+ else
+ data->cur_val &= ~(1 << offset);
+ writeb(data->cur_val, data->mmioaddr);
+ mmiowb();
+ spin_unlock_irqrestore(&txx9_iocled_lock, flags);
+}
+
+static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset)
+{
+ return 0;
+}
+
+static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ txx9_iocled_set(chip, offset, value);
+ return 0;
+}
+
+void __init txx9_iocled_init(unsigned long baseaddr,
+ int basenum, unsigned int num, int lowactive,
+ const char *color, char **deftriggers)
+{
+ struct txx9_iocled_data *iocled;
+ struct platform_device *pdev;
+ int i;
+ static char *default_triggers[] __initdata = {
+ "heartbeat",
+ "ide-disk",
+ "nand-disk",
+ NULL,
+ };
+
+ if (!deftriggers)
+ deftriggers = default_triggers;
+ iocled = kzalloc(sizeof(*iocled), GFP_KERNEL);
+ if (!iocled)
+ return;
+ iocled->mmioaddr = ioremap(baseaddr, 1);
+ if (!iocled->mmioaddr)
+ return;
+ iocled->chip.get = txx9_iocled_get;
+ iocled->chip.set = txx9_iocled_set;
+ iocled->chip.direction_input = txx9_iocled_dir_in;
+ iocled->chip.direction_output = txx9_iocled_dir_out;
+ iocled->chip.label = "iocled";
+ iocled->chip.base = basenum;
+ iocled->chip.ngpio = num;
+ if (gpiochip_add(&iocled->chip))
+ return;
+ if (basenum < 0)
+ basenum = iocled->chip.base;
+
+ pdev = platform_device_alloc("leds-gpio", basenum);
+ if (!pdev)
+ return;
+ iocled->pdata.num_leds = num;
+ iocled->pdata.leds = iocled->leds;
+ for (i = 0; i < num; i++) {
+ struct gpio_led *led = &iocled->leds[i];
+ snprintf(iocled->names[i], sizeof(iocled->names[i]),
+ "iocled:%s:%u", color, i);
+ led->name = iocled->names[i];
+ led->gpio = basenum + i;
+ led->active_low = lowactive;
+ if (deftriggers && *deftriggers)
+ led->default_trigger = *deftriggers++;
+ }
+ pdev->dev.platform_data = &iocled->pdata;
+ if (platform_device_add(pdev))
+ platform_device_put(pdev);
+}
+#else /* CONFIG_LEDS_GPIO */
+void __init txx9_iocled_init(unsigned long baseaddr,
+ int basenum, unsigned int num, int lowactive,
+ const char *color, char **deftriggers)
+{
+}
+#endif /* CONFIG_LEDS_GPIO */