0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/leds.h>
0009 #include <linux/mfd/mt6323/registers.h>
0010 #include <linux/mfd/mt6397/core.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/regmap.h>
0015
0016
0017
0018
0019
0020 #define MT6323_RG_DRV_32K_CK_PDN BIT(11)
0021 #define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11)
0022
0023
0024
0025
0026
0027 #define MT6323_RG_ISINK_CK_PDN(i) BIT(i)
0028 #define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i)
0029
0030
0031
0032
0033
0034 #define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i))
0035
0036
0037
0038
0039
0040 #define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i))
0041 #define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8)
0042 #define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \
0043 MT6323_ISINK_DIM_DUTY_MASK)
0044
0045
0046 #define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i))
0047 #define MT6323_ISINK_DIM_FSEL_MASK (0xffff)
0048 #define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK)
0049
0050
0051 #define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i))
0052 #define MT6323_ISINK_CH_STEP_SHIFT 12
0053 #define MT6323_ISINK_CH_STEP_MASK (0x7 << 12)
0054 #define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \
0055 MT6323_ISINK_CH_STEP_MASK)
0056 #define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1)
0057 #define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \
0058 MT6323_ISINK_SFSTR0_TC_MASK)
0059 #define MT6323_ISINK_SFSTR0_EN_MASK BIT(0)
0060 #define MT6323_ISINK_SFSTR0_EN BIT(0)
0061
0062
0063 #define MT6323_ISINK_CH_EN_MASK(i) BIT(i)
0064 #define MT6323_ISINK_CH_EN(i) BIT(i)
0065
0066 #define MT6323_MAX_PERIOD 10000
0067 #define MT6323_MAX_LEDS 4
0068 #define MT6323_MAX_BRIGHTNESS 6
0069 #define MT6323_UNIT_DUTY 3125
0070 #define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\
0071 (p) * MT6323_UNIT_DUTY)
0072
0073 struct mt6323_leds;
0074
0075
0076
0077
0078
0079
0080
0081
0082 struct mt6323_led {
0083 int id;
0084 struct mt6323_leds *parent;
0085 struct led_classdev cdev;
0086 enum led_brightness current_brightness;
0087 };
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 struct mt6323_leds {
0100 struct device *dev;
0101 struct mt6397_chip *hw;
0102
0103 struct mutex lock;
0104 struct mt6323_led *led[MT6323_MAX_LEDS];
0105 };
0106
0107 static int mt6323_led_hw_brightness(struct led_classdev *cdev,
0108 enum led_brightness brightness)
0109 {
0110 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0111 struct mt6323_leds *leds = led->parent;
0112 struct regmap *regmap = leds->hw->regmap;
0113 u32 con2_mask = 0, con2_val = 0;
0114 int ret;
0115
0116
0117
0118
0119
0120 con2_mask |= MT6323_ISINK_CH_STEP_MASK |
0121 MT6323_ISINK_SFSTR0_TC_MASK |
0122 MT6323_ISINK_SFSTR0_EN_MASK;
0123 con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) |
0124 MT6323_ISINK_SFSTR0_TC(2) |
0125 MT6323_ISINK_SFSTR0_EN;
0126
0127 ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
0128 con2_mask, con2_val);
0129 return ret;
0130 }
0131
0132 static int mt6323_led_hw_off(struct led_classdev *cdev)
0133 {
0134 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0135 struct mt6323_leds *leds = led->parent;
0136 struct regmap *regmap = leds->hw->regmap;
0137 unsigned int status;
0138 int ret;
0139
0140 status = MT6323_ISINK_CH_EN(led->id);
0141 ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
0142 MT6323_ISINK_CH_EN_MASK(led->id), ~status);
0143 if (ret < 0)
0144 return ret;
0145
0146 usleep_range(100, 300);
0147 ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
0148 MT6323_RG_ISINK_CK_PDN_MASK(led->id),
0149 MT6323_RG_ISINK_CK_PDN(led->id));
0150 if (ret < 0)
0151 return ret;
0152
0153 return 0;
0154 }
0155
0156 static enum led_brightness
0157 mt6323_get_led_hw_brightness(struct led_classdev *cdev)
0158 {
0159 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0160 struct mt6323_leds *leds = led->parent;
0161 struct regmap *regmap = leds->hw->regmap;
0162 unsigned int status;
0163 int ret;
0164
0165 ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
0166 if (ret < 0)
0167 return ret;
0168
0169 if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
0170 return 0;
0171
0172 ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
0173 if (ret < 0)
0174 return ret;
0175
0176 if (!(status & MT6323_ISINK_CH_EN(led->id)))
0177 return 0;
0178
0179 ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
0180 if (ret < 0)
0181 return ret;
0182
0183 return ((status & MT6323_ISINK_CH_STEP_MASK)
0184 >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
0185 }
0186
0187 static int mt6323_led_hw_on(struct led_classdev *cdev,
0188 enum led_brightness brightness)
0189 {
0190 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0191 struct mt6323_leds *leds = led->parent;
0192 struct regmap *regmap = leds->hw->regmap;
0193 unsigned int status;
0194 int ret;
0195
0196
0197
0198
0199
0200
0201 ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
0202 MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
0203 if (ret < 0)
0204 return ret;
0205
0206 status = MT6323_RG_ISINK_CK_PDN(led->id);
0207 ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
0208 MT6323_RG_ISINK_CK_PDN_MASK(led->id),
0209 ~status);
0210 if (ret < 0)
0211 return ret;
0212
0213 usleep_range(100, 300);
0214
0215 ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
0216 MT6323_ISINK_CH_EN_MASK(led->id),
0217 MT6323_ISINK_CH_EN(led->id));
0218 if (ret < 0)
0219 return ret;
0220
0221 ret = mt6323_led_hw_brightness(cdev, brightness);
0222 if (ret < 0)
0223 return ret;
0224
0225 ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
0226 MT6323_ISINK_DIM_DUTY_MASK,
0227 MT6323_ISINK_DIM_DUTY(31));
0228 if (ret < 0)
0229 return ret;
0230
0231 ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
0232 MT6323_ISINK_DIM_FSEL_MASK,
0233 MT6323_ISINK_DIM_FSEL(1000));
0234 if (ret < 0)
0235 return ret;
0236
0237 return 0;
0238 }
0239
0240 static int mt6323_led_set_blink(struct led_classdev *cdev,
0241 unsigned long *delay_on,
0242 unsigned long *delay_off)
0243 {
0244 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0245 struct mt6323_leds *leds = led->parent;
0246 struct regmap *regmap = leds->hw->regmap;
0247 unsigned long period;
0248 u8 duty_hw;
0249 int ret;
0250
0251
0252
0253
0254
0255
0256
0257 if (!*delay_on && !*delay_off) {
0258 *delay_on = 500;
0259 *delay_off = 500;
0260 }
0261
0262
0263
0264
0265
0266 period = *delay_on + *delay_off;
0267
0268 if (period > MT6323_MAX_PERIOD)
0269 return -EINVAL;
0270
0271
0272
0273
0274
0275 duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
0276
0277
0278 if (!duty_hw)
0279 return -EINVAL;
0280
0281 mutex_lock(&leds->lock);
0282
0283
0284
0285
0286 if (!led->current_brightness) {
0287 ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
0288 if (ret < 0)
0289 goto out;
0290 led->current_brightness = cdev->max_brightness;
0291 }
0292
0293 ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
0294 MT6323_ISINK_DIM_DUTY_MASK,
0295 MT6323_ISINK_DIM_DUTY(duty_hw - 1));
0296 if (ret < 0)
0297 goto out;
0298
0299 ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
0300 MT6323_ISINK_DIM_FSEL_MASK,
0301 MT6323_ISINK_DIM_FSEL(period - 1));
0302 out:
0303 mutex_unlock(&leds->lock);
0304
0305 return ret;
0306 }
0307
0308 static int mt6323_led_set_brightness(struct led_classdev *cdev,
0309 enum led_brightness brightness)
0310 {
0311 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0312 struct mt6323_leds *leds = led->parent;
0313 int ret;
0314
0315 mutex_lock(&leds->lock);
0316
0317 if (!led->current_brightness && brightness) {
0318 ret = mt6323_led_hw_on(cdev, brightness);
0319 if (ret < 0)
0320 goto out;
0321 } else if (brightness) {
0322 ret = mt6323_led_hw_brightness(cdev, brightness);
0323 if (ret < 0)
0324 goto out;
0325 } else {
0326 ret = mt6323_led_hw_off(cdev);
0327 if (ret < 0)
0328 goto out;
0329 }
0330
0331 led->current_brightness = brightness;
0332 out:
0333 mutex_unlock(&leds->lock);
0334
0335 return ret;
0336 }
0337
0338 static int mt6323_led_set_dt_default(struct led_classdev *cdev,
0339 struct device_node *np)
0340 {
0341 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
0342 const char *state;
0343 int ret = 0;
0344
0345 state = of_get_property(np, "default-state", NULL);
0346 if (state) {
0347 if (!strcmp(state, "keep")) {
0348 ret = mt6323_get_led_hw_brightness(cdev);
0349 if (ret < 0)
0350 return ret;
0351 led->current_brightness = ret;
0352 ret = 0;
0353 } else if (!strcmp(state, "on")) {
0354 ret =
0355 mt6323_led_set_brightness(cdev, cdev->max_brightness);
0356 } else {
0357 ret = mt6323_led_set_brightness(cdev, LED_OFF);
0358 }
0359 }
0360
0361 return ret;
0362 }
0363
0364 static int mt6323_led_probe(struct platform_device *pdev)
0365 {
0366 struct device *dev = &pdev->dev;
0367 struct device_node *np = dev_of_node(dev);
0368 struct device_node *child;
0369 struct mt6397_chip *hw = dev_get_drvdata(dev->parent);
0370 struct mt6323_leds *leds;
0371 struct mt6323_led *led;
0372 int ret;
0373 unsigned int status;
0374 u32 reg;
0375
0376 leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
0377 if (!leds)
0378 return -ENOMEM;
0379
0380 platform_set_drvdata(pdev, leds);
0381 leds->dev = dev;
0382
0383
0384
0385
0386
0387 leds->hw = hw;
0388 mutex_init(&leds->lock);
0389
0390 status = MT6323_RG_DRV_32K_CK_PDN;
0391 ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
0392 MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
0393 if (ret < 0) {
0394 dev_err(leds->dev,
0395 "Failed to update MT6323_TOP_CKPDN0 Register\n");
0396 return ret;
0397 }
0398
0399 for_each_available_child_of_node(np, child) {
0400 struct led_init_data init_data = {};
0401
0402 ret = of_property_read_u32(child, "reg", ®);
0403 if (ret) {
0404 dev_err(dev, "Failed to read led 'reg' property\n");
0405 goto put_child_node;
0406 }
0407
0408 if (reg >= MT6323_MAX_LEDS || leds->led[reg]) {
0409 dev_err(dev, "Invalid led reg %u\n", reg);
0410 ret = -EINVAL;
0411 goto put_child_node;
0412 }
0413
0414 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
0415 if (!led) {
0416 ret = -ENOMEM;
0417 goto put_child_node;
0418 }
0419
0420 leds->led[reg] = led;
0421 leds->led[reg]->id = reg;
0422 leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
0423 leds->led[reg]->cdev.brightness_set_blocking =
0424 mt6323_led_set_brightness;
0425 leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
0426 leds->led[reg]->cdev.brightness_get =
0427 mt6323_get_led_hw_brightness;
0428 leds->led[reg]->parent = leds;
0429
0430 ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
0431 if (ret < 0) {
0432 dev_err(leds->dev,
0433 "Failed to LED set default from devicetree\n");
0434 goto put_child_node;
0435 }
0436
0437 init_data.fwnode = of_fwnode_handle(child);
0438
0439 ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev,
0440 &init_data);
0441 if (ret) {
0442 dev_err(dev, "Failed to register LED: %d\n", ret);
0443 goto put_child_node;
0444 }
0445 }
0446
0447 return 0;
0448
0449 put_child_node:
0450 of_node_put(child);
0451 return ret;
0452 }
0453
0454 static int mt6323_led_remove(struct platform_device *pdev)
0455 {
0456 struct mt6323_leds *leds = platform_get_drvdata(pdev);
0457 int i;
0458
0459
0460 for (i = 0 ; leds->led[i] ; i++)
0461 mt6323_led_hw_off(&leds->led[i]->cdev);
0462
0463 regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
0464 MT6323_RG_DRV_32K_CK_PDN_MASK,
0465 MT6323_RG_DRV_32K_CK_PDN);
0466
0467 mutex_destroy(&leds->lock);
0468
0469 return 0;
0470 }
0471
0472 static const struct of_device_id mt6323_led_dt_match[] = {
0473 { .compatible = "mediatek,mt6323-led" },
0474 {},
0475 };
0476 MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
0477
0478 static struct platform_driver mt6323_led_driver = {
0479 .probe = mt6323_led_probe,
0480 .remove = mt6323_led_remove,
0481 .driver = {
0482 .name = "mt6323-led",
0483 .of_match_table = mt6323_led_dt_match,
0484 },
0485 };
0486
0487 module_platform_driver(mt6323_led_driver);
0488
0489 MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
0490 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
0491 MODULE_LICENSE("GPL");