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