On Mon 16 Aug 17:55 PDT 2021, Dmitry Baryshkov wrote: [..] > 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@xxxxxxxxxx> > + * > + * 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