Merge branch 'address-masking'
[linux-2.6-microblaze.git] / drivers / leds / flash / leds-ktd2692.c
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");