Skip to content

Commit

Permalink
Merge tag 'pwrseq-updates-for-v6.13-rc1' of git://git.kernel.org/pub/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
torvalds committed Nov 20, 2024
2 parents 131561f + bd4c8ba commit 0cea110
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 3 deletions.
1 change: 1 addition & 0 deletions drivers/power/sequencing/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
101 changes: 98 additions & 3 deletions drivers/power/sequencing/pwrseq-qcom-wcn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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",
Expand All @@ -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[] = {
Expand All @@ -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,
Expand Down Expand Up @@ -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.
Expand All @@ -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))
Expand Down

0 comments on commit 0cea110

Please sign in to comment.