0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/leds.h>
0010 #include <linux/regmap.h>
0011 #include <linux/of_platform.h>
0012
0013 enum ec_index {
0014 EC_BLUE_LED = 0x01,
0015 EC_AMBER_LED = 0x02,
0016 EC_GREEN_LED = 0x03,
0017 };
0018
0019 enum {
0020 EC_LED_OFF = 0x00,
0021 EC_LED_STILL = 0x01,
0022 EC_LED_FADE = 0x02,
0023 EC_LED_BLINK = 0x03,
0024 };
0025
0026 struct ariel_led {
0027 struct regmap *ec_ram;
0028 enum ec_index ec_index;
0029 struct led_classdev led_cdev;
0030 };
0031
0032 #define led_cdev_to_ariel_led(c) container_of(c, struct ariel_led, led_cdev)
0033
0034 static enum led_brightness ariel_led_get(struct led_classdev *led_cdev)
0035 {
0036 struct ariel_led *led = led_cdev_to_ariel_led(led_cdev);
0037 unsigned int led_status = 0;
0038
0039 if (regmap_read(led->ec_ram, led->ec_index, &led_status))
0040 return LED_OFF;
0041
0042 if (led_status == EC_LED_STILL)
0043 return LED_FULL;
0044 else
0045 return LED_OFF;
0046 }
0047
0048 static void ariel_led_set(struct led_classdev *led_cdev,
0049 enum led_brightness brightness)
0050 {
0051 struct ariel_led *led = led_cdev_to_ariel_led(led_cdev);
0052
0053 if (brightness == LED_OFF)
0054 regmap_write(led->ec_ram, led->ec_index, EC_LED_OFF);
0055 else
0056 regmap_write(led->ec_ram, led->ec_index, EC_LED_STILL);
0057 }
0058
0059 static int ariel_blink_set(struct led_classdev *led_cdev,
0060 unsigned long *delay_on, unsigned long *delay_off)
0061 {
0062 struct ariel_led *led = led_cdev_to_ariel_led(led_cdev);
0063
0064 if (*delay_on == 0 && *delay_off == 0)
0065 return -EINVAL;
0066
0067 if (*delay_on == 0) {
0068 regmap_write(led->ec_ram, led->ec_index, EC_LED_OFF);
0069 } else if (*delay_off == 0) {
0070 regmap_write(led->ec_ram, led->ec_index, EC_LED_STILL);
0071 } else {
0072 *delay_on = 500;
0073 *delay_off = 500;
0074 regmap_write(led->ec_ram, led->ec_index, EC_LED_BLINK);
0075 }
0076
0077 return 0;
0078 }
0079
0080 #define NLEDS 3
0081
0082 static int ariel_led_probe(struct platform_device *pdev)
0083 {
0084 struct device *dev = &pdev->dev;
0085 struct ariel_led *leds;
0086 struct regmap *ec_ram;
0087 int ret;
0088 int i;
0089
0090 ec_ram = dev_get_regmap(dev->parent, "ec_ram");
0091 if (!ec_ram)
0092 return -ENODEV;
0093
0094 leds = devm_kcalloc(dev, NLEDS, sizeof(*leds), GFP_KERNEL);
0095 if (!leds)
0096 return -ENOMEM;
0097
0098 leds[0].ec_index = EC_BLUE_LED;
0099 leds[0].led_cdev.name = "blue:power";
0100 leds[0].led_cdev.default_trigger = "default-on";
0101
0102 leds[1].ec_index = EC_AMBER_LED;
0103 leds[1].led_cdev.name = "amber:status";
0104
0105 leds[2].ec_index = EC_GREEN_LED;
0106 leds[2].led_cdev.name = "green:status";
0107 leds[2].led_cdev.default_trigger = "default-on";
0108
0109 for (i = 0; i < NLEDS; i++) {
0110 leds[i].ec_ram = ec_ram;
0111 leds[i].led_cdev.brightness_get = ariel_led_get;
0112 leds[i].led_cdev.brightness_set = ariel_led_set;
0113 leds[i].led_cdev.blink_set = ariel_blink_set;
0114
0115 ret = devm_led_classdev_register(dev, &leds[i].led_cdev);
0116 if (ret)
0117 return ret;
0118 }
0119
0120 return 0;
0121 }
0122
0123 static struct platform_driver ariel_led_driver = {
0124 .probe = ariel_led_probe,
0125 .driver = {
0126 .name = "dell-wyse-ariel-led",
0127 },
0128 };
0129 module_platform_driver(ariel_led_driver);
0130
0131 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
0132 MODULE_DESCRIPTION("Dell Wyse 3020 Status LEDs Driver");
0133 MODULE_LICENSE("Dual BSD/GPL");