drivers/pwm/pwm-xilinx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm-xilinx.c
Extension
.c
Size
9346 bytes
Lines
301
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

if (!xilinx_timer_pwm_enabled(tcsr0, tcsr1)) {
			/* Load TLR into TCR */
			regmap_write(priv->map, TCSR0, tcsr0 | TCSR_LOAD);
			regmap_write(priv->map, TCSR1, tcsr1 | TCSR_LOAD);
			/* Enable timers all at once with ENALL */
			tcsr0 = (TCSR_PWM_SET & ~TCSR_ENT) | (tcsr0 & TCSR_UDT);
			tcsr1 = TCSR_PWM_SET | TCSR_ENALL | (tcsr1 & TCSR_UDT);
			regmap_write(priv->map, TCSR0, tcsr0);
			regmap_write(priv->map, TCSR1, tcsr1);
		}
	} else {
		regmap_write(priv->map, TCSR0, 0);
		regmap_write(priv->map, TCSR1, 0);
	}

	return 0;
}

static int xilinx_pwm_get_state(struct pwm_chip *chip,
				struct pwm_device *unused,
				struct pwm_state *state)
{
	struct xilinx_timer_priv *priv = xilinx_pwm_chip_to_priv(chip);
	u32 tlr0, tlr1, tcsr0, tcsr1;

	regmap_read(priv->map, TLR0, &tlr0);
	regmap_read(priv->map, TLR1, &tlr1);
	regmap_read(priv->map, TCSR0, &tcsr0);
	regmap_read(priv->map, TCSR1, &tcsr1);
	state->period = xilinx_timer_get_period(priv, tlr0, tcsr0);
	state->duty_cycle = xilinx_timer_get_period(priv, tlr1, tcsr1);
	state->enabled = xilinx_timer_pwm_enabled(tcsr0, tcsr1);
	state->polarity = PWM_POLARITY_NORMAL;

	/*
	 * 100% duty cycle results in constant low output. This may be (very)
	 * wrong if rate > 1 GHz, so fix this if you have such hardware :)
	 */
	if (state->period == state->duty_cycle)
		state->duty_cycle = 0;

	return 0;
}

static const struct pwm_ops xilinx_pwm_ops = {
	.apply = xilinx_pwm_apply,
	.get_state = xilinx_pwm_get_state,
};

static const struct regmap_config xilinx_pwm_regmap_config = {
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
	.val_format_endian = REGMAP_ENDIAN_LITTLE,
	.max_register = TCR1,
};

static int xilinx_pwm_probe(struct platform_device *pdev)
{
	int ret;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct xilinx_timer_priv *priv;
	struct pwm_chip *chip;
	u32 pwm_cells, one_timer, width;
	void __iomem *regs;

	/* If there are no PWM cells, this binding is for a timer */
	ret = of_property_read_u32(np, "#pwm-cells", &pwm_cells);
	if (ret == -EINVAL)
		return -ENODEV;
	if (ret)
		return dev_err_probe(dev, ret, "could not read #pwm-cells\n");

	chip = devm_pwmchip_alloc(dev, 1, sizeof(*priv));
	if (IS_ERR(chip))
		return PTR_ERR(chip);
	priv = xilinx_pwm_chip_to_priv(chip);

	regs = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(regs))
		return PTR_ERR(regs);

	priv->map = devm_regmap_init_mmio(dev, regs,
					  &xilinx_pwm_regmap_config);
	if (IS_ERR(priv->map))
		return dev_err_probe(dev, PTR_ERR(priv->map),
				     "Could not create regmap\n");

	ret = of_property_read_u32(np, "xlnx,one-timer-only", &one_timer);

Annotation

Implementation Notes