dell-uart-backlight.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Dell AIO Serial Backlight Driver
  4. *
  5. * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
  6. * Copyright (C) 2017 AceLan Kao <acelan.kao@canonical.com>
  7. */
  8. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9. #include <linux/acpi.h>
  10. #include <linux/backlight.h>
  11. #include <linux/delay.h>
  12. #include <linux/device.h>
  13. #include <linux/err.h>
  14. #include <linux/module.h>
  15. #include <linux/mutex.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/serdev.h>
  18. #include <linux/string.h>
  19. #include <linux/types.h>
  20. #include <linux/wait.h>
  21. #include <acpi/video.h>
  22. #include "../serdev_helpers.h"
  23. /* The backlight controller must respond within 1 second */
  24. #define DELL_BL_TIMEOUT msecs_to_jiffies(1000)
  25. #define DELL_BL_MAX_BRIGHTNESS 100
  26. /* Defines for the commands send to the controller */
  27. /* 1st byte Start Of Frame 3 MSB bits: cmd-len + 01010 SOF marker */
  28. #define DELL_SOF(len) (((len) << 5) | 0x0a)
  29. #define GET_CMD_LEN 3
  30. #define SET_CMD_LEN 4
  31. /* 2nd byte command */
  32. #define CMD_GET_VERSION 0x06
  33. #define CMD_SET_BRIGHTNESS 0x0b
  34. #define CMD_GET_BRIGHTNESS 0x0c
  35. #define CMD_SET_BL_POWER 0x0e
  36. /* Indexes and other defines for response received from the controller */
  37. #define RESP_LEN 0
  38. #define RESP_CMD 1 /* Echo of CMD byte from command */
  39. #define RESP_DATA 2 /* Start of received data */
  40. #define SET_RESP_LEN 3
  41. #define GET_RESP_LEN 4
  42. #define MIN_RESP_LEN 3
  43. #define MAX_RESP_LEN 80
  44. struct dell_uart_backlight {
  45. struct mutex mutex;
  46. wait_queue_head_t wait_queue;
  47. struct device *dev;
  48. struct backlight_device *bl;
  49. u8 *resp;
  50. u8 resp_idx;
  51. u8 resp_len;
  52. u8 resp_max_len;
  53. u8 pending_cmd;
  54. int status;
  55. int power;
  56. };
  57. /* Checksum: SUM(Length and Cmd and Data) xor 0xFF */
  58. static u8 dell_uart_checksum(u8 *buf, int len)
  59. {
  60. u8 val = 0;
  61. while (len-- > 0)
  62. val += buf[len];
  63. return val ^ 0xff;
  64. }
  65. static int dell_uart_bl_command(struct dell_uart_backlight *dell_bl,
  66. const u8 *cmd, int cmd_len,
  67. u8 *resp, int resp_max_len)
  68. {
  69. int ret;
  70. ret = mutex_lock_killable(&dell_bl->mutex);
  71. if (ret)
  72. return ret;
  73. dell_bl->status = -EBUSY;
  74. dell_bl->resp = resp;
  75. dell_bl->resp_idx = 0;
  76. dell_bl->resp_len = -1; /* Invalid / unset */
  77. dell_bl->resp_max_len = resp_max_len;
  78. dell_bl->pending_cmd = cmd[1];
  79. /* The TTY buffer should be big enough to take the entire cmd in one go */
  80. ret = serdev_device_write_buf(to_serdev_device(dell_bl->dev), cmd, cmd_len);
  81. if (ret != cmd_len) {
  82. dev_err(dell_bl->dev, "Error writing command: %d\n", ret);
  83. dell_bl->status = (ret < 0) ? ret : -EIO;
  84. goto out;
  85. }
  86. ret = wait_event_timeout(dell_bl->wait_queue, dell_bl->status != -EBUSY,
  87. DELL_BL_TIMEOUT);
  88. if (ret == 0) {
  89. dev_err(dell_bl->dev, "Timed out waiting for response.\n");
  90. /* Clear busy status to discard bytes received after this */
  91. dell_bl->status = -ETIMEDOUT;
  92. }
  93. out:
  94. mutex_unlock(&dell_bl->mutex);
  95. return dell_bl->status;
  96. }
  97. static int dell_uart_set_brightness(struct dell_uart_backlight *dell_bl, int brightness)
  98. {
  99. u8 set_brightness[SET_CMD_LEN], resp[SET_RESP_LEN];
  100. set_brightness[0] = DELL_SOF(SET_CMD_LEN);
  101. set_brightness[1] = CMD_SET_BRIGHTNESS;
  102. set_brightness[2] = brightness;
  103. set_brightness[3] = dell_uart_checksum(set_brightness, 3);
  104. return dell_uart_bl_command(dell_bl, set_brightness, SET_CMD_LEN, resp, SET_RESP_LEN);
  105. }
  106. static int dell_uart_get_brightness(struct dell_uart_backlight *dell_bl)
  107. {
  108. struct device *dev = dell_bl->dev;
  109. u8 get_brightness[GET_CMD_LEN], resp[GET_RESP_LEN];
  110. int ret;
  111. get_brightness[0] = DELL_SOF(GET_CMD_LEN);
  112. get_brightness[1] = CMD_GET_BRIGHTNESS;
  113. get_brightness[2] = dell_uart_checksum(get_brightness, 2);
  114. ret = dell_uart_bl_command(dell_bl, get_brightness, GET_CMD_LEN, resp, GET_RESP_LEN);
  115. if (ret)
  116. return ret;
  117. if (resp[RESP_LEN] != GET_RESP_LEN) {
  118. dev_err(dev, "Unexpected get brightness response length: %d\n", resp[RESP_LEN]);
  119. return -EIO;
  120. }
  121. if (resp[RESP_DATA] > DELL_BL_MAX_BRIGHTNESS) {
  122. dev_err(dev, "Unexpected get brightness response: %d\n", resp[RESP_DATA]);
  123. return -EIO;
  124. }
  125. return resp[RESP_DATA];
  126. }
  127. static int dell_uart_set_bl_power(struct dell_uart_backlight *dell_bl, int power)
  128. {
  129. u8 set_power[SET_CMD_LEN], resp[SET_RESP_LEN];
  130. int ret;
  131. set_power[0] = DELL_SOF(SET_CMD_LEN);
  132. set_power[1] = CMD_SET_BL_POWER;
  133. set_power[2] = (power == BACKLIGHT_POWER_ON) ? 1 : 0;
  134. set_power[3] = dell_uart_checksum(set_power, 3);
  135. ret = dell_uart_bl_command(dell_bl, set_power, SET_CMD_LEN, resp, SET_RESP_LEN);
  136. if (ret)
  137. return ret;
  138. dell_bl->power = power;
  139. return 0;
  140. }
  141. /*
  142. * There is no command to get backlight power status,
  143. * so we set the backlight power to "on" while initializing,
  144. * and then track and report its status by power variable.
  145. */
  146. static int dell_uart_get_bl_power(struct dell_uart_backlight *dell_bl)
  147. {
  148. return dell_bl->power;
  149. }
  150. static int dell_uart_update_status(struct backlight_device *bd)
  151. {
  152. struct dell_uart_backlight *dell_bl = bl_get_data(bd);
  153. int ret;
  154. ret = dell_uart_set_brightness(dell_bl, bd->props.brightness);
  155. if (ret)
  156. return ret;
  157. if (bd->props.power != dell_uart_get_bl_power(dell_bl))
  158. return dell_uart_set_bl_power(dell_bl, bd->props.power);
  159. return 0;
  160. }
  161. static int dell_uart_get_brightness_op(struct backlight_device *bd)
  162. {
  163. return dell_uart_get_brightness(bl_get_data(bd));
  164. }
  165. static const struct backlight_ops dell_uart_backlight_ops = {
  166. .update_status = dell_uart_update_status,
  167. .get_brightness = dell_uart_get_brightness_op,
  168. };
  169. static size_t dell_uart_bl_receive(struct serdev_device *serdev, const u8 *data, size_t len)
  170. {
  171. struct dell_uart_backlight *dell_bl = serdev_device_get_drvdata(serdev);
  172. size_t i;
  173. u8 csum;
  174. dev_dbg(dell_bl->dev, "Recv: %*ph\n", (int)len, data);
  175. /* Throw away unexpected bytes / remainder of response after an error */
  176. if (dell_bl->status != -EBUSY) {
  177. dev_warn(dell_bl->dev, "Bytes received out of band, dropping them.\n");
  178. return len;
  179. }
  180. i = 0;
  181. while (i < len && dell_bl->resp_idx != dell_bl->resp_len) {
  182. dell_bl->resp[dell_bl->resp_idx] = data[i++];
  183. switch (dell_bl->resp_idx) {
  184. case RESP_LEN: /* Length byte */
  185. dell_bl->resp_len = dell_bl->resp[RESP_LEN];
  186. if (dell_bl->resp_len < MIN_RESP_LEN ||
  187. dell_bl->resp_len > dell_bl->resp_max_len) {
  188. dev_err(dell_bl->dev, "Response length %d out if range %d - %d\n",
  189. dell_bl->resp_len, MIN_RESP_LEN, dell_bl->resp_max_len);
  190. dell_bl->status = -EIO;
  191. goto wakeup;
  192. }
  193. break;
  194. case RESP_CMD: /* CMD byte */
  195. if (dell_bl->resp[RESP_CMD] != dell_bl->pending_cmd) {
  196. dev_err(dell_bl->dev, "Response cmd 0x%02x != pending 0x%02x\n",
  197. dell_bl->resp[RESP_CMD], dell_bl->pending_cmd);
  198. dell_bl->status = -EIO;
  199. goto wakeup;
  200. }
  201. break;
  202. }
  203. dell_bl->resp_idx++;
  204. }
  205. if (dell_bl->resp_idx != dell_bl->resp_len)
  206. return len; /* Response not complete yet */
  207. csum = dell_uart_checksum(dell_bl->resp, dell_bl->resp_len - 1);
  208. if (dell_bl->resp[dell_bl->resp_len - 1] == csum) {
  209. dell_bl->status = 0; /* Success */
  210. } else {
  211. dev_err(dell_bl->dev, "Checksum mismatch got 0x%02x expected 0x%02x\n",
  212. dell_bl->resp[dell_bl->resp_len - 1], csum);
  213. dell_bl->status = -EIO;
  214. }
  215. wakeup:
  216. wake_up(&dell_bl->wait_queue);
  217. return i;
  218. }
  219. static const struct serdev_device_ops dell_uart_bl_serdev_ops = {
  220. .receive_buf = dell_uart_bl_receive,
  221. .write_wakeup = serdev_device_write_wakeup,
  222. };
  223. static int dell_uart_bl_serdev_probe(struct serdev_device *serdev)
  224. {
  225. u8 get_version[GET_CMD_LEN], resp[MAX_RESP_LEN];
  226. struct backlight_properties props = {};
  227. struct dell_uart_backlight *dell_bl;
  228. struct device *dev = &serdev->dev;
  229. int ret;
  230. dell_bl = devm_kzalloc(dev, sizeof(*dell_bl), GFP_KERNEL);
  231. if (!dell_bl)
  232. return -ENOMEM;
  233. mutex_init(&dell_bl->mutex);
  234. init_waitqueue_head(&dell_bl->wait_queue);
  235. dell_bl->dev = dev;
  236. serdev_device_set_drvdata(serdev, dell_bl);
  237. serdev_device_set_client_ops(serdev, &dell_uart_bl_serdev_ops);
  238. ret = devm_serdev_device_open(dev, serdev);
  239. if (ret)
  240. return dev_err_probe(dev, ret, "opening UART device\n");
  241. /* 9600 bps, no flow control, these are the default but set them to be sure */
  242. serdev_device_set_baudrate(serdev, 9600);
  243. serdev_device_set_flow_control(serdev, false);
  244. get_version[0] = DELL_SOF(GET_CMD_LEN);
  245. get_version[1] = CMD_GET_VERSION;
  246. get_version[2] = dell_uart_checksum(get_version, 2);
  247. ret = dell_uart_bl_command(dell_bl, get_version, GET_CMD_LEN, resp, MAX_RESP_LEN);
  248. if (ret)
  249. return dev_err_probe(dev, ret, "getting firmware version\n");
  250. dev_dbg(dev, "Firmware version: %.*s\n", resp[RESP_LEN] - 3, resp + RESP_DATA);
  251. /* Initialize bl_power to a known value */
  252. ret = dell_uart_set_bl_power(dell_bl, BACKLIGHT_POWER_ON);
  253. if (ret)
  254. return ret;
  255. ret = dell_uart_get_brightness(dell_bl);
  256. if (ret < 0)
  257. return ret;
  258. props.type = BACKLIGHT_PLATFORM;
  259. props.brightness = ret;
  260. props.max_brightness = DELL_BL_MAX_BRIGHTNESS;
  261. props.power = dell_bl->power;
  262. dell_bl->bl = devm_backlight_device_register(dev, "dell_uart_backlight",
  263. dev, dell_bl,
  264. &dell_uart_backlight_ops,
  265. &props);
  266. return PTR_ERR_OR_ZERO(dell_bl->bl);
  267. }
  268. static struct serdev_device_driver dell_uart_bl_serdev_driver = {
  269. .probe = dell_uart_bl_serdev_probe,
  270. .driver = {
  271. .name = KBUILD_MODNAME,
  272. },
  273. };
  274. static int dell_uart_bl_pdev_probe(struct platform_device *pdev)
  275. {
  276. enum acpi_backlight_type bl_type;
  277. struct serdev_device *serdev;
  278. struct device *ctrl_dev;
  279. int ret;
  280. bl_type = acpi_video_get_backlight_type();
  281. if (bl_type != acpi_backlight_dell_uart) {
  282. dev_dbg(&pdev->dev, "Not loading (ACPI backlight type = %d)\n", bl_type);
  283. return -ENODEV;
  284. }
  285. ctrl_dev = get_serdev_controller("DELL0501", NULL, 0, "serial0");
  286. if (IS_ERR(ctrl_dev))
  287. return PTR_ERR(ctrl_dev);
  288. serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev));
  289. put_device(ctrl_dev);
  290. if (!serdev)
  291. return -ENOMEM;
  292. ret = serdev_device_add(serdev);
  293. if (ret) {
  294. dev_err(&pdev->dev, "error %d adding serdev\n", ret);
  295. serdev_device_put(serdev);
  296. return ret;
  297. }
  298. ret = serdev_device_driver_register(&dell_uart_bl_serdev_driver);
  299. if (ret)
  300. goto err_remove_serdev;
  301. /*
  302. * serdev device <-> driver matching relies on OF or ACPI matches and
  303. * neither is available here, manually bind the driver.
  304. */
  305. ret = device_driver_attach(&dell_uart_bl_serdev_driver.driver, &serdev->dev);
  306. if (ret)
  307. goto err_unregister_serdev_driver;
  308. /* So that dell_uart_bl_pdev_remove() can remove the serdev */
  309. platform_set_drvdata(pdev, serdev);
  310. return 0;
  311. err_unregister_serdev_driver:
  312. serdev_device_driver_unregister(&dell_uart_bl_serdev_driver);
  313. err_remove_serdev:
  314. serdev_device_remove(serdev);
  315. return ret;
  316. }
  317. static void dell_uart_bl_pdev_remove(struct platform_device *pdev)
  318. {
  319. struct serdev_device *serdev = platform_get_drvdata(pdev);
  320. serdev_device_driver_unregister(&dell_uart_bl_serdev_driver);
  321. serdev_device_remove(serdev);
  322. }
  323. static struct platform_driver dell_uart_bl_pdev_driver = {
  324. .probe = dell_uart_bl_pdev_probe,
  325. .remove = dell_uart_bl_pdev_remove,
  326. .driver = {
  327. .name = "dell-uart-backlight",
  328. },
  329. };
  330. module_platform_driver(dell_uart_bl_pdev_driver);
  331. MODULE_ALIAS("platform:dell-uart-backlight");
  332. MODULE_DESCRIPTION("Dell AIO Serial Backlight driver");
  333. MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
  334. MODULE_LICENSE("GPL");