drivers/pmdomain/imx/gpc.c

Source file repositories/reference/linux-study-clean/drivers/pmdomain/imx/gpc.c

File Facts

System
Linux kernel
Corpus path
drivers/pmdomain/imx/gpc.c
Extension
.c
Size
13498 bytes
Lines
551
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 imx_pm_domain {
	struct generic_pm_domain base;
	struct regmap *regmap;
	struct regulator *supply;
	struct clk *clk[GPC_CLK_MAX];
	int num_clks;
	unsigned int reg_offs;
	signed char cntr_pdn_bit;
	unsigned int ipg_rate_mhz;
};

static inline struct imx_pm_domain *
to_imx_pm_domain(struct generic_pm_domain *genpd)
{
	return container_of(genpd, struct imx_pm_domain, base);
}

static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd)
{
	struct imx_pm_domain *pd = to_imx_pm_domain(genpd);
	int iso, iso2sw;
	u32 val;

	/* Read ISO and ISO2SW power down delays */
	regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val);
	iso = val & 0x3f;
	iso2sw = (val >> 8) & 0x3f;

	/* Gate off domain when powered down */
	regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
			   0x1, 0x1);

	/* Request GPC to power down domain */
	val = BIT(pd->cntr_pdn_bit);
	regmap_update_bits(pd->regmap, GPC_CNTR, val, val);

	/* Wait ISO + ISO2SW IPG clock cycles */
	udelay(DIV_ROUND_UP(iso + iso2sw, pd->ipg_rate_mhz));

	if (pd->supply)
		regulator_disable(pd->supply);

	return 0;
}

static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd)
{
	struct imx_pm_domain *pd = to_imx_pm_domain(genpd);
	int i, ret;
	u32 val, req;

	if (pd->supply) {
		ret = regulator_enable(pd->supply);
		if (ret) {
			pr_err("%s: failed to enable regulator: %d\n",
			       __func__, ret);
			return ret;
		}
	}

	/* Enable reset clocks for all devices in the domain */
	for (i = 0; i < pd->num_clks; i++)
		clk_prepare_enable(pd->clk[i]);

	/* Gate off domain when powered down */
	regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
			   0x1, 0x1);

	/* Request GPC to power up domain */
	req = BIT(pd->cntr_pdn_bit + 1);
	regmap_update_bits(pd->regmap, GPC_CNTR, req, req);

	/* Wait for the PGC to handle the request */
	ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req),
				       1, 50);
	if (ret)
		pr_err("powerup request on domain %s timed out\n", genpd->name);

	/* Wait for reset to propagate through peripherals */
	usleep_range(5, 10);

	/* Disable reset clocks for all devices in the domain */
	for (i = 0; i < pd->num_clks; i++)
		clk_disable_unprepare(pd->clk[i]);

	return 0;
}

static int imx_pgc_get_clocks(struct device *dev, struct imx_pm_domain *domain)
{

Annotation

Implementation Notes