leds-mt6323.c 13 KB

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