diff options
author | Sean Wang <sean.wang@mediatek.com> | 2019-06-01 21:04:16 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2019-07-06 07:00:04 -0400 |
commit | a3cb6d602a7a948f0b4ff77b6a087f9c25038d52 (patch) | |
tree | 1235513c96ec8eef5d4a34a38c47c14d64481a17 /drivers/bluetooth | |
parent | 14e3ed84d77e78fbf386006d3e5a0c20150681f5 (diff) |
Bluetooth: btmtkuart: add an implementation for boot-gpios property
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>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/btmtkuart.c | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index f5dbeec8e274..1257149cfdc4 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c | |||
@@ -119,6 +119,7 @@ struct btmtkuart_dev { | |||
119 | 119 | ||
120 | struct regulator *vcc; | 120 | struct regulator *vcc; |
121 | struct gpio_desc *reset; | 121 | struct gpio_desc *reset; |
122 | struct gpio_desc *boot; | ||
122 | struct pinctrl *pinctrl; | 123 | struct pinctrl *pinctrl; |
123 | struct pinctrl_state *pins_runtime; | 124 | struct pinctrl_state *pins_runtime; |
124 | struct pinctrl_state *pins_boot; | 125 | struct pinctrl_state *pins_boot; |
@@ -911,6 +912,13 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev) | |||
911 | return err; | 912 | return err; |
912 | } | 913 | } |
913 | 914 | ||
915 | bdev->boot = devm_gpiod_get_optional(&serdev->dev, "boot", | ||
916 | GPIOD_OUT_LOW); | ||
917 | if (IS_ERR(bdev->boot)) { | ||
918 | err = PTR_ERR(bdev->boot); | ||
919 | return err; | ||
920 | } | ||
921 | |||
914 | bdev->pinctrl = devm_pinctrl_get(&serdev->dev); | 922 | bdev->pinctrl = devm_pinctrl_get(&serdev->dev); |
915 | if (IS_ERR(bdev->pinctrl)) { | 923 | if (IS_ERR(bdev->pinctrl)) { |
916 | err = PTR_ERR(bdev->pinctrl); | 924 | err = PTR_ERR(bdev->pinctrl); |
@@ -919,8 +927,10 @@ static int btmtkuart_parse_dt(struct serdev_device *serdev) | |||
919 | 927 | ||
920 | bdev->pins_boot = pinctrl_lookup_state(bdev->pinctrl, | 928 | bdev->pins_boot = pinctrl_lookup_state(bdev->pinctrl, |
921 | "default"); | 929 | "default"); |
922 | if (IS_ERR(bdev->pins_boot)) { | 930 | if (IS_ERR(bdev->pins_boot) && !bdev->boot) { |
923 | err = PTR_ERR(bdev->pins_boot); | 931 | err = PTR_ERR(bdev->pins_boot); |
932 | dev_err(&serdev->dev, | ||
933 | "Should assign RXD to LOW at boot stage\n"); | ||
924 | return err; | 934 | return err; |
925 | } | 935 | } |
926 | 936 | ||
@@ -996,8 +1006,14 @@ static int btmtkuart_probe(struct serdev_device *serdev) | |||
996 | set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); | 1006 | set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); |
997 | 1007 | ||
998 | if (btmtkuart_is_standalone(bdev)) { | 1008 | if (btmtkuart_is_standalone(bdev)) { |
999 | /* Switch to the specific pin state for the booting requires */ | 1009 | if (bdev->boot) { |
1000 | pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); | 1010 | gpiod_set_value_cansleep(bdev->boot, 1); |
1011 | } else { | ||
1012 | /* Switch to the specific pin state for the booting | ||
1013 | * requires. | ||
1014 | */ | ||
1015 | pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); | ||
1016 | } | ||
1001 | 1017 | ||
1002 | /* Power on */ | 1018 | /* Power on */ |
1003 | err = regulator_enable(bdev->vcc); | 1019 | err = regulator_enable(bdev->vcc); |
@@ -1017,6 +1033,10 @@ static int btmtkuart_probe(struct serdev_device *serdev) | |||
1017 | * mode the device requires for UART transfers. | 1033 | * mode the device requires for UART transfers. |
1018 | */ | 1034 | */ |
1019 | msleep(50); | 1035 | msleep(50); |
1036 | |||
1037 | if (bdev->boot) | ||
1038 | devm_gpiod_put(&serdev->dev, bdev->boot); | ||
1039 | |||
1020 | pinctrl_select_state(bdev->pinctrl, bdev->pins_runtime); | 1040 | pinctrl_select_state(bdev->pinctrl, bdev->pins_runtime); |
1021 | 1041 | ||
1022 | /* A standalone device doesn't depends on power domain on SoC, | 1042 | /* A standalone device doesn't depends on power domain on SoC, |
@@ -1037,10 +1057,8 @@ static int btmtkuart_probe(struct serdev_device *serdev) | |||
1037 | return 0; | 1057 | return 0; |
1038 | 1058 | ||
1039 | err_regulator_disable: | 1059 | err_regulator_disable: |
1040 | if (btmtkuart_is_standalone(bdev)) { | 1060 | if (btmtkuart_is_standalone(bdev)) |
1041 | pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); | ||
1042 | regulator_disable(bdev->vcc); | 1061 | regulator_disable(bdev->vcc); |
1043 | } | ||
1044 | 1062 | ||
1045 | return err; | 1063 | return err; |
1046 | } | 1064 | } |
@@ -1050,10 +1068,8 @@ static void btmtkuart_remove(struct serdev_device *serdev) | |||
1050 | struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); | 1068 | struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); |
1051 | struct hci_dev *hdev = bdev->hdev; | 1069 | struct hci_dev *hdev = bdev->hdev; |
1052 | 1070 | ||
1053 | if (btmtkuart_is_standalone(bdev)) { | 1071 | if (btmtkuart_is_standalone(bdev)) |
1054 | pinctrl_select_state(bdev->pinctrl, bdev->pins_boot); | ||
1055 | regulator_disable(bdev->vcc); | 1072 | regulator_disable(bdev->vcc); |
1056 | } | ||
1057 | 1073 | ||
1058 | hci_unregister_dev(hdev); | 1074 | hci_unregister_dev(hdev); |
1059 | hci_free_dev(hdev); | 1075 | hci_free_dev(hdev); |