Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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