fujitsu-laptop.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*-*-linux-c-*-*/
  3. /*
  4. Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
  5. Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
  6. Copyright (C) 2008 Tony Vroon <tony@linx.net>
  7. Based on earlier work:
  8. Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
  9. Adrian Yee <brewt-fujitsu@brewt.org>
  10. Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
  11. by its respective authors.
  12. */
  13. /*
  14. * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
  15. * features made available on a range of Fujitsu laptops including the
  16. * P2xxx/P5xxx/S2xxx/S6xxx/S7xxx series.
  17. *
  18. * This driver implements a vendor-specific backlight control interface for
  19. * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu
  20. * laptops.
  21. *
  22. * This driver has been tested on a Fujitsu Lifebook S2110, S6410, S7020 and
  23. * P8010. It should work on most P-series and S-series Lifebooks, but
  24. * YMMV.
  25. *
  26. * The module parameter use_alt_lcd_levels switches between different ACPI
  27. * brightness controls which are used by different Fujitsu laptops. In most
  28. * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
  29. * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
  30. *
  31. */
  32. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  33. #include <linux/module.h>
  34. #include <linux/kernel.h>
  35. #include <linux/init.h>
  36. #include <linux/acpi.h>
  37. #include <linux/bitops.h>
  38. #include <linux/dmi.h>
  39. #include <linux/backlight.h>
  40. #include <linux/input.h>
  41. #include <linux/input/sparse-keymap.h>
  42. #include <linux/kfifo.h>
  43. #include <linux/leds.h>
  44. #include <linux/platform_device.h>
  45. #include <linux/power_supply.h>
  46. #include <acpi/battery.h>
  47. #include <acpi/video.h>
  48. #define FUJITSU_DRIVER_VERSION "0.6.0"
  49. #define FUJITSU_LCD_N_LEVELS 8
  50. #define ACPI_FUJITSU_CLASS "fujitsu"
  51. #define ACPI_FUJITSU_BL_HID "FUJ02B1"
  52. #define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
  53. #define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1"
  54. #define ACPI_FUJITSU_LAPTOP_HID "FUJ02E3"
  55. #define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
  56. #define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3"
  57. #define ACPI_FUJITSU_NOTIFY_CODE 0x80
  58. /* FUNC interface - command values */
  59. #define FUNC_FLAGS BIT(12)
  60. #define FUNC_LEDS (BIT(12) | BIT(0))
  61. #define FUNC_BUTTONS (BIT(12) | BIT(1))
  62. #define FUNC_BACKLIGHT (BIT(12) | BIT(2))
  63. /* FUNC interface - responses */
  64. #define UNSUPPORTED_CMD 0x80000000
  65. /* FUNC interface - status flags */
  66. #define FLAG_RFKILL BIT(5)
  67. #define FLAG_LID BIT(8)
  68. #define FLAG_DOCK BIT(9)
  69. #define FLAG_TOUCHPAD_TOGGLE BIT(26)
  70. #define FLAG_MICMUTE BIT(29)
  71. #define FLAG_SOFTKEYS (FLAG_RFKILL | FLAG_TOUCHPAD_TOGGLE | FLAG_MICMUTE)
  72. /* FUNC interface - LED control */
  73. #define FUNC_LED_OFF BIT(0)
  74. #define FUNC_LED_ON (BIT(0) | BIT(16) | BIT(17))
  75. #define LOGOLAMP_POWERON BIT(13)
  76. #define LOGOLAMP_ALWAYS BIT(14)
  77. #define KEYBOARD_LAMPS BIT(8)
  78. #define RADIO_LED_ON BIT(5)
  79. #define ECO_LED BIT(16)
  80. #define ECO_LED_ON BIT(19)
  81. /* FUNC interface - backlight power control */
  82. #define BACKLIGHT_PARAM_POWER BIT(2)
  83. #define BACKLIGHT_OFF (BIT(0) | BIT(1))
  84. #define BACKLIGHT_ON 0
  85. /* FUNC interface - battery control interface */
  86. #define FUNC_S006_METHOD 0x1006
  87. #define CHARGE_CONTROL_RW 0x21
  88. /* Scancodes read from the GIRB register */
  89. #define KEY1_CODE 0x410
  90. #define KEY2_CODE 0x411
  91. #define KEY3_CODE 0x412
  92. #define KEY4_CODE 0x413
  93. #define KEY5_CODE 0x414
  94. #define KEY6_CODE 0x415
  95. #define KEY7_CODE 0x416
  96. #define KEY8_CODE 0x417
  97. #define KEY9_CODE 0x420
  98. /* Hotkey ringbuffer limits */
  99. #define MAX_HOTKEY_RINGBUFFER_SIZE 100
  100. #define RINGBUFFERSIZE 40
  101. /* Module parameters */
  102. static int use_alt_lcd_levels = -1;
  103. static bool disable_brightness_adjust;
  104. /* Device controlling the backlight and associated keys */
  105. struct fujitsu_bl {
  106. struct input_dev *input;
  107. char phys[32];
  108. struct backlight_device *bl_device;
  109. unsigned int max_brightness;
  110. unsigned int brightness_level;
  111. };
  112. static struct fujitsu_bl *fujitsu_bl;
  113. /* Device used to access hotkeys and other features on the laptop */
  114. struct fujitsu_laptop {
  115. struct input_dev *input;
  116. char phys[32];
  117. struct platform_device *pf_device;
  118. struct kfifo fifo;
  119. spinlock_t fifo_lock;
  120. int flags_supported;
  121. int flags_state;
  122. bool charge_control_supported;
  123. };
  124. static struct acpi_device *fext;
  125. /* Fujitsu ACPI interface function */
  126. static int call_fext_func(struct acpi_device *device,
  127. int func, int op, int feature, int state)
  128. {
  129. union acpi_object params[4] = {
  130. { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func },
  131. { .integer.type = ACPI_TYPE_INTEGER, .integer.value = op },
  132. { .integer.type = ACPI_TYPE_INTEGER, .integer.value = feature },
  133. { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state }
  134. };
  135. struct acpi_object_list arg_list = { 4, params };
  136. unsigned long long value;
  137. acpi_status status;
  138. status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list,
  139. &value);
  140. if (ACPI_FAILURE(status)) {
  141. acpi_handle_err(device->handle, "Failed to evaluate FUNC\n");
  142. return -ENODEV;
  143. }
  144. acpi_handle_debug(device->handle,
  145. "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
  146. func, op, feature, state, (int)value);
  147. return value;
  148. }
  149. /* Battery charge control code */
  150. static ssize_t charge_control_end_threshold_store(struct device *dev,
  151. struct device_attribute *attr,
  152. const char *buf, size_t count)
  153. {
  154. int cc_end_value, s006_cc_return;
  155. unsigned int value;
  156. int ret;
  157. ret = kstrtouint(buf, 10, &value);
  158. if (ret)
  159. return ret;
  160. if (value > 100)
  161. return -EINVAL;
  162. if (value < 50)
  163. value = 50;
  164. cc_end_value = value * 0x100 + 0x20;
  165. s006_cc_return = call_fext_func(fext, FUNC_S006_METHOD,
  166. CHARGE_CONTROL_RW, cc_end_value, 0x0);
  167. if (s006_cc_return < 0)
  168. return s006_cc_return;
  169. /*
  170. * The S006 0x21 method returns 0x00 in case the provided value
  171. * is invalid.
  172. */
  173. if (s006_cc_return == 0x00)
  174. return -EINVAL;
  175. return count;
  176. }
  177. static ssize_t charge_control_end_threshold_show(struct device *dev,
  178. struct device_attribute *attr,
  179. char *buf)
  180. {
  181. int status;
  182. status = call_fext_func(fext, FUNC_S006_METHOD,
  183. CHARGE_CONTROL_RW, 0x21, 0x0);
  184. if (status < 0)
  185. return status;
  186. return sysfs_emit(buf, "%d\n", status);
  187. }
  188. static DEVICE_ATTR_RW(charge_control_end_threshold);
  189. /* ACPI battery hook */
  190. static int fujitsu_battery_add_hook(struct power_supply *battery,
  191. struct acpi_battery_hook *hook)
  192. {
  193. return device_create_file(&battery->dev,
  194. &dev_attr_charge_control_end_threshold);
  195. }
  196. static int fujitsu_battery_remove_hook(struct power_supply *battery,
  197. struct acpi_battery_hook *hook)
  198. {
  199. device_remove_file(&battery->dev,
  200. &dev_attr_charge_control_end_threshold);
  201. return 0;
  202. }
  203. static struct acpi_battery_hook battery_hook = {
  204. .add_battery = fujitsu_battery_add_hook,
  205. .remove_battery = fujitsu_battery_remove_hook,
  206. .name = "Fujitsu Battery Extension",
  207. };
  208. /*
  209. * These functions are intended to be called from acpi_fujitsu_laptop_add and
  210. * acpi_fujitsu_laptop_remove.
  211. */
  212. static int fujitsu_battery_charge_control_add(struct acpi_device *device)
  213. {
  214. struct fujitsu_laptop *priv = acpi_driver_data(device);
  215. int s006_cc_return;
  216. priv->charge_control_supported = false;
  217. /*
  218. * Check if the S006 0x21 method exists by trying to get the current
  219. * battery charge limit.
  220. */
  221. s006_cc_return = call_fext_func(fext, FUNC_S006_METHOD,
  222. CHARGE_CONTROL_RW, 0x21, 0x0);
  223. if (s006_cc_return < 0)
  224. return s006_cc_return;
  225. if (s006_cc_return == UNSUPPORTED_CMD)
  226. return -ENODEV;
  227. priv->charge_control_supported = true;
  228. battery_hook_register(&battery_hook);
  229. return 0;
  230. }
  231. static void fujitsu_battery_charge_control_remove(struct acpi_device *device)
  232. {
  233. struct fujitsu_laptop *priv = acpi_driver_data(device);
  234. if (priv->charge_control_supported)
  235. battery_hook_unregister(&battery_hook);
  236. }
  237. /* Hardware access for LCD brightness control */
  238. static int set_lcd_level(struct acpi_device *device, int level)
  239. {
  240. struct fujitsu_bl *priv = acpi_driver_data(device);
  241. acpi_status status;
  242. char *method;
  243. switch (use_alt_lcd_levels) {
  244. case -1:
  245. if (acpi_has_method(device->handle, "SBL2"))
  246. method = "SBL2";
  247. else
  248. method = "SBLL";
  249. break;
  250. case 1:
  251. method = "SBL2";
  252. break;
  253. default:
  254. method = "SBLL";
  255. break;
  256. }
  257. acpi_handle_debug(device->handle, "set lcd level via %s [%d]\n", method,
  258. level);
  259. if (level < 0 || level >= priv->max_brightness)
  260. return -EINVAL;
  261. status = acpi_execute_simple_method(device->handle, method, level);
  262. if (ACPI_FAILURE(status)) {
  263. acpi_handle_err(device->handle, "Failed to evaluate %s\n",
  264. method);
  265. return -ENODEV;
  266. }
  267. priv->brightness_level = level;
  268. return 0;
  269. }
  270. static int get_lcd_level(struct acpi_device *device)
  271. {
  272. struct fujitsu_bl *priv = acpi_driver_data(device);
  273. unsigned long long state = 0;
  274. acpi_status status = AE_OK;
  275. acpi_handle_debug(device->handle, "get lcd level via GBLL\n");
  276. status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state);
  277. if (ACPI_FAILURE(status))
  278. return 0;
  279. priv->brightness_level = state & 0x0fffffff;
  280. return priv->brightness_level;
  281. }
  282. static int get_max_brightness(struct acpi_device *device)
  283. {
  284. struct fujitsu_bl *priv = acpi_driver_data(device);
  285. unsigned long long state = 0;
  286. acpi_status status = AE_OK;
  287. acpi_handle_debug(device->handle, "get max lcd level via RBLL\n");
  288. status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state);
  289. if (ACPI_FAILURE(status))
  290. return -1;
  291. priv->max_brightness = state;
  292. return priv->max_brightness;
  293. }
  294. /* Backlight device stuff */
  295. static int bl_get_brightness(struct backlight_device *b)
  296. {
  297. struct acpi_device *device = bl_get_data(b);
  298. return b->props.power == BACKLIGHT_POWER_OFF ? 0 : get_lcd_level(device);
  299. }
  300. static int bl_update_status(struct backlight_device *b)
  301. {
  302. struct acpi_device *device = bl_get_data(b);
  303. if (fext) {
  304. if (b->props.power == BACKLIGHT_POWER_OFF)
  305. call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
  306. BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF);
  307. else
  308. call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
  309. BACKLIGHT_PARAM_POWER, BACKLIGHT_ON);
  310. }
  311. return set_lcd_level(device, b->props.brightness);
  312. }
  313. static const struct backlight_ops fujitsu_bl_ops = {
  314. .get_brightness = bl_get_brightness,
  315. .update_status = bl_update_status,
  316. };
  317. static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
  318. char *buf)
  319. {
  320. struct fujitsu_laptop *priv = dev_get_drvdata(dev);
  321. if (!(priv->flags_supported & FLAG_LID))
  322. return sysfs_emit(buf, "unknown\n");
  323. if (priv->flags_state & FLAG_LID)
  324. return sysfs_emit(buf, "open\n");
  325. else
  326. return sysfs_emit(buf, "closed\n");
  327. }
  328. static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
  329. char *buf)
  330. {
  331. struct fujitsu_laptop *priv = dev_get_drvdata(dev);
  332. if (!(priv->flags_supported & FLAG_DOCK))
  333. return sysfs_emit(buf, "unknown\n");
  334. if (priv->flags_state & FLAG_DOCK)
  335. return sysfs_emit(buf, "docked\n");
  336. else
  337. return sysfs_emit(buf, "undocked\n");
  338. }
  339. static ssize_t radios_show(struct device *dev, struct device_attribute *attr,
  340. char *buf)
  341. {
  342. struct fujitsu_laptop *priv = dev_get_drvdata(dev);
  343. if (!(priv->flags_supported & FLAG_RFKILL))
  344. return sysfs_emit(buf, "unknown\n");
  345. if (priv->flags_state & FLAG_RFKILL)
  346. return sysfs_emit(buf, "on\n");
  347. else
  348. return sysfs_emit(buf, "killed\n");
  349. }
  350. static DEVICE_ATTR_RO(lid);
  351. static DEVICE_ATTR_RO(dock);
  352. static DEVICE_ATTR_RO(radios);
  353. static struct attribute *fujitsu_pf_attributes[] = {
  354. &dev_attr_lid.attr,
  355. &dev_attr_dock.attr,
  356. &dev_attr_radios.attr,
  357. NULL
  358. };
  359. static const struct attribute_group fujitsu_pf_attribute_group = {
  360. .attrs = fujitsu_pf_attributes
  361. };
  362. static struct platform_driver fujitsu_pf_driver = {
  363. .driver = {
  364. .name = "fujitsu-laptop",
  365. }
  366. };
  367. /* ACPI device for LCD brightness control */
  368. static const struct key_entry keymap_backlight[] = {
  369. { KE_KEY, true, { KEY_BRIGHTNESSUP } },
  370. { KE_KEY, false, { KEY_BRIGHTNESSDOWN } },
  371. { KE_END, 0 }
  372. };
  373. static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
  374. {
  375. struct fujitsu_bl *priv = acpi_driver_data(device);
  376. int ret;
  377. priv->input = devm_input_allocate_device(&device->dev);
  378. if (!priv->input)
  379. return -ENOMEM;
  380. snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0",
  381. acpi_device_hid(device));
  382. priv->input->name = acpi_device_name(device);
  383. priv->input->phys = priv->phys;
  384. priv->input->id.bustype = BUS_HOST;
  385. priv->input->id.product = 0x06;
  386. ret = sparse_keymap_setup(priv->input, keymap_backlight, NULL);
  387. if (ret)
  388. return ret;
  389. return input_register_device(priv->input);
  390. }
  391. static int fujitsu_backlight_register(struct acpi_device *device)
  392. {
  393. struct fujitsu_bl *priv = acpi_driver_data(device);
  394. const struct backlight_properties props = {
  395. .brightness = priv->brightness_level,
  396. .max_brightness = priv->max_brightness - 1,
  397. .type = BACKLIGHT_PLATFORM
  398. };
  399. struct backlight_device *bd;
  400. bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop",
  401. &device->dev, device,
  402. &fujitsu_bl_ops, &props);
  403. if (IS_ERR(bd))
  404. return PTR_ERR(bd);
  405. priv->bl_device = bd;
  406. return 0;
  407. }
  408. static int acpi_fujitsu_bl_add(struct acpi_device *device)
  409. {
  410. struct fujitsu_bl *priv;
  411. int ret;
  412. if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
  413. return -ENODEV;
  414. priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
  415. if (!priv)
  416. return -ENOMEM;
  417. fujitsu_bl = priv;
  418. strscpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME);
  419. strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
  420. device->driver_data = priv;
  421. pr_info("ACPI: %s [%s]\n",
  422. acpi_device_name(device), acpi_device_bid(device));
  423. if (get_max_brightness(device) <= 0)
  424. priv->max_brightness = FUJITSU_LCD_N_LEVELS;
  425. get_lcd_level(device);
  426. ret = acpi_fujitsu_bl_input_setup(device);
  427. if (ret)
  428. return ret;
  429. return fujitsu_backlight_register(device);
  430. }
  431. /* Brightness notify */
  432. static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
  433. {
  434. struct fujitsu_bl *priv = acpi_driver_data(device);
  435. int oldb, newb;
  436. if (event != ACPI_FUJITSU_NOTIFY_CODE) {
  437. acpi_handle_info(device->handle, "unsupported event [0x%x]\n",
  438. event);
  439. sparse_keymap_report_event(priv->input, -1, 1, true);
  440. return;
  441. }
  442. oldb = priv->brightness_level;
  443. get_lcd_level(device);
  444. newb = priv->brightness_level;
  445. acpi_handle_debug(device->handle,
  446. "brightness button event [%i -> %i]\n", oldb, newb);
  447. if (oldb == newb)
  448. return;
  449. if (!disable_brightness_adjust)
  450. set_lcd_level(device, newb);
  451. sparse_keymap_report_event(priv->input, oldb < newb, 1, true);
  452. }
  453. /* ACPI device for hotkey handling */
  454. static const struct key_entry keymap_default[] = {
  455. { KE_KEY, KEY1_CODE, { KEY_PROG1 } },
  456. { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
  457. { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
  458. { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
  459. { KE_KEY, KEY9_CODE, { KEY_RFKILL } },
  460. /* Soft keys read from status flags */
  461. { KE_KEY, FLAG_RFKILL, { KEY_RFKILL } },
  462. { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } },
  463. { KE_KEY, FLAG_MICMUTE, { KEY_MICMUTE } },
  464. { KE_END, 0 }
  465. };
  466. static const struct key_entry keymap_s64x0[] = {
  467. { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */
  468. { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */
  469. { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
  470. { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
  471. { KE_END, 0 }
  472. };
  473. static const struct key_entry keymap_p8010[] = {
  474. { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */
  475. { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
  476. { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */
  477. { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */
  478. { KE_END, 0 }
  479. };
  480. static const struct key_entry keymap_s2110[] = {
  481. { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, /* "A" */
  482. { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, /* "B" */
  483. { KE_KEY, KEY3_CODE, { KEY_WWW } }, /* "Internet" */
  484. { KE_KEY, KEY4_CODE, { KEY_EMAIL } }, /* "E-mail" */
  485. { KE_KEY, KEY5_CODE, { KEY_STOPCD } },
  486. { KE_KEY, KEY6_CODE, { KEY_PLAYPAUSE } },
  487. { KE_KEY, KEY7_CODE, { KEY_PREVIOUSSONG } },
  488. { KE_KEY, KEY8_CODE, { KEY_NEXTSONG } },
  489. { KE_END, 0 }
  490. };
  491. static const struct key_entry *keymap = keymap_default;
  492. static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id)
  493. {
  494. pr_info("Identified laptop model '%s'\n", id->ident);
  495. keymap = id->driver_data;
  496. return 1;
  497. }
  498. static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
  499. {
  500. .callback = fujitsu_laptop_dmi_keymap_override,
  501. .ident = "Fujitsu Siemens S6410",
  502. .matches = {
  503. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  504. DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
  505. },
  506. .driver_data = (void *)keymap_s64x0
  507. },
  508. {
  509. .callback = fujitsu_laptop_dmi_keymap_override,
  510. .ident = "Fujitsu Siemens S6420",
  511. .matches = {
  512. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  513. DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
  514. },
  515. .driver_data = (void *)keymap_s64x0
  516. },
  517. {
  518. .callback = fujitsu_laptop_dmi_keymap_override,
  519. .ident = "Fujitsu LifeBook P8010",
  520. .matches = {
  521. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
  522. DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
  523. },
  524. .driver_data = (void *)keymap_p8010
  525. },
  526. {
  527. .callback = fujitsu_laptop_dmi_keymap_override,
  528. .ident = "Fujitsu LifeBook S2110",
  529. .matches = {
  530. DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  531. DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S2110"),
  532. },
  533. .driver_data = (void *)keymap_s2110
  534. },
  535. {}
  536. };
  537. static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
  538. {
  539. struct fujitsu_laptop *priv = acpi_driver_data(device);
  540. int ret;
  541. priv->input = devm_input_allocate_device(&device->dev);
  542. if (!priv->input)
  543. return -ENOMEM;
  544. snprintf(priv->phys, sizeof(priv->phys), "%s/input0",
  545. acpi_device_hid(device));
  546. priv->input->name = acpi_device_name(device);
  547. priv->input->phys = priv->phys;
  548. priv->input->id.bustype = BUS_HOST;
  549. dmi_check_system(fujitsu_laptop_dmi_table);
  550. ret = sparse_keymap_setup(priv->input, keymap, NULL);
  551. if (ret)
  552. return ret;
  553. return input_register_device(priv->input);
  554. }
  555. static int fujitsu_laptop_platform_add(struct acpi_device *device)
  556. {
  557. struct fujitsu_laptop *priv = acpi_driver_data(device);
  558. int ret;
  559. priv->pf_device = platform_device_alloc("fujitsu-laptop", PLATFORM_DEVID_NONE);
  560. if (!priv->pf_device)
  561. return -ENOMEM;
  562. platform_set_drvdata(priv->pf_device, priv);
  563. ret = platform_device_add(priv->pf_device);
  564. if (ret)
  565. goto err_put_platform_device;
  566. ret = sysfs_create_group(&priv->pf_device->dev.kobj,
  567. &fujitsu_pf_attribute_group);
  568. if (ret)
  569. goto err_del_platform_device;
  570. return 0;
  571. err_del_platform_device:
  572. platform_device_del(priv->pf_device);
  573. err_put_platform_device:
  574. platform_device_put(priv->pf_device);
  575. return ret;
  576. }
  577. static void fujitsu_laptop_platform_remove(struct acpi_device *device)
  578. {
  579. struct fujitsu_laptop *priv = acpi_driver_data(device);
  580. sysfs_remove_group(&priv->pf_device->dev.kobj,
  581. &fujitsu_pf_attribute_group);
  582. platform_device_unregister(priv->pf_device);
  583. }
  584. static int logolamp_set(struct led_classdev *cdev,
  585. enum led_brightness brightness)
  586. {
  587. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  588. int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
  589. int ret;
  590. if (brightness < LED_HALF)
  591. poweron = FUNC_LED_OFF;
  592. if (brightness < LED_FULL)
  593. always = FUNC_LED_OFF;
  594. ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
  595. if (ret < 0)
  596. return ret;
  597. return call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
  598. }
  599. static enum led_brightness logolamp_get(struct led_classdev *cdev)
  600. {
  601. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  602. int ret;
  603. ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
  604. if (ret == FUNC_LED_ON)
  605. return LED_FULL;
  606. ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
  607. if (ret == FUNC_LED_ON)
  608. return LED_HALF;
  609. return LED_OFF;
  610. }
  611. static int kblamps_set(struct led_classdev *cdev,
  612. enum led_brightness brightness)
  613. {
  614. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  615. if (brightness >= LED_FULL)
  616. return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
  617. FUNC_LED_ON);
  618. else
  619. return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
  620. FUNC_LED_OFF);
  621. }
  622. static enum led_brightness kblamps_get(struct led_classdev *cdev)
  623. {
  624. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  625. enum led_brightness brightness = LED_OFF;
  626. if (call_fext_func(device,
  627. FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
  628. brightness = LED_FULL;
  629. return brightness;
  630. }
  631. static int radio_led_set(struct led_classdev *cdev,
  632. enum led_brightness brightness)
  633. {
  634. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  635. if (brightness >= LED_FULL)
  636. return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
  637. RADIO_LED_ON);
  638. else
  639. return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
  640. 0x0);
  641. }
  642. static enum led_brightness radio_led_get(struct led_classdev *cdev)
  643. {
  644. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  645. enum led_brightness brightness = LED_OFF;
  646. if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
  647. brightness = LED_FULL;
  648. return brightness;
  649. }
  650. static int eco_led_set(struct led_classdev *cdev,
  651. enum led_brightness brightness)
  652. {
  653. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  654. int curr;
  655. curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0);
  656. if (brightness >= LED_FULL)
  657. return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
  658. curr | ECO_LED_ON);
  659. else
  660. return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
  661. curr & ~ECO_LED_ON);
  662. }
  663. static enum led_brightness eco_led_get(struct led_classdev *cdev)
  664. {
  665. struct acpi_device *device = to_acpi_device(cdev->dev->parent);
  666. enum led_brightness brightness = LED_OFF;
  667. if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
  668. brightness = LED_FULL;
  669. return brightness;
  670. }
  671. static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
  672. {
  673. struct fujitsu_laptop *priv = acpi_driver_data(device);
  674. struct led_classdev *led;
  675. int ret;
  676. if (call_fext_func(device,
  677. FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
  678. led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
  679. if (!led)
  680. return -ENOMEM;
  681. led->name = "fujitsu::logolamp";
  682. led->brightness_set_blocking = logolamp_set;
  683. led->brightness_get = logolamp_get;
  684. ret = devm_led_classdev_register(&device->dev, led);
  685. if (ret)
  686. return ret;
  687. }
  688. if ((call_fext_func(device,
  689. FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
  690. (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
  691. led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
  692. if (!led)
  693. return -ENOMEM;
  694. led->name = "fujitsu::kblamps";
  695. led->brightness_set_blocking = kblamps_set;
  696. led->brightness_get = kblamps_get;
  697. ret = devm_led_classdev_register(&device->dev, led);
  698. if (ret)
  699. return ret;
  700. }
  701. /*
  702. * Some Fujitsu laptops have a radio toggle button in place of a slide
  703. * switch and all such machines appear to also have an RF LED. Based on
  704. * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
  705. * S7110, S8420; the first one has a radio toggle button, the other
  706. * three have slide switches), bit 17 of flags_supported (the value
  707. * returned by method S000 of ACPI device FUJ02E3) seems to indicate
  708. * whether given model has a radio toggle button.
  709. */
  710. if (priv->flags_supported & BIT(17)) {
  711. led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
  712. if (!led)
  713. return -ENOMEM;
  714. led->name = "fujitsu::radio_led";
  715. led->brightness_set_blocking = radio_led_set;
  716. led->brightness_get = radio_led_get;
  717. led->default_trigger = "rfkill-any";
  718. ret = devm_led_classdev_register(&device->dev, led);
  719. if (ret)
  720. return ret;
  721. }
  722. /* Support for eco led is not always signaled in bit corresponding
  723. * to the bit used to control the led. According to the DSDT table,
  724. * bit 14 seems to indicate presence of said led as well.
  725. * Confirm by testing the status.
  726. */
  727. if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
  728. (call_fext_func(device,
  729. FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
  730. led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
  731. if (!led)
  732. return -ENOMEM;
  733. led->name = "fujitsu::eco_led";
  734. led->brightness_set_blocking = eco_led_set;
  735. led->brightness_get = eco_led_get;
  736. ret = devm_led_classdev_register(&device->dev, led);
  737. if (ret)
  738. return ret;
  739. }
  740. return 0;
  741. }
  742. static int acpi_fujitsu_laptop_add(struct acpi_device *device)
  743. {
  744. struct fujitsu_laptop *priv;
  745. int ret, i = 0;
  746. priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
  747. if (!priv)
  748. return -ENOMEM;
  749. WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended.");
  750. fext = device;
  751. strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
  752. strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
  753. device->driver_data = priv;
  754. /* kfifo */
  755. spin_lock_init(&priv->fifo_lock);
  756. ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
  757. GFP_KERNEL);
  758. if (ret)
  759. return ret;
  760. pr_info("ACPI: %s [%s]\n",
  761. acpi_device_name(device), acpi_device_bid(device));
  762. while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
  763. i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
  764. ; /* No action, result is discarded */
  765. acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
  766. i);
  767. priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0,
  768. 0x0);
  769. /* Make sure our bitmask of supported functions is cleared if the
  770. RFKILL function block is not implemented, like on the S7020. */
  771. if (priv->flags_supported == UNSUPPORTED_CMD)
  772. priv->flags_supported = 0;
  773. if (priv->flags_supported)
  774. priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
  775. 0x0);
  776. /* Suspect this is a keymap of the application panel, print it */
  777. acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
  778. call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0));
  779. /* Sync backlight power status */
  780. if (fujitsu_bl && fujitsu_bl->bl_device &&
  781. acpi_video_get_backlight_type() == acpi_backlight_vendor) {
  782. if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
  783. BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
  784. fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_OFF;
  785. else
  786. fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_ON;
  787. }
  788. ret = acpi_fujitsu_laptop_input_setup(device);
  789. if (ret)
  790. goto err_free_fifo;
  791. ret = acpi_fujitsu_laptop_leds_register(device);
  792. if (ret)
  793. goto err_free_fifo;
  794. ret = fujitsu_laptop_platform_add(device);
  795. if (ret)
  796. goto err_free_fifo;
  797. ret = fujitsu_battery_charge_control_add(device);
  798. if (ret < 0)
  799. pr_warn("Unable to register battery charge control: %d\n", ret);
  800. return 0;
  801. err_free_fifo:
  802. kfifo_free(&priv->fifo);
  803. return ret;
  804. }
  805. static void acpi_fujitsu_laptop_remove(struct acpi_device *device)
  806. {
  807. struct fujitsu_laptop *priv = acpi_driver_data(device);
  808. fujitsu_battery_charge_control_remove(device);
  809. fujitsu_laptop_platform_remove(device);
  810. kfifo_free(&priv->fifo);
  811. }
  812. static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
  813. {
  814. struct fujitsu_laptop *priv = acpi_driver_data(device);
  815. int ret;
  816. ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
  817. sizeof(scancode), &priv->fifo_lock);
  818. if (ret != sizeof(scancode)) {
  819. dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n",
  820. scancode);
  821. return;
  822. }
  823. sparse_keymap_report_event(priv->input, scancode, 1, false);
  824. dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n",
  825. scancode);
  826. }
  827. static void acpi_fujitsu_laptop_release(struct acpi_device *device)
  828. {
  829. struct fujitsu_laptop *priv = acpi_driver_data(device);
  830. int scancode, ret;
  831. while (true) {
  832. ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode,
  833. sizeof(scancode), &priv->fifo_lock);
  834. if (ret != sizeof(scancode))
  835. return;
  836. sparse_keymap_report_event(priv->input, scancode, 0, false);
  837. dev_dbg(&priv->input->dev,
  838. "Pop scancode from ringbuffer [0x%x]\n", scancode);
  839. }
  840. }
  841. static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
  842. {
  843. struct fujitsu_laptop *priv = acpi_driver_data(device);
  844. unsigned long flags;
  845. int scancode, i = 0;
  846. unsigned int irb;
  847. if (event != ACPI_FUJITSU_NOTIFY_CODE) {
  848. acpi_handle_info(device->handle, "Unsupported event [0x%x]\n",
  849. event);
  850. sparse_keymap_report_event(priv->input, -1, 1, true);
  851. return;
  852. }
  853. if (priv->flags_supported)
  854. priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
  855. 0x0);
  856. while ((irb = call_fext_func(device,
  857. FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
  858. i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
  859. scancode = irb & 0x4ff;
  860. if (sparse_keymap_entry_from_scancode(priv->input, scancode))
  861. acpi_fujitsu_laptop_press(device, scancode);
  862. else if (scancode == 0)
  863. acpi_fujitsu_laptop_release(device);
  864. else
  865. acpi_handle_info(device->handle,
  866. "Unknown GIRB result [%x]\n", irb);
  867. }
  868. /*
  869. * First seen on the Skylake-based Lifebook E736/E746/E756), the
  870. * touchpad toggle hotkey (Fn+F4) is handled in software. Other models
  871. * have since added additional "soft keys". These are reported in the
  872. * status flags queried using FUNC_FLAGS.
  873. */
  874. if (priv->flags_supported & (FLAG_SOFTKEYS)) {
  875. flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
  876. flags &= (FLAG_SOFTKEYS);
  877. for_each_set_bit(i, &flags, BITS_PER_LONG)
  878. sparse_keymap_report_event(priv->input, BIT(i), 1, true);
  879. }
  880. }
  881. /* Initialization */
  882. static const struct acpi_device_id fujitsu_bl_device_ids[] = {
  883. {ACPI_FUJITSU_BL_HID, 0},
  884. {"", 0},
  885. };
  886. static struct acpi_driver acpi_fujitsu_bl_driver = {
  887. .name = ACPI_FUJITSU_BL_DRIVER_NAME,
  888. .class = ACPI_FUJITSU_CLASS,
  889. .ids = fujitsu_bl_device_ids,
  890. .ops = {
  891. .add = acpi_fujitsu_bl_add,
  892. .notify = acpi_fujitsu_bl_notify,
  893. },
  894. };
  895. static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
  896. {ACPI_FUJITSU_LAPTOP_HID, 0},
  897. {"", 0},
  898. };
  899. static struct acpi_driver acpi_fujitsu_laptop_driver = {
  900. .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
  901. .class = ACPI_FUJITSU_CLASS,
  902. .ids = fujitsu_laptop_device_ids,
  903. .ops = {
  904. .add = acpi_fujitsu_laptop_add,
  905. .remove = acpi_fujitsu_laptop_remove,
  906. .notify = acpi_fujitsu_laptop_notify,
  907. },
  908. };
  909. static const struct acpi_device_id fujitsu_ids[] __used = {
  910. {ACPI_FUJITSU_BL_HID, 0},
  911. {ACPI_FUJITSU_LAPTOP_HID, 0},
  912. {"", 0}
  913. };
  914. MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
  915. static int __init fujitsu_init(void)
  916. {
  917. int ret;
  918. ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver);
  919. if (ret)
  920. return ret;
  921. /* Register platform stuff */
  922. ret = platform_driver_register(&fujitsu_pf_driver);
  923. if (ret)
  924. goto err_unregister_acpi;
  925. /* Register laptop driver */
  926. ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver);
  927. if (ret)
  928. goto err_unregister_platform_driver;
  929. pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
  930. return 0;
  931. err_unregister_platform_driver:
  932. platform_driver_unregister(&fujitsu_pf_driver);
  933. err_unregister_acpi:
  934. acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
  935. return ret;
  936. }
  937. static void __exit fujitsu_cleanup(void)
  938. {
  939. acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver);
  940. platform_driver_unregister(&fujitsu_pf_driver);
  941. acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
  942. pr_info("driver unloaded\n");
  943. }
  944. module_init(fujitsu_init);
  945. module_exit(fujitsu_cleanup);
  946. module_param(use_alt_lcd_levels, int, 0644);
  947. MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)");
  948. module_param(disable_brightness_adjust, bool, 0644);
  949. MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment");
  950. MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
  951. MODULE_DESCRIPTION("Fujitsu laptop extras support");
  952. MODULE_VERSION(FUJITSU_DRIVER_VERSION);
  953. MODULE_LICENSE("GPL");