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