/drivers/media/video/cx25840/cx25840-ir.c
C | 1280 lines | 926 code | 191 blank | 163 comment | 117 complexity | 216e028ce94470533c6ddab2e32aed8a MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * Driver for the Conexant CX2584x Audio/Video decoder chip and related cores
- *
- * Integrated Consumer Infrared Controller
- *
- * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
- #include <linux/slab.h>
- #include <linux/kfifo.h>
- #include <media/cx25840.h>
- #include <media/rc-core.h>
- #include "cx25840-core.h"
- static unsigned int ir_debug;
- module_param(ir_debug, int, 0644);
- MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
- #define CX25840_IR_REG_BASE 0x200
- #define CX25840_IR_CNTRL_REG 0x200
- #define CNTRL_WIN_3_3 0x00000000
- #define CNTRL_WIN_4_3 0x00000001
- #define CNTRL_WIN_3_4 0x00000002
- #define CNTRL_WIN_4_4 0x00000003
- #define CNTRL_WIN 0x00000003
- #define CNTRL_EDG_NONE 0x00000000
- #define CNTRL_EDG_FALL 0x00000004
- #define CNTRL_EDG_RISE 0x00000008
- #define CNTRL_EDG_BOTH 0x0000000C
- #define CNTRL_EDG 0x0000000C
- #define CNTRL_DMD 0x00000010
- #define CNTRL_MOD 0x00000020
- #define CNTRL_RFE 0x00000040
- #define CNTRL_TFE 0x00000080
- #define CNTRL_RXE 0x00000100
- #define CNTRL_TXE 0x00000200
- #define CNTRL_RIC 0x00000400
- #define CNTRL_TIC 0x00000800
- #define CNTRL_CPL 0x00001000
- #define CNTRL_LBM 0x00002000
- #define CNTRL_R 0x00004000
- #define CX25840_IR_TXCLK_REG 0x204
- #define TXCLK_TCD 0x0000FFFF
- #define CX25840_IR_RXCLK_REG 0x208
- #define RXCLK_RCD 0x0000FFFF
- #define CX25840_IR_CDUTY_REG 0x20C
- #define CDUTY_CDC 0x0000000F
- #define CX25840_IR_STATS_REG 0x210
- #define STATS_RTO 0x00000001
- #define STATS_ROR 0x00000002
- #define STATS_RBY 0x00000004
- #define STATS_TBY 0x00000008
- #define STATS_RSR 0x00000010
- #define STATS_TSR 0x00000020
- #define CX25840_IR_IRQEN_REG 0x214
- #define IRQEN_RTE 0x00000001
- #define IRQEN_ROE 0x00000002
- #define IRQEN_RSE 0x00000010
- #define IRQEN_TSE 0x00000020
- #define IRQEN_MSK 0x00000033
- #define CX25840_IR_FILTR_REG 0x218
- #define FILTR_LPF 0x0000FFFF
- #define CX25840_IR_FIFO_REG 0x23C
- #define FIFO_RXTX 0x0000FFFF
- #define FIFO_RXTX_LVL 0x00010000
- #define FIFO_RXTX_RTO 0x0001FFFF
- #define FIFO_RX_NDV 0x00020000
- #define FIFO_RX_DEPTH 8
- #define FIFO_TX_DEPTH 8
- #define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
- #define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2)
- /*
- * We use this union internally for convenience, but callers to tx_write
- * and rx_read will be expecting records of type struct ir_raw_event.
- * Always ensure the size of this union is dictated by struct ir_raw_event.
- */
- union cx25840_ir_fifo_rec {
- u32 hw_fifo_data;
- struct ir_raw_event ir_core_data;
- };
- #define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
- #define CX25840_IR_TX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
- struct cx25840_ir_state {
- struct i2c_client *c;
- struct v4l2_subdev_ir_parameters rx_params;
- struct mutex rx_params_lock; /* protects Rx parameter settings cache */
- atomic_t rxclk_divider;
- atomic_t rx_invert;
- struct kfifo rx_kfifo;
- spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */
- struct v4l2_subdev_ir_parameters tx_params;
- struct mutex tx_params_lock; /* protects Tx parameter settings cache */
- atomic_t txclk_divider;
- };
- static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd)
- {
- struct cx25840_state *state = to_state(sd);
- return state ? state->ir_state : NULL;
- }
- /*
- * Rx and Tx Clock Divider register computations
- *
- * Note the largest clock divider value of 0xffff corresponds to:
- * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
- * which fits in 21 bits, so we'll use unsigned int for time arguments.
- */
- static inline u16 count_to_clock_divider(unsigned int d)
- {
- if (d > RXCLK_RCD + 1)
- d = RXCLK_RCD;
- else if (d < 2)
- d = 1;
- else
- d--;
- return (u16) d;
- }
- static inline u16 ns_to_clock_divider(unsigned int ns)
- {
- return count_to_clock_divider(
- DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
- }
- static inline unsigned int clock_divider_to_ns(unsigned int divider)
- {
- /* Period of the Rx or Tx clock in ns */
- return DIV_ROUND_CLOSEST((divider + 1) * 1000,
- CX25840_IR_REFCLK_FREQ / 1000000);
- }
- static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
- {
- return count_to_clock_divider(
- DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16));
- }
- static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
- {
- return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16);
- }
- static inline u16 freq_to_clock_divider(unsigned int freq,
- unsigned int rollovers)
- {
- return count_to_clock_divider(
- DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers));
- }
- static inline unsigned int clock_divider_to_freq(unsigned int divider,
- unsigned int rollovers)
- {
- return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ,
- (divider + 1) * rollovers);
- }
- /*
- * Low Pass Filter register calculations
- *
- * Note the largest count value of 0xffff corresponds to:
- * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
- * which fits in 21 bits, so we'll use unsigned int for time arguments.
- */
- static inline u16 count_to_lpf_count(unsigned int d)
- {
- if (d > FILTR_LPF)
- d = FILTR_LPF;
- else if (d < 4)
- d = 0;
- return (u16) d;
- }
- static inline u16 ns_to_lpf_count(unsigned int ns)
- {
- return count_to_lpf_count(
- DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
- }
- static inline unsigned int lpf_count_to_ns(unsigned int count)
- {
- /* Duration of the Low Pass Filter rejection window in ns */
- return DIV_ROUND_CLOSEST(count * 1000,
- CX25840_IR_REFCLK_FREQ / 1000000);
- }
- static inline unsigned int lpf_count_to_us(unsigned int count)
- {
- /* Duration of the Low Pass Filter rejection window in us */
- return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000);
- }
- /*
- * FIFO register pulse width count compuations
- */
- static u32 clock_divider_to_resolution(u16 divider)
- {
- /*
- * Resolution is the duration of 1 tick of the readable portion of
- * of the pulse width counter as read from the FIFO. The two lsb's are
- * not readable, hence the << 2. This function returns ns.
- */
- return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000,
- CX25840_IR_REFCLK_FREQ / 1000000);
- }
- static u64 pulse_width_count_to_ns(u16 count, u16 divider)
- {
- u64 n;
- u32 rem;
- /*
- * The 2 lsb's of the pulse width timer count are not readable, hence
- * the (count << 2) | 0x3
- */
-