summaryrefslogtreecommitdiffstats
path: root/drivers/pmdomain/arm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-23 13:28:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-23 13:28:57 -0700
commit4352b8aee98005853aa63f57d6377282de17a33f (patch)
tree27614d7a9ef05c32d089004e104364ce42324837 /drivers/pmdomain/arm
downloadlinux-stable-4352b8aee98005853aa63f57d6377282de17a33f.tar.gz
linux-stable-4352b8aee98005853aa63f57d6377282de17a33f.zip
Merge tag 'i3c/for-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linuxgrafted
Pull I3C updates from Alexandre Belloni: "A new driver this cycle, for the AMD AXI I3C controller. There are also new features such as IBI wakeup support, SETAASA device discovery and ACPI support for the the DAA methods, meaning we can now communicate with the SPD devices on DDR5 modules. New driver: - AMD AXI I3C master controller Subsystem: - I3C Common Command Code (CCC) handling improvements, especially around GET CCCs - SETAASA device discovery support - ACPI support for all existing DAA methods like SETDASA, SETNEWDA as well as I2C devices on I3C bus - IBI-based wakeup support Drivers: - dw: SETAASA support - mipi-i3c-hci: advertise IBI wakeup capability, AMD_PT I3C controller support, PIO queue management support for HCI v1.2 - renesas: improve suspend to RAM support, add runtime PM support" * tag 'i3c/for-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: (70 commits) i3c: dw: reduce do_daa time if there's no client i3c: mipi-i3c-hci: Add support for AMD_PT I3C controller i3c: mipi-i3c-hci: Add PIO queue management support for HCI v1.2 i3c: mipi-i3c-hci: Fix missing STAT_IBI_STATUS_THLD in PIO mode i3c: dw: rename "pclk" to "apb" to match dt-binding i3c: dw: make struct dw_i3c_cmd smaller i3c: dw: use COMMAND_PORT_TRANSFER_ARG instead of hardcoding i3c: renesas: Don't register devices when ENTDAA times out i3c: master: dw-i3c-master: fix OD timing for first broadcast i3c: mipi-i3c-hci: Advertise IBI wakeup capability i3c: mipi-i3c-hci: Factor out i3c_hci_sysdev() i3c: mipi-i3c-hci-pci: Propagate I3C wakeup requirements to PCI i3c: master: Reject IBI requests from non-IBI-capable devices i3c: master: Add helper to query bus wakeup requirements i3c: master: Report wakeup events for IBIs i3c: master: Support IBI-based wakeup capability i3c: master: Fix potential UAF in i3c_device_match() i3c: master: Fix potential UAF in i3c_device_uevent() i3c: Make dev->desc locking assumptions explicit i3c: master: Fix use-after-free of master->this ...
Diffstat (limited to 'drivers/pmdomain/arm')
-rw-r--r--drivers/pmdomain/arm/Kconfig37
-rw-r--r--drivers/pmdomain/arm/Makefile5
-rw-r--r--drivers/pmdomain/arm/scmi_perf_domain.c188
-rw-r--r--drivers/pmdomain/arm/scmi_pm_domain.c172
-rw-r--r--drivers/pmdomain/arm/scpi_pm_domain.c157
5 files changed, 559 insertions, 0 deletions
diff --git a/drivers/pmdomain/arm/Kconfig b/drivers/pmdomain/arm/Kconfig
new file mode 100644
index 000000000..ba0b190a6
--- /dev/null
+++ b/drivers/pmdomain/arm/Kconfig
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config ARM_SCMI_PERF_DOMAIN
+ tristate "SCMI performance domain driver"
+ depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+ default ARM_SCMI_PROTOCOL
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCMI performance domains which can be
+ enabled or disabled via the SCP firmware.
+
+ This driver can also be built as a module. If so, the module will be
+ called scmi_perf_domain.
+
+config ARM_SCMI_POWER_DOMAIN
+ tristate "SCMI power domain driver"
+ depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+ default ARM_SCMI_PROTOCOL
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCMI power domains which can be
+ enabled or disabled via the SCP firmware
+
+ This driver can also be built as a module. If so, the module
+ will be called scmi_pm_domain. Note this may be needed early in boot
+ before rootfs may be available.
+
+config ARM_SCPI_POWER_DOMAIN
+ tristate "SCPI power domain driver"
+ depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
+ default ARM_SCPI_PROTOCOL
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCPI power domains which can be
+ enabled or disabled via the SCP firmware
+
+ This driver can also be built as a module. If so, the module will be
+ called scpi_pm_domain.
diff --git a/drivers/pmdomain/arm/Makefile b/drivers/pmdomain/arm/Makefile
new file mode 100644
index 000000000..502fe4d0a
--- /dev/null
+++ b/drivers/pmdomain/arm/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o
+obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
+obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
diff --git a/drivers/pmdomain/arm/scmi_perf_domain.c b/drivers/pmdomain/arm/scmi_perf_domain.c
new file mode 100644
index 000000000..e390f902a
--- /dev/null
+++ b/drivers/pmdomain/arm/scmi_perf_domain.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCMI performance domain support.
+ *
+ * Copyright (C) 2023 Linaro Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
+#include <linux/scmi_protocol.h>
+#include <linux/slab.h>
+
+struct scmi_perf_domain {
+ struct generic_pm_domain genpd;
+ const struct scmi_perf_proto_ops *perf_ops;
+ const struct scmi_protocol_handle *ph;
+ const struct scmi_perf_domain_info *info;
+ u32 domain_id;
+};
+
+#define to_scmi_pd(pd) container_of(pd, struct scmi_perf_domain, genpd)
+
+static int
+scmi_pd_set_perf_state(struct generic_pm_domain *genpd, unsigned int state)
+{
+ struct scmi_perf_domain *pd = to_scmi_pd(genpd);
+ int ret;
+
+ if (!pd->info->set_perf)
+ return 0;
+
+ if (!state)
+ return 0;
+
+ ret = pd->perf_ops->level_set(pd->ph, pd->domain_id, state, false);
+ if (ret)
+ dev_warn(&genpd->dev, "Failed with %d when trying to set %d perf level",
+ ret, state);
+
+ return ret;
+}
+
+static int
+scmi_pd_attach_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ struct scmi_perf_domain *pd = to_scmi_pd(genpd);
+ int ret;
+
+ /*
+ * Allow the device to be attached, but don't add the OPP table unless
+ * the performance level can be changed.
+ */
+ if (!pd->info->set_perf)
+ return 0;
+
+ ret = pd->perf_ops->device_opps_add(pd->ph, dev, pd->domain_id);
+ if (ret)
+ dev_warn(dev, "failed to add OPPs for the device\n");
+
+ return ret;
+}
+
+static void
+scmi_pd_detach_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ struct scmi_perf_domain *pd = to_scmi_pd(genpd);
+
+ if (!pd->info->set_perf)
+ return;
+
+ dev_pm_opp_remove_all_dynamic(dev);
+}
+
+static int scmi_perf_domain_probe(struct scmi_device *sdev)
+{
+ struct device *dev = &sdev->dev;
+ const struct scmi_handle *handle = sdev->handle;
+ const struct scmi_perf_proto_ops *perf_ops;
+ struct scmi_protocol_handle *ph;
+ struct scmi_perf_domain *scmi_pd;
+ struct genpd_onecell_data *scmi_pd_data;
+ struct generic_pm_domain **domains;
+ int num_domains, i, ret = 0;
+
+ if (!handle)
+ return -ENODEV;
+
+ /* The OF node must specify us as a power-domain provider. */
+ if (!of_find_property(dev->of_node, "#power-domain-cells", NULL))
+ return 0;
+
+ perf_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PERF, &ph);
+ if (IS_ERR(perf_ops))
+ return PTR_ERR(perf_ops);
+
+ num_domains = perf_ops->num_domains_get(ph);
+ if (num_domains < 0) {
+ dev_warn(dev, "Failed with %d when getting num perf domains\n",
+ num_domains);
+ return num_domains;
+ } else if (!num_domains) {
+ return 0;
+ }
+
+ scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL);
+ if (!scmi_pd)
+ return -ENOMEM;
+
+ scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL);
+ if (!scmi_pd_data)
+ return -ENOMEM;
+
+ domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ for (i = 0; i < num_domains; i++, scmi_pd++) {
+ scmi_pd->info = perf_ops->info_get(ph, i);
+
+ scmi_pd->domain_id = i;
+ scmi_pd->perf_ops = perf_ops;
+ scmi_pd->ph = ph;
+ scmi_pd->genpd.name = scmi_pd->info->name;
+ scmi_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON |
+ GENPD_FLAG_OPP_TABLE_FW |
+ GENPD_FLAG_DEV_NAME_FW;
+ scmi_pd->genpd.set_performance_state = scmi_pd_set_perf_state;
+ scmi_pd->genpd.attach_dev = scmi_pd_attach_dev;
+ scmi_pd->genpd.detach_dev = scmi_pd_detach_dev;
+
+ ret = pm_genpd_init(&scmi_pd->genpd, NULL, false);
+ if (ret)
+ goto err;
+
+ domains[i] = &scmi_pd->genpd;
+ }
+
+ scmi_pd_data->domains = domains;
+ scmi_pd_data->num_domains = num_domains;
+
+ ret = of_genpd_add_provider_onecell(dev->of_node, scmi_pd_data);
+ if (ret)
+ goto err;
+
+ dev_set_drvdata(dev, scmi_pd_data);
+ dev_info(dev, "Initialized %d performance domains", num_domains);
+ return 0;
+err:
+ for (i--; i >= 0; i--)
+ pm_genpd_remove(domains[i]);
+ return ret;
+}
+
+static void scmi_perf_domain_remove(struct scmi_device *sdev)
+{
+ struct device *dev = &sdev->dev;
+ struct genpd_onecell_data *scmi_pd_data = dev_get_drvdata(dev);
+ int i;
+
+ if (!scmi_pd_data)
+ return;
+
+ of_genpd_del_provider(dev->of_node);
+
+ for (i = 0; i < scmi_pd_data->num_domains; i++)
+ pm_genpd_remove(scmi_pd_data->domains[i]);
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_PERF, "perf" },
+ { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_perf_domain_driver = {
+ .name = "scmi-perf-domain",
+ .probe = scmi_perf_domain_probe,
+ .remove = scmi_perf_domain_remove,
+ .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_perf_domain_driver);
+
+MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org>");
+MODULE_DESCRIPTION("ARM SCMI perf domain driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pmdomain/arm/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c
new file mode 100644
index 000000000..3d73aef21
--- /dev/null
+++ b/drivers/pmdomain/arm/scmi_pm_domain.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCMI Generic power domain support.
+ *
+ * Copyright (C) 2018-2021 ARM Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/scmi_protocol.h>
+
+static const struct scmi_power_proto_ops *power_ops;
+
+struct scmi_pm_domain {
+ struct generic_pm_domain genpd;
+ const struct scmi_protocol_handle *ph;
+ const char *name;
+ u32 domain;
+};
+
+#define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd)
+
+static int scmi_pd_power(struct generic_pm_domain *domain, u32 state)
+{
+ struct scmi_pm_domain *pd = to_scmi_pd(domain);
+
+ return power_ops->state_set(pd->ph, pd->domain, state);
+}
+
+static int scmi_pd_power_on(struct generic_pm_domain *domain)
+{
+ return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_ON);
+}
+
+static int scmi_pd_power_off(struct generic_pm_domain *domain)
+{
+ return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_OFF);
+}
+
+static int scmi_pm_domain_probe(struct scmi_device *sdev)
+{
+ int num_domains, i, ret;
+ struct device *dev = &sdev->dev;
+ struct device_node *np = dev->of_node;
+ struct scmi_pm_domain *scmi_pd;
+ struct genpd_onecell_data *scmi_pd_data;
+ struct generic_pm_domain **domains;
+ const struct scmi_handle *handle = sdev->handle;
+ struct scmi_protocol_handle *ph;
+
+ if (!handle)
+ return -ENODEV;
+
+ power_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_POWER, &ph);
+ if (IS_ERR(power_ops))
+ return PTR_ERR(power_ops);
+
+ num_domains = power_ops->num_domains_get(ph);
+ if (num_domains < 0) {
+ dev_err(dev, "number of domains not found\n");
+ return num_domains;
+ }
+
+ scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL);
+ if (!scmi_pd)
+ return -ENOMEM;
+
+ scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL);
+ if (!scmi_pd_data)
+ return -ENOMEM;
+
+ domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ for (i = 0; i < num_domains; i++, scmi_pd++) {
+ u32 state;
+
+ if (power_ops->state_get(ph, i, &state)) {
+ dev_warn(dev, "failed to get state for domain %d\n", i);
+ continue;
+ }
+
+ /*
+ * Register the explicit power on request to the firmware so
+ * that it is tracked as used by OSPM agent and not
+ * accidentally turned off with OSPM's knowledge
+ */
+ if (state == SCMI_POWER_STATE_GENERIC_ON)
+ power_ops->state_set(ph, i, state);
+
+ scmi_pd->domain = i;
+ scmi_pd->ph = ph;
+ scmi_pd->name = power_ops->name_get(ph, i);
+ scmi_pd->genpd.name = scmi_pd->name;
+ scmi_pd->genpd.power_off = scmi_pd_power_off;
+ scmi_pd->genpd.power_on = scmi_pd_power_on;
+ scmi_pd->genpd.flags = GENPD_FLAG_ACTIVE_WAKEUP;
+
+ pm_genpd_init(&scmi_pd->genpd, NULL,
+ state == SCMI_POWER_STATE_GENERIC_OFF);
+
+ domains[i] = &scmi_pd->genpd;
+ }
+
+ scmi_pd_data->domains = domains;
+ scmi_pd_data->num_domains = num_domains;
+
+ ret = of_genpd_add_provider_onecell(np, scmi_pd_data);
+ if (ret)
+ goto err_rm_genpds;
+
+ dev_set_drvdata(dev, scmi_pd_data);
+
+ /*
+ * Parse (optional) power-domains-child-ids property to establish
+ * parent-child relationships.
+ */
+ ret = of_genpd_add_child_ids(np, scmi_pd_data);
+ if (ret < 0)
+ dev_err(dev, "Failed to add child domain hierarchy: %d\n", ret);
+
+ dev_info(dev, "Initialized %d power domains", num_domains);
+
+ return 0;
+err_rm_genpds:
+ for (i = num_domains - 1; i >= 0; i--)
+ pm_genpd_remove(domains[i]);
+
+ return ret;
+}
+
+static void scmi_pm_domain_remove(struct scmi_device *sdev)
+{
+ int i;
+ struct genpd_onecell_data *scmi_pd_data;
+ struct device *dev = &sdev->dev;
+ struct device_node *np = dev->of_node;
+
+ scmi_pd_data = dev_get_drvdata(dev);
+
+ /* Remove any parent-child relationships established at probe time */
+ of_genpd_remove_child_ids(np, scmi_pd_data);
+
+ of_genpd_del_provider(np);
+
+ for (i = 0; i < scmi_pd_data->num_domains; i++) {
+ if (!scmi_pd_data->domains[i])
+ continue;
+ pm_genpd_remove(scmi_pd_data->domains[i]);
+ }
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_POWER, "genpd" },
+ { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_power_domain_driver = {
+ .name = "scmi-power-domain",
+ .probe = scmi_pm_domain_probe,
+ .remove = scmi_pm_domain_remove,
+ .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_power_domain_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI power domain driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pmdomain/arm/scpi_pm_domain.c b/drivers/pmdomain/arm/scpi_pm_domain.c
new file mode 100644
index 000000000..2231e6dd2
--- /dev/null
+++ b/drivers/pmdomain/arm/scpi_pm_domain.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SCPI Generic power domain support.
+ *
+ * Copyright (C) 2016 ARM Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/scpi_protocol.h>
+
+struct scpi_pm_domain {
+ struct generic_pm_domain genpd;
+ struct scpi_ops *ops;
+ u32 domain;
+};
+
+/*
+ * These device power state values are not well-defined in the specification.
+ * In case, different implementations use different values, we can make these
+ * specific to compatibles rather than getting these values from device tree.
+ */
+enum scpi_power_domain_state {
+ SCPI_PD_STATE_ON = 0,
+ SCPI_PD_STATE_OFF = 3,
+};
+
+#define to_scpi_pd(gpd) container_of(gpd, struct scpi_pm_domain, genpd)
+
+static int scpi_pd_power(struct scpi_pm_domain *pd, bool power_on)
+{
+ int ret;
+ enum scpi_power_domain_state state;
+
+ if (power_on)
+ state = SCPI_PD_STATE_ON;
+ else
+ state = SCPI_PD_STATE_OFF;
+
+ ret = pd->ops->device_set_power_state(pd->domain, state);
+ if (ret)
+ return ret;
+
+ return !(state == pd->ops->device_get_power_state(pd->domain));
+}
+
+static int scpi_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct scpi_pm_domain *pd = to_scpi_pd(domain);
+
+ return scpi_pd_power(pd, true);
+}
+
+static int scpi_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct scpi_pm_domain *pd = to_scpi_pd(domain);
+
+ return scpi_pd_power(pd, false);
+}
+
+static int scpi_pm_domain_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct scpi_pm_domain *scpi_pd;
+ struct genpd_onecell_data *scpi_pd_data;
+ struct generic_pm_domain **domains;
+ struct scpi_ops *scpi_ops;
+ int ret, num_domains, i;
+
+ scpi_ops = get_scpi_ops();
+ if (!scpi_ops)
+ return -EPROBE_DEFER;
+
+ if (!np) {
+ dev_err(dev, "device tree node not found\n");
+ return -ENODEV;
+ }
+
+ if (!scpi_ops->device_set_power_state ||
+ !scpi_ops->device_get_power_state) {
+ dev_err(dev, "power domains not supported in the firmware\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(np, "num-domains", &num_domains);
+ if (ret) {
+ dev_err(dev, "number of domains not found\n");
+ return -EINVAL;
+ }
+
+ scpi_pd = devm_kcalloc(dev, num_domains, sizeof(*scpi_pd), GFP_KERNEL);
+ if (!scpi_pd)
+ return -ENOMEM;
+
+ scpi_pd_data = devm_kzalloc(dev, sizeof(*scpi_pd_data), GFP_KERNEL);
+ if (!scpi_pd_data)
+ return -ENOMEM;
+
+ domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ for (i = 0; i < num_domains; i++, scpi_pd++) {
+ domains[i] = &scpi_pd->genpd;
+
+ scpi_pd->domain = i;
+ scpi_pd->ops = scpi_ops;
+ scpi_pd->genpd.name = devm_kasprintf(dev, GFP_KERNEL,
+ "%pOFn.%d", np, i);
+ if (!scpi_pd->genpd.name) {
+ dev_err(dev, "Failed to allocate genpd name:%pOFn.%d\n",
+ np, i);
+ continue;
+ }
+ scpi_pd->genpd.power_off = scpi_pd_power_off;
+ scpi_pd->genpd.power_on = scpi_pd_power_on;
+
+ /*
+ * Treat all power domains as off at boot.
+ *
+ * The SCP firmware itself may have switched on some domains,
+ * but for reference counting purpose, keep it this way.
+ */
+ pm_genpd_init(&scpi_pd->genpd, NULL, true);
+ }
+
+ scpi_pd_data->domains = domains;
+ scpi_pd_data->num_domains = num_domains;
+
+ of_genpd_add_provider_onecell(np, scpi_pd_data);
+
+ return 0;
+}
+
+static const struct of_device_id scpi_power_domain_ids[] = {
+ { .compatible = "arm,scpi-power-domains", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, scpi_power_domain_ids);
+
+static struct platform_driver scpi_power_domain_driver = {
+ .driver = {
+ .name = "scpi_power_domain",
+ .of_match_table = scpi_power_domain_ids,
+ },
+ .probe = scpi_pm_domain_probe,
+};
+module_platform_driver(scpi_power_domain_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI power domain driver");
+MODULE_LICENSE("GPL v2");