Re: [RFC PATCH 10/15] pwrseq: add support for QCA BT+WiFi power sequencer
From: Bjorn Andersson <hidden>
Date: 2021-08-19 23:17:41
Also in:
linux-arm-msm, linux-mmc, linux-wireless, lkml, netdev
On Mon 16 Aug 17:55 PDT 2021, Dmitry Baryshkov wrote: [..]
quoted hunk ↗ jump to hunk
diff --git a/drivers/power/pwrseq/pwrseq_qca.c b/drivers/power/pwrseq/pwrseq_qca.c new file mode 100644 index 000000000000..3421a4821126 --- /dev/null +++ b/drivers/power/pwrseq/pwrseq_qca.c@@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, Linaro Ltd. + * + * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> + * + * Power Sequencer for Qualcomm WiFi + BT SoCs + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/platform_device.h> +#include <linux/pwrseq/driver.h> +#include <linux/regulator/consumer.h> + +/* + * Voltage regulator information required for configuring the + * QCA WiFi+Bluetooth chipset + */ +struct qca_vreg { + const char *name; + unsigned int load_uA; +}; + +struct qca_device_data { + struct qca_vreg vddio;
Any particular reason why this isn't just the first entry in vregs and operated as part of the bulk API?
+ struct qca_vreg *vregs;
+ size_t num_vregs;
+ bool has_bt_en;
+ bool has_wifi_en;
+};
+
+struct pwrseq_qca;
+struct pwrseq_qca_one {
+ struct pwrseq_qca *common;
+ struct gpio_desc *enable;
+};
+
+#define PWRSEQ_QCA_WIFI 0
+#define PWRSEQ_QCA_BT 1
+
+#define PWRSEQ_QCA_MAX 2
+
+struct pwrseq_qca {
+ struct regulator *vddio;
+ struct gpio_desc *sw_ctrl;
+ struct pwrseq_qca_one pwrseq_qcas[PWRSEQ_QCA_MAX];
+ int num_vregs;
+ struct regulator_bulk_data vregs[];
+};
+
+static int pwrseq_qca_power_on(struct pwrseq *pwrseq)
+{
+ struct pwrseq_qca_one *qca_one = pwrseq_get_data(pwrseq);
+ int ret;
+
+ if (qca_one->common->vddio) {devm_regulator_get() doesn't return NULL, so this is always true.
+ ret = regulator_enable(qca_one->common->vddio);
+ if (ret)
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(qca_one->common->num_vregs, qca_one->common->vregs);
+ if (ret)
+ goto vddio_off;
+
+ if (qca_one->enable) {
+ gpiod_set_value_cansleep(qca_one->enable, 0);
+ msleep(50);
+ gpiod_set_value_cansleep(qca_one->enable, 1);
+ msleep(150);
+ }
+
+ if (qca_one->common->sw_ctrl) {
+ bool sw_ctrl_state = gpiod_get_value_cansleep(qca_one->common->sw_ctrl);
+ dev_dbg(&pwrseq->dev, "SW_CTRL is %d", sw_ctrl_state);
+ }
+
+ return 0;
+
+vddio_off:
+ regulator_disable(qca_one->common->vddio);
+
+ return ret;
+}[..]
+static int pwrseq_qca_probe(struct platform_device *pdev)
+{
+ struct pwrseq_qca *pwrseq_qca;
+ struct pwrseq *pwrseq;
+ struct pwrseq_provider *provider;
+ struct device *dev = &pdev->dev;
+ struct pwrseq_onecell_data *onecell;
+ const struct qca_device_data *data;
+ int ret, i;
+
+ data = device_get_match_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ pwrseq_qca = devm_kzalloc(dev, struct_size(pwrseq_qca, vregs, data->num_vregs), GFP_KERNEL);
+ if (!pwrseq_qca)
+ return -ENOMEM;
+
+ onecell = devm_kzalloc(dev, struct_size(onecell, pwrseqs, PWRSEQ_QCA_MAX), GFP_KERNEL);
+ if (!onecell)
+ return -ENOMEM;
+
+ ret = pwrseq_qca_regulators_init(dev, pwrseq_qca, data);
+ if (ret)
+ return ret;
+
+ if (data->has_wifi_en) {
+ pwrseq_qca->pwrseq_qcas[PWRSEQ_QCA_WIFI].enable = devm_gpiod_get(dev, "wifi-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(pwrseq_qca->pwrseq_qcas[PWRSEQ_QCA_WIFI].enable)) {
+ return dev_err_probe(dev, PTR_ERR(pwrseq_qca->pwrseq_qcas[PWRSEQ_QCA_WIFI].enable),
+ "failed to acquire WIFI enable GPIO\n");
+ }
+ }
+
+ if (data->has_bt_en) {
+ pwrseq_qca->pwrseq_qcas[PWRSEQ_QCA_BT].enable = devm_gpiod_get(dev, "bt-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(pwrseq_qca->pwrseq_qcas[PWRSEQ_QCA_BT].enable)) {
+ return dev_err_probe(dev, PTR_ERR(pwrseq_qca->pwrseq_qcas[PWRSEQ_QCA_BT].enable),
+ "failed to acquire BT enable GPIO\n");
+ }
+ }
+
+ pwrseq_qca->sw_ctrl = devm_gpiod_get_optional(dev, "swctrl", GPIOD_IN);
+ if (IS_ERR(pwrseq_qca->sw_ctrl)) {
+ return dev_err_probe(dev, PTR_ERR(pwrseq_qca->sw_ctrl),
+ "failed to acquire SW_CTRL gpio\n");
+ } else if (!pwrseq_qca->sw_ctrl)
+ dev_info(dev, "No SW_CTRL gpio\n");
Some {} around the else as well please.
Regards,
Bjorn