unsigned int pwup_delay_ms;
unsigned int gpio_enable_delay_ms;
const struct pwrseq_target_data **targets;
+ bool has_vddio; /* separate VDD IO regulator */
+ int (*match)(struct pwrseq_device *pwrseq, struct device *dev);
};
struct pwrseq_qcom_wcn_ctx {
struct device_node *of_node;
const struct pwrseq_qcom_wcn_pdata *pdata;
struct regulator_bulk_data *regs;
+ struct regulator *vddio;
struct gpio_desc *bt_gpio;
struct gpio_desc *wlan_gpio;
struct gpio_desc *xo_clk_gpio;
msleep(ctx->pdata->gpio_enable_delay_ms - diff_msecs);
}
+static int pwrseq_qcom_wcn_vddio_enable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return regulator_enable(ctx->vddio);
+}
+
+static int pwrseq_qcom_wcn_vddio_disable(struct pwrseq_device *pwrseq)
+{
+ struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
+
+ return regulator_disable(ctx->vddio);
+}
+
+static const struct pwrseq_unit_data pwrseq_qcom_wcn_vddio_unit_data = {
+ .name = "vddio-enable",
+ .enable = pwrseq_qcom_wcn_vddio_enable,
+ .disable = pwrseq_qcom_wcn_vddio_disable,
+};
+
static int pwrseq_qcom_wcn_vregs_enable(struct pwrseq_device *pwrseq)
{
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
.disable = pwrseq_qcom_wcn_clk_disable,
};
+static const struct pwrseq_unit_data *pwrseq_qcom_wcn3990_unit_deps[] = {
+ &pwrseq_qcom_wcn_vddio_unit_data,
+ &pwrseq_qcom_wcn_vregs_unit_data,
+ NULL,
+};
+
+static const struct pwrseq_unit_data pwrseq_qcom_wcn3990_unit_data = {
+ .name = "clock-enable",
+ .deps = pwrseq_qcom_wcn3990_unit_deps,
+ .enable = pwrseq_qcom_wcn_clk_enable,
+ .disable = pwrseq_qcom_wcn_clk_disable,
+};
+
static const struct pwrseq_unit_data *pwrseq_qcom_wcn_unit_deps[] = {
&pwrseq_qcom_wcn_vregs_unit_data,
&pwrseq_qcom_wcn_clk_unit_data,
.post_enable = pwrseq_qcom_wcn_pwup_delay,
};
+/* There are no separate BT and WLAN enablement pins */
+static const struct pwrseq_target_data pwrseq_qcom_wcn3990_bt_target_data = {
+ .name = "bluetooth",
+ .unit = &pwrseq_qcom_wcn3990_unit_data,
+};
+
+static const struct pwrseq_target_data pwrseq_qcom_wcn3990_wlan_target_data = {
+ .name = "wlan",
+ .unit = &pwrseq_qcom_wcn3990_unit_data,
+};
+
static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
.name = "bluetooth",
.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
NULL
};
+static const struct pwrseq_target_data *pwrseq_qcom_wcn3990_targets[] = {
+ &pwrseq_qcom_wcn3990_bt_target_data,
+ &pwrseq_qcom_wcn3990_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,
.targets = pwrseq_qcom_wcn_targets,
};
+static const char *const pwrseq_wcn3990_vregs[] = {
+ /* vddio is handled separately */
+ "vddxo",
+ "vddrf",
+ "vddch0",
+ "vddch1",
+};
+
+static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
+ struct device *dev);
+
+static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn3990_of_data = {
+ .vregs = pwrseq_wcn3990_vregs,
+ .num_vregs = ARRAY_SIZE(pwrseq_wcn3990_vregs),
+ .pwup_delay_ms = 50,
+ .targets = pwrseq_qcom_wcn3990_targets,
+ .has_vddio = true,
+ .match = pwrseq_qcom_wcn3990_match,
+};
+
static const char *const pwrseq_wcn6750_vregs[] = {
"vddaon",
"vddasd",
.targets = pwrseq_qcom_wcn_targets,
};
-static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
- struct device *dev)
+static int pwrseq_qcom_wcn_match_regulator(struct pwrseq_device *pwrseq,
+ struct device *dev,
+ const char *name)
{
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
struct device_node *dev_node = dev->of_node;
* 'vddaon-supply' property and whether it leads us to the right
* device.
*/
- if (!of_property_present(dev_node, "vddaon-supply"))
+ if (!of_property_present(dev_node, name))
return PWRSEQ_NO_MATCH;
struct device_node *reg_node __free(device_node) =
- of_parse_phandle(dev_node, "vddaon-supply", 0);
+ of_parse_phandle(dev_node, name, 0);
if (!reg_node)
return PWRSEQ_NO_MATCH;
return PWRSEQ_MATCH_OK;
}
+static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
+ struct device *dev)
+{
+ return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddaon-supply");
+}
+
+static int pwrseq_qcom_wcn3990_match(struct pwrseq_device *pwrseq,
+ struct device *dev)
+{
+ int ret;
+
+ /* BT device */
+ ret = pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vddio-supply");
+ if (ret == PWRSEQ_MATCH_OK)
+ return ret;
+
+ /* WiFi device match */
+ return pwrseq_qcom_wcn_match_regulator(pwrseq, dev, "vdd-1.8-xo-supply");
+}
+
static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
return dev_err_probe(dev, ret,
"Failed to get all regulators\n");
+ if (ctx->pdata->has_vddio) {
+ ctx->vddio = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(ctx->vddio))
+ return dev_err_probe(dev, ret, "Failed to get VDDIO\n");
+ }
+
ctx->bt_gpio = devm_gpiod_get_optional(dev, "bt-enable", GPIOD_OUT_LOW);
if (IS_ERR(ctx->bt_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->bt_gpio),
config.parent = dev;
config.owner = THIS_MODULE;
config.drvdata = ctx;
- config.match = pwrseq_qcom_wcn_match;
+ config.match = ctx->pdata->match ? : pwrseq_qcom_wcn_match;
config.targets = ctx->pdata->targets;
ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
}
static const struct of_device_id pwrseq_qcom_wcn_of_match[] = {
+ {
+ .compatible = "qcom,wcn3950-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3988-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3990-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3991-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
+ {
+ .compatible = "qcom,wcn3998-pmu",
+ .data = &pwrseq_wcn3990_of_data,
+ },
{
.compatible = "qcom,qca6390-pmu",
.data = &pwrseq_qca6390_of_data,