backlight-pwm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #define DBG_TAG "backlight.pwm"
  14. #define DBG_LVL DBG_INFO
  15. #include <rtdbg.h>
  16. struct pwm_backlight
  17. {
  18. struct rt_backlight_device parent;
  19. rt_uint32_t lth_brightness;
  20. rt_uint32_t *levels;
  21. rt_base_t enable_pin;
  22. rt_uint8_t active_val;
  23. rt_uint32_t scale;
  24. rt_uint32_t post_pwm_on_delay;
  25. rt_uint32_t pwm_off_delay;
  26. rt_uint32_t dft_brightness;
  27. rt_uint32_t max_brightness;
  28. rt_bool_t enabled;
  29. struct rt_device_pwm *pwm_dev;
  30. struct rt_pwm_configuration pwm_conf;
  31. struct rt_regulator *power_supply;
  32. };
  33. #define raw_to_pwm_backlight(raw) rt_container_of(raw, struct pwm_backlight, parent)
  34. static void pwm_backlight_power_on(struct pwm_backlight *pbl)
  35. {
  36. rt_err_t err;
  37. if (pbl->enabled)
  38. {
  39. return;
  40. }
  41. if (pbl->power_supply)
  42. {
  43. if ((err = rt_regulator_enable(pbl->power_supply)))
  44. {
  45. LOG_E("Enable power supply error = %s", rt_strerror(err));
  46. }
  47. }
  48. if (pbl->post_pwm_on_delay)
  49. {
  50. rt_thread_mdelay(pbl->post_pwm_on_delay);
  51. }
  52. if (pbl->enable_pin >= 0)
  53. {
  54. rt_pin_write(pbl->enable_pin, pbl->active_val);
  55. }
  56. pbl->enabled = RT_TRUE;
  57. }
  58. static void pwm_backlight_power_off(struct pwm_backlight *pbl)
  59. {
  60. if (!pbl->enabled)
  61. {
  62. return;
  63. }
  64. if (pbl->enable_pin >= 0)
  65. {
  66. rt_pin_write(pbl->enable_pin, !pbl->active_val);
  67. }
  68. if (pbl->pwm_off_delay)
  69. {
  70. rt_thread_mdelay(pbl->pwm_off_delay);
  71. }
  72. if (pbl->power_supply)
  73. {
  74. rt_regulator_disable(pbl->power_supply);
  75. }
  76. pbl->enabled = RT_FALSE;
  77. }
  78. static int compute_duty_cycle(struct pwm_backlight *pbl, rt_uint32_t brightness,
  79. rt_uint32_t period)
  80. {
  81. rt_uint64_t duty_cycle;
  82. rt_uint32_t lth = pbl->lth_brightness;
  83. if (pbl->levels)
  84. {
  85. duty_cycle = pbl->levels[brightness];
  86. }
  87. else
  88. {
  89. duty_cycle = brightness;
  90. }
  91. duty_cycle *= period - lth;
  92. rt_do_div(duty_cycle, pbl->scale);
  93. return duty_cycle + lth;
  94. }
  95. static rt_err_t pwm_backlight_update_status(struct rt_backlight_device *bl)
  96. {
  97. rt_uint32_t brightness, duty_cycle;
  98. struct rt_pwm_configuration pwm_conf = {};
  99. struct pwm_backlight *pbl = raw_to_pwm_backlight(bl);
  100. rt_pwm_get(pbl->pwm_dev, &pwm_conf);
  101. brightness = rt_backlight_power_brightness(bl);
  102. if (brightness > 0)
  103. {
  104. duty_cycle = compute_duty_cycle(pbl, brightness, pwm_conf.period);
  105. pwm_conf.pulse = duty_cycle;
  106. rt_pwm_set(pbl->pwm_dev, pwm_conf.channel, pwm_conf.period, pwm_conf.pulse);
  107. rt_pwm_enable(pbl->pwm_dev, pbl->pwm_conf.channel);
  108. pwm_backlight_power_on(pbl);
  109. }
  110. else
  111. {
  112. pwm_backlight_power_off(pbl);
  113. pwm_conf.pulse = 0;
  114. rt_pwm_set(pbl->pwm_dev, pwm_conf.channel, pwm_conf.period, pwm_conf.pulse);
  115. if (pbl->power_supply || pbl->enable_pin >= 0)
  116. {
  117. rt_pwm_disable(pbl->pwm_dev, pbl->pwm_conf.channel);
  118. }
  119. }
  120. return RT_EOK;
  121. }
  122. static struct rt_backlight_ops pwm_backlight_ops =
  123. {
  124. .update_status = pwm_backlight_update_status,
  125. };
  126. #define PWM_LUMINANCE_SHIFT 16
  127. #define PWM_LUMINANCE_SCALE (1 << PWM_LUMINANCE_SHIFT) /* luminance scale */
  128. rt_inline int period_fls(int period)
  129. {
  130. return period ? sizeof(period) * 8 - __rt_clz(period) : 0;
  131. }
  132. static rt_err_t pwm_backlight_brightness_default(struct pwm_backlight *pbl,
  133. rt_uint32_t period)
  134. {
  135. rt_uint32_t lightness;
  136. rt_uint64_t res, cie1931;
  137. pbl->max_brightness = rt_min((int)RT_DIV_ROUND_UP(period, period_fls(period)), 4096);
  138. pbl->levels = rt_calloc(pbl->max_brightness, sizeof(*pbl->levels));
  139. if (!pbl->levels)
  140. {
  141. return -RT_ENOMEM;
  142. }
  143. /* Fill the table using the cie1931 algorithm */
  144. for (int i = 0; i < pbl->max_brightness; ++i)
  145. {
  146. lightness = (i * PWM_LUMINANCE_SCALE) / pbl->max_brightness * 100;
  147. if (lightness <= (8 * PWM_LUMINANCE_SCALE))
  148. {
  149. cie1931 = RT_DIV_ROUND_CLOSEST(lightness * 10, 9033);
  150. }
  151. else
  152. {
  153. cie1931 = (lightness + (16 * PWM_LUMINANCE_SCALE)) / 116;
  154. cie1931 *= cie1931 * cie1931;
  155. cie1931 += 1ULL << (2 * PWM_LUMINANCE_SHIFT - 1);
  156. cie1931 >>= 2 * PWM_LUMINANCE_SHIFT;
  157. }
  158. res = cie1931 * period;
  159. res = RT_DIV_ROUND_CLOSEST_ULL(res, PWM_LUMINANCE_SCALE);
  160. if (res > RT_UINT32_MAX)
  161. {
  162. return -RT_EINVAL;
  163. }
  164. pbl->levels[i] = (rt_uint32_t)res;
  165. }
  166. pbl->dft_brightness = pbl->max_brightness / 2;
  167. pbl->max_brightness--;
  168. return 0;
  169. }
  170. static rt_err_t pwm_backlight_ofw_parse(struct pwm_backlight *pbl,
  171. struct rt_ofw_node *np)
  172. {
  173. rt_err_t err;
  174. rt_ssize_t length;
  175. rt_uint32_t *table, value;
  176. rt_uint32_t num_levels, num_steps = 0;
  177. struct rt_ofw_prop *prop;
  178. /*
  179. * These values are optional and set as 0 by default, the out values
  180. * are modified only if a valid u32 value can be decoded.
  181. */
  182. rt_ofw_prop_read_u32(np, "post-pwm-on-delay-ms", &pbl->post_pwm_on_delay);
  183. rt_ofw_prop_read_u32(np, "pwm-off-delay-ms", &pbl->pwm_off_delay);
  184. /*
  185. * Determine the number of brightness levels, if this property is not
  186. * set a default table of brightness levels will be used.
  187. */
  188. prop = rt_ofw_get_prop(np, "brightness-levels", &length);
  189. if (!prop)
  190. {
  191. return RT_EOK;
  192. }
  193. num_levels = length / sizeof(rt_uint32_t);
  194. if (!num_levels)
  195. {
  196. return RT_EOK;
  197. }
  198. pbl->levels = rt_calloc(num_levels, sizeof(*pbl->levels));
  199. if (!pbl->levels)
  200. {
  201. return -RT_ENOMEM;
  202. }
  203. if ((err = rt_ofw_prop_read_u32_array_index(np, "brightness-levels",
  204. 0, num_levels, pbl->levels)) < 0)
  205. {
  206. goto _fail;
  207. }
  208. if ((err = rt_ofw_prop_read_u32(np, "default-brightness-level", &value)))
  209. {
  210. goto _fail;
  211. }
  212. pbl->dft_brightness = value;
  213. /*
  214. * This property is optional, if is set enables linear
  215. * interpolation between each of the values of brightness levels
  216. * and creates a new pre-computed table.
  217. */
  218. rt_ofw_prop_read_u32(np, "num-interpolated-steps", &num_steps);
  219. /*
  220. * Make sure that there is at least two entries in the
  221. * brightness-levels table, otherwise we can't interpolate
  222. * between two points.
  223. */
  224. if (num_steps)
  225. {
  226. rt_int64_t dy;
  227. rt_uint32_t x1, x2, x, dx, y1, y2;
  228. rt_uint32_t num_input_levels = num_levels;
  229. if (num_input_levels < 2)
  230. {
  231. LOG_E("Can't interpolate");
  232. err = -RT_EINVAL;
  233. goto _fail;
  234. }
  235. num_levels = (num_input_levels - 1) * num_steps + 1;
  236. table = rt_calloc(num_levels, sizeof(*table));
  237. if (!table)
  238. {
  239. err = -RT_ENOMEM;
  240. goto _fail;
  241. }
  242. /*
  243. * Fill the interpolated table[x] = y
  244. * by draw lines between each (x1, y1) to (x2, y2).
  245. */
  246. dx = num_steps;
  247. for (int i = 0; i < num_input_levels - 1; ++i)
  248. {
  249. x1 = i * dx;
  250. x2 = x1 + dx;
  251. y1 = pbl->levels[i];
  252. y2 = pbl->levels[i + 1];
  253. dy = (rt_int64_t)y2 - y1;
  254. for (x = x1; x < x2; ++x)
  255. {
  256. table[x] = y1 + (rt_int64_t)(dy * (x - x1)) / (rt_int64_t)dx;
  257. }
  258. }
  259. /* Fill in the last point, since no line starts here. */
  260. table[x2] = y2;
  261. rt_free(pbl->levels);
  262. pbl->levels = table;
  263. }
  264. pbl->max_brightness = num_levels - 1;
  265. return RT_EOK;
  266. _fail:
  267. rt_free(pbl->levels);
  268. return err;
  269. }
  270. static enum rt_backlight_power pwm_backlight_initial_power_state(
  271. struct pwm_backlight *pbl, struct rt_device *dev)
  272. {
  273. rt_bool_t active = RT_TRUE;
  274. if (pbl->enable_pin >= 0 && rt_pin_read(pbl->enable_pin) != pbl->active_val)
  275. {
  276. active = RT_FALSE;
  277. }
  278. if (pbl->power_supply && !rt_regulator_is_enabled(pbl->power_supply))
  279. {
  280. active = RT_FALSE;
  281. }
  282. /* Synchronize the enable_gpio with the observed state of the hardware. */
  283. rt_pin_mode(pbl->enable_pin, PIN_MODE_OUTPUT);
  284. rt_pin_write(pbl->enable_pin, active ? pbl->active_val : !pbl->active_val);
  285. /* Not booted with device tree or no phandle link to the node */
  286. if (!dev->ofw_node || rt_dm_dev_prop_read_bool(dev, "phandle"))
  287. {
  288. return RT_BACKLIGHT_POWER_UNBLANK;
  289. }
  290. return active ? RT_BACKLIGHT_POWER_UNBLANK: RT_BACKLIGHT_POWER_POWERDOWN;
  291. }
  292. static rt_err_t pwm_backlight_probe(struct rt_platform_device *pdev)
  293. {
  294. rt_err_t err;
  295. enum rt_backlight_power power;
  296. struct rt_ofw_cell_args pwm_args;
  297. struct rt_device *dev = &pdev->parent;
  298. struct rt_ofw_node *np = dev->ofw_node, *pwm_np;
  299. struct pwm_backlight *pbl = rt_calloc(1, sizeof(*pbl));
  300. if (!pbl)
  301. {
  302. return -RT_ENOMEM;
  303. }
  304. if ((err = pwm_backlight_ofw_parse(pbl, dev->ofw_node)))
  305. {
  306. goto _fail;
  307. }
  308. pbl->enable_pin = rt_pin_get_named_pin(dev, "enable", 0, RT_NULL, &pbl->active_val);
  309. if (pbl->enable_pin < 0 && pbl->enable_pin != PIN_NONE)
  310. {
  311. err = pbl->enable_pin;
  312. goto _fail;
  313. }
  314. pbl->power_supply = rt_regulator_get(dev, "power");
  315. if (rt_is_err(pbl->power_supply))
  316. {
  317. err = rt_ptr_err(pbl->power_supply);
  318. goto _fail;
  319. }
  320. if (rt_ofw_parse_phandle_cells(np, "pwms", "#pwm-cells", 0, &pwm_args))
  321. {
  322. err = -RT_EINVAL;
  323. goto _fail;
  324. }
  325. pwm_np = pwm_args.data;
  326. if (!rt_ofw_data(pwm_np))
  327. {
  328. rt_platform_ofw_request(pwm_np);
  329. }
  330. pbl->pwm_dev = rt_ofw_data(pwm_np);
  331. rt_ofw_node_put(pwm_np);
  332. if (!pbl->pwm_dev)
  333. {
  334. err = -RT_EINVAL;
  335. goto _fail;
  336. }
  337. pbl->pwm_conf.channel = pwm_args.args[0];
  338. pbl->pwm_conf.period = pwm_args.args[1];
  339. rt_pwm_set_period(pbl->pwm_dev, pbl->pwm_conf.channel, pbl->pwm_conf.period);
  340. if (pbl->levels)
  341. {
  342. for (int i = 0; i <= pbl->max_brightness; ++i)
  343. {
  344. if (pbl->levels[i] > pbl->scale)
  345. {
  346. pbl->scale = pbl->levels[i];
  347. }
  348. }
  349. }
  350. else if (!pbl->max_brightness)
  351. {
  352. struct rt_pwm_configuration pwm_conf = {};
  353. rt_pwm_get(pbl->pwm_dev, &pwm_conf);
  354. /* Make levels */
  355. if ((err = pwm_backlight_brightness_default(pbl, pbl->pwm_conf.period)))
  356. {
  357. LOG_E("Setup default brightness table error = %s", rt_strerror(err));
  358. goto _fail;
  359. }
  360. for (int i = 0; i <= pbl->max_brightness; ++i)
  361. {
  362. if (pbl->levels[i] > pbl->scale)
  363. {
  364. pbl->scale = pbl->levels[i];
  365. }
  366. }
  367. }
  368. else
  369. {
  370. pbl->scale = pbl->max_brightness;
  371. }
  372. pbl->parent.props.max_brightness = pbl->max_brightness;
  373. pbl->parent.ops = &pwm_backlight_ops;
  374. if ((err = rt_backlight_register(&pbl->parent)))
  375. {
  376. goto _fail;
  377. }
  378. power = pwm_backlight_initial_power_state(pbl, dev);
  379. rt_backlight_set_power(&pbl->parent, power);
  380. if (pbl->dft_brightness > pbl->max_brightness)
  381. {
  382. LOG_W("Invalid default brightness level: %u, using %u",
  383. pbl->dft_brightness, pbl->max_brightness);
  384. pbl->dft_brightness = pbl->max_brightness;
  385. }
  386. rt_backlight_set_brightness(&pbl->parent, pbl->dft_brightness);
  387. return RT_EOK;
  388. _fail:
  389. if (!rt_is_err_or_null(pbl->power_supply))
  390. {
  391. rt_regulator_put(pbl->power_supply);
  392. }
  393. if (pbl->levels)
  394. {
  395. rt_free(pbl->levels);
  396. }
  397. rt_free(pbl);
  398. return err;
  399. }
  400. static rt_err_t pwm_backlight_remove(struct rt_platform_device *pdev)
  401. {
  402. struct rt_pwm_configuration pwm_conf = {};
  403. struct pwm_backlight *pbl = pdev->parent.user_data;
  404. rt_backlight_unregister(&pbl->parent);
  405. pwm_backlight_power_off(pbl);
  406. rt_regulator_put(pbl->power_supply);
  407. rt_pwm_get(pbl->pwm_dev, &pwm_conf);
  408. pwm_conf.pulse = 0;
  409. rt_pwm_set(pbl->pwm_dev, pwm_conf.channel, pwm_conf.period, pwm_conf.pulse);
  410. rt_pwm_disable(pbl->pwm_dev, pbl->pwm_conf.channel);
  411. if (pbl->levels)
  412. {
  413. rt_free(pbl->levels);
  414. }
  415. rt_free(pbl);
  416. return RT_EOK;
  417. }
  418. static rt_err_t pwm_backlight_shutdown(struct rt_platform_device *pdev)
  419. {
  420. struct rt_pwm_configuration pwm_conf = {};
  421. struct pwm_backlight *pbl = pdev->parent.user_data;
  422. pwm_backlight_power_off(pbl);
  423. rt_pwm_get(pbl->pwm_dev, &pwm_conf);
  424. pwm_conf.pulse = 0;
  425. rt_pwm_set(pbl->pwm_dev, pwm_conf.channel, pwm_conf.period, pwm_conf.pulse);
  426. rt_pwm_disable(pbl->pwm_dev, pbl->pwm_conf.channel);
  427. return RT_EOK;
  428. }
  429. static const struct rt_ofw_node_id pwm_backlight_ofw_ids[] =
  430. {
  431. { .compatible = "pwm-backlight" },
  432. { /* sentinel */ }
  433. };
  434. static struct rt_platform_driver pwm_backlight_driver =
  435. {
  436. .name = "pwm-backlight",
  437. .ids = pwm_backlight_ofw_ids,
  438. .probe = pwm_backlight_probe,
  439. .remove = pwm_backlight_remove,
  440. .shutdown = pwm_backlight_shutdown,
  441. };
  442. RT_PLATFORM_DRIVER_EXPORT(pwm_backlight_driver);