/* * Each capture input can be programmed to detect rising-edge, falling-edge, * either edge or neither egde.
*/ enum sti_cpt_edge {
CPT_EDGE_DISABLED,
CPT_EDGE_RISING,
CPT_EDGE_FALLING,
CPT_EDGE_BOTH,
};
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.
*/ staticint sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns)
{ struct sti_pwm_chip *pc = to_sti_pwmchip(chip); unsignedint ncfg, value, prescale = 0; struct pwm_device *cur = pc->cur; struct device *dev = pc->dev; bool period_same = false; int ret;
ncfg = hweight_long(pc->configured); if (ncfg)
period_same = (period_ns == pwm_get_period(cur));
/* * Allow configuration changes if one of the following conditions * satisfy. * 1. No devices have been configured. * 2. Only one device has been configured and the new request is for * the same device. * 3. Only one device has been configured and the new request is for * a new device and period of the new device is same as the current * configured period. * 4. More than one devices are configured and period of the new * requestis the same as the current period.
*/ if (!ncfg ||
((ncfg == 1) && (pwm->hwpwm == cur->hwpwm)) ||
((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) ||
((ncfg > 1) && period_same)) { /* Enable clock before writing to PWM registers. */
ret = clk_enable(pc->pwm_clk); if (ret) return ret;
ret = clk_enable(pc->cpt_clk); if (ret) return ret;
if (!period_same) {
ret = sti_pwm_get_prescale(pc, period_ns, &prescale); if (ret) goto clk_dis;
value = prescale & PWM_PRESCALE_LOW_MASK;
ret = regmap_field_write(pc->prescale_low, value); if (ret) goto clk_dis;
value = (prescale & PWM_PRESCALE_HIGH_MASK) >> 4;
ret = regmap_field_write(pc->prescale_high, value); if (ret) goto clk_dis;
}
/* * When PWMVal == 0, PWM pulse = 1 local clock cycle. * When PWMVal == max_pwm_count, * PWM pulse = (max_pwm_count + 1) local cycles, * that is continuous pulse: signal never goes low.
*/
value = pc->max_pwm_cnt * duty_ns / period_ns;
ret = regmap_write(pc->regmap, PWM_OUT_VAL(pwm->hwpwm), value); if (ret) goto clk_dis;
switch (ddata->index) { case 0: case 1: /* * Getting here could mean: * - input signal is constant of less than 1 Hz * - there is no input signal at all * * In such case the frequency is rounded down to 0
*/
result->period = 0;
result->duty_cycle = 0;
break;
case 2: /* We have everying we need */
high = ddata->snapshot[1] - ddata->snapshot[0];
low = ddata->snapshot[2] - ddata->snapshot[1];
static irqreturn_t sti_pwm_interrupt(int irq, void *data)
{ struct sti_pwm_chip *pc = data; struct device *dev = pc->dev; struct sti_cpt_ddata *ddata; int devicenum; unsignedint cpt_int_stat; unsignedint reg; int ret = IRQ_NONE;
ret = regmap_field_read(pc->pwm_cpt_int_stat, &cpt_int_stat); if (ret) return ret;
while (cpt_int_stat) {
devicenum = ffs(cpt_int_stat) - 1;
ddata = &pc->ddata[devicenum];
/* * Capture input: * _______ _______ * | | | | * __| |_________________| |________ * ^0 ^1 ^2 * * Capture start by the first available rising edge. When a * capture event occurs, capture value (CPT_VALx) is stored, * index incremented, capture edge changed. * * After the capture, if the index > 1, we have collected the * necessary data so we signal the thread waiting for it and * disable the capture by setting capture edge to none
*/
ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs); if (!ret)
pwm_num_devs = num_devs;
ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs); if (!ret)
cpt_num_devs = num_devs;
if (!pwm_num_devs && !cpt_num_devs) return dev_err_probe(dev, -EINVAL, "No channels configured\n");
chip = devm_pwmchip_alloc(dev, max(pwm_num_devs, cpt_num_devs), sizeof(*pc)); if (IS_ERR(chip)) return PTR_ERR(chip);
pc = to_sti_pwmchip(chip);
pc->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio)) return PTR_ERR(pc->mmio);
pc->regmap = devm_regmap_init_mmio(dev, pc->mmio,
&sti_pwm_regmap_config); if (IS_ERR(pc->regmap)) return dev_err_probe(dev, PTR_ERR(pc->regmap), "Failed to initialize regmap\n");
irq = platform_get_irq(pdev, 0); if (irq < 0) return irq;
ret = devm_request_irq(&pdev->dev, irq, sti_pwm_interrupt, 0,
pdev->name, pc); if (ret < 0)
dev_err_probe(&pdev->dev, ret, "Failed to request IRQ\n");
/* * Setup PWM data with default values: some values could be replaced * with specific ones provided from Device Tree.
*/
pc->max_prescale = 0xff;
pc->max_pwm_cnt = 255;
pc->pwm_num_devs = pwm_num_devs;
pc->cpt_num_devs = cpt_num_devs;
pc->dev = dev;
pc->en_count = 0;
ret = sti_pwm_probe_regmap(pc); if (ret) return dev_err_probe(dev, ret, "Failed to initialize regmap fields\n");
if (pwm_num_devs) {
pc->pwm_clk = devm_clk_get_prepared(dev, "pwm"); if (IS_ERR(pc->pwm_clk)) return dev_err_probe(dev, PTR_ERR(pc->pwm_clk), "failed to get PWM clock\n");
}
if (cpt_num_devs) {
pc->cpt_clk = devm_clk_get_prepared(dev, "capture"); if (IS_ERR(pc->cpt_clk)) return dev_err_probe(dev, PTR_ERR(pc->cpt_clk), "failed to get PWM capture clock\n");
pc->ddata = devm_kcalloc(dev, cpt_num_devs, sizeof(*pc->ddata), GFP_KERNEL); if (!pc->ddata) return -ENOMEM;
for (i = 0; i < cpt_num_devs; i++) { struct sti_cpt_ddata *ddata = &pc->ddata[i];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.