drivers/pmdomain/sunxi/sun55i-pck600.c

Source file repositories/reference/linux-study-clean/drivers/pmdomain/sunxi/sun55i-pck600.c

File Facts

System
Linux kernel
Corpus path
drivers/pmdomain/sunxi/sun55i-pck600.c
Extension
.c
Size
7456 bytes
Lines
271
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 sunxi_pck600_pd_desc {
	const char *name;
	unsigned int flags;
};

struct sunxi_pck600_desc {
	const struct sunxi_pck600_pd_desc *pd_descs;
	unsigned int num_domains;
	u32 logic_power_switch0_delay_offset;
	u32 logic_power_switch1_delay_offset;
	u32 off2on_delay_offset;
	u32 device_ctrl0_delay;
	u32 device_ctrl1_delay;
	u32 logic_power_switch0_delay;
	u32 logic_power_switch1_delay;
	u32 off2on_delay;
	bool has_rst_clk;
};

struct sunxi_pck600_pd {
	struct generic_pm_domain genpd;
	struct sunxi_pck600 *pck;
	void __iomem *base;
};

struct sunxi_pck600 {
	struct device *dev;
	struct genpd_onecell_data genpd_data;
	struct sunxi_pck600_pd pds[];
};

#define to_sunxi_pd(gpd) container_of(gpd, struct sunxi_pck600_pd, genpd)

static int sunxi_pck600_pd_set_power(struct sunxi_pck600_pd *pd, bool on)
{
	struct sunxi_pck600 *pck = pd->pck;
	struct generic_pm_domain *genpd = &pd->genpd;
	int ret;
	u32 val, reg;

	val = on ? PPU_POWER_MODE_ON : PPU_POWER_MODE_OFF;

	reg = readl(pd->base + PPU_PWPR);
	FIELD_MODIFY(PPU_PWR_STATUS, &reg, val);
	writel(reg, pd->base + PPU_PWPR);

	/* push write out to hardware */
	reg = readl(pd->base + PPU_PWPR);

	ret = readl_poll_timeout_atomic(pd->base + PPU_PWSR, reg,
					FIELD_GET(PPU_PWR_STATUS, reg) == val,
					0, 10000);
	if (ret)
		dev_err(pck->dev, "failed to turn domain \"%s\" %s: %d\n",
			genpd->name, str_on_off(on), ret);

	return ret;
}

static int sunxi_pck600_power_on(struct generic_pm_domain *domain)
{
	struct sunxi_pck600_pd *pd = to_sunxi_pd(domain);

	return sunxi_pck600_pd_set_power(pd, true);
}

static int sunxi_pck600_power_off(struct generic_pm_domain *domain)
{
	struct sunxi_pck600_pd *pd = to_sunxi_pd(domain);

	return sunxi_pck600_pd_set_power(pd, false);
}

static void sunxi_pck600_pd_setup(struct sunxi_pck600_pd *pd,
				  const struct sunxi_pck600_desc *desc)
{
	writel(desc->device_ctrl0_delay, pd->base + PPU_DCDR0);
	writel(desc->device_ctrl1_delay, pd->base + PPU_DCDR1);
	writel(desc->logic_power_switch0_delay,
	       pd->base + desc->logic_power_switch0_delay_offset);
	writel(desc->logic_power_switch1_delay,
	       pd->base + desc->logic_power_switch1_delay_offset);
	writel(desc->off2on_delay, pd->base + desc->off2on_delay_offset);
}

static int sunxi_pck600_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	const struct sunxi_pck600_desc *desc;
	struct genpd_onecell_data *genpds;

Annotation

Implementation Notes