Skip to content

Commit 4c33162

Browse files
l1kholtmann
authored andcommitted
Bluetooth: hci_bcm: Support Apple GPIO handling
Enable Bluetooth on the following Macs which provide custom ACPI methods to toggle the GPIOs for device wake and shutdown instead of accessing the pins directly: MacBook8,1 2015 12" MacBook9,1 2016 12" MacBook10,1 2017 12" MacBookPro13,1 2016 13" MacBookPro13,2 2016 13" with Touch Bar MacBookPro13,3 2016 15" with Touch Bar MacBookPro14,1 2017 13" MacBookPro14,2 2017 13" with Touch Bar MacBookPro14,3 2017 15" with Touch Bar On the MacBook8,1 Bluetooth is muxed with a second device (a debug port on the SSD) under the control of PCH GPIO 36. Because serdev cannot deal with multiple slaves yet, it is currently necessary to patch the DSDT and remove the SSDC device. The custom ACPI methods are called: BTLP (Low Power) takes one argument, toggles device wake GPIO BTPU (Power Up) tells SMC to drive shutdown GPIO high BTPD (Power Down) tells SMC to drive shutdown GPIO low BTRS (Reset) calls BTPD followed by BTPU BTRB unknown, not present on all MacBooks Search for the BTLP, BTPU and BTPD methods on ->probe and cache them in struct bcm_device if the machine is a Mac. Additionally, set the init_speed based on a custom device property provided by Apple in lieu of _CRS resources. The Broadcom UART's speed is fixed on Apple Macs: Any attempt to change it results in Bluetooth status code 0x0c and bcm_set_baudrate() thus always returns -EBUSY. By setting only the init_speed and leaving oper_speed at zero, we can achieve that the host UART's speed is adjusted but the Broadcom UART's speed is left as is. The host wake pin goes into the SMC which handles it independently of the OS, so there's no IRQ for it. Thanks to Ronald Tschalär who did extensive debugging and testing of this patch and contributed fixes. ACPI snippet containing the custom methods and device properties (taken from a MacBook8,1): Method (BTLP, 1, Serialized) { If (LEqual (Arg0, 0x00)) { Store (0x01, GD54) /* set PCH GPIO 54 direction to input */ } If (LEqual (Arg0, 0x01)) { Store (0x00, GD54) /* set PCH GPIO 54 direction to output */ Store (0x00, GP54) /* set PCH GPIO 54 value to low */ } } Method (BTPU, 0, Serialized) { Store (0x01, \_SB.PCI0.LPCB.EC.BTPC) Sleep (0x0A) } Method (BTPD, 0, Serialized) { Store (0x00, \_SB.PCI0.LPCB.EC.BTPC) Sleep (0x0A) } Method (BTRS, 0, Serialized) { BTPD () BTPU () } Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method { If (LEqual (Arg0, ToUUID ("a0b5b7c6-1318-441c-b0c9-fe695eaf949b"))) { Store (Package (0x08) { "baud", Buffer (0x08) { 0xC0, 0xC6, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00 }, "parity", Buffer (0x08) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "dataBits", Buffer (0x08) { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "stopBits", Buffer (0x08) { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, Local0) DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0)) Return (Local0) } Return (0x00) } Link: Dunedan/mbp-2016-linux#29 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=110901 Reported-by: Leif Liddy <[email protected]> Cc: Mika Westerberg <[email protected]> Cc: Frédéric Danis <[email protected]> Cc: Loic Poulain <[email protected]> Cc: Hans de Goede <[email protected]> Tested-by: Max Shavrick <[email protected]> [MacBook8,1] Tested-by: Leif Liddy <[email protected]> [MacBook9,1] Tested-by: Daniel Roschka <[email protected]> [MacBookPro13,2] Tested-by: Ronald Tschalär <[email protected]> [MacBookPro13,3] Tested-by: Peter Y. Chuang <[email protected]> [MacBookPro14,1] Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Ronald Tschalär <[email protected]> Signed-off-by: Lukas Wunner <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 8bfa7e1 commit 4c33162

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

