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