diff options
Diffstat (limited to 'drivers/media/cec/core')
-rw-r--r-- | drivers/media/cec/core/cec-pin-error-inj.c | 59 | ||||
-rw-r--r-- | drivers/media/cec/core/cec-pin-priv.h | 8 | ||||
-rw-r--r-- | drivers/media/cec/core/cec-pin.c | 31 |
3 files changed, 96 insertions, 2 deletions
diff --git a/drivers/media/cec/core/cec-pin-error-inj.c b/drivers/media/cec/core/cec-pin-error-inj.c index 6e61a04b8168..d9e613c7ce3f 100644 --- a/drivers/media/cec/core/cec-pin-error-inj.c +++ b/drivers/media/cec/core/cec-pin-error-inj.c @@ -91,16 +91,22 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) if (!strcmp(token, "clear")) { memset(pin->error_inj, 0, sizeof(pin->error_inj)); pin->rx_toggle = pin->tx_toggle = false; + pin->rx_no_low_drive = false; pin->tx_ignore_nack_until_eom = false; pin->tx_custom_pulse = false; pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT; + pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT; + pin->tx_glitch_falling_edge = false; + pin->tx_glitch_rising_edge = false; return true; } if (!strcmp(token, "rx-clear")) { for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK; pin->rx_toggle = false; + pin->rx_no_low_drive = false; return true; } if (!strcmp(token, "tx-clear")) { @@ -111,6 +117,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) pin->tx_custom_pulse = false; pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT; + pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT; + pin->tx_glitch_falling_edge = false; + pin->tx_glitch_rising_edge = false; + return true; + } + if (!strcmp(token, "rx-no-low-drive")) { + pin->rx_no_low_drive = true; return true; } if (!strcmp(token, "tx-ignore-nack-until-eom")) { @@ -122,6 +136,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) cec_pin_start_timer(pin); return true; } + if (!strcmp(token, "tx-glitch-falling-edge")) { + pin->tx_glitch_falling_edge = true; + return true; + } + if (!strcmp(token, "tx-glitch-rising-edge")) { + pin->tx_glitch_rising_edge = true; + return true; + } if (!p) return false; @@ -139,7 +161,23 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) if (kstrtou32(p, 0, &usecs) || usecs > 10000000) return false; - pin->tx_custom_high_usecs = usecs; + pin->tx_glitch_high_usecs = usecs; + return true; + } + if (!strcmp(token, "tx-glitch-low-usecs")) { + u32 usecs; + + if (kstrtou32(p, 0, &usecs) || usecs > 100) + return false; + pin->tx_glitch_low_usecs = usecs; + return true; + } + if (!strcmp(token, "tx-glitch-high-usecs")) { + u32 usecs; + + if (kstrtou32(p, 0, &usecs) || usecs > 100) + return false; + pin->tx_glitch_high_usecs = usecs; return true; } @@ -273,6 +311,9 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n"); seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n"); seq_puts(sf, "#\n"); + seq_puts(sf, "# RX error injection settings:\n"); + seq_puts(sf, "# rx-no-low-drive do not generate low-drive pulses\n"); + seq_puts(sf, "#\n"); seq_puts(sf, "# RX error injection:\n"); seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n"); seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n"); @@ -285,6 +326,10 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n"); seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n"); seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n"); + seq_puts(sf, "# tx-glitch-low-usecs <usecs> define the 'low' time for the glitch pulse\n"); + seq_puts(sf, "# tx-glitch-high-usecs <usecs> define the 'high' time for the glitch pulse\n"); + seq_puts(sf, "# tx-glitch-falling-edge send the glitch pulse after every falling edge\n"); + seq_puts(sf, "# tx-glitch-rising-edge send the glitch pulse after every rising edge\n"); seq_puts(sf, "#\n"); seq_puts(sf, "# TX error injection:\n"); seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n"); @@ -332,8 +377,14 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) } } + if (pin->rx_no_low_drive) + seq_puts(sf, "rx-no-low-drive\n"); if (pin->tx_ignore_nack_until_eom) seq_puts(sf, "tx-ignore-nack-until-eom\n"); + if (pin->tx_glitch_falling_edge) + seq_puts(sf, "tx-glitch-falling-edge\n"); + if (pin->tx_glitch_rising_edge) + seq_puts(sf, "tx-glitch-rising-edge\n"); if (pin->tx_custom_pulse) seq_puts(sf, "tx-custom-pulse\n"); if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT) @@ -342,5 +393,11 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT) seq_printf(sf, "tx-custom-high-usecs %u\n", pin->tx_custom_high_usecs); + if (pin->tx_glitch_low_usecs != CEC_TIM_GLITCH_DEFAULT) + seq_printf(sf, "tx-glitch-low-usecs %u\n", + pin->tx_glitch_low_usecs); + if (pin->tx_glitch_high_usecs != CEC_TIM_GLITCH_DEFAULT) + seq_printf(sf, "tx-glitch-high-usecs %u\n", + pin->tx_glitch_high_usecs); return 0; } diff --git a/drivers/media/cec/core/cec-pin-priv.h b/drivers/media/cec/core/cec-pin-priv.h index 156a9f81be94..e7801be9adb9 100644 --- a/drivers/media/cec/core/cec-pin-priv.h +++ b/drivers/media/cec/core/cec-pin-priv.h @@ -164,6 +164,9 @@ enum cec_pin_state { /* The default for the low/high time of the custom pulse */ #define CEC_TIM_CUSTOM_DEFAULT 1000 +/* The default for the low/high time of the glitch pulse */ +#define CEC_TIM_GLITCH_DEFAULT 1 + #define CEC_NUM_PIN_EVENTS 128 #define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0) #define CEC_PIN_EVENT_FL_DROPPED (1 << 1) @@ -225,12 +228,17 @@ struct cec_pin { u32 timer_max_overrun; u32 timer_sum_overrun; + bool rx_no_low_drive; u32 tx_custom_low_usecs; u32 tx_custom_high_usecs; + u32 tx_glitch_low_usecs; + u32 tx_glitch_high_usecs; bool tx_ignore_nack_until_eom; bool tx_custom_pulse; bool tx_generated_poll; bool tx_post_eom; + bool tx_glitch_falling_edge; + bool tx_glitch_rising_edge; u8 tx_extra_bytes; u32 tx_low_drive_cnt; #ifdef CONFIG_CEC_PIN_ERROR_INJ diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index 59ac12113f3a..4d7155281daa 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -142,15 +142,42 @@ static bool cec_pin_read(struct cec_pin *pin) return v; } +static void cec_pin_insert_glitch(struct cec_pin *pin, bool rising_edge) +{ + /* + * Insert a short glitch after the falling or rising edge to + * simulate reflections on the CEC line. This can be used to + * test deglitch filters, which should be present in CEC devices + * to deal with noise on the line. + */ + if (!pin->tx_glitch_high_usecs || !pin->tx_glitch_low_usecs) + return; + if (rising_edge) { + udelay(pin->tx_glitch_high_usecs); + call_void_pin_op(pin, low); + udelay(pin->tx_glitch_low_usecs); + call_void_pin_op(pin, high); + } else { + udelay(pin->tx_glitch_low_usecs); + call_void_pin_op(pin, high); + udelay(pin->tx_glitch_high_usecs); + call_void_pin_op(pin, low); + } +} + static void cec_pin_low(struct cec_pin *pin) { call_void_pin_op(pin, low); + if (pin->tx_glitch_falling_edge && pin->adap->cec_pin_is_high) + cec_pin_insert_glitch(pin, false); cec_pin_update(pin, false, false); } static bool cec_pin_high(struct cec_pin *pin) { call_void_pin_op(pin, high); + if (pin->tx_glitch_rising_edge && !pin->adap->cec_pin_is_high) + cec_pin_insert_glitch(pin, true); return cec_pin_read(pin); } @@ -770,7 +797,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) * Go to low drive state when the total bit time is * too short. */ - if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) { + if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN && !pin->rx_no_low_drive) { if (!pin->rx_data_bit_too_short_cnt++) { pin->rx_data_bit_too_short_ts = ktime_to_ns(pin->ts); pin->rx_data_bit_too_short_delta = delta; @@ -1350,6 +1377,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, init_waitqueue_head(&pin->kthread_waitq); pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; + pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT; + pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT; adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, |