^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * LED driver : leds-ktd2692.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015 Samsung Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Ingi Kim <ingi2.kim@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/led-class-flash.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* Value related the movie mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define KTD2692_MM_TO_FL_RATIO(x) ((x) / 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define KTD2692_MM_MIN_CURR_THRESHOLD_SCALE 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /* Value related the flash mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define KTD2692_FLASH_MODE_TIMEOUT_LEVELS 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define KTD2692_FLASH_MODE_TIMEOUT_DISABLE 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define KTD2692_FLASH_MODE_CURR_PERCENT(x) (((x) * 16) / 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* Macro for getting offset of flash timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define GET_TIMEOUT_OFFSET(timeout, step) ((timeout) / (step))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* Base register address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define KTD2692_REG_LVP_BASE 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define KTD2692_REG_FLASH_TIMEOUT_BASE 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define KTD2692_REG_MOVIE_CURRENT_BASE 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define KTD2692_REG_FLASH_CURRENT_BASE 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define KTD2692_REG_MODE_BASE 0xA0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Set bit coding time for expresswire interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define KTD2692_TIME_RESET_US 700
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define KTD2692_TIME_DATA_START_TIME_US 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define KTD2692_TIME_HIGH_END_OF_DATA_US 350
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define KTD2692_TIME_LOW_END_OF_DATA_US 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define KTD2692_TIME_SHORT_BITSET_US 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define KTD2692_TIME_LONG_BITSET_US 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* KTD2692 default length of name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define KTD2692_NAME_LENGTH 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) enum ktd2692_bitset {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) KTD2692_LOW = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) KTD2692_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* Movie / Flash Mode Control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) enum ktd2692_led_mode {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) KTD2692_MODE_DISABLE = 0, /* default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) KTD2692_MODE_MOVIE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) KTD2692_MODE_FLASH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct ktd2692_led_config_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* maximum LED current in movie mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u32 movie_max_microamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* maximum LED current in flash mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u32 flash_max_microamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* maximum flash timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u32 flash_max_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* max LED brightness level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) enum led_brightness max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct ktd2692_context {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Related LED Flash class device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct led_classdev_flash fled_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* secures access to the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct regulator *regulator;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct gpio_desc *aux_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct gpio_desc *ctrl_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) enum ktd2692_led_mode mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) enum led_brightness torch_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static struct ktd2692_context *fled_cdev_to_led(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct led_classdev_flash *fled_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return container_of(fled_cdev, struct ktd2692_context, fled_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static void ktd2692_expresswire_start(struct ktd2692_context *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) udelay(KTD2692_TIME_DATA_START_TIME_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static void ktd2692_expresswire_reset(struct ktd2692_context *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) udelay(KTD2692_TIME_RESET_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static void ktd2692_expresswire_end(struct ktd2692_context *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) udelay(KTD2692_TIME_LOW_END_OF_DATA_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) udelay(KTD2692_TIME_HIGH_END_OF_DATA_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void ktd2692_expresswire_set_bit(struct ktd2692_context *led, bool bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * The Low Bit(0) and High Bit(1) is based on a time detection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * algorithm between time low and time high
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * Time_(L_LB) : Low time of the Low Bit(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * Time_(H_LB) : High time of the LOW Bit(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * Time_(L_HB) : Low time of the High Bit(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * Time_(H_HB) : High time of the High Bit(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * It can be simplified to:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * Low Bit(0) : 2 * Time_(H_LB) < Time_(L_LB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * High Bit(1) : 2 * Time_(L_HB) < Time_(H_HB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * HIGH ___ ____ _.. _________ ___
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * |_________| |_.. |____| |__|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * LOW <L_LB> <H_LB> <L_HB> <H_HB>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * [ Low Bit (0) ] [ High Bit(1) ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (bit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) udelay(KTD2692_TIME_SHORT_BITSET_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) udelay(KTD2692_TIME_LONG_BITSET_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) udelay(KTD2692_TIME_LONG_BITSET_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) udelay(KTD2692_TIME_SHORT_BITSET_US);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ktd2692_expresswire_start(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) for (i = 7; i >= 0; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ktd2692_expresswire_set_bit(led, value & BIT(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ktd2692_expresswire_end(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) mutex_lock(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (brightness == LED_OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) led->mode = KTD2692_MODE_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ktd2692_expresswire_write(led, brightness |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) KTD2692_REG_MOVIE_CURRENT_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) led->mode = KTD2692_MODE_MOVIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) mutex_unlock(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) bool state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct led_flash_setting *timeout = &fled_cdev->timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) u32 flash_tm_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) mutex_lock(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ktd2692_expresswire_write(led, flash_tm_reg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) | KTD2692_REG_FLASH_TIMEOUT_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) led->mode = KTD2692_MODE_FLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) gpiod_direction_output(led->aux_gpio, KTD2692_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) led->mode = KTD2692_MODE_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) fled_cdev->led_cdev.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) led->mode = KTD2692_MODE_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) mutex_unlock(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) static int ktd2692_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) u32 timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static void ktd2692_init_movie_current_max(struct ktd2692_led_config_data *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) u32 offset, step;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u32 movie_current_microamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) offset = KTD2692_MOVIE_MODE_CURRENT_LEVELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) step = KTD2692_MM_TO_FL_RATIO(cfg->flash_max_microamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) / KTD2692_MOVIE_MODE_CURRENT_LEVELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) movie_current_microamp = step * offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) offset--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) } while ((movie_current_microamp > cfg->movie_max_microamp) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) (offset > 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cfg->max_brightness = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct ktd2692_led_config_data *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) struct led_flash_setting *setting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) setting = &fled_cdev->timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) setting->min = KTD2692_FLASH_MODE_TIMEOUT_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) setting->max = cfg->flash_max_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) setting->step = cfg->flash_max_timeout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) / (KTD2692_FLASH_MODE_TIMEOUT_LEVELS - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) setting->val = cfg->flash_max_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static void ktd2692_setup(struct ktd2692_context *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) led->mode = KTD2692_MODE_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ktd2692_expresswire_reset(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) | KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) | KTD2692_REG_FLASH_CURRENT_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void regulator_disable_action(void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct device *dev = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct ktd2692_context *led = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ret = regulator_disable(led->regulator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dev_err(dev, "Failed to disable supply: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) struct ktd2692_led_config_data *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct device_node *np = dev_of_node(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) struct device_node *child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (!dev_of_node(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) ret = PTR_ERR_OR_ZERO(led->aux_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) dev_err(dev, "cannot get aux-gpios %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) led->regulator = devm_regulator_get(dev, "vin");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (IS_ERR(led->regulator))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) led->regulator = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (led->regulator) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) ret = regulator_enable(led->regulator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dev_err(dev, "Failed to enable supply: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) ret = devm_add_action_or_reset(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) regulator_disable_action, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) child_node = of_get_next_available_child(np, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (!child_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) dev_err(dev, "No DT child node found for connected LED.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) led->fled_cdev.led_cdev.name =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) of_get_property(child_node, "label", NULL) ? : child_node->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) ret = of_property_read_u32(child_node, "led-max-microamp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) &cfg->movie_max_microamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) dev_err(dev, "failed to parse led-max-microamp\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) goto err_parse_dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ret = of_property_read_u32(child_node, "flash-max-microamp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) &cfg->flash_max_microamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) dev_err(dev, "failed to parse flash-max-microamp\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) goto err_parse_dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) ret = of_property_read_u32(child_node, "flash-max-timeout-us",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) &cfg->flash_max_timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) dev_err(dev, "failed to parse flash-max-timeout-us\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) goto err_parse_dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) err_parse_dt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) of_node_put(child_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static const struct led_flash_ops flash_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) .strobe_set = ktd2692_led_flash_strobe_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) .timeout_set = ktd2692_led_flash_timeout_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static int ktd2692_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) struct ktd2692_context *led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct led_classdev *led_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct led_classdev_flash *fled_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct ktd2692_led_config_data led_cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (!led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) fled_cdev = &led->fled_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) led_cdev = &fled_cdev->led_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ret = ktd2692_parse_dt(led, &pdev->dev, &led_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) ktd2692_init_flash_timeout(fled_cdev, &led_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) ktd2692_init_movie_current_max(&led_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) fled_cdev->ops = &flash_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) led_cdev->max_brightness = led_cfg.max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) led_cdev->brightness_set_blocking = ktd2692_led_brightness_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) mutex_init(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) platform_set_drvdata(pdev, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) ret = led_classdev_flash_register(&pdev->dev, fled_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) dev_err(&pdev->dev, "can't register LED %s\n", led_cdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) mutex_destroy(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) ktd2692_setup(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static int ktd2692_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct ktd2692_context *led = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) led_classdev_flash_unregister(&led->fled_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) mutex_destroy(&led->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static const struct of_device_id ktd2692_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) { .compatible = "kinetic,ktd2692", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) { /* sentinel */ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) MODULE_DEVICE_TABLE(of, ktd2692_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static struct platform_driver ktd2692_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .name = "ktd2692",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) .of_match_table = ktd2692_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) .probe = ktd2692_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) .remove = ktd2692_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) module_platform_driver(ktd2692_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) MODULE_DESCRIPTION("Kinetic KTD2692 LED driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) MODULE_LICENSE("GPL v2");