Lines Matching +full:clock +full:- +full:duration +full:- +full:ns

1 // SPDX-License-Identifier: GPL-2.0-or-later
13 #include <media/drv-intf/cx25840.h>
14 #include <media/rc-core.h>
16 #include "cx25840-core.h"
117 return state ? state->ir_state : NULL; in to_ir_state()
122 * Rx and Tx Clock Divider register computations
124 * Note the largest clock divider value of 0xffff corresponds to:
125 * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
135 d--; in count_to_clock_divider()
161 * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
173 static inline u16 ns_to_lpf_count(unsigned int ns) in ns_to_lpf_count() argument
176 DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); in ns_to_lpf_count()
181 /* Duration of the Low Pass Filter rejection window in ns */ in lpf_count_to_ns()
188 /* Duration of the Low Pass Filter rejection window in us */ in lpf_count_to_us()
198 * Resolution is the duration of 1 tick of the readable portion of in clock_divider_to_resolution()
200 * not readable, hence the << 2. This function returns ns. in clock_divider_to_resolution()
216 rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ in pulse_width_count_to_ns()
224 static u16 ns_to_pulse_width_count(u32 ns, u16 divider)
234 n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */
265 * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
267 * The total pulse clock count is an 18 bit pulse width timer count as the most
268 * significant part and (up to) 16 bit clock divider count as a modulus.
269 * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
272 static u64 ns_to_pulse_clocks(u32 ns) in ns_to_pulse_clocks() argument
276 clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ in ns_to_pulse_clocks()
293 count--; in pulse_clocks_to_clock_divider()
371 if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { in control_rx_s_carrier_window()
373 *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); in control_rx_s_carrier_window()
376 *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); in control_rx_s_carrier_window()
389 * IR Rx & Tx Clock Register helpers
409 static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns, in txclk_tx_s_max_pulse_width() argument
414 if (ns > IR_MAX_DURATION) in txclk_tx_s_max_pulse_width()
415 ns = IR_MAX_DURATION; in txclk_tx_s_max_pulse_width()
416 pulse_clocks = ns_to_pulse_clocks(ns); in txclk_tx_s_max_pulse_width()
422 static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns, in rxclk_rx_s_max_pulse_width() argument
427 if (ns > IR_MAX_DURATION) in rxclk_rx_s_max_pulse_width()
428 ns = IR_MAX_DURATION; in rxclk_rx_s_max_pulse_width()
429 pulse_clocks = ns_to_pulse_clocks(ns); in rxclk_rx_s_max_pulse_width()
444 n--; in cduty_tx_s_duty_cycle()
471 cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, in irqenable_rx()
482 cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask); in irqenable_tx()
503 return -ENODEV; in cx25840_ir_irq_handler()
505 c = ir_state->c; in cx25840_ir_irq_handler()
509 return -ENODEV; in cx25840_ir_irq_handler()
579 k = kfifo_in_locked(&ir_state->rx_kfifo, in cx25840_ir_irq_handler()
581 &ir_state->rx_kfifo_lock); in cx25840_ir_irq_handler()
617 spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); in cx25840_ir_irq_handler()
618 if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2) in cx25840_ir_irq_handler()
620 spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); in cx25840_ir_irq_handler()
639 return -ENODEV; in cx25840_ir_rx_read()
641 invert = (bool) atomic_read(&ir_state->rx_invert); in cx25840_ir_rx_read()
642 divider = (u16) atomic_read(&ir_state->rxclk_divider); in cx25840_ir_rx_read()
651 n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n, in cx25840_ir_rx_read()
652 &ir_state->rx_kfifo_lock); in cx25840_ir_rx_read()
659 if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { in cx25840_ir_rx_read()
664 u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; in cx25840_ir_rx_read()
671 (u16)(p->hw_fifo_data & FIFO_RXTX), divider) / 1000; in cx25840_ir_rx_read()
675 p->ir_core_data = (struct ir_raw_event) in cx25840_ir_rx_read()
676 { .pulse = u, .duration = v, .timeout = w }; in cx25840_ir_rx_read()
678 v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s %s\n", in cx25840_ir_rx_read()
692 return -ENODEV; in cx25840_ir_rx_g_parameters()
694 mutex_lock(&ir_state->rx_params_lock); in cx25840_ir_rx_g_parameters()
695 memcpy(p, &ir_state->rx_params, in cx25840_ir_rx_g_parameters()
697 mutex_unlock(&ir_state->rx_params_lock); in cx25840_ir_rx_g_parameters()
707 return -ENODEV; in cx25840_ir_rx_shutdown()
709 c = ir_state->c; in cx25840_ir_rx_shutdown()
710 mutex_lock(&ir_state->rx_params_lock); in cx25840_ir_rx_shutdown()
720 ir_state->rx_params.shutdown = true; in cx25840_ir_rx_shutdown()
722 mutex_unlock(&ir_state->rx_params_lock); in cx25840_ir_rx_shutdown()
735 return -ENODEV; in cx25840_ir_rx_s_parameters()
737 if (p->shutdown) in cx25840_ir_rx_s_parameters()
740 if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) in cx25840_ir_rx_s_parameters()
741 return -ENOSYS; in cx25840_ir_rx_s_parameters()
743 c = ir_state->c; in cx25840_ir_rx_s_parameters()
744 o = &ir_state->rx_params; in cx25840_ir_rx_s_parameters()
746 mutex_lock(&ir_state->rx_params_lock); in cx25840_ir_rx_s_parameters()
748 o->shutdown = p->shutdown; in cx25840_ir_rx_s_parameters()
750 p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; in cx25840_ir_rx_s_parameters()
751 o->mode = p->mode; in cx25840_ir_rx_s_parameters()
753 p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); in cx25840_ir_rx_s_parameters()
754 o->bytes_per_data_element = p->bytes_per_data_element; in cx25840_ir_rx_s_parameters()
760 control_rx_demodulation_enable(c, p->modulation); in cx25840_ir_rx_s_parameters()
761 o->modulation = p->modulation; in cx25840_ir_rx_s_parameters()
763 if (p->modulation) { in cx25840_ir_rx_s_parameters()
764 p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq, in cx25840_ir_rx_s_parameters()
767 o->carrier_freq = p->carrier_freq; in cx25840_ir_rx_s_parameters()
769 p->duty_cycle = 50; in cx25840_ir_rx_s_parameters()
770 o->duty_cycle = p->duty_cycle; in cx25840_ir_rx_s_parameters()
772 control_rx_s_carrier_window(c, p->carrier_freq, in cx25840_ir_rx_s_parameters()
773 &p->carrier_range_lower, in cx25840_ir_rx_s_parameters()
774 &p->carrier_range_upper); in cx25840_ir_rx_s_parameters()
775 o->carrier_range_lower = p->carrier_range_lower; in cx25840_ir_rx_s_parameters()
776 o->carrier_range_upper = p->carrier_range_upper; in cx25840_ir_rx_s_parameters()
778 p->max_pulse_width = in cx25840_ir_rx_s_parameters()
781 p->max_pulse_width = in cx25840_ir_rx_s_parameters()
782 rxclk_rx_s_max_pulse_width(c, p->max_pulse_width, in cx25840_ir_rx_s_parameters()
785 o->max_pulse_width = p->max_pulse_width; in cx25840_ir_rx_s_parameters()
786 atomic_set(&ir_state->rxclk_divider, rxclk_divider); in cx25840_ir_rx_s_parameters()
788 p->noise_filter_min_width = in cx25840_ir_rx_s_parameters()
789 filter_rx_s_min_width(c, p->noise_filter_min_width); in cx25840_ir_rx_s_parameters()
790 o->noise_filter_min_width = p->noise_filter_min_width; in cx25840_ir_rx_s_parameters()
792 p->resolution = clock_divider_to_resolution(rxclk_divider); in cx25840_ir_rx_s_parameters()
793 o->resolution = p->resolution; in cx25840_ir_rx_s_parameters()
795 /* FIXME - make this dependent on resolution for better performance */ in cx25840_ir_rx_s_parameters()
800 o->invert_level = p->invert_level; in cx25840_ir_rx_s_parameters()
801 atomic_set(&ir_state->rx_invert, p->invert_level); in cx25840_ir_rx_s_parameters()
803 o->interrupt_enable = p->interrupt_enable; in cx25840_ir_rx_s_parameters()
804 o->enable = p->enable; in cx25840_ir_rx_s_parameters()
805 if (p->enable) { in cx25840_ir_rx_s_parameters()
808 spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags); in cx25840_ir_rx_s_parameters()
809 kfifo_reset(&ir_state->rx_kfifo); in cx25840_ir_rx_s_parameters()
810 spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags); in cx25840_ir_rx_s_parameters()
811 if (p->interrupt_enable) in cx25840_ir_rx_s_parameters()
813 control_rx_enable(c, p->enable); in cx25840_ir_rx_s_parameters()
816 mutex_unlock(&ir_state->rx_params_lock); in cx25840_ir_rx_s_parameters()
827 return -ENODEV; in cx25840_ir_tx_write()
831 * FIXME - the code below is an incomplete and untested sketch of what in cx25840_ir_tx_write()
833 * from the tx_kfifo, or converted from ns to the proper units from the in cx25840_ir_tx_write()
837 * tx_kfifo - don't let it happen and let the caller know not all his in cx25840_ir_tx_write()
846 n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo); in cx25840_ir_tx_write()
850 /* FIXME - turn on Tx Fifo service interrupt in cx25840_ir_tx_write()
859 ir_state->txclk_divider); in cx25840_ir_tx_write()
864 kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse, in cx25840_ir_tx_write()
882 return -ENODEV; in cx25840_ir_tx_g_parameters()
884 mutex_lock(&ir_state->tx_params_lock); in cx25840_ir_tx_g_parameters()
885 memcpy(p, &ir_state->tx_params, in cx25840_ir_tx_g_parameters()
887 mutex_unlock(&ir_state->tx_params_lock); in cx25840_ir_tx_g_parameters()
897 return -ENODEV; in cx25840_ir_tx_shutdown()
899 c = ir_state->c; in cx25840_ir_tx_shutdown()
900 mutex_lock(&ir_state->tx_params_lock); in cx25840_ir_tx_shutdown()
908 ir_state->tx_params.shutdown = true; in cx25840_ir_tx_shutdown()
910 mutex_unlock(&ir_state->tx_params_lock); in cx25840_ir_tx_shutdown()
923 return -ENODEV; in cx25840_ir_tx_s_parameters()
925 if (p->shutdown) in cx25840_ir_tx_s_parameters()
928 if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) in cx25840_ir_tx_s_parameters()
929 return -ENOSYS; in cx25840_ir_tx_s_parameters()
931 c = ir_state->c; in cx25840_ir_tx_s_parameters()
932 o = &ir_state->tx_params; in cx25840_ir_tx_s_parameters()
933 mutex_lock(&ir_state->tx_params_lock); in cx25840_ir_tx_s_parameters()
935 o->shutdown = p->shutdown; in cx25840_ir_tx_s_parameters()
937 p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; in cx25840_ir_tx_s_parameters()
938 o->mode = p->mode; in cx25840_ir_tx_s_parameters()
940 p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec); in cx25840_ir_tx_s_parameters()
941 o->bytes_per_data_element = p->bytes_per_data_element; in cx25840_ir_tx_s_parameters()
947 control_tx_modulation_enable(c, p->modulation); in cx25840_ir_tx_s_parameters()
948 o->modulation = p->modulation; in cx25840_ir_tx_s_parameters()
950 if (p->modulation) { in cx25840_ir_tx_s_parameters()
951 p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq, in cx25840_ir_tx_s_parameters()
953 o->carrier_freq = p->carrier_freq; in cx25840_ir_tx_s_parameters()
955 p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle); in cx25840_ir_tx_s_parameters()
956 o->duty_cycle = p->duty_cycle; in cx25840_ir_tx_s_parameters()
958 p->max_pulse_width = in cx25840_ir_tx_s_parameters()
961 p->max_pulse_width = in cx25840_ir_tx_s_parameters()
962 txclk_tx_s_max_pulse_width(c, p->max_pulse_width, in cx25840_ir_tx_s_parameters()
965 o->max_pulse_width = p->max_pulse_width; in cx25840_ir_tx_s_parameters()
966 atomic_set(&ir_state->txclk_divider, txclk_divider); in cx25840_ir_tx_s_parameters()
968 p->resolution = clock_divider_to_resolution(txclk_divider); in cx25840_ir_tx_s_parameters()
969 o->resolution = p->resolution; in cx25840_ir_tx_s_parameters()
971 /* FIXME - make this dependent on resolution for better performance */ in cx25840_ir_tx_s_parameters()
974 control_tx_polarity_invert(c, p->invert_carrier_sense); in cx25840_ir_tx_s_parameters()
975 o->invert_carrier_sense = p->invert_carrier_sense; in cx25840_ir_tx_s_parameters()
983 o->invert_level = p->invert_level; in cx25840_ir_tx_s_parameters()
985 o->interrupt_enable = p->interrupt_enable; in cx25840_ir_tx_s_parameters()
986 o->enable = p->enable; in cx25840_ir_tx_s_parameters()
987 if (p->enable) { in cx25840_ir_tx_s_parameters()
989 if (p->interrupt_enable) in cx25840_ir_tx_s_parameters()
991 control_tx_enable(c, p->enable); in cx25840_ir_tx_s_parameters()
994 mutex_unlock(&ir_state->tx_params_lock); in cx25840_ir_tx_s_parameters()
1005 struct i2c_client *c = state->c; in cx25840_ir_log_status()
1080 v4l2_info(sd, "\tNext carrier edge window: 16 clocks -%1d/+%1d, %u to %u Hz\n", in cx25840_ir_log_status()
1083 clock_divider_to_freq(rxclk, 16 - i)); in cx25840_ir_log_status()
1085 v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n", in cx25840_ir_log_status()
1091 v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, %u ns\n", in cx25840_ir_log_status()
1094 v4l2_info(sd, "\tPulse width timer timed-out: %s\n", in cx25840_ir_log_status()
1096 v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", in cx25840_ir_log_status()
1127 v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n", in cx25840_ir_log_status()
1161 .carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */
1163 /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
1164 /* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
1165 .noise_filter_min_width = 333333, /* ns */
1180 .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
1181 .duty_cycle = 25, /* 25 % - RC-5 carrier */
1196 ir_state = devm_kzalloc(&state->c->dev, sizeof(*ir_state), GFP_KERNEL); in cx25840_ir_probe()
1198 return -ENOMEM; in cx25840_ir_probe()
1200 spin_lock_init(&ir_state->rx_kfifo_lock); in cx25840_ir_probe()
1201 if (kfifo_alloc(&ir_state->rx_kfifo, in cx25840_ir_probe()
1203 return -ENOMEM; in cx25840_ir_probe()
1205 ir_state->c = state->c; in cx25840_ir_probe()
1206 state->ir_state = ir_state; in cx25840_ir_probe()
1210 cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK); in cx25840_ir_probe()
1212 cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0); in cx25840_ir_probe()
1214 mutex_init(&ir_state->rx_params_lock); in cx25840_ir_probe()
1218 mutex_init(&ir_state->tx_params_lock); in cx25840_ir_probe()
1231 return -ENODEV; in cx25840_ir_remove()
1236 kfifo_free(&ir_state->rx_kfifo); in cx25840_ir_remove()
1237 state->ir_state = NULL; in cx25840_ir_remove()