18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Bluetooth HCI UART driver for Broadcom devices 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2015 Intel Corporation 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci#include <linux/firmware.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/acpi.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 178c2ecf20Sopenharmony_ci#include <linux/property.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/apple.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/clk.h> 228c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 238c2ecf20Sopenharmony_ci#include <linux/tty.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <linux/dmi.h> 268c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 278c2ecf20Sopenharmony_ci#include <linux/serdev.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 308c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "btbcm.h" 338c2ecf20Sopenharmony_ci#include "hci_uart.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define BCM_NULL_PKT 0x00 368c2ecf20Sopenharmony_ci#define BCM_NULL_SIZE 0 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define BCM_LM_DIAG_PKT 0x07 398c2ecf20Sopenharmony_ci#define BCM_LM_DIAG_SIZE 63 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define BCM_TYPE49_PKT 0x31 428c2ecf20Sopenharmony_ci#define BCM_TYPE49_SIZE 0 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define BCM_TYPE52_PKT 0x34 458c2ecf20Sopenharmony_ci#define BCM_TYPE52_SIZE 0 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define BCM_NUM_SUPPLIES 2 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/** 528c2ecf20Sopenharmony_ci * struct bcm_device_data - device specific data 538c2ecf20Sopenharmony_ci * @no_early_set_baudrate: Disallow set baudrate before driver setup() 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistruct bcm_device_data { 568c2ecf20Sopenharmony_ci bool no_early_set_baudrate; 578c2ecf20Sopenharmony_ci bool drive_rts_on_open; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/** 618c2ecf20Sopenharmony_ci * struct bcm_device - device driver resources 628c2ecf20Sopenharmony_ci * @serdev_hu: HCI UART controller struct 638c2ecf20Sopenharmony_ci * @list: bcm_device_list node 648c2ecf20Sopenharmony_ci * @dev: physical UART slave 658c2ecf20Sopenharmony_ci * @name: device name logged by bt_dev_*() functions 668c2ecf20Sopenharmony_ci * @device_wakeup: BT_WAKE pin, 678c2ecf20Sopenharmony_ci * assert = Bluetooth device must wake up or remain awake, 688c2ecf20Sopenharmony_ci * deassert = Bluetooth device may sleep when sleep criteria are met 698c2ecf20Sopenharmony_ci * @shutdown: BT_REG_ON pin, 708c2ecf20Sopenharmony_ci * power up or power down Bluetooth device internal regulators 718c2ecf20Sopenharmony_ci * @set_device_wakeup: callback to toggle BT_WAKE pin 728c2ecf20Sopenharmony_ci * either by accessing @device_wakeup or by calling @btlp 738c2ecf20Sopenharmony_ci * @set_shutdown: callback to toggle BT_REG_ON pin 748c2ecf20Sopenharmony_ci * either by accessing @shutdown or by calling @btpu/@btpd 758c2ecf20Sopenharmony_ci * @btlp: Apple ACPI method to toggle BT_WAKE pin ("Bluetooth Low Power") 768c2ecf20Sopenharmony_ci * @btpu: Apple ACPI method to drive BT_REG_ON pin high ("Bluetooth Power Up") 778c2ecf20Sopenharmony_ci * @btpd: Apple ACPI method to drive BT_REG_ON pin low ("Bluetooth Power Down") 788c2ecf20Sopenharmony_ci * @txco_clk: external reference frequency clock used by Bluetooth device 798c2ecf20Sopenharmony_ci * @lpo_clk: external LPO clock used by Bluetooth device 808c2ecf20Sopenharmony_ci * @supplies: VBAT and VDDIO supplies used by Bluetooth device 818c2ecf20Sopenharmony_ci * @res_enabled: whether clocks and supplies are prepared and enabled 828c2ecf20Sopenharmony_ci * @init_speed: default baudrate of Bluetooth device; 838c2ecf20Sopenharmony_ci * the host UART is initially set to this baudrate so that 848c2ecf20Sopenharmony_ci * it can configure the Bluetooth device for @oper_speed 858c2ecf20Sopenharmony_ci * @oper_speed: preferred baudrate of Bluetooth device; 868c2ecf20Sopenharmony_ci * set to 0 if @init_speed is already the preferred baudrate 878c2ecf20Sopenharmony_ci * @irq: interrupt triggered by HOST_WAKE_BT pin 888c2ecf20Sopenharmony_ci * @irq_active_low: whether @irq is active low 898c2ecf20Sopenharmony_ci * @hu: pointer to HCI UART controller struct, 908c2ecf20Sopenharmony_ci * used to disable flow control during runtime suspend and system sleep 918c2ecf20Sopenharmony_ci * @is_suspended: whether flow control is currently disabled 928c2ecf20Sopenharmony_ci * @no_early_set_baudrate: don't set_baudrate before setup() 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_cistruct bcm_device { 958c2ecf20Sopenharmony_ci /* Must be the first member, hci_serdev.c expects this. */ 968c2ecf20Sopenharmony_ci struct hci_uart serdev_hu; 978c2ecf20Sopenharmony_ci struct list_head list; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct device *dev; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci const char *name; 1028c2ecf20Sopenharmony_ci struct gpio_desc *device_wakeup; 1038c2ecf20Sopenharmony_ci struct gpio_desc *shutdown; 1048c2ecf20Sopenharmony_ci int (*set_device_wakeup)(struct bcm_device *, bool); 1058c2ecf20Sopenharmony_ci int (*set_shutdown)(struct bcm_device *, bool); 1068c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 1078c2ecf20Sopenharmony_ci acpi_handle btlp, btpu, btpd; 1088c2ecf20Sopenharmony_ci int gpio_count; 1098c2ecf20Sopenharmony_ci int gpio_int_idx; 1108c2ecf20Sopenharmony_ci#endif 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci struct clk *txco_clk; 1138c2ecf20Sopenharmony_ci struct clk *lpo_clk; 1148c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[BCM_NUM_SUPPLIES]; 1158c2ecf20Sopenharmony_ci bool res_enabled; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci u32 init_speed; 1188c2ecf20Sopenharmony_ci u32 oper_speed; 1198c2ecf20Sopenharmony_ci int irq; 1208c2ecf20Sopenharmony_ci bool irq_active_low; 1218c2ecf20Sopenharmony_ci bool irq_acquired; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1248c2ecf20Sopenharmony_ci struct hci_uart *hu; 1258c2ecf20Sopenharmony_ci bool is_suspended; 1268c2ecf20Sopenharmony_ci#endif 1278c2ecf20Sopenharmony_ci bool no_early_set_baudrate; 1288c2ecf20Sopenharmony_ci bool drive_rts_on_open; 1298c2ecf20Sopenharmony_ci u8 pcm_int_params[5]; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* generic bcm uart resources */ 1338c2ecf20Sopenharmony_cistruct bcm_data { 1348c2ecf20Sopenharmony_ci struct sk_buff *rx_skb; 1358c2ecf20Sopenharmony_ci struct sk_buff_head txq; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci struct bcm_device *dev; 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* List of BCM BT UART devices */ 1418c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(bcm_device_lock); 1428c2ecf20Sopenharmony_cistatic LIST_HEAD(bcm_device_list); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int irq_polarity = -1; 1458c2ecf20Sopenharmony_cimodule_param(irq_polarity, int, 0444); 1468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq_polarity, "IRQ polarity 0: active-high 1: active-low"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci if (hu->serdev) 1518c2ecf20Sopenharmony_ci serdev_device_set_baudrate(hu->serdev, speed); 1528c2ecf20Sopenharmony_ci else 1538c2ecf20Sopenharmony_ci hci_uart_set_baudrate(hu, speed); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct hci_dev *hdev = hu->hdev; 1598c2ecf20Sopenharmony_ci struct sk_buff *skb; 1608c2ecf20Sopenharmony_ci struct bcm_update_uart_baud_rate param; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (speed > 3000000) { 1638c2ecf20Sopenharmony_ci struct bcm_write_uart_clock_setting clock; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci clock.type = BCM_UART_CLOCK_48MHZ; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "Set Controller clock (%d)", clock.type); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* This Broadcom specific command changes the UART's controller 1708c2ecf20Sopenharmony_ci * clock for baud rate > 3000000. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci skb = __hci_cmd_sync(hdev, 0xfc45, 1, &clock, HCI_INIT_TIMEOUT); 1738c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 1748c2ecf20Sopenharmony_ci int err = PTR_ERR(skb); 1758c2ecf20Sopenharmony_ci bt_dev_err(hdev, "BCM: failed to write clock (%d)", 1768c2ecf20Sopenharmony_ci err); 1778c2ecf20Sopenharmony_ci return err; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci kfree_skb(skb); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "Set Controller UART speed to %d bit/s", speed); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci param.zero = cpu_to_le16(0); 1868c2ecf20Sopenharmony_ci param.baud_rate = cpu_to_le32(speed); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* This Broadcom specific command changes the UART's controller baud 1898c2ecf20Sopenharmony_ci * rate. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci skb = __hci_cmd_sync(hdev, 0xfc18, sizeof(param), ¶m, 1928c2ecf20Sopenharmony_ci HCI_INIT_TIMEOUT); 1938c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 1948c2ecf20Sopenharmony_ci int err = PTR_ERR(skb); 1958c2ecf20Sopenharmony_ci bt_dev_err(hdev, "BCM: failed to write update baudrate (%d)", 1968c2ecf20Sopenharmony_ci err); 1978c2ecf20Sopenharmony_ci return err; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci kfree_skb(skb); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* bcm_device_exists should be protected by bcm_device_lock */ 2068c2ecf20Sopenharmony_cistatic bool bcm_device_exists(struct bcm_device *device) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct list_head *p; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 2118c2ecf20Sopenharmony_ci /* Devices using serdev always exist */ 2128c2ecf20Sopenharmony_ci if (device && device->hu && device->hu->serdev) 2138c2ecf20Sopenharmony_ci return true; 2148c2ecf20Sopenharmony_ci#endif 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci list_for_each(p, &bcm_device_list) { 2178c2ecf20Sopenharmony_ci struct bcm_device *dev = list_entry(p, struct bcm_device, list); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (device == dev) 2208c2ecf20Sopenharmony_ci return true; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return false; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int bcm_gpio_set_power(struct bcm_device *dev, bool powered) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int err; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (powered && !dev->res_enabled) { 2318c2ecf20Sopenharmony_ci /* Intel Macs use bcm_apple_get_resources() and don't 2328c2ecf20Sopenharmony_ci * have regulator supplies configured. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (dev->supplies[0].supply) { 2358c2ecf20Sopenharmony_ci err = regulator_bulk_enable(BCM_NUM_SUPPLIES, 2368c2ecf20Sopenharmony_ci dev->supplies); 2378c2ecf20Sopenharmony_ci if (err) 2388c2ecf20Sopenharmony_ci return err; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* LPO clock needs to be 32.768 kHz */ 2428c2ecf20Sopenharmony_ci err = clk_set_rate(dev->lpo_clk, 32768); 2438c2ecf20Sopenharmony_ci if (err) { 2448c2ecf20Sopenharmony_ci dev_err(dev->dev, "Could not set LPO clock rate\n"); 2458c2ecf20Sopenharmony_ci goto err_regulator_disable; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->lpo_clk); 2498c2ecf20Sopenharmony_ci if (err) 2508c2ecf20Sopenharmony_ci goto err_regulator_disable; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->txco_clk); 2538c2ecf20Sopenharmony_ci if (err) 2548c2ecf20Sopenharmony_ci goto err_lpo_clk_disable; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci err = dev->set_shutdown(dev, powered); 2588c2ecf20Sopenharmony_ci if (err) 2598c2ecf20Sopenharmony_ci goto err_txco_clk_disable; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci err = dev->set_device_wakeup(dev, powered); 2628c2ecf20Sopenharmony_ci if (err) 2638c2ecf20Sopenharmony_ci goto err_revert_shutdown; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!powered && dev->res_enabled) { 2668c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->txco_clk); 2678c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->lpo_clk); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Intel Macs use bcm_apple_get_resources() and don't 2708c2ecf20Sopenharmony_ci * have regulator supplies configured. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci if (dev->supplies[0].supply) 2738c2ecf20Sopenharmony_ci regulator_bulk_disable(BCM_NUM_SUPPLIES, 2748c2ecf20Sopenharmony_ci dev->supplies); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* wait for device to power on and come out of reset */ 2788c2ecf20Sopenharmony_ci usleep_range(100000, 120000); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci dev->res_enabled = powered; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cierr_revert_shutdown: 2858c2ecf20Sopenharmony_ci dev->set_shutdown(dev, !powered); 2868c2ecf20Sopenharmony_cierr_txco_clk_disable: 2878c2ecf20Sopenharmony_ci if (powered && !dev->res_enabled) 2888c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->txco_clk); 2898c2ecf20Sopenharmony_cierr_lpo_clk_disable: 2908c2ecf20Sopenharmony_ci if (powered && !dev->res_enabled) 2918c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->lpo_clk); 2928c2ecf20Sopenharmony_cierr_regulator_disable: 2938c2ecf20Sopenharmony_ci if (powered && !dev->res_enabled) 2948c2ecf20Sopenharmony_ci regulator_bulk_disable(BCM_NUM_SUPPLIES, dev->supplies); 2958c2ecf20Sopenharmony_ci return err; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 2998c2ecf20Sopenharmony_cistatic irqreturn_t bcm_host_wake(int irq, void *data) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct bcm_device *bdev = data; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "Host wake IRQ"); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci pm_runtime_get(bdev->dev); 3068c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdev->dev); 3078c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdev->dev); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int bcm_request_irq(struct bcm_data *bcm) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct bcm_device *bdev = bcm->dev; 3158c2ecf20Sopenharmony_ci int err; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 3188c2ecf20Sopenharmony_ci if (!bcm_device_exists(bdev)) { 3198c2ecf20Sopenharmony_ci err = -ENODEV; 3208c2ecf20Sopenharmony_ci goto unlock; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (bdev->irq <= 0) { 3248c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 3258c2ecf20Sopenharmony_ci goto unlock; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci err = devm_request_irq(bdev->dev, bdev->irq, bcm_host_wake, 3298c2ecf20Sopenharmony_ci bdev->irq_active_low ? IRQF_TRIGGER_FALLING : 3308c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING, 3318c2ecf20Sopenharmony_ci "host_wake", bdev); 3328c2ecf20Sopenharmony_ci if (err) { 3338c2ecf20Sopenharmony_ci bdev->irq = err; 3348c2ecf20Sopenharmony_ci goto unlock; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci bdev->irq_acquired = true; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci device_init_wakeup(bdev->dev, true); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(bdev->dev, 3428c2ecf20Sopenharmony_ci BCM_AUTOSUSPEND_DELAY); 3438c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(bdev->dev); 3448c2ecf20Sopenharmony_ci pm_runtime_set_active(bdev->dev); 3458c2ecf20Sopenharmony_ci pm_runtime_enable(bdev->dev); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciunlock: 3488c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return err; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic const struct bcm_set_sleep_mode default_sleep_params = { 3548c2ecf20Sopenharmony_ci .sleep_mode = 1, /* 0=Disabled, 1=UART, 2=Reserved, 3=USB */ 3558c2ecf20Sopenharmony_ci .idle_host = 2, /* idle threshold HOST, in 300ms */ 3568c2ecf20Sopenharmony_ci .idle_dev = 2, /* idle threshold device, in 300ms */ 3578c2ecf20Sopenharmony_ci .bt_wake_active = 1, /* BT_WAKE active mode: 1 = high, 0 = low */ 3588c2ecf20Sopenharmony_ci .host_wake_active = 0, /* HOST_WAKE active mode: 1 = high, 0 = low */ 3598c2ecf20Sopenharmony_ci .allow_host_sleep = 1, /* Allow host sleep in SCO flag */ 3608c2ecf20Sopenharmony_ci .combine_modes = 1, /* Combine sleep and LPM flag */ 3618c2ecf20Sopenharmony_ci .tristate_control = 0, /* Allow tri-state control of UART tx flag */ 3628c2ecf20Sopenharmony_ci /* Irrelevant USB flags */ 3638c2ecf20Sopenharmony_ci .usb_auto_sleep = 0, 3648c2ecf20Sopenharmony_ci .usb_resume_timeout = 0, 3658c2ecf20Sopenharmony_ci .break_to_host = 0, 3668c2ecf20Sopenharmony_ci .pulsed_host_wake = 1, 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int bcm_setup_sleep(struct hci_uart *hu) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 3728c2ecf20Sopenharmony_ci struct sk_buff *skb; 3738c2ecf20Sopenharmony_ci struct bcm_set_sleep_mode sleep_params = default_sleep_params; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci sleep_params.host_wake_active = !bcm->dev->irq_active_low; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_params), 3788c2ecf20Sopenharmony_ci &sleep_params, HCI_INIT_TIMEOUT); 3798c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 3808c2ecf20Sopenharmony_ci int err = PTR_ERR(skb); 3818c2ecf20Sopenharmony_ci bt_dev_err(hu->hdev, "Sleep VSC failed (%d)", err); 3828c2ecf20Sopenharmony_ci return err; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci kfree_skb(skb); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci bt_dev_dbg(hu->hdev, "Set Sleep Parameters VSC succeeded"); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci#else 3918c2ecf20Sopenharmony_cistatic inline int bcm_request_irq(struct bcm_data *bcm) { return 0; } 3928c2ecf20Sopenharmony_cistatic inline int bcm_setup_sleep(struct hci_uart *hu) { return 0; } 3938c2ecf20Sopenharmony_ci#endif 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int bcm_set_diag(struct hci_dev *hdev, bool enable) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 3988c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 3998c2ecf20Sopenharmony_ci struct sk_buff *skb; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (!test_bit(HCI_RUNNING, &hdev->flags)) 4028c2ecf20Sopenharmony_ci return -ENETDOWN; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci skb = bt_skb_alloc(3, GFP_KERNEL); 4058c2ecf20Sopenharmony_ci if (!skb) 4068c2ecf20Sopenharmony_ci return -ENOMEM; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci skb_put_u8(skb, BCM_LM_DIAG_PKT); 4098c2ecf20Sopenharmony_ci skb_put_u8(skb, 0xf0); 4108c2ecf20Sopenharmony_ci skb_put_u8(skb, enable); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci skb_queue_tail(&bcm->txq, skb); 4138c2ecf20Sopenharmony_ci hci_uart_tx_wakeup(hu); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic int bcm_open(struct hci_uart *hu) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct bcm_data *bcm; 4218c2ecf20Sopenharmony_ci struct list_head *p; 4228c2ecf20Sopenharmony_ci int err; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci bt_dev_dbg(hu->hdev, "hu %p", hu); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!hci_uart_has_flow_control(hu)) 4278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); 4308c2ecf20Sopenharmony_ci if (!bcm) 4318c2ecf20Sopenharmony_ci return -ENOMEM; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci skb_queue_head_init(&bcm->txq); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci hu->priv = bcm; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (hu->serdev) { 4408c2ecf20Sopenharmony_ci bcm->dev = serdev_device_get_drvdata(hu->serdev); 4418c2ecf20Sopenharmony_ci goto out; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (!hu->tty->dev) 4458c2ecf20Sopenharmony_ci goto out; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci list_for_each(p, &bcm_device_list) { 4488c2ecf20Sopenharmony_ci struct bcm_device *dev = list_entry(p, struct bcm_device, list); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* Retrieve saved bcm_device based on parent of the 4518c2ecf20Sopenharmony_ci * platform device (saved during device probe) and 4528c2ecf20Sopenharmony_ci * parent of tty device used by hci_uart 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ci if (hu->tty->dev->parent == dev->dev->parent) { 4558c2ecf20Sopenharmony_ci bcm->dev = dev; 4568c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4578c2ecf20Sopenharmony_ci dev->hu = hu; 4588c2ecf20Sopenharmony_ci#endif 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ciout: 4648c2ecf20Sopenharmony_ci if (bcm->dev) { 4658c2ecf20Sopenharmony_ci if (bcm->dev->drive_rts_on_open) 4668c2ecf20Sopenharmony_ci hci_uart_set_flow_control(hu, true); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci hu->init_speed = bcm->dev->init_speed; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* If oper_speed is set, ldisc/serdev will set the baudrate 4718c2ecf20Sopenharmony_ci * before calling setup() 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci if (!bcm->dev->no_early_set_baudrate) 4748c2ecf20Sopenharmony_ci hu->oper_speed = bcm->dev->oper_speed; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci err = bcm_gpio_set_power(bcm->dev, true); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (bcm->dev->drive_rts_on_open) 4798c2ecf20Sopenharmony_ci hci_uart_set_flow_control(hu, false); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (err) 4828c2ecf20Sopenharmony_ci goto err_unset_hu; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cierr_unset_hu: 4898c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4908c2ecf20Sopenharmony_ci if (!hu->serdev) 4918c2ecf20Sopenharmony_ci bcm->dev->hu = NULL; 4928c2ecf20Sopenharmony_ci#endif 4938c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 4948c2ecf20Sopenharmony_ci hu->priv = NULL; 4958c2ecf20Sopenharmony_ci kfree(bcm); 4968c2ecf20Sopenharmony_ci return err; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic int bcm_close(struct hci_uart *hu) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 5028c2ecf20Sopenharmony_ci struct bcm_device *bdev = NULL; 5038c2ecf20Sopenharmony_ci int err; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci bt_dev_dbg(hu->hdev, "hu %p", hu); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Protect bcm->dev against removal of the device or driver */ 5088c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (hu->serdev) { 5118c2ecf20Sopenharmony_ci bdev = serdev_device_get_drvdata(hu->serdev); 5128c2ecf20Sopenharmony_ci } else if (bcm_device_exists(bcm->dev)) { 5138c2ecf20Sopenharmony_ci bdev = bcm->dev; 5148c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5158c2ecf20Sopenharmony_ci bdev->hu = NULL; 5168c2ecf20Sopenharmony_ci#endif 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (bdev) { 5208c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PM) && bdev->irq_acquired) { 5218c2ecf20Sopenharmony_ci devm_free_irq(bdev->dev, bdev->irq, bdev); 5228c2ecf20Sopenharmony_ci device_init_wakeup(bdev->dev, false); 5238c2ecf20Sopenharmony_ci pm_runtime_disable(bdev->dev); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci err = bcm_gpio_set_power(bdev, false); 5278c2ecf20Sopenharmony_ci if (err) 5288c2ecf20Sopenharmony_ci bt_dev_err(hu->hdev, "Failed to power down"); 5298c2ecf20Sopenharmony_ci else 5308c2ecf20Sopenharmony_ci pm_runtime_set_suspended(bdev->dev); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci skb_queue_purge(&bcm->txq); 5358c2ecf20Sopenharmony_ci kfree_skb(bcm->rx_skb); 5368c2ecf20Sopenharmony_ci kfree(bcm); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci hu->priv = NULL; 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int bcm_flush(struct hci_uart *hu) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci bt_dev_dbg(hu->hdev, "hu %p", hu); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci skb_queue_purge(&bcm->txq); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int bcm_setup(struct hci_uart *hu) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 5568c2ecf20Sopenharmony_ci bool fw_load_done = false; 5578c2ecf20Sopenharmony_ci unsigned int speed; 5588c2ecf20Sopenharmony_ci int err; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci bt_dev_dbg(hu->hdev, "hu %p", hu); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci hu->hdev->set_diag = bcm_set_diag; 5638c2ecf20Sopenharmony_ci hu->hdev->set_bdaddr = btbcm_set_bdaddr; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci err = btbcm_initialize(hu->hdev, &fw_load_done); 5668c2ecf20Sopenharmony_ci if (err) 5678c2ecf20Sopenharmony_ci return err; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!fw_load_done) 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Init speed if any */ 5738c2ecf20Sopenharmony_ci if (hu->init_speed) 5748c2ecf20Sopenharmony_ci speed = hu->init_speed; 5758c2ecf20Sopenharmony_ci else if (hu->proto->init_speed) 5768c2ecf20Sopenharmony_ci speed = hu->proto->init_speed; 5778c2ecf20Sopenharmony_ci else 5788c2ecf20Sopenharmony_ci speed = 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (speed) 5818c2ecf20Sopenharmony_ci host_set_baudrate(hu, speed); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Operational speed if any */ 5848c2ecf20Sopenharmony_ci if (hu->oper_speed) 5858c2ecf20Sopenharmony_ci speed = hu->oper_speed; 5868c2ecf20Sopenharmony_ci else if (bcm->dev && bcm->dev->oper_speed) 5878c2ecf20Sopenharmony_ci speed = bcm->dev->oper_speed; 5888c2ecf20Sopenharmony_ci else if (hu->proto->oper_speed) 5898c2ecf20Sopenharmony_ci speed = hu->proto->oper_speed; 5908c2ecf20Sopenharmony_ci else 5918c2ecf20Sopenharmony_ci speed = 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (speed) { 5948c2ecf20Sopenharmony_ci err = bcm_set_baudrate(hu, speed); 5958c2ecf20Sopenharmony_ci if (!err) 5968c2ecf20Sopenharmony_ci host_set_baudrate(hu, speed); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* PCM parameters if provided */ 6008c2ecf20Sopenharmony_ci if (bcm->dev && bcm->dev->pcm_int_params[0] != 0xff) { 6018c2ecf20Sopenharmony_ci struct bcm_set_pcm_int_params params; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci btbcm_read_pcm_int_params(hu->hdev, ¶ms); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci memcpy(¶ms, bcm->dev->pcm_int_params, 5); 6068c2ecf20Sopenharmony_ci btbcm_write_pcm_int_params(hu->hdev, ¶ms); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci err = btbcm_finalize(hu->hdev, &fw_load_done); 6108c2ecf20Sopenharmony_ci if (err) 6118c2ecf20Sopenharmony_ci return err; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Some devices ship with the controller default address. 6148c2ecf20Sopenharmony_ci * Allow the bootloader to set a valid address through the 6158c2ecf20Sopenharmony_ci * device tree. 6168c2ecf20Sopenharmony_ci */ 6178c2ecf20Sopenharmony_ci set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hu->hdev->quirks); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (!bcm_request_irq(bcm)) 6208c2ecf20Sopenharmony_ci err = bcm_setup_sleep(hu); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return err; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci#define BCM_RECV_LM_DIAG \ 6268c2ecf20Sopenharmony_ci .type = BCM_LM_DIAG_PKT, \ 6278c2ecf20Sopenharmony_ci .hlen = BCM_LM_DIAG_SIZE, \ 6288c2ecf20Sopenharmony_ci .loff = 0, \ 6298c2ecf20Sopenharmony_ci .lsize = 0, \ 6308c2ecf20Sopenharmony_ci .maxlen = BCM_LM_DIAG_SIZE 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci#define BCM_RECV_NULL \ 6338c2ecf20Sopenharmony_ci .type = BCM_NULL_PKT, \ 6348c2ecf20Sopenharmony_ci .hlen = BCM_NULL_SIZE, \ 6358c2ecf20Sopenharmony_ci .loff = 0, \ 6368c2ecf20Sopenharmony_ci .lsize = 0, \ 6378c2ecf20Sopenharmony_ci .maxlen = BCM_NULL_SIZE 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci#define BCM_RECV_TYPE49 \ 6408c2ecf20Sopenharmony_ci .type = BCM_TYPE49_PKT, \ 6418c2ecf20Sopenharmony_ci .hlen = BCM_TYPE49_SIZE, \ 6428c2ecf20Sopenharmony_ci .loff = 0, \ 6438c2ecf20Sopenharmony_ci .lsize = 0, \ 6448c2ecf20Sopenharmony_ci .maxlen = BCM_TYPE49_SIZE 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci#define BCM_RECV_TYPE52 \ 6478c2ecf20Sopenharmony_ci .type = BCM_TYPE52_PKT, \ 6488c2ecf20Sopenharmony_ci .hlen = BCM_TYPE52_SIZE, \ 6498c2ecf20Sopenharmony_ci .loff = 0, \ 6508c2ecf20Sopenharmony_ci .lsize = 0, \ 6518c2ecf20Sopenharmony_ci .maxlen = BCM_TYPE52_SIZE 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic const struct h4_recv_pkt bcm_recv_pkts[] = { 6548c2ecf20Sopenharmony_ci { H4_RECV_ACL, .recv = hci_recv_frame }, 6558c2ecf20Sopenharmony_ci { H4_RECV_SCO, .recv = hci_recv_frame }, 6568c2ecf20Sopenharmony_ci { H4_RECV_EVENT, .recv = hci_recv_frame }, 6578c2ecf20Sopenharmony_ci { BCM_RECV_LM_DIAG, .recv = hci_recv_diag }, 6588c2ecf20Sopenharmony_ci { BCM_RECV_NULL, .recv = hci_recv_diag }, 6598c2ecf20Sopenharmony_ci { BCM_RECV_TYPE49, .recv = hci_recv_diag }, 6608c2ecf20Sopenharmony_ci { BCM_RECV_TYPE52, .recv = hci_recv_diag }, 6618c2ecf20Sopenharmony_ci}; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int bcm_recv(struct hci_uart *hu, const void *data, int count) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) 6688c2ecf20Sopenharmony_ci return -EUNATCH; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count, 6718c2ecf20Sopenharmony_ci bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts)); 6728c2ecf20Sopenharmony_ci if (IS_ERR(bcm->rx_skb)) { 6738c2ecf20Sopenharmony_ci int err = PTR_ERR(bcm->rx_skb); 6748c2ecf20Sopenharmony_ci bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err); 6758c2ecf20Sopenharmony_ci bcm->rx_skb = NULL; 6768c2ecf20Sopenharmony_ci return err; 6778c2ecf20Sopenharmony_ci } else if (!bcm->rx_skb) { 6788c2ecf20Sopenharmony_ci /* Delay auto-suspend when receiving completed packet */ 6798c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 6808c2ecf20Sopenharmony_ci if (bcm->dev && bcm_device_exists(bcm->dev)) { 6818c2ecf20Sopenharmony_ci pm_runtime_get(bcm->dev->dev); 6828c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bcm->dev->dev); 6838c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bcm->dev->dev); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return count; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci bt_dev_dbg(hu->hdev, "hu %p skb %p", hu, skb); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* Prepend skb with frame type */ 6988c2ecf20Sopenharmony_ci memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); 6998c2ecf20Sopenharmony_ci skb_queue_tail(&bcm->txq, skb); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci return 0; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic struct sk_buff *bcm_dequeue(struct hci_uart *hu) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct bcm_data *bcm = hu->priv; 7078c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 7088c2ecf20Sopenharmony_ci struct bcm_device *bdev = NULL; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (bcm_device_exists(bcm->dev)) { 7138c2ecf20Sopenharmony_ci bdev = bcm->dev; 7148c2ecf20Sopenharmony_ci pm_runtime_get_sync(bdev->dev); 7158c2ecf20Sopenharmony_ci /* Shall be resumed here */ 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci skb = skb_dequeue(&bcm->txq); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (bdev) { 7218c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(bdev->dev); 7228c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(bdev->dev); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return skb; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7318c2ecf20Sopenharmony_cistatic int bcm_suspend_device(struct device *dev) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct bcm_device *bdev = dev_get_drvdata(dev); 7348c2ecf20Sopenharmony_ci int err; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, ""); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (!bdev->is_suspended && bdev->hu) { 7398c2ecf20Sopenharmony_ci hci_uart_set_flow_control(bdev->hu, true); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Once this returns, driver suspends BT via GPIO */ 7428c2ecf20Sopenharmony_ci bdev->is_suspended = true; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Suspend the device */ 7468c2ecf20Sopenharmony_ci err = bdev->set_device_wakeup(bdev, false); 7478c2ecf20Sopenharmony_ci if (err) { 7488c2ecf20Sopenharmony_ci if (bdev->is_suspended && bdev->hu) { 7498c2ecf20Sopenharmony_ci bdev->is_suspended = false; 7508c2ecf20Sopenharmony_ci hci_uart_set_flow_control(bdev->hu, false); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci return -EBUSY; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "suspend, delaying 15 ms"); 7568c2ecf20Sopenharmony_ci msleep(15); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return 0; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic int bcm_resume_device(struct device *dev) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct bcm_device *bdev = dev_get_drvdata(dev); 7648c2ecf20Sopenharmony_ci int err; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, ""); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci err = bdev->set_device_wakeup(bdev, true); 7698c2ecf20Sopenharmony_ci if (err) { 7708c2ecf20Sopenharmony_ci dev_err(dev, "Failed to power up\n"); 7718c2ecf20Sopenharmony_ci return err; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "resume, delaying 15 ms"); 7758c2ecf20Sopenharmony_ci msleep(15); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* When this executes, the device has woken up already */ 7788c2ecf20Sopenharmony_ci if (bdev->is_suspended && bdev->hu) { 7798c2ecf20Sopenharmony_ci bdev->is_suspended = false; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci hci_uart_set_flow_control(bdev->hu, false); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci return 0; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci#endif 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7898c2ecf20Sopenharmony_ci/* suspend callback */ 7908c2ecf20Sopenharmony_cistatic int bcm_suspend(struct device *dev) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci struct bcm_device *bdev = dev_get_drvdata(dev); 7938c2ecf20Sopenharmony_ci int error; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* 7988c2ecf20Sopenharmony_ci * When used with a device instantiated as platform_device, bcm_suspend 7998c2ecf20Sopenharmony_ci * can be called at any time as long as the platform device is bound, 8008c2ecf20Sopenharmony_ci * so it should use bcm_device_lock to protect access to hci_uart 8018c2ecf20Sopenharmony_ci * and device_wake-up GPIO. 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (!bdev->hu) 8068c2ecf20Sopenharmony_ci goto unlock; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (pm_runtime_active(dev)) 8098c2ecf20Sopenharmony_ci bcm_suspend_device(dev); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (device_may_wakeup(dev) && bdev->irq > 0) { 8128c2ecf20Sopenharmony_ci error = enable_irq_wake(bdev->irq); 8138c2ecf20Sopenharmony_ci if (!error) 8148c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "BCM irq: enabled"); 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ciunlock: 8188c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return 0; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci/* resume callback */ 8248c2ecf20Sopenharmony_cistatic int bcm_resume(struct device *dev) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci struct bcm_device *bdev = dev_get_drvdata(dev); 8278c2ecf20Sopenharmony_ci int err = 0; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* 8328c2ecf20Sopenharmony_ci * When used with a device instantiated as platform_device, bcm_resume 8338c2ecf20Sopenharmony_ci * can be called at any time as long as platform device is bound, 8348c2ecf20Sopenharmony_ci * so it should use bcm_device_lock to protect access to hci_uart 8358c2ecf20Sopenharmony_ci * and device_wake-up GPIO. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (!bdev->hu) 8408c2ecf20Sopenharmony_ci goto unlock; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (device_may_wakeup(dev) && bdev->irq > 0) { 8438c2ecf20Sopenharmony_ci disable_irq_wake(bdev->irq); 8448c2ecf20Sopenharmony_ci bt_dev_dbg(bdev, "BCM irq: disabled"); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci err = bcm_resume_device(dev); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ciunlock: 8508c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (!err) { 8538c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 8548c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 8558c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci#endif 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */ 8638c2ecf20Sopenharmony_cistatic const struct dmi_system_id bcm_broken_irq_dmi_table[] = { 8648c2ecf20Sopenharmony_ci { 8658c2ecf20Sopenharmony_ci .ident = "Meegopad T08", 8668c2ecf20Sopenharmony_ci .matches = { 8678c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_BOARD_VENDOR, 8688c2ecf20Sopenharmony_ci "To be filled by OEM."), 8698c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_BOARD_NAME, "T3 MRD"), 8708c2ecf20Sopenharmony_ci DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V1.1"), 8718c2ecf20Sopenharmony_ci }, 8728c2ecf20Sopenharmony_ci }, 8738c2ecf20Sopenharmony_ci { } 8748c2ecf20Sopenharmony_ci}; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 8778c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params first_gpio = { 0, 0, false }; 8788c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params second_gpio = { 1, 0, false }; 8798c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params third_gpio = { 2, 0, false }; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_bcm_int_last_gpios[] = { 8828c2ecf20Sopenharmony_ci { "device-wakeup-gpios", &first_gpio, 1 }, 8838c2ecf20Sopenharmony_ci { "shutdown-gpios", &second_gpio, 1 }, 8848c2ecf20Sopenharmony_ci { "host-wakeup-gpios", &third_gpio, 1 }, 8858c2ecf20Sopenharmony_ci { }, 8868c2ecf20Sopenharmony_ci}; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = { 8898c2ecf20Sopenharmony_ci { "host-wakeup-gpios", &first_gpio, 1 }, 8908c2ecf20Sopenharmony_ci { "device-wakeup-gpios", &second_gpio, 1 }, 8918c2ecf20Sopenharmony_ci { "shutdown-gpios", &third_gpio, 1 }, 8928c2ecf20Sopenharmony_ci { }, 8938c2ecf20Sopenharmony_ci}; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int bcm_resource(struct acpi_resource *ares, void *data) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct bcm_device *dev = data; 8988c2ecf20Sopenharmony_ci struct acpi_resource_extended_irq *irq; 8998c2ecf20Sopenharmony_ci struct acpi_resource_gpio *gpio; 9008c2ecf20Sopenharmony_ci struct acpi_resource_uart_serialbus *sb; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci switch (ares->type) { 9038c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 9048c2ecf20Sopenharmony_ci irq = &ares->data.extended_irq; 9058c2ecf20Sopenharmony_ci if (irq->polarity != ACPI_ACTIVE_LOW) 9068c2ecf20Sopenharmony_ci dev_info(dev->dev, "ACPI Interrupt resource is active-high, this is usually wrong, treating the IRQ as active-low\n"); 9078c2ecf20Sopenharmony_ci dev->irq_active_low = true; 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_GPIO: 9118c2ecf20Sopenharmony_ci gpio = &ares->data.gpio; 9128c2ecf20Sopenharmony_ci if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) { 9138c2ecf20Sopenharmony_ci dev->gpio_int_idx = dev->gpio_count; 9148c2ecf20Sopenharmony_ci dev->irq_active_low = gpio->polarity == ACPI_ACTIVE_LOW; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci dev->gpio_count++; 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci case ACPI_RESOURCE_TYPE_SERIAL_BUS: 9208c2ecf20Sopenharmony_ci sb = &ares->data.uart_serial_bus; 9218c2ecf20Sopenharmony_ci if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_UART) { 9228c2ecf20Sopenharmony_ci dev->init_speed = sb->default_baud_rate; 9238c2ecf20Sopenharmony_ci dev->oper_speed = 4000000; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci default: 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic int bcm_apple_set_device_wakeup(struct bcm_device *dev, bool awake) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_execute_simple_method(dev->btlp, NULL, !awake))) 9378c2ecf20Sopenharmony_ci return -EIO; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic int bcm_apple_set_shutdown(struct bcm_device *dev, bool powered) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_evaluate_object(powered ? dev->btpu : dev->btpd, 9458c2ecf20Sopenharmony_ci NULL, NULL, NULL))) 9468c2ecf20Sopenharmony_ci return -EIO; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return 0; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic int bcm_apple_get_resources(struct bcm_device *dev) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(dev->dev); 9548c2ecf20Sopenharmony_ci const union acpi_object *obj; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!adev || 9578c2ecf20Sopenharmony_ci ACPI_FAILURE(acpi_get_handle(adev->handle, "BTLP", &dev->btlp)) || 9588c2ecf20Sopenharmony_ci ACPI_FAILURE(acpi_get_handle(adev->handle, "BTPU", &dev->btpu)) || 9598c2ecf20Sopenharmony_ci ACPI_FAILURE(acpi_get_handle(adev->handle, "BTPD", &dev->btpd))) 9608c2ecf20Sopenharmony_ci return -ENODEV; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (!acpi_dev_get_property(adev, "baud", ACPI_TYPE_BUFFER, &obj) && 9638c2ecf20Sopenharmony_ci obj->buffer.length == 8) 9648c2ecf20Sopenharmony_ci dev->init_speed = *(u64 *)obj->buffer.pointer; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci dev->set_device_wakeup = bcm_apple_set_device_wakeup; 9678c2ecf20Sopenharmony_ci dev->set_shutdown = bcm_apple_set_shutdown; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci return 0; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci#else 9728c2ecf20Sopenharmony_cistatic inline int bcm_apple_get_resources(struct bcm_device *dev) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(dev->device_wakeup, awake); 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(dev->shutdown, powered); 9878c2ecf20Sopenharmony_ci return 0; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci/* Try a bunch of names for TXCO */ 9918c2ecf20Sopenharmony_cistatic struct clk *bcm_get_txco(struct device *dev) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct clk *clk; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* New explicit name */ 9968c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, "txco"); 9978c2ecf20Sopenharmony_ci if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) 9988c2ecf20Sopenharmony_ci return clk; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* Deprecated name */ 10018c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, "extclk"); 10028c2ecf20Sopenharmony_ci if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) 10038c2ecf20Sopenharmony_ci return clk; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Original code used no name at all */ 10068c2ecf20Sopenharmony_ci return devm_clk_get(dev, NULL); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic int bcm_get_resources(struct bcm_device *dev) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci const struct dmi_system_id *dmi_id; 10128c2ecf20Sopenharmony_ci int err; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci dev->name = dev_name(dev->dev); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (x86_apple_machine && !bcm_apple_get_resources(dev)) 10178c2ecf20Sopenharmony_ci return 0; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci dev->txco_clk = bcm_get_txco(dev->dev); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* Handle deferred probing */ 10228c2ecf20Sopenharmony_ci if (dev->txco_clk == ERR_PTR(-EPROBE_DEFER)) 10238c2ecf20Sopenharmony_ci return PTR_ERR(dev->txco_clk); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* Ignore all other errors as before */ 10268c2ecf20Sopenharmony_ci if (IS_ERR(dev->txco_clk)) 10278c2ecf20Sopenharmony_ci dev->txco_clk = NULL; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci dev->lpo_clk = devm_clk_get(dev->dev, "lpo"); 10308c2ecf20Sopenharmony_ci if (dev->lpo_clk == ERR_PTR(-EPROBE_DEFER)) 10318c2ecf20Sopenharmony_ci return PTR_ERR(dev->lpo_clk); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (IS_ERR(dev->lpo_clk)) 10348c2ecf20Sopenharmony_ci dev->lpo_clk = NULL; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* Check if we accidentally fetched the lpo clock twice */ 10378c2ecf20Sopenharmony_ci if (dev->lpo_clk && clk_is_match(dev->lpo_clk, dev->txco_clk)) { 10388c2ecf20Sopenharmony_ci devm_clk_put(dev->dev, dev->txco_clk); 10398c2ecf20Sopenharmony_ci dev->txco_clk = NULL; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci dev->device_wakeup = devm_gpiod_get_optional(dev->dev, "device-wakeup", 10438c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 10448c2ecf20Sopenharmony_ci if (IS_ERR(dev->device_wakeup)) 10458c2ecf20Sopenharmony_ci return PTR_ERR(dev->device_wakeup); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown", 10488c2ecf20Sopenharmony_ci GPIOD_OUT_LOW); 10498c2ecf20Sopenharmony_ci if (IS_ERR(dev->shutdown)) 10508c2ecf20Sopenharmony_ci return PTR_ERR(dev->shutdown); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci dev->set_device_wakeup = bcm_gpio_set_device_wakeup; 10538c2ecf20Sopenharmony_ci dev->set_shutdown = bcm_gpio_set_shutdown; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci dev->supplies[0].supply = "vbat"; 10568c2ecf20Sopenharmony_ci dev->supplies[1].supply = "vddio"; 10578c2ecf20Sopenharmony_ci err = devm_regulator_bulk_get(dev->dev, BCM_NUM_SUPPLIES, 10588c2ecf20Sopenharmony_ci dev->supplies); 10598c2ecf20Sopenharmony_ci if (err) 10608c2ecf20Sopenharmony_ci return err; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* IRQ can be declared in ACPI table as Interrupt or GpioInt */ 10638c2ecf20Sopenharmony_ci if (dev->irq <= 0) { 10648c2ecf20Sopenharmony_ci struct gpio_desc *gpio; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci gpio = devm_gpiod_get_optional(dev->dev, "host-wakeup", 10678c2ecf20Sopenharmony_ci GPIOD_IN); 10688c2ecf20Sopenharmony_ci if (IS_ERR(gpio)) 10698c2ecf20Sopenharmony_ci return PTR_ERR(gpio); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci dev->irq = gpiod_to_irq(gpio); 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci dmi_id = dmi_first_match(bcm_broken_irq_dmi_table); 10758c2ecf20Sopenharmony_ci if (dmi_id) { 10768c2ecf20Sopenharmony_ci dev_info(dev->dev, "%s: Has a broken IRQ config, disabling IRQ support / runtime-pm\n", 10778c2ecf20Sopenharmony_ci dmi_id->ident); 10788c2ecf20Sopenharmony_ci dev->irq = 0; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "BCM irq: %d\n", dev->irq); 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 10868c2ecf20Sopenharmony_cistatic int bcm_acpi_probe(struct bcm_device *dev) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci LIST_HEAD(resources); 10898c2ecf20Sopenharmony_ci const struct acpi_gpio_mapping *gpio_mapping = acpi_bcm_int_last_gpios; 10908c2ecf20Sopenharmony_ci struct resource_entry *entry; 10918c2ecf20Sopenharmony_ci int ret; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* Retrieve UART ACPI info */ 10948c2ecf20Sopenharmony_ci dev->gpio_int_idx = -1; 10958c2ecf20Sopenharmony_ci ret = acpi_dev_get_resources(ACPI_COMPANION(dev->dev), 10968c2ecf20Sopenharmony_ci &resources, bcm_resource, dev); 10978c2ecf20Sopenharmony_ci if (ret < 0) 10988c2ecf20Sopenharmony_ci return ret; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci resource_list_for_each_entry(entry, &resources) { 11018c2ecf20Sopenharmony_ci if (resource_type(entry->res) == IORESOURCE_IRQ) { 11028c2ecf20Sopenharmony_ci dev->irq = entry->res->start; 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci acpi_dev_free_resource_list(&resources); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* If the DSDT uses an Interrupt resource for the IRQ, then there are 11098c2ecf20Sopenharmony_ci * only 2 GPIO resources, we use the irq-last mapping for this, since 11108c2ecf20Sopenharmony_ci * we already have an irq the 3th / last mapping will not be used. 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_ci if (dev->irq) 11138c2ecf20Sopenharmony_ci gpio_mapping = acpi_bcm_int_last_gpios; 11148c2ecf20Sopenharmony_ci else if (dev->gpio_int_idx == 0) 11158c2ecf20Sopenharmony_ci gpio_mapping = acpi_bcm_int_first_gpios; 11168c2ecf20Sopenharmony_ci else if (dev->gpio_int_idx == 2) 11178c2ecf20Sopenharmony_ci gpio_mapping = acpi_bcm_int_last_gpios; 11188c2ecf20Sopenharmony_ci else 11198c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Unexpected ACPI gpio_int_idx: %d\n", 11208c2ecf20Sopenharmony_ci dev->gpio_int_idx); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Warn if our expectations are not met. */ 11238c2ecf20Sopenharmony_ci if (dev->gpio_count != (dev->irq ? 2 : 3)) 11248c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Unexpected number of ACPI GPIOs: %d\n", 11258c2ecf20Sopenharmony_ci dev->gpio_count); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping); 11288c2ecf20Sopenharmony_ci if (ret) 11298c2ecf20Sopenharmony_ci return ret; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (irq_polarity != -1) { 11328c2ecf20Sopenharmony_ci dev->irq_active_low = irq_polarity; 11338c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n", 11348c2ecf20Sopenharmony_ci dev->irq_active_low ? "low" : "high"); 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci#else 11408c2ecf20Sopenharmony_cistatic int bcm_acpi_probe(struct bcm_device *dev) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci return -EINVAL; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic int bcm_of_probe(struct bcm_device *bdev) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci device_property_read_u32(bdev->dev, "max-speed", &bdev->oper_speed); 11498c2ecf20Sopenharmony_ci device_property_read_u8_array(bdev->dev, "brcm,bt-pcm-int-params", 11508c2ecf20Sopenharmony_ci bdev->pcm_int_params, 5); 11518c2ecf20Sopenharmony_ci bdev->irq = of_irq_get_byname(bdev->dev->of_node, "host-wakeup"); 11528c2ecf20Sopenharmony_ci bdev->irq_active_low = irq_get_trigger_type(bdev->irq) 11538c2ecf20Sopenharmony_ci & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW); 11548c2ecf20Sopenharmony_ci return 0; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic int bcm_probe(struct platform_device *pdev) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct bcm_device *dev; 11608c2ecf20Sopenharmony_ci int ret; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 11638c2ecf20Sopenharmony_ci if (!dev) 11648c2ecf20Sopenharmony_ci return -ENOMEM; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci dev->dev = &pdev->dev; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 11698c2ecf20Sopenharmony_ci if (ret < 0) 11708c2ecf20Sopenharmony_ci return ret; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci dev->irq = ret; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* Initialize routing field to an unused value */ 11758c2ecf20Sopenharmony_ci dev->pcm_int_params[0] = 0xff; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (has_acpi_companion(&pdev->dev)) { 11788c2ecf20Sopenharmony_ci ret = bcm_acpi_probe(dev); 11798c2ecf20Sopenharmony_ci if (ret) 11808c2ecf20Sopenharmony_ci return ret; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci ret = bcm_get_resources(dev); 11848c2ecf20Sopenharmony_ci if (ret) 11858c2ecf20Sopenharmony_ci return ret; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%s device registered.\n", dev->name); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* Place this instance on the device list */ 11928c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 11938c2ecf20Sopenharmony_ci list_add_tail(&dev->list, &bcm_device_list); 11948c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci ret = bcm_gpio_set_power(dev, false); 11978c2ecf20Sopenharmony_ci if (ret) 11988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to power down\n"); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci return 0; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic int bcm_remove(struct platform_device *pdev) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci struct bcm_device *dev = platform_get_drvdata(pdev); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci mutex_lock(&bcm_device_lock); 12088c2ecf20Sopenharmony_ci list_del(&dev->list); 12098c2ecf20Sopenharmony_ci mutex_unlock(&bcm_device_lock); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "%s device unregistered.\n", dev->name); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return 0; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic const struct hci_uart_proto bcm_proto = { 12178c2ecf20Sopenharmony_ci .id = HCI_UART_BCM, 12188c2ecf20Sopenharmony_ci .name = "Broadcom", 12198c2ecf20Sopenharmony_ci .manufacturer = 15, 12208c2ecf20Sopenharmony_ci .init_speed = 115200, 12218c2ecf20Sopenharmony_ci .open = bcm_open, 12228c2ecf20Sopenharmony_ci .close = bcm_close, 12238c2ecf20Sopenharmony_ci .flush = bcm_flush, 12248c2ecf20Sopenharmony_ci .setup = bcm_setup, 12258c2ecf20Sopenharmony_ci .set_baudrate = bcm_set_baudrate, 12268c2ecf20Sopenharmony_ci .recv = bcm_recv, 12278c2ecf20Sopenharmony_ci .enqueue = bcm_enqueue, 12288c2ecf20Sopenharmony_ci .dequeue = bcm_dequeue, 12298c2ecf20Sopenharmony_ci}; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 12328c2ecf20Sopenharmony_cistatic const struct acpi_device_id bcm_acpi_match[] = { 12338c2ecf20Sopenharmony_ci { "BCM2E00" }, 12348c2ecf20Sopenharmony_ci { "BCM2E01" }, 12358c2ecf20Sopenharmony_ci { "BCM2E02" }, 12368c2ecf20Sopenharmony_ci { "BCM2E03" }, 12378c2ecf20Sopenharmony_ci { "BCM2E04" }, 12388c2ecf20Sopenharmony_ci { "BCM2E05" }, 12398c2ecf20Sopenharmony_ci { "BCM2E06" }, 12408c2ecf20Sopenharmony_ci { "BCM2E07" }, 12418c2ecf20Sopenharmony_ci { "BCM2E08" }, 12428c2ecf20Sopenharmony_ci { "BCM2E09" }, 12438c2ecf20Sopenharmony_ci { "BCM2E0A" }, 12448c2ecf20Sopenharmony_ci { "BCM2E0B" }, 12458c2ecf20Sopenharmony_ci { "BCM2E0C" }, 12468c2ecf20Sopenharmony_ci { "BCM2E0D" }, 12478c2ecf20Sopenharmony_ci { "BCM2E0E" }, 12488c2ecf20Sopenharmony_ci { "BCM2E0F" }, 12498c2ecf20Sopenharmony_ci { "BCM2E10" }, 12508c2ecf20Sopenharmony_ci { "BCM2E11" }, 12518c2ecf20Sopenharmony_ci { "BCM2E12" }, 12528c2ecf20Sopenharmony_ci { "BCM2E13" }, 12538c2ecf20Sopenharmony_ci { "BCM2E14" }, 12548c2ecf20Sopenharmony_ci { "BCM2E15" }, 12558c2ecf20Sopenharmony_ci { "BCM2E16" }, 12568c2ecf20Sopenharmony_ci { "BCM2E17" }, 12578c2ecf20Sopenharmony_ci { "BCM2E18" }, 12588c2ecf20Sopenharmony_ci { "BCM2E19" }, 12598c2ecf20Sopenharmony_ci { "BCM2E1A" }, 12608c2ecf20Sopenharmony_ci { "BCM2E1B" }, 12618c2ecf20Sopenharmony_ci { "BCM2E1C" }, 12628c2ecf20Sopenharmony_ci { "BCM2E1D" }, 12638c2ecf20Sopenharmony_ci { "BCM2E1F" }, 12648c2ecf20Sopenharmony_ci { "BCM2E20" }, 12658c2ecf20Sopenharmony_ci { "BCM2E21" }, 12668c2ecf20Sopenharmony_ci { "BCM2E22" }, 12678c2ecf20Sopenharmony_ci { "BCM2E23" }, 12688c2ecf20Sopenharmony_ci { "BCM2E24" }, 12698c2ecf20Sopenharmony_ci { "BCM2E25" }, 12708c2ecf20Sopenharmony_ci { "BCM2E26" }, 12718c2ecf20Sopenharmony_ci { "BCM2E27" }, 12728c2ecf20Sopenharmony_ci { "BCM2E28" }, 12738c2ecf20Sopenharmony_ci { "BCM2E29" }, 12748c2ecf20Sopenharmony_ci { "BCM2E2A" }, 12758c2ecf20Sopenharmony_ci { "BCM2E2B" }, 12768c2ecf20Sopenharmony_ci { "BCM2E2C" }, 12778c2ecf20Sopenharmony_ci { "BCM2E2D" }, 12788c2ecf20Sopenharmony_ci { "BCM2E2E" }, 12798c2ecf20Sopenharmony_ci { "BCM2E2F" }, 12808c2ecf20Sopenharmony_ci { "BCM2E30" }, 12818c2ecf20Sopenharmony_ci { "BCM2E31" }, 12828c2ecf20Sopenharmony_ci { "BCM2E32" }, 12838c2ecf20Sopenharmony_ci { "BCM2E33" }, 12848c2ecf20Sopenharmony_ci { "BCM2E34" }, 12858c2ecf20Sopenharmony_ci { "BCM2E35" }, 12868c2ecf20Sopenharmony_ci { "BCM2E36" }, 12878c2ecf20Sopenharmony_ci { "BCM2E37" }, 12888c2ecf20Sopenharmony_ci { "BCM2E38" }, 12898c2ecf20Sopenharmony_ci { "BCM2E39" }, 12908c2ecf20Sopenharmony_ci { "BCM2E3A" }, 12918c2ecf20Sopenharmony_ci { "BCM2E3B" }, 12928c2ecf20Sopenharmony_ci { "BCM2E3C" }, 12938c2ecf20Sopenharmony_ci { "BCM2E3D" }, 12948c2ecf20Sopenharmony_ci { "BCM2E3E" }, 12958c2ecf20Sopenharmony_ci { "BCM2E3F" }, 12968c2ecf20Sopenharmony_ci { "BCM2E40" }, 12978c2ecf20Sopenharmony_ci { "BCM2E41" }, 12988c2ecf20Sopenharmony_ci { "BCM2E42" }, 12998c2ecf20Sopenharmony_ci { "BCM2E43" }, 13008c2ecf20Sopenharmony_ci { "BCM2E44" }, 13018c2ecf20Sopenharmony_ci { "BCM2E45" }, 13028c2ecf20Sopenharmony_ci { "BCM2E46" }, 13038c2ecf20Sopenharmony_ci { "BCM2E47" }, 13048c2ecf20Sopenharmony_ci { "BCM2E48" }, 13058c2ecf20Sopenharmony_ci { "BCM2E49" }, 13068c2ecf20Sopenharmony_ci { "BCM2E4A" }, 13078c2ecf20Sopenharmony_ci { "BCM2E4B" }, 13088c2ecf20Sopenharmony_ci { "BCM2E4C" }, 13098c2ecf20Sopenharmony_ci { "BCM2E4D" }, 13108c2ecf20Sopenharmony_ci { "BCM2E4E" }, 13118c2ecf20Sopenharmony_ci { "BCM2E4F" }, 13128c2ecf20Sopenharmony_ci { "BCM2E50" }, 13138c2ecf20Sopenharmony_ci { "BCM2E51" }, 13148c2ecf20Sopenharmony_ci { "BCM2E52" }, 13158c2ecf20Sopenharmony_ci { "BCM2E53" }, 13168c2ecf20Sopenharmony_ci { "BCM2E54" }, 13178c2ecf20Sopenharmony_ci { "BCM2E55" }, 13188c2ecf20Sopenharmony_ci { "BCM2E56" }, 13198c2ecf20Sopenharmony_ci { "BCM2E57" }, 13208c2ecf20Sopenharmony_ci { "BCM2E58" }, 13218c2ecf20Sopenharmony_ci { "BCM2E59" }, 13228c2ecf20Sopenharmony_ci { "BCM2E5A" }, 13238c2ecf20Sopenharmony_ci { "BCM2E5B" }, 13248c2ecf20Sopenharmony_ci { "BCM2E5C" }, 13258c2ecf20Sopenharmony_ci { "BCM2E5D" }, 13268c2ecf20Sopenharmony_ci { "BCM2E5E" }, 13278c2ecf20Sopenharmony_ci { "BCM2E5F" }, 13288c2ecf20Sopenharmony_ci { "BCM2E60" }, 13298c2ecf20Sopenharmony_ci { "BCM2E61" }, 13308c2ecf20Sopenharmony_ci { "BCM2E62" }, 13318c2ecf20Sopenharmony_ci { "BCM2E63" }, 13328c2ecf20Sopenharmony_ci { "BCM2E64" }, 13338c2ecf20Sopenharmony_ci { "BCM2E65" }, 13348c2ecf20Sopenharmony_ci { "BCM2E66" }, 13358c2ecf20Sopenharmony_ci { "BCM2E67" }, 13368c2ecf20Sopenharmony_ci { "BCM2E68" }, 13378c2ecf20Sopenharmony_ci { "BCM2E69" }, 13388c2ecf20Sopenharmony_ci { "BCM2E6B" }, 13398c2ecf20Sopenharmony_ci { "BCM2E6D" }, 13408c2ecf20Sopenharmony_ci { "BCM2E6E" }, 13418c2ecf20Sopenharmony_ci { "BCM2E6F" }, 13428c2ecf20Sopenharmony_ci { "BCM2E70" }, 13438c2ecf20Sopenharmony_ci { "BCM2E71" }, 13448c2ecf20Sopenharmony_ci { "BCM2E72" }, 13458c2ecf20Sopenharmony_ci { "BCM2E73" }, 13468c2ecf20Sopenharmony_ci { "BCM2E74" }, 13478c2ecf20Sopenharmony_ci { "BCM2E75" }, 13488c2ecf20Sopenharmony_ci { "BCM2E76" }, 13498c2ecf20Sopenharmony_ci { "BCM2E77" }, 13508c2ecf20Sopenharmony_ci { "BCM2E78" }, 13518c2ecf20Sopenharmony_ci { "BCM2E79" }, 13528c2ecf20Sopenharmony_ci { "BCM2E7A" }, 13538c2ecf20Sopenharmony_ci { "BCM2E7B" }, 13548c2ecf20Sopenharmony_ci { "BCM2E7C" }, 13558c2ecf20Sopenharmony_ci { "BCM2E7D" }, 13568c2ecf20Sopenharmony_ci { "BCM2E7E" }, 13578c2ecf20Sopenharmony_ci { "BCM2E7F" }, 13588c2ecf20Sopenharmony_ci { "BCM2E80" }, 13598c2ecf20Sopenharmony_ci { "BCM2E81" }, 13608c2ecf20Sopenharmony_ci { "BCM2E82" }, 13618c2ecf20Sopenharmony_ci { "BCM2E83" }, 13628c2ecf20Sopenharmony_ci { "BCM2E84" }, 13638c2ecf20Sopenharmony_ci { "BCM2E85" }, 13648c2ecf20Sopenharmony_ci { "BCM2E86" }, 13658c2ecf20Sopenharmony_ci { "BCM2E87" }, 13668c2ecf20Sopenharmony_ci { "BCM2E88" }, 13678c2ecf20Sopenharmony_ci { "BCM2E89" }, 13688c2ecf20Sopenharmony_ci { "BCM2E8A" }, 13698c2ecf20Sopenharmony_ci { "BCM2E8B" }, 13708c2ecf20Sopenharmony_ci { "BCM2E8C" }, 13718c2ecf20Sopenharmony_ci { "BCM2E8D" }, 13728c2ecf20Sopenharmony_ci { "BCM2E8E" }, 13738c2ecf20Sopenharmony_ci { "BCM2E90" }, 13748c2ecf20Sopenharmony_ci { "BCM2E92" }, 13758c2ecf20Sopenharmony_ci { "BCM2E93" }, 13768c2ecf20Sopenharmony_ci { "BCM2E94" }, 13778c2ecf20Sopenharmony_ci { "BCM2E95" }, 13788c2ecf20Sopenharmony_ci { "BCM2E96" }, 13798c2ecf20Sopenharmony_ci { "BCM2E97" }, 13808c2ecf20Sopenharmony_ci { "BCM2E98" }, 13818c2ecf20Sopenharmony_ci { "BCM2E99" }, 13828c2ecf20Sopenharmony_ci { "BCM2E9A" }, 13838c2ecf20Sopenharmony_ci { "BCM2E9B" }, 13848c2ecf20Sopenharmony_ci { "BCM2E9C" }, 13858c2ecf20Sopenharmony_ci { "BCM2E9D" }, 13868c2ecf20Sopenharmony_ci { "BCM2EA0" }, 13878c2ecf20Sopenharmony_ci { "BCM2EA1" }, 13888c2ecf20Sopenharmony_ci { "BCM2EA2" }, 13898c2ecf20Sopenharmony_ci { "BCM2EA3" }, 13908c2ecf20Sopenharmony_ci { "BCM2EA4" }, 13918c2ecf20Sopenharmony_ci { "BCM2EA5" }, 13928c2ecf20Sopenharmony_ci { "BCM2EA6" }, 13938c2ecf20Sopenharmony_ci { "BCM2EA7" }, 13948c2ecf20Sopenharmony_ci { "BCM2EA8" }, 13958c2ecf20Sopenharmony_ci { "BCM2EA9" }, 13968c2ecf20Sopenharmony_ci { "BCM2EAA" }, 13978c2ecf20Sopenharmony_ci { "BCM2EAB" }, 13988c2ecf20Sopenharmony_ci { "BCM2EAC" }, 13998c2ecf20Sopenharmony_ci { }, 14008c2ecf20Sopenharmony_ci}; 14018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, bcm_acpi_match); 14028c2ecf20Sopenharmony_ci#endif 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci/* suspend and resume callbacks */ 14058c2ecf20Sopenharmony_cistatic const struct dev_pm_ops bcm_pm_ops = { 14068c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume) 14078c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(bcm_suspend_device, bcm_resume_device, NULL) 14088c2ecf20Sopenharmony_ci}; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic struct platform_driver bcm_driver = { 14118c2ecf20Sopenharmony_ci .probe = bcm_probe, 14128c2ecf20Sopenharmony_ci .remove = bcm_remove, 14138c2ecf20Sopenharmony_ci .driver = { 14148c2ecf20Sopenharmony_ci .name = "hci_bcm", 14158c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(bcm_acpi_match), 14168c2ecf20Sopenharmony_ci .pm = &bcm_pm_ops, 14178c2ecf20Sopenharmony_ci }, 14188c2ecf20Sopenharmony_ci}; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic int bcm_serdev_probe(struct serdev_device *serdev) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci struct bcm_device *bcmdev; 14238c2ecf20Sopenharmony_ci const struct bcm_device_data *data; 14248c2ecf20Sopenharmony_ci int err; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci bcmdev = devm_kzalloc(&serdev->dev, sizeof(*bcmdev), GFP_KERNEL); 14278c2ecf20Sopenharmony_ci if (!bcmdev) 14288c2ecf20Sopenharmony_ci return -ENOMEM; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci bcmdev->dev = &serdev->dev; 14318c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 14328c2ecf20Sopenharmony_ci bcmdev->hu = &bcmdev->serdev_hu; 14338c2ecf20Sopenharmony_ci#endif 14348c2ecf20Sopenharmony_ci bcmdev->serdev_hu.serdev = serdev; 14358c2ecf20Sopenharmony_ci serdev_device_set_drvdata(serdev, bcmdev); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci /* Initialize routing field to an unused value */ 14388c2ecf20Sopenharmony_ci bcmdev->pcm_int_params[0] = 0xff; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (has_acpi_companion(&serdev->dev)) 14418c2ecf20Sopenharmony_ci err = bcm_acpi_probe(bcmdev); 14428c2ecf20Sopenharmony_ci else 14438c2ecf20Sopenharmony_ci err = bcm_of_probe(bcmdev); 14448c2ecf20Sopenharmony_ci if (err) 14458c2ecf20Sopenharmony_ci return err; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci err = bcm_get_resources(bcmdev); 14488c2ecf20Sopenharmony_ci if (err) 14498c2ecf20Sopenharmony_ci return err; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (!bcmdev->shutdown) { 14528c2ecf20Sopenharmony_ci dev_warn(&serdev->dev, 14538c2ecf20Sopenharmony_ci "No reset resource, using default baud rate\n"); 14548c2ecf20Sopenharmony_ci bcmdev->oper_speed = bcmdev->init_speed; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci err = bcm_gpio_set_power(bcmdev, false); 14588c2ecf20Sopenharmony_ci if (err) 14598c2ecf20Sopenharmony_ci dev_err(&serdev->dev, "Failed to power down\n"); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci data = device_get_match_data(bcmdev->dev); 14628c2ecf20Sopenharmony_ci if (data) { 14638c2ecf20Sopenharmony_ci bcmdev->no_early_set_baudrate = data->no_early_set_baudrate; 14648c2ecf20Sopenharmony_ci bcmdev->drive_rts_on_open = data->drive_rts_on_open; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto); 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic void bcm_serdev_remove(struct serdev_device *serdev) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci struct bcm_device *bcmdev = serdev_device_get_drvdata(serdev); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci hci_uart_unregister_device(&bcmdev->serdev_hu); 14758c2ecf20Sopenharmony_ci} 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 14788c2ecf20Sopenharmony_cistatic struct bcm_device_data bcm4354_device_data = { 14798c2ecf20Sopenharmony_ci .no_early_set_baudrate = true, 14808c2ecf20Sopenharmony_ci}; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic struct bcm_device_data bcm43438_device_data = { 14838c2ecf20Sopenharmony_ci .drive_rts_on_open = true, 14848c2ecf20Sopenharmony_ci}; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cistatic const struct of_device_id bcm_bluetooth_of_match[] = { 14878c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm20702a1" }, 14888c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm4329-bt" }, 14898c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm4345c5" }, 14908c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm4330-bt" }, 14918c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data }, 14928c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm4349-bt", .data = &bcm43438_device_data }, 14938c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data }, 14948c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm4335a0" }, 14958c2ecf20Sopenharmony_ci { .compatible = "infineon,cyw55572-bt" }, 14968c2ecf20Sopenharmony_ci { }, 14978c2ecf20Sopenharmony_ci}; 14988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match); 14998c2ecf20Sopenharmony_ci#endif 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic struct serdev_device_driver bcm_serdev_driver = { 15028c2ecf20Sopenharmony_ci .probe = bcm_serdev_probe, 15038c2ecf20Sopenharmony_ci .remove = bcm_serdev_remove, 15048c2ecf20Sopenharmony_ci .driver = { 15058c2ecf20Sopenharmony_ci .name = "hci_uart_bcm", 15068c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(bcm_bluetooth_of_match), 15078c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(bcm_acpi_match), 15088c2ecf20Sopenharmony_ci .pm = &bcm_pm_ops, 15098c2ecf20Sopenharmony_ci }, 15108c2ecf20Sopenharmony_ci}; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ciint __init bcm_init(void) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci /* For now, we need to keep both platform device 15158c2ecf20Sopenharmony_ci * driver (ACPI generated) and serdev driver (DT). 15168c2ecf20Sopenharmony_ci */ 15178c2ecf20Sopenharmony_ci platform_driver_register(&bcm_driver); 15188c2ecf20Sopenharmony_ci serdev_device_driver_register(&bcm_serdev_driver); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci return hci_uart_register_proto(&bcm_proto); 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ciint __exit bcm_deinit(void) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci platform_driver_unregister(&bcm_driver); 15268c2ecf20Sopenharmony_ci serdev_device_driver_unregister(&bcm_serdev_driver); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci return hci_uart_unregister_proto(&bcm_proto); 15298c2ecf20Sopenharmony_ci} 1530