summaryrefslogtreecommitdiff
path: root/drivers/bluetooth/btmtkuart.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btmtkuart.c')
-rw-r--r--drivers/bluetooth/btmtkuart.c51
1 files changed, 41 insertions, 10 deletions
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index f5dbeec8e274..e11169ad8247 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -115,10 +115,12 @@ struct btmtk_hci_wmt_params {
struct btmtkuart_dev {
struct hci_dev *hdev;
struct serdev_device *serdev;
- struct clk *clk;
+ struct clk *clk;
+ struct clk *osc;
struct regulator *vcc;
struct gpio_desc *reset;
+ struct gpio_desc *boot;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_runtime;
struct pinctrl_state *pins_boot;
@@ -911,6 +913,19 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev)
return err;
}
+ bdev->osc = devm_clk_get_optional(&serdev->dev, "osc");
+ if (IS_ERR(bdev->osc)) {
+ err = PTR_ERR(bdev->osc);
+ return err;
+ }
+
+ bdev->boot = devm_gpiod_get_optional(&serdev->dev, "boot",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(bdev->boot)) {
+ err = PTR_ERR(bdev->boot);
+ return err;
+ }
+
bdev->pinctrl = devm_pinctrl_get(&serdev->dev);
if (IS_ERR(bdev->pinctrl)) {
err = PTR_ERR(bdev->pinctrl);
@@ -919,8 +934,10 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev)
bdev->pins_boot = pinctrl_lookup_state(bdev->pinctrl,
"default");
- if (IS_ERR(bdev->pins_boot)) {
+ if (IS_ERR(bdev->pins_boot) && !bdev->boot) {
err = PTR_ERR(bdev->pins_boot);
+ dev_err(&serdev->dev,
+ "Should assign RXD to LOW at boot stage\n");
return err;
}
@@ -996,13 +1013,25 @@ static int btmtkuart_probe(struct serdev_device *serdev)
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
if (btmtkuart_is_standalone(bdev)) {
- /* Switch to the specific pin state for the booting requires */
- pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ err = clk_prepare_enable(bdev->osc);
+ if (err < 0)
+ return err;
+
+ 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)
+ if (err < 0) {
+ clk_disable_unprepare(bdev->osc);
return err;
+ }
/* Reset if the reset-gpios is available otherwise the board
* -level design should be guaranteed.
@@ -1017,6 +1046,10 @@ static int btmtkuart_probe(struct serdev_device *serdev)
* 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,
@@ -1037,10 +1070,8 @@ static int btmtkuart_probe(struct serdev_device *serdev)
return 0;
err_regulator_disable:
- if (btmtkuart_is_standalone(bdev)) {
- pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ if (btmtkuart_is_standalone(bdev))
regulator_disable(bdev->vcc);
- }
return err;
}
@@ -1050,9 +1081,9 @@ static void btmtkuart_remove(struct serdev_device *serdev)
struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
struct hci_dev *hdev = bdev->hdev;
- if (btmtkuart_is_standalone(bdev)) {
- pinctrl_select_state(bdev->pinctrl, bdev->pins_boot);
+ if (btmtkuart_is_standalone(bdev)) {
regulator_disable(bdev->vcc);
+ clk_disable_unprepare(bdev->osc);
}
hci_unregister_dev(hdev);