Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2018 Spreadtrum Communications Inc.
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 /* PMIC global control register definition */
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 /* Breathing light controller register definition */
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 /* Stage duration step, in milliseconds */
0042 #define SC27XX_LEDS_STEP    125
0043 /* Minimum and maximum duration, in milliseconds */
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     /* Reset the rise, high, fall and low time to zero. */
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      * Must contain 4 tuples to configure the rise time, high time, fall
0184      * time and low time to enable the breathing mode.
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     /* Enable the LED breathing mode */
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", &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");