drivers/pwm/pwm-sti.c

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

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-sti.c
Extension
.c
Size
15934 bytes
Lines
645
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 sti_cpt_ddata {
	u32 snapshot[3];
	unsigned int index;
	struct mutex lock;
	wait_queue_head_t wait;
};

struct sti_pwm_chip {
	struct device *dev;
	struct clk *pwm_clk;
	struct clk *cpt_clk;
	struct regmap *regmap;
	unsigned int pwm_num_devs;
	unsigned int cpt_num_devs;
	unsigned int max_pwm_cnt;
	unsigned int max_prescale;
	struct sti_cpt_ddata *ddata;
	struct regmap_field *prescale_low;
	struct regmap_field *prescale_high;
	struct regmap_field *pwm_out_en;
	struct regmap_field *pwm_cpt_en;
	struct regmap_field *pwm_cpt_int_en;
	struct regmap_field *pwm_cpt_int_stat;
	struct pwm_device *cur;
	unsigned long configured;
	unsigned int en_count;
	void __iomem *mmio;
};

static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
	[PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWM_CTRL, 0, 3),
	[PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWM_CTRL, 11, 14),
	[CPTCLK_PRESCALE] = REG_FIELD(STI_PWM_CTRL, 4, 8),
	[PWM_OUT_EN] = REG_FIELD(STI_PWM_CTRL, 9, 9),
	[PWM_CPT_EN] = REG_FIELD(STI_PWM_CTRL, 10, 10),
	[PWM_CPT_INT_EN] = REG_FIELD(STI_INT_EN, 1, 4),
	[PWM_CPT_INT_STAT] = REG_FIELD(STI_INT_STA, 1, 4),
};

static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
{
	return pwmchip_get_drvdata(chip);
}

/*
 * Calculate the prescaler value corresponding to the period.
 */
static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period,
				unsigned int *prescale)
{
	unsigned long clk_rate;
	unsigned long value;
	unsigned int ps;

	clk_rate = clk_get_rate(pc->pwm_clk);
	if (!clk_rate) {
		dev_err(pc->dev, "failed to get clock rate\n");
		return -EINVAL;
	}

	/*
	 * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_cnt + 1)) - 1
	 */
	value = NSEC_PER_SEC / clk_rate;
	value *= pc->max_pwm_cnt + 1;

	if (period % value)
		return -EINVAL;

	ps  = period / value - 1;
	if (ps > pc->max_prescale)
		return -EINVAL;

	*prescale = ps;

	return 0;
}

/*
 * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles. The
 * only way to change the period (apart from changing the PWM input clock) is
 * to change the PWM clock prescaler.
 *
 * The prescaler is of 8 bits, so 256 prescaler values and hence 256 possible
 * period values are supported (for a particular clock rate). The requested
 * period will be applied only if it matches one of these 256 values.
 */
static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
			  int duty_ns, int period_ns)
{

Annotation

Implementation Notes