diff options
author | Sifan Naeem <sifan.naeem@imgtec.com> | 2014-12-11 15:06:24 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-12-23 12:15:26 -0500 |
commit | 02744c8c9a11a64bce740528077cf5223ab60e31 (patch) | |
tree | c8399b84b64f3807feef2711843c9f7b665cc4b8 | |
parent | 33e01833268d2f006e599b863a21d4e219f96bd7 (diff) |
[media] rc: img-ir: biphase enabled with workaround
Biphase decoding in the current img-ir has got a quirk, where multiple
Interrupts are generated when an incomplete IR code is received by the
decoder.
Patch adds a work around for the quirk and enables biphase decoding.
Signed-off-by: Sifan Naeem <sifan.naeem@imgtec.com>
Acked-by: James Hogan <james.hogan@imgtec.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r-- | drivers/media/rc/img-ir/img-ir-hw.c | 60 | ||||
-rw-r--r-- | drivers/media/rc/img-ir/img-ir-hw.h | 4 |
2 files changed, 61 insertions, 3 deletions
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 9cecda73f980..5c32f05b32ec 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c | |||
@@ -52,6 +52,11 @@ static struct img_ir_decoder *img_ir_decoders[] = { | |||
52 | 52 | ||
53 | #define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */ | 53 | #define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */ |
54 | #define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */ | 54 | #define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */ |
55 | /* | ||
56 | * The decoder generates rapid interrupts without actually having | ||
57 | * received any new data after an incomplete IR code is decoded. | ||
58 | */ | ||
59 | #define IMG_IR_QUIRK_CODE_IRQ 0x4 | ||
55 | 60 | ||
56 | /* functions for preprocessing timings, ensuring max is set */ | 61 | /* functions for preprocessing timings, ensuring max is set */ |
57 | 62 | ||
@@ -542,6 +547,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, | |||
542 | */ | 547 | */ |
543 | spin_unlock_irq(&priv->lock); | 548 | spin_unlock_irq(&priv->lock); |
544 | del_timer_sync(&hw->end_timer); | 549 | del_timer_sync(&hw->end_timer); |
550 | del_timer_sync(&hw->suspend_timer); | ||
545 | spin_lock_irq(&priv->lock); | 551 | spin_lock_irq(&priv->lock); |
546 | 552 | ||
547 | hw->stopping = false; | 553 | hw->stopping = false; |
@@ -861,6 +867,29 @@ static void img_ir_end_timer(unsigned long arg) | |||
861 | spin_unlock_irq(&priv->lock); | 867 | spin_unlock_irq(&priv->lock); |
862 | } | 868 | } |
863 | 869 | ||
870 | /* | ||
871 | * Timer function to re-enable the current protocol after it had been | ||
872 | * cleared when invalid interrupts were generated due to a quirk in the | ||
873 | * img-ir decoder. | ||
874 | */ | ||
875 | static void img_ir_suspend_timer(unsigned long arg) | ||
876 | { | ||
877 | struct img_ir_priv *priv = (struct img_ir_priv *)arg; | ||
878 | |||
879 | spin_lock_irq(&priv->lock); | ||
880 | /* | ||
881 | * Don't overwrite enabled valid/match IRQs if they have already been | ||
882 | * changed by e.g. a filter change. | ||
883 | */ | ||
884 | if ((priv->hw.quirk_suspend_irq & IMG_IR_IRQ_EDGE) == | ||
885 | img_ir_read(priv, IMG_IR_IRQ_ENABLE)) | ||
886 | img_ir_write(priv, IMG_IR_IRQ_ENABLE, | ||
887 | priv->hw.quirk_suspend_irq); | ||
888 | /* enable */ | ||
889 | img_ir_write(priv, IMG_IR_CONTROL, priv->hw.reg_timings.ctrl); | ||
890 | spin_unlock_irq(&priv->lock); | ||
891 | } | ||
892 | |||
864 | #ifdef CONFIG_COMMON_CLK | 893 | #ifdef CONFIG_COMMON_CLK |
865 | static void img_ir_change_frequency(struct img_ir_priv *priv, | 894 | static void img_ir_change_frequency(struct img_ir_priv *priv, |
866 | struct clk_notifier_data *change) | 895 | struct clk_notifier_data *change) |
@@ -926,15 +955,38 @@ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status) | |||
926 | if (!hw->decoder) | 955 | if (!hw->decoder) |
927 | return; | 956 | return; |
928 | 957 | ||
958 | ct = hw->decoder->control.code_type; | ||
959 | |||
929 | ir_status = img_ir_read(priv, IMG_IR_STATUS); | 960 | ir_status = img_ir_read(priv, IMG_IR_STATUS); |
930 | if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) | 961 | if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) { |
962 | if (!(priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_IRQ) || | ||
963 | hw->stopping) | ||
964 | return; | ||
965 | /* | ||
966 | * The below functionality is added as a work around to stop | ||
967 | * multiple Interrupts generated when an incomplete IR code is | ||
968 | * received by the decoder. | ||
969 | * The decoder generates rapid interrupts without actually | ||
970 | * having received any new data. After a single interrupt it's | ||
971 | * expected to clear up, but instead multiple interrupts are | ||
972 | * rapidly generated. only way to get out of this loop is to | ||
973 | * reset the control register after a short delay. | ||
974 | */ | ||
975 | img_ir_write(priv, IMG_IR_CONTROL, 0); | ||
976 | hw->quirk_suspend_irq = img_ir_read(priv, IMG_IR_IRQ_ENABLE); | ||
977 | img_ir_write(priv, IMG_IR_IRQ_ENABLE, | ||
978 | hw->quirk_suspend_irq & IMG_IR_IRQ_EDGE); | ||
979 | |||
980 | /* Timer activated to re-enable the protocol. */ | ||
981 | mod_timer(&hw->suspend_timer, | ||
982 | jiffies + msecs_to_jiffies(5)); | ||
931 | return; | 983 | return; |
984 | } | ||
932 | ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); | 985 | ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); |
933 | img_ir_write(priv, IMG_IR_STATUS, ir_status); | 986 | img_ir_write(priv, IMG_IR_STATUS, ir_status); |
934 | 987 | ||
935 | len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT; | 988 | len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT; |
936 | /* some versions report wrong length for certain code types */ | 989 | /* some versions report wrong length for certain code types */ |
937 | ct = hw->decoder->control.code_type; | ||
938 | if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR) | 990 | if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR) |
939 | ++len; | 991 | ++len; |
940 | 992 | ||
@@ -976,7 +1028,7 @@ static void img_ir_probe_hw_caps(struct img_ir_priv *priv) | |||
976 | hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN] | 1028 | hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN] |
977 | |= IMG_IR_QUIRK_CODE_LEN_INCR; | 1029 | |= IMG_IR_QUIRK_CODE_LEN_INCR; |
978 | hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE] | 1030 | hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE] |
979 | |= IMG_IR_QUIRK_CODE_BROKEN; | 1031 | |= IMG_IR_QUIRK_CODE_IRQ; |
980 | hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS] | 1032 | hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS] |
981 | |= IMG_IR_QUIRK_CODE_BROKEN; | 1033 | |= IMG_IR_QUIRK_CODE_BROKEN; |
982 | } | 1034 | } |
@@ -995,6 +1047,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv) | |||
995 | 1047 | ||
996 | /* Set up the end timer */ | 1048 | /* Set up the end timer */ |
997 | setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv); | 1049 | setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv); |
1050 | setup_timer(&hw->suspend_timer, img_ir_suspend_timer, | ||
1051 | (unsigned long)priv); | ||
998 | 1052 | ||
999 | /* Register a clock notifier */ | 1053 | /* Register a clock notifier */ |
1000 | if (!IS_ERR(priv->clk)) { | 1054 | if (!IS_ERR(priv->clk)) { |
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index beac3a6c4660..b31ffc947e41 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h | |||
@@ -218,6 +218,7 @@ enum img_ir_mode { | |||
218 | * @rdev: Remote control device | 218 | * @rdev: Remote control device |
219 | * @clk_nb: Notifier block for clock notify events. | 219 | * @clk_nb: Notifier block for clock notify events. |
220 | * @end_timer: Timer until repeat timeout. | 220 | * @end_timer: Timer until repeat timeout. |
221 | * @suspend_timer: Timer to re-enable protocol. | ||
221 | * @decoder: Current decoder settings. | 222 | * @decoder: Current decoder settings. |
222 | * @enabled_protocols: Currently enabled protocols. | 223 | * @enabled_protocols: Currently enabled protocols. |
223 | * @clk_hz: Current core clock rate in Hz. | 224 | * @clk_hz: Current core clock rate in Hz. |
@@ -228,12 +229,14 @@ enum img_ir_mode { | |||
228 | * @stopping: Indicates that decoder is being taken down and timers | 229 | * @stopping: Indicates that decoder is being taken down and timers |
229 | * should not be restarted. | 230 | * should not be restarted. |
230 | * @suspend_irqen: Saved IRQ enable mask over suspend. | 231 | * @suspend_irqen: Saved IRQ enable mask over suspend. |
232 | * @quirk_suspend_irq: Saved IRQ enable mask over quirk suspend timer. | ||
231 | */ | 233 | */ |
232 | struct img_ir_priv_hw { | 234 | struct img_ir_priv_hw { |
233 | unsigned int ct_quirks[4]; | 235 | unsigned int ct_quirks[4]; |
234 | struct rc_dev *rdev; | 236 | struct rc_dev *rdev; |
235 | struct notifier_block clk_nb; | 237 | struct notifier_block clk_nb; |
236 | struct timer_list end_timer; | 238 | struct timer_list end_timer; |
239 | struct timer_list suspend_timer; | ||
237 | const struct img_ir_decoder *decoder; | 240 | const struct img_ir_decoder *decoder; |
238 | u64 enabled_protocols; | 241 | u64 enabled_protocols; |
239 | unsigned long clk_hz; | 242 | unsigned long clk_hz; |
@@ -244,6 +247,7 @@ struct img_ir_priv_hw { | |||
244 | enum img_ir_mode mode; | 247 | enum img_ir_mode mode; |
245 | bool stopping; | 248 | bool stopping; |
246 | u32 suspend_irqen; | 249 | u32 suspend_irqen; |
250 | u32 quirk_suspend_irq; | ||
247 | }; | 251 | }; |
248 | 252 | ||
249 | static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw) | 253 | static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw) |