cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

leds-ot200.c (2751B)


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