diff options
author | David Phillips <david@yeah.nah.nz> | 2021-05-16 21:18:01 +1200 |
---|---|---|
committer | David Phillips <david@yeah.nah.nz> | 2021-05-16 21:18:01 +1200 |
commit | 4c0e0e4711a30923603b3bcd8cdf297c04aecef9 (patch) | |
tree | 3cedae0e9d3d829add77ff9879dc759a6fc73857 | |
parent | 5ff1c42c83849fc69c8d5bad13c6c7dc1e02a481 (diff) | |
download | cds9k-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.c | 31 |
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); |