diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-03 15:38:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-03 15:38:19 -0400 |
commit | e40dc66220b7ff1b816311b135b9298f8ba14ce6 (patch) | |
tree | 994467c0ea67857575a389161e6fdb97a9bae526 | |
parent | cc5ada7ca3618e25c1c2be29dad3c092573200d3 (diff) | |
parent | 92d7ec1d71e351f11ba503369eb78225510cfcc7 (diff) |
Merge tag 'leds_for_4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds
Pull LED updates from Jacek Anaszewski:
"New LED class driver:
- add driver for Mellanox regmap LEDs
Improvement to ledtrig-disk:
- extend disk trigger for reads and writes
Improvements and fixes to existing LED class drivers:
- add more product/board names for PC Engines APU2
- fix wrong dmi_match on PC Engines APU LEDs
- clarify chips supported by LM355x driver
- fix Kconfig text for MLXCPLD, SYSCON, MC13783, NETXBIG
- allow leds-mlxcpld compilation for 32 bit arch"
* tag 'leds_for_4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds:
leds: Fix wrong dmi_match on PC Engines APU LEDs
leds: Extends disk trigger for reads and writes
leds: Add more product/board names for PC Engines APU2
leds: add driver for support Mellanox regmap LEDs for BMC and x86 platform
leds: fix Kconfig text for MLXCPLD, SYSCON, MC13783, NETXBIG
leds: Clarify supported chips by LM355x driver
leds: leds-mlxcpld: Allow compilation for 32 bit arch
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 2 | ||||
-rw-r--r-- | drivers/ide/ide-disk.c | 2 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 29 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-apu.c | 28 | ||||
-rw-r--r-- | drivers/leds/leds-mlxreg.c | 281 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-disk.c | 12 | ||||
-rw-r--r-- | include/linux/leds.h | 4 |
9 files changed, 342 insertions, 18 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 5a9634a0eeb4..65ab509e4a42 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -8988,6 +8988,7 @@ M: Vadim Pasternak <vadimp@mellanox.com> | |||
8988 | L: linux-leds@vger.kernel.org | 8988 | L: linux-leds@vger.kernel.org |
8989 | S: Supported | 8989 | S: Supported |
8990 | F: drivers/leds/leds-mlxcpld.c | 8990 | F: drivers/leds/leds-mlxcpld.c |
8991 | F: drivers/leds/leds-mlxreg.c | ||
8991 | F: Documentation/leds/leds-mlxcpld.txt | 8992 | F: Documentation/leds/leds-mlxcpld.txt |
8992 | 8993 | ||
8993 | MELLANOX PLATFORM DRIVER | 8994 | MELLANOX PLATFORM DRIVER |
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7431ccd03316..728ed4764678 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -5240,7 +5240,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) | |||
5240 | struct ata_port *ap = qc->ap; | 5240 | struct ata_port *ap = qc->ap; |
5241 | 5241 | ||
5242 | /* Trigger the LED (if available) */ | 5242 | /* Trigger the LED (if available) */ |
5243 | ledtrig_disk_activity(); | 5243 | ledtrig_disk_activity(!!(qc->tf.flags & ATA_TFLAG_WRITE)); |
5244 | 5244 | ||
5245 | /* XXX: New EH and old EH use different mechanisms to | 5245 | /* XXX: New EH and old EH use different mechanisms to |
5246 | * synchronize EH with regular execution path. | 5246 | * synchronize EH with regular execution path. |
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 188d1b03715d..67bc72d78fbf 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c | |||
@@ -187,7 +187,7 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, | |||
187 | BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); | 187 | BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); |
188 | BUG_ON(blk_rq_is_passthrough(rq)); | 188 | BUG_ON(blk_rq_is_passthrough(rq)); |
189 | 189 | ||
190 | ledtrig_disk_activity(); | 190 | ledtrig_disk_activity(rq_data_dir(rq) == WRITE); |
191 | 191 | ||
192 | pr_debug("%s: %sing: block=%llu, sectors=%u\n", | 192 | pr_debug("%s: %sing: block=%llu, sectors=%u\n", |
193 | drive->name, rq_data_dir(rq) == READ ? "read" : "writ", | 193 | drive->name, rq_data_dir(rq) == READ ? "read" : "writ", |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 3e763d2a0cb3..2c896c0e69e1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -69,7 +69,7 @@ config LEDS_APU | |||
69 | module will be called leds-apu. | 69 | module will be called leds-apu. |
70 | 70 | ||
71 | config LEDS_AS3645A | 71 | config LEDS_AS3645A |
72 | tristate "AS3645A LED flash controller support" | 72 | tristate "AS3645A and LM3555 LED flash controllers support" |
73 | depends on I2C && LEDS_CLASS_FLASH | 73 | depends on I2C && LEDS_CLASS_FLASH |
74 | depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS | 74 | depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS |
75 | help | 75 | help |
@@ -521,7 +521,7 @@ config LEDS_MC13783 | |||
521 | depends on LEDS_CLASS | 521 | depends on LEDS_CLASS |
522 | depends on MFD_MC13XXX | 522 | depends on MFD_MC13XXX |
523 | help | 523 | help |
524 | This option enable support for on-chip LED drivers found | 524 | This option enables support for on-chip LED drivers found |
525 | on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC. | 525 | on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC. |
526 | 526 | ||
527 | config LEDS_NS2 | 527 | config LEDS_NS2 |
@@ -544,7 +544,7 @@ config LEDS_NETXBIG | |||
544 | depends on MACH_KIRKWOOD | 544 | depends on MACH_KIRKWOOD |
545 | default y | 545 | default y |
546 | help | 546 | help |
547 | This option enable support for LEDs found on the LaCie 2Big | 547 | This option enables support for LEDs found on the LaCie 2Big |
548 | and 5Big Network v2 boards. The LEDs are wired to a CPLD and are | 548 | and 5Big Network v2 boards. The LEDs are wired to a CPLD and are |
549 | controlled through a GPIO extension bus. | 549 | controlled through a GPIO extension bus. |
550 | 550 | ||
@@ -594,12 +594,12 @@ config LEDS_MAX8997 | |||
594 | MAXIM MAX8997 PMIC. | 594 | MAXIM MAX8997 PMIC. |
595 | 595 | ||
596 | config LEDS_LM355x | 596 | config LEDS_LM355x |
597 | tristate "LED support for LM355x Chips, LM3554 and LM3556" | 597 | tristate "LED support for LM3554 and LM3556 chips" |
598 | depends on LEDS_CLASS && I2C | 598 | depends on LEDS_CLASS && I2C |
599 | select REGMAP_I2C | 599 | select REGMAP_I2C |
600 | help | 600 | help |
601 | This option enables support for LEDs connected to LM355x. | 601 | This option enables support for LEDs connected to LM3554 |
602 | LM355x includes Torch, Flash and Indicator functions. | 602 | and LM3556. It includes Torch, Flash and Indicator functions. |
603 | 603 | ||
604 | config LEDS_OT200 | 604 | config LEDS_OT200 |
605 | tristate "LED support for the Bachmann OT200" | 605 | tristate "LED support for the Bachmann OT200" |
@@ -674,7 +674,7 @@ config LEDS_SYSCON | |||
674 | depends on MFD_SYSCON | 674 | depends on MFD_SYSCON |
675 | depends on OF | 675 | depends on OF |
676 | help | 676 | help |
677 | This option enabled support for the LEDs on syscon type | 677 | This option enables support for the LEDs on syscon type |
678 | devices. This will only work with device tree enabled | 678 | devices. This will only work with device tree enabled |
679 | devices. | 679 | devices. |
680 | 680 | ||
@@ -688,11 +688,20 @@ config LEDS_PM8058 | |||
688 | 688 | ||
689 | config LEDS_MLXCPLD | 689 | config LEDS_MLXCPLD |
690 | tristate "LED support for the Mellanox boards" | 690 | tristate "LED support for the Mellanox boards" |
691 | depends on X86_64 && DMI | 691 | depends on X86 && DMI |
692 | depends on LEDS_CLASS | ||
693 | help | ||
694 | This option enables support for the LEDs on the Mellanox | ||
695 | boards. Say Y to enable these. | ||
696 | |||
697 | config LEDS_MLXREG | ||
698 | tristate "LED support for the Mellanox switches management control" | ||
692 | depends on LEDS_CLASS | 699 | depends on LEDS_CLASS |
693 | help | 700 | help |
694 | This option enabled support for the LEDs on the Mellanox | 701 | This option enables support for the LEDs on the Mellanox Ethernet and |
695 | boards. Say Y to enabled these. | 702 | InfiniBand switches. The driver can be activated by the platform device |
703 | device add call. Say Y to enable these. To compile this driver as a | ||
704 | module, choose 'M' here: the module will be called leds-mlxreg. | ||
696 | 705 | ||
697 | config LEDS_USER | 706 | config LEDS_USER |
698 | tristate "Userspace LED support" | 707 | tristate "Userspace LED support" |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 987884a5b9a5..91eca81cae82 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -72,6 +72,7 @@ obj-$(CONFIG_LEDS_IS31FL319X) += leds-is31fl319x.o | |||
72 | obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o | 72 | obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o |
73 | obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o | 73 | obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o |
74 | obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o | 74 | obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o |
75 | obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o | ||
75 | obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o | 76 | obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o |
76 | obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o | 77 | obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o |
77 | obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o | 78 | obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o |
diff --git a/drivers/leds/leds-apu.c b/drivers/leds/leds-apu.c index 74820aab9497..90eeedcbf371 100644 --- a/drivers/leds/leds-apu.c +++ b/drivers/leds/leds-apu.c | |||
@@ -110,6 +110,7 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = { | |||
110 | DMI_MATCH(DMI_PRODUCT_NAME, "APU") | 110 | DMI_MATCH(DMI_PRODUCT_NAME, "APU") |
111 | } | 111 | } |
112 | }, | 112 | }, |
113 | /* PC Engines APU2 with "Legacy" bios < 4.0.8 */ | ||
113 | { | 114 | { |
114 | .ident = "apu2", | 115 | .ident = "apu2", |
115 | .matches = { | 116 | .matches = { |
@@ -117,6 +118,22 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = { | |||
117 | DMI_MATCH(DMI_BOARD_NAME, "APU2") | 118 | DMI_MATCH(DMI_BOARD_NAME, "APU2") |
118 | } | 119 | } |
119 | }, | 120 | }, |
121 | /* PC Engines APU2 with "Legacy" bios >= 4.0.8 */ | ||
122 | { | ||
123 | .ident = "apu2", | ||
124 | .matches = { | ||
125 | DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), | ||
126 | DMI_MATCH(DMI_BOARD_NAME, "apu2") | ||
127 | } | ||
128 | }, | ||
129 | /* PC Engines APU2 with "Mainline" bios */ | ||
130 | { | ||
131 | .ident = "apu2", | ||
132 | .matches = { | ||
133 | DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), | ||
134 | DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2") | ||
135 | } | ||
136 | }, | ||
120 | {} | 137 | {} |
121 | }; | 138 | }; |
122 | MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table); | 139 | MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table); |
@@ -206,12 +223,14 @@ static int __init apu_led_probe(struct platform_device *pdev) | |||
206 | 223 | ||
207 | apu_led->pdev = pdev; | 224 | apu_led->pdev = pdev; |
208 | 225 | ||
209 | if (dmi_match(DMI_BOARD_NAME, "APU")) { | 226 | if (dmi_match(DMI_PRODUCT_NAME, "APU")) { |
210 | apu_led->profile = apu1_led_profile; | 227 | apu_led->profile = apu1_led_profile; |
211 | apu_led->platform = APU1_LED_PLATFORM; | 228 | apu_led->platform = APU1_LED_PLATFORM; |
212 | apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile); | 229 | apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile); |
213 | apu_led->iosize = APU1_IOSIZE; | 230 | apu_led->iosize = APU1_IOSIZE; |
214 | } else if (dmi_match(DMI_BOARD_NAME, "APU2")) { | 231 | } else if (dmi_match(DMI_BOARD_NAME, "APU2") || |
232 | dmi_match(DMI_BOARD_NAME, "apu2") || | ||
233 | dmi_match(DMI_BOARD_NAME, "PC Engines apu2")) { | ||
215 | apu_led->profile = apu2_led_profile; | 234 | apu_led->profile = apu2_led_profile; |
216 | apu_led->platform = APU2_LED_PLATFORM; | 235 | apu_led->platform = APU2_LED_PLATFORM; |
217 | apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile); | 236 | apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile); |
@@ -237,7 +256,10 @@ static int __init apu_led_init(void) | |||
237 | pr_err("No PC Engines board detected\n"); | 256 | pr_err("No PC Engines board detected\n"); |
238 | return -ENODEV; | 257 | return -ENODEV; |
239 | } | 258 | } |
240 | if (!(dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "APU2"))) { | 259 | if (!(dmi_match(DMI_PRODUCT_NAME, "APU") || |
260 | dmi_match(DMI_PRODUCT_NAME, "APU2") || | ||
261 | dmi_match(DMI_PRODUCT_NAME, "apu2") || | ||
262 | dmi_match(DMI_PRODUCT_NAME, "PC Engines apu2"))) { | ||
241 | pr_err("Unknown PC Engines board: %s\n", | 263 | pr_err("Unknown PC Engines board: %s\n", |
242 | dmi_get_system_info(DMI_PRODUCT_NAME)); | 264 | dmi_get_system_info(DMI_PRODUCT_NAME)); |
243 | return -ENODEV; | 265 | return -ENODEV; |
diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c new file mode 100644 index 000000000000..1ee48cb21df9 --- /dev/null +++ b/drivers/leds/leds-mlxreg.c | |||
@@ -0,0 +1,281 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) | ||
2 | // | ||
3 | // Copyright (c) 2018 Mellanox Technologies. All rights reserved. | ||
4 | // Copyright (c) 2018 Vadim Pasternak <vadimp@mellanox.com> | ||
5 | |||
6 | #include <linux/bitops.h> | ||
7 | #include <linux/device.h> | ||
8 | #include <linux/io.h> | ||
9 | #include <linux/leds.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/of_device.h> | ||
12 | #include <linux/platform_data/mlxreg.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/regmap.h> | ||
15 | |||
16 | /* Codes for LEDs. */ | ||
17 | #define MLXREG_LED_OFFSET_BLINK_3HZ 0x01 /* Offset from solid: 3Hz blink */ | ||
18 | #define MLXREG_LED_OFFSET_BLINK_6HZ 0x02 /* Offset from solid: 6Hz blink */ | ||
19 | #define MLXREG_LED_IS_OFF 0x00 /* Off */ | ||
20 | #define MLXREG_LED_RED_SOLID 0x05 /* Solid red */ | ||
21 | #define MLXREG_LED_GREEN_SOLID 0x0D /* Solid green */ | ||
22 | #define MLXREG_LED_AMBER_SOLID 0x09 /* Solid amber */ | ||
23 | #define MLXREG_LED_BLINK_3HZ 167 /* ~167 msec off/on - HW support */ | ||
24 | #define MLXREG_LED_BLINK_6HZ 83 /* ~83 msec off/on - HW support */ | ||
25 | |||
26 | /** | ||
27 | * struct mlxreg_led_data - led control data: | ||
28 | * | ||
29 | * @data: led configuration data; | ||
30 | * @led_classdev: led class data; | ||
31 | * @base_color: base led color (other colors have constant offset from base); | ||
32 | * @led_data: led data; | ||
33 | * @data_parent: pointer to private device control data of parent; | ||
34 | */ | ||
35 | struct mlxreg_led_data { | ||
36 | struct mlxreg_core_data *data; | ||
37 | struct led_classdev led_cdev; | ||
38 | u8 base_color; | ||
39 | void *data_parent; | ||
40 | char led_cdev_name[MLXREG_CORE_LABEL_MAX_SIZE]; | ||
41 | }; | ||
42 | |||
43 | #define cdev_to_priv(c) container_of(c, struct mlxreg_led_data, led_cdev) | ||
44 | |||
45 | /** | ||
46 | * struct mlxreg_led_priv_data - platform private data: | ||
47 | * | ||
48 | * @pdev: platform device; | ||
49 | * @pdata: platform data; | ||
50 | * @access_lock: mutex for attribute IO access; | ||
51 | */ | ||
52 | struct mlxreg_led_priv_data { | ||
53 | struct platform_device *pdev; | ||
54 | struct mlxreg_core_platform_data *pdata; | ||
55 | struct mutex access_lock; /* protect IO operations */ | ||
56 | }; | ||
57 | |||
58 | static int | ||
59 | mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset) | ||
60 | { | ||
61 | struct mlxreg_led_priv_data *priv = led_data->data_parent; | ||
62 | struct mlxreg_core_platform_data *led_pdata = priv->pdata; | ||
63 | struct mlxreg_core_data *data = led_data->data; | ||
64 | u32 regval; | ||
65 | u32 nib; | ||
66 | int ret; | ||
67 | |||
68 | /* | ||
69 | * Each LED is controlled through low or high nibble of the relevant | ||
70 | * register byte. Register offset is specified by off parameter. | ||
71 | * Parameter vset provides color code: 0x0 for off, 0x5 for solid red, | ||
72 | * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink | ||
73 | * green. | ||
74 | * Parameter mask specifies which nibble is used for specific LED: mask | ||
75 | * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f - | ||
76 | * higher nibble (bits from 4 to 7). | ||
77 | */ | ||
78 | mutex_lock(&priv->access_lock); | ||
79 | |||
80 | ret = regmap_read(led_pdata->regmap, data->reg, ®val); | ||
81 | if (ret) | ||
82 | goto access_error; | ||
83 | |||
84 | nib = (ror32(data->mask, data->bit) == 0xf0) ? rol32(vset, data->bit) : | ||
85 | rol32(vset, data->bit + 4); | ||
86 | regval = (regval & data->mask) | nib; | ||
87 | |||
88 | ret = regmap_write(led_pdata->regmap, data->reg, regval); | ||
89 | |||
90 | access_error: | ||
91 | mutex_unlock(&priv->access_lock); | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static enum led_brightness | ||
97 | mlxreg_led_get_hw(struct mlxreg_led_data *led_data) | ||
98 | { | ||
99 | struct mlxreg_led_priv_data *priv = led_data->data_parent; | ||
100 | struct mlxreg_core_platform_data *led_pdata = priv->pdata; | ||
101 | struct mlxreg_core_data *data = led_data->data; | ||
102 | u32 regval; | ||
103 | int err; | ||
104 | |||
105 | /* | ||
106 | * Each LED is controlled through low or high nibble of the relevant | ||
107 | * register byte. Register offset is specified by off parameter. | ||
108 | * Parameter vset provides color code: 0x0 for off, 0x5 for solid red, | ||
109 | * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink | ||
110 | * green. | ||
111 | * Parameter mask specifies which nibble is used for specific LED: mask | ||
112 | * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f - | ||
113 | * higher nibble (bits from 4 to 7). | ||
114 | */ | ||
115 | err = regmap_read(led_pdata->regmap, data->reg, ®val); | ||
116 | if (err < 0) { | ||
117 | dev_warn(led_data->led_cdev.dev, "Failed to get current brightness, error: %d\n", | ||
118 | err); | ||
119 | /* Assume the LED is OFF */ | ||
120 | return LED_OFF; | ||
121 | } | ||
122 | |||
123 | regval = regval & ~data->mask; | ||
124 | regval = (ror32(data->mask, data->bit) == 0xf0) ? ror32(regval, | ||
125 | data->bit) : ror32(regval, data->bit + 4); | ||
126 | if (regval >= led_data->base_color && | ||
127 | regval <= (led_data->base_color + MLXREG_LED_OFFSET_BLINK_6HZ)) | ||
128 | return LED_FULL; | ||
129 | |||
130 | return LED_OFF; | ||
131 | } | ||
132 | |||
133 | static int | ||
134 | mlxreg_led_brightness_set(struct led_classdev *cled, enum led_brightness value) | ||
135 | { | ||
136 | struct mlxreg_led_data *led_data = cdev_to_priv(cled); | ||
137 | |||
138 | if (value) | ||
139 | return mlxreg_led_store_hw(led_data, led_data->base_color); | ||
140 | else | ||
141 | return mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF); | ||
142 | } | ||
143 | |||
144 | static enum led_brightness | ||
145 | mlxreg_led_brightness_get(struct led_classdev *cled) | ||
146 | { | ||
147 | struct mlxreg_led_data *led_data = cdev_to_priv(cled); | ||
148 | |||
149 | return mlxreg_led_get_hw(led_data); | ||
150 | } | ||
151 | |||
152 | static int | ||
153 | mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on, | ||
154 | unsigned long *delay_off) | ||
155 | { | ||
156 | struct mlxreg_led_data *led_data = cdev_to_priv(cled); | ||
157 | int err; | ||
158 | |||
159 | /* | ||
160 | * HW supports two types of blinking: full (6Hz) and half (3Hz). | ||
161 | * For delay on/off zero LED is setting to solid color. For others | ||
162 | * combination blinking is to be controlled by the software timer. | ||
163 | */ | ||
164 | if (!(*delay_on == 0 && *delay_off == 0) && | ||
165 | !(*delay_on == MLXREG_LED_BLINK_3HZ && | ||
166 | *delay_off == MLXREG_LED_BLINK_3HZ) && | ||
167 | !(*delay_on == MLXREG_LED_BLINK_6HZ && | ||
168 | *delay_off == MLXREG_LED_BLINK_6HZ)) | ||
169 | return -EINVAL; | ||
170 | |||
171 | if (*delay_on == MLXREG_LED_BLINK_6HZ) | ||
172 | err = mlxreg_led_store_hw(led_data, led_data->base_color + | ||
173 | MLXREG_LED_OFFSET_BLINK_6HZ); | ||
174 | else if (*delay_on == MLXREG_LED_BLINK_3HZ) | ||
175 | err = mlxreg_led_store_hw(led_data, led_data->base_color + | ||
176 | MLXREG_LED_OFFSET_BLINK_3HZ); | ||
177 | else | ||
178 | err = mlxreg_led_store_hw(led_data, led_data->base_color); | ||
179 | |||
180 | return err; | ||
181 | } | ||
182 | |||
183 | static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) | ||
184 | { | ||
185 | struct mlxreg_core_platform_data *led_pdata = priv->pdata; | ||
186 | struct mlxreg_core_data *data = led_pdata->data; | ||
187 | struct mlxreg_led_data *led_data; | ||
188 | struct led_classdev *led_cdev; | ||
189 | enum led_brightness brightness; | ||
190 | int i; | ||
191 | int err; | ||
192 | |||
193 | for (i = 0; i < led_pdata->counter; i++, data++) { | ||
194 | led_data = devm_kzalloc(&priv->pdev->dev, sizeof(*led_data), | ||
195 | GFP_KERNEL); | ||
196 | if (!led_data) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | led_cdev = &led_data->led_cdev; | ||
200 | led_data->data_parent = priv; | ||
201 | if (strstr(data->label, "red") || | ||
202 | strstr(data->label, "orange")) { | ||
203 | brightness = LED_OFF; | ||
204 | led_data->base_color = MLXREG_LED_RED_SOLID; | ||
205 | } else if (strstr(data->label, "amber")) { | ||
206 | brightness = LED_OFF; | ||
207 | led_data->base_color = MLXREG_LED_AMBER_SOLID; | ||
208 | } else { | ||
209 | brightness = LED_OFF; | ||
210 | led_data->base_color = MLXREG_LED_GREEN_SOLID; | ||
211 | } | ||
212 | sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg", | ||
213 | data->label); | ||
214 | led_cdev->name = led_data->led_cdev_name; | ||
215 | led_cdev->brightness = brightness; | ||
216 | led_cdev->max_brightness = LED_ON; | ||
217 | led_cdev->brightness_set_blocking = | ||
218 | mlxreg_led_brightness_set; | ||
219 | led_cdev->brightness_get = mlxreg_led_brightness_get; | ||
220 | led_cdev->blink_set = mlxreg_led_blink_set; | ||
221 | led_cdev->flags = LED_CORE_SUSPENDRESUME; | ||
222 | led_data->data = data; | ||
223 | err = devm_led_classdev_register(&priv->pdev->dev, led_cdev); | ||
224 | if (err) | ||
225 | return err; | ||
226 | |||
227 | if (led_cdev->brightness) | ||
228 | mlxreg_led_brightness_set(led_cdev, | ||
229 | led_cdev->brightness); | ||
230 | dev_info(led_cdev->dev, "label: %s, mask: 0x%02x, offset:0x%02x\n", | ||
231 | data->label, data->mask, data->reg); | ||
232 | } | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int mlxreg_led_probe(struct platform_device *pdev) | ||
238 | { | ||
239 | struct mlxreg_core_platform_data *led_pdata; | ||
240 | struct mlxreg_led_priv_data *priv; | ||
241 | |||
242 | led_pdata = dev_get_platdata(&pdev->dev); | ||
243 | if (!led_pdata) { | ||
244 | dev_err(&pdev->dev, "Failed to get platform data.\n"); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
249 | if (!priv) | ||
250 | return -ENOMEM; | ||
251 | |||
252 | mutex_init(&priv->access_lock); | ||
253 | priv->pdev = pdev; | ||
254 | priv->pdata = led_pdata; | ||
255 | |||
256 | return mlxreg_led_config(priv); | ||
257 | } | ||
258 | |||
259 | static int mlxreg_led_remove(struct platform_device *pdev) | ||
260 | { | ||
261 | struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev); | ||
262 | |||
263 | mutex_destroy(&priv->access_lock); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static struct platform_driver mlxreg_led_driver = { | ||
269 | .driver = { | ||
270 | .name = "leds-mlxreg", | ||
271 | }, | ||
272 | .probe = mlxreg_led_probe, | ||
273 | .remove = mlxreg_led_remove, | ||
274 | }; | ||
275 | |||
276 | module_platform_driver(mlxreg_led_driver); | ||
277 | |||
278 | MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); | ||
279 | MODULE_DESCRIPTION("Mellanox LED regmap driver"); | ||
280 | MODULE_LICENSE("Dual BSD/GPL"); | ||
281 | MODULE_ALIAS("platform:leds-mlxreg"); | ||
diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c index cd525b4125eb..9816b0d60270 100644 --- a/drivers/leds/trigger/ledtrig-disk.c +++ b/drivers/leds/trigger/ledtrig-disk.c | |||
@@ -18,9 +18,11 @@ | |||
18 | #define BLINK_DELAY 30 | 18 | #define BLINK_DELAY 30 |
19 | 19 | ||
20 | DEFINE_LED_TRIGGER(ledtrig_disk); | 20 | DEFINE_LED_TRIGGER(ledtrig_disk); |
21 | DEFINE_LED_TRIGGER(ledtrig_disk_read); | ||
22 | DEFINE_LED_TRIGGER(ledtrig_disk_write); | ||
21 | DEFINE_LED_TRIGGER(ledtrig_ide); | 23 | DEFINE_LED_TRIGGER(ledtrig_ide); |
22 | 24 | ||
23 | void ledtrig_disk_activity(void) | 25 | void ledtrig_disk_activity(bool write) |
24 | { | 26 | { |
25 | unsigned long blink_delay = BLINK_DELAY; | 27 | unsigned long blink_delay = BLINK_DELAY; |
26 | 28 | ||
@@ -28,12 +30,20 @@ void ledtrig_disk_activity(void) | |||
28 | &blink_delay, &blink_delay, 0); | 30 | &blink_delay, &blink_delay, 0); |
29 | led_trigger_blink_oneshot(ledtrig_ide, | 31 | led_trigger_blink_oneshot(ledtrig_ide, |
30 | &blink_delay, &blink_delay, 0); | 32 | &blink_delay, &blink_delay, 0); |
33 | if (write) | ||
34 | led_trigger_blink_oneshot(ledtrig_disk_write, | ||
35 | &blink_delay, &blink_delay, 0); | ||
36 | else | ||
37 | led_trigger_blink_oneshot(ledtrig_disk_read, | ||
38 | &blink_delay, &blink_delay, 0); | ||
31 | } | 39 | } |
32 | EXPORT_SYMBOL(ledtrig_disk_activity); | 40 | EXPORT_SYMBOL(ledtrig_disk_activity); |
33 | 41 | ||
34 | static int __init ledtrig_disk_init(void) | 42 | static int __init ledtrig_disk_init(void) |
35 | { | 43 | { |
36 | led_trigger_register_simple("disk-activity", &ledtrig_disk); | 44 | led_trigger_register_simple("disk-activity", &ledtrig_disk); |
45 | led_trigger_register_simple("disk-read", &ledtrig_disk_read); | ||
46 | led_trigger_register_simple("disk-write", &ledtrig_disk_write); | ||
37 | led_trigger_register_simple("ide-disk", &ledtrig_ide); | 47 | led_trigger_register_simple("ide-disk", &ledtrig_ide); |
38 | 48 | ||
39 | return 0; | 49 | return 0; |
diff --git a/include/linux/leds.h b/include/linux/leds.h index 5579c64c8fd6..b7e82550e655 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
@@ -346,9 +346,9 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) | |||
346 | 346 | ||
347 | /* Trigger specific functions */ | 347 | /* Trigger specific functions */ |
348 | #ifdef CONFIG_LEDS_TRIGGER_DISK | 348 | #ifdef CONFIG_LEDS_TRIGGER_DISK |
349 | extern void ledtrig_disk_activity(void); | 349 | extern void ledtrig_disk_activity(bool write); |
350 | #else | 350 | #else |
351 | static inline void ledtrig_disk_activity(void) {} | 351 | static inline void ledtrig_disk_activity(bool write) {} |
352 | #endif | 352 | #endif |
353 | 353 | ||
354 | #ifdef CONFIG_LEDS_TRIGGER_MTD | 354 | #ifdef CONFIG_LEDS_TRIGGER_MTD |