fix race condition in cor_announce_send_stop
[cor.git] / drivers / leds / leds-sc27xx-bltc.c
blob0ede87420bfc7f2470b60d255ed80c029d98da5a
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Spreadtrum Communications Inc.
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>
10 /* PMIC global control register definition */
11 #define SC27XX_MODULE_EN0 0xc08
12 #define SC27XX_CLK_EN0 0xc18
13 #define SC27XX_RGB_CTRL 0xebc
15 #define SC27XX_BLTC_EN BIT(9)
16 #define SC27XX_RTC_EN BIT(7)
17 #define SC27XX_RGB_PD BIT(0)
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
26 #define SC27XX_CTRL_SHIFT 4
27 #define SC27XX_LED_RUN BIT(0)
28 #define SC27XX_LED_TYPE BIT(1)
30 #define SC27XX_DUTY_SHIFT 8
31 #define SC27XX_DUTY_MASK GENMASK(15, 0)
32 #define SC27XX_MOD_MASK GENMASK(7, 0)
34 #define SC27XX_CURVE_SHIFT 8
35 #define SC27XX_CURVE_L_MASK GENMASK(7, 0)
36 #define SC27XX_CURVE_H_MASK GENMASK(15, 8)
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)
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;
55 struct sc27xx_led_priv {
56 struct sc27xx_led leds[SC27XX_LEDS_MAX];
57 struct regmap *regmap;
58 struct mutex lock;
59 u32 base;
62 #define to_sc27xx_led(ldev) \
63 container_of(ldev, struct sc27xx_led, ldev)
65 static int sc27xx_led_init(struct regmap *regmap)
67 int err;
69 err = regmap_update_bits(regmap, SC27XX_MODULE_EN0, SC27XX_BLTC_EN,
70 SC27XX_BLTC_EN);
71 if (err)
72 return err;
74 err = regmap_update_bits(regmap, SC27XX_CLK_EN0, SC27XX_RTC_EN,
75 SC27XX_RTC_EN);
76 if (err)
77 return err;
79 return regmap_update_bits(regmap, SC27XX_RGB_CTRL, SC27XX_RGB_PD, 0);
82 static u32 sc27xx_led_get_offset(struct sc27xx_led *leds)
84 return leds->priv->base + SC27XX_LEDS_OFFSET * leds->line;
87 static int sc27xx_led_enable(struct sc27xx_led *leds, enum led_brightness value)
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;
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;
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);
107 static int sc27xx_led_disable(struct sc27xx_led *leds)
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;
113 return regmap_update_bits(regmap, ctrl_base,
114 (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
117 static int sc27xx_led_set(struct led_classdev *ldev, enum led_brightness value)
119 struct sc27xx_led *leds = to_sc27xx_led(ldev);
120 int err;
122 mutex_lock(&leds->priv->lock);
124 if (value == LED_OFF)
125 err = sc27xx_led_disable(leds);
126 else
127 err = sc27xx_led_enable(leds, value);
129 mutex_unlock(&leds->priv->lock);
131 return err;
134 static void sc27xx_led_clamp_align_delta_t(u32 *delta_t)
136 u32 v, offset, t = *delta_t;
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);
143 *delta_t = SC27XX_DELTA_T_MIN + offset;
146 static int sc27xx_led_pattern_clear(struct led_classdev *ldev)
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;
155 mutex_lock(&leds->priv->lock);
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);
161 err = regmap_update_bits(regmap, ctrl_base,
162 (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
164 ldev->brightness = LED_OFF;
166 mutex_unlock(&leds->priv->lock);
168 return err;
171 static int sc27xx_led_pattern_set(struct led_classdev *ldev,
172 struct led_pattern *pattern,
173 u32 len, int repeat)
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;
183 * Must contain 4 tuples to configure the rise time, high time, fall
184 * time and low time to enable the breathing mode.
186 if (len != SC27XX_LEDS_PATTERN_CNT)
187 return -EINVAL;
189 mutex_lock(&leds->priv->lock);
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;
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;
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;
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;
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;
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;
235 out:
236 mutex_unlock(&leds->priv->lock);
238 return err;
241 static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
243 int i, err;
245 err = sc27xx_led_init(priv->regmap);
246 if (err)
247 return err;
249 for (i = 0; i < SC27XX_LEDS_MAX; i++) {
250 struct sc27xx_led *led = &priv->leds[i];
251 struct led_init_data init_data = {};
253 if (!led->active)
254 continue;
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";
263 init_data.fwnode = led->fwnode;
264 init_data.devicename = "sc27xx";
265 init_data.default_label = ":";
267 err = devm_led_classdev_register_ext(dev, &led->ldev,
268 &init_data);
269 if (err)
270 return err;
273 return 0;
276 static int sc27xx_led_probe(struct platform_device *pdev)
278 struct device *dev = &pdev->dev;
279 struct device_node *np = dev->of_node, *child;
280 struct sc27xx_led_priv *priv;
281 u32 base, count, reg;
282 int err;
284 count = of_get_child_count(np);
285 if (!count || count > SC27XX_LEDS_MAX)
286 return -EINVAL;
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;
294 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
295 if (!priv)
296 return -ENOMEM;
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;
308 for_each_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;
316 if (reg >= SC27XX_LEDS_MAX || priv->leds[reg].active) {
317 of_node_put(child);
318 mutex_destroy(&priv->lock);
319 return -EINVAL;
322 priv->leds[reg].fwnode = of_fwnode_handle(child);
323 priv->leds[reg].active = true;
326 err = sc27xx_led_register(dev, priv);
327 if (err)
328 mutex_destroy(&priv->lock);
330 return err;
333 static int sc27xx_led_remove(struct platform_device *pdev)
335 struct sc27xx_led_priv *priv = platform_get_drvdata(pdev);
337 mutex_destroy(&priv->lock);
338 return 0;
341 static const struct of_device_id sc27xx_led_of_match[] = {
342 { .compatible = "sprd,sc2731-bltc", },
345 MODULE_DEVICE_TABLE(of, sc27xx_led_of_match);
347 static struct platform_driver sc27xx_led_driver = {
348 .driver = {
349 .name = "sprd-bltc",
350 .of_match_table = sc27xx_led_of_match,
352 .probe = sc27xx_led_probe,
353 .remove = sc27xx_led_remove,
356 module_platform_driver(sc27xx_led_driver);
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");