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