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