drivers/pmdomain/arm/scpi_pm_domain.c

Source file repositories/reference/linux-study-clean/drivers/pmdomain/arm/scpi_pm_domain.c

File Facts

System
Linux kernel
Corpus path
drivers/pmdomain/arm/scpi_pm_domain.c
Extension
.c
Size
3905 bytes
Lines
158
Domain
Driver Families
Bucket
drivers/pmdomain
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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)

Annotation

Implementation Notes