// SPDX-License-Identifier: GPL-2.0-or-later /* * ImgTec IR Hardware Decoder found in PowerDown Controller. * * Copyright 2010-2014 Imagination Technologies Ltd. * * This ties into the input subsystem using the RC-core. Protocol support is * provided in separate modules which provide the parameters and scancode * translation functions to set up the hardware decoder and interpret the * resulting input.
*/
#define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */ #define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */ /* * The decoder generates rapid interrupts without actually having * received any new data after an incomplete IR code is decoded.
*/ #define IMG_IR_QUIRK_CODE_IRQ 0x4
/* functions for preprocessing timings, ensuring max is set */
staticvoid img_ir_timing_preprocess(struct img_ir_timing_range *range, unsignedint unit)
{ if (range->max < range->min)
range->max = range->min; if (unit) { /* multiply by unit and convert to microseconds */
range->min = (range->min*unit)/1000;
range->max = (range->max*unit + 999)/1000; /* round up */
}
}
staticvoid img_ir_timings_preprocess(struct img_ir_timings *timings, unsignedint unit)
{
img_ir_symbol_timing_preprocess(&timings->ldr, unit);
img_ir_symbol_timing_preprocess(&timings->s00, unit);
img_ir_symbol_timing_preprocess(&timings->s01, unit);
img_ir_symbol_timing_preprocess(&timings->s10, unit);
img_ir_symbol_timing_preprocess(&timings->s11, unit); /* default s10 and s11 to s00 and s01 if no leader */ if (unit) /* multiply by unit and convert to microseconds (round up) */
timings->ft.ft_min = (timings->ft.ft_min*unit + 999)/1000;
}
/* functions for filling empty fields with defaults */
staticvoid img_ir_timing_defaults(struct img_ir_timing_range *range, struct img_ir_timing_range *defaults)
{ if (!range->min)
range->min = defaults->min; if (!range->max)
range->max = defaults->max;
}
/* functions for converting timings to register values */
/** * img_ir_control() - Convert control struct to control register value. * @control: Control data * * Returns: The control register value equivalent of @control.
*/ static u32 img_ir_control(conststruct img_ir_control *control)
{
u32 ctrl = control->code_type << IMG_IR_CODETYPE_SHIFT; if (control->decoden)
ctrl |= IMG_IR_DECODEN; if (control->hdrtog)
ctrl |= IMG_IR_HDRTOG; if (control->ldrdec)
ctrl |= IMG_IR_LDRDEC; if (control->decodinpol)
ctrl |= IMG_IR_DECODINPOL; if (control->bitorien)
ctrl |= IMG_IR_BITORIEN; if (control->d1validsel)
ctrl |= IMG_IR_D1VALIDSEL; if (control->bitinv)
ctrl |= IMG_IR_BITINV; if (control->decodend2)
ctrl |= IMG_IR_DECODEND2; if (control->bitoriend2)
ctrl |= IMG_IR_BITORIEND2; if (control->bitinvd2)
ctrl |= IMG_IR_BITINVD2; return ctrl;
}
/** * img_ir_timing_range_convert() - Convert microsecond range. * @out: Output timing range in clock cycles with a shift. * @in: Input timing range in microseconds. * @tolerance: Tolerance as a fraction of 128 (roughly percent). * @clock_hz: IR clock rate in Hz. * @shift: Shift of output units. * * Converts min and max from microseconds to IR clock cycles, applies a * tolerance, and shifts for the register, rounding in the right direction. * Note that in and out can safely be the same object.
*/ staticvoid img_ir_timing_range_convert(struct img_ir_timing_range *out, conststruct img_ir_timing_range *in, unsignedint tolerance, unsignedlong clock_hz, unsignedint shift)
{ unsignedint min = in->min; unsignedint max = in->max; /* add a tolerance */
min = min - (min*tolerance >> 7);
max = max + (max*tolerance >> 7); /* convert from microseconds into clock cycles */
min = min*clock_hz / 1000000;
max = (max*clock_hz + 999999) / 1000000; /* round up */ /* apply shift and copy to output */
out->min = min >> shift;
out->max = (max + ((1 << shift) - 1)) >> shift; /* round up */
}
/** * img_ir_symbol_timing() - Convert symbol timing struct to register value. * @timing: Symbol timing data * @tolerance: Timing tolerance where 0-128 represents 0-100% * @clock_hz: Frequency of source clock in Hz * @pd_shift: Shift to apply to symbol period * @w_shift: Shift to apply to symbol width * * Returns: Symbol timing register value based on arguments.
*/ static u32 img_ir_symbol_timing(conststruct img_ir_symbol_timing *timing, unsignedint tolerance, unsignedlong clock_hz, unsignedint pd_shift, unsignedint w_shift)
{ struct img_ir_timing_range hw_pulse, hw_period; /* we calculate period in hw_period, then convert in place */
hw_period.min = timing->pulse.min + timing->space.min;
hw_period.max = timing->pulse.max + timing->space.max;
img_ir_timing_range_convert(&hw_period, &hw_period,
tolerance, clock_hz, pd_shift);
img_ir_timing_range_convert(&hw_pulse, &timing->pulse,
tolerance, clock_hz, w_shift); /* construct register value */ return (hw_period.max << IMG_IR_PD_MAX_SHIFT) |
(hw_period.min << IMG_IR_PD_MIN_SHIFT) |
(hw_pulse.max << IMG_IR_W_MAX_SHIFT) |
(hw_pulse.min << IMG_IR_W_MIN_SHIFT);
}
/** * img_ir_free_timing() - Convert free time timing struct to register value. * @timing: Free symbol timing data * @clock_hz: Source clock frequency in Hz * * Returns: Free symbol timing register value.
*/ static u32 img_ir_free_timing(conststruct img_ir_free_timing *timing, unsignedlong clock_hz)
{ unsignedint minlen, maxlen, ft_min; /* minlen is only 5 bits, and round minlen to multiple of 2 */ if (timing->minlen < 30)
minlen = timing->minlen & -2; else
minlen = 30; /* maxlen has maximum value of 48, and round maxlen to multiple of 2 */ if (timing->maxlen < 48)
maxlen = (timing->maxlen + 1) & -2; else
maxlen = 48; /* convert and shift ft_min, rounding upwards */
ft_min = (timing->ft_min*clock_hz + 999999) / 1000000;
ft_min = (ft_min + 7) >> 3; /* construct register value */ return (maxlen << IMG_IR_MAXLEN_SHIFT) |
(minlen << IMG_IR_MINLEN_SHIFT) |
(ft_min << IMG_IR_FT_MIN_SHIFT);
}
/** * img_ir_free_timing_dynamic() - Update free time register value. * @st_ft: Static free time register value from img_ir_free_timing. * @filter: Current filter which may additionally restrict min/max len. * * Returns: Updated free time register value based on the current filter.
*/ static u32 img_ir_free_timing_dynamic(u32 st_ft, struct img_ir_filter *filter)
{ unsignedint minlen, maxlen, newminlen, newmaxlen;
/* round minlen, maxlen to multiple of 2 */
newminlen = filter->minlen & -2;
newmaxlen = (filter->maxlen + 1) & -2; /* extract min/max len from register */
minlen = (st_ft & IMG_IR_MINLEN) >> IMG_IR_MINLEN_SHIFT;
maxlen = (st_ft & IMG_IR_MAXLEN) >> IMG_IR_MAXLEN_SHIFT; /* if the new values are more restrictive, update the register value */ if (newminlen > minlen) {
st_ft &= ~IMG_IR_MINLEN;
st_ft |= newminlen << IMG_IR_MINLEN_SHIFT;
} if (newmaxlen < maxlen) {
st_ft &= ~IMG_IR_MAXLEN;
st_ft |= newmaxlen << IMG_IR_MAXLEN_SHIFT;
} return st_ft;
}
/** * img_ir_timings_convert() - Convert timings to register values * @regs: Output timing register values * @timings: Input timing data * @tolerance: Timing tolerance where 0-128 represents 0-100% * @clock_hz: Source clock frequency in Hz
*/ staticvoid img_ir_timings_convert(struct img_ir_timing_regvals *regs, conststruct img_ir_timings *timings, unsignedint tolerance, unsignedint clock_hz)
{ /* leader symbol timings are divided by 16 */
regs->ldr = img_ir_symbol_timing(&timings->ldr, tolerance, clock_hz,
4, 4); /* other symbol timings, pd fields only are divided by 2 */
regs->s00 = img_ir_symbol_timing(&timings->s00, tolerance, clock_hz,
1, 0);
regs->s01 = img_ir_symbol_timing(&timings->s01, tolerance, clock_hz,
1, 0);
regs->s10 = img_ir_symbol_timing(&timings->s10, tolerance, clock_hz,
1, 0);
regs->s11 = img_ir_symbol_timing(&timings->s11, tolerance, clock_hz,
1, 0);
regs->ft = img_ir_free_timing(&timings->ft, clock_hz);
}
/** * img_ir_decoder_preprocess() - Preprocess timings in decoder. * @decoder: Decoder to be preprocessed. * * Ensures that the symbol timing ranges are valid with respect to ordering, and * does some fixed conversion on them.
*/ staticvoid img_ir_decoder_preprocess(struct img_ir_decoder *decoder)
{ /* default tolerance */ if (!decoder->tolerance)
decoder->tolerance = 10; /* percent */ /* and convert tolerance to fraction out of 128 */
decoder->tolerance = decoder->tolerance * 128 / 100;
/* fill in implicit fields */
img_ir_timings_preprocess(&decoder->timings, decoder->unit);
/* do the same for repeat timings if applicable */ if (decoder->repeat) {
img_ir_timings_preprocess(&decoder->rtimings, decoder->unit);
img_ir_timings_defaults(&decoder->rtimings, &decoder->timings);
}
}
/** * img_ir_decoder_convert() - Generate internal timings in decoder. * @decoder: Decoder to be converted to internal timings. * @reg_timings: Timing register values. * @clock_hz: IR clock rate in Hz. * * Fills out the repeat timings and timing register values for a specific clock * rate.
*/ staticvoid img_ir_decoder_convert(conststruct img_ir_decoder *decoder, struct img_ir_reg_timings *reg_timings, unsignedint clock_hz)
{ /* calculate control value */
reg_timings->ctrl = img_ir_control(&decoder->control);
/* fill in implicit fields and calculate register values */
img_ir_timings_convert(®_timings->timings, &decoder->timings,
decoder->tolerance, clock_hz);
/* do the same for repeat timings if applicable */ if (decoder->repeat)
img_ir_timings_convert(®_timings->rtimings,
&decoder->rtimings, decoder->tolerance,
clock_hz);
}
/** * img_ir_write_timings() - Write timings to the hardware now * @priv: IR private data * @regs: Timing register values to write * @type: RC filter type (RC_FILTER_*) * * Write timing register values @regs to the hardware, taking into account the * current filter which may impose restrictions on the length of the expected * data.
*/ staticvoid img_ir_write_timings(struct img_ir_priv *priv, struct img_ir_timing_regvals *regs, enum rc_filter_type type)
{ struct img_ir_priv_hw *hw = &priv->hw;
/* filter may be more restrictive to minlen, maxlen */
u32 ft = regs->ft; if (hw->flags & BIT(type))
ft = img_ir_free_timing_dynamic(regs->ft, &hw->filters[type]); /* write to registers */
img_ir_write(priv, IMG_IR_LEAD_SYMB_TIMING, regs->ldr);
img_ir_write(priv, IMG_IR_S00_SYMB_TIMING, regs->s00);
img_ir_write(priv, IMG_IR_S01_SYMB_TIMING, regs->s01);
img_ir_write(priv, IMG_IR_S10_SYMB_TIMING, regs->s10);
img_ir_write(priv, IMG_IR_S11_SYMB_TIMING, regs->s11);
img_ir_write(priv, IMG_IR_FREE_SYMB_TIMING, ft);
dev_dbg(priv->dev, "timings: ldr=%#x, s=[%#x, %#x, %#x, %#x], ft=%#x\n",
regs->ldr, regs->s00, regs->s01, regs->s10, regs->s11, ft);
}
/** * img_ir_set_decoder() - Set the current decoder. * @priv: IR private data. * @decoder: Decoder to use with immediate effect. * @proto: Protocol bitmap (or 0 to use decoder->type).
*/ staticvoid img_ir_set_decoder(struct img_ir_priv *priv, conststruct img_ir_decoder *decoder,
u64 proto)
{ struct img_ir_priv_hw *hw = &priv->hw; struct rc_dev *rdev = hw->rdev;
u32 ir_status, irq_en;
spin_lock_irq(&priv->lock);
/* * First record that the protocol is being stopped so that the end timer * isn't restarted while we're trying to stop it.
*/
hw->stopping = true;
/* * Release the lock to stop the end timer, since the end timer handler * acquires the lock and we don't want to deadlock waiting for it.
*/
spin_unlock_irq(&priv->lock);
timer_delete_sync(&hw->end_timer);
timer_delete_sync(&hw->suspend_timer);
spin_lock_irq(&priv->lock);
/* set the enabled protocols */ if (!proto)
proto = decoder->type;
hw->enabled_protocols = proto;
/* write the new timings */
img_ir_decoder_convert(decoder, &hw->reg_timings, hw->clk_hz);
img_ir_write_timings(priv, &hw->reg_timings.timings, RC_FILTER_NORMAL);
/* set up and enable */
img_ir_write(priv, IMG_IR_CONTROL, hw->reg_timings.ctrl);
unlock:
spin_unlock_irq(&priv->lock);
}
/** * img_ir_decoder_compatible() - Find whether a decoder will work with a device. * @priv: IR private data. * @dec: Decoder to check. * * Returns: true if @dec is compatible with the device @priv refers to.
*/ staticbool img_ir_decoder_compatible(struct img_ir_priv *priv, conststruct img_ir_decoder *dec)
{ unsignedint ct;
/* don't accept decoders using code types which aren't supported */
ct = dec->control.code_type; if (priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_BROKEN) returnfalse;
returntrue;
}
/** * img_ir_allowed_protos() - Get allowed protocols from global decoder list. * @priv: IR private data. * * Returns: Mask of protocols supported by the device @priv refers to.
*/ static u64 img_ir_allowed_protos(struct img_ir_priv *priv)
{
u64 protos = 0; struct img_ir_decoder **decp;
if (!*ir_type) { /* disable all protocols */
img_ir_set_decoder(priv, NULL, 0); goto success;
} for (decp = img_ir_decoders; *decp; ++decp) { conststruct img_ir_decoder *dec = *decp; if (!img_ir_decoder_compatible(priv, dec)) continue; if (*ir_type & dec->type) {
*ir_type &= dec->type;
img_ir_set_decoder(priv, dec, *ir_type); goto success;
}
} return -EINVAL;
success: /* * Only allow matching wakeup protocols for now, and only if filtering * is supported.
*/
wakeup_protocols = *ir_type; if (!hw->decoder || !hw->decoder->filter)
wakeup_protocols = 0;
rdev->allowed_wakeup_protocols = wakeup_protocols; return 0;
}
/* Set up IR decoders */ staticvoid img_ir_init_decoders(void)
{ struct img_ir_decoder **decp;
spin_lock(&img_ir_decoders_lock); if (!img_ir_decoders_preprocessed) { for (decp = img_ir_decoders; *decp; ++decp)
img_ir_decoder_preprocess(*decp);
img_ir_decoders_preprocessed = true;
}
spin_unlock(&img_ir_decoders_lock);
}
#ifdef CONFIG_PM_SLEEP /** * img_ir_enable_wake() - Switch to wake mode. * @priv: IR private data. * * Returns: non-zero if the IR can wake the system.
*/ staticint img_ir_enable_wake(struct img_ir_priv *priv)
{ struct img_ir_priv_hw *hw = &priv->hw; int ret = 0;
spin_lock_irq(&priv->lock); if (hw->flags & IMG_IR_F_WAKE) { /* interrupt only on a match */
hw->suspend_irqen = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
img_ir_write(priv, IMG_IR_IRQ_ENABLE, IMG_IR_IRQ_DATA_MATCH);
img_ir_write_filter(priv, &hw->filters[RC_FILTER_WAKEUP]);
img_ir_write_timings(priv, &hw->reg_timings.timings,
RC_FILTER_WAKEUP);
hw->mode = IMG_IR_M_WAKE;
ret = 1;
}
spin_unlock_irq(&priv->lock); return ret;
}
/** * img_ir_disable_wake() - Switch out of wake mode. * @priv: IR private data * * Returns: 1 if the hardware should be allowed to wake from a sleep state. * 0 otherwise.
*/ staticint img_ir_disable_wake(struct img_ir_priv *priv)
{ struct img_ir_priv_hw *hw = &priv->hw; int ret = 0;
/* * Timer function to re-enable the current protocol after it had been * cleared when invalid interrupts were generated due to a quirk in the * img-ir decoder.
*/ staticvoid img_ir_suspend_timer(struct timer_list *t)
{ struct img_ir_priv *priv = timer_container_of(priv, t,
hw.suspend_timer);
spin_lock_irq(&priv->lock); /* * Don't overwrite enabled valid/match IRQs if they have already been * changed by e.g. a filter change.
*/ if ((priv->hw.quirk_suspend_irq & IMG_IR_IRQ_EDGE) ==
img_ir_read(priv, IMG_IR_IRQ_ENABLE))
img_ir_write(priv, IMG_IR_IRQ_ENABLE,
priv->hw.quirk_suspend_irq); /* enable */
img_ir_write(priv, IMG_IR_CONTROL, priv->hw.reg_timings.ctrl);
spin_unlock_irq(&priv->lock);
}
/* called with priv->lock held */ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status)
{ struct img_ir_priv_hw *hw = &priv->hw;
u32 ir_status, len, lw, up; unsignedint ct;
/* use the current decoder */ if (!hw->decoder) return;
ct = hw->decoder->control.code_type;
ir_status = img_ir_read(priv, IMG_IR_STATUS); if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) { if (!(priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_IRQ) ||
hw->stopping) return; /* * The below functionality is added as a work around to stop * multiple Interrupts generated when an incomplete IR code is * received by the decoder. * The decoder generates rapid interrupts without actually * having received any new data. After a single interrupt it's * expected to clear up, but instead multiple interrupts are * rapidly generated. only way to get out of this loop is to * reset the control register after a short delay.
*/
img_ir_write(priv, IMG_IR_CONTROL, 0);
hw->quirk_suspend_irq = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
img_ir_write(priv, IMG_IR_IRQ_ENABLE,
hw->quirk_suspend_irq & IMG_IR_IRQ_EDGE);
len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT; /* some versions report wrong length for certain code types */ if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR)
++len;
/* Use the first available decoder (or disable stuff if NULL) */ for (decp = img_ir_decoders; *decp; ++decp) { conststruct img_ir_decoder *dec = *decp; if (img_ir_decoder_compatible(priv, dec)) {
img_ir_set_protocol(priv, dec->type);
img_ir_set_decoder(priv, dec, 0); return;
}
}
img_ir_set_decoder(priv, NULL, 0);
}
/** * img_ir_probe_hw_caps() - Probe capabilities of the hardware. * @priv: IR private data.
*/ staticvoid img_ir_probe_hw_caps(struct img_ir_priv *priv)
{ struct img_ir_priv_hw *hw = &priv->hw; /* * When a version of the block becomes available without these quirks, * they'll have to depend on the core revision.
*/
hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN]
|= IMG_IR_QUIRK_CODE_LEN_INCR;
hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE]
|= IMG_IR_QUIRK_CODE_IRQ;
hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS]
|= IMG_IR_QUIRK_CODE_BROKEN;
}
int img_ir_probe_hw(struct img_ir_priv *priv)
{ struct img_ir_priv_hw *hw = &priv->hw; struct rc_dev *rdev; int error;
/* Ensure hardware decoders have been preprocessed */
img_ir_init_decoders();
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.