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 | |
| 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')
| -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); |
