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-nic78bx.c (4600B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 National Instruments Corp.
      4 */
      5
      6#include <linux/acpi.h>
      7#include <linux/leds.h>
      8#include <linux/module.h>
      9#include <linux/platform_device.h>
     10#include <linux/spinlock.h>
     11
     12#define NIC78BX_USER1_LED_MASK		0x3
     13#define NIC78BX_USER1_GREEN_LED		BIT(0)
     14#define NIC78BX_USER1_YELLOW_LED	BIT(1)
     15
     16#define NIC78BX_USER2_LED_MASK		0xC
     17#define NIC78BX_USER2_GREEN_LED		BIT(2)
     18#define NIC78BX_USER2_YELLOW_LED	BIT(3)
     19
     20#define NIC78BX_LOCK_REG_OFFSET		1
     21#define NIC78BX_LOCK_VALUE		0xA5
     22#define NIC78BX_UNLOCK_VALUE		0x5A
     23
     24#define NIC78BX_USER_LED_IO_SIZE	2
     25
     26struct nic78bx_led_data {
     27	u16 io_base;
     28	spinlock_t lock;
     29	struct platform_device *pdev;
     30};
     31
     32struct nic78bx_led {
     33	u8 bit;
     34	u8 mask;
     35	struct nic78bx_led_data *data;
     36	struct led_classdev cdev;
     37};
     38
     39static inline struct nic78bx_led *to_nic78bx_led(struct led_classdev *cdev)
     40{
     41	return container_of(cdev, struct nic78bx_led, cdev);
     42}
     43
     44static void nic78bx_brightness_set(struct led_classdev *cdev,
     45				  enum led_brightness brightness)
     46{
     47	struct nic78bx_led *nled = to_nic78bx_led(cdev);
     48	unsigned long flags;
     49	u8 value;
     50
     51	spin_lock_irqsave(&nled->data->lock, flags);
     52	value = inb(nled->data->io_base);
     53
     54	if (brightness) {
     55		value &= ~nled->mask;
     56		value |= nled->bit;
     57	} else {
     58		value &= ~nled->bit;
     59	}
     60
     61	outb(value, nled->data->io_base);
     62	spin_unlock_irqrestore(&nled->data->lock, flags);
     63}
     64
     65static enum led_brightness nic78bx_brightness_get(struct led_classdev *cdev)
     66{
     67	struct nic78bx_led *nled = to_nic78bx_led(cdev);
     68	unsigned long flags;
     69	u8 value;
     70
     71	spin_lock_irqsave(&nled->data->lock, flags);
     72	value = inb(nled->data->io_base);
     73	spin_unlock_irqrestore(&nled->data->lock, flags);
     74
     75	return (value & nled->bit) ? 1 : LED_OFF;
     76}
     77
     78static struct nic78bx_led nic78bx_leds[] = {
     79	{
     80		.bit = NIC78BX_USER1_GREEN_LED,
     81		.mask = NIC78BX_USER1_LED_MASK,
     82		.cdev = {
     83			.name = "nilrt:green:user1",
     84			.max_brightness = 1,
     85			.brightness_set = nic78bx_brightness_set,
     86			.brightness_get = nic78bx_brightness_get,
     87		}
     88	},
     89	{
     90		.bit = NIC78BX_USER1_YELLOW_LED,
     91		.mask = NIC78BX_USER1_LED_MASK,
     92		.cdev = {
     93			.name = "nilrt:yellow:user1",
     94			.max_brightness = 1,
     95			.brightness_set = nic78bx_brightness_set,
     96			.brightness_get = nic78bx_brightness_get,
     97		}
     98	},
     99	{
    100		.bit = NIC78BX_USER2_GREEN_LED,
    101		.mask = NIC78BX_USER2_LED_MASK,
    102		.cdev = {
    103			.name = "nilrt:green:user2",
    104			.max_brightness = 1,
    105			.brightness_set = nic78bx_brightness_set,
    106			.brightness_get = nic78bx_brightness_get,
    107		}
    108	},
    109	{
    110		.bit = NIC78BX_USER2_YELLOW_LED,
    111		.mask = NIC78BX_USER2_LED_MASK,
    112		.cdev = {
    113			.name = "nilrt:yellow:user2",
    114			.max_brightness = 1,
    115			.brightness_set = nic78bx_brightness_set,
    116			.brightness_get = nic78bx_brightness_get,
    117		}
    118	}
    119};
    120
    121static int nic78bx_probe(struct platform_device *pdev)
    122{
    123	struct device *dev = &pdev->dev;
    124	struct nic78bx_led_data *led_data;
    125	struct resource *io_rc;
    126	int ret, i;
    127
    128	led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
    129	if (!led_data)
    130		return -ENOMEM;
    131
    132	led_data->pdev = pdev;
    133	platform_set_drvdata(pdev, led_data);
    134
    135	io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
    136	if (!io_rc) {
    137		dev_err(dev, "missing IO resources\n");
    138		return -EINVAL;
    139	}
    140
    141	if (resource_size(io_rc) < NIC78BX_USER_LED_IO_SIZE) {
    142		dev_err(dev, "IO region too small\n");
    143		return -EINVAL;
    144	}
    145
    146	if (!devm_request_region(dev, io_rc->start, resource_size(io_rc),
    147				 KBUILD_MODNAME)) {
    148		dev_err(dev, "failed to get IO region\n");
    149		return -EBUSY;
    150	}
    151
    152	led_data->io_base = io_rc->start;
    153	spin_lock_init(&led_data->lock);
    154
    155	for (i = 0; i < ARRAY_SIZE(nic78bx_leds); i++) {
    156		nic78bx_leds[i].data = led_data;
    157
    158		ret = devm_led_classdev_register(dev, &nic78bx_leds[i].cdev);
    159		if (ret)
    160			return ret;
    161	}
    162
    163	/* Unlock LED register */
    164	outb(NIC78BX_UNLOCK_VALUE,
    165	     led_data->io_base + NIC78BX_LOCK_REG_OFFSET);
    166
    167	return ret;
    168}
    169
    170static int nic78bx_remove(struct platform_device *pdev)
    171{
    172	struct nic78bx_led_data *led_data = platform_get_drvdata(pdev);
    173
    174	/* Lock LED register */
    175	outb(NIC78BX_LOCK_VALUE,
    176	     led_data->io_base + NIC78BX_LOCK_REG_OFFSET);
    177
    178	return 0;
    179}
    180
    181static const struct acpi_device_id led_device_ids[] = {
    182	{"NIC78B3", 0},
    183	{"", 0},
    184};
    185MODULE_DEVICE_TABLE(acpi, led_device_ids);
    186
    187static struct platform_driver led_driver = {
    188	.probe = nic78bx_probe,
    189	.remove = nic78bx_remove,
    190	.driver = {
    191		.name = KBUILD_MODNAME,
    192		.acpi_match_table = ACPI_PTR(led_device_ids),
    193	},
    194};
    195
    196module_platform_driver(led_driver);
    197
    198MODULE_DESCRIPTION("National Instruments PXI User LEDs driver");
    199MODULE_AUTHOR("Hui Chun Ong <hui.chun.ong@ni.com>");
    200MODULE_LICENSE("GPL");