aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <david@yeah.nah.nz>2021-05-16 21:18:01 +1200
committerDavid Phillips <david@yeah.nah.nz>2021-05-16 21:18:01 +1200
commit4c0e0e4711a30923603b3bcd8cdf297c04aecef9 (patch)
tree3cedae0e9d3d829add77ff9879dc759a6fc73857
parent5ff1c42c83849fc69c8d5bad13c6c7dc1e02a481 (diff)
downloadcds9k-4c0e0e4711a30923603b3bcd8cdf297c04aecef9.tar.xz
led: add blink support
The blink support is a bit of an odd case that has to be shoehorned into the Linux LED API. CDS9K's LED blink logic doesn't allow for anything other than 50% duty, so we ignore delay_off all the time, and just set it to whatever we derive delay_on to rounded to.
-rw-r--r--cds9k-led.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/cds9k-led.c b/cds9k-led.c
index 3f976cc..adcb18b 100644
--- a/cds9k-led.c
+++ b/cds9k-led.c
@@ -4,8 +4,13 @@
#include <linux/regmap.h>
#include <linux/leds.h>
-#define LED_REG_VALUE 0x0
-#define LED_REG_RATE 0x1
+#define LED_REG_VALUE 0x0
+#define LED_REG_PERIOD 0x1
+
+#define LED_BLINK_MIN_MS 20
+#define LED_BLINK_MAX_MS 5100
+#define MS_TO_CDS9K(x) ((x) / 10)
+#define CDS9K_TO_MS(x) ((x) * 10)
struct cds9k_led {
struct led_classdev cdev;
@@ -13,11 +18,30 @@ struct cds9k_led {
u32 base;
};
-void cds9k_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+int cds9k_led_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
{
struct cds9k_led *led = container_of(led_cdev, struct cds9k_led, cdev);
+ unsigned long blink_value;
+ /* Only 50% duty is supported by controller, so we ignore delay_off */
+ blink_value = MS_TO_CDS9K(*delay_on);
+ if (blink_value >= 255) {
+ blink_value = 255;
+ }
+ *delay_off = *delay_on = CDS9K_TO_MS(blink_value);
+
+ return regmap_write(led->regmap, led->base + LED_REG_PERIOD, blink_value);
+}
+void cds9k_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ unsigned long blink_off = 0;
+ struct cds9k_led *led = container_of(led_cdev, struct cds9k_led, cdev);
regmap_write(led->regmap, led->base + LED_REG_VALUE, brightness);
+ if (brightness == LED_OFF)
+ cds9k_led_blink_set(led_cdev, &blink_off, &blink_off);
}
enum led_brightness cds9k_led_brightness_get(struct led_classdev *led_cdev)
@@ -64,6 +88,7 @@ static int cds9k_led_probe(struct platform_device *pdev)
led->cdev.brightness_set = cds9k_led_brightness_set;
led->cdev.brightness_get = cds9k_led_brightness_get;
led->cdev.max_brightness = 0xFF;
+ led->cdev.blink_set = cds9k_led_blink_set;
/* FIXME default state keep/on etc */
init_data.fwnode = of_fwnode_handle(np);