Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / leds / leds-sc27xx-bltc.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Spreadtrum Communications Inc.
3
4 #include <linux/leds.h>
5 #include <linux/module.h>
6 #include <linux/of.h>
7 #include <linux/platform_device.h>
8 #include <linux/regmap.h>
9
10 /* PMIC global control register definition */
11 #define SC27XX_MODULE_EN0       0xc08
12 #define SC27XX_CLK_EN0          0xc18
13 #define SC27XX_RGB_CTRL         0xebc
14
15 #define SC27XX_BLTC_EN          BIT(9)
16 #define SC27XX_RTC_EN           BIT(7)
17 #define SC27XX_RGB_PD           BIT(0)
18
19 /* Breathing light controller register definition */
20 #define SC27XX_LEDS_CTRL        0x00
21 #define SC27XX_LEDS_PRESCALE    0x04
22 #define SC27XX_LEDS_DUTY        0x08
23 #define SC27XX_LEDS_CURVE0      0x0c
24 #define SC27XX_LEDS_CURVE1      0x10
25
26 #define SC27XX_CTRL_SHIFT       4
27 #define SC27XX_LED_RUN          BIT(0)
28 #define SC27XX_LED_TYPE         BIT(1)
29
30 #define SC27XX_DUTY_SHIFT       8
31 #define SC27XX_DUTY_MASK        GENMASK(15, 0)
32 #define SC27XX_MOD_MASK         GENMASK(7, 0)
33
34 #define SC27XX_CURVE_SHIFT      8
35 #define SC27XX_CURVE_L_MASK     GENMASK(7, 0)
36 #define SC27XX_CURVE_H_MASK     GENMASK(15, 8)
37
38 #define SC27XX_LEDS_OFFSET      0x10
39 #define SC27XX_LEDS_MAX         3
40 #define SC27XX_LEDS_PATTERN_CNT 4
41 /* Stage duration step, in milliseconds */
42 #define SC27XX_LEDS_STEP        125
43 /* Minimum and maximum duration, in milliseconds */
44 #define SC27XX_DELTA_T_MIN      SC27XX_LEDS_STEP
45 #define SC27XX_DELTA_T_MAX      (SC27XX_LEDS_STEP * 255)
46
47 struct sc27xx_led {
48         struct fwnode_handle *fwnode;
49         struct led_classdev ldev;
50         struct sc27xx_led_priv *priv;
51         u8 line;
52         bool active;
53 };
54
55 struct sc27xx_led_priv {
56         struct sc27xx_led leds[SC27XX_LEDS_MAX];
57         struct regmap *regmap;
58         struct mutex lock;
59         u32 base;
60 };
61
62 #define to_sc27xx_led(ldev) \
63         container_of(ldev, struct sc27xx_led, ldev)
64
65 static int sc27xx_led_init(struct regmap *regmap)
66 {
67         int err;
68
69         err = regmap_update_bits(regmap, SC27XX_MODULE_EN0, SC27XX_BLTC_EN,
70                                  SC27XX_BLTC_EN);
71         if (err)
72                 return err;
73
74         err = regmap_update_bits(regmap, SC27XX_CLK_EN0, SC27XX_RTC_EN,
75                                  SC27XX_RTC_EN);
76         if (err)
77                 return err;
78
79         return regmap_update_bits(regmap, SC27XX_RGB_CTRL, SC27XX_RGB_PD, 0);
80 }
81
82 static u32 sc27xx_led_get_offset(struct sc27xx_led *leds)
83 {
84         return leds->priv->base + SC27XX_LEDS_OFFSET * leds->line;
85 }
86
87 static int sc27xx_led_enable(struct sc27xx_led *leds, enum led_brightness value)
88 {
89         u32 base = sc27xx_led_get_offset(leds);
90         u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
91         u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
92         struct regmap *regmap = leds->priv->regmap;
93         int err;
94
95         err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY,
96                                  SC27XX_DUTY_MASK,
97                                  (value << SC27XX_DUTY_SHIFT) |
98                                  SC27XX_MOD_MASK);
99         if (err)
100                 return err;
101
102         return regmap_update_bits(regmap, ctrl_base,
103                         (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift,
104                         (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift);
105 }
106
107 static int sc27xx_led_disable(struct sc27xx_led *leds)
108 {
109         struct regmap *regmap = leds->priv->regmap;
110         u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
111         u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
112
113         return regmap_update_bits(regmap, ctrl_base,
114                         (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
115 }
116
117 static int sc27xx_led_set(struct led_classdev *ldev, enum led_brightness value)
118 {
119         struct sc27xx_led *leds = to_sc27xx_led(ldev);
120         int err;
121
122         mutex_lock(&leds->priv->lock);
123
124         if (value == LED_OFF)
125                 err = sc27xx_led_disable(leds);
126         else
127                 err = sc27xx_led_enable(leds, value);
128
129         mutex_unlock(&leds->priv->lock);
130
131         return err;
132 }
133
134 static void sc27xx_led_clamp_align_delta_t(u32 *delta_t)
135 {
136         u32 v, offset, t = *delta_t;
137
138         v = t + SC27XX_LEDS_STEP / 2;
139         v = clamp_t(u32, v, SC27XX_DELTA_T_MIN, SC27XX_DELTA_T_MAX);
140         offset = v - SC27XX_DELTA_T_MIN;
141         offset = SC27XX_LEDS_STEP * (offset / SC27XX_LEDS_STEP);
142
143         *delta_t = SC27XX_DELTA_T_MIN + offset;
144 }
145
146 static int sc27xx_led_pattern_clear(struct led_classdev *ldev)
147 {
148         struct sc27xx_led *leds = to_sc27xx_led(ldev);
149         struct regmap *regmap = leds->priv->regmap;
150         u32 base = sc27xx_led_get_offset(leds);
151         u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
152         u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
153         int err;
154
155         mutex_lock(&leds->priv->lock);
156
157         /* Reset the rise, high, fall and low time to zero. */
158         regmap_write(regmap, base + SC27XX_LEDS_CURVE0, 0);
159         regmap_write(regmap, base + SC27XX_LEDS_CURVE1, 0);
160
161         err = regmap_update_bits(regmap, ctrl_base,
162                         (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
163
164         ldev->brightness = LED_OFF;
165
166         mutex_unlock(&leds->priv->lock);
167
168         return err;
169 }
170
171 static int sc27xx_led_pattern_set(struct led_classdev *ldev,
172                                   struct led_pattern *pattern,
173                                   u32 len, int repeat)
174 {
175         struct sc27xx_led *leds = to_sc27xx_led(ldev);
176         u32 base = sc27xx_led_get_offset(leds);
177         u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
178         u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
179         struct regmap *regmap = leds->priv->regmap;
180         int err;
181
182         /*
183          * Must contain 4 tuples to configure the rise time, high time, fall
184          * time and low time to enable the breathing mode.
185          */
186         if (len != SC27XX_LEDS_PATTERN_CNT)
187                 return -EINVAL;
188
189         mutex_lock(&leds->priv->lock);
190
191         sc27xx_led_clamp_align_delta_t(&pattern[0].delta_t);
192         err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0,
193                                  SC27XX_CURVE_L_MASK,
194                                  pattern[0].delta_t / SC27XX_LEDS_STEP);
195         if (err)
196                 goto out;
197
198         sc27xx_led_clamp_align_delta_t(&pattern[1].delta_t);
199         err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1,
200                                  SC27XX_CURVE_L_MASK,
201                                  pattern[1].delta_t / SC27XX_LEDS_STEP);
202         if (err)
203                 goto out;
204
205         sc27xx_led_clamp_align_delta_t(&pattern[2].delta_t);
206         err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0,
207                                  SC27XX_CURVE_H_MASK,
208                                  (pattern[2].delta_t / SC27XX_LEDS_STEP) <<
209                                  SC27XX_CURVE_SHIFT);
210         if (err)
211                 goto out;
212
213         sc27xx_led_clamp_align_delta_t(&pattern[3].delta_t);
214         err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1,
215                                  SC27XX_CURVE_H_MASK,
216                                  (pattern[3].delta_t / SC27XX_LEDS_STEP) <<
217                                  SC27XX_CURVE_SHIFT);
218         if (err)
219                 goto out;
220
221         err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY,
222                                  SC27XX_DUTY_MASK,
223                                  (pattern[1].brightness << SC27XX_DUTY_SHIFT) |
224                                  SC27XX_MOD_MASK);
225         if (err)
226                 goto out;
227
228         /* Enable the LED breathing mode */
229         err = regmap_update_bits(regmap, ctrl_base,
230                                  SC27XX_LED_RUN << ctrl_shift,
231                                  SC27XX_LED_RUN << ctrl_shift);
232         if (!err)
233                 ldev->brightness = pattern[1].brightness;
234
235 out:
236         mutex_unlock(&leds->priv->lock);
237
238         return err;
239 }
240
241 static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
242 {
243         int i, err;
244
245         err = sc27xx_led_init(priv->regmap);
246         if (err)
247                 return err;
248
249         for (i = 0; i < SC27XX_LEDS_MAX; i++) {
250                 struct sc27xx_led *led = &priv->leds[i];
251                 struct led_init_data init_data = {};
252
253                 if (!led->active)
254                         continue;
255
256                 led->line = i;
257                 led->priv = priv;
258                 led->ldev.brightness_set_blocking = sc27xx_led_set;
259                 led->ldev.pattern_set = sc27xx_led_pattern_set;
260                 led->ldev.pattern_clear = sc27xx_led_pattern_clear;
261                 led->ldev.default_trigger = "pattern";
262
263                 init_data.fwnode = led->fwnode;
264                 init_data.devicename = "sc27xx";
265                 init_data.default_label = ":";
266
267                 err = devm_led_classdev_register_ext(dev, &led->ldev,
268                                                      &init_data);
269                 if (err)
270                         return err;
271         }
272
273         return 0;
274 }
275
276 static int sc27xx_led_probe(struct platform_device *pdev)
277 {
278         struct device *dev = &pdev->dev;
279         struct device_node *np = dev_of_node(dev), *child;
280         struct sc27xx_led_priv *priv;
281         u32 base, count, reg;
282         int err;
283
284         count = of_get_available_child_count(np);
285         if (!count || count > SC27XX_LEDS_MAX)
286                 return -EINVAL;
287
288         err = of_property_read_u32(np, "reg", &base);
289         if (err) {
290                 dev_err(dev, "fail to get reg of property\n");
291                 return err;
292         }
293
294         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
295         if (!priv)
296                 return -ENOMEM;
297
298         platform_set_drvdata(pdev, priv);
299         mutex_init(&priv->lock);
300         priv->base = base;
301         priv->regmap = dev_get_regmap(dev->parent, NULL);
302         if (!priv->regmap) {
303                 err = -ENODEV;
304                 dev_err(dev, "failed to get regmap: %d\n", err);
305                 return err;
306         }
307
308         for_each_available_child_of_node(np, child) {
309                 err = of_property_read_u32(child, "reg", &reg);
310                 if (err) {
311                         of_node_put(child);
312                         mutex_destroy(&priv->lock);
313                         return err;
314                 }
315
316                 if (reg >= SC27XX_LEDS_MAX || priv->leds[reg].active) {
317                         of_node_put(child);
318                         mutex_destroy(&priv->lock);
319                         return -EINVAL;
320                 }
321
322                 priv->leds[reg].fwnode = of_fwnode_handle(child);
323                 priv->leds[reg].active = true;
324         }
325
326         err = sc27xx_led_register(dev, priv);
327         if (err)
328                 mutex_destroy(&priv->lock);
329
330         return err;
331 }
332
333 static int sc27xx_led_remove(struct platform_device *pdev)
334 {
335         struct sc27xx_led_priv *priv = platform_get_drvdata(pdev);
336
337         mutex_destroy(&priv->lock);
338         return 0;
339 }
340
341 static const struct of_device_id sc27xx_led_of_match[] = {
342         { .compatible = "sprd,sc2731-bltc", },
343         { }
344 };
345 MODULE_DEVICE_TABLE(of, sc27xx_led_of_match);
346
347 static struct platform_driver sc27xx_led_driver = {
348         .driver = {
349                 .name = "sprd-bltc",
350                 .of_match_table = sc27xx_led_of_match,
351         },
352         .probe = sc27xx_led_probe,
353         .remove = sc27xx_led_remove,
354 };
355
356 module_platform_driver(sc27xx_led_driver);
357
358 MODULE_DESCRIPTION("Spreadtrum SC27xx breathing light controller driver");
359 MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");
360 MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>");
361 MODULE_LICENSE("GPL v2");