--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================================================
+Kernel driver for Intel Cherry Trail Whiskey Cove PMIC LEDs
+===========================================================
+
+/sys/class/leds/<led>/hw_pattern
+--------------------------------
+
+Specify a hardware pattern for the Whiskey Cove PMIC LEDs.
+
+The only supported pattern is hardware breathing mode::
+
+ "0 2000 1 2000"
+
+ ^
+ |
+ Max-| ---
+ | / \
+ | / \
+ | / \ /
+ | / \ /
+ Min-|- ---
+ |
+ 0------2------4--> time (sec)
+
+The rise and fall times must be the same value.
+Supported values are 2000, 1000, 500 and 250 for
+breathing frequencies of 1/4, 1/2, 1 and 2 Hz.
+
+The set pattern only controls the timing. For max brightness the last
+set brightness is used and the max brightness can be changed
+while breathing by writing the brightness attribute.
+
+This is just like how blinking works in the LED subsystem,
+for both sw and hw blinking the brightness can also be changed
+while blinking. Breathing on this hw really is just a variant
+mode of blinking.
return -1;
}
-static int cht_wc_leds_blink_set(struct led_classdev *cdev,
- unsigned long *delay_on,
- unsigned long *delay_off)
+static int cht_wc_leds_set_effect(struct led_classdev *cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off,
+ u8 effect)
{
struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev);
unsigned int ctrl;
}
ret = regmap_update_bits(led->regmap, led->regs->fsm,
- CHT_WC_LED_EFF_MASK, CHT_WC_LED_EFF_BLINKING);
+ CHT_WC_LED_EFF_MASK, effect);
if (ret < 0)
dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret);
return ret;
}
+static int cht_wc_leds_blink_set(struct led_classdev *cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ return cht_wc_leds_set_effect(cdev, delay_on, delay_off, CHT_WC_LED_EFF_BLINKING);
+}
+
+static int cht_wc_leds_pattern_set(struct led_classdev *cdev,
+ struct led_pattern *pattern,
+ u32 len, int repeat)
+{
+ unsigned long delay_off, delay_on;
+
+ if (repeat > 0 || len != 2 ||
+ pattern[0].brightness != 0 || pattern[1].brightness != 1 ||
+ pattern[0].delta_t != pattern[1].delta_t ||
+ (pattern[0].delta_t != 250 && pattern[0].delta_t != 500 &&
+ pattern[0].delta_t != 1000 && pattern[0].delta_t != 2000))
+ return -EINVAL;
+
+ delay_off = pattern[0].delta_t;
+ delay_on = pattern[1].delta_t;
+
+ return cht_wc_leds_set_effect(cdev, &delay_on, &delay_off, CHT_WC_LED_EFF_BREATHING);
+}
+
+static int cht_wc_leds_pattern_clear(struct led_classdev *cdev)
+{
+ return cht_wc_leds_brightness_set(cdev, 0);
+}
+
static int cht_wc_led_save_regs(struct cht_wc_led *led,
struct cht_wc_led_saved_regs *saved_regs)
{
led->cdev.brightness_set_blocking = cht_wc_leds_brightness_set;
led->cdev.brightness_get = cht_wc_leds_brightness_get;
led->cdev.blink_set = cht_wc_leds_blink_set;
+ led->cdev.pattern_set = cht_wc_leds_pattern_set;
+ led->cdev.pattern_clear = cht_wc_leds_pattern_clear;
led->cdev.max_brightness = 255;
ret = led_classdev_register(&pdev->dev, &led->cdev);