1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * LED driver for Mediatek MT6323 PMIC 4 * 5 * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com> 6 */ 7 #include <linux/kernel.h> 8 #include <linux/leds.h> 9 #include <linux/mfd/mt6323/registers.h> 10 #include <linux/mfd/mt6397/core.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/regmap.h> 15 16 /* 17 * Register field for MT6323_TOP_CKPDN0 to enable 18 * 32K clock common for LED device. 19 */ 20 #define MT6323_RG_DRV_32K_CK_PDN BIT(11) 21 #define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11) 22 23 /* 24 * Register field for MT6323_TOP_CKPDN2 to enable 25 * individual clock for LED device. 26 */ 27 #define MT6323_RG_ISINK_CK_PDN(i) BIT(i) 28 #define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i) 29 30 /* 31 * Register field for MT6323_TOP_CKCON1 to select 32 * clock source. 33 */ 34 #define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i)) 35 36 /* 37 * Register for MT6323_ISINK_CON0 to setup the 38 * duty cycle of the blink. 39 */ 40 #define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i)) 41 #define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8) 42 #define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \ 43 MT6323_ISINK_DIM_DUTY_MASK) 44 45 /* Register to setup the period of the blink. */ 46 #define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i)) 47 #define MT6323_ISINK_DIM_FSEL_MASK (0xffff) 48 #define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK) 49 50 /* Register to control the brightness. */ 51 #define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i)) 52 #define MT6323_ISINK_CH_STEP_SHIFT 12 53 #define MT6323_ISINK_CH_STEP_MASK (0x7 << 12) 54 #define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \ 55 MT6323_ISINK_CH_STEP_MASK) 56 #define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1) 57 #define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \ 58 MT6323_ISINK_SFSTR0_TC_MASK) 59 #define MT6323_ISINK_SFSTR0_EN_MASK BIT(0) 60 #define MT6323_ISINK_SFSTR0_EN BIT(0) 61 62 /* Register to LED channel enablement. */ 63 #define MT6323_ISINK_CH_EN_MASK(i) BIT(i) 64 #define MT6323_ISINK_CH_EN(i) BIT(i) 65 66 #define MT6323_MAX_PERIOD 10000 67 #define MT6323_MAX_LEDS 4 68 #define MT6323_MAX_BRIGHTNESS 6 69 #define MT6323_UNIT_DUTY 3125 70 #define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\ 71 (p) * MT6323_UNIT_DUTY) 72 73 struct mt6323_leds; 74 75 /** 76 * struct mt6323_led - state container for the LED device 77 * @id: the identifier in MT6323 LED device 78 * @parent: the pointer to MT6323 LED controller 79 * @cdev: LED class device for this LED device 80 * @current_brightness: current state of the LED device 81 */ 82 struct mt6323_led { 83 int id; 84 struct mt6323_leds *parent; 85 struct led_classdev cdev; 86 enum led_brightness current_brightness; 87 }; 88 89 /** 90 * struct mt6323_leds - state container for holding LED controller 91 * of the driver 92 * @dev: the device pointer 93 * @hw: the underlying hardware providing shared 94 * bus for the register operations 95 * @lock: the lock among process context 96 * @led: the array that contains the state of individual 97 * LED device 98 */ 99 struct mt6323_leds { 100 struct device *dev; 101 struct mt6397_chip *hw; 102 /* protect among process context */ 103 struct mutex lock; 104 struct mt6323_led *led[MT6323_MAX_LEDS]; 105 }; 106 107 static int mt6323_led_hw_brightness(struct led_classdev *cdev, 108 enum led_brightness brightness) 109 { 110 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 111 struct mt6323_leds *leds = led->parent; 112 struct regmap *regmap = leds->hw->regmap; 113 u32 con2_mask = 0, con2_val = 0; 114 int ret; 115 116 /* 117 * Setup current output for the corresponding 118 * brightness level. 119 */ 120 con2_mask |= MT6323_ISINK_CH_STEP_MASK | 121 MT6323_ISINK_SFSTR0_TC_MASK | 122 MT6323_ISINK_SFSTR0_EN_MASK; 123 con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) | 124 MT6323_ISINK_SFSTR0_TC(2) | 125 MT6323_ISINK_SFSTR0_EN; 126 127 ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id), 128 con2_mask, con2_val); 129 return ret; 130 } 131 132 static int mt6323_led_hw_off(struct led_classdev *cdev) 133 { 134 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 135 struct mt6323_leds *leds = led->parent; 136 struct regmap *regmap = leds->hw->regmap; 137 unsigned int status; 138 int ret; 139 140 status = MT6323_ISINK_CH_EN(led->id); 141 ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, 142 MT6323_ISINK_CH_EN_MASK(led->id), ~status); 143 if (ret < 0) 144 return ret; 145 146 usleep_range(100, 300); 147 ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, 148 MT6323_RG_ISINK_CK_PDN_MASK(led->id), 149 MT6323_RG_ISINK_CK_PDN(led->id)); 150 if (ret < 0) 151 return ret; 152 153 return 0; 154 } 155 156 static enum led_brightness 157 mt6323_get_led_hw_brightness(struct led_classdev *cdev) 158 { 159 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 160 struct mt6323_leds *leds = led->parent; 161 struct regmap *regmap = leds->hw->regmap; 162 unsigned int status; 163 int ret; 164 165 ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status); 166 if (ret < 0) 167 return ret; 168 169 if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id)) 170 return 0; 171 172 ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status); 173 if (ret < 0) 174 return ret; 175 176 if (!(status & MT6323_ISINK_CH_EN(led->id))) 177 return 0; 178 179 ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status); 180 if (ret < 0) 181 return ret; 182 183 return ((status & MT6323_ISINK_CH_STEP_MASK) 184 >> MT6323_ISINK_CH_STEP_SHIFT) + 1; 185 } 186 187 static int mt6323_led_hw_on(struct led_classdev *cdev, 188 enum led_brightness brightness) 189 { 190 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 191 struct mt6323_leds *leds = led->parent; 192 struct regmap *regmap = leds->hw->regmap; 193 unsigned int status; 194 int ret; 195 196 /* 197 * Setup required clock source, enable the corresponding 198 * clock and channel and let work with continuous blink as 199 * the default. 200 */ 201 ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1, 202 MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0); 203 if (ret < 0) 204 return ret; 205 206 status = MT6323_RG_ISINK_CK_PDN(led->id); 207 ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, 208 MT6323_RG_ISINK_CK_PDN_MASK(led->id), 209 ~status); 210 if (ret < 0) 211 return ret; 212 213 usleep_range(100, 300); 214 215 ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, 216 MT6323_ISINK_CH_EN_MASK(led->id), 217 MT6323_ISINK_CH_EN(led->id)); 218 if (ret < 0) 219 return ret; 220 221 ret = mt6323_led_hw_brightness(cdev, brightness); 222 if (ret < 0) 223 return ret; 224 225 ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), 226 MT6323_ISINK_DIM_DUTY_MASK, 227 MT6323_ISINK_DIM_DUTY(31)); 228 if (ret < 0) 229 return ret; 230 231 ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), 232 MT6323_ISINK_DIM_FSEL_MASK, 233 MT6323_ISINK_DIM_FSEL(1000)); 234 if (ret < 0) 235 return ret; 236 237 return 0; 238 } 239 240 static int mt6323_led_set_blink(struct led_classdev *cdev, 241 unsigned long *delay_on, 242 unsigned long *delay_off) 243 { 244 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 245 struct mt6323_leds *leds = led->parent; 246 struct regmap *regmap = leds->hw->regmap; 247 unsigned long period; 248 u8 duty_hw; 249 int ret; 250 251 /* 252 * Units are in ms, if over the hardware able 253 * to support, fallback into software blink 254 */ 255 period = *delay_on + *delay_off; 256 257 if (period > MT6323_MAX_PERIOD) 258 return -EINVAL; 259 260 /* 261 * LED subsystem requires a default user 262 * friendly blink pattern for the LED so using 263 * 1Hz duty cycle 50% here if without specific 264 * value delay_on and delay off being assigned. 265 */ 266 if (!*delay_on && !*delay_off) { 267 *delay_on = 500; 268 *delay_off = 500; 269 } 270 271 /* 272 * Calculate duty_hw based on the percentage of period during 273 * which the led is ON. 274 */ 275 duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period); 276 277 /* hardware doesn't support zero duty cycle. */ 278 if (!duty_hw) 279 return -EINVAL; 280 281 mutex_lock(&leds->lock); 282 /* 283 * Set max_brightness as the software blink behavior 284 * when no blink brightness. 285 */ 286 if (!led->current_brightness) { 287 ret = mt6323_led_hw_on(cdev, cdev->max_brightness); 288 if (ret < 0) 289 goto out; 290 led->current_brightness = cdev->max_brightness; 291 } 292 293 ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), 294 MT6323_ISINK_DIM_DUTY_MASK, 295 MT6323_ISINK_DIM_DUTY(duty_hw - 1)); 296 if (ret < 0) 297 goto out; 298 299 ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), 300 MT6323_ISINK_DIM_FSEL_MASK, 301 MT6323_ISINK_DIM_FSEL(period - 1)); 302 out: 303 mutex_unlock(&leds->lock); 304 305 return ret; 306 } 307 308 static int mt6323_led_set_brightness(struct led_classdev *cdev, 309 enum led_brightness brightness) 310 { 311 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 312 struct mt6323_leds *leds = led->parent; 313 int ret; 314 315 mutex_lock(&leds->lock); 316 317 if (!led->current_brightness && brightness) { 318 ret = mt6323_led_hw_on(cdev, brightness); 319 if (ret < 0) 320 goto out; 321 } else if (brightness) { 322 ret = mt6323_led_hw_brightness(cdev, brightness); 323 if (ret < 0) 324 goto out; 325 } else { 326 ret = mt6323_led_hw_off(cdev); 327 if (ret < 0) 328 goto out; 329 } 330 331 led->current_brightness = brightness; 332 out: 333 mutex_unlock(&leds->lock); 334 335 return ret; 336 } 337 338 static int mt6323_led_set_dt_default(struct led_classdev *cdev, 339 struct device_node *np) 340 { 341 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 342 const char *state; 343 int ret = 0; 344 345 led->cdev.name = of_get_property(np, "label", NULL) ? : np->name; 346 led->cdev.default_trigger = of_get_property(np, 347 "linux,default-trigger", 348 NULL); 349 350 state = of_get_property(np, "default-state", NULL); 351 if (state) { 352 if (!strcmp(state, "keep")) { 353 ret = mt6323_get_led_hw_brightness(cdev); 354 if (ret < 0) 355 return ret; 356 led->current_brightness = ret; 357 ret = 0; 358 } else if (!strcmp(state, "on")) { 359 ret = 360 mt6323_led_set_brightness(cdev, cdev->max_brightness); 361 } else { 362 ret = mt6323_led_set_brightness(cdev, LED_OFF); 363 } 364 } 365 366 return ret; 367 } 368 369 static int mt6323_led_probe(struct platform_device *pdev) 370 { 371 struct device *dev = &pdev->dev; 372 struct device_node *np = pdev->dev.of_node; 373 struct device_node *child; 374 struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent); 375 struct mt6323_leds *leds; 376 struct mt6323_led *led; 377 int ret; 378 unsigned int status; 379 u32 reg; 380 381 leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); 382 if (!leds) 383 return -ENOMEM; 384 385 platform_set_drvdata(pdev, leds); 386 leds->dev = dev; 387 388 /* 389 * leds->hw points to the underlying bus for the register 390 * controlled. 391 */ 392 leds->hw = hw; 393 mutex_init(&leds->lock); 394 395 status = MT6323_RG_DRV_32K_CK_PDN; 396 ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, 397 MT6323_RG_DRV_32K_CK_PDN_MASK, ~status); 398 if (ret < 0) { 399 dev_err(leds->dev, 400 "Failed to update MT6323_TOP_CKPDN0 Register\n"); 401 return ret; 402 } 403 404 for_each_available_child_of_node(np, child) { 405 ret = of_property_read_u32(child, "reg", ®); 406 if (ret) { 407 dev_err(dev, "Failed to read led 'reg' property\n"); 408 goto put_child_node; 409 } 410 411 if (reg >= MT6323_MAX_LEDS || leds->led[reg]) { 412 dev_err(dev, "Invalid led reg %u\n", reg); 413 ret = -EINVAL; 414 goto put_child_node; 415 } 416 417 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); 418 if (!led) { 419 ret = -ENOMEM; 420 goto put_child_node; 421 } 422 423 leds->led[reg] = led; 424 leds->led[reg]->id = reg; 425 leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS; 426 leds->led[reg]->cdev.brightness_set_blocking = 427 mt6323_led_set_brightness; 428 leds->led[reg]->cdev.blink_set = mt6323_led_set_blink; 429 leds->led[reg]->cdev.brightness_get = 430 mt6323_get_led_hw_brightness; 431 leds->led[reg]->parent = leds; 432 433 ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child); 434 if (ret < 0) { 435 dev_err(leds->dev, 436 "Failed to LED set default from devicetree\n"); 437 goto put_child_node; 438 } 439 440 ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev); 441 if (ret) { 442 dev_err(&pdev->dev, "Failed to register LED: %d\n", 443 ret); 444 goto put_child_node; 445 } 446 leds->led[reg]->cdev.dev->of_node = child; 447 } 448 449 return 0; 450 451 put_child_node: 452 of_node_put(child); 453 return ret; 454 } 455 456 static int mt6323_led_remove(struct platform_device *pdev) 457 { 458 struct mt6323_leds *leds = platform_get_drvdata(pdev); 459 int i; 460 461 /* Turn the LEDs off on driver removal. */ 462 for (i = 0 ; leds->led[i] ; i++) 463 mt6323_led_hw_off(&leds->led[i]->cdev); 464 465 regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, 466 MT6323_RG_DRV_32K_CK_PDN_MASK, 467 MT6323_RG_DRV_32K_CK_PDN); 468 469 mutex_destroy(&leds->lock); 470 471 return 0; 472 } 473 474 static const struct of_device_id mt6323_led_dt_match[] = { 475 { .compatible = "mediatek,mt6323-led" }, 476 {}, 477 }; 478 MODULE_DEVICE_TABLE(of, mt6323_led_dt_match); 479 480 static struct platform_driver mt6323_led_driver = { 481 .probe = mt6323_led_probe, 482 .remove = mt6323_led_remove, 483 .driver = { 484 .name = "mt6323-led", 485 .of_match_table = mt6323_led_dt_match, 486 }, 487 }; 488 489 module_platform_driver(mt6323_led_driver); 490 491 MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC"); 492 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 493 MODULE_LICENSE("GPL"); 494