0001-surface3-power.patch 17 KB

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