Skip to content

Commit

Permalink
Bluetooth: btmtkuart: add an implementation for boot-gpios property
Browse files Browse the repository at this point in the history
Not every platform has the pinctrl device integrates the GPIO the function
such as MT7621 whose pinctrl and GPIO are separate hardware so the driver
adds additional boot-gpios to let the MT766[3,8]U can enter the proper boot
mode by gpiod for such platform.

Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
Sean Wang authored and Marcel Holtmann committed Jul 6, 2019
1 parent 14e3ed8 commit a3cb6d6
Showing 1 changed file with 25 additions and 9 deletions.
34 changes: 25 additions & 9 deletions drivers/bluetooth/btmtkuart.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ struct btmtkuart_dev {

struct regulator *vcc;
struct gpio_desc *reset;
struct gpio_desc *boot;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_runtime;
struct pinctrl_state *pins_boot;
Expand Down Expand Up @@ -911,6 +912,13 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev)
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);
Expand All @@ -919,8 +927,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;
}

Expand Down Expand Up @@ -996,8 +1006,14 @@ 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);
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);
Expand All @@ -1017,6 +1033,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,
Expand All @@ -1037,10 +1057,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;
}
Expand All @@ -1050,10 +1068,8 @@ 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);
}

hci_unregister_dev(hdev);
hci_free_dev(hdev);
Expand Down

0 comments on commit a3cb6d6

Please sign in to comment.