in btmtkuart.c [966:1079]
static int btmtkuart_probe(struct serdev_device *serdev)
{
struct btmtkuart_dev *bdev;
struct hci_dev *hdev;
int err;
bdev = devm_kzalloc(&serdev->dev, sizeof(*bdev), GFP_KERNEL);
if (!bdev)
return -ENOMEM;
bdev->data = of_device_get_match_data(&serdev->dev);
if (!bdev->data)
return -ENODEV;
bdev->serdev = serdev;
serdev_device_set_drvdata(serdev, bdev);
serdev_device_set_client_ops(serdev, &btmtkuart_client_ops);
err = btmtkuart_parse_dt(serdev);
if (err < 0)
return err;
INIT_WORK(&bdev->tx_work, btmtkuart_tx_work);
skb_queue_head_init(&bdev->txq);
/* Initialize and register HCI device */
hdev = hci_alloc_dev();
if (!hdev) {
dev_err(&serdev->dev, "Can't allocate HCI device\n");
return -ENOMEM;
}
bdev->hdev = hdev;
hdev->bus = HCI_UART;
hci_set_drvdata(hdev, bdev);
hdev->open = btmtkuart_open;
hdev->close = btmtkuart_close;
hdev->flush = btmtkuart_flush;
hdev->setup = btmtkuart_setup;
hdev->shutdown = btmtkuart_shutdown;
hdev->send = btmtkuart_send_frame;
SET_HCIDEV_DEV(hdev, &serdev->dev);
hdev->manufacturer = 70;
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
if (btmtkuart_is_standalone(bdev)) {
err = clk_prepare_enable(bdev->osc);
if (err < 0)
goto err_hci_free_dev;
if (bdev->boot) {
gpiod_set_value_cansleep(bdev->boot, 1);
} else {
/* Switch to the specific pin state for the booting
* requires.
*/
pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
}
/* Power on */
err = regulator_enable(bdev->vcc);
if (err < 0)
goto err_clk_disable_unprepare;
/* Reset if the reset-gpios is available otherwise the board
* -level design should be guaranteed.
*/
if (bdev->reset) {
gpiod_set_value_cansleep(bdev->reset, 1);
usleep_range(1000, 2000);
gpiod_set_value_cansleep(bdev->reset, 0);
}
/* Wait some time until device got ready and switch to the pin
* mode the device requires for UART transfers.
*/
msleep(50);
if (bdev->boot)
devm_gpiod_put(&serdev->dev, bdev->boot);
pinctrl_select_state(bdev->pinctrl, bdev->pins_runtime);
/* A standalone device doesn't depends on power domain on SoC,
* so mark it as no callbacks.
*/
pm_runtime_no_callbacks(&serdev->dev);
set_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state);
}
err = hci_register_dev(hdev);
if (err < 0) {
dev_err(&serdev->dev, "Can't register HCI device\n");
goto err_regulator_disable;
}
return 0;
err_regulator_disable:
if (btmtkuart_is_standalone(bdev))
regulator_disable(bdev->vcc);
err_clk_disable_unprepare:
if (btmtkuart_is_standalone(bdev))
clk_disable_unprepare(bdev->osc);
err_hci_free_dev:
hci_free_dev(hdev);
return err;
}