Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Bachmann ot200 leds driver.
0003  *
0004  * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
0005  *         Christian Gmeiner <christian.gmeiner@gmail.com>
0006  *
0007  * License: GPL as published by the FSF.
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013 #include <linux/leds.h>
0014 #include <linux/io.h>
0015 #include <linux/module.h>
0016 
0017 
0018 struct ot200_led {
0019     struct led_classdev cdev;
0020     const char *name;
0021     unsigned long port;
0022     u8 mask;
0023 };
0024 
0025 /*
0026  * The device has three leds on the back panel (led_err, led_init and led_run)
0027  * and can handle up to seven leds on the front panel.
0028  */
0029 
0030 static struct ot200_led leds[] = {
0031     {
0032         .name = "led_run",
0033         .port = 0x5a,
0034         .mask = BIT(0),
0035     },
0036     {
0037         .name = "led_init",
0038         .port = 0x5a,
0039         .mask = BIT(1),
0040     },
0041     {
0042         .name = "led_err",
0043         .port = 0x5a,
0044         .mask = BIT(2),
0045     },
0046     {
0047         .name = "led_1",
0048         .port = 0x49,
0049         .mask = BIT(6),
0050     },
0051     {
0052         .name = "led_2",
0053         .port = 0x49,
0054         .mask = BIT(5),
0055     },
0056     {
0057         .name = "led_3",
0058         .port = 0x49,
0059         .mask = BIT(4),
0060     },
0061     {
0062         .name = "led_4",
0063         .port = 0x49,
0064         .mask = BIT(3),
0065     },
0066     {
0067         .name = "led_5",
0068         .port = 0x49,
0069         .mask = BIT(2),
0070     },
0071     {
0072         .name = "led_6",
0073         .port = 0x49,
0074         .mask = BIT(1),
0075     },
0076     {
0077         .name = "led_7",
0078         .port = 0x49,
0079         .mask = BIT(0),
0080     }
0081 };
0082 
0083 static DEFINE_SPINLOCK(value_lock);
0084 
0085 /*
0086  * we need to store the current led states, as it is not
0087  * possible to read the current led state via inb().
0088  */
0089 static u8 leds_back;
0090 static u8 leds_front;
0091 
0092 static void ot200_led_brightness_set(struct led_classdev *led_cdev,
0093         enum led_brightness value)
0094 {
0095     struct ot200_led *led = container_of(led_cdev, struct ot200_led, cdev);
0096     u8 *val;
0097     unsigned long flags;
0098 
0099     spin_lock_irqsave(&value_lock, flags);
0100 
0101     if (led->port == 0x49)
0102         val = &leds_front;
0103     else if (led->port == 0x5a)
0104         val = &leds_back;
0105     else
0106         BUG();
0107 
0108     if (value == LED_OFF)
0109         *val &= ~led->mask;
0110     else
0111         *val |= led->mask;
0112 
0113     outb(*val, led->port);
0114     spin_unlock_irqrestore(&value_lock, flags);
0115 }
0116 
0117 static int ot200_led_probe(struct platform_device *pdev)
0118 {
0119     int i;
0120     int ret;
0121 
0122     for (i = 0; i < ARRAY_SIZE(leds); i++) {
0123 
0124         leds[i].cdev.name = leds[i].name;
0125         leds[i].cdev.brightness_set = ot200_led_brightness_set;
0126 
0127         ret = devm_led_classdev_register(&pdev->dev, &leds[i].cdev);
0128         if (ret < 0)
0129             return ret;
0130     }
0131 
0132     leds_front = 0;     /* turn off all front leds */
0133     leds_back = BIT(1); /* turn on init led */
0134     outb(leds_front, 0x49);
0135     outb(leds_back, 0x5a);
0136 
0137     return 0;
0138 }
0139 
0140 static struct platform_driver ot200_led_driver = {
0141     .probe      = ot200_led_probe,
0142     .driver     = {
0143         .name   = "leds-ot200",
0144     },
0145 };
0146 
0147 module_platform_driver(ot200_led_driver);
0148 
0149 MODULE_AUTHOR("Sebastian A. Siewior <bigeasy@linutronix.de>");
0150 MODULE_DESCRIPTION("ot200 LED driver");
0151 MODULE_LICENSE("GPL");
0152 MODULE_ALIAS("platform:leds-ot200");