mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
power sequencing updates for v7.4-rc1
Power sequencing core:
- add a suite of kunit test cases for the power sequencing core
functionalities
- provide a new consumer API: pwrseq_is_controllable()
New Drivers:
- add the Renesas RZ/G3L Power Ready driver which provides information
on power readiness for various IPs on RZ/G3L
Driver changes:
- use pwrseq_is_controllable() to report controllability to consumers in
pwrseq-qcom-wcn and pwrseq-pcie-m2
- add support for PCIe switch topologies to pwrseq-pcie-m2
- add the PCI ID for Foxconn WCN7850 to pwrseq-pcie-m2
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmrV2hkACgkQBZ0uy/82
hMMBnQ//ciYweRR/AgASdvZsybFnDirMDKi07WFc5xnes5aAQs7IO2qbd2sk+tes
tFTpzNHA/s1w62kpfabRb6oyXAP5LgqfAGR6LBTMCPApUYh3a2FfyK515ATfG6Ql
a2oxjD5D/WO8utqt9daebYZX7fKWSMifhEI7ystHtJDtoWNTsEXPjkzDZNdLmiir
g7dv0fhCssdvnlT1OUYUgFjQ0GAqPCgouC9jSwRzneHjSmAf8pv6d8r7d+SSUEI8
XcRgpfcn3HEAMnfwLGUXFFf9kRwHOvL6wKgvzBck4y0KnsKJ04Q77RQYWPepf8ZL
WLys63KuOvWSol+L7Bb8NwHT3+ZTyIYu62nlXRs9xNrJSpEDsXxQWjgEA24L4FdI
4ZJSic0UUGYZkAAIrcxyrx3+Kv/bqCma5SamVUs0fmcos3SLddV4ymPYkFye0HLu
OhpSCheA4oHMxoqR0Z284i9dWkktPLSdAeBXWCT49qU8YRdgt7PvEVhhHj/yaEJY
g0M0J/xAxghBsM7SpfkeEtNBINXq293N3+U5iwnXt+80pA/XQFgVc1qpjbCItnSy
nZzxZwWITFTAKmGcASktSmWyzC3mNRJzBpulcBiFcHWqAifs4rPJ4rZQSpH5frKX
KTua2o6SnONiK7QGC5Q9Rhp5OIoS/uOgWjgakKMRwkuEP73SvCA=
=EM35
-----END PGP SIGNATURE-----
Merge tag 'pwrseq-updates-for-v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull power sequencing updates from Bartosz Golaszewski:
"The bulk of added lines are kunit tests that comprehensively verify
the core functionality of the power sequencing framework.
Other than that, we have another pwrseq driver: Renesas RZ/G3L Power
Ready and support for more models in pwrseq-pcie-m2. We also added a
new consumer-facing API in the form of pwrseq_is_controllable()
function which allows consumers to check if a given target resource is
actually host-controllable.
Summary:
Power sequencing core:
- add a suite of kunit test cases for the power sequencing core
functionalities
- provide a new consumer API: pwrseq_is_controllable()
New Drivers:
- add the Renesas RZ/G3L Power Ready driver which provides
information on power readiness for various IPs on RZ/G3L
Driver changes:
- use pwrseq_is_controllable() to report controllability to consumers
in pwrseq-qcom-wcn and pwrseq-pcie-m2
- add support for PCIe switch topologies to pwrseq-pcie-m2
- add the PCI ID for Foxconn WCN7850 to pwrseq-pcie-m2"
* tag 'pwrseq-updates-for-v7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
power: sequencing: pcie-m2: Add Foxconn WCN7850 subsystem PCI ID
power: sequencing: qcom-wcn: Report power controllability
power: sequencing: pcie-m2: Report power controllability
power: sequencing: Add pwrseq_is_controllable() API
power: sequencing: add kunit test cases
power: sequencing: pwrseq-pcie-m2: Support PCIe switch topologies
power: sequencing: Add Renesas RZ/G3L Power Ready driver
This commit is contained in:
commit
74b1dbf6f2
|
|
@ -27,6 +27,15 @@ config POWER_SEQUENCING_QCOM_WCN
|
|||
this driver is needed for correct power control or else we'd risk not
|
||||
respecting the required delays between enabling Bluetooth and WLAN.
|
||||
|
||||
config POWER_SEQUENCING_RENESAS_PWRRDY
|
||||
tristate "Renesas Power Ready sequencing driver"
|
||||
depends on SYSC_RZ || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
Say Y here to enable the power sequencing driver for the Renesas
|
||||
Power Ready signals. This driver handles the power ready signals
|
||||
required to power on the various IP's on RZ/G3L platform.
|
||||
|
||||
config POWER_SEQUENCING_TH1520_GPU
|
||||
tristate "T-HEAD TH1520 GPU power sequencing driver"
|
||||
depends on ARCH_THEAD || COMPILE_TEST
|
||||
|
|
@ -47,4 +56,14 @@ config POWER_SEQUENCING_PCIE_M2
|
|||
connectors. This driver handles the power sequencing for the M.2
|
||||
connectors exposing multiple interfaces like PCIe, SATA, UART, etc...
|
||||
|
||||
config POWER_SEQUENCING_KUNIT
|
||||
tristate "Build power sequencing KUnit test cases"
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
Say Y here to build the module containing KUnit test cases for the
|
||||
power sequencing subsystem.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -4,5 +4,7 @@ obj-$(CONFIG_POWER_SEQUENCING) += pwrseq-core.o
|
|||
pwrseq-core-y := core.o
|
||||
|
||||
obj-$(CONFIG_POWER_SEQUENCING_QCOM_WCN) += pwrseq-qcom-wcn.o
|
||||
obj-$(CONFIG_POWER_SEQUENCING_RENESAS_PWRRDY) += pwrseq-renesas-pwrrdy.o
|
||||
obj-$(CONFIG_POWER_SEQUENCING_TH1520_GPU) += pwrseq-thead-gpu.o
|
||||
obj-$(CONFIG_POWER_SEQUENCING_PCIE_M2) += pwrseq-pcie-m2.o
|
||||
obj-$(CONFIG_POWER_SEQUENCING_KUNIT) += pwrseq-kunit.o
|
||||
|
|
|
|||
|
|
@ -183,12 +183,15 @@ static void pwrseq_unit_release(struct kref *ref)
|
|||
* 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.
|
||||
* @is_controllable: Optional callback reporting whether enabling/disabling
|
||||
* this target actually controls power.
|
||||
*/
|
||||
struct pwrseq_target {
|
||||
struct list_head list;
|
||||
const char *name;
|
||||
struct pwrseq_unit *unit;
|
||||
pwrseq_power_state_func post_enable;
|
||||
pwrseq_is_controllable_func is_controllable;
|
||||
};
|
||||
|
||||
static struct pwrseq_target *
|
||||
|
|
@ -207,6 +210,7 @@ pwrseq_target_new(const struct pwrseq_target_data *data)
|
|||
}
|
||||
|
||||
target->post_enable = data->post_enable;
|
||||
target->is_controllable = data->is_controllable;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
|
@ -994,6 +998,51 @@ struct device *pwrseq_to_device(struct pwrseq_desc *desc)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pwrseq_to_device);
|
||||
|
||||
/**
|
||||
* pwrseq_is_controllable() - Check whether the target provides a
|
||||
* host-controllable power actuator.
|
||||
* @desc: Descriptor referencing the power sequencer.
|
||||
*
|
||||
* Some power sequencing targets provide no host-controllable enable for their
|
||||
* function on a given board, for instance when the enable line is not wired up
|
||||
* and is instead hardwired to an always-on level. For such targets a call to
|
||||
* pwrseq_power_off() is still allowed, so that the consumer can drop its vote
|
||||
* on the (possibly shared) resources, but the host cannot gate the function
|
||||
* on its own.
|
||||
*
|
||||
* Returns:
|
||||
* True if the target provides a host-controllable power actuator, false
|
||||
* otherwise. Also returns false if @desc is NULL.
|
||||
*/
|
||||
bool pwrseq_is_controllable(struct pwrseq_desc *desc)
|
||||
{
|
||||
struct pwrseq_device *pwrseq;
|
||||
struct pwrseq_target *target;
|
||||
struct pwrseq_unit *unit;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!desc)
|
||||
return false;
|
||||
|
||||
pwrseq = desc->pwrseq;
|
||||
target = desc->target;
|
||||
unit = target->unit;
|
||||
|
||||
guard(rwsem_read)(&pwrseq->rw_lock);
|
||||
if (!device_is_registered(&pwrseq->dev))
|
||||
return false;
|
||||
|
||||
if (!unit->enable && !unit->disable)
|
||||
return false;
|
||||
|
||||
if (!target->is_controllable)
|
||||
return true;
|
||||
|
||||
return target->is_controllable(pwrseq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwrseq_is_controllable);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||
|
||||
struct pwrseq_debugfs_count_ctx {
|
||||
|
|
|
|||
1497
drivers/power/sequencing/pwrseq-kunit.c
Normal file
1497
drivers/power/sequencing/pwrseq-kunit.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -83,6 +83,18 @@ static int pwrseq_pci_m2_e_uart_disable(struct pwrseq_device *pwrseq)
|
|||
return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1);
|
||||
}
|
||||
|
||||
static bool pwrseq_pci_m2_e_uart_is_controllable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
/*
|
||||
* The UART enable is driven through the W_DISABLE2# line. When it is not
|
||||
* wired up on this connector the enable/disable callbacks are no-ops, so
|
||||
* the host cannot gate the Bluetooth function on its own.
|
||||
*/
|
||||
return !!ctx->w_disable2_gpio;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_pcie_m2_e_uart_unit_data = {
|
||||
.name = "uart-enable",
|
||||
.deps = pwrseq_pcie_m2_unit_deps,
|
||||
|
|
@ -104,6 +116,18 @@ static int pwrseq_pci_m2_e_pcie_disable(struct pwrseq_device *pwrseq)
|
|||
return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 1);
|
||||
}
|
||||
|
||||
static bool pwrseq_pci_m2_e_pcie_is_controllable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
/*
|
||||
* The PCIe/WiFi enable is driven through the W_DISABLE1# line. When it
|
||||
* is not wired up on this connector the enable/disable callbacks are
|
||||
* no-ops, so the host cannot gate the PCIe/WiFi function on its own.
|
||||
*/
|
||||
return !!ctx->w_disable1_gpio;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_pcie_m2_e_pcie_unit_data = {
|
||||
.name = "pcie-enable",
|
||||
.deps = pwrseq_pcie_m2_unit_deps,
|
||||
|
|
@ -132,12 +156,14 @@ static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = {
|
|||
.name = "uart",
|
||||
.unit = &pwrseq_pcie_m2_e_uart_unit_data,
|
||||
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
|
||||
.is_controllable = pwrseq_pci_m2_e_uart_is_controllable,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = {
|
||||
.name = "pcie",
|
||||
.unit = &pwrseq_pcie_m2_e_pcie_unit_data,
|
||||
.post_enable = pwrseq_pcie_m2_e_pwup_delay,
|
||||
.is_controllable = pwrseq_pci_m2_e_pcie_is_controllable,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = {
|
||||
|
|
@ -199,6 +225,8 @@ static const struct pci_device_id pwrseq_m2_pci_ids[] = {
|
|||
.driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x1107, PCI_VENDOR_ID_LENOVO, 0xe0e9),
|
||||
.driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x1107, PCI_VENDOR_ID_FOXCONN, 0xe0ee),
|
||||
.driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
|
||||
{ } /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
@ -378,6 +406,21 @@ static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx,
|
|||
mutex_unlock(&ctx->list_lock);
|
||||
}
|
||||
|
||||
static bool pwrseq_pcie_m2_pci_parent_matches(struct pci_dev *pdev,
|
||||
struct device_node *pci_parent)
|
||||
{
|
||||
struct device *dev = pdev->dev.parent;
|
||||
|
||||
while (dev) {
|
||||
if (dev->of_node == pci_parent)
|
||||
return true;
|
||||
if (!dev_is_pci(dev))
|
||||
break;
|
||||
dev = dev->parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
|
|
@ -392,7 +435,7 @@ static int pwrseq_pcie_m2_notify(struct notifier_block *nb, unsigned long action
|
|||
*/
|
||||
struct device_node *pci_parent __free(device_node) =
|
||||
of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0);
|
||||
if (!pci_parent || (pci_parent != pdev->dev.parent->of_node))
|
||||
if (!pci_parent || !pwrseq_pcie_m2_pci_parent_matches(pdev, pci_parent))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
switch (action) {
|
||||
|
|
@ -466,7 +509,7 @@ static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx)
|
|||
|
||||
/* Create serdev for existing PCI devices if required */
|
||||
for_each_pci_dev(pdev) {
|
||||
if (!pdev->dev.parent || pci_parent != pdev->dev.parent->of_node)
|
||||
if (!pwrseq_pcie_m2_pci_parent_matches(pdev, pci_parent))
|
||||
continue;
|
||||
|
||||
if (!pci_match_id(pwrseq_m2_pci_ids, pdev))
|
||||
|
|
|
|||
|
|
@ -183,6 +183,19 @@ static int pwrseq_qcom_wcn_bt_disable(struct pwrseq_device *pwrseq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool pwrseq_qcom_wcn_bt_is_controllable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
/*
|
||||
* The Bluetooth enable is driven through the BT_EN GPIO. When it is not
|
||||
* wired up (e.g. hardwired to an always-on pull-up), the enable/disable
|
||||
* callbacks are no-ops, so the host cannot gate the Bluetooth function
|
||||
* on its own.
|
||||
*/
|
||||
return !!ctx->bt_gpio;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_qcom_wcn_bt_unit_data = {
|
||||
.name = "bluetooth-enable",
|
||||
.deps = pwrseq_qcom_wcn_unit_deps,
|
||||
|
|
@ -217,6 +230,19 @@ static int pwrseq_qcom_wcn_wlan_disable(struct pwrseq_device *pwrseq)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool pwrseq_qcom_wcn_wlan_is_controllable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
/*
|
||||
* The WLAN enable is driven through the WLAN_EN GPIO. When it is not
|
||||
* wired up (e.g. hardwired to an always-on pull-up), the enable/disable
|
||||
* callbacks are no-ops, so the host cannot gate the WLAN function on
|
||||
* its own.
|
||||
*/
|
||||
return !!ctx->wlan_gpio;
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_qcom_wcn_wlan_unit_data = {
|
||||
.name = "wlan-enable",
|
||||
.deps = pwrseq_qcom_wcn_unit_deps,
|
||||
|
|
@ -257,12 +283,14 @@ 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,
|
||||
.is_controllable = pwrseq_qcom_wcn_bt_is_controllable,
|
||||
};
|
||||
|
||||
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,
|
||||
.is_controllable = pwrseq_qcom_wcn_wlan_is_controllable,
|
||||
};
|
||||
|
||||
/* There are no separate BT and WLAN enablement pins */
|
||||
|
|
@ -280,12 +308,14 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = {
|
|||
.name = "bluetooth",
|
||||
.unit = &pwrseq_qcom_wcn6855_bt_unit_data,
|
||||
.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
|
||||
.is_controllable = pwrseq_qcom_wcn_bt_is_controllable,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = {
|
||||
.name = "wlan",
|
||||
.unit = &pwrseq_qcom_wcn6855_wlan_unit_data,
|
||||
.post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert,
|
||||
.is_controllable = pwrseq_qcom_wcn_wlan_is_controllable,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = {
|
||||
|
|
|
|||
142
drivers/power/sequencing/pwrseq-renesas-pwrrdy.c
Normal file
142
drivers/power/sequencing/pwrseq-renesas-pwrrdy.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Renesas RZ/G3L Power Ready driver
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pwrseq/provider.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define SYS_PWRRDY_N 0xd70
|
||||
#define SYS_PWRRDY_N_USB_MASK BIT(0)
|
||||
#define SYS_PWRRDY_N_DSI_MASK BIT(1)
|
||||
#define SYS_PWRRDY_N_CSI_MASK BIT(2)
|
||||
|
||||
static int pwrseq_rzg3l_set_pwrrdy(struct pwrseq_device *pwrseq, u32 mask,
|
||||
bool val)
|
||||
{
|
||||
struct regmap *regmap = pwrseq_device_get_drvdata(pwrseq);
|
||||
|
||||
return regmap_assign_bits(regmap, SYS_PWRRDY_N, mask, val);
|
||||
}
|
||||
|
||||
static int pwrseq_rzg3l_usb_pwrrdy_enable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
return pwrseq_rzg3l_set_pwrrdy(pwrseq, SYS_PWRRDY_N_USB_MASK, 0);
|
||||
}
|
||||
|
||||
static int pwrseq_rzg3l_usb_pwrrdy_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
return pwrseq_rzg3l_set_pwrrdy(pwrseq, SYS_PWRRDY_N_USB_MASK, 1);
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_rzg3l_usb_pwrrdy_unit = {
|
||||
.name = "usb-pwrrdy-power-sequence",
|
||||
.enable = pwrseq_rzg3l_usb_pwrrdy_enable,
|
||||
.disable = pwrseq_rzg3l_usb_pwrrdy_disable,
|
||||
};
|
||||
|
||||
static int pwrseq_rzg3l_dsi_pwrrdy_enable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
return pwrseq_rzg3l_set_pwrrdy(pwrseq, SYS_PWRRDY_N_DSI_MASK, 0);
|
||||
}
|
||||
|
||||
static int pwrseq_rzg3l_dsi_pwrrdy_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
return pwrseq_rzg3l_set_pwrrdy(pwrseq, SYS_PWRRDY_N_DSI_MASK, 1);
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_rzg3l_dsi_pwrrdy_unit = {
|
||||
.name = "dsi-pwrrdy-sequence",
|
||||
.enable = pwrseq_rzg3l_dsi_pwrrdy_enable,
|
||||
.disable = pwrseq_rzg3l_dsi_pwrrdy_disable,
|
||||
};
|
||||
|
||||
static int pwrseq_rzg3l_csi_pwrrdy_enable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
return pwrseq_rzg3l_set_pwrrdy(pwrseq, SYS_PWRRDY_N_CSI_MASK, 0);
|
||||
}
|
||||
|
||||
static int pwrseq_rzg3l_csi_pwrrdy_disable(struct pwrseq_device *pwrseq)
|
||||
{
|
||||
return pwrseq_rzg3l_set_pwrrdy(pwrseq, SYS_PWRRDY_N_CSI_MASK, 1);
|
||||
}
|
||||
|
||||
static const struct pwrseq_unit_data pwrseq_rzg3l_csi_pwrrdy_unit = {
|
||||
.name = "csi-pwrrdy-power-sequence",
|
||||
.enable = pwrseq_rzg3l_csi_pwrrdy_enable,
|
||||
.disable = pwrseq_rzg3l_csi_pwrrdy_disable,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_rzg3l_usb_pwrrdy_target = {
|
||||
.name = "usb-pwrrdy",
|
||||
.unit = &pwrseq_rzg3l_usb_pwrrdy_unit,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_rzg3l_dsi_pwrrdy_target = {
|
||||
.name = "dsi-pwrrdy",
|
||||
.unit = &pwrseq_rzg3l_dsi_pwrrdy_unit,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data pwrseq_rzg3l_csi_pwrrdy_target = {
|
||||
.name = "csi-pwrrdy",
|
||||
.unit = &pwrseq_rzg3l_csi_pwrrdy_unit,
|
||||
};
|
||||
|
||||
static const struct pwrseq_target_data *pwrseq_rzg3l_pwrrdy_targets[] = {
|
||||
&pwrseq_rzg3l_usb_pwrrdy_target,
|
||||
&pwrseq_rzg3l_dsi_pwrrdy_target,
|
||||
&pwrseq_rzg3l_csi_pwrrdy_target,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const pwrseq_rzg3l_pwrrdy_compats[] = {
|
||||
"renesas,r9a08g046-usbphy-ctrl",
|
||||
"renesas,r9a08g046-mipi-dsi",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int pwrseq_rzg3l_pwrrdy_match(struct pwrseq_device *pwrseq,
|
||||
struct device *dev)
|
||||
{
|
||||
if (of_device_compatible_match(dev->of_node, pwrseq_rzg3l_pwrrdy_compats))
|
||||
return PWRSEQ_MATCH_OK;
|
||||
|
||||
return PWRSEQ_NO_MATCH;
|
||||
}
|
||||
|
||||
static int pwrseq_rzg3l_pwrrdy_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct pwrseq_config config = {
|
||||
.parent = &adev->dev,
|
||||
.owner = THIS_MODULE,
|
||||
.drvdata = adev->dev.platform_data,
|
||||
.match = pwrseq_rzg3l_pwrrdy_match,
|
||||
.targets = pwrseq_rzg3l_pwrrdy_targets,
|
||||
};
|
||||
|
||||
return PTR_ERR_OR_ZERO(devm_pwrseq_device_register(&adev->dev, &config));
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id pwrseq_rzg3l_pwrrdy_id_table[] = {
|
||||
{ .name = "rz_sysc.pwrseq-pwrrdy" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, pwrseq_rzg3l_pwrrdy_id_table);
|
||||
|
||||
static struct auxiliary_driver pwrseq_rzg3l_pwrrdy_driver = {
|
||||
.driver = {
|
||||
.name = "pwrseq-rzg3l-pwrrdy",
|
||||
},
|
||||
.probe = pwrseq_rzg3l_pwrrdy_probe,
|
||||
.id_table = pwrseq_rzg3l_pwrrdy_id_table,
|
||||
};
|
||||
module_auxiliary_driver(pwrseq_rzg3l_pwrrdy_driver);
|
||||
|
||||
MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
|
||||
MODULE_DESCRIPTION("Renesas RZ/G3L Power Ready Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -25,6 +25,8 @@ int pwrseq_disable(struct pwrseq_desc *desc);
|
|||
|
||||
struct device *pwrseq_to_device(struct pwrseq_desc *desc);
|
||||
|
||||
bool pwrseq_is_controllable(struct pwrseq_desc *desc);
|
||||
|
||||
#else /* CONFIG_POWER_SEQUENCING */
|
||||
|
||||
static inline struct pwrseq_desc * __must_check
|
||||
|
|
@ -58,6 +60,11 @@ static inline struct device *pwrseq_to_device(struct pwrseq_desc *desc)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool pwrseq_is_controllable(struct pwrseq_desc *desc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_POWER_SEQUENCING */
|
||||
|
||||
#endif /* __POWER_SEQUENCING_CONSUMER_H__ */
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
#ifndef __POWER_SEQUENCING_PROVIDER_H__
|
||||
#define __POWER_SEQUENCING_PROVIDER_H__
|
||||
|
||||
#include <linux/types.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 *);
|
||||
typedef bool (*pwrseq_is_controllable_func)(struct pwrseq_device *);
|
||||
|
||||
#define PWRSEQ_NO_MATCH 0
|
||||
#define PWRSEQ_MATCH_OK 1
|
||||
|
|
@ -43,11 +46,16 @@ struct pwrseq_unit_data {
|
|||
* 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.
|
||||
* @is_controllable: Optional callback checking whether enabling/disabling this
|
||||
* target actually controls power (for example when the
|
||||
* controlling GPIO is wired up). If not provided, the
|
||||
* target's power is assumed to be always controllable.
|
||||
*/
|
||||
struct pwrseq_target_data {
|
||||
const char *name;
|
||||
const struct pwrseq_unit_data *unit;
|
||||
pwrseq_power_state_func post_enable;
|
||||
pwrseq_is_controllable_func is_controllable;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user