toshiba_bluetooth: Adapt *_enable, *_notify and *_resume functions to rfkill
[firefly-linux-kernel-4.4.55.git] / drivers / platform / x86 / toshiba_bluetooth.c
1 /*
2  * Toshiba Bluetooth Enable Driver
3  *
4  * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
5  * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com>
6  *
7  * Thanks to Matthew Garrett for background info on ACPI innards which
8  * normal people aren't meant to understand :-)
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/init.h>
20 #include <linux/types.h>
21 #include <linux/acpi.h>
22 #include <linux/rfkill.h>
23
24 #define BT_KILLSWITCH_MASK      0x01
25 #define BT_PLUGGED_MASK         0x40
26 #define BT_POWER_MASK           0x80
27
28 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
29 MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
30 MODULE_LICENSE("GPL");
31
32 struct toshiba_bluetooth_dev {
33         struct acpi_device *acpi_dev;
34         struct rfkill *rfk;
35
36         bool killswitch;
37         bool plugged;
38         bool powered;
39 };
40
41 static int toshiba_bt_rfkill_add(struct acpi_device *device);
42 static int toshiba_bt_rfkill_remove(struct acpi_device *device);
43 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
44
45 static const struct acpi_device_id bt_device_ids[] = {
46         { "TOS6205", 0},
47         { "", 0},
48 };
49 MODULE_DEVICE_TABLE(acpi, bt_device_ids);
50
51 #ifdef CONFIG_PM_SLEEP
52 static int toshiba_bt_resume(struct device *dev);
53 #endif
54 static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
55
56 static struct acpi_driver toshiba_bt_rfkill_driver = {
57         .name =         "Toshiba BT",
58         .class =        "Toshiba",
59         .ids =          bt_device_ids,
60         .ops =          {
61                                 .add =          toshiba_bt_rfkill_add,
62                                 .remove =       toshiba_bt_rfkill_remove,
63                                 .notify =       toshiba_bt_rfkill_notify,
64                         },
65         .owner =        THIS_MODULE,
66         .drv.pm =       &toshiba_bt_pm,
67 };
68
69 static int toshiba_bluetooth_present(acpi_handle handle)
70 {
71         acpi_status result;
72         u64 bt_present;
73
74         /*
75          * Some Toshiba laptops may have a fake TOS6205 device in
76          * their ACPI BIOS, so query the _STA method to see if there
77          * is really anything there.
78          */
79         result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present);
80         if (ACPI_FAILURE(result)) {
81                 pr_err("ACPI call to query Bluetooth presence failed");
82                 return -ENXIO;
83         } else if (!bt_present) {
84                 pr_info("Bluetooth device not present\n");
85                 return -ENODEV;
86         }
87
88         return 0;
89 }
90
91 static int toshiba_bluetooth_status(acpi_handle handle)
92 {
93         acpi_status result;
94         u64 status;
95
96         result = acpi_evaluate_integer(handle, "BTST", NULL, &status);
97         if (ACPI_FAILURE(result)) {
98                 pr_err("Could not get Bluetooth device status\n");
99                 return -ENXIO;
100         }
101
102         pr_info("Bluetooth status %llu\n", status);
103
104         return status;
105 }
106
107 static int toshiba_bluetooth_enable(acpi_handle handle)
108 {
109         acpi_status result;
110
111         result = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
112         if (ACPI_FAILURE(result)) {
113                 pr_err("Could not attach USB Bluetooth device\n");
114                 return -ENXIO;
115         }
116
117         result = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
118         if (ACPI_FAILURE(result)) {
119                 pr_err("Could not power ON Bluetooth device\n");
120                 return -ENXIO;
121         }
122
123         return 0;
124 }
125
126 static int toshiba_bluetooth_disable(acpi_handle handle)
127 {
128         acpi_status result;
129
130         result = acpi_evaluate_object(handle, "BTPF", NULL, NULL);
131         if (ACPI_FAILURE(result)) {
132                 pr_err("Could not power OFF Bluetooth device\n");
133                 return -ENXIO;
134         }
135
136         result = acpi_evaluate_object(handle, "DUSB", NULL, NULL);
137         if (ACPI_FAILURE(result)) {
138                 pr_err("Could not detach USB Bluetooth device\n");
139                 return -ENXIO;
140         }
141
142         return 0;
143 }
144
145 /* Helper function */
146 static int toshiba_bluetooth_sync_status(struct toshiba_bluetooth_dev *bt_dev)
147 {
148         int status;
149
150         status = toshiba_bluetooth_status(bt_dev->acpi_dev->handle);
151         if (status < 0) {
152                 pr_err("Could not sync bluetooth device status\n");
153                 return status;
154         }
155
156         bt_dev->killswitch = (status & BT_KILLSWITCH_MASK) ? true : false;
157         bt_dev->plugged = (status & BT_PLUGGED_MASK) ? true : false;
158         bt_dev->powered = (status & BT_POWER_MASK) ? true : false;
159
160         return 0;
161 }
162
163 /* RFKill handlers */
164 static int bt_rfkill_set_block(void *data, bool blocked)
165 {
166         struct toshiba_bluetooth_dev *bt_dev = data;
167         int ret;
168
169         ret = toshiba_bluetooth_sync_status(bt_dev);
170         if (ret)
171                 return ret;
172
173         if (!bt_dev->killswitch)
174                 return 0;
175
176         if (blocked)
177                 ret = toshiba_bluetooth_disable(bt_dev->acpi_dev->handle);
178         else
179                 ret = toshiba_bluetooth_enable(bt_dev->acpi_dev->handle);
180
181         return ret;
182 }
183
184 static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
185 {
186         struct toshiba_bluetooth_dev *bt_dev = data;
187
188         if (toshiba_bluetooth_sync_status(bt_dev))
189                 return;
190
191         /*
192          * Note the Toshiba Bluetooth RFKill switch seems to be a strange
193          * fish. It only provides a BT event when the switch is flipped to
194          * the 'on' position. When flipping it to 'off', the USB device is
195          * simply pulled away underneath us, without any BT event being
196          * delivered.
197          */
198         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
199 }
200
201 static const struct rfkill_ops rfk_ops = {
202         .set_block = bt_rfkill_set_block,
203         .poll = bt_rfkill_poll,
204 };
205
206 /* ACPI driver functions */
207 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
208 {
209         struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
210
211         if (toshiba_bluetooth_sync_status(bt_dev))
212                 return;
213
214         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
215 }
216
217 #ifdef CONFIG_PM_SLEEP
218 static int toshiba_bt_resume(struct device *dev)
219 {
220         struct toshiba_bluetooth_dev *bt_dev;
221         int ret;
222
223         bt_dev = acpi_driver_data(to_acpi_device(dev));
224
225         ret = toshiba_bluetooth_sync_status(bt_dev);
226         if (ret)
227                 return ret;
228
229         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
230
231         return 0;
232 }
233 #endif
234
235 static int toshiba_bt_rfkill_add(struct acpi_device *device)
236 {
237         struct toshiba_bluetooth_dev *bt_dev;
238         int result;
239
240         result = toshiba_bluetooth_present(device->handle);
241         if (result)
242                 return result;
243
244         pr_info("Toshiba ACPI Bluetooth device driver\n");
245
246         bt_dev = kzalloc(sizeof(*bt_dev), GFP_KERNEL);
247         if (!bt_dev)
248                 return -ENOMEM;
249         bt_dev->acpi_dev = device;
250         device->driver_data = bt_dev;
251         dev_set_drvdata(&device->dev, bt_dev);
252
253         result = toshiba_bluetooth_sync_status(bt_dev);
254         if (result) {
255                 kfree(bt_dev);
256                 return result;
257         }
258
259         bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth",
260                                    &device->dev,
261                                    RFKILL_TYPE_BLUETOOTH,
262                                    &rfk_ops,
263                                    bt_dev);
264         if (!bt_dev->rfk) {
265                 pr_err("Unable to allocate rfkill device\n");
266                 kfree(bt_dev);
267                 return -ENOMEM;
268         }
269
270         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
271
272         result = rfkill_register(bt_dev->rfk);
273         if (result) {
274                 pr_err("Unable to register rfkill device\n");
275                 rfkill_destroy(bt_dev->rfk);
276                 kfree(bt_dev);
277         }
278
279         return result;
280 }
281
282 static int toshiba_bt_rfkill_remove(struct acpi_device *device)
283 {
284         struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
285
286         /* clean up */
287         if (bt_dev->rfk) {
288                 rfkill_unregister(bt_dev->rfk);
289                 rfkill_destroy(bt_dev->rfk);
290         }
291
292         kfree(bt_dev);
293
294         return toshiba_bluetooth_disable(device->handle);
295 }
296
297 module_acpi_driver(toshiba_bt_rfkill_driver);