]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/bluetooth/btmtkuart.c
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux.git] / drivers / bluetooth / btmtkuart.c
index f5dbeec8e2748b6a812b0ca41378de6d620b2e81..e11169ad8247ecea7cda9dbf56b8847727032066 100644 (file)
@@ -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);