drivers/pwm/pwm-loongson.c

Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-loongson.c

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-loongson.c
Extension
.c
Size
8635 bytes
Lines
291
Domain
Driver Families
Bucket
drivers/pwm
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 pwm_loongson_ddata {
	struct clk *clk;
	void __iomem *base;
	u64 clk_rate;
};

static inline __pure struct pwm_loongson_ddata *to_pwm_loongson_ddata(struct pwm_chip *chip)
{
	return pwmchip_get_drvdata(chip);
}

static inline u32 pwm_loongson_readl(struct pwm_loongson_ddata *ddata, u32 offset)
{
	return readl(ddata->base + offset);
}

static inline void pwm_loongson_writel(struct pwm_loongson_ddata *ddata,
				       u32 val, u32 offset)
{
	writel(val, ddata->base + offset);
}

static int pwm_loongson_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
				     enum pwm_polarity polarity)
{
	u16 val;
	struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip);

	val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL);

	if (polarity == PWM_POLARITY_INVERSED)
		/* Duty cycle defines LOW period of PWM */
		val |= LOONGSON_PWM_CTRL_REG_INVERT;
	else
		/* Duty cycle defines HIGH period of PWM */
		val &= ~LOONGSON_PWM_CTRL_REG_INVERT;

	pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL);

	return 0;
}

static void pwm_loongson_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	u32 val;
	struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip);

	val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL);
	val &= ~LOONGSON_PWM_CTRL_REG_EN;
	pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL);
}

static int pwm_loongson_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	u32 val;
	struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip);

	val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL);
	val |= LOONGSON_PWM_CTRL_REG_EN;
	pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL);

	return 0;
}

static int pwm_loongson_config(struct pwm_chip *chip, struct pwm_device *pwm,
			       u64 duty_ns, u64 period_ns)
{
	u64 duty, period;
	struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip);

	/* duty = duty_ns * ddata->clk_rate / NSEC_PER_SEC */
	duty = mul_u64_u64_div_u64(duty_ns, ddata->clk_rate, NSEC_PER_SEC);
	if (duty > U32_MAX)
		duty = U32_MAX;

	/* period = period_ns * ddata->clk_rate / NSEC_PER_SEC */
	period = mul_u64_u64_div_u64(period_ns, ddata->clk_rate, NSEC_PER_SEC);
	if (period > U32_MAX)
		period = U32_MAX;

	pwm_loongson_writel(ddata, duty, LOONGSON_PWM_REG_DUTY);
	pwm_loongson_writel(ddata, period, LOONGSON_PWM_REG_PERIOD);

	return 0;
}

static int pwm_loongson_apply(struct pwm_chip *chip, struct pwm_device *pwm,
			      const struct pwm_state *state)
{
	int ret;

Annotation

Implementation Notes