2 * Copyright (C) 2016 National Instruments Corp.
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.
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.
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>
21 #define NIC78BX_USER1_LED_MASK 0x3
22 #define NIC78BX_USER1_GREEN_LED BIT(0)
23 #define NIC78BX_USER1_YELLOW_LED BIT(1)
25 #define NIC78BX_USER2_LED_MASK 0xC
26 #define NIC78BX_USER2_GREEN_LED BIT(2)
27 #define NIC78BX_USER2_YELLOW_LED BIT(3)
29 #define NIC78BX_LOCK_REG_OFFSET 1
30 #define NIC78BX_LOCK_VALUE 0xA5
31 #define NIC78BX_UNLOCK_VALUE 0x5A
33 #define NIC78BX_USER_LED_IO_SIZE 2
35 struct nic78bx_led_data
{
38 struct platform_device
*pdev
;
44 struct nic78bx_led_data
*data
;
45 struct led_classdev cdev
;
48 static inline struct nic78bx_led
*to_nic78bx_led(struct led_classdev
*cdev
)
50 return container_of(cdev
, struct nic78bx_led
, cdev
);
53 static void nic78bx_brightness_set(struct led_classdev
*cdev
,
54 enum led_brightness brightness
)
56 struct nic78bx_led
*nled
= to_nic78bx_led(cdev
);
60 spin_lock_irqsave(&nled
->data
->lock
, flags
);
61 value
= inb(nled
->data
->io_base
);
70 outb(value
, nled
->data
->io_base
);
71 spin_unlock_irqrestore(&nled
->data
->lock
, flags
);
74 static enum led_brightness
nic78bx_brightness_get(struct led_classdev
*cdev
)
76 struct nic78bx_led
*nled
= to_nic78bx_led(cdev
);
80 spin_lock_irqsave(&nled
->data
->lock
, flags
);
81 value
= inb(nled
->data
->io_base
);
82 spin_unlock_irqrestore(&nled
->data
->lock
, flags
);
84 return (value
& nled
->bit
) ? 1 : LED_OFF
;
87 static struct nic78bx_led nic78bx_leds
[] = {
89 .bit
= NIC78BX_USER1_GREEN_LED
,
90 .mask
= NIC78BX_USER1_LED_MASK
,
92 .name
= "nilrt:green:user1",
94 .brightness_set
= nic78bx_brightness_set
,
95 .brightness_get
= nic78bx_brightness_get
,
99 .bit
= NIC78BX_USER1_YELLOW_LED
,
100 .mask
= NIC78BX_USER1_LED_MASK
,
102 .name
= "nilrt:yellow:user1",
104 .brightness_set
= nic78bx_brightness_set
,
105 .brightness_get
= nic78bx_brightness_get
,
109 .bit
= NIC78BX_USER2_GREEN_LED
,
110 .mask
= NIC78BX_USER2_LED_MASK
,
112 .name
= "nilrt:green:user2",
114 .brightness_set
= nic78bx_brightness_set
,
115 .brightness_get
= nic78bx_brightness_get
,
119 .bit
= NIC78BX_USER2_YELLOW_LED
,
120 .mask
= NIC78BX_USER2_LED_MASK
,
122 .name
= "nilrt:yellow:user2",
124 .brightness_set
= nic78bx_brightness_set
,
125 .brightness_get
= nic78bx_brightness_get
,
130 static int nic78bx_probe(struct platform_device
*pdev
)
132 struct device
*dev
= &pdev
->dev
;
133 struct nic78bx_led_data
*led_data
;
134 struct resource
*io_rc
;
137 led_data
= devm_kzalloc(dev
, sizeof(*led_data
), GFP_KERNEL
);
141 led_data
->pdev
= pdev
;
142 platform_set_drvdata(pdev
, led_data
);
144 io_rc
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
146 dev_err(dev
, "missing IO resources\n");
150 if (resource_size(io_rc
) < NIC78BX_USER_LED_IO_SIZE
) {
151 dev_err(dev
, "IO region too small\n");
155 if (!devm_request_region(dev
, io_rc
->start
, resource_size(io_rc
),
157 dev_err(dev
, "failed to get IO region\n");
161 led_data
->io_base
= io_rc
->start
;
162 spin_lock_init(&led_data
->lock
);
164 for (i
= 0; i
< ARRAY_SIZE(nic78bx_leds
); i
++) {
165 nic78bx_leds
[i
].data
= led_data
;
167 ret
= devm_led_classdev_register(dev
, &nic78bx_leds
[i
].cdev
);
172 /* Unlock LED register */
173 outb(NIC78BX_UNLOCK_VALUE
,
174 led_data
->io_base
+ NIC78BX_LOCK_REG_OFFSET
);
179 static int nic78bx_remove(struct platform_device
*pdev
)
181 struct nic78bx_led_data
*led_data
= platform_get_drvdata(pdev
);
183 /* Lock LED register */
184 outb(NIC78BX_LOCK_VALUE
,
185 led_data
->io_base
+ NIC78BX_LOCK_REG_OFFSET
);
190 static const struct acpi_device_id led_device_ids
[] = {
194 MODULE_DEVICE_TABLE(acpi
, led_device_ids
);
196 static struct platform_driver led_driver
= {
197 .probe
= nic78bx_probe
,
198 .remove
= nic78bx_remove
,
200 .name
= KBUILD_MODNAME
,
201 .acpi_match_table
= ACPI_PTR(led_device_ids
),
205 module_platform_driver(led_driver
);
207 MODULE_DESCRIPTION("National Instruments PXI User LEDs driver");
208 MODULE_AUTHOR("Hui Chun Ong <hui.chun.ong@ni.com>");
209 MODULE_LICENSE("GPL");