leds-mt6323.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  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. * Register field for TOP_CKPDN0 to enable
  17. * 32K clock common for LED device.
  18. */
  19. #define RG_DRV_32K_CK_PDN BIT(11)
  20. #define RG_DRV_32K_CK_PDN_MASK BIT(11)
  21. /* 32K/1M/6M clock common for WLED device */
  22. #define RG_VWLED_1M_CK_PDN BIT(0)
  23. #define RG_VWLED_32K_CK_PDN BIT(12)
  24. #define RG_VWLED_6M_CK_PDN BIT(13)
  25. /*
  26. * Register field for TOP_CKPDN2 to enable
  27. * individual clock for LED device.
  28. */
  29. #define RG_ISINK_CK_PDN(i) BIT(i)
  30. #define RG_ISINK_CK_PDN_MASK(i) BIT(i)
  31. /*
  32. * Register field for TOP_CKCON1 to select
  33. * clock source.
  34. */
  35. #define RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i))
  36. #define ISINK_CON(r, i) (r + 0x8 * (i))
  37. /* ISINK_CON0: Register to setup the duty cycle of the blink. */
  38. #define ISINK_DIM_DUTY_MASK (0x1f << 8)
  39. #define ISINK_DIM_DUTY(i) (((i) << 8) & ISINK_DIM_DUTY_MASK)
  40. /* ISINK_CON1: Register to setup the period of the blink. */
  41. #define ISINK_DIM_FSEL_MASK (0xffff)
  42. #define ISINK_DIM_FSEL(i) ((i) & ISINK_DIM_FSEL_MASK)
  43. /* ISINK_CON2: Register to control the brightness. */
  44. #define ISINK_CH_STEP_SHIFT 12
  45. #define ISINK_CH_STEP_MASK (0x7 << 12)
  46. #define ISINK_CH_STEP(i) (((i) << 12) & ISINK_CH_STEP_MASK)
  47. #define ISINK_SFSTR0_TC_MASK (0x3 << 1)
  48. #define ISINK_SFSTR0_TC(i) (((i) << 1) & ISINK_SFSTR0_TC_MASK)
  49. #define ISINK_SFSTR0_EN_MASK BIT(0)
  50. #define ISINK_SFSTR0_EN BIT(0)
  51. /* Register to LED channel enablement. */
  52. #define ISINK_CH_EN_MASK(i) BIT(i)
  53. #define ISINK_CH_EN(i) BIT(i)
  54. #define MAX_SUPPORTED_LEDS 8
  55. struct mt6323_leds;
  56. /**
  57. * struct mt6323_led - state container for the LED device
  58. * @id: the identifier in MT6323 LED device
  59. * @parent: the pointer to MT6323 LED controller
  60. * @cdev: LED class device for this LED device
  61. * @current_brightness: current state of the LED device
  62. */
  63. struct mt6323_led {
  64. int id;
  65. struct mt6323_leds *parent;
  66. struct led_classdev cdev;
  67. enum led_brightness current_brightness;
  68. };
  69. /**
  70. * struct mt6323_regs - register spec for the LED device
  71. * @top_ckpdn: Offset to ISINK_CKPDN[0..x] registers
  72. * @num_top_ckpdn: Number of ISINK_CKPDN registers
  73. * @top_ckcon: Offset to ISINK_CKCON[0..x] registers
  74. * @num_top_ckcon: Number of ISINK_CKCON registers
  75. * @isink_con: Offset to ISINKx_CON[0..x] registers
  76. * @num_isink_con: Number of ISINKx_CON registers
  77. * @isink_max_regs: Number of ISINK[0..x] registers
  78. * @isink_en_ctrl: Offset to ISINK_EN_CTRL register
  79. * @iwled_en_ctrl: Offset to IWLED_EN_CTRL register
  80. */
  81. struct mt6323_regs {
  82. const u16 *top_ckpdn;
  83. u8 num_top_ckpdn;
  84. const u16 *top_ckcon;
  85. u8 num_top_ckcon;
  86. const u16 *isink_con;
  87. u8 num_isink_con;
  88. u8 isink_max_regs;
  89. u16 isink_en_ctrl;
  90. u16 iwled_en_ctrl;
  91. };
  92. /**
  93. * struct mt6323_hwspec - hardware specific parameters
  94. * @max_period: Maximum period for all LEDs
  95. * @max_leds: Maximum number of supported LEDs
  96. * @max_wleds: Maximum number of WLEDs
  97. * @max_brightness: Maximum brightness for all LEDs
  98. * @unit_duty: Steps of duty per period
  99. */
  100. struct mt6323_hwspec {
  101. u16 max_period;
  102. u8 max_leds;
  103. u8 max_wleds;
  104. u16 max_brightness;
  105. u16 unit_duty;
  106. };
  107. /**
  108. * struct mt6323_data - device specific data
  109. * @regs: Register spec for this device
  110. * @spec: Hardware specific parameters
  111. */
  112. struct mt6323_data {
  113. const struct mt6323_regs *regs;
  114. const struct mt6323_hwspec *spec;
  115. };
  116. /**
  117. * struct mt6323_leds - state container for holding LED controller
  118. * of the driver
  119. * @dev: the device pointer
  120. * @hw: the underlying hardware providing shared
  121. * bus for the register operations
  122. * @pdata: device specific data
  123. * @lock: the lock among process context
  124. * @led: the array that contains the state of individual
  125. * LED device
  126. */
  127. struct mt6323_leds {
  128. struct device *dev;
  129. struct mt6397_chip *hw;
  130. const struct mt6323_data *pdata;
  131. /* protect among process context */
  132. struct mutex lock;
  133. struct mt6323_led *led[MAX_SUPPORTED_LEDS];
  134. };
  135. static int mt6323_led_hw_brightness(struct led_classdev *cdev,
  136. enum led_brightness brightness)
  137. {
  138. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  139. struct mt6323_leds *leds = led->parent;
  140. const struct mt6323_regs *regs = leds->pdata->regs;
  141. struct regmap *regmap = leds->hw->regmap;
  142. u32 con2_mask = 0, con2_val = 0;
  143. int ret;
  144. /*
  145. * Setup current output for the corresponding
  146. * brightness level.
  147. */
  148. con2_mask |= ISINK_CH_STEP_MASK |
  149. ISINK_SFSTR0_TC_MASK |
  150. ISINK_SFSTR0_EN_MASK;
  151. con2_val |= ISINK_CH_STEP(brightness - 1) |
  152. ISINK_SFSTR0_TC(2) |
  153. ISINK_SFSTR0_EN;
  154. ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[2], led->id),
  155. con2_mask, con2_val);
  156. return ret;
  157. }
  158. static int mt6323_led_hw_off(struct led_classdev *cdev)
  159. {
  160. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  161. struct mt6323_leds *leds = led->parent;
  162. const struct mt6323_regs *regs = leds->pdata->regs;
  163. struct regmap *regmap = leds->hw->regmap;
  164. unsigned int status;
  165. int ret;
  166. status = ISINK_CH_EN(led->id);
  167. ret = regmap_update_bits(regmap, regs->isink_en_ctrl,
  168. ISINK_CH_EN_MASK(led->id), ~status);
  169. if (ret < 0)
  170. return ret;
  171. usleep_range(100, 300);
  172. ret = regmap_update_bits(regmap, regs->top_ckpdn[2],
  173. RG_ISINK_CK_PDN_MASK(led->id),
  174. RG_ISINK_CK_PDN(led->id));
  175. if (ret < 0)
  176. return ret;
  177. return 0;
  178. }
  179. static enum led_brightness
  180. mt6323_get_led_hw_brightness(struct led_classdev *cdev)
  181. {
  182. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  183. struct mt6323_leds *leds = led->parent;
  184. const struct mt6323_regs *regs = leds->pdata->regs;
  185. struct regmap *regmap = leds->hw->regmap;
  186. unsigned int status;
  187. int ret;
  188. ret = regmap_read(regmap, regs->top_ckpdn[2], &status);
  189. if (ret < 0)
  190. return ret;
  191. if (status & RG_ISINK_CK_PDN_MASK(led->id))
  192. return 0;
  193. ret = regmap_read(regmap, regs->isink_en_ctrl, &status);
  194. if (ret < 0)
  195. return ret;
  196. if (!(status & ISINK_CH_EN(led->id)))
  197. return 0;
  198. ret = regmap_read(regmap, ISINK_CON(regs->isink_con[2], led->id), &status);
  199. if (ret < 0)
  200. return ret;
  201. return ((status & ISINK_CH_STEP_MASK)
  202. >> ISINK_CH_STEP_SHIFT) + 1;
  203. }
  204. static int mt6323_led_hw_on(struct led_classdev *cdev,
  205. enum led_brightness brightness)
  206. {
  207. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  208. struct mt6323_leds *leds = led->parent;
  209. const struct mt6323_regs *regs = leds->pdata->regs;
  210. struct regmap *regmap = leds->hw->regmap;
  211. unsigned int status;
  212. int ret;
  213. /*
  214. * Setup required clock source, enable the corresponding
  215. * clock and channel and let work with continuous blink as
  216. * the default.
  217. */
  218. ret = regmap_update_bits(regmap, regs->top_ckcon[1],
  219. RG_ISINK_CK_SEL_MASK(led->id), 0);
  220. if (ret < 0)
  221. return ret;
  222. status = RG_ISINK_CK_PDN(led->id);
  223. ret = regmap_update_bits(regmap, regs->top_ckpdn[2],
  224. RG_ISINK_CK_PDN_MASK(led->id),
  225. ~status);
  226. if (ret < 0)
  227. return ret;
  228. usleep_range(100, 300);
  229. ret = regmap_update_bits(regmap, regs->isink_en_ctrl,
  230. ISINK_CH_EN_MASK(led->id),
  231. ISINK_CH_EN(led->id));
  232. if (ret < 0)
  233. return ret;
  234. ret = mt6323_led_hw_brightness(cdev, brightness);
  235. if (ret < 0)
  236. return ret;
  237. ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[0], led->id),
  238. ISINK_DIM_DUTY_MASK,
  239. ISINK_DIM_DUTY(31));
  240. if (ret < 0)
  241. return ret;
  242. ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[1], led->id),
  243. ISINK_DIM_FSEL_MASK,
  244. ISINK_DIM_FSEL(1000));
  245. if (ret < 0)
  246. return ret;
  247. return 0;
  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. const struct mt6323_regs *regs = leds->pdata->regs;
  256. const struct mt6323_hwspec *spec = leds->pdata->spec;
  257. struct regmap *regmap = leds->hw->regmap;
  258. unsigned long period;
  259. u8 duty_hw;
  260. int ret;
  261. /*
  262. * LED subsystem requires a default user
  263. * friendly blink pattern for the LED so using
  264. * 1Hz duty cycle 50% here if without specific
  265. * value delay_on and delay off being assigned.
  266. */
  267. if (!*delay_on && !*delay_off) {
  268. *delay_on = 500;
  269. *delay_off = 500;
  270. }
  271. /*
  272. * Units are in ms, if over the hardware able
  273. * to support, fallback into software blink
  274. */
  275. period = *delay_on + *delay_off;
  276. if (period > spec->max_period)
  277. return -EINVAL;
  278. /*
  279. * Calculate duty_hw based on the percentage of period during
  280. * which the led is ON.
  281. */
  282. duty_hw = DIV_ROUND_CLOSEST(*delay_on * 100000ul, period * spec->unit_duty);
  283. /* hardware doesn't support zero duty cycle. */
  284. if (!duty_hw)
  285. return -EINVAL;
  286. mutex_lock(&leds->lock);
  287. /*
  288. * Set max_brightness as the software blink behavior
  289. * when no blink brightness.
  290. */
  291. if (!led->current_brightness) {
  292. ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
  293. if (ret < 0)
  294. goto out;
  295. led->current_brightness = cdev->max_brightness;
  296. }
  297. ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[0], led->id),
  298. ISINK_DIM_DUTY_MASK,
  299. ISINK_DIM_DUTY(duty_hw - 1));
  300. if (ret < 0)
  301. goto out;
  302. ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[1], led->id),
  303. ISINK_DIM_FSEL_MASK,
  304. ISINK_DIM_FSEL(period - 1));
  305. out:
  306. mutex_unlock(&leds->lock);
  307. return ret;
  308. }
  309. static int mt6323_led_set_brightness(struct led_classdev *cdev,
  310. enum led_brightness brightness)
  311. {
  312. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  313. struct mt6323_leds *leds = led->parent;
  314. int ret;
  315. mutex_lock(&leds->lock);
  316. if (!led->current_brightness && brightness) {
  317. ret = mt6323_led_hw_on(cdev, brightness);
  318. if (ret < 0)
  319. goto out;
  320. } else if (brightness) {
  321. ret = mt6323_led_hw_brightness(cdev, brightness);
  322. if (ret < 0)
  323. goto out;
  324. } else {
  325. ret = mt6323_led_hw_off(cdev);
  326. if (ret < 0)
  327. goto out;
  328. }
  329. led->current_brightness = brightness;
  330. out:
  331. mutex_unlock(&leds->lock);
  332. return ret;
  333. }
  334. static int mtk_wled_hw_on(struct led_classdev *cdev)
  335. {
  336. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  337. struct mt6323_leds *leds = led->parent;
  338. const struct mt6323_regs *regs = leds->pdata->regs;
  339. struct regmap *regmap = leds->hw->regmap;
  340. int ret;
  341. ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_32K_CK_PDN);
  342. if (ret)
  343. return ret;
  344. ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_6M_CK_PDN);
  345. if (ret)
  346. return ret;
  347. ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_1M_CK_PDN);
  348. if (ret)
  349. return ret;
  350. usleep_range(5000, 6000);
  351. /* Enable WLED channel pair */
  352. ret = regmap_set_bits(regmap, regs->iwled_en_ctrl, BIT(led->id));
  353. if (ret)
  354. return ret;
  355. ret = regmap_set_bits(regmap, regs->iwled_en_ctrl, BIT(led->id + 1));
  356. if (ret)
  357. return ret;
  358. return 0;
  359. }
  360. static int mtk_wled_hw_off(struct led_classdev *cdev)
  361. {
  362. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  363. struct mt6323_leds *leds = led->parent;
  364. const struct mt6323_regs *regs = leds->pdata->regs;
  365. struct regmap *regmap = leds->hw->regmap;
  366. int ret;
  367. ret = regmap_clear_bits(regmap, regs->iwled_en_ctrl, BIT(led->id + 1));
  368. if (ret)
  369. return ret;
  370. ret = regmap_clear_bits(regmap, regs->iwled_en_ctrl, BIT(led->id));
  371. if (ret)
  372. return ret;
  373. ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_32K_CK_PDN);
  374. if (ret)
  375. return ret;
  376. ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_6M_CK_PDN);
  377. if (ret)
  378. return ret;
  379. ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_1M_CK_PDN);
  380. if (ret)
  381. return ret;
  382. return 0;
  383. }
  384. static enum led_brightness mt6323_get_wled_brightness(struct led_classdev *cdev)
  385. {
  386. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  387. struct mt6323_leds *leds = led->parent;
  388. const struct mt6323_regs *regs = leds->pdata->regs;
  389. struct regmap *regmap = leds->hw->regmap;
  390. unsigned int status;
  391. int ret;
  392. ret = regmap_read(regmap, regs->iwled_en_ctrl, &status);
  393. if (ret)
  394. return 0;
  395. /* Always two channels per WLED */
  396. status &= BIT(led->id) | BIT(led->id + 1);
  397. return status ? led->current_brightness : 0;
  398. }
  399. static int mt6323_wled_set_brightness(struct led_classdev *cdev,
  400. enum led_brightness brightness)
  401. {
  402. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  403. struct mt6323_leds *leds = led->parent;
  404. int ret = 0;
  405. mutex_lock(&leds->lock);
  406. if (brightness) {
  407. if (!led->current_brightness)
  408. ret = mtk_wled_hw_on(cdev);
  409. if (ret)
  410. goto out;
  411. } else {
  412. ret = mtk_wled_hw_off(cdev);
  413. if (ret)
  414. goto out;
  415. }
  416. led->current_brightness = brightness;
  417. out:
  418. mutex_unlock(&leds->lock);
  419. return ret;
  420. }
  421. static int mt6323_led_set_dt_default(struct led_classdev *cdev,
  422. struct device_node *np)
  423. {
  424. struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
  425. enum led_default_state state;
  426. int ret = 0;
  427. state = led_init_default_state_get(of_fwnode_handle(np));
  428. switch (state) {
  429. case LEDS_DEFSTATE_ON:
  430. ret = mt6323_led_set_brightness(cdev, cdev->max_brightness);
  431. break;
  432. case LEDS_DEFSTATE_KEEP:
  433. ret = mt6323_get_led_hw_brightness(cdev);
  434. if (ret < 0)
  435. return ret;
  436. led->current_brightness = ret;
  437. ret = 0;
  438. break;
  439. default:
  440. ret = mt6323_led_set_brightness(cdev, LED_OFF);
  441. }
  442. return ret;
  443. }
  444. static int mt6323_led_probe(struct platform_device *pdev)
  445. {
  446. struct device *dev = &pdev->dev;
  447. struct device_node *np = dev_of_node(dev);
  448. struct mt6397_chip *hw = dev_get_drvdata(dev->parent);
  449. struct mt6323_leds *leds;
  450. struct mt6323_led *led;
  451. const struct mt6323_regs *regs;
  452. const struct mt6323_hwspec *spec;
  453. int ret;
  454. unsigned int status;
  455. u32 reg;
  456. u8 max_leds;
  457. leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
  458. if (!leds)
  459. return -ENOMEM;
  460. platform_set_drvdata(pdev, leds);
  461. leds->dev = dev;
  462. leds->pdata = device_get_match_data(dev);
  463. regs = leds->pdata->regs;
  464. spec = leds->pdata->spec;
  465. max_leds = spec->max_leds + spec->max_wleds;
  466. /*
  467. * leds->hw points to the underlying bus for the register
  468. * controlled.
  469. */
  470. leds->hw = hw;
  471. mutex_init(&leds->lock);
  472. status = RG_DRV_32K_CK_PDN;
  473. ret = regmap_update_bits(leds->hw->regmap, regs->top_ckpdn[0],
  474. RG_DRV_32K_CK_PDN_MASK, ~status);
  475. if (ret < 0) {
  476. dev_err(leds->dev,
  477. "Failed to update TOP_CKPDN0 Register\n");
  478. return ret;
  479. }
  480. for_each_available_child_of_node_scoped(np, child) {
  481. struct led_init_data init_data = {};
  482. bool is_wled;
  483. ret = of_property_read_u32(child, "reg", &reg);
  484. if (ret) {
  485. dev_err(dev, "Failed to read led 'reg' property\n");
  486. return ret;
  487. }
  488. if (reg >= max_leds || reg >= MAX_SUPPORTED_LEDS ||
  489. leds->led[reg]) {
  490. dev_err(dev, "Invalid led reg %u\n", reg);
  491. return -EINVAL;
  492. }
  493. led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
  494. if (!led)
  495. return -ENOMEM;
  496. is_wled = of_property_read_bool(child, "mediatek,is-wled");
  497. leds->led[reg] = led;
  498. leds->led[reg]->id = reg;
  499. leds->led[reg]->cdev.max_brightness = spec->max_brightness;
  500. if (is_wled) {
  501. leds->led[reg]->cdev.brightness_set_blocking =
  502. mt6323_wled_set_brightness;
  503. leds->led[reg]->cdev.brightness_get =
  504. mt6323_get_wled_brightness;
  505. } else {
  506. leds->led[reg]->cdev.brightness_set_blocking =
  507. mt6323_led_set_brightness;
  508. leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
  509. leds->led[reg]->cdev.brightness_get =
  510. mt6323_get_led_hw_brightness;
  511. }
  512. leds->led[reg]->parent = leds;
  513. ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
  514. if (ret < 0) {
  515. dev_err(leds->dev,
  516. "Failed to LED set default from devicetree\n");
  517. return ret;
  518. }
  519. init_data.fwnode = of_fwnode_handle(child);
  520. ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev,
  521. &init_data);
  522. if (ret) {
  523. dev_err(dev, "Failed to register LED: %d\n", ret);
  524. return ret;
  525. }
  526. }
  527. return 0;
  528. }
  529. static void mt6323_led_remove(struct platform_device *pdev)
  530. {
  531. struct mt6323_leds *leds = platform_get_drvdata(pdev);
  532. const struct mt6323_regs *regs = leds->pdata->regs;
  533. int i;
  534. /* Turn the LEDs off on driver removal. */
  535. for (i = 0 ; leds->led[i] ; i++)
  536. mt6323_led_hw_off(&leds->led[i]->cdev);
  537. regmap_update_bits(leds->hw->regmap, regs->top_ckpdn[0],
  538. RG_DRV_32K_CK_PDN_MASK,
  539. RG_DRV_32K_CK_PDN);
  540. mutex_destroy(&leds->lock);
  541. }
  542. static const struct mt6323_regs mt6323_registers = {
  543. .top_ckpdn = (const u16[]){ 0x102, 0x106, 0x10e },
  544. .num_top_ckpdn = 3,
  545. .top_ckcon = (const u16[]){ 0x120, 0x126 },
  546. .num_top_ckcon = 2,
  547. .isink_con = (const u16[]){ 0x330, 0x332, 0x334 },
  548. .num_isink_con = 3,
  549. .isink_max_regs = 4, /* ISINK[0..3] */
  550. .isink_en_ctrl = 0x356,
  551. };
  552. static const struct mt6323_regs mt6331_registers = {
  553. .top_ckpdn = (const u16[]){ 0x138, 0x13e, 0x144 },
  554. .num_top_ckpdn = 3,
  555. .top_ckcon = (const u16[]){ 0x14c, 0x14a },
  556. .num_top_ckcon = 2,
  557. .isink_con = (const u16[]){ 0x40c, 0x40e, 0x410, 0x412, 0x414 },
  558. .num_isink_con = 5,
  559. .isink_max_regs = 4, /* ISINK[0..3] */
  560. .isink_en_ctrl = 0x43a,
  561. };
  562. static const struct mt6323_regs mt6332_registers = {
  563. .top_ckpdn = (const u16[]){ 0x8094, 0x809a, 0x80a0 },
  564. .num_top_ckpdn = 3,
  565. .top_ckcon = (const u16[]){ 0x80a6, 0x80ac },
  566. .num_top_ckcon = 2,
  567. .isink_con = (const u16[]){ 0x8cd4 },
  568. .num_isink_con = 1,
  569. .isink_max_regs = 12, /* IWLED[0..2, 3..9] */
  570. .iwled_en_ctrl = 0x8cda,
  571. };
  572. static const struct mt6323_hwspec mt6323_spec = {
  573. .max_period = 10000,
  574. .max_leds = 4,
  575. .max_brightness = 6,
  576. .unit_duty = 3125,
  577. };
  578. static const struct mt6323_hwspec mt6332_spec = {
  579. /* There are no LEDs in MT6332. Only WLEDs are present. */
  580. .max_leds = 0,
  581. .max_wleds = 1,
  582. .max_brightness = 1024,
  583. };
  584. static const struct mt6323_data mt6323_pdata = {
  585. .regs = &mt6323_registers,
  586. .spec = &mt6323_spec,
  587. };
  588. static const struct mt6323_data mt6331_pdata = {
  589. .regs = &mt6331_registers,
  590. .spec = &mt6323_spec,
  591. };
  592. static const struct mt6323_data mt6332_pdata = {
  593. .regs = &mt6332_registers,
  594. .spec = &mt6332_spec,
  595. };
  596. static const struct of_device_id mt6323_led_dt_match[] = {
  597. { .compatible = "mediatek,mt6323-led", .data = &mt6323_pdata},
  598. { .compatible = "mediatek,mt6331-led", .data = &mt6331_pdata },
  599. { .compatible = "mediatek,mt6332-led", .data = &mt6332_pdata },
  600. {},
  601. };
  602. MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
  603. static struct platform_driver mt6323_led_driver = {
  604. .probe = mt6323_led_probe,
  605. .remove_new = mt6323_led_remove,
  606. .driver = {
  607. .name = "mt6323-led",
  608. .of_match_table = mt6323_led_dt_match,
  609. },
  610. };
  611. module_platform_driver(mt6323_led_driver);
  612. MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
  613. MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
  614. MODULE_LICENSE("GPL");