drivers/pmdomain/bcm/raspberrypi-power.c

Source file repositories/reference/linux-study-clean/drivers/pmdomain/bcm/raspberrypi-power.c

File Facts

System
Linux kernel
Corpus path
drivers/pmdomain/bcm/raspberrypi-power.c
Extension
.c
Size
7577 bytes
Lines
253
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 rpi_power_domain {
	u32 domain;
	bool enabled;
	bool old_interface;
	struct generic_pm_domain base;
	struct rpi_firmware *fw;
};

struct rpi_power_domains {
	bool has_new_interface;
	struct genpd_onecell_data xlate;
	struct rpi_firmware *fw;
	struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT];
};

/*
 * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and
 * RPI_FIRMWARE_SET_DOMAIN_STATE
 */
struct rpi_power_domain_packet {
	u32 domain;
	u32 state;
};

/*
 * Asks the firmware to enable or disable power on a specific power
 * domain.
 */
static int rpi_firmware_set_power(struct generic_pm_domain *domain, bool on)
{
	struct rpi_power_domain *rpi_domain =
		container_of(domain, struct rpi_power_domain, base);
	bool old_interface = rpi_domain->old_interface;
	struct rpi_power_domain_packet packet;
	int ret;

	packet.domain = rpi_domain->domain;
	packet.state = on;

	ret = rpi_firmware_property(rpi_domain->fw, old_interface ?
				    RPI_FIRMWARE_SET_POWER_STATE :
				    RPI_FIRMWARE_SET_DOMAIN_STATE,
				    &packet, sizeof(packet));
	if (ret)
		dev_err(&domain->dev, "Failed to set %s to %u (%d)\n",
			old_interface ? "power" : "domain", on, ret);
	else
		dev_dbg(&domain->dev, "Set %s to %u\n",
			old_interface ? "power" : "domain", on);

	return ret;
}

static int rpi_domain_off(struct generic_pm_domain *domain)
{
	return rpi_firmware_set_power(domain, false);
}

static int rpi_domain_on(struct generic_pm_domain *domain)
{
	return rpi_firmware_set_power(domain, true);
}

static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
					 int xlate_index, const char *name)
{
	struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];

	dom->fw = rpi_domains->fw;

	dom->base.name = name;
	dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP;
	dom->base.power_on = rpi_domain_on;
	dom->base.power_off = rpi_domain_off;

	/*
	 * Treat all power domains as off at boot.
	 *
	 * The firmware itself may be keeping some domains on, but
	 * from Linux's perspective all we control is the refcounts
	 * that we give to the firmware, and we can't ask the firmware
	 * to turn off something that we haven't ourselves turned on.
	 */
	pm_genpd_init(&dom->base, NULL, true);

	rpi_domains->xlate.domains[xlate_index] = &dom->base;
}

static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains,
				  int xlate_index, const char *name)

Annotation

Implementation Notes