1 // SPDX-License-Identifier: GPL-2.0
3 * SCMI Generic power domain support.
5 * Copyright (C) 2018 ARM Ltd.
10 #include <linux/module.h>
11 #include <linux/pm_domain.h>
12 #include <linux/scmi_protocol.h>
14 struct scmi_pm_domain
{
15 struct generic_pm_domain genpd
;
16 const struct scmi_handle
*handle
;
21 #define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd)
23 static int scmi_pd_power(struct generic_pm_domain
*domain
, bool power_on
)
27 struct scmi_pm_domain
*pd
= to_scmi_pd(domain
);
28 const struct scmi_power_ops
*ops
= pd
->handle
->power_ops
;
31 state
= SCMI_POWER_STATE_GENERIC_ON
;
33 state
= SCMI_POWER_STATE_GENERIC_OFF
;
35 ret
= ops
->state_set(pd
->handle
, pd
->domain
, state
);
37 ret
= ops
->state_get(pd
->handle
, pd
->domain
, &ret_state
);
38 if (!ret
&& state
!= ret_state
)
44 static int scmi_pd_power_on(struct generic_pm_domain
*domain
)
46 return scmi_pd_power(domain
, true);
49 static int scmi_pd_power_off(struct generic_pm_domain
*domain
)
51 return scmi_pd_power(domain
, false);
54 static int scmi_pm_domain_probe(struct scmi_device
*sdev
)
57 struct device
*dev
= &sdev
->dev
;
58 struct device_node
*np
= dev
->of_node
;
59 struct scmi_pm_domain
*scmi_pd
;
60 struct genpd_onecell_data
*scmi_pd_data
;
61 struct generic_pm_domain
**domains
;
62 const struct scmi_handle
*handle
= sdev
->handle
;
64 if (!handle
|| !handle
->power_ops
)
67 num_domains
= handle
->power_ops
->num_domains_get(handle
);
68 if (num_domains
< 0) {
69 dev_err(dev
, "number of domains not found\n");
73 scmi_pd
= devm_kcalloc(dev
, num_domains
, sizeof(*scmi_pd
), GFP_KERNEL
);
77 scmi_pd_data
= devm_kzalloc(dev
, sizeof(*scmi_pd_data
), GFP_KERNEL
);
81 domains
= devm_kcalloc(dev
, num_domains
, sizeof(*domains
), GFP_KERNEL
);
85 for (i
= 0; i
< num_domains
; i
++, scmi_pd
++) {
88 domains
[i
] = &scmi_pd
->genpd
;
91 scmi_pd
->handle
= handle
;
92 scmi_pd
->name
= handle
->power_ops
->name_get(handle
, i
);
93 scmi_pd
->genpd
.name
= scmi_pd
->name
;
94 scmi_pd
->genpd
.power_off
= scmi_pd_power_off
;
95 scmi_pd
->genpd
.power_on
= scmi_pd_power_on
;
97 if (handle
->power_ops
->state_get(handle
, i
, &state
)) {
98 dev_warn(dev
, "failed to get state for domain %d\n", i
);
102 pm_genpd_init(&scmi_pd
->genpd
, NULL
,
103 state
== SCMI_POWER_STATE_GENERIC_OFF
);
106 scmi_pd_data
->domains
= domains
;
107 scmi_pd_data
->num_domains
= num_domains
;
109 of_genpd_add_provider_onecell(np
, scmi_pd_data
);
114 static const struct scmi_device_id scmi_id_table
[] = {
115 { SCMI_PROTOCOL_POWER
},
118 MODULE_DEVICE_TABLE(scmi
, scmi_id_table
);
120 static struct scmi_driver scmi_power_domain_driver
= {
121 .name
= "scmi-power-domain",
122 .probe
= scmi_pm_domain_probe
,
123 .id_table
= scmi_id_table
,
125 module_scmi_driver(scmi_power_domain_driver
);
127 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
128 MODULE_DESCRIPTION("ARM SCMI power domain driver");
129 MODULE_LICENSE("GPL v2");