/** * struct bcm_device_data - device specific data * @no_early_set_baudrate: Disallow set baudrate before driver setup() * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it * @no_uart_clock_set: UART clock set command for >3Mbps mode is unavailable * @max_autobaud_speed: max baudrate supported by device in autobaud mode * @max_speed: max baudrate supported
*/ struct bcm_device_data { bool no_early_set_baudrate; bool drive_rts_on_open; bool no_uart_clock_set;
u32 max_autobaud_speed;
u32 max_speed;
};
/** * struct bcm_device - device driver resources * @serdev_hu: HCI UART controller struct * @list: bcm_device_list node * @dev: physical UART slave * @name: device name logged by bt_dev_*() functions * @device_wakeup: BT_WAKE pin, * assert = Bluetooth device must wake up or remain awake, * deassert = Bluetooth device may sleep when sleep criteria are met * @shutdown: BT_REG_ON pin, * power up or power down Bluetooth device internal regulators * @reset: BT_RST_N pin, * active low resets the Bluetooth logic core * @set_device_wakeup: callback to toggle BT_WAKE pin * either by accessing @device_wakeup or by calling @btlp * @set_shutdown: callback to toggle BT_REG_ON pin * either by accessing @shutdown or by calling @btpu/@btpd * @btlp: Apple ACPI method to toggle BT_WAKE pin ("Bluetooth Low Power") * @btpu: Apple ACPI method to drive BT_REG_ON pin high ("Bluetooth Power Up") * @btpd: Apple ACPI method to drive BT_REG_ON pin low ("Bluetooth Power Down") * @gpio_count: internal counter for GPIO resources associated with ACPI device * @gpio_int_idx: index in _CRS for GpioInt() resource * @txco_clk: external reference frequency clock used by Bluetooth device * @lpo_clk: external LPO clock used by Bluetooth device * @supplies: VBAT and VDDIO supplies used by Bluetooth device * @res_enabled: whether clocks and supplies are prepared and enabled * @init_speed: default baudrate of Bluetooth device; * the host UART is initially set to this baudrate so that * it can configure the Bluetooth device for @oper_speed * @oper_speed: preferred baudrate of Bluetooth device; * set to 0 if @init_speed is already the preferred baudrate * @irq: interrupt triggered by HOST_WAKE_BT pin * @irq_active_low: whether @irq is active low * @irq_acquired: flag to show if IRQ handler has been assigned * @hu: pointer to HCI UART controller struct, * used to disable flow control during runtime suspend and system sleep * @is_suspended: whether flow control is currently disabled * @no_early_set_baudrate: don't set_baudrate before setup() * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it * @no_uart_clock_set: UART clock set command for >3Mbps mode is unavailable * @pcm_int_params: keep the initial PCM configuration * @use_autobaud_mode: start Bluetooth device in autobaud mode * @max_autobaud_speed: max baudrate supported by device in autobaud mode
*/ struct bcm_device { /* Must be the first member, hci_serdev.c expects this. */ struct hci_uart serdev_hu; struct list_head list;
struct device *dev;
constchar *name; struct gpio_desc *device_wakeup; struct gpio_desc *shutdown; struct gpio_desc *reset; int (*set_device_wakeup)(struct bcm_device *, bool); int (*set_shutdown)(struct bcm_device *, bool); #ifdef CONFIG_ACPI
acpi_handle btlp, btpu, btpd; int gpio_count; int gpio_int_idx; #endif
staticint bcm_gpio_set_power(struct bcm_device *dev, bool powered)
{ int err;
if (powered && !dev->res_enabled) { /* Intel Macs use bcm_apple_get_resources() and don't * have regulator supplies configured.
*/ if (dev->supplies[0].supply) {
err = regulator_bulk_enable(BCM_NUM_SUPPLIES,
dev->supplies); if (err) return err;
}
/* LPO clock needs to be 32.768 kHz */
err = clk_set_rate(dev->lpo_clk, 32768); if (err) {
dev_err(dev->dev, "Could not set LPO clock rate\n"); goto err_regulator_disable;
}
err = clk_prepare_enable(dev->lpo_clk); if (err) goto err_regulator_disable;
err = clk_prepare_enable(dev->txco_clk); if (err) goto err_lpo_clk_disable;
}
err = dev->set_shutdown(dev, powered); if (err) goto err_txco_clk_disable;
err = dev->set_device_wakeup(dev, powered); if (err) goto err_revert_shutdown;
if (!powered && dev->res_enabled) {
clk_disable_unprepare(dev->txco_clk);
clk_disable_unprepare(dev->lpo_clk);
/* Intel Macs use bcm_apple_get_resources() and don't * have regulator supplies configured.
*/ if (dev->supplies[0].supply)
regulator_bulk_disable(BCM_NUM_SUPPLIES,
dev->supplies);
}
/* wait for device to power on and come out of reset */
usleep_range(100000, 120000);
dev->res_enabled = powered;
return 0;
err_revert_shutdown:
dev->set_shutdown(dev, !powered);
err_txco_clk_disable: if (powered && !dev->res_enabled)
clk_disable_unprepare(dev->txco_clk);
err_lpo_clk_disable: if (powered && !dev->res_enabled)
clk_disable_unprepare(dev->lpo_clk);
err_regulator_disable: if (powered && !dev->res_enabled)
regulator_bulk_disable(BCM_NUM_SUPPLIES, dev->supplies); return err;
}
/* Retrieve saved bcm_device based on parent of the * platform device (saved during device probe) and * parent of tty device used by hci_uart
*/ if (hu->tty->dev->parent == dev->dev->parent) {
bcm->dev = dev; #ifdef CONFIG_PM
dev->hu = hu; #endif break;
}
}
out: if (bcm->dev) { if (bcm->dev->use_autobaud_mode)
hci_uart_set_flow_control(hu, false); /* Assert BT_UART_CTS_N */ elseif (bcm->dev->drive_rts_on_open)
hci_uart_set_flow_control(hu, true);
/* If oper_speed is set, ldisc/serdev will set the baudrate * before calling setup()
*/ if (!bcm->dev->no_early_set_baudrate && !bcm->dev->use_autobaud_mode)
hu->oper_speed = bcm->dev->oper_speed;
err = bcm_gpio_set_power(bcm->dev, true);
if (bcm->dev->drive_rts_on_open)
hci_uart_set_flow_control(hu, false);
if (bdev) { if (IS_ENABLED(CONFIG_PM) && bdev->irq_acquired) {
devm_free_irq(bdev->dev, bdev->irq, bdev);
device_init_wakeup(bdev->dev, false);
pm_runtime_disable(bdev->dev);
}
err = bcm_gpio_set_power(bdev, false); if (err)
bt_dev_err(hu->hdev, "Failed to power down"); else
pm_runtime_set_suspended(bdev->dev);
}
mutex_unlock(&bcm_device_lock);
err = btbcm_finalize(hu->hdev, &fw_load_done, use_autobaud_mode); if (err) return err;
/* Some devices ship with the controller default address. * Allow the bootloader to set a valid address through the * device tree.
*/ if (hci_test_quirk(hu->hdev, HCI_QUIRK_INVALID_BDADDR))
hci_set_quirk(hu->hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
if (!bcm_request_irq(bcm))
err = bcm_setup_sleep(hu);
/* * When used with a device instantiated as platform_device, bcm_suspend * can be called at any time as long as the platform device is bound, * so it should use bcm_device_lock to protect access to hci_uart * and device_wake-up GPIO.
*/
mutex_lock(&bcm_device_lock);
if (!bdev->hu) goto unlock;
if (pm_runtime_active(dev))
bcm_suspend_device(dev);
if (device_may_wakeup(dev) && bdev->irq > 0) {
error = enable_irq_wake(bdev->irq); if (!error)
bt_dev_dbg(bdev, "BCM irq: enabled");
}
/* * When used with a device instantiated as platform_device, bcm_resume * can be called at any time as long as platform device is bound, * so it should use bcm_device_lock to protect access to hci_uart * and device_wake-up GPIO.
*/
mutex_lock(&bcm_device_lock);
if (!err) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
}
return 0;
} #endif
/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */ staticstruct gpiod_lookup_table irq_on_int33fc02_pin17_gpios = {
.dev_id = "serial0-0",
.table = {
GPIO_LOOKUP("INT33FC:02", 17, "host-wakeup-alt", GPIO_ACTIVE_HIGH),
{ }
},
};
switch (ares->type) { case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
irq = &ares->data.extended_irq; if (irq->polarity != ACPI_ACTIVE_LOW)
dev_info(dev->dev, "ACPI Interrupt resource is active-high, this is usually wrong, treating the IRQ as active-low\n");
dev->irq_active_low = true; break;
staticint bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered)
{
gpiod_set_value_cansleep(dev->shutdown, powered); if (dev->reset) /* * The reset line is asserted on powerdown and deasserted * on poweron so the inverse of powered is used. Notice * that the GPIO line BT_RST_N needs to be specified as * active low in the device tree or similar system * description.
*/
gpiod_set_value_cansleep(dev->reset, !powered); return 0;
}
/* Try a bunch of names for TXCO */ staticstruct clk *bcm_get_txco(struct device *dev)
{ struct clk *clk;
/* New explicit name */
clk = devm_clk_get_optional(dev, "txco"); if (clk) return clk;
/* Deprecated name */
clk = devm_clk_get_optional(dev, "extclk"); if (clk) return clk;
/* Original code used no name at all */ return devm_clk_get_optional(dev, NULL);
}
/* If the DSDT uses an Interrupt resource for the IRQ, then there are * only 2 GPIO resources, we use the irq-last mapping for this, since * we already have an irq the 3th / last mapping will not be used.
*/ if (dev->irq)
gpio_mapping = acpi_bcm_int_last_gpios; elseif (dev->gpio_int_idx == 0)
gpio_mapping = acpi_bcm_int_first_gpios; elseif (dev->gpio_int_idx == 2)
gpio_mapping = acpi_bcm_int_last_gpios; else
dev_warn(dev->dev, "Unexpected ACPI gpio_int_idx: %d\n",
dev->gpio_int_idx);
/* Warn if our expectations are not met. */ if (dev->gpio_count != (dev->irq ? 2 : 3))
dev_warn(dev->dev, "Unexpected number of ACPI GPIOs: %d\n",
dev->gpio_count);
ret = devm_acpi_dev_add_driver_gpios(dev->dev, gpio_mapping); if (ret) return ret;
if (irq_polarity != -1) {
dev->irq_active_low = irq_polarity;
dev_warn(dev->dev, "Overwriting IRQ polarity to active %s by module-param\n",
dev->irq_active_low ? "low" : "high");
}
/* Place this instance on the device list */
mutex_lock(&bcm_device_lock);
list_add_tail(&dev->list, &bcm_device_list);
mutex_unlock(&bcm_device_lock);
ret = bcm_gpio_set_power(dev, false); if (ret)
dev_err(&pdev->dev, "Failed to power down\n");
int __init bcm_init(void)
{ /* For now, we need to keep both platform device * driver (ACPI generated) and serdev driver (DT).
*/
platform_driver_register(&bcm_driver);
serdev_device_driver_register(&bcm_serdev_driver);
return hci_uart_register_proto(&bcm_proto);
}
int __exit bcm_deinit(void)
{
platform_driver_unregister(&bcm_driver);
serdev_device_driver_unregister(&bcm_serdev_driver);
return hci_uart_unregister_proto(&bcm_proto);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.42 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.