1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2020 Luca Weiss <luca@z3ntu.xyz> 3 4 #include <linux/gpio/consumer.h> 5 #include <linux/led-class-flash.h> 6 #include <linux/module.h> 7 #include <linux/regulator/consumer.h> 8 #include <linux/platform_device.h> 9 10 #include <media/v4l2-flash-led-class.h> 11 12 #define FLASH_TIMEOUT_DEFAULT 250000U /* 250ms */ 13 #define FLASH_MAX_TIMEOUT_DEFAULT 300000U /* 300ms */ 14 15 struct sgm3140 { 16 struct led_classdev_flash fled_cdev; 17 struct v4l2_flash *v4l2_flash; 18 19 struct timer_list powerdown_timer; 20 21 struct gpio_desc *flash_gpio; 22 struct gpio_desc *enable_gpio; 23 struct regulator *vin_regulator; 24 25 bool enabled; 26 27 /* current timeout in us */ 28 u32 timeout; 29 /* maximum timeout in us */ 30 u32 max_timeout; 31 }; 32 33 static struct sgm3140 *flcdev_to_sgm3140(struct led_classdev_flash *flcdev) 34 { 35 return container_of(flcdev, struct sgm3140, fled_cdev); 36 } 37 38 static int sgm3140_strobe_set(struct led_classdev_flash *fled_cdev, bool state) 39 { 40 struct sgm3140 *priv = flcdev_to_sgm3140(fled_cdev); 41 int ret; 42 43 if (priv->enabled == state) 44 return 0; 45 46 if (state) { 47 ret = regulator_enable(priv->vin_regulator); 48 if (ret) { 49 dev_err(fled_cdev->led_cdev.dev, 50 "failed to enable regulator: %d\n", ret); 51 return ret; 52 } 53 gpiod_set_value_cansleep(priv->flash_gpio, 1); 54 gpiod_set_value_cansleep(priv->enable_gpio, 1); 55 mod_timer(&priv->powerdown_timer, 56 jiffies + usecs_to_jiffies(priv->timeout)); 57 } else { 58 del_timer_sync(&priv->powerdown_timer); 59 gpiod_set_value_cansleep(priv->enable_gpio, 0); 60 gpiod_set_value_cansleep(priv->flash_gpio, 0); 61 ret = regulator_disable(priv->vin_regulator); 62 if (ret) { 63 dev_err(fled_cdev->led_cdev.dev, 64 "failed to disable regulator: %d\n", ret); 65 return ret; 66 } 67 } 68 69 priv->enabled = state; 70 71 return 0; 72 } 73 74 static int sgm3140_strobe_get(struct led_classdev_flash *fled_cdev, bool *state) 75 { 76 struct sgm3140 *priv = flcdev_to_sgm3140(fled_cdev); 77 78 *state = timer_pending(&priv->powerdown_timer); 79 80 return 0; 81 } 82 83 static int sgm3140_timeout_set(struct led_classdev_flash *fled_cdev, 84 u32 timeout) 85 { 86 struct sgm3140 *priv = flcdev_to_sgm3140(fled_cdev); 87 88 priv->timeout = timeout; 89 90 return 0; 91 } 92 93 static const struct led_flash_ops sgm3140_flash_ops = { 94 .strobe_set = sgm3140_strobe_set, 95 .strobe_get = sgm3140_strobe_get, 96 .timeout_set = sgm3140_timeout_set, 97 }; 98 99 static int sgm3140_brightness_set(struct led_classdev *led_cdev, 100 enum led_brightness brightness) 101 { 102 struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 103 struct sgm3140 *priv = flcdev_to_sgm3140(fled_cdev); 104 bool enable = brightness == LED_ON; 105 int ret; 106 107 if (priv->enabled == enable) 108 return 0; 109 110 if (enable) { 111 ret = regulator_enable(priv->vin_regulator); 112 if (ret) { 113 dev_err(led_cdev->dev, 114 "failed to enable regulator: %d\n", ret); 115 return ret; 116 } 117 gpiod_set_value_cansleep(priv->flash_gpio, 0); 118 gpiod_set_value_cansleep(priv->enable_gpio, 1); 119 } else { 120 del_timer_sync(&priv->powerdown_timer); 121 gpiod_set_value_cansleep(priv->flash_gpio, 0); 122 gpiod_set_value_cansleep(priv->enable_gpio, 0); 123 ret = regulator_disable(priv->vin_regulator); 124 if (ret) { 125 dev_err(led_cdev->dev, 126 "failed to disable regulator: %d\n", ret); 127 return ret; 128 } 129 } 130 131 priv->enabled = enable; 132 133 return 0; 134 } 135 136 static void sgm3140_powerdown_timer(struct timer_list *t) 137 { 138 struct sgm3140 *priv = from_timer(priv, t, powerdown_timer); 139 140 gpiod_set_value(priv->enable_gpio, 0); 141 gpiod_set_value(priv->flash_gpio, 0); 142 regulator_disable(priv->vin_regulator); 143 144 priv->enabled = false; 145 } 146 147 static void sgm3140_init_flash_timeout(struct sgm3140 *priv) 148 { 149 struct led_classdev_flash *fled_cdev = &priv->fled_cdev; 150 struct led_flash_setting *s; 151 152 /* Init flash timeout setting */ 153 s = &fled_cdev->timeout; 154 s->min = 1; 155 s->max = priv->max_timeout; 156 s->step = 1; 157 s->val = FLASH_TIMEOUT_DEFAULT; 158 } 159 160 #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) 161 static void sgm3140_init_v4l2_flash_config(struct sgm3140 *priv, 162 struct v4l2_flash_config *v4l2_sd_cfg) 163 { 164 struct led_classdev *led_cdev = &priv->fled_cdev.led_cdev; 165 struct led_flash_setting *s; 166 167 strscpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name, 168 sizeof(v4l2_sd_cfg->dev_name)); 169 170 /* Init flash intensity setting */ 171 s = &v4l2_sd_cfg->intensity; 172 s->min = 0; 173 s->max = 1; 174 s->step = 1; 175 s->val = 1; 176 } 177 178 #else 179 static void sgm3140_init_v4l2_flash_config(struct sgm3140 *priv, 180 struct v4l2_flash_config *v4l2_sd_cfg) 181 { 182 } 183 #endif 184 185 static int sgm3140_probe(struct platform_device *pdev) 186 { 187 struct sgm3140 *priv; 188 struct led_classdev *led_cdev; 189 struct led_classdev_flash *fled_cdev; 190 struct led_init_data init_data = {}; 191 struct fwnode_handle *child_node; 192 struct v4l2_flash_config v4l2_sd_cfg = {}; 193 int ret; 194 195 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 196 if (!priv) 197 return -ENOMEM; 198 199 priv->flash_gpio = devm_gpiod_get(&pdev->dev, "flash", GPIOD_OUT_LOW); 200 ret = PTR_ERR_OR_ZERO(priv->flash_gpio); 201 if (ret) 202 return dev_err_probe(&pdev->dev, ret, 203 "Failed to request flash gpio\n"); 204 205 priv->enable_gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW); 206 ret = PTR_ERR_OR_ZERO(priv->enable_gpio); 207 if (ret) 208 return dev_err_probe(&pdev->dev, ret, 209 "Failed to request enable gpio\n"); 210 211 priv->vin_regulator = devm_regulator_get(&pdev->dev, "vin"); 212 ret = PTR_ERR_OR_ZERO(priv->vin_regulator); 213 if (ret) 214 return dev_err_probe(&pdev->dev, ret, 215 "Failed to request regulator\n"); 216 217 child_node = fwnode_get_next_available_child_node(pdev->dev.fwnode, 218 NULL); 219 if (!child_node) { 220 dev_err(&pdev->dev, 221 "No fwnode child node found for connected LED.\n"); 222 return -EINVAL; 223 } 224 225 ret = fwnode_property_read_u32(child_node, "flash-max-timeout-us", 226 &priv->max_timeout); 227 if (ret) { 228 priv->max_timeout = FLASH_MAX_TIMEOUT_DEFAULT; 229 dev_warn(&pdev->dev, 230 "flash-max-timeout-us property missing\n"); 231 } 232 233 /* 234 * Set default timeout to FLASH_DEFAULT_TIMEOUT except if max_timeout 235 * from DT is lower. 236 */ 237 priv->timeout = min(priv->max_timeout, FLASH_TIMEOUT_DEFAULT); 238 239 timer_setup(&priv->powerdown_timer, sgm3140_powerdown_timer, 0); 240 241 fled_cdev = &priv->fled_cdev; 242 led_cdev = &fled_cdev->led_cdev; 243 244 fled_cdev->ops = &sgm3140_flash_ops; 245 246 led_cdev->brightness_set_blocking = sgm3140_brightness_set; 247 led_cdev->max_brightness = LED_ON; 248 led_cdev->flags |= LED_DEV_CAP_FLASH; 249 250 sgm3140_init_flash_timeout(priv); 251 252 init_data.fwnode = child_node; 253 254 platform_set_drvdata(pdev, priv); 255 256 /* Register in the LED subsystem */ 257 ret = devm_led_classdev_flash_register_ext(&pdev->dev, 258 fled_cdev, &init_data); 259 if (ret) { 260 dev_err(&pdev->dev, "Failed to register flash device: %d\n", 261 ret); 262 goto err; 263 } 264 265 sgm3140_init_v4l2_flash_config(priv, &v4l2_sd_cfg); 266 267 /* Create V4L2 Flash subdev */ 268 priv->v4l2_flash = v4l2_flash_init(&pdev->dev, 269 child_node, 270 fled_cdev, NULL, 271 &v4l2_sd_cfg); 272 if (IS_ERR(priv->v4l2_flash)) { 273 ret = PTR_ERR(priv->v4l2_flash); 274 goto err; 275 } 276 277 return ret; 278 279 err: 280 fwnode_handle_put(child_node); 281 return ret; 282 } 283 284 static void sgm3140_remove(struct platform_device *pdev) 285 { 286 struct sgm3140 *priv = platform_get_drvdata(pdev); 287 288 del_timer_sync(&priv->powerdown_timer); 289 290 v4l2_flash_release(priv->v4l2_flash); 291 } 292 293 static const struct of_device_id sgm3140_dt_match[] = { 294 { .compatible = "ocs,ocp8110" }, 295 { .compatible = "richtek,rt5033-led" }, 296 { .compatible = "sgmicro,sgm3140" }, 297 { /* sentinel */ } 298 }; 299 MODULE_DEVICE_TABLE(of, sgm3140_dt_match); 300 301 static struct platform_driver sgm3140_driver = { 302 .probe = sgm3140_probe, 303 .remove_new = sgm3140_remove, 304 .driver = { 305 .name = "sgm3140", 306 .of_match_table = sgm3140_dt_match, 307 }, 308 }; 309 310 module_platform_driver(sgm3140_driver); 311 312 MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xyz>"); 313 MODULE_DESCRIPTION("SG Micro SGM3140 charge pump LED driver"); 314 MODULE_LICENSE("GPL v2"); 315