Initial implementation of the power sequencing subsystem for linux v6.11
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmZpT80ACgkQEacuoBRx 13IftRAAq6VS7HWQ07npHeBp1YGuw/+3zjymS4esPoDouhMVeuNpsqqy7Y7JaaZ9 kLHi0FxdFH2qDZ8ATDqGm8UntORH4ugvXt/bphZiEXh6dFINDCIUmFITx/08MJc3 t6myhtWQTGgzGWZ+rlYGLPLOXwhQeYp9xNKt5ddQzRtPWuZxYnkwORr8hPlO8CqE 3XqF1ctf/j6UtQRxZEGLAvvatVlxPEnGxjnVfd7ShavjMvmxhYIAaBS0hg7tbLjx M9Q3iXn+n+0/XfCteZ05I4wq//HaQ2BUpUfxOp0kBOXB5BukaUk68xBV55PtG/ZT wfK8jtOV3iHV2np0hbRK3TZvqjpD00qRDOZGRGgPM5V6HmxJCvaLBBTC8S7vrwad 8t+WhXq1XeDVc0qcY3Alo+s3ECOyHsntCAvFywu8iF9unE0lWB6DIW98uOPTXTDM z+/VPDi+Wk6NY8LM6BqIXmoST5pjlo8FVytGpkwSG3pSGzFW9kj2sylvp8HvGnmf K0u43d5oeTSUvHUH5c5vtSwRgVM4Hcnm4w+tzdnY8rpZiVfuzg0iIVAShPJ1i4Qv P2Cw+4+G+sklV9HfYGSQcS203B+qYZfDQ5GqtzA9Pxx2gks2Qokm6mHIAVmlKqEY HZC5Dfplq5vLoHuyuS5mPvAC/EgsOjRnTK5qw9j7vCvdheWfosg= =Ft39 -----END PGP SIGNATURE----- Merge tag 'pwrseq-initial-for-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux into HEAD Initial implementation of the power sequencing subsystem for linux v6.11
This commit is contained in:
commit
f497862d99
@ -17908,6 +17908,14 @@ F: include/linux/pm_*
|
||||
F: include/linux/powercap.h
|
||||
F: kernel/configs/nopm.config
|
||||
|
||||
POWER SEQUENCING
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
|
||||
F: drivers/power/sequencing/
|
||||
F: include/linux/pwrseq/
|
||||
|
||||
POWER STATE COORDINATION INTERFACE (PSCI)
|
||||
M: Mark Rutland <mark.rutland@arm.com>
|
||||
M: Lorenzo Pieralisi <lpieralisi@kernel.org>
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
source "drivers/power/reset/Kconfig"
|
||||
source "drivers/power/sequencing/Kconfig"
|
||||
source "drivers/power/supply/Kconfig"
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
obj-$(CONFIG_POWER_SEQUENCING) += sequencing/
|
||||
obj-$(CONFIG_POWER_SUPPLY) += supply/
|
||||
|
29
drivers/power/sequencing/Kconfig
Normal file
29
drivers/power/sequencing/Kconfig
Normal file
@ -0,0 +1,29 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
menuconfig POWER_SEQUENCING
|
||||
tristate "Power Sequencing support"
|
||||
help
|
||||
Say Y here to enable the Power Sequencing subsystem.
|
||||
|
||||
This subsystem is designed to control power to devices that share
|
||||
complex resources and/or require specific power sequences to be run
|
||||
during power-up.
|
||||
|
||||
If unsure, say no.
|
||||
|
||||
if POWER_SEQUENCING
|
||||
|
||||
config POWER_SEQUENCING_QCOM_WCN
|
||||
tristate "Qualcomm WCN family PMU driver"
|
||||
default m if ARCH_QCOM
|
||||
help
|
||||
Say Y here to enable the power sequencing driver for Qualcomm
|
||||
WCN Bluetooth/WLAN chipsets.
|
||||
|
||||
Typically, a package from the Qualcomm WCN family contains the BT
|
||||
and WLAN modules whose power is controlled by the PMU module. As the
|
||||
former two share the power-up sequence which is executed by the PMU,
|
||||
this driver is needed for correct power control or else we'd risk not
|
||||
respecting the required delays between enabling Bluetooth and WLAN.
|
||||
|
||||
endif
|
6
drivers/power/sequencing/Makefile
Normal file
6
drivers/power/sequencing/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_POWER_SEQUENCING) += pwrseq-core.o
|
||||
pwrseq-core-y := core.o
|
||||
|
||||
obj-$(CONFIG_POWER_SEQUENCING_QCOM_WCN) += pwrseq-qcom-wcn.o
|
1105
drivers/power/sequencing/core.c
Normal file
1105
drivers/power/sequencing/core.c
Normal file
File diff suppressed because it is too large
Load Diff
336
drivers/power/sequencing/pwrseq-qcom-wcn.c
Normal file
336
drivers/power/sequencing/pwrseq-qcom-wcn.c
Normal file
@ -0,0 +1,336 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2024 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pwrseq/provider.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct pwrseq_qcom_wcn_pdata {
|
||||
const char *const *vregs;
|
||||
size_t num_vregs;
|
||||
unsigned int pwup_delay_ms;
|
||||
unsigned int gpio_enable_delay_ms;
|
||||
};
|
||||
|
||||
struct pwrseq_qcom_wcn_ctx {
|
||||
struct pwrseq_device *pwrseq;
|
||||
struct device_node *of_node;
|
||||
const struct pwrseq_qcom_wcn_pdata *pdata;
|
||||
struct regulator_bulk_data *regs;
|
||||
struct gpio_desc *bt_gpio;
|
||||
struct gpio_desc *wlan_gpio;
|
||||
struct clk *clk;
|
||||
unsigned long last_gpio_enable_jf;
|
||||
};
|
||||
|
||||
static void pwrseq_qcom_wcn_ensure_gpio_delay(struct pwrseq_qcom_wcn_ctx *ctx)
|
||||
{
|
||||
unsigned long diff_jiffies;
|
||||
unsigned int diff_msecs;
|
||||
|
||||
if (!ctx->pdata->gpio_enable_delay_ms)
|
||||
return;
|
||||
|
||||
diff_jiffies = jiffies - ctx->last_gpio_enable_jf;
|
||||
diff_msecs = jiffies_to_msecs(diff_jiffies);
|
||||
|
||||
if (diff_msecs < ctx->pdata->gpio_enable_delay_ms)
|
||||
msleep(ctx->pdata->gpio_enable_delay_ms - diff_msecs);
|
||||
}
|
||||
|
||||
static int pwrseq_qcom_wcn_vregs_enable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
return regulator_bulk_enable(ctx->pdata->num_vregs, ctx->regs);
|
||||
}
|
||||
|
||||
static int pwrseq_qcom_wcn_vregs_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
return regulator_bulk_disable(ctx->pdata->num_vregs, ctx->regs);
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_qcom_wcn_vregs_unit_data = {
|
||||
.name = "regulators-enable",
|
||||
.enable = pwrseq_qcom_wcn_vregs_enable,
|
||||
.disable = pwrseq_qcom_wcn_vregs_disable,
|
||||
};
|
||||
|
||||
static int pwrseq_qcom_wcn_clk_enable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
return clk_prepare_enable(ctx->clk);
|
||||
}
|
||||
|
||||
static int pwrseq_qcom_wcn_clk_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
clk_disable_unprepare(ctx->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_qcom_wcn_clk_unit_data = {
|
||||
.name = "clock-enable",
|
||||
.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,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int pwrseq_qcom_wcn_bt_enable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
pwrseq_qcom_wcn_ensure_gpio_delay(ctx);
|
||||
gpiod_set_value_cansleep(ctx->bt_gpio, 1);
|
||||
ctx->last_gpio_enable_jf = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwrseq_qcom_wcn_bt_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->bt_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_qcom_wcn_bt_unit_data = {
|
||||
.name = "bluetooth-enable",
|
||||
.deps = pwrseq_qcom_wcn_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);
|
||||
|
||||
pwrseq_qcom_wcn_ensure_gpio_delay(ctx);
|
||||
gpiod_set_value_cansleep(ctx->wlan_gpio, 1);
|
||||
ctx->last_gpio_enable_jf = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwrseq_qcom_wcn_wlan_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->wlan_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_qcom_wcn_wlan_unit_data = {
|
||||
.name = "wlan-enable",
|
||||
.deps = pwrseq_qcom_wcn_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);
|
||||
|
||||
if (ctx->pdata->pwup_delay_ms)
|
||||
msleep(ctx->pdata->pwup_delay_ms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = {
|
||||
.name = "bluetooth",
|
||||
.unit = &pwrseq_qcom_wcn_bt_unit_data,
|
||||
.post_enable = pwrseq_qcom_wcn_pwup_delay,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = {
|
||||
.name = "wlan",
|
||||
.unit = &pwrseq_qcom_wcn_wlan_unit_data,
|
||||
.post_enable = pwrseq_qcom_wcn_pwup_delay,
|
||||
};
|
||||
|
||||
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 char *const pwrseq_qca6390_vregs[] = {
|
||||
"vddio",
|
||||
"vddaon",
|
||||
"vddpmu",
|
||||
"vddrfa0p95",
|
||||
"vddrfa1p3",
|
||||
"vddrfa1p9",
|
||||
"vddpcie1p3",
|
||||
"vddpcie1p9",
|
||||
};
|
||||
|
||||
static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = {
|
||||
.vregs = pwrseq_qca6390_vregs,
|
||||
.num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs),
|
||||
.pwup_delay_ms = 60,
|
||||
.gpio_enable_delay_ms = 100,
|
||||
};
|
||||
|
||||
static const char *const pwrseq_wcn7850_vregs[] = {
|
||||
"vdd",
|
||||
"vddio",
|
||||
"vddio1p2",
|
||||
"vddaon",
|
||||
"vdddig",
|
||||
"vddrfa1p2",
|
||||
"vddrfa1p8",
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq,
|
||||
struct device *dev)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
struct device_node *dev_node = dev->of_node;
|
||||
|
||||
/*
|
||||
* The PMU supplies power to the Bluetooth and WLAN modules. both
|
||||
* consume the PMU AON output so check the presence of the
|
||||
* 'vddaon-supply' property and whether it leads us to the right
|
||||
* device.
|
||||
*/
|
||||
if (!of_property_present(dev_node, "vddaon-supply"))
|
||||
return 0;
|
||||
|
||||
struct device_node *reg_node __free(device_node) =
|
||||
of_parse_phandle(dev_node, "vddaon-supply", 0);
|
||||
if (!reg_node)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* `reg_node` is the PMU AON regulator, its parent is the `regulators`
|
||||
* node and finally its grandparent is the PMU device node that we're
|
||||
* looking for.
|
||||
*/
|
||||
if (!reg_node->parent || !reg_node->parent->parent ||
|
||||
reg_node->parent->parent != ctx->of_node)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pwrseq_qcom_wcn_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwrseq_qcom_wcn_ctx *ctx;
|
||||
struct pwrseq_config config;
|
||||
int i, ret;
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->of_node = dev->of_node;
|
||||
|
||||
ctx->pdata = of_device_get_match_data(dev);
|
||||
if (!ctx->pdata)
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"Failed to obtain platform data\n");
|
||||
|
||||
ctx->regs = devm_kcalloc(dev, ctx->pdata->num_vregs,
|
||||
sizeof(*ctx->regs), GFP_KERNEL);
|
||||
if (!ctx->regs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ctx->pdata->num_vregs; i++)
|
||||
ctx->regs[i].supply = ctx->pdata->vregs[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, ctx->pdata->num_vregs, ctx->regs);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get all regulators\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),
|
||||
"Failed to get the Bluetooth enable GPIO\n");
|
||||
|
||||
ctx->wlan_gpio = devm_gpiod_get_optional(dev, "wlan-enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->wlan_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio),
|
||||
"Failed to get the WLAN enable GPIO\n");
|
||||
|
||||
ctx->clk = devm_clk_get_optional(dev, NULL);
|
||||
if (IS_ERR(ctx->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->clk),
|
||||
"Failed to get the reference clock\n");
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
config.parent = dev;
|
||||
config.owner = THIS_MODULE;
|
||||
config.drvdata = ctx;
|
||||
config.match = pwrseq_qcom_wcn_match;
|
||||
config.targets = pwrseq_qcom_wcn_targets;
|
||||
|
||||
ctx->pwrseq = devm_pwrseq_device_register(dev, &config);
|
||||
if (IS_ERR(ctx->pwrseq))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->pwrseq),
|
||||
"Failed to register the power sequencer\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pwrseq_qcom_wcn_of_match[] = {
|
||||
{
|
||||
.compatible = "qcom,qca6390-pmu",
|
||||
.data = &pwrseq_qca6390_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,wcn7850-pmu",
|
||||
.data = &pwrseq_wcn7850_of_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pwrseq_qcom_wcn_of_match);
|
||||
|
||||
static struct platform_driver pwrseq_qcom_wcn_driver = {
|
||||
.driver = {
|
||||
.name = "pwrseq-qcom_wcn",
|
||||
.of_match_table = pwrseq_qcom_wcn_of_match,
|
||||
},
|
||||
.probe = pwrseq_qcom_wcn_probe,
|
||||
};
|
||||
module_platform_driver(pwrseq_qcom_wcn_driver);
|
||||
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");
|
||||
MODULE_DESCRIPTION("Qualcomm WCN PMU power sequencing driver");
|
||||
MODULE_LICENSE("GPL");
|
56
include/linux/pwrseq/consumer.h
Normal file
56
include/linux/pwrseq/consumer.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2024 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __POWER_SEQUENCING_CONSUMER_H__
|
||||
#define __POWER_SEQUENCING_CONSUMER_H__
|
||||
|
||||
#include <linux/err.h>
|
||||
|
||||
struct device;
|
||||
struct pwrseq_desc;
|
||||
|
||||
#if IS_ENABLED(CONFIG_POWER_SEQUENCING)
|
||||
|
||||
struct pwrseq_desc * __must_check
|
||||
pwrseq_get(struct device *dev, const char *target);
|
||||
void pwrseq_put(struct pwrseq_desc *desc);
|
||||
|
||||
struct pwrseq_desc * __must_check
|
||||
devm_pwrseq_get(struct device *dev, const char *target);
|
||||
|
||||
int pwrseq_power_on(struct pwrseq_desc *desc);
|
||||
int pwrseq_power_off(struct pwrseq_desc *desc);
|
||||
|
||||
#else /* CONFIG_POWER_SEQUENCING */
|
||||
|
||||
static inline struct pwrseq_desc * __must_check
|
||||
pwrseq_get(struct device *dev, const char *target)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline void pwrseq_put(struct pwrseq_desc *desc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct pwrseq_desc * __must_check
|
||||
devm_pwrseq_get(struct device *dev, const char *target)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline int pwrseq_power_on(struct pwrseq_desc *desc)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int pwrseq_power_off(struct pwrseq_desc *desc)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_POWER_SEQUENCING */
|
||||
|
||||
#endif /* __POWER_SEQUENCING_CONSUMER_H__ */
|
75
include/linux/pwrseq/provider.h
Normal file
75
include/linux/pwrseq/provider.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2024 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __POWER_SEQUENCING_PROVIDER_H__
|
||||
#define __POWER_SEQUENCING_PROVIDER_H__
|
||||
|
||||
struct device;
|
||||
struct module;
|
||||
struct pwrseq_device;
|
||||
|
||||
typedef int (*pwrseq_power_state_func)(struct pwrseq_device *);
|
||||
typedef int (*pwrseq_match_func)(struct pwrseq_device *, struct device *);
|
||||
|
||||
/**
|
||||
* struct pwrseq_unit_data - Configuration of a single power sequencing
|
||||
* unit.
|
||||
* @name: Name of the unit.
|
||||
* @deps: Units that must be enabled before this one and disabled after it
|
||||
* in the order they come in this array. Must be NULL-terminated.
|
||||
* @enable: Callback running the part of the power-on sequence provided by
|
||||
* this unit.
|
||||
* @disable: Callback running the part of the power-off sequence provided
|
||||
* by this unit.
|
||||
*/
|
||||
struct pwrseq_unit_data {
|
||||
const char *name;
|
||||
const struct pwrseq_unit_data **deps;
|
||||
pwrseq_power_state_func enable;
|
||||
pwrseq_power_state_func disable;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pwrseq_target_data - Configuration of a power sequencing target.
|
||||
* @name: Name of the target.
|
||||
* @unit: Final unit that this target must reach in order to be considered
|
||||
* enabled.
|
||||
* @post_enable: Callback run after the target unit has been enabled, *after*
|
||||
* the state lock has been released. It's useful for implementing
|
||||
* boot-up delays without blocking other users from powering up
|
||||
* using the same power sequencer.
|
||||
*/
|
||||
struct pwrseq_target_data {
|
||||
const char *name;
|
||||
const struct pwrseq_unit_data *unit;
|
||||
pwrseq_power_state_func post_enable;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pwrseq_config - Configuration used for registering a new provider.
|
||||
* @parent: Parent device for the sequencer. Must be set.
|
||||
* @owner: Module providing this device.
|
||||
* @drvdata: Private driver data.
|
||||
* @match: Provider callback used to match the consumer device to the sequencer.
|
||||
* @targets: Array of targets for this power sequencer. Must be NULL-terminated.
|
||||
*/
|
||||
struct pwrseq_config {
|
||||
struct device *parent;
|
||||
struct module *owner;
|
||||
void *drvdata;
|
||||
pwrseq_match_func match;
|
||||
const struct pwrseq_target_data **targets;
|
||||
};
|
||||
|
||||
struct pwrseq_device *
|
||||
pwrseq_device_register(const struct pwrseq_config *config);
|
||||
void pwrseq_device_unregister(struct pwrseq_device *pwrseq);
|
||||
struct pwrseq_device *
|
||||
devm_pwrseq_device_register(struct device *dev,
|
||||
const struct pwrseq_config *config);
|
||||
|
||||
void *pwrseq_device_get_drvdata(struct pwrseq_device *pwrseq);
|
||||
|
||||
#endif /* __POWER_SEQUENCING_PROVIDER_H__ */
|
Loading…
x
Reference in New Issue
Block a user