diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index f39f0bfe6eefcd..89413c6e8374ba 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -23,8 +23,7 @@ config LEDS_AS3645A config LEDS_KTD2692 tristate "LED support for Kinetic KTD2692 flash LED controller" depends on OF - depends on GPIOLIB - select LEDS_EXPRESSWIRE + depends on GPIOLIB || COMPILE_TEST help This option enables support for Kinetic KTD2692 LED flash connected through ExpressWire interface. diff --git a/drivers/leds/flash/leds-ktd2692.c b/drivers/leds/flash/leds-ktd2692.c index 7bb0aa2753e365..598eee5daa5271 100644 --- a/drivers/leds/flash/leds-ktd2692.c +++ b/drivers/leds/flash/leds-ktd2692.c @@ -6,9 +6,9 @@ * Ingi Kim */ +#include #include #include -#include #include #include #include @@ -37,9 +37,22 @@ #define KTD2692_REG_FLASH_CURRENT_BASE 0x80 #define KTD2692_REG_MODE_BASE 0xA0 +/* Set bit coding time for expresswire interface */ +#define KTD2692_TIME_RESET_US 700 +#define KTD2692_TIME_DATA_START_TIME_US 10 +#define KTD2692_TIME_HIGH_END_OF_DATA_US 350 +#define KTD2692_TIME_LOW_END_OF_DATA_US 10 +#define KTD2692_TIME_SHORT_BITSET_US 4 +#define KTD2692_TIME_LONG_BITSET_US 12 + /* KTD2692 default length of name */ #define KTD2692_NAME_LENGTH 20 +enum ktd2692_bitset { + KTD2692_LOW = 0, + KTD2692_HIGH, +}; + /* Movie / Flash Mode Control */ enum ktd2692_led_mode { KTD2692_MODE_DISABLE = 0, /* default */ @@ -58,19 +71,7 @@ struct ktd2692_led_config_data { enum led_brightness max_brightness; }; -const struct expresswire_timing ktd2692_timing = { - .poweroff_us = 700, - .data_start_us = 10, - .end_of_data_low_us = 10, - .end_of_data_high_us = 350, - .short_bitset_us = 4, - .long_bitset_us = 12 -}; - struct ktd2692_context { - /* Common ExpressWire properties (ctrl GPIO and timing) */ - struct expresswire_common_props props; - /* Related LED Flash class device */ struct led_classdev_flash fled_cdev; @@ -79,6 +80,7 @@ struct ktd2692_context { struct regulator *regulator; struct gpio_desc *aux_gpio; + struct gpio_desc *ctrl_gpio; enum ktd2692_led_mode mode; enum led_brightness torch_brightness; @@ -90,6 +92,67 @@ static struct ktd2692_context *fled_cdev_to_led( return container_of(fled_cdev, struct ktd2692_context, fled_cdev); } +static void ktd2692_expresswire_start(struct ktd2692_context *led) +{ + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); + udelay(KTD2692_TIME_DATA_START_TIME_US); +} + +static void ktd2692_expresswire_reset(struct ktd2692_context *led) +{ + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); + udelay(KTD2692_TIME_RESET_US); +} + +static void ktd2692_expresswire_end(struct ktd2692_context *led) +{ + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); + udelay(KTD2692_TIME_LOW_END_OF_DATA_US); + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); + udelay(KTD2692_TIME_HIGH_END_OF_DATA_US); +} + +static void ktd2692_expresswire_set_bit(struct ktd2692_context *led, bool bit) +{ + /* + * The Low Bit(0) and High Bit(1) is based on a time detection + * algorithm between time low and time high + * Time_(L_LB) : Low time of the Low Bit(0) + * Time_(H_LB) : High time of the LOW Bit(0) + * Time_(L_HB) : Low time of the High Bit(1) + * Time_(H_HB) : High time of the High Bit(1) + * + * It can be simplified to: + * Low Bit(0) : 2 * Time_(H_LB) < Time_(L_LB) + * High Bit(1) : 2 * Time_(L_HB) < Time_(H_HB) + * HIGH ___ ____ _.. _________ ___ + * |_________| |_.. |____| |__| + * LOW + * [ Low Bit (0) ] [ High Bit(1) ] + */ + if (bit) { + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); + udelay(KTD2692_TIME_SHORT_BITSET_US); + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); + udelay(KTD2692_TIME_LONG_BITSET_US); + } else { + gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW); + udelay(KTD2692_TIME_LONG_BITSET_US); + gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH); + udelay(KTD2692_TIME_SHORT_BITSET_US); + } +} + +static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value) +{ + int i; + + ktd2692_expresswire_start(led); + for (i = 7; i >= 0; i--) + ktd2692_expresswire_set_bit(led, value & BIT(i)); + ktd2692_expresswire_end(led); +} + static int ktd2692_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -100,14 +163,14 @@ static int ktd2692_led_brightness_set(struct led_classdev *led_cdev, if (brightness == LED_OFF) { led->mode = KTD2692_MODE_DISABLE; - gpiod_direction_output(led->aux_gpio, 0); + gpiod_direction_output(led->aux_gpio, KTD2692_LOW); } else { - expresswire_write_u8(&led->props, brightness | + ktd2692_expresswire_write(led, brightness | KTD2692_REG_MOVIE_CURRENT_BASE); led->mode = KTD2692_MODE_MOVIE; } - expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE); + ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE); mutex_unlock(&led->lock); return 0; @@ -124,17 +187,17 @@ static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev, if (state) { flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step); - expresswire_write_u8(&led->props, flash_tm_reg + ktd2692_expresswire_write(led, flash_tm_reg | KTD2692_REG_FLASH_TIMEOUT_BASE); led->mode = KTD2692_MODE_FLASH; - gpiod_direction_output(led->aux_gpio, 1); + gpiod_direction_output(led->aux_gpio, KTD2692_HIGH); } else { led->mode = KTD2692_MODE_DISABLE; - gpiod_direction_output(led->aux_gpio, 0); + gpiod_direction_output(led->aux_gpio, KTD2692_LOW); } - expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE); + ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE); fled_cdev->led_cdev.brightness = LED_OFF; led->mode = KTD2692_MODE_DISABLE; @@ -184,12 +247,12 @@ static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev, static void ktd2692_setup(struct ktd2692_context *led) { led->mode = KTD2692_MODE_DISABLE; - expresswire_power_off(&led->props); - gpiod_direction_output(led->aux_gpio, 0); + ktd2692_expresswire_reset(led); + gpiod_direction_output(led->aux_gpio, KTD2692_LOW); - expresswire_write_u8(&led->props, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1) + ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1) | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE); - expresswire_write_u8(&led->props, KTD2692_FLASH_MODE_CURR_PERCENT(45) + ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45) | KTD2692_REG_FLASH_CURRENT_BASE); } @@ -214,8 +277,8 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, if (!np) return -ENXIO; - led->props.ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); - ret = PTR_ERR_OR_ZERO(led->props.ctrl_gpio); + led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(led->ctrl_gpio); if (ret) return dev_err_probe(dev, ret, "cannot get ctrl-gpios\n"); @@ -349,7 +412,6 @@ static struct platform_driver ktd2692_driver = { module_platform_driver(ktd2692_driver); -MODULE_IMPORT_NS(EXPRESSWIRE); MODULE_AUTHOR("Ingi Kim "); MODULE_DESCRIPTION("Kinetic KTD2692 LED driver"); MODULE_LICENSE("GPL v2");