Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | /* * Bachmann ot200 leds driver. * * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * Christian Gmeiner <christian.gmeiner@gmail.com> * * License: GPL as published by the FSF. */ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/leds.h> #include <linux/io.h> #include <linux/module.h> struct ot200_led { struct led_classdev cdev; const char *name; unsigned long port; u8 mask; }; /* * The device has three leds on the back panel (led_err, led_init and led_run) * and can handle up to seven leds on the front panel. */ static struct ot200_led leds[] = { { .name = "led_run", .port = 0x5a, .mask = BIT(0), }, { .name = "led_init", .port = 0x5a, .mask = BIT(1), }, { .name = "led_err", .port = 0x5a, .mask = BIT(2), }, { .name = "led_1", .port = 0x49, .mask = BIT(6), }, { .name = "led_2", .port = 0x49, .mask = BIT(5), }, { .name = "led_3", .port = 0x49, .mask = BIT(4), }, { .name = "led_4", .port = 0x49, .mask = BIT(3), }, { .name = "led_5", .port = 0x49, .mask = BIT(2), }, { .name = "led_6", .port = 0x49, .mask = BIT(1), }, { .name = "led_7", .port = 0x49, .mask = BIT(0), } }; static DEFINE_SPINLOCK(value_lock); /* * we need to store the current led states, as it is not * possible to read the current led state via inb(). */ static u8 leds_back; static u8 leds_front; static void ot200_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { struct ot200_led *led = container_of(led_cdev, struct ot200_led, cdev); u8 *val; unsigned long flags; spin_lock_irqsave(&value_lock, flags); if (led->port == 0x49) val = &leds_front; else if (led->port == 0x5a) val = &leds_back; else BUG(); if (value == LED_OFF) *val &= ~led->mask; else *val |= led->mask; outb(*val, led->port); spin_unlock_irqrestore(&value_lock, flags); } static int ot200_led_probe(struct platform_device *pdev) { int i; int ret; for (i = 0; i < ARRAY_SIZE(leds); i++) { leds[i].cdev.name = leds[i].name; leds[i].cdev.brightness_set = ot200_led_brightness_set; ret = led_classdev_register(&pdev->dev, &leds[i].cdev); if (ret < 0) goto err; } leds_front = 0; /* turn off all front leds */ leds_back = BIT(1); /* turn on init led */ outb(leds_front, 0x49); outb(leds_back, 0x5a); return 0; err: for (i = i - 1; i >= 0; i--) led_classdev_unregister(&leds[i].cdev); return ret; } static int ot200_led_remove(struct platform_device *pdev) { int i; for (i = 0; i < ARRAY_SIZE(leds); i++) led_classdev_unregister(&leds[i].cdev); return 0; } static struct platform_driver ot200_led_driver = { .probe = ot200_led_probe, .remove = ot200_led_remove, .driver = { .name = "leds-ot200", .owner = THIS_MODULE, }, }; module_platform_driver(ot200_led_driver); MODULE_AUTHOR("Sebastian A. Siewior <bigeasy@linutronix.de>"); MODULE_DESCRIPTION("ot200 LED driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:leds-ot200"); |