list_for_each_entry(event_node, &counter->events_list, l) { switch (event_node->event) { case COUNTER_EVENT_OVERFLOW_UNDERFLOW: /* first clear possibly latched UIF before enabling */ if (!regmap_test_bits(priv->regmap, TIM_DIER, TIM_DIER_UIE))
regmap_write(priv->regmap, TIM_SR, (u32)~TIM_SR_UIF);
dier |= TIM_DIER_UIE; break; case COUNTER_EVENT_CAPTURE:
ret = stm32_count_capture_configure(counter, event_node->channel, true); if (ret) return ret;
dier |= TIM_DIER_CCxIE(event_node->channel + 1); break; default: /* should never reach this path */ return -EINVAL;
}
}
/* Enable / disable all events at once, from events_list, so write all DIER bits */
regmap_write(priv->regmap, TIM_DIER, dier);
/* check for disabled capture events */ for (i = 0 ; i < priv->nchannels; i++) { if (!(dier & TIM_DIER_CCxIE(i + 1))) {
ret = stm32_count_capture_configure(counter, i, false); if (ret) return ret;
}
}
staticstruct counter_signal stm32_signals[] = { /* * Need to declare all the signals as a static array, and keep the signals order here, * even if they're unused or unexisting on some timer instances. It's an abstraction, * e.g. high level view of the counter features. * * Userspace programs may rely on signal0 to be "Channel 1", signal1 to be "Channel 2", * and so on. When a signal is unexisting, the COUNTER_SYNAPSE_ACTION_NONE can be used, * to indicate that a signal doesn't affect the counter.
*/
{
.id = STM32_CH1_SIG,
.name = "Channel 1"
},
{
.id = STM32_CH2_SIG,
.name = "Channel 2"
},
{
.id = STM32_CLOCK_SIG,
.name = "Clock",
.ext = stm32_count_clock_ext,
.num_ext = ARRAY_SIZE(stm32_count_clock_ext),
},
{
.id = STM32_CH3_SIG,
.name = "Channel 3"
},
{
.id = STM32_CH4_SIG,
.name = "Channel 4"
},
};
static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr)
{ struct counter_device *counter = ptr; struct stm32_timer_cnt *const priv = counter_priv(counter);
u32 clr = GENMASK(31, 0); /* SR flags can be cleared by writing 0 (wr 1 has no effect) */
u32 sr, dier; int i;
regmap_read(priv->regmap, TIM_SR, &sr);
regmap_read(priv->regmap, TIM_DIER, &dier); /* * Some status bits in SR don't match with the enable bits in DIER. Only take care of * the possibly enabled bits in DIER (that matches in between SR and DIER).
*/
dier &= (TIM_DIER_UIE | TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE);
sr &= dier;
if (sr & TIM_SR_UIF) {
spin_lock(&priv->lock);
priv->nb_ovf++;
spin_unlock(&priv->lock);
counter_push_event(counter, COUNTER_EVENT_OVERFLOW_UNDERFLOW, 0);
dev_dbg(counter->parent, "COUNTER_EVENT_OVERFLOW_UNDERFLOW\n"); /* SR flags can be cleared by writing 0, only clear relevant flag */
clr &= ~TIM_SR_UIF;
}
/* Check capture events */ for (i = 0 ; i < priv->nchannels; i++) { if (sr & TIM_SR_CC_IF(i)) {
counter_push_event(counter, COUNTER_EVENT_CAPTURE, i);
clr &= ~TIM_SR_CC_IF(i);
dev_dbg(counter->parent, "COUNTER_EVENT_CAPTURE, %d\n", i);
}
}
/* * Need to retrieve the trigger node index from DT, to be able * to determine if the counter supports encoder mode. It also * enforce backward compatibility, and allow to support other * counter modes in this driver (when the timer doesn't support * encoder).
*/ for (i = 0; i < ARRAY_SIZE(stm32_timer_trigger_compat) && !tnode; i++)
tnode = of_get_compatible_child(pnode, stm32_timer_trigger_compat[i]); if (!tnode) {
dev_err(dev, "Can't find trigger node\n"); return -ENODATA;
}
ret = of_property_read_u32(tnode, "reg", &idx);
of_node_put(tnode); if (ret) {
dev_err(dev, "Can't get index (%d)\n", ret); return ret;
}
/* STM32 Timers can have either 1 global, or 4 dedicated interrupts (optional) */ if (priv->nr_irqs == 1) { /* All events reported through the global interrupt */
ret = devm_request_irq(&pdev->dev, ddata->irq[0], stm32_timer_cnt_isr,
0, dev_name(dev), counter); if (ret) {
dev_err(dev, "Failed to request irq %d (err %d)\n",
ddata->irq[0], ret); return ret;
}
} else { for (i = 0; i < priv->nr_irqs; i++) { /* * Only take care of update IRQ for overflow events, and cc for * capture events.
*/ if (i != STM32_TIMERS_IRQ_UP && i != STM32_TIMERS_IRQ_CC) continue;
ret = devm_request_irq(&pdev->dev, ddata->irq[i], stm32_timer_cnt_isr,
0, dev_name(dev), counter); if (ret) {
dev_err(dev, "Failed to request irq %d (err %d)\n",
ddata->irq[i], ret); return ret;
}
}
}
/* Reset input selector to its default input */
regmap_write(priv->regmap, TIM_TISEL, 0x0);
/* Register Counter device */
ret = devm_counter_add(dev, counter); if (ret < 0)
dev_err_probe(dev, ret, "Failed to add counter\n");
/* Only take care of enabled counter: don't disturb other MFD child */ if (priv->enabled) { /* Backup registers that may get lost in low power mode */
regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr);
regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr);
regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt);
regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1);
ret = pinctrl_pm_select_default_state(dev); if (ret) return ret;
if (priv->enabled) {
ret = clk_enable(priv->clk); if (ret) {
dev_err(dev, "Cannot enable clock %d\n", ret); return ret;
}
/* Restore registers that may have been lost */
regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr);
regmap_write(priv->regmap, TIM_ARR, priv->bak.arr);
regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt);
/* Also re-enables the counter */
regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1);
}
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.