diff options
| -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 |
