drivers/pmdomain/starfive/jh71xx-pmu.c

Source file repositories/reference/linux-study-clean/drivers/pmdomain/starfive/jh71xx-pmu.c

File Facts

System
Linux kernel
Corpus path
drivers/pmdomain/starfive/jh71xx-pmu.c
Extension
.c
Size
11889 bytes
Lines
465
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 jh71xx_domain_info {
	const char * const name;
	unsigned int flags;
	u8 bit;
};

struct jh71xx_pmu;
struct jh71xx_pmu_dev;

struct jh71xx_pmu_match_data {
	const struct jh71xx_domain_info *domain_info;
	int num_domains;
	unsigned int pmu_status;
	int (*pmu_parse_irq)(struct platform_device *pdev,
			     struct jh71xx_pmu *pmu);
	int (*pmu_set_state)(struct jh71xx_pmu_dev *pmd,
			     u32 mask, bool on);
};

struct jh71xx_pmu {
	struct device *dev;
	const struct jh71xx_pmu_match_data *match_data;
	void __iomem *base;
	struct generic_pm_domain **genpd;
	struct genpd_onecell_data genpd_data;
	int irq;
	spinlock_t lock;	/* protects pmu reg */
};

struct jh71xx_pmu_dev {
	const struct jh71xx_domain_info *domain_info;
	struct jh71xx_pmu *pmu;
	struct generic_pm_domain genpd;
};

static int jh71xx_pmu_get_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool *is_on)
{
	struct jh71xx_pmu *pmu = pmd->pmu;

	if (!mask)
		return -EINVAL;

	*is_on = readl(pmu->base + pmu->match_data->pmu_status) & mask;

	return 0;
}

static int jh7110_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
{
	struct jh71xx_pmu *pmu = pmd->pmu;
	unsigned long flags;
	u32 val;
	u32 mode;
	u32 encourage_lo;
	u32 encourage_hi;
	int ret;

	spin_lock_irqsave(&pmu->lock, flags);

	/*
	 * The PMU accepts software encourage to switch power mode in the following 2 steps:
	 *
	 * 1.Configure the register SW_TURN_ON_POWER (offset 0x0c) by writing 1 to
	 *   the bit corresponding to the power domain that will be turned on
	 *   and writing 0 to the others.
	 *   Likewise, configure the register SW_TURN_OFF_POWER (offset 0x10) by
	 *   writing 1 to the bit corresponding to the power domain that will be
	 *   turned off and writing 0 to the others.
	 */
	if (on) {
		mode = JH71XX_PMU_SW_TURN_ON_POWER;
		encourage_lo = JH71XX_PMU_SW_ENCOURAGE_EN_LO;
		encourage_hi = JH71XX_PMU_SW_ENCOURAGE_EN_HI;
	} else {
		mode = JH71XX_PMU_SW_TURN_OFF_POWER;
		encourage_lo = JH71XX_PMU_SW_ENCOURAGE_DIS_LO;
		encourage_hi = JH71XX_PMU_SW_ENCOURAGE_DIS_HI;
	}

	writel(mask, pmu->base + mode);

	/*
	 * 2.Write SW encourage command sequence to the Software Encourage Reg (offset 0x44)
	 *   First write SW_MODE_ENCOURAGE_ON to JH71XX_PMU_SW_ENCOURAGE. This will reset
	 *   the state machine which parses the command sequence. This register must be
	 *   written every time software wants to power on/off a domain.
	 *   Then write the lower bits of the command sequence, followed by the upper
	 *   bits. The sequence differs between powering on & off a domain.
	 */
	writel(JH71XX_PMU_SW_ENCOURAGE_ON, pmu->base + JH71XX_PMU_SW_ENCOURAGE);

Annotation

Implementation Notes