// 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. */ #include <linux/bitops.h> #include <linux/clk.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/timer.h> #include <media/rc-core.h> #include "img-ir.h" /* Decoders lock (only modified to preprocess them) */ static DEFINE_SPINLOCK(img_ir_decoders_lock); static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = …; #define IMG_IR_F_FILTER … #define IMG_IR_F_WAKE … /* code type quirks */ #define IMG_IR_QUIRK_CODE_BROKEN … #define IMG_IR_QUIRK_CODE_LEN_INCR … /* * 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 … /* functions for preprocessing timings, ensuring max is set */ static void img_ir_timing_preprocess(struct img_ir_timing_range *range, unsigned int unit) { … } static void img_ir_symbol_timing_preprocess(struct img_ir_symbol_timing *timing, unsigned int unit) { … } static void img_ir_timings_preprocess(struct img_ir_timings *timings, unsigned int unit) { … } /* functions for filling empty fields with defaults */ static void img_ir_timing_defaults(struct img_ir_timing_range *range, struct img_ir_timing_range *defaults) { … } static void img_ir_symbol_timing_defaults(struct img_ir_symbol_timing *timing, struct img_ir_symbol_timing *defaults) { … } static void img_ir_timings_defaults(struct img_ir_timings *timings, struct img_ir_timings *defaults) { … } /* 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(const struct img_ir_control *control) { … } /** * 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. */ static void img_ir_timing_range_convert(struct img_ir_timing_range *out, const struct img_ir_timing_range *in, unsigned int tolerance, unsigned long clock_hz, unsigned int shift) { … } /** * 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(const struct img_ir_symbol_timing *timing, unsigned int tolerance, unsigned long clock_hz, unsigned int pd_shift, unsigned int w_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(const struct img_ir_free_timing *timing, unsigned long clock_hz) { … } /** * 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) { … } /** * 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 */ static void img_ir_timings_convert(struct img_ir_timing_regvals *regs, const struct img_ir_timings *timings, unsigned int tolerance, unsigned int 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. */ static void img_ir_decoder_preprocess(struct img_ir_decoder *decoder) { … } /** * 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. */ static void img_ir_decoder_convert(const struct img_ir_decoder *decoder, struct img_ir_reg_timings *reg_timings, unsigned int 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. */ static void img_ir_write_timings(struct img_ir_priv *priv, struct img_ir_timing_regvals *regs, enum rc_filter_type type) { … } static void img_ir_write_filter(struct img_ir_priv *priv, struct img_ir_filter *filter) { … } /* caller must have lock */ static void _img_ir_set_filter(struct img_ir_priv *priv, struct img_ir_filter *filter) { … } /* caller must have lock */ static void _img_ir_set_wake_filter(struct img_ir_priv *priv, struct img_ir_filter *filter) { … } /* Callback for setting scancode filter */ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type, struct rc_scancode_filter *sc_filter) { … } static int img_ir_set_normal_filter(struct rc_dev *dev, struct rc_scancode_filter *sc_filter) { … } static int img_ir_set_wakeup_filter(struct rc_dev *dev, struct rc_scancode_filter *sc_filter) { … } /** * 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). */ static void img_ir_set_decoder(struct img_ir_priv *priv, const struct img_ir_decoder *decoder, u64 proto) { … } /** * 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. */ static bool img_ir_decoder_compatible(struct img_ir_priv *priv, const struct img_ir_decoder *dec) { … } /** * 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) { … } /* Callback for changing protocol using sysfs */ static int img_ir_change_protocol(struct rc_dev *dev, u64 *ir_type) { … } /* Changes ir-core protocol device attribute */ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto) { … } /* Set up IR decoders */ static void img_ir_init_decoders(void) { … } #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. */ static int img_ir_enable_wake(struct img_ir_priv *priv) { … } /** * 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. */ static int img_ir_disable_wake(struct img_ir_priv *priv) { … } #endif /* CONFIG_PM_SLEEP */ /* lock must be held */ static void img_ir_begin_repeat(struct img_ir_priv *priv) { … } /* lock must be held */ static void img_ir_end_repeat(struct img_ir_priv *priv) { … } /* lock must be held */ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) { … } /* timer function to end waiting for repeat. */ static void img_ir_end_timer(struct timer_list *t) { … } /* * 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. */ static void img_ir_suspend_timer(struct timer_list *t) { … } #ifdef CONFIG_COMMON_CLK static void img_ir_change_frequency(struct img_ir_priv *priv, struct clk_notifier_data *change) { … } static int img_ir_clk_notify(struct notifier_block *self, unsigned long action, void *data) { … } #endif /* CONFIG_COMMON_CLK */ /* called with priv->lock held */ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status) { … } void img_ir_setup_hw(struct img_ir_priv *priv) { … } /** * img_ir_probe_hw_caps() - Probe capabilities of the hardware. * @priv: IR private data. */ static void img_ir_probe_hw_caps(struct img_ir_priv *priv) { … } int img_ir_probe_hw(struct img_ir_priv *priv) { … } void img_ir_remove_hw(struct img_ir_priv *priv) { … } #ifdef CONFIG_PM_SLEEP int img_ir_suspend(struct device *dev) { … } int img_ir_resume(struct device *dev) { … } #endif /* CONFIG_PM_SLEEP */