drivers/pwm/pwm-mediatek.c

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

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-mediatek.c
Extension
.c
Size
16512 bytes
Lines
646
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_mediatek_of_data {
	unsigned int num_pwms;
	bool clksel_fixup;
	bool pwm45_fixup;
	u16 pwm_ck_26m_sel_reg;
	unsigned int chanreg_base;
	unsigned int chanreg_width;
};

/**
 * struct pwm_mediatek_chip - struct representing PWM chip
 * @regs: base address of PWM chip
 * @clk_top: the top clock generator
 * @clk_main: the clock used by PWM core
 * @soc: pointer to chip's platform data
 * @clk_pwms: the clock and clkrate used by each PWM channel
 */
struct pwm_mediatek_chip {
	void __iomem *regs;
	struct clk *clk_top;
	struct clk *clk_main;
	const struct pwm_mediatek_of_data *soc;
	struct {
		struct clk *clk;
		unsigned long rate;
	} clk_pwms[];
};

static inline struct pwm_mediatek_chip *
to_pwm_mediatek_chip(struct pwm_chip *chip)
{
	return pwmchip_get_drvdata(chip);
}

static int pwm_mediatek_clk_enable(struct pwm_mediatek_chip *pc,
				   unsigned int hwpwm)
{
	int ret;

	ret = clk_prepare_enable(pc->clk_top);
	if (ret < 0)
		return ret;

	ret = clk_prepare_enable(pc->clk_main);
	if (ret < 0)
		goto disable_clk_top;

	ret = clk_prepare_enable(pc->clk_pwms[hwpwm].clk);
	if (ret < 0)
		goto disable_clk_main;

	if (!pc->clk_pwms[hwpwm].rate) {
		pc->clk_pwms[hwpwm].rate = clk_get_rate(pc->clk_pwms[hwpwm].clk);

		/*
		 * With the clk running with not more than 1 GHz the
		 * calculations in .apply() won't overflow.
		 */
		if (!pc->clk_pwms[hwpwm].rate ||
		    pc->clk_pwms[hwpwm].rate > 1000000000) {
			ret = -EINVAL;
			goto disable_clk_hwpwm;
		}
	}

	return 0;

disable_clk_hwpwm:
	clk_disable_unprepare(pc->clk_pwms[hwpwm].clk);
disable_clk_main:
	clk_disable_unprepare(pc->clk_main);
disable_clk_top:
	clk_disable_unprepare(pc->clk_top);

	return ret;
}

static void pwm_mediatek_clk_disable(struct pwm_mediatek_chip *pc,
				     unsigned int hwpwm)
{
	clk_disable_unprepare(pc->clk_pwms[hwpwm].clk);
	clk_disable_unprepare(pc->clk_main);
	clk_disable_unprepare(pc->clk_top);
}

static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
				       unsigned int num, unsigned int offset,
				       u32 value)
{
	writel(value, chip->regs + chip->soc->chanreg_base +

Annotation

Implementation Notes