0001-surface3-power.patch 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. From 7f67d3c72b8968df814d0b94c2f2f8c6b621fbdf Mon Sep 17 00:00:00 2001
  2. From: qzed <qzed@users.noreply.github.com>
  3. Date: Tue, 17 Sep 2019 17:17:56 +0200
  4. Subject: [PATCH 1/6] surface3-power
  5. ---
  6. drivers/platform/x86/Kconfig | 7 +
  7. drivers/platform/x86/Makefile | 1 +
  8. drivers/platform/x86/surface3_power.c | 604 ++++++++++++++++++++++++++
  9. 3 files changed, 612 insertions(+)
  10. create mode 100644 drivers/platform/x86/surface3_power.c
  11. diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
  12. index 1cab993205142..348c795019fa4 100644
  13. --- a/drivers/platform/x86/Kconfig
  14. +++ b/drivers/platform/x86/Kconfig
  15. @@ -1209,6 +1209,13 @@ config SURFACE_3_BUTTON
  16. ---help---
  17. This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
  18. +config SURFACE_3_POWER_OPREGION
  19. + tristate "Surface 3 battery platform operation region support"
  20. + depends on ACPI && I2C
  21. + help
  22. + Select this option to enable support for ACPI operation
  23. + region of the Surface 3 battery platform driver.
  24. +
  25. config INTEL_PUNIT_IPC
  26. tristate "Intel P-Unit IPC Driver"
  27. ---help---
  28. diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
  29. index 4151040330601..6dd955ad9bf18 100644
  30. --- a/drivers/platform/x86/Makefile
  31. +++ b/drivers/platform/x86/Makefile
  32. @@ -85,6 +85,7 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
  33. obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o
  34. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  35. obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
  36. +obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
  37. obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
  38. obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o
  39. obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
  40. diff --git a/drivers/platform/x86/surface3_power.c b/drivers/platform/x86/surface3_power.c
  41. new file mode 100644
  42. index 0000000000000..e0af01a603025
  43. --- /dev/null
  44. +++ b/drivers/platform/x86/surface3_power.c
  45. @@ -0,0 +1,604 @@
  46. +// SPDX-License-Identifier: GPL-2.0+
  47. +
  48. +/*
  49. + * Supports for the power IC on the Surface 3 tablet.
  50. + *
  51. + * (C) Copyright 2016-2018 Red Hat, Inc
  52. + * (C) Copyright 2016-2018 Benjamin Tissoires <benjamin.tissoires@gmail.com>
  53. + * (C) Copyright 2016 Stephen Just <stephenjust@gmail.com>
  54. + *
  55. + */
  56. +
  57. +/*
  58. + * This driver has been reverse-engineered by parsing the DSDT of the Surface 3
  59. + * and looking at the registers of the chips.
  60. + *
  61. + * The DSDT allowed to find out that:
  62. + * - the driver is required for the ACPI BAT0 device to communicate to the chip
  63. + * through an operation region.
  64. + * - the various defines for the operation region functions to communicate with
  65. + * this driver
  66. + * - the DSM 3f99e367-6220-4955-8b0f-06ef2ae79412 allows to trigger ACPI
  67. + * events to BAT0 (the code is all available in the DSDT).
  68. + *
  69. + * Further findings regarding the 2 chips declared in the MSHW0011 are:
  70. + * - there are 2 chips declared:
  71. + * . 0x22 seems to control the ADP1 line status (and probably the charger)
  72. + * . 0x55 controls the battery directly
  73. + * - the battery chip uses a SMBus protocol (using plain SMBus allows non
  74. + * destructive commands):
  75. + * . the commands/registers used are in the range 0x00..0x7F
  76. + * . if bit 8 (0x80) is set in the SMBus command, the returned value is the
  77. + * same as when it is not set. There is a high chance this bit is the
  78. + * read/write
  79. + * . the various registers semantic as been deduced by observing the register
  80. + * dumps.
  81. + */
  82. +
  83. +#include <asm/unaligned.h>
  84. +#include <linux/acpi.h>
  85. +#include <linux/freezer.h>
  86. +#include <linux/i2c.h>
  87. +#include <linux/kernel.h>
  88. +#include <linux/kthread.h>
  89. +#include <linux/slab.h>
  90. +#include <linux/uuid.h>
  91. +
  92. +#define POLL_INTERVAL (2 * HZ)
  93. +
  94. +struct mshw0011_data {
  95. + struct i2c_client *adp1;
  96. + struct i2c_client *bat0;
  97. + unsigned short notify_mask;
  98. + struct task_struct *poll_task;
  99. + bool kthread_running;
  100. +
  101. + bool charging;
  102. + bool bat_charging;
  103. + u8 trip_point;
  104. + s32 full_capacity;
  105. +};
  106. +
  107. +struct mshw0011_lookup {
  108. + struct mshw0011_data *cdata;
  109. + unsigned int n;
  110. + unsigned int index;
  111. + int addr;
  112. +};
  113. +
  114. +struct mshw0011_handler_data {
  115. + struct acpi_connection_info info;
  116. + struct i2c_client *client;
  117. +};
  118. +
  119. +struct bix {
  120. + u32 revision;
  121. + u32 power_unit;
  122. + u32 design_capacity;
  123. + u32 last_full_charg_capacity;
  124. + u32 battery_technology;
  125. + u32 design_voltage;
  126. + u32 design_capacity_of_warning;
  127. + u32 design_capacity_of_low;
  128. + u32 cycle_count;
  129. + u32 measurement_accuracy;
  130. + u32 max_sampling_time;
  131. + u32 min_sampling_time;
  132. + u32 max_average_interval;
  133. + u32 min_average_interval;
  134. + u32 battery_capacity_granularity_1;
  135. + u32 battery_capacity_granularity_2;
  136. + char model[10];
  137. + char serial[10];
  138. + char type[10];
  139. + char OEM[10];
  140. +} __packed;
  141. +
  142. +struct bst {
  143. + u32 battery_state;
  144. + s32 battery_present_rate;
  145. + u32 battery_remaining_capacity;
  146. + u32 battery_present_voltage;
  147. +} __packed;
  148. +
  149. +struct gsb_command {
  150. + u8 arg0;
  151. + u8 arg1;
  152. + u8 arg2;
  153. +} __packed;
  154. +
  155. +struct gsb_buffer {
  156. + u8 status;
  157. + u8 len;
  158. + u8 ret;
  159. + union {
  160. + struct gsb_command cmd;
  161. + struct bst bst;
  162. + struct bix bix;
  163. + } __packed;
  164. +} __packed;
  165. +
  166. +
  167. +#define ACPI_BATTERY_STATE_DISCHARGING BIT(0)
  168. +#define ACPI_BATTERY_STATE_CHARGING BIT(1)
  169. +#define ACPI_BATTERY_STATE_CRITICAL BIT(2)
  170. +
  171. +#define MSHW0011_CMD_DEST_BAT0 0x01
  172. +#define MSHW0011_CMD_DEST_ADP1 0x03
  173. +
  174. +#define MSHW0011_CMD_BAT0_STA 0x01
  175. +#define MSHW0011_CMD_BAT0_BIX 0x02
  176. +#define MSHW0011_CMD_BAT0_BCT 0x03
  177. +#define MSHW0011_CMD_BAT0_BTM 0x04
  178. +#define MSHW0011_CMD_BAT0_BST 0x05
  179. +#define MSHW0011_CMD_BAT0_BTP 0x06
  180. +#define MSHW0011_CMD_ADP1_PSR 0x07
  181. +#define MSHW0011_CMD_BAT0_PSOC 0x09
  182. +#define MSHW0011_CMD_BAT0_PMAX 0x0a
  183. +#define MSHW0011_CMD_BAT0_PSRC 0x0b
  184. +#define MSHW0011_CMD_BAT0_CHGI 0x0c
  185. +#define MSHW0011_CMD_BAT0_ARTG 0x0d
  186. +
  187. +#define MSHW0011_NOTIFY_GET_VERSION 0x00
  188. +#define MSHW0011_NOTIFY_ADP1 0x01
  189. +#define MSHW0011_NOTIFY_BAT0_BST 0x02
  190. +#define MSHW0011_NOTIFY_BAT0_BIX 0x05
  191. +
  192. +#define MSHW0011_ADP1_REG_PSR 0x04
  193. +
  194. +#define MSHW0011_BAT0_REG_CAPACITY 0x0c
  195. +#define MSHW0011_BAT0_REG_FULL_CHG_CAPACITY 0x0e
  196. +#define MSHW0011_BAT0_REG_DESIGN_CAPACITY 0x40
  197. +#define MSHW0011_BAT0_REG_VOLTAGE 0x08
  198. +#define MSHW0011_BAT0_REG_RATE 0x14
  199. +#define MSHW0011_BAT0_REG_OEM 0x45
  200. +#define MSHW0011_BAT0_REG_TYPE 0x4e
  201. +#define MSHW0011_BAT0_REG_SERIAL_NO 0x56
  202. +#define MSHW0011_BAT0_REG_CYCLE_CNT 0x6e
  203. +
  204. +#define MSHW0011_EV_2_5 0x1ff
  205. +
  206. +static int
  207. +mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2,
  208. + unsigned int *ret_value)
  209. +{
  210. + static const guid_t mshw0011_guid =
  211. + GUID_INIT(0x3F99E367, 0x6220, 0x4955,
  212. + 0x8B, 0x0F, 0x06, 0xEF, 0x2A, 0xE7, 0x94, 0x12);
  213. + union acpi_object *obj;
  214. + struct acpi_device *adev;
  215. + acpi_handle handle;
  216. + unsigned int i;
  217. +
  218. + handle = ACPI_HANDLE(&cdata->adp1->dev);
  219. + if (!handle || acpi_bus_get_device(handle, &adev))
  220. + return -ENODEV;
  221. +
  222. + obj = acpi_evaluate_dsm_typed(handle, &mshw0011_guid, arg1, arg2, NULL,
  223. + ACPI_TYPE_BUFFER);
  224. + if (!obj) {
  225. + dev_err(&cdata->adp1->dev, "device _DSM execution failed\n");
  226. + return -ENODEV;
  227. + }
  228. +
  229. + *ret_value = 0;
  230. + for (i = 0; i < obj->buffer.length; i++)
  231. + *ret_value |= obj->buffer.pointer[i] << (i * 8);
  232. +
  233. + ACPI_FREE(obj);
  234. + return 0;
  235. +}
  236. +
  237. +static const struct bix default_bix = {
  238. + .revision = 0x00,
  239. + .power_unit = 0x01,
  240. + .design_capacity = 0x1dca,
  241. + .last_full_charg_capacity = 0x1dca,
  242. + .battery_technology = 0x01,
  243. + .design_voltage = 0x10df,
  244. + .design_capacity_of_warning = 0x8f,
  245. + .design_capacity_of_low = 0x47,
  246. + .cycle_count = 0xffffffff,
  247. + .measurement_accuracy = 0x00015f90,
  248. + .max_sampling_time = 0x03e8,
  249. + .min_sampling_time = 0x03e8,
  250. + .max_average_interval = 0x03e8,
  251. + .min_average_interval = 0x03e8,
  252. + .battery_capacity_granularity_1 = 0x45,
  253. + .battery_capacity_granularity_2 = 0x11,
  254. + .model = "P11G8M",
  255. + .serial = "",
  256. + .type = "LION",
  257. + .OEM = "",
  258. +};
  259. +
  260. +static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
  261. +{
  262. + struct i2c_client *client = cdata->bat0;
  263. + char buf[10];
  264. + int ret;
  265. +
  266. + *bix = default_bix;
  267. +
  268. + /* get design capacity */
  269. + ret = i2c_smbus_read_word_data(client,
  270. + MSHW0011_BAT0_REG_DESIGN_CAPACITY);
  271. + if (ret < 0) {
  272. + dev_err(&client->dev, "Error reading design capacity: %d\n",
  273. + ret);
  274. + return ret;
  275. + }
  276. + bix->design_capacity = ret;
  277. +
  278. + /* get last full charge capacity */
  279. + ret = i2c_smbus_read_word_data(client,
  280. + MSHW0011_BAT0_REG_FULL_CHG_CAPACITY);
  281. + if (ret < 0) {
  282. + dev_err(&client->dev,
  283. + "Error reading last full charge capacity: %d\n", ret);
  284. + return ret;
  285. + }
  286. + bix->last_full_charg_capacity = ret;
  287. +
  288. + /* get serial number */
  289. + ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_SERIAL_NO,
  290. + 10, buf);
  291. + if (ret != 10) {
  292. + dev_err(&client->dev, "Error reading serial no: %d\n", ret);
  293. + return ret;
  294. + }
  295. + snprintf(bix->serial, ARRAY_SIZE(bix->serial),
  296. + "%*pE%*pE", 3, buf + 7, 6, buf);
  297. +
  298. + /* get cycle count */
  299. + ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CYCLE_CNT);
  300. + if (ret < 0) {
  301. + dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
  302. + return ret;
  303. + }
  304. + bix->cycle_count = ret;
  305. +
  306. + /* get OEM name */
  307. + ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_OEM,
  308. + 4, buf);
  309. + if (ret != 4) {
  310. + dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
  311. + return ret;
  312. + }
  313. + snprintf(bix->OEM, ARRAY_SIZE(bix->OEM), "%*pE", 3, buf);
  314. +
  315. + return 0;
  316. +}
  317. +
  318. +static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
  319. +{
  320. + struct i2c_client *client = cdata->bat0;
  321. + int rate, capacity, voltage, state;
  322. + s16 tmp;
  323. +
  324. + rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);
  325. + if (rate < 0)
  326. + return rate;
  327. +
  328. + capacity = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CAPACITY);
  329. + if (capacity < 0)
  330. + return capacity;
  331. +
  332. + voltage = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_VOLTAGE);
  333. + if (voltage < 0)
  334. + return voltage;
  335. +
  336. + tmp = rate;
  337. + bst->battery_present_rate = abs((s32)tmp);
  338. +
  339. + state = 0;
  340. + if ((s32) tmp > 0)
  341. + state |= ACPI_BATTERY_STATE_CHARGING;
  342. + else if ((s32) tmp < 0)
  343. + state |= ACPI_BATTERY_STATE_DISCHARGING;
  344. + bst->battery_state = state;
  345. +
  346. + bst->battery_remaining_capacity = capacity;
  347. + bst->battery_present_voltage = voltage;
  348. +
  349. + return 0;
  350. +}
  351. +
  352. +static int mshw0011_adp_psr(struct mshw0011_data *cdata)
  353. +{
  354. + struct i2c_client *client = cdata->adp1;
  355. + int ret;
  356. +
  357. + ret = i2c_smbus_read_byte_data(client, MSHW0011_ADP1_REG_PSR);
  358. + if (ret < 0)
  359. + return ret;
  360. +
  361. + return ret;
  362. +}
  363. +
  364. +static int mshw0011_isr(struct mshw0011_data *cdata)
  365. +{
  366. + struct bst bst;
  367. + struct bix bix;
  368. + int ret;
  369. + bool status, bat_status;
  370. +
  371. + ret = mshw0011_adp_psr(cdata);
  372. + if (ret < 0)
  373. + return ret;
  374. +
  375. + status = ret;
  376. +
  377. + if (status != cdata->charging)
  378. + mshw0011_notify(cdata, cdata->notify_mask,
  379. + MSHW0011_NOTIFY_ADP1, &ret);
  380. +
  381. + cdata->charging = status;
  382. +
  383. + ret = mshw0011_bst(cdata, &bst);
  384. + if (ret < 0)
  385. + return ret;
  386. +
  387. + bat_status = bst.battery_state;
  388. +
  389. + if (bat_status != cdata->bat_charging)
  390. + mshw0011_notify(cdata, cdata->notify_mask,
  391. + MSHW0011_NOTIFY_BAT0_BST, &ret);
  392. +
  393. + cdata->bat_charging = bat_status;
  394. +
  395. + ret = mshw0011_bix(cdata, &bix);
  396. + if (ret < 0)
  397. + return ret;
  398. + if (bix.last_full_charg_capacity != cdata->full_capacity)
  399. + mshw0011_notify(cdata, cdata->notify_mask,
  400. + MSHW0011_NOTIFY_BAT0_BIX, &ret);
  401. +
  402. + cdata->full_capacity = bix.last_full_charg_capacity;
  403. +
  404. + return 0;
  405. +}
  406. +
  407. +static int mshw0011_poll_task(void *data)
  408. +{
  409. + struct mshw0011_data *cdata = data;
  410. + int ret = 0;
  411. +
  412. + cdata->kthread_running = true;
  413. +
  414. + set_freezable();
  415. +
  416. + while (!kthread_should_stop()) {
  417. + schedule_timeout_interruptible(POLL_INTERVAL);
  418. + try_to_freeze();
  419. + ret = mshw0011_isr(data);
  420. + if (ret)
  421. + break;
  422. + }
  423. +
  424. + cdata->kthread_running = false;
  425. + return ret;
  426. +}
  427. +
  428. +static acpi_status
  429. +mshw0011_space_handler(u32 function, acpi_physical_address command,
  430. + u32 bits, u64 *value64,
  431. + void *handler_context, void *region_context)
  432. +{
  433. + struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
  434. + struct mshw0011_handler_data *data = handler_context;
  435. + struct acpi_connection_info *info = &data->info;
  436. + struct acpi_resource_i2c_serialbus *sb;
  437. + struct i2c_client *client = data->client;
  438. + struct mshw0011_data *cdata = i2c_get_clientdata(client);
  439. + struct acpi_resource *ares;
  440. + u32 accessor_type = function >> 16;
  441. + acpi_status ret;
  442. + int status = 1;
  443. +
  444. + ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
  445. + if (ACPI_FAILURE(ret))
  446. + return ret;
  447. +
  448. + if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
  449. + ret = AE_BAD_PARAMETER;
  450. + goto err;
  451. + }
  452. +
  453. + sb = &ares->data.i2c_serial_bus;
  454. + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
  455. + ret = AE_BAD_PARAMETER;
  456. + goto err;
  457. + }
  458. +
  459. + if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {
  460. + ret = AE_BAD_PARAMETER;
  461. + goto err;
  462. + }
  463. +
  464. + if (gsb->cmd.arg0 == MSHW0011_CMD_DEST_ADP1 &&
  465. + gsb->cmd.arg1 == MSHW0011_CMD_ADP1_PSR) {
  466. + ret = mshw0011_adp_psr(cdata);
  467. + if (ret >= 0) {
  468. + status = ret;
  469. + ret = 0;
  470. + }
  471. + goto out;
  472. + }
  473. +
  474. + if (gsb->cmd.arg0 != MSHW0011_CMD_DEST_BAT0) {
  475. + ret = AE_BAD_PARAMETER;
  476. + goto err;
  477. + }
  478. +
  479. + switch (gsb->cmd.arg1) {
  480. + case MSHW0011_CMD_BAT0_STA:
  481. + break;
  482. + case MSHW0011_CMD_BAT0_BIX:
  483. + ret = mshw0011_bix(cdata, &gsb->bix);
  484. + break;
  485. + case MSHW0011_CMD_BAT0_BTP:
  486. + cdata->trip_point = gsb->cmd.arg2;
  487. + break;
  488. + case MSHW0011_CMD_BAT0_BST:
  489. + ret = mshw0011_bst(cdata, &gsb->bst);
  490. + break;
  491. + default:
  492. + pr_info("command(0x%02x) is not supported.\n", gsb->cmd.arg1);
  493. + ret = AE_BAD_PARAMETER;
  494. + goto err;
  495. + }
  496. +
  497. + out:
  498. + gsb->ret = status;
  499. + gsb->status = 0;
  500. +
  501. + err:
  502. + ACPI_FREE(ares);
  503. + return ret;
  504. +}
  505. +
  506. +static int mshw0011_install_space_handler(struct i2c_client *client)
  507. +{
  508. + acpi_handle handle;
  509. + struct mshw0011_handler_data *data;
  510. + acpi_status status;
  511. +
  512. + handle = ACPI_HANDLE(&client->dev);
  513. +
  514. + if (!handle)
  515. + return -ENODEV;
  516. +
  517. + data = kzalloc(sizeof(struct mshw0011_handler_data),
  518. + GFP_KERNEL);
  519. + if (!data)
  520. + return -ENOMEM;
  521. +
  522. + data->client = client;
  523. + status = acpi_bus_attach_private_data(handle, (void *)data);
  524. + if (ACPI_FAILURE(status)) {
  525. + kfree(data);
  526. + return -ENOMEM;
  527. + }
  528. +
  529. + status = acpi_install_address_space_handler(handle,
  530. + ACPI_ADR_SPACE_GSBUS,
  531. + &mshw0011_space_handler,
  532. + NULL,
  533. + data);
  534. + if (ACPI_FAILURE(status)) {
  535. + dev_err(&client->dev, "Error installing i2c space handler\n");
  536. + acpi_bus_detach_private_data(handle);
  537. + kfree(data);
  538. + return -ENOMEM;
  539. + }
  540. +
  541. + acpi_walk_dep_device_list(handle);
  542. + return 0;
  543. +}
  544. +
  545. +static void mshw0011_remove_space_handler(struct i2c_client *client)
  546. +{
  547. + acpi_handle handle = ACPI_HANDLE(&client->dev);
  548. + struct mshw0011_handler_data *data;
  549. + acpi_status status;
  550. +
  551. + if (!handle)
  552. + return;
  553. +
  554. + acpi_remove_address_space_handler(handle,
  555. + ACPI_ADR_SPACE_GSBUS,
  556. + &mshw0011_space_handler);
  557. +
  558. + status = acpi_bus_get_private_data(handle, (void **)&data);
  559. + if (ACPI_SUCCESS(status))
  560. + kfree(data);
  561. +
  562. + acpi_bus_detach_private_data(handle);
  563. +}
  564. +
  565. +static int mshw0011_probe(struct i2c_client *client)
  566. +{
  567. + struct i2c_board_info board_info;
  568. + struct device *dev = &client->dev;
  569. + struct i2c_client *bat0;
  570. +
  571. + struct mshw0011_data *data;
  572. + int error, mask;
  573. +
  574. + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  575. + if (!data)
  576. + return -ENOMEM;
  577. +
  578. + data->adp1 = client;
  579. + i2c_set_clientdata(client, data);
  580. +
  581. + memset(&board_info, 0, sizeof(board_info));
  582. + strlcpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE);
  583. +
  584. + bat0 = i2c_acpi_new_device(dev, 1, &board_info);
  585. + if (!bat0)
  586. + return -ENOMEM;
  587. +
  588. + data->bat0 = bat0;
  589. + i2c_set_clientdata(bat0, data);
  590. +
  591. + error = mshw0011_notify(data, 1, MSHW0011_NOTIFY_GET_VERSION, &mask);
  592. + if (error)
  593. + goto out_err;
  594. +
  595. + data->notify_mask = mask == MSHW0011_EV_2_5;
  596. +
  597. + data->poll_task = kthread_run(mshw0011_poll_task, data, "mshw0011_adp");
  598. + if (IS_ERR(data->poll_task)) {
  599. + error = PTR_ERR(data->poll_task);
  600. + dev_err(&client->dev, "Unable to run kthread err %d\n", error);
  601. + goto out_err;
  602. + }
  603. +
  604. + error = mshw0011_install_space_handler(client);
  605. + if (error)
  606. + goto out_err;
  607. +
  608. + return 0;
  609. +
  610. +out_err:
  611. + if (data->kthread_running)
  612. + kthread_stop(data->poll_task);
  613. + i2c_unregister_device(data->bat0);
  614. + return error;
  615. +}
  616. +
  617. +static int mshw0011_remove(struct i2c_client *client)
  618. +{
  619. + struct mshw0011_data *cdata = i2c_get_clientdata(client);
  620. +
  621. + mshw0011_remove_space_handler(client);
  622. +
  623. + if (cdata->kthread_running)
  624. + kthread_stop(cdata->poll_task);
  625. +
  626. + i2c_unregister_device(cdata->bat0);
  627. +
  628. + return 0;
  629. +}
  630. +
  631. +static const struct acpi_device_id mshw0011_acpi_match[] = {
  632. + { "MSHW0011", 0 },
  633. + { }
  634. +};
  635. +MODULE_DEVICE_TABLE(acpi, mshw0011_acpi_match);
  636. +
  637. +static struct i2c_driver mshw0011_driver = {
  638. + .probe_new = mshw0011_probe,
  639. + .remove = mshw0011_remove,
  640. + .driver = {
  641. + .name = "mshw0011",
  642. + .acpi_match_table = ACPI_PTR(mshw0011_acpi_match),
  643. + },
  644. +};
  645. +module_i2c_driver(mshw0011_driver);
  646. +
  647. +MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
  648. +MODULE_DESCRIPTION("mshw0011 driver");
  649. +MODULE_LICENSE("GPL v2");
  650. --
  651. 2.28.0