Merge tag 'asm-generic-fix-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / leds / leds-cht-wcove.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for LEDs connected to the Intel Cherry Trail Whiskey Cove PMIC
4  *
5  * Copyright 2019 Yauhen Kharuzhy <jekhor@gmail.com>
6  * Copyright 2023 Hans de Goede <hansg@kernel.org>
7  *
8  * Register info comes from the Lenovo Yoga Book Android opensource code
9  * available from Lenovo. File lenovo_yb1_x90f_l_osc_201803.7z path in the 7z:
10  * YB1_source_code/kernel/cht/drivers/misc/charger_gp_led.c
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/leds.h>
15 #include <linux/mfd/intel_soc_pmic.h>
16 #include <linux/module.h>
17 #include <linux/mod_devicetable.h>
18 #include <linux/platform_device.h>
19 #include <linux/regmap.h>
20 #include <linux/suspend.h>
21
22 #define CHT_WC_LED1_CTRL                0x5e1f
23 #define CHT_WC_LED1_FSM                 0x5e20
24 #define CHT_WC_LED1_PWM                 0x5e21
25
26 #define CHT_WC_LED2_CTRL                0x4fdf
27 #define CHT_WC_LED2_FSM                 0x4fe0
28 #define CHT_WC_LED2_PWM                 0x4fe1
29
30 #define CHT_WC_LED1_SWCTL               BIT(0)          /* HW or SW control of charging led */
31 #define CHT_WC_LED1_ON                  BIT(1)
32
33 #define CHT_WC_LED2_ON                  BIT(0)
34 #define CHT_WC_LED_I_MA2_5              (2 << 2)        /* LED current limit */
35 #define CHT_WC_LED_I_MASK               GENMASK(3, 2)   /* LED current limit mask */
36
37 #define CHT_WC_LED_F_1_4_HZ             (0 << 4)
38 #define CHT_WC_LED_F_1_2_HZ             (1 << 4)
39 #define CHT_WC_LED_F_1_HZ               (2 << 4)
40 #define CHT_WC_LED_F_2_HZ               (3 << 4)
41 #define CHT_WC_LED_F_MASK               GENMASK(5, 4)
42
43 #define CHT_WC_LED_EFF_OFF              (0 << 1)
44 #define CHT_WC_LED_EFF_ON               (1 << 1)
45 #define CHT_WC_LED_EFF_BLINKING         (2 << 1)
46 #define CHT_WC_LED_EFF_BREATHING        (3 << 1)
47 #define CHT_WC_LED_EFF_MASK             GENMASK(2, 1)
48
49 #define CHT_WC_LED_COUNT                2
50
51 struct cht_wc_led_regs {
52         /* Register addresses */
53         u16 ctrl;
54         u16 fsm;
55         u16 pwm;
56         /* Mask + values for turning the LED on/off */
57         u8 on_off_mask;
58         u8 on_val;
59         u8 off_val;
60 };
61
62 struct cht_wc_led_saved_regs {
63         unsigned int ctrl;
64         unsigned int fsm;
65         unsigned int pwm;
66 };
67
68 struct cht_wc_led {
69         struct led_classdev cdev;
70         const struct cht_wc_led_regs *regs;
71         struct regmap *regmap;
72         struct mutex mutex;
73         struct cht_wc_led_saved_regs saved_regs;
74 };
75
76 struct cht_wc_leds {
77         struct cht_wc_led leds[CHT_WC_LED_COUNT];
78         /* Saved LED1 initial register values */
79         struct cht_wc_led_saved_regs led1_initial_regs;
80 };
81
82 static const struct cht_wc_led_regs cht_wc_led_regs[CHT_WC_LED_COUNT] = {
83         {
84                 .ctrl           = CHT_WC_LED1_CTRL,
85                 .fsm            = CHT_WC_LED1_FSM,
86                 .pwm            = CHT_WC_LED1_PWM,
87                 .on_off_mask    = CHT_WC_LED1_SWCTL | CHT_WC_LED1_ON,
88                 .on_val         = CHT_WC_LED1_SWCTL | CHT_WC_LED1_ON,
89                 .off_val        = CHT_WC_LED1_SWCTL,
90         },
91         {
92                 .ctrl           = CHT_WC_LED2_CTRL,
93                 .fsm            = CHT_WC_LED2_FSM,
94                 .pwm            = CHT_WC_LED2_PWM,
95                 .on_off_mask    = CHT_WC_LED2_ON,
96                 .on_val         = CHT_WC_LED2_ON,
97                 .off_val        = 0,
98         },
99 };
100
101 static const char * const cht_wc_leds_names[CHT_WC_LED_COUNT] = {
102         "platform::" LED_FUNCTION_CHARGING,
103         "platform::" LED_FUNCTION_INDICATOR,
104 };
105
106 static int cht_wc_leds_brightness_set(struct led_classdev *cdev,
107                                       enum led_brightness value)
108 {
109         struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev);
110         int ret;
111
112         mutex_lock(&led->mutex);
113
114         if (!value) {
115                 ret = regmap_update_bits(led->regmap, led->regs->ctrl,
116                                          led->regs->on_off_mask, led->regs->off_val);
117                 if (ret < 0) {
118                         dev_err(cdev->dev, "Failed to turn off: %d\n", ret);
119                         goto out;
120                 }
121
122                 /* Disable HW blinking */
123                 ret = regmap_update_bits(led->regmap, led->regs->fsm,
124                                          CHT_WC_LED_EFF_MASK, CHT_WC_LED_EFF_ON);
125                 if (ret < 0)
126                         dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret);
127         } else {
128                 ret = regmap_write(led->regmap, led->regs->pwm, value);
129                 if (ret < 0) {
130                         dev_err(cdev->dev, "Failed to set brightness: %d\n", ret);
131                         goto out;
132                 }
133
134                 ret = regmap_update_bits(led->regmap, led->regs->ctrl,
135                                          led->regs->on_off_mask, led->regs->on_val);
136                 if (ret < 0)
137                         dev_err(cdev->dev, "Failed to turn on: %d\n", ret);
138         }
139 out:
140         mutex_unlock(&led->mutex);
141         return ret;
142 }
143
144 static enum led_brightness cht_wc_leds_brightness_get(struct led_classdev *cdev)
145 {
146         struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev);
147         unsigned int val;
148         int ret;
149
150         mutex_lock(&led->mutex);
151
152         ret = regmap_read(led->regmap, led->regs->ctrl, &val);
153         if (ret < 0) {
154                 dev_err(cdev->dev, "Failed to read LED CTRL reg: %d\n", ret);
155                 ret = 0;
156                 goto done;
157         }
158
159         val &= led->regs->on_off_mask;
160         if (val != led->regs->on_val) {
161                 ret = 0;
162                 goto done;
163         }
164
165         ret = regmap_read(led->regmap, led->regs->pwm, &val);
166         if (ret < 0) {
167                 dev_err(cdev->dev, "Failed to read LED PWM reg: %d\n", ret);
168                 ret = 0;
169                 goto done;
170         }
171
172         ret = val;
173 done:
174         mutex_unlock(&led->mutex);
175
176         return ret;
177 }
178
179 /* Return blinking period for given CTRL reg value */
180 static unsigned long cht_wc_leds_get_period(int ctrl)
181 {
182         ctrl &= CHT_WC_LED_F_MASK;
183
184         switch (ctrl) {
185         case CHT_WC_LED_F_1_4_HZ:
186                 return 1000 * 4;
187         case CHT_WC_LED_F_1_2_HZ:
188                 return 1000 * 2;
189         case CHT_WC_LED_F_1_HZ:
190                 return 1000;
191         case CHT_WC_LED_F_2_HZ:
192                 return 1000 / 2;
193         }
194
195         return 0;
196 }
197
198 /*
199  * Find suitable hardware blink mode for given period.
200  * period < 750 ms - select 2 HZ
201  * 750 ms <= period < 1500 ms - select 1 HZ
202  * 1500 ms <= period < 3000 ms - select 1/2 HZ
203  * 3000 ms <= period < 5000 ms - select 1/4 HZ
204  * 5000 ms <= period - return -1
205  */
206 static int cht_wc_leds_find_freq(unsigned long period)
207 {
208         if (period < 750)
209                 return CHT_WC_LED_F_2_HZ;
210         else if (period < 1500)
211                 return CHT_WC_LED_F_1_HZ;
212         else if (period < 3000)
213                 return CHT_WC_LED_F_1_2_HZ;
214         else if (period < 5000)
215                 return CHT_WC_LED_F_1_4_HZ;
216         else
217                 return -1;
218 }
219
220 static int cht_wc_leds_set_effect(struct led_classdev *cdev,
221                                   unsigned long *delay_on,
222                                   unsigned long *delay_off,
223                                   u8 effect)
224 {
225         struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev);
226         int ctrl, ret;
227
228         mutex_lock(&led->mutex);
229
230         /* Blink with 1 Hz as default if nothing specified */
231         if (!*delay_on && !*delay_off)
232                 *delay_on = *delay_off = 500;
233
234         ctrl = cht_wc_leds_find_freq(*delay_on + *delay_off);
235         if (ctrl < 0) {
236                 /* Disable HW blinking */
237                 ret = regmap_update_bits(led->regmap, led->regs->fsm,
238                                          CHT_WC_LED_EFF_MASK, CHT_WC_LED_EFF_ON);
239                 if (ret < 0)
240                         dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret);
241
242                 /* Fallback to software timer */
243                 *delay_on = *delay_off = 0;
244                 ret = -EINVAL;
245                 goto done;
246         }
247
248         ret = regmap_update_bits(led->regmap, led->regs->fsm,
249                                  CHT_WC_LED_EFF_MASK, effect);
250         if (ret < 0)
251                 dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret);
252
253         /* Set the frequency and make sure the LED is on */
254         ret = regmap_update_bits(led->regmap, led->regs->ctrl,
255                                  CHT_WC_LED_F_MASK | led->regs->on_off_mask,
256                                  ctrl | led->regs->on_val);
257         if (ret < 0)
258                 dev_err(cdev->dev, "Failed to update LED CTRL reg: %d\n", ret);
259
260         *delay_off = *delay_on = cht_wc_leds_get_period(ctrl) / 2;
261
262 done:
263         mutex_unlock(&led->mutex);
264
265         return ret;
266 }
267
268 static int cht_wc_leds_blink_set(struct led_classdev *cdev,
269                                  unsigned long *delay_on,
270                                  unsigned long *delay_off)
271 {
272         u8 effect = CHT_WC_LED_EFF_BLINKING;
273
274         /*
275          * The desired default behavior of LED1 / the charge LED is breathing
276          * while charging and on/solid when full. Since triggers cannot select
277          * breathing, blink_set() gets called when charging. Use slow breathing
278          * when the default "charging-blink-full-solid" trigger is used to
279          * achieve the desired default behavior.
280          */
281         if (cdev->flags & LED_INIT_DEFAULT_TRIGGER) {
282                 *delay_on = *delay_off = 1000;
283                 effect = CHT_WC_LED_EFF_BREATHING;
284         }
285
286         return cht_wc_leds_set_effect(cdev, delay_on, delay_off, effect);
287 }
288
289 static int cht_wc_leds_pattern_set(struct led_classdev *cdev,
290                                    struct led_pattern *pattern,
291                                    u32 len, int repeat)
292 {
293         unsigned long delay_off, delay_on;
294
295         if (repeat > 0 || len != 2 ||
296             pattern[0].brightness != 0 || pattern[1].brightness != 1 ||
297             pattern[0].delta_t != pattern[1].delta_t ||
298             (pattern[0].delta_t != 250 && pattern[0].delta_t != 500 &&
299              pattern[0].delta_t != 1000 && pattern[0].delta_t != 2000))
300                 return -EINVAL;
301
302         delay_off = pattern[0].delta_t;
303         delay_on  = pattern[1].delta_t;
304
305         return cht_wc_leds_set_effect(cdev, &delay_on, &delay_off, CHT_WC_LED_EFF_BREATHING);
306 }
307
308 static int cht_wc_leds_pattern_clear(struct led_classdev *cdev)
309 {
310         return cht_wc_leds_brightness_set(cdev, 0);
311 }
312
313 static int cht_wc_led_save_regs(struct cht_wc_led *led,
314                                 struct cht_wc_led_saved_regs *saved_regs)
315 {
316         int ret;
317
318         ret = regmap_read(led->regmap, led->regs->ctrl, &saved_regs->ctrl);
319         if (ret < 0)
320                 return ret;
321
322         ret = regmap_read(led->regmap, led->regs->fsm, &saved_regs->fsm);
323         if (ret < 0)
324                 return ret;
325
326         return regmap_read(led->regmap, led->regs->pwm, &saved_regs->pwm);
327 }
328
329 static void cht_wc_led_restore_regs(struct cht_wc_led *led,
330                                     const struct cht_wc_led_saved_regs *saved_regs)
331 {
332         regmap_write(led->regmap, led->regs->ctrl, saved_regs->ctrl);
333         regmap_write(led->regmap, led->regs->fsm, saved_regs->fsm);
334         regmap_write(led->regmap, led->regs->pwm, saved_regs->pwm);
335 }
336
337 static int cht_wc_leds_probe(struct platform_device *pdev)
338 {
339         struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
340         struct cht_wc_leds *leds;
341         int ret;
342         int i;
343
344         /*
345          * On the Lenovo Yoga Tab 3 the LED1 driver output is actually
346          * connected to a haptic feedback motor rather then a LED.
347          * So do not register a LED classdev there (LED2 is unused).
348          */
349         if (pmic->cht_wc_model == INTEL_CHT_WC_LENOVO_YT3_X90)
350                 return -ENODEV;
351
352         leds = devm_kzalloc(&pdev->dev, sizeof(*leds), GFP_KERNEL);
353         if (!leds)
354                 return -ENOMEM;
355
356         /*
357          * LED1 might be in hw-controlled mode when this driver gets loaded; and
358          * since the PMIC is always powered by the battery any changes made are
359          * permanent. Save LED1 regs to restore them on remove() or shutdown().
360          */
361         leds->leds[0].regs = &cht_wc_led_regs[0];
362         leds->leds[0].regmap = pmic->regmap;
363         ret = cht_wc_led_save_regs(&leds->leds[0], &leds->led1_initial_regs);
364         if (ret < 0)
365                 return ret;
366
367         /* Set LED1 default trigger based on machine model */
368         switch (pmic->cht_wc_model) {
369         case INTEL_CHT_WC_GPD_WIN_POCKET:
370                 leds->leds[0].cdev.default_trigger = "max170xx_battery-charging-blink-full-solid";
371                 break;
372         case INTEL_CHT_WC_XIAOMI_MIPAD2:
373                 leds->leds[0].cdev.default_trigger = "bq27520-0-charging-blink-full-solid";
374                 break;
375         case INTEL_CHT_WC_LENOVO_YOGABOOK1:
376                 leds->leds[0].cdev.default_trigger = "bq27542-0-charging-blink-full-solid";
377                 break;
378         default:
379                 dev_warn(&pdev->dev, "Unknown model, no default charging trigger\n");
380                 break;
381         }
382
383         for (i = 0; i < CHT_WC_LED_COUNT; i++) {
384                 struct cht_wc_led *led = &leds->leds[i];
385
386                 led->regs = &cht_wc_led_regs[i];
387                 led->regmap = pmic->regmap;
388                 mutex_init(&led->mutex);
389                 led->cdev.name = cht_wc_leds_names[i];
390                 led->cdev.brightness_set_blocking = cht_wc_leds_brightness_set;
391                 led->cdev.brightness_get = cht_wc_leds_brightness_get;
392                 led->cdev.blink_set = cht_wc_leds_blink_set;
393                 led->cdev.pattern_set = cht_wc_leds_pattern_set;
394                 led->cdev.pattern_clear = cht_wc_leds_pattern_clear;
395                 led->cdev.max_brightness = 255;
396
397                 ret = led_classdev_register(&pdev->dev, &led->cdev);
398                 if (ret < 0)
399                         return ret;
400         }
401
402         platform_set_drvdata(pdev, leds);
403         return 0;
404 }
405
406 static void cht_wc_leds_remove(struct platform_device *pdev)
407 {
408         struct cht_wc_leds *leds = platform_get_drvdata(pdev);
409         int i;
410
411         for (i = 0; i < CHT_WC_LED_COUNT; i++)
412                 led_classdev_unregister(&leds->leds[i].cdev);
413
414         /* Restore LED1 regs if hw-control was active else leave LED1 off */
415         if (!(leds->led1_initial_regs.ctrl & CHT_WC_LED1_SWCTL))
416                 cht_wc_led_restore_regs(&leds->leds[0], &leds->led1_initial_regs);
417 }
418
419 static void cht_wc_leds_disable(struct platform_device *pdev)
420 {
421         struct cht_wc_leds *leds = platform_get_drvdata(pdev);
422         int i;
423
424         for (i = 0; i < CHT_WC_LED_COUNT; i++)
425                 cht_wc_leds_brightness_set(&leds->leds[i].cdev, 0);
426
427         /* Restore LED1 regs if hw-control was active else leave LED1 off */
428         if (!(leds->led1_initial_regs.ctrl & CHT_WC_LED1_SWCTL))
429                 cht_wc_led_restore_regs(&leds->leds[0], &leds->led1_initial_regs);
430 }
431
432 /* On suspend save current settings and turn LEDs off */
433 static int cht_wc_leds_suspend(struct device *dev)
434 {
435         struct cht_wc_leds *leds = dev_get_drvdata(dev);
436         int i, ret;
437
438         for (i = 0; i < CHT_WC_LED_COUNT; i++) {
439                 ret = cht_wc_led_save_regs(&leds->leds[i], &leds->leds[i].saved_regs);
440                 if (ret < 0)
441                         return ret;
442         }
443
444         cht_wc_leds_disable(to_platform_device(dev));
445         return 0;
446 }
447
448 /* On resume restore the saved settings */
449 static int cht_wc_leds_resume(struct device *dev)
450 {
451         struct cht_wc_leds *leds = dev_get_drvdata(dev);
452         int i;
453
454         for (i = 0; i < CHT_WC_LED_COUNT; i++)
455                 cht_wc_led_restore_regs(&leds->leds[i], &leds->leds[i].saved_regs);
456
457         return 0;
458 }
459
460 static DEFINE_SIMPLE_DEV_PM_OPS(cht_wc_leds_pm, cht_wc_leds_suspend, cht_wc_leds_resume);
461
462 static struct platform_driver cht_wc_leds_driver = {
463         .probe = cht_wc_leds_probe,
464         .remove_new = cht_wc_leds_remove,
465         .shutdown = cht_wc_leds_disable,
466         .driver = {
467                 .name = "cht_wcove_leds",
468                 .pm = pm_sleep_ptr(&cht_wc_leds_pm),
469         },
470 };
471 module_platform_driver(cht_wc_leds_driver);
472
473 MODULE_ALIAS("platform:cht_wcove_leds");
474 MODULE_DESCRIPTION("Intel Cherry Trail Whiskey Cove PMIC LEDs driver");
475 MODULE_AUTHOR("Yauhen Kharuzhy <jekhor@gmail.com>");
476 MODULE_LICENSE("GPL");