diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-20 12:41:03 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-20 12:41:03 -0800 |
commit | 0cea11025519f8f658963d8e835c7234450500bf (patch) | |
tree | f3c8bdf5074fdb32b1a3acaf1c3dc55c1b139fe1 /drivers/power | |
parent | 131561f2ca075f3737c2b4821c4d067dfba0f55f (diff) | |
parent | bd4c8bafcf50b6bd415c8bf04e98ebfba78071f9 (diff) | |
download | lwn-0cea11025519f8f658963d8e835c7234450500bf.tar.gz lwn-0cea11025519f8f658963d8e835c7234450500bf.zip |
Merge tag 'pwrseq-updates-for-v6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull power sequencing updates from Bartosz Golaszewski:
- extend support for the wcn6855 model in the pwrseq-qcom-wcn driver
- make this driver depend on CONFIG_OF=y as it uses some very
OF-specific interfaces and depends on phandle parsing
* tag 'pwrseq-updates-for-v6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
power: sequencing: qcom-wcn: improve support for wcn6855
power: sequencing: make the QCom PMU pwrseq driver depend on CONFIG_OF
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/sequencing/Kconfig | 1 | ||||
-rw-r--r-- | drivers/power/sequencing/pwrseq-qcom-wcn.c | 101 |
2 files changed, 99 insertions, 3 deletions
diff --git a/drivers/power/sequencing/Kconfig b/drivers/power/sequencing/Kconfig index c9f1cdb66524..ddcc42a98492 100644 --- a/drivers/power/sequencing/Kconfig +++ b/drivers/power/sequencing/Kconfig @@ -16,6 +16,7 @@ if POWER_SEQUENCING config POWER_SEQUENCING_QCOM_WCN tristate "Qualcomm WCN family PMU driver" default m if ARCH_QCOM + depends on OF help Say Y here to enable the power sequencing driver for Qualcomm WCN Bluetooth/WLAN chipsets. diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c index 4fa129877d7e..682a9beac69e 100644 --- a/drivers/power/sequencing/pwrseq-qcom-wcn.c +++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c @@ -22,6 +22,7 @@ struct pwrseq_qcom_wcn_pdata { size_t num_vregs; unsigned int pwup_delay_ms; unsigned int gpio_enable_delay_ms; + const struct pwrseq_target_data **targets; }; struct pwrseq_qcom_wcn_ctx { @@ -31,6 +32,7 @@ struct pwrseq_qcom_wcn_ctx { struct regulator_bulk_data *regs; struct gpio_desc *bt_gpio; struct gpio_desc *wlan_gpio; + struct gpio_desc *xo_clk_gpio; struct clk *clk; unsigned long last_gpio_enable_jf; }; @@ -98,6 +100,33 @@ static const struct pwrseq_unit_data *pwrseq_qcom_wcn_unit_deps[] = { NULL }; +static int pwrseq_qcom_wcn6855_clk_assert(struct pwrseq_device *pwrseq) +{ + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); + + if (!ctx->xo_clk_gpio) + return 0; + + msleep(1); + + gpiod_set_value_cansleep(ctx->xo_clk_gpio, 1); + usleep_range(100, 200); + + return 0; +} + +static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_xo_clk_assert = { + .name = "xo-clk-assert", + .enable = pwrseq_qcom_wcn6855_clk_assert, +}; + +static const struct pwrseq_unit_data *pwrseq_qcom_wcn6855_unit_deps[] = { + &pwrseq_qcom_wcn_vregs_unit_data, + &pwrseq_qcom_wcn_clk_unit_data, + &pwrseq_qcom_wcn6855_xo_clk_assert, + NULL +}; + static int pwrseq_qcom_wcn_bt_enable(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -125,6 +154,13 @@ static const struct pwrseq_unit_data pwrseq_qcom_wcn_bt_unit_data = { .disable = pwrseq_qcom_wcn_bt_disable, }; +static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_bt_unit_data = { + .name = "wlan-enable", + .deps = pwrseq_qcom_wcn6855_unit_deps, + .enable = pwrseq_qcom_wcn_bt_enable, + .disable = pwrseq_qcom_wcn_bt_disable, +}; + static int pwrseq_qcom_wcn_wlan_enable(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -152,6 +188,13 @@ static const struct pwrseq_unit_data pwrseq_qcom_wcn_wlan_unit_data = { .disable = pwrseq_qcom_wcn_wlan_disable, }; +static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_wlan_unit_data = { + .name = "wlan-enable", + .deps = pwrseq_qcom_wcn6855_unit_deps, + .enable = pwrseq_qcom_wcn_wlan_enable, + .disable = pwrseq_qcom_wcn_wlan_disable, +}; + static int pwrseq_qcom_wcn_pwup_delay(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -162,6 +205,18 @@ static int pwrseq_qcom_wcn_pwup_delay(struct pwrseq_device *pwrseq) return 0; } +static int pwrseq_qcom_wcn6855_xo_clk_deassert(struct pwrseq_device *pwrseq) +{ + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); + + if (ctx->xo_clk_gpio) { + usleep_range(2000, 5000); + gpiod_set_value_cansleep(ctx->xo_clk_gpio, 0); + } + + return pwrseq_qcom_wcn_pwup_delay(pwrseq); +} + static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = { .name = "bluetooth", .unit = &pwrseq_qcom_wcn_bt_unit_data, @@ -174,12 +229,30 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = { .post_enable = pwrseq_qcom_wcn_pwup_delay, }; +static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = { + .name = "bluetooth", + .unit = &pwrseq_qcom_wcn6855_bt_unit_data, + .post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert, +}; + +static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = { + .name = "wlan", + .unit = &pwrseq_qcom_wcn6855_wlan_unit_data, + .post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert, +}; + static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = { &pwrseq_qcom_wcn_bt_target_data, &pwrseq_qcom_wcn_wlan_target_data, NULL }; +static const struct pwrseq_target_data *pwrseq_qcom_wcn6855_targets[] = { + &pwrseq_qcom_wcn6855_bt_target_data, + &pwrseq_qcom_wcn6855_wlan_target_data, + NULL +}; + static const char *const pwrseq_qca6390_vregs[] = { "vddio", "vddaon", @@ -196,13 +269,28 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = { .num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs), .pwup_delay_ms = 60, .gpio_enable_delay_ms = 100, + .targets = pwrseq_qcom_wcn_targets, +}; + +static const char *const pwrseq_wcn6855_vregs[] = { + "vddio", + "vddaon", + "vddpmu", + "vddpmumx", + "vddpmucx", + "vddrfa0p95", + "vddrfa1p3", + "vddrfa1p9", + "vddpcie1p3", + "vddpcie1p9", }; static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6855_of_data = { - .vregs = pwrseq_qca6390_vregs, - .num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs), + .vregs = pwrseq_wcn6855_vregs, + .num_vregs = ARRAY_SIZE(pwrseq_wcn6855_vregs), .pwup_delay_ms = 50, .gpio_enable_delay_ms = 5, + .targets = pwrseq_qcom_wcn6855_targets, }; static const char *const pwrseq_wcn7850_vregs[] = { @@ -219,6 +307,7 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = { .vregs = pwrseq_wcn7850_vregs, .num_vregs = ARRAY_SIZE(pwrseq_wcn7850_vregs), .pwup_delay_ms = 50, + .targets = pwrseq_qcom_wcn_targets, }; static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, @@ -295,6 +384,12 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio), "Failed to get the WLAN enable GPIO\n"); + ctx->xo_clk_gpio = devm_gpiod_get_optional(dev, "xo-clk", + GPIOD_OUT_LOW); + if (IS_ERR(ctx->xo_clk_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->xo_clk_gpio), + "Failed to get the XO_CLK GPIO\n"); + /* * Set direction to output but keep the current value in order to not * disable the WLAN module accidentally if it's already powered on. @@ -313,7 +408,7 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) config.owner = THIS_MODULE; config.drvdata = ctx; config.match = pwrseq_qcom_wcn_match; - config.targets = pwrseq_qcom_wcn_targets; + config.targets = ctx->pdata->targets; ctx->pwrseq = devm_pwrseq_device_register(dev, &config); if (IS_ERR(ctx->pwrseq)) |