drivers/bluetooth/hci_bcm.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/acpi.h>
3030
#include <linux/of.h>
3131
#include <linux/property.h>
32+
#include <linux/platform_data/x86/apple.h>
3233
#include <linux/platform_device.h>
3334
#include <linux/clk.h>
3435
#include <linux/gpio/consumer.h>
@@ -64,7 +65,12 @@
6465
* @shutdown: BT_REG_ON pin,
6566
* power up or power down Bluetooth device internal regulators
6667
* @set_device_wakeup: callback to toggle BT_WAKE pin
68+
* either by accessing @device_wakeup or by calling @btlp
6769
* @set_shutdown: callback to toggle BT_REG_ON pin
70+
* either by accessing @shutdown or by calling @btpu/@btpd
71+
* @btlp: Apple ACPI method to toggle BT_WAKE pin ("Bluetooth Low Power")
72+
* @btpu: Apple ACPI method to drive BT_REG_ON pin high ("Bluetooth Power Up")
73+
* @btpd: Apple ACPI method to drive BT_REG_ON pin low ("Bluetooth Power Down")
6874
* @clk: clock used by Bluetooth device
6975
* @clk_enabled: whether @clk is prepared and enabled
7076
* @init_speed: default baudrate of Bluetooth device;
@@ -90,6 +96,9 @@ struct bcm_device {
9096
struct gpio_desc *shutdown;
9197
int (*set_device_wakeup)(struct bcm_device *, bool);
9298
int (*set_shutdown)(struct bcm_device *, bool);
99+
#ifdef CONFIG_ACPI
100+
acpi_handle btlp, btpu, btpd;
101+
#endif
93102

94103
struct clk *clk;
95104
bool clk_enabled;
@@ -844,6 +853,49 @@ static int bcm_resource(struct acpi_resource *ares, void *data)
844853

845854
return 0;
846855
}
856+
857+
static int bcm_apple_set_device_wakeup(struct bcm_device *dev, bool awake)
858+
{
859+
if (ACPI_FAILURE(acpi_execute_simple_method(dev->btlp, NULL, !awake)))
860+
return -EIO;
861+
862+
return 0;
863+
}
864+
865+
static int bcm_apple_set_shutdown(struct bcm_device *dev, bool powered)
866+
{
867+
if (ACPI_FAILURE(acpi_evaluate_object(powered ? dev->btpu : dev->btpd,
868+
NULL, NULL, NULL)))
869+
return -EIO;
870+
871+
return 0;
872+
}
873+
874+
static int bcm_apple_get_resources(struct bcm_device *dev)
875+
{
876+
struct acpi_device *adev = ACPI_COMPANION(dev->dev);
877+
const union acpi_object *obj;
878+
879+
if (!adev ||
880+
ACPI_FAILURE(acpi_get_handle(adev->handle, "BTLP", &dev->btlp)) ||
881+
ACPI_FAILURE(acpi_get_handle(adev->handle, "BTPU", &dev->btpu)) ||
882+
ACPI_FAILURE(acpi_get_handle(adev->handle, "BTPD", &dev->btpd)))
883+
return -ENODEV;
884+
885+
if (!acpi_dev_get_property(adev, "baud", ACPI_TYPE_BUFFER, &obj) &&
886+
obj->buffer.length == 8)
887+
dev->init_speed = *(u64 *)obj->buffer.pointer;
888+
889+
dev->set_device_wakeup = bcm_apple_set_device_wakeup;
890+
dev->set_shutdown = bcm_apple_set_shutdown;
891+
892+
return 0;
893+
}
894+
#else
895+
static inline int bcm_apple_get_resources(struct bcm_device *dev)
896+
{
897+
return -EOPNOTSUPP;
898+
}
847899
#endif /* CONFIG_ACPI */
848900

849901
static int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake)
@@ -862,6 +914,9 @@ static int bcm_get_resources(struct bcm_device *dev)
862914
{
863915
dev->name = dev_name(dev->dev);
864916

917+
if (x86_apple_machine && !bcm_apple_get_resources(dev))
918+
return 0;
919+
865920
dev->clk = devm_clk_get(dev->dev, NULL);
866921

867922
dev->device_wakeup = devm_gpiod_get(dev->dev, "device-wakeup",

0 commit comments

Comments
 (0)