0001
0002
0003
0004 #include <linux/leds.h>
0005 #include <linux/module.h>
0006 #include <linux/of.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/regmap.h>
0009
0010
0011 #define SC27XX_MODULE_EN0 0xc08
0012 #define SC27XX_CLK_EN0 0xc18
0013 #define SC27XX_RGB_CTRL 0xebc
0014
0015 #define SC27XX_BLTC_EN BIT(9)
0016 #define SC27XX_RTC_EN BIT(7)
0017 #define SC27XX_RGB_PD BIT(0)
0018
0019
0020 #define SC27XX_LEDS_CTRL 0x00
0021 #define SC27XX_LEDS_PRESCALE 0x04
0022 #define SC27XX_LEDS_DUTY 0x08
0023 #define SC27XX_LEDS_CURVE0 0x0c
0024 #define SC27XX_LEDS_CURVE1 0x10
0025
0026 #define SC27XX_CTRL_SHIFT 4
0027 #define SC27XX_LED_RUN BIT(0)
0028 #define SC27XX_LED_TYPE BIT(1)
0029
0030 #define SC27XX_DUTY_SHIFT 8
0031 #define SC27XX_DUTY_MASK GENMASK(15, 0)
0032 #define SC27XX_MOD_MASK GENMASK(7, 0)
0033
0034 #define SC27XX_CURVE_SHIFT 8
0035 #define SC27XX_CURVE_L_MASK GENMASK(7, 0)
0036 #define SC27XX_CURVE_H_MASK GENMASK(15, 8)
0037
0038 #define SC27XX_LEDS_OFFSET 0x10
0039 #define SC27XX_LEDS_MAX 3
0040 #define SC27XX_LEDS_PATTERN_CNT 4
0041
0042 #define SC27XX_LEDS_STEP 125
0043
0044 #define SC27XX_DELTA_T_MIN SC27XX_LEDS_STEP
0045 #define SC27XX_DELTA_T_MAX (SC27XX_LEDS_STEP * 255)
0046
0047 struct sc27xx_led {
0048 struct fwnode_handle *fwnode;
0049 struct led_classdev ldev;
0050 struct sc27xx_led_priv *priv;
0051 u8 line;
0052 bool active;
0053 };
0054
0055 struct sc27xx_led_priv {
0056 struct sc27xx_led leds[SC27XX_LEDS_MAX];
0057 struct regmap *regmap;
0058 struct mutex lock;
0059 u32 base;
0060 };
0061
0062 #define to_sc27xx_led(ldev) \
0063 container_of(ldev, struct sc27xx_led, ldev)
0064
0065 static int sc27xx_led_init(struct regmap *regmap)
0066 {
0067 int err;
0068
0069 err = regmap_update_bits(regmap, SC27XX_MODULE_EN0, SC27XX_BLTC_EN,
0070 SC27XX_BLTC_EN);
0071 if (err)
0072 return err;
0073
0074 err = regmap_update_bits(regmap, SC27XX_CLK_EN0, SC27XX_RTC_EN,
0075 SC27XX_RTC_EN);
0076 if (err)
0077 return err;
0078
0079 return regmap_update_bits(regmap, SC27XX_RGB_CTRL, SC27XX_RGB_PD, 0);
0080 }
0081
0082 static u32 sc27xx_led_get_offset(struct sc27xx_led *leds)
0083 {
0084 return leds->priv->base + SC27XX_LEDS_OFFSET * leds->line;
0085 }
0086
0087 static int sc27xx_led_enable(struct sc27xx_led *leds, enum led_brightness value)
0088 {
0089 u32 base = sc27xx_led_get_offset(leds);
0090 u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
0091 u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
0092 struct regmap *regmap = leds->priv->regmap;
0093 int err;
0094
0095 err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY,
0096 SC27XX_DUTY_MASK,
0097 (value << SC27XX_DUTY_SHIFT) |
0098 SC27XX_MOD_MASK);
0099 if (err)
0100 return err;
0101
0102 return regmap_update_bits(regmap, ctrl_base,
0103 (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift,
0104 (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift);
0105 }
0106
0107 static int sc27xx_led_disable(struct sc27xx_led *leds)
0108 {
0109 struct regmap *regmap = leds->priv->regmap;
0110 u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
0111 u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
0112
0113 return regmap_update_bits(regmap, ctrl_base,
0114 (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
0115 }
0116
0117 static int sc27xx_led_set(struct led_classdev *ldev, enum led_brightness value)
0118 {
0119 struct sc27xx_led *leds = to_sc27xx_led(ldev);
0120 int err;
0121
0122 mutex_lock(&leds->priv->lock);
0123
0124 if (value == LED_OFF)
0125 err = sc27xx_led_disable(leds);
0126 else
0127 err = sc27xx_led_enable(leds, value);
0128
0129 mutex_unlock(&leds->priv->lock);
0130
0131 return err;
0132 }
0133
0134 static void sc27xx_led_clamp_align_delta_t(u32 *delta_t)
0135 {
0136 u32 v, offset, t = *delta_t;
0137
0138 v = t + SC27XX_LEDS_STEP / 2;
0139 v = clamp_t(u32, v, SC27XX_DELTA_T_MIN, SC27XX_DELTA_T_MAX);
0140 offset = v - SC27XX_DELTA_T_MIN;
0141 offset = SC27XX_LEDS_STEP * (offset / SC27XX_LEDS_STEP);
0142
0143 *delta_t = SC27XX_DELTA_T_MIN + offset;
0144 }
0145
0146 static int sc27xx_led_pattern_clear(struct led_classdev *ldev)
0147 {
0148 struct sc27xx_led *leds = to_sc27xx_led(ldev);
0149 struct regmap *regmap = leds->priv->regmap;
0150 u32 base = sc27xx_led_get_offset(leds);
0151 u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
0152 u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
0153 int err;
0154
0155 mutex_lock(&leds->priv->lock);
0156
0157
0158 regmap_write(regmap, base + SC27XX_LEDS_CURVE0, 0);
0159 regmap_write(regmap, base + SC27XX_LEDS_CURVE1, 0);
0160
0161 err = regmap_update_bits(regmap, ctrl_base,
0162 (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
0163
0164 ldev->brightness = LED_OFF;
0165
0166 mutex_unlock(&leds->priv->lock);
0167
0168 return err;
0169 }
0170
0171 static int sc27xx_led_pattern_set(struct led_classdev *ldev,
0172 struct led_pattern *pattern,
0173 u32 len, int repeat)
0174 {
0175 struct sc27xx_led *leds = to_sc27xx_led(ldev);
0176 u32 base = sc27xx_led_get_offset(leds);
0177 u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
0178 u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
0179 struct regmap *regmap = leds->priv->regmap;
0180 int err;
0181
0182
0183
0184
0185
0186 if (len != SC27XX_LEDS_PATTERN_CNT)
0187 return -EINVAL;
0188
0189 mutex_lock(&leds->priv->lock);
0190
0191 sc27xx_led_clamp_align_delta_t(&pattern[0].delta_t);
0192 err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0,
0193 SC27XX_CURVE_L_MASK,
0194 pattern[0].delta_t / SC27XX_LEDS_STEP);
0195 if (err)
0196 goto out;
0197
0198 sc27xx_led_clamp_align_delta_t(&pattern[1].delta_t);
0199 err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1,
0200 SC27XX_CURVE_L_MASK,
0201 pattern[1].delta_t / SC27XX_LEDS_STEP);
0202 if (err)
0203 goto out;
0204
0205 sc27xx_led_clamp_align_delta_t(&pattern[2].delta_t);
0206 err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0,
0207 SC27XX_CURVE_H_MASK,
0208 (pattern[2].delta_t / SC27XX_LEDS_STEP) <<
0209 SC27XX_CURVE_SHIFT);
0210 if (err)
0211 goto out;
0212
0213 sc27xx_led_clamp_align_delta_t(&pattern[3].delta_t);
0214 err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1,
0215 SC27XX_CURVE_H_MASK,
0216 (pattern[3].delta_t / SC27XX_LEDS_STEP) <<
0217 SC27XX_CURVE_SHIFT);
0218 if (err)
0219 goto out;
0220
0221 err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY,
0222 SC27XX_DUTY_MASK,
0223 (pattern[1].brightness << SC27XX_DUTY_SHIFT) |
0224 SC27XX_MOD_MASK);
0225 if (err)
0226 goto out;
0227
0228
0229 err = regmap_update_bits(regmap, ctrl_base,
0230 SC27XX_LED_RUN << ctrl_shift,
0231 SC27XX_LED_RUN << ctrl_shift);
0232 if (!err)
0233 ldev->brightness = pattern[1].brightness;
0234
0235 out:
0236 mutex_unlock(&leds->priv->lock);
0237
0238 return err;
0239 }
0240
0241 static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
0242 {
0243 int i, err;
0244
0245 err = sc27xx_led_init(priv->regmap);
0246 if (err)
0247 return err;
0248
0249 for (i = 0; i < SC27XX_LEDS_MAX; i++) {
0250 struct sc27xx_led *led = &priv->leds[i];
0251 struct led_init_data init_data = {};
0252
0253 if (!led->active)
0254 continue;
0255
0256 led->line = i;
0257 led->priv = priv;
0258 led->ldev.brightness_set_blocking = sc27xx_led_set;
0259 led->ldev.pattern_set = sc27xx_led_pattern_set;
0260 led->ldev.pattern_clear = sc27xx_led_pattern_clear;
0261 led->ldev.default_trigger = "pattern";
0262
0263 init_data.fwnode = led->fwnode;
0264 init_data.devicename = "sc27xx";
0265 init_data.default_label = ":";
0266
0267 err = devm_led_classdev_register_ext(dev, &led->ldev,
0268 &init_data);
0269 if (err)
0270 return err;
0271 }
0272
0273 return 0;
0274 }
0275
0276 static int sc27xx_led_probe(struct platform_device *pdev)
0277 {
0278 struct device *dev = &pdev->dev;
0279 struct device_node *np = dev_of_node(dev), *child;
0280 struct sc27xx_led_priv *priv;
0281 u32 base, count, reg;
0282 int err;
0283
0284 count = of_get_available_child_count(np);
0285 if (!count || count > SC27XX_LEDS_MAX)
0286 return -EINVAL;
0287
0288 err = of_property_read_u32(np, "reg", &base);
0289 if (err) {
0290 dev_err(dev, "fail to get reg of property\n");
0291 return err;
0292 }
0293
0294 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0295 if (!priv)
0296 return -ENOMEM;
0297
0298 platform_set_drvdata(pdev, priv);
0299 mutex_init(&priv->lock);
0300 priv->base = base;
0301 priv->regmap = dev_get_regmap(dev->parent, NULL);
0302 if (!priv->regmap) {
0303 err = -ENODEV;
0304 dev_err(dev, "failed to get regmap: %d\n", err);
0305 return err;
0306 }
0307
0308 for_each_available_child_of_node(np, child) {
0309 err = of_property_read_u32(child, "reg", ®);
0310 if (err) {
0311 of_node_put(child);
0312 mutex_destroy(&priv->lock);
0313 return err;
0314 }
0315
0316 if (reg >= SC27XX_LEDS_MAX || priv->leds[reg].active) {
0317 of_node_put(child);
0318 mutex_destroy(&priv->lock);
0319 return -EINVAL;
0320 }
0321
0322 priv->leds[reg].fwnode = of_fwnode_handle(child);
0323 priv->leds[reg].active = true;
0324 }
0325
0326 err = sc27xx_led_register(dev, priv);
0327 if (err)
0328 mutex_destroy(&priv->lock);
0329
0330 return err;
0331 }
0332
0333 static int sc27xx_led_remove(struct platform_device *pdev)
0334 {
0335 struct sc27xx_led_priv *priv = platform_get_drvdata(pdev);
0336
0337 mutex_destroy(&priv->lock);
0338 return 0;
0339 }
0340
0341 static const struct of_device_id sc27xx_led_of_match[] = {
0342 { .compatible = "sprd,sc2731-bltc", },
0343 { }
0344 };
0345 MODULE_DEVICE_TABLE(of, sc27xx_led_of_match);
0346
0347 static struct platform_driver sc27xx_led_driver = {
0348 .driver = {
0349 .name = "sprd-bltc",
0350 .of_match_table = sc27xx_led_of_match,
0351 },
0352 .probe = sc27xx_led_probe,
0353 .remove = sc27xx_led_remove,
0354 };
0355
0356 module_platform_driver(sc27xx_led_driver);
0357
0358 MODULE_DESCRIPTION("Spreadtrum SC27xx breathing light controller driver");
0359 MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");
0360 MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>");
0361 MODULE_LICENSE("GPL v2");