From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C931DC07E9E for ; Tue, 6 Jul 2021 07:54:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9259861964 for ; Tue, 6 Jul 2021 07:54:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230376AbhGFH5U (ORCPT ); Tue, 6 Jul 2021 03:57:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230356AbhGFH5T (ORCPT ); Tue, 6 Jul 2021 03:57:19 -0400 Received: from mail-ua1-x92c.google.com (mail-ua1-x92c.google.com [IPv6:2607:f8b0:4864:20::92c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7938AC061760 for ; Tue, 6 Jul 2021 00:54:41 -0700 (PDT) Received: by mail-ua1-x92c.google.com with SMTP id r9so7938167ual.7 for ; Tue, 06 Jul 2021 00:54:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=3qVePH9JFi87gONiyEqEdKz88cGEkgKWEUb6Ms2bBU8=; b=XRM9E87jhVyUlS0XtwfZ5x2PTgH5hDP6NQ5u66cYG0oPKzkuDFYWgxKpqOjeVUemWX yp6ze/h8jcInvAKuFuqrN3gw5nEMqK/0z/nd/DkxJigc71FkzP14YJ90oivp2vncKvSB RHQBawnAg5S5EpHEmcmHrKIfBPseJL3z/qsAJnSQAAqiBR+Zgo77DmKobTCIeoEuzvRC jQwBkEc5cfDE/mlOz0JcE763rwsudr3CKHcNntk9D5SLRsbpWgiNsZ/9V3x4X8VzTQqx 88GQMa535qU15/xdVecvblRxVXJ6xWoVc6MKKYsEtmUTBc3tV/M+a8iqoLK9N8c8KgoO HS8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=3qVePH9JFi87gONiyEqEdKz88cGEkgKWEUb6Ms2bBU8=; b=h3lUWQHrOivho9lkptkwpIsHon7s9FbfHtKbH++2iZhnnQc7IvZd76PxP062zi6Pz7 r/3gmf0yfa1nC2t0GRQPV4IRCnjOBh7PRdiP6EAO3UpqG9CTHwhxHXrQaWp0DThljO9D 3rcKvp4uM5bexs9rkui71hNidtluO0m1eaROIN34YlGdenAMHnF3PkvMApiK2trVqZ8m Bnqarv2sESobu3BntiS8HguFvTcD1Ff/B4bWla7shzAY+0S4I0Rxn4o4fcKISYPAyvMZ jtWh1RWMhZ9DWCCsYiwTufpbPxt4qqyfCerpxnVCjfBM9uXuZ7JMovso3cWRoVycjoP0 SkQA== X-Gm-Message-State: AOAM531lPKU7+Z/y+1QZrDx4SRe9fSUwl2GNmXRJf3/wCmKhsK0HGm7a 7BhK/Wj6qckdOIYe5waDvaT2Yzw8zeCVVAVbp6VTjQ== X-Google-Smtp-Source: ABdhPJxEZnuXd+n69XMyNsgZarr+p438MNk52aNKyWibfsJUb8OZKm+m9/Gkou1JtUbyJlcMGha3wNxb2AkejdiHRxU= X-Received: by 2002:ab0:42a6:: with SMTP id j35mr11625376uaj.129.1625558080121; Tue, 06 Jul 2021 00:54:40 -0700 (PDT) MIME-Version: 1.0 References: <20210621223141.1638189-1-dmitry.baryshkov@linaro.org> <20210621223141.1638189-3-dmitry.baryshkov@linaro.org> In-Reply-To: <20210621223141.1638189-3-dmitry.baryshkov@linaro.org> From: Ulf Hansson Date: Tue, 6 Jul 2021 09:54:03 +0200 Message-ID: Subject: Re: [PATCH v3 2/7] regulator: qca6390: add support for QCA639x powerup sequence To: Dmitry Baryshkov , Peter Chen Cc: Andy Gross , Bjorn Andersson , Rob Herring , Liam Girdwood , Mark Brown , Marcel Holtmann , Johan Hedberg , Luiz Augusto von Dentz , linux-arm-msm , Manivannan Sadhasivam , DTML , Linux Kernel Mailing List , linux-bluetooth@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org + Peter On Tue, 22 Jun 2021 at 00:32, Dmitry Baryshkov wrote: > > Qualcomm QCA6390/1 is a family of WiFi + Bluetooth SoCs, with BT part > being controlled through the UART and WiFi being present on PCIe > bus. Both blocks share common power sources. Add device driver handling > power sequencing of QCA6390/1. > > Signed-off-by: Dmitry Baryshkov Power sequencing of discoverable buses have been discussed several times before at LKML. The last attempt [1] I am aware of, was in 2017 from Peter Chen. I don't think there is a common solution, yet. Note that, this isn't specific to the PCIe bus, but rather to all buses that may have discoverable devices attached and which need some kind of pre-power-sequence before they can be discovered/probed. USB, PCIe, SDIO, etc. Long time ago, we fixed the problem for SDIO (that also can have WiFi, UART, bluetooth chips attached), but unfortunately through an MMC subsystem specific implementation, that can't be re-used in a generic way. In any case, I have looped in Peter Chen, maybe he can provide us with a better update on how things have moved forward, if at all. Kind regards Uffe [1] https://www.spinics.net/lists/linux-usb/msg158451.html > --- > drivers/regulator/Kconfig | 13 +++ > drivers/regulator/Makefile | 1 + > drivers/regulator/qcom-qca639x.c | 157 +++++++++++++++++++++++++++++++ > 3 files changed, 171 insertions(+) > create mode 100644 drivers/regulator/qcom-qca639x.c > > diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig > index 3e7a38525cb3..7a560cddea7a 100644 > --- a/drivers/regulator/Kconfig > +++ b/drivers/regulator/Kconfig > @@ -909,6 +909,19 @@ config REGULATOR_PWM > This driver supports PWM controlled voltage regulators. PWM > duty cycle can increase or decrease the voltage. > > +config REGULATOR_QCOM_QCA639X > + tristate "Qualcomm QCA639x WiFi/Bluetooth module support" > + help > + If you say yes to this option, support will be included for Qualcomm > + QCA639x family of WiFi and Bluetooth SoCs. Note, this driver supports > + only power control for this SoC, you still have to enable individual > + Bluetooth and WiFi drivers. This driver is only necessary on ARM > + platforms with this chip. PCIe cards handle power sequencing on their > + own. > + > + Say M here if you want to include support for QCA639x chips as a > + module. This will build a module called "qcom-qca639x". > + > config REGULATOR_QCOM_RPM > tristate "Qualcomm RPM regulator driver" > depends on MFD_QCOM_RPM > diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile > index 580b015296ea..129c2110b78d 100644 > --- a/drivers/regulator/Makefile > +++ b/drivers/regulator/Makefile > @@ -99,6 +99,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o > obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o > obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o > obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o > +obj-$(CONFIG_REGULATOR_QCOM_QCA639X) += qcom-qca639x.o > obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o > obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o > obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o > diff --git a/drivers/regulator/qcom-qca639x.c b/drivers/regulator/qcom-qca639x.c > new file mode 100644 > index 000000000000..a2c78c0f8baa > --- /dev/null > +++ b/drivers/regulator/qcom-qca639x.c > @@ -0,0 +1,157 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2021, Linaro Limited > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define MAX_NUM_REGULATORS 8 > + > +static struct vreg { > + const char *name; > + unsigned int load_uA; > +} vregs[MAX_NUM_REGULATORS] = { > + /* 2.0 V */ > + { "vddpcie2", 15000 }, > + { "vddrfa3", 400000 }, > + > + /* 0.95 V */ > + { "vddaon", 100000 }, > + { "vddpmu", 1250000 }, > + { "vddrfa1", 200000 }, > + > + /* 1.35 V */ > + { "vddrfa2", 400000 }, > + { "vddpcie1", 35000 }, > + > + /* 1.8 V */ > + { "vddio", 20000 }, > +}; > + > +struct qca6390_data { > + struct device *dev; > + struct regulator_bulk_data regulators[MAX_NUM_REGULATORS]; > + size_t num_vregs; > + > + struct regulator_desc desc; > + struct regulator_dev *regulator_dev; > + unsigned int enable_counter; > +}; > + > +#define domain_to_data(domain) container_of(domain, struct qca6390_data, pd) > + > +static int qca6390_enable(struct regulator_dev *rdev) > +{ > + struct qca6390_data *data = rdev_get_drvdata(rdev); > + int ret; > + > + ret = regulator_bulk_enable(data->num_vregs, data->regulators); > + if (ret) { > + dev_err(data->dev, "Failed to enable regulators"); > + return ret; > + } > + > + /* Wait for 1ms before toggling enable pins. */ > + usleep_range(1000, 2000); > + > + data->enable_counter++; > + > + return 0; > +} > + > +static int qca6390_disable(struct regulator_dev *rdev) > +{ > + struct qca6390_data *data = rdev_get_drvdata(rdev); > + > + regulator_bulk_disable(data->num_vregs, data->regulators); > + > + data->enable_counter--; > + > + return 0; > +} > + > +static int qca6390_is_enabled(struct regulator_dev *rdev) > +{ > + struct qca6390_data *data = rdev_get_drvdata(rdev); > + > + return data->enable_counter > 0; > +} > + > +static const struct regulator_ops qca6390_ops = { > + .enable = qca6390_enable, > + .disable = qca6390_disable, > + .is_enabled = qca6390_is_enabled, > +}; > + > +static int qca6390_probe(struct platform_device *pdev) > +{ > + struct qca6390_data *data; > + struct device *dev = &pdev->dev; > + struct regulator_config cfg = { }; > + int i, ret; > + > + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + data->dev = dev; > + data->num_vregs = ARRAY_SIZE(vregs); > + > + for (i = 0; i < data->num_vregs; i++) > + data->regulators[i].supply = vregs[i].name; > + > + ret = devm_regulator_bulk_get(dev, data->num_vregs, data->regulators); > + if (ret < 0) > + return ret; > + > + for (i = 0; i < data->num_vregs; i++) { > + ret = regulator_set_load(data->regulators[i].consumer, vregs[i].load_uA); > + if (ret) > + return ret; > + } > + > + data->desc.name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); > + if (!data->desc.name) > + return -ENOMEM; > + > + data->desc.type = REGULATOR_VOLTAGE; > + data->desc.owner = THIS_MODULE; > + data->desc.ops = &qca6390_ops; > + > + cfg.dev = dev; > + cfg.of_node = dev->of_node; > + cfg.driver_data = data; > + cfg.init_data = of_get_regulator_init_data(dev, dev->of_node, &data->desc); > + > + data->regulator_dev = devm_regulator_register(dev, &data->desc, &cfg); > + if (IS_ERR(data->regulator_dev)) { > + ret = PTR_ERR(data->regulator_dev); > + return ret; > + } > + > + platform_set_drvdata(pdev, data); > + > + return 0; > +} > + > +static const struct of_device_id qca6390_of_match[] = { > + { .compatible = "qcom,qca6390" }, > +}; > + > +static struct platform_driver qca6390_driver = { > + .probe = qca6390_probe, > + .driver = { > + .name = "qca6390", > + .of_match_table = qca6390_of_match, > + }, > +}; > + > +module_platform_driver(qca6390_driver); > +MODULE_AUTHOR("Dmitry Baryshkov "); > +MODULE_DESCRIPTION("Power control for Qualcomm QCA6390/1 BT/WiFi chip"); > +MODULE_LICENSE("GPL v2"); > -- > 2.30.2 >