aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 15:38:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 15:38:19 -0400
commite40dc66220b7ff1b816311b135b9298f8ba14ce6 (patch)
tree994467c0ea67857575a389161e6fdb97a9bae526
parentcc5ada7ca3618e25c1c2be29dad3c092573200d3 (diff)
parent92d7ec1d71e351f11ba503369eb78225510cfcc7 (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--MAINTAINERS1
-rw-r--r--drivers/ata/libata-core.c2
-rw-r--r--drivers/ide/ide-disk.c2
-rw-r--r--drivers/leds/Kconfig29
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-apu.c28
-rw-r--r--drivers/leds/leds-mlxreg.c281
-rw-r--r--drivers/leds/trigger/ledtrig-disk.c12
-rw-r--r--include/linux/leds.h4
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>
8988L: linux-leds@vger.kernel.org 8988L: linux-leds@vger.kernel.org
8989S: Supported 8989S: Supported
8990F: drivers/leds/leds-mlxcpld.c 8990F: drivers/leds/leds-mlxcpld.c
8991F: drivers/leds/leds-mlxreg.c
8991F: Documentation/leds/leds-mlxcpld.txt 8992F: Documentation/leds/leds-mlxcpld.txt
8992 8993
8993MELLANOX PLATFORM DRIVER 8994MELLANOX 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
71config LEDS_AS3645A 71config 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
527config LEDS_NS2 527config 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
596config LEDS_LM355x 596config 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
604config LEDS_OT200 604config 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
689config LEDS_MLXCPLD 689config 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
697config 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
697config LEDS_USER 706config 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
72obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o 72obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
73obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o 73obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
74obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o 74obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
75obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o
75obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o 76obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o
76obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o 77obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o
77obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o 78obj-$(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};
122MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table); 139MODULE_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 */
35struct 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 */
52struct 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
58static int
59mlxreg_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, &regval);
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
90access_error:
91 mutex_unlock(&priv->access_lock);
92
93 return ret;
94}
95
96static enum led_brightness
97mlxreg_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, &regval);
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
133static int
134mlxreg_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
144static enum led_brightness
145mlxreg_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
152static int
153mlxreg_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
183static 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
237static 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
259static 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
268static 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
276module_platform_driver(mlxreg_led_driver);
277
278MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
279MODULE_DESCRIPTION("Mellanox LED regmap driver");
280MODULE_LICENSE("Dual BSD/GPL");
281MODULE_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
20DEFINE_LED_TRIGGER(ledtrig_disk); 20DEFINE_LED_TRIGGER(ledtrig_disk);
21DEFINE_LED_TRIGGER(ledtrig_disk_read);
22DEFINE_LED_TRIGGER(ledtrig_disk_write);
21DEFINE_LED_TRIGGER(ledtrig_ide); 23DEFINE_LED_TRIGGER(ledtrig_ide);
22 24
23void ledtrig_disk_activity(void) 25void 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}
32EXPORT_SYMBOL(ledtrig_disk_activity); 40EXPORT_SYMBOL(ledtrig_disk_activity);
33 41
34static int __init ledtrig_disk_init(void) 42static 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
349extern void ledtrig_disk_activity(void); 349extern void ledtrig_disk_activity(bool write);
350#else 350#else
351static inline void ledtrig_disk_activity(void) {} 351static 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