152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  Driver for the Conexant CX2584x Audio/Video decoder chip and related cores
352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  Integrated Consumer Infrared Controller
552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  Copyright (C) 2010  Andy Walls <awalls@md.metrocast.net>
752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  This program is free software; you can redistribute it and/or
952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  modify it under the terms of the GNU General Public License
1052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  as published by the Free Software Foundation; either version 2
1152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  of the License, or (at your option) any later version.
1252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
1352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  This program is distributed in the hope that it will be useful,
1452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  GNU General Public License for more details.
1752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
1852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  You should have received a copy of the GNU General Public License
1952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  along with this program; if not, write to the Free Software
2052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *  02110-1301, USA.
2252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
2352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
2452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#include <linux/slab.h>
2552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#include <linux/kfifo.h>
267a707b89202f905bd9f9fbde326933c59a81214cPaul Gortmaker#include <linux/module.h>
2752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#include <media/cx25840.h>
286bda96447cef24fbf97a798b1ea664224d5fdc25Mauro Carvalho Chehab#include <media/rc-core.h>
2952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
3052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#include "cx25840-core.h"
3152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
3252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic unsigned int ir_debug;
3352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsmodule_param(ir_debug, int, 0644);
3452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy WallsMODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
3552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
3652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_REG_BASE 	0x200
3752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
3852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_CNTRL_REG	0x200
3952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_WIN_3_3	0x00000000
4052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_WIN_4_3	0x00000001
4152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_WIN_3_4	0x00000002
4252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_WIN_4_4	0x00000003
4352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_WIN	0x00000003
4452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_EDG_NONE	0x00000000
4552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_EDG_FALL	0x00000004
4652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_EDG_RISE	0x00000008
4752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_EDG_BOTH	0x0000000C
4852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_EDG	0x0000000C
4952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_DMD	0x00000010
5052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_MOD	0x00000020
5152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_RFE	0x00000040
5252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_TFE	0x00000080
5352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_RXE	0x00000100
5452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_TXE	0x00000200
5552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_RIC	0x00000400
5652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_TIC	0x00000800
5752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_CPL	0x00001000
5852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_LBM	0x00002000
5952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CNTRL_R		0x00004000
6052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
6152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_TXCLK_REG	0x204
6252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define TXCLK_TCD	0x0000FFFF
6352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
6452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_RXCLK_REG	0x208
6552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define RXCLK_RCD	0x0000FFFF
6652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
6752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_CDUTY_REG	0x20C
6852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CDUTY_CDC	0x0000000F
6952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
7052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_STATS_REG	0x210
7152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define STATS_RTO	0x00000001
7252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define STATS_ROR	0x00000002
7352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define STATS_RBY	0x00000004
7452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define STATS_TBY	0x00000008
7552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define STATS_RSR	0x00000010
7652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define STATS_TSR	0x00000020
7752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
7852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_IRQEN_REG	0x214
7952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define IRQEN_RTE	0x00000001
8052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define IRQEN_ROE	0x00000002
8152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define IRQEN_RSE	0x00000010
8252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define IRQEN_TSE	0x00000020
8352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define IRQEN_MSK	0x00000033
8452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
8552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_FILTR_REG	0x218
8652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FILTR_LPF	0x0000FFFF
8752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
8852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_FIFO_REG	0x23C
8952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FIFO_RXTX	0x0000FFFF
9052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FIFO_RXTX_LVL	0x00010000
9152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FIFO_RXTX_RTO	0x0001FFFF
9252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FIFO_RX_NDV	0x00020000
9352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FIFO_RX_DEPTH	8
9452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define FIFO_TX_DEPTH	8
9552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
9652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_VIDCLK_FREQ	108000000 /* 108 MHz, BT.656 */
9752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#define CX25840_IR_REFCLK_FREQ	(CX25840_VIDCLK_FREQ / 2)
9852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
99c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls/*
100c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls * We use this union internally for convenience, but callers to tx_write
101c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls * and rx_read will be expecting records of type struct ir_raw_event.
102c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls * Always ensure the size of this union is dictated by struct ir_raw_event.
103c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls */
104c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Wallsunion cx25840_ir_fifo_rec {
105c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	u32 hw_fifo_data;
106c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	struct ir_raw_event ir_core_data;
107c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls};
108c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls
109c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls#define CX25840_IR_RX_KFIFO_SIZE    (256 * sizeof(union cx25840_ir_fifo_rec))
110c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls#define CX25840_IR_TX_KFIFO_SIZE    (256 * sizeof(union cx25840_ir_fifo_rec))
11152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
11252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstruct cx25840_ir_state {
11352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c;
11452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
11552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct v4l2_subdev_ir_parameters rx_params;
11652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct mutex rx_params_lock; /* protects Rx parameter settings cache */
11752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	atomic_t rxclk_divider;
11852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	atomic_t rx_invert;
11952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
12052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct kfifo rx_kfifo;
12152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */
12252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
12352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct v4l2_subdev_ir_parameters tx_params;
12452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct mutex tx_params_lock; /* protects Tx parameter settings cache */
12552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	atomic_t txclk_divider;
12652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls};
12752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
12852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd)
12952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
13052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
13152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return state ? state->ir_state : NULL;
13252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
13352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
13452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
13552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
13652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * Rx and Tx Clock Divider register computations
13752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
13852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * Note the largest clock divider value of 0xffff corresponds to:
13952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * 	(0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
14052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * which fits in 21 bits, so we'll use unsigned int for time arguments.
14152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
14252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline u16 count_to_clock_divider(unsigned int d)
14352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
14452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (d > RXCLK_RCD + 1)
14552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		d = RXCLK_RCD;
14652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else if (d < 2)
14752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		d = 1;
14852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else
14952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		d--;
15052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (u16) d;
15152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
15252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
15352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline u16 ns_to_clock_divider(unsigned int ns)
15452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
15552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return count_to_clock_divider(
15652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
15752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
15852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
15952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline unsigned int clock_divider_to_ns(unsigned int divider)
16052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
16152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Period of the Rx or Tx clock in ns */
16252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST((divider + 1) * 1000,
16352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				 CX25840_IR_REFCLK_FREQ / 1000000);
16452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
16552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
16652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline u16 carrier_freq_to_clock_divider(unsigned int freq)
16752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
16852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return count_to_clock_divider(
16952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16));
17052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
17152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
17252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
17352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
17452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16);
17552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
17652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
17752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline u16 freq_to_clock_divider(unsigned int freq,
17852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					unsigned int rollovers)
17952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
18052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return count_to_clock_divider(
18152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		   DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers));
18252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
18352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
18452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline unsigned int clock_divider_to_freq(unsigned int divider,
18552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						 unsigned int rollovers)
18652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
18752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ,
18852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				 (divider + 1) * rollovers);
18952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
19052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
19152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
19252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * Low Pass Filter register calculations
19352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
19452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * Note the largest count value of 0xffff corresponds to:
19552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * 	0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
19652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * which fits in 21 bits, so we'll use unsigned int for time arguments.
19752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
19852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline u16 count_to_lpf_count(unsigned int d)
19952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
20052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (d > FILTR_LPF)
20152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		d = FILTR_LPF;
20252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else if (d < 4)
20352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		d = 0;
20452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (u16) d;
20552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
20652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
20752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline u16 ns_to_lpf_count(unsigned int ns)
20852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
20952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return count_to_lpf_count(
21052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
21152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
21252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
21352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline unsigned int lpf_count_to_ns(unsigned int count)
21452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
21552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Duration of the Low Pass Filter rejection window in ns */
21652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST(count * 1000,
21752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				 CX25840_IR_REFCLK_FREQ / 1000000);
21852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
21952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
22052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline unsigned int lpf_count_to_us(unsigned int count)
22152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
22252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Duration of the Low Pass Filter rejection window in us */
22352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000);
22452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
22552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
22652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
22752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * FIFO register pulse width count compuations
22852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
22952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u32 clock_divider_to_resolution(u16 divider)
23052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
23152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
23252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * Resolution is the duration of 1 tick of the readable portion of
23352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * of the pulse width counter as read from the FIFO.  The two lsb's are
23452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * not readable, hence the << 2.  This function returns ns.
23552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
23652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST((1 << 2)  * ((u32) divider + 1) * 1000,
23752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				 CX25840_IR_REFCLK_FREQ / 1000000);
23852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
23952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
24052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u64 pulse_width_count_to_ns(u16 count, u16 divider)
24152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
24252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u64 n;
24352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 rem;
24452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
24552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
24652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * The 2 lsb's of the pulse width timer count are not readable, hence
24752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * the (count << 2) | 0x3
24852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
24952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
25052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000);     /* / MHz => ns */
25152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
25252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n++;
25352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return n;
25452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
25552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
25652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#if 0
25752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/* Keep as we will need this for Transmit functionality */
25852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u16 ns_to_pulse_width_count(u32 ns, u16 divider)
25952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
26052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u64 n;
26152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 d;
26252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 rem;
26352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
26452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
265b595076a180a56d1bb170e6eceda6eb9d76f4cd3Uwe Kleine-König	 * The 2 lsb's of the pulse width timer count are not accessible, hence
26652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * the (1 << 2)
26752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
26852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */
26952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */
27052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rem = do_div(n, d);
27152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (rem >= d / 2)
27252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n++;
27352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
27452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (n > FIFO_RXTX)
27552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n = FIFO_RXTX;
27652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else if (n == 0)
27752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n = 1;
27852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (u16) n;
27952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
28052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
28152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#endif
28252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic unsigned int pulse_width_count_to_us(u16 count, u16 divider)
28352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
28452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u64 n;
28552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 rem;
28652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
28752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
28852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * The 2 lsb's of the pulse width timer count are not readable, hence
28952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * the (count << 2) | 0x3
29052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
29152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = (((u64) count << 2) | 0x3) * (divider + 1);    /* cycles      */
29252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
29352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
29452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n++;
29552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (unsigned int) n;
29652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
29752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
29852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
29952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
30052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls *
30152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * The total pulse clock count is an 18 bit pulse width timer count as the most
30252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * significant part and (up to) 16 bit clock divider count as a modulus.
30352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
30452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * width timer count's least significant bit.
30552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
30652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u64 ns_to_pulse_clocks(u32 ns)
30752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
30852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u64 clocks;
30952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 rem;
31052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles  */
31152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rem = do_div(clocks, 1000);                         /* /1000 = cycles */
31252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (rem >= 1000 / 2)
31352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		clocks++;
31452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return clocks;
31552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
31652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
31752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u16 pulse_clocks_to_clock_divider(u64 count)
31852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
31952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 rem;
32052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
32152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
32252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
32352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* net result needs to be rounded down and decremented by 1 */
32452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (count > RXCLK_RCD + 1)
32552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		count = RXCLK_RCD;
32652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else if (count < 2)
32752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		count = 1;
32852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else
32952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		count--;
33052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (u16) count;
33152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
33252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
33352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
33452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * IR Control Register helpers
33552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
33652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsenum tx_fifo_watermark {
33752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	TX_FIFO_HALF_EMPTY = 0,
33852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	TX_FIFO_EMPTY      = CNTRL_TIC,
33952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls};
34052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
34152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsenum rx_fifo_watermark {
34252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	RX_FIFO_HALF_FULL = 0,
34352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	RX_FIFO_NOT_EMPTY = CNTRL_RIC,
34452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls};
34552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
34652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_tx_irq_watermark(struct i2c_client *c,
34752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					    enum tx_fifo_watermark level)
34852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
34952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level);
35052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
35152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
35252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_rx_irq_watermark(struct i2c_client *c,
35352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					    enum rx_fifo_watermark level)
35452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
35552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level);
35652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
35752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
35852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_tx_enable(struct i2c_client *c, bool enable)
35952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
36052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE),
36152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			enable ? (CNTRL_TXE | CNTRL_TFE) : 0);
36252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
36352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
36452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_rx_enable(struct i2c_client *c, bool enable)
36552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
36652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE),
36752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			enable ? (CNTRL_RXE | CNTRL_RFE) : 0);
36852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
36952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
37052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_tx_modulation_enable(struct i2c_client *c,
37152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						bool enable)
37252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
37352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD,
37452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			enable ? CNTRL_MOD : 0);
37552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
37652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
37752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_rx_demodulation_enable(struct i2c_client *c,
37852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						  bool enable)
37952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
38052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD,
38152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			enable ? CNTRL_DMD : 0);
38252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
38352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
38452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_rx_s_edge_detection(struct i2c_client *c,
38552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					       u32 edge_types)
38652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
38752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH,
38852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			edge_types & CNTRL_EDG_BOTH);
38952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
39052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
39152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic void control_rx_s_carrier_window(struct i2c_client *c,
39252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					unsigned int carrier,
39352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					unsigned int *carrier_range_low,
39452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					unsigned int *carrier_range_high)
39552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
39652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 v;
39752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	unsigned int c16 = carrier * 16;
39852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
39952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) {
40052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v = CNTRL_WIN_3_4;
40152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4);
40252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	} else {
40352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v = CNTRL_WIN_3_3;
40452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3);
40552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
40652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
40752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) {
40852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v |= CNTRL_WIN_4_3;
40952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4);
41052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	} else {
41152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v |= CNTRL_WIN_3_3;
41252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3);
41352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
41452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v);
41552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
41652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
41752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void control_tx_polarity_invert(struct i2c_client *c,
41852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					      bool invert)
41952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
42052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL,
42152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			invert ? CNTRL_CPL : 0);
42252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
42352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
42452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
42552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * IR Rx & Tx Clock Register helpers
42652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
42752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic unsigned int txclk_tx_s_carrier(struct i2c_client *c,
42852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				       unsigned int freq,
42952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				       u16 *divider)
43052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
43152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*divider = carrier_freq_to_clock_divider(freq);
43252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
43352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return clock_divider_to_carrier_freq(*divider);
43452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
43552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
43652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic unsigned int rxclk_rx_s_carrier(struct i2c_client *c,
43752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				       unsigned int freq,
43852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				       u16 *divider)
43952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
44052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*divider = carrier_freq_to_clock_divider(freq);
44152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
44252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return clock_divider_to_carrier_freq(*divider);
44352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
44452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
44552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns,
44652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      u16 *divider)
44752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
44852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u64 pulse_clocks;
44952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
450c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	if (ns > IR_MAX_DURATION)
451c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		ns = IR_MAX_DURATION;
45252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	pulse_clocks = ns_to_pulse_clocks(ns);
45352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
45452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
45552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
45652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
45752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
45852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns,
45952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      u16 *divider)
46052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
46152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u64 pulse_clocks;
46252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
463c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	if (ns > IR_MAX_DURATION)
464c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		ns = IR_MAX_DURATION;
46552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	pulse_clocks = ns_to_pulse_clocks(ns);
46652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*divider = pulse_clocks_to_clock_divider(pulse_clocks);
46752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
46852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
46952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
47052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
47152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
47252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * IR Tx Carrier Duty Cycle register helpers
47352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
47452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c,
47552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					  unsigned int duty_cycle)
47652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
47752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 n;
47852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */
47952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (n != 0)
48052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n--;
48152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (n > 15)
48252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		n = 15;
48352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_CDUTY_REG, n);
48452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
48552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
48652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
48752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
48852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * IR Filter Register helpers
48952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
49052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns)
49152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
49252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 count = ns_to_lpf_count(min_width_ns);
49352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_FILTR_REG, count);
49452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return lpf_count_to_ns(count);
49552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
49652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
49752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
49852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * IR IRQ Enable Register helpers
49952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
50052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask)
50152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
50252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
50352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
50452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (is_cx23885(state) || is_cx23887(state))
50552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		mask ^= IRQEN_MSK;
50652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE);
50752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG,
50852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask);
50952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
51052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
51152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask)
51252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
51352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
51452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
51552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (is_cx23885(state) || is_cx23887(state))
51652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		mask ^= IRQEN_MSK;
51752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mask &= IRQEN_TSE;
51852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask);
51952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
52052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
52152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
52252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * V4L2 Subdevice IR Ops
52352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
52452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsint cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
52552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
52652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
52752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
52852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c = NULL;
52952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	unsigned long flags;
53052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
531c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH];
532c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	unsigned int i, j, k;
53352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 events, v;
53452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
53552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 cntrl, irqen, stats;
53652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
53752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*handled = false;
53852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
53952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
54052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
54152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	c = ir_state->c;
54252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
54352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Only support the IR controller for the CX2388[57] AV Core for now */
54452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (!(is_cx23885(state) || is_cx23887(state)))
54552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
54652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
54752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
54852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
54952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (is_cx23885(state) || is_cx23887(state))
55052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		irqen ^= IRQEN_MSK;
55152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	stats = cx25840_read4(c, CX25840_IR_STATS_REG);
55252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
55352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	tsr = stats & STATS_TSR; /* Tx FIFO Service Request */
55452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rsr = stats & STATS_RSR; /* Rx FIFO Service Request */
55552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */
55652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	ror = stats & STATS_ROR; /* Rx FIFO Over Run */
55752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
55852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */
55952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */
56052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */
56152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */
56252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
56352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_dbg(2, ir_debug, sd, "IR IRQ Status:  %s %s %s %s %s %s\n",
56452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 tsr ? "tsr" : "   ", rsr ? "rsr" : "   ",
56552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 rto ? "rto" : "   ", ror ? "ror" : "   ",
56652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 stats & STATS_TBY ? "tby" : "   ",
56752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 stats & STATS_RBY ? "rby" : "   ");
56852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
56952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n",
57052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 tse ? "tse" : "   ", rse ? "rse" : "   ",
57152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 rte ? "rte" : "   ", roe ? "roe" : "   ");
57252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
57352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
57452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * Transmitter interrupt service
57552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
57652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (tse && tsr) {
57752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/*
57852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * TODO:
57952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * Check the watermark threshold setting
58052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo
58152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * Push the data to the hardware FIFO.
58252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * If there was nothing more to send in the tx_kfifo, disable
58352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 *	the TSR IRQ and notify the v4l2_device.
58452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * If there was something in the tx_kfifo, check the tx_kfifo
58552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 *      level and notify the v4l2_device, if it is low.
58652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 */
58752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/* For now, inhibit TSR interrupt until Tx is implemented */
58852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		irqenable_tx(sd, 0);
58952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
59052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events);
59152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*handled = true;
59252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
59352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
59452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
59552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * Receiver interrupt service
59652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
59752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	kror = 0;
59852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if ((rse && rsr) || (rte && rto)) {
59952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/*
60052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * Receive data on RSR to clear the STATS_RSR.
60152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * Receive data on RTO, since we may not have yet hit the RSR
60252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * watermark when we receive the RTO.
60352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 */
60452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		for (i = 0, v = FIFO_RX_NDV;
60552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		     (v & FIFO_RX_NDV) && !kror; i = 0) {
60652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			for (j = 0;
60752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			     (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
60852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				v = cx25840_read4(c, CX25840_IR_FIFO_REG);
609c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls				rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV;
610c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls				i++;
61152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			}
61252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			if (i == 0)
61352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				break;
614c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls			j = i * sizeof(union cx25840_ir_fifo_rec);
61552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			k = kfifo_in_locked(&ir_state->rx_kfifo,
61652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					    (unsigned char *) rx_data, j,
61752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					    &ir_state->rx_kfifo_lock);
61852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			if (k != j)
61952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				kror++; /* rx_kfifo over run */
62052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		}
62152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*handled = true;
62252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
62352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
62452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	events = 0;
62552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v = 0;
62652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (kror) {
62752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
62852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_err(sd, "IR receiver software FIFO overrun\n");
62952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
63052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (roe && ror) {
63152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/*
63252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear
63352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * the Rx FIFO Over Run status (STATS_ROR)
63452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 */
63552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v |= CNTRL_RFE;
63652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
63752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_err(sd, "IR receiver hardware FIFO overrun\n");
63852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
63952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (rte && rto) {
64052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/*
64152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear
64252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 * the Rx Pulse Width Timer Time Out (STATS_RTO)
64352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		 */
64452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v |= CNTRL_RXE;
64552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
64652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
64752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (v) {
64852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */
64952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v);
65052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl);
65152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*handled = true;
65252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
65352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
65452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2)
65552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
65652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
65752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
65852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (events)
65952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
66052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
66152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
66252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
66352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/* Receiver */
66452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
66552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			      ssize_t *num)
66652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
66752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
66852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	bool invert;
66952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u16 divider;
67052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	unsigned int i, n;
671c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	union cx25840_ir_fifo_rec *p;
672bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls	unsigned u, v, w;
67352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
67452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
67552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
67652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
67752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	invert = (bool) atomic_read(&ir_state->rx_invert);
67852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	divider = (u16) atomic_read(&ir_state->rxclk_divider);
67952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
680c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	n = count / sizeof(union cx25840_ir_fifo_rec)
681c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		* sizeof(union cx25840_ir_fifo_rec);
68252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (n == 0) {
68352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		*num = 0;
68452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return 0;
68552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
68652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
68752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
68852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			     &ir_state->rx_kfifo_lock);
68952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
690c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	n /= sizeof(union cx25840_ir_fifo_rec);
691c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	*num = n * sizeof(union cx25840_ir_fifo_rec);
69252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
693c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
6942560d94e330f35776e944b54256a526a19259429Andy Walls
695c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
6962560d94e330f35776e944b54256a526a19259429Andy Walls			/* Assume RTO was because of no IR light input */
6972560d94e330f35776e944b54256a526a19259429Andy Walls			u = 0;
698bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls			w = 1;
6992560d94e330f35776e944b54256a526a19259429Andy Walls		} else {
700c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls			u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
7012560d94e330f35776e944b54256a526a19259429Andy Walls			if (invert)
702c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls				u = u ? 0 : 1;
703bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls			w = 0;
70452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		}
70552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
706c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		v = (unsigned) pulse_width_count_to_ns(
707c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls				  (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
708c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		if (v > IR_MAX_DURATION)
709c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls			v = IR_MAX_DURATION;
71052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
711dc69798447173a6b711fe36b714892dd2e880297Maxim Levitsky		init_ir_raw_event(&p->ir_core_data);
712c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		p->ir_core_data.pulse = u;
713c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls		p->ir_core_data.duration = v;
714bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls		p->ir_core_data.timeout = w;
71552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
716bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls		v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns  %s  %s\n",
717bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls			 v, u ? "mark" : "space", w ? "(timed out)" : "");
718bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls		if (w)
719bd829e9d1d7de3178d67d94043f43527213a63a0Andy Walls			v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
72052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
72152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
72252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
72352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
72452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd,
72552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      struct v4l2_subdev_ir_parameters *p)
72652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
72752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
72852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
72952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
73052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
73152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
73252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_lock(&ir_state->rx_params_lock);
73352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	memcpy(p, &ir_state->rx_params,
73452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      sizeof(struct v4l2_subdev_ir_parameters));
73552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_unlock(&ir_state->rx_params_lock);
73652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
73752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
73852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
73952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd)
74052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
74152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
74252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c;
74352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
74452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
74552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
74652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
74752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	c = ir_state->c;
74852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_lock(&ir_state->rx_params_lock);
74952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
75052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Disable or slow down all IR Rx circuits and counters */
75152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqenable_rx(sd, 0);
75252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_enable(c, false);
75352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_demodulation_enable(c, false);
75452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_s_edge_detection(c, CNTRL_EDG_NONE);
75552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	filter_rx_s_min_width(c, 0);
75652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD);
75752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
75852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	ir_state->rx_params.shutdown = true;
75952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
76052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_unlock(&ir_state->rx_params_lock);
76152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
76252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
76352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
76452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd,
76552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      struct v4l2_subdev_ir_parameters *p)
76652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
76752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
76852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c;
76952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct v4l2_subdev_ir_parameters *o;
77052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u16 rxclk_divider;
77152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
77252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
77352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
77452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
77552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->shutdown)
77652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return cx25840_ir_rx_shutdown(sd);
77752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
77852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
77952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENOSYS;
78052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
78152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	c = ir_state->c;
78252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o = &ir_state->rx_params;
78352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
78452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_lock(&ir_state->rx_params_lock);
78552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
78652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->shutdown = p->shutdown;
78752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
78852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
78952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->mode = p->mode;
79052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
791c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
79252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->bytes_per_data_element = p->bytes_per_data_element;
79352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
79452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Before we tweak the hardware, we have to disable the receiver */
79552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqenable_rx(sd, 0);
79652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_enable(c, false);
79752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
79852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_demodulation_enable(c, p->modulation);
79952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->modulation = p->modulation;
80052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
80152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->modulation) {
80252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq,
80352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						     &rxclk_divider);
80452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
80552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		o->carrier_freq = p->carrier_freq;
80652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
80752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		p->duty_cycle = 50;
80852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		o->duty_cycle = p->duty_cycle;
80952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
81052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		control_rx_s_carrier_window(c, p->carrier_freq,
81152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					    &p->carrier_range_lower,
81252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					    &p->carrier_range_upper);
81352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		o->carrier_range_lower = p->carrier_range_lower;
81452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		o->carrier_range_upper = p->carrier_range_upper;
815ceb152add687db152d90ba64b54687b3975963cfAndy Walls
816ceb152add687db152d90ba64b54687b3975963cfAndy Walls		p->max_pulse_width =
817ceb152add687db152d90ba64b54687b3975963cfAndy Walls			(u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider);
81852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	} else {
81952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		p->max_pulse_width =
82052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			    rxclk_rx_s_max_pulse_width(c, p->max_pulse_width,
82152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						       &rxclk_divider);
82252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
823ceb152add687db152d90ba64b54687b3975963cfAndy Walls	o->max_pulse_width = p->max_pulse_width;
82452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	atomic_set(&ir_state->rxclk_divider, rxclk_divider);
82552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
82652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	p->noise_filter_min_width =
82752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			    filter_rx_s_min_width(c, p->noise_filter_min_width);
82852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->noise_filter_min_width = p->noise_filter_min_width;
82952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
83052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	p->resolution = clock_divider_to_resolution(rxclk_divider);
83152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->resolution = p->resolution;
83252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
83352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* FIXME - make this dependent on resolution for better performance */
83452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_irq_watermark(c, RX_FIFO_HALF_FULL);
83552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
83652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_rx_s_edge_detection(c, CNTRL_EDG_BOTH);
83752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
83852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->invert_level = p->invert_level;
83952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	atomic_set(&ir_state->rx_invert, p->invert_level);
84052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
84152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->interrupt_enable = p->interrupt_enable;
84252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->enable = p->enable;
84352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->enable) {
84452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		unsigned long flags;
84552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
84652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
84752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		kfifo_reset(&ir_state->rx_kfifo);
84852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
84952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		if (p->interrupt_enable)
85052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
85152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		control_rx_enable(c, p->enable);
85252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
85352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
85452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_unlock(&ir_state->rx_params_lock);
85552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
85652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
85752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
85852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/* Transmitter */
85952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
86052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			       ssize_t *num)
86152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
86252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
86352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c;
86452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
86552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
86652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
86752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
86852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	c = ir_state->c;
86952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#if 0
87052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
87152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * FIXME - the code below is an incomplete and untested sketch of what
87252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * may need to be done.  The critical part is to get 4 (or 8) pulses
87352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * from the tx_kfifo, or converted from ns to the proper units from the
87452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * input, and push them off to the hardware Tx FIFO right away, if the
87552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * HW TX fifo needs service.  The rest can be pushed to the tx_kfifo in
87652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * a less critical timeframe.  Also watch out for overruning the
87752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * tx_kfifo - don't let it happen and let the caller know not all his
87852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * pulses were written.
87952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
88052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 *ns_pulse = (u32 *) buf;
88152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	unsigned int n;
88252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 fifo_pulse[FIFO_TX_DEPTH];
88352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 mark;
88452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
88552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Compute how much we can fit in the tx kfifo */
88652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo);
88752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n = min(n, (unsigned int) count);
88852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	n /= sizeof(u32);
88952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
89052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* FIXME - turn on Tx Fifo service interrupt
89152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * check hardware fifo level, and other stuff
89252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
89352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	for (i = 0; i < n; ) {
89452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) {
895d69e85b644dbc8c68dec3b4149941989d4bcc66fAndy Walls			mark = ns_pulse[i] & LEVEL_MASK;
89652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			fifo_pulse[j] = ns_to_pulse_width_count(
89752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					 ns_pulse[i] &
898d69e85b644dbc8c68dec3b4149941989d4bcc66fAndy Walls					       ~LEVEL_MASK,
89952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls					 ir_state->txclk_divider);
90052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			if (mark)
90152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				fifo_pulse[j] &= FIFO_RXTX_LVL;
90252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			i++;
90352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		}
90452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse,
90552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls							       j * sizeof(u32));
90652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
90752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*num = n * sizeof(u32);
90852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#else
90952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* For now enable the Tx FIFO Service interrupt & pretend we did work */
91052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqenable_tx(sd, IRQEN_TSE);
91152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	*num = count;
91252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls#endif
91352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
91452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
91552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
91652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd,
91752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      struct v4l2_subdev_ir_parameters *p)
91852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
91952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
92052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
92152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
92252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
92352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
92452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_lock(&ir_state->tx_params_lock);
92552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	memcpy(p, &ir_state->tx_params,
92652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      sizeof(struct v4l2_subdev_ir_parameters));
92752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_unlock(&ir_state->tx_params_lock);
92852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
92952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
93052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
93152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd)
93252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
93352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
93452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c;
93552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
93652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
93752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
93852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
93952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	c = ir_state->c;
94052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_lock(&ir_state->tx_params_lock);
94152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
94252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Disable or slow down all IR Tx circuits and counters */
94352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqenable_tx(sd, 0);
94452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_tx_enable(c, false);
94552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_tx_modulation_enable(c, false);
94652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD);
94752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
94852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	ir_state->tx_params.shutdown = true;
94952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
95052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_unlock(&ir_state->tx_params_lock);
95152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
95252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
95352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
95452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd,
95552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				      struct v4l2_subdev_ir_parameters *p)
95652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
95752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
95852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c;
95952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct v4l2_subdev_ir_parameters *o;
96052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u16 txclk_divider;
96152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
96252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
96352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
96452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
96552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->shutdown)
96652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return cx25840_ir_tx_shutdown(sd);
96752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
96852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
96952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENOSYS;
97052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
97152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	c = ir_state->c;
97252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o = &ir_state->tx_params;
97352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_lock(&ir_state->tx_params_lock);
97452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
97552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->shutdown = p->shutdown;
97652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
97752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
97852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->mode = p->mode;
97952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
980c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
98152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->bytes_per_data_element = p->bytes_per_data_element;
98252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
98352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Before we tweak the hardware, we have to disable the transmitter */
98452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqenable_tx(sd, 0);
98552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_tx_enable(c, false);
98652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
98752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_tx_modulation_enable(c, p->modulation);
98852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->modulation = p->modulation;
98952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
99052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->modulation) {
99152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq,
99252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						     &txclk_divider);
99352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		o->carrier_freq = p->carrier_freq;
99452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
99552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle);
99652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		o->duty_cycle = p->duty_cycle;
997ceb152add687db152d90ba64b54687b3975963cfAndy Walls
998ceb152add687db152d90ba64b54687b3975963cfAndy Walls		p->max_pulse_width =
999ceb152add687db152d90ba64b54687b3975963cfAndy Walls			(u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider);
100052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	} else {
100152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		p->max_pulse_width =
100252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			    txclk_tx_s_max_pulse_width(c, p->max_pulse_width,
100352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls						       &txclk_divider);
100452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
1005ceb152add687db152d90ba64b54687b3975963cfAndy Walls	o->max_pulse_width = p->max_pulse_width;
100652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	atomic_set(&ir_state->txclk_divider, txclk_divider);
100752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
100852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	p->resolution = clock_divider_to_resolution(txclk_divider);
100952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->resolution = p->resolution;
101052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
101152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* FIXME - make this dependent on resolution for better performance */
101252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY);
101352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
101452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	control_tx_polarity_invert(c, p->invert_carrier_sense);
101552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->invert_carrier_sense = p->invert_carrier_sense;
101652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
101752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/*
101852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * FIXME: we don't have hardware help for IO pin level inversion
101952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * here like we have on the CX23888.
102052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * Act on this with some mix of logical inversion of data levels,
102152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 * carrier polarity, and carrier duty cycle.
102252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	 */
102352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->invert_level = p->invert_level;
102452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
102552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->interrupt_enable = p->interrupt_enable;
102652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	o->enable = p->enable;
102752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (p->enable) {
102852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		/* reset tx_fifo here */
102952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		if (p->interrupt_enable)
103052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			irqenable_tx(sd, IRQEN_TSE);
103152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		control_tx_enable(c, p->enable);
103252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
103352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
103452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_unlock(&ir_state->tx_params_lock);
103552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
103652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
103752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
103852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
103952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls/*
104052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls * V4L2 Subdevice Core Ops support
104152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls */
104252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsint cx25840_ir_log_status(struct v4l2_subdev *sd)
104352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
104452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
104552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct i2c_client *c = state->c;
104652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	char *s;
104752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	int i, j;
104852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr;
104952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
105052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* The CX23888 chip doesn't have an IR controller on the A/V core */
105152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (is_cx23888(state))
105252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return 0;
105352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
105452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
105552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD;
105652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD;
105752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC;
105852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	stats = cx25840_read4(c, CX25840_IR_STATS_REG);
105952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
106052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (is_cx23885(state) || is_cx23887(state))
106152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		irqen ^= IRQEN_MSK;
106252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF;
106352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
106452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "IR Receiver:\n");
106552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tEnabled:                           %s\n",
106652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_RXE ? "yes" : "no");
106752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tDemodulation from a carrier:       %s\n",
106852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_DMD ? "enabled" : "disabled");
106952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO:                              %s\n",
107052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_RFE ? "enabled" : "disabled");
107152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	switch (cntrl & CNTRL_EDG) {
107252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	case CNTRL_EDG_NONE:
107352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		s = "disabled";
107452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		break;
107552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	case CNTRL_EDG_FALL:
107652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		s = "falling edge";
107752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		break;
107852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	case CNTRL_EDG_RISE:
107952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		s = "rising edge";
108052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		break;
108152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	case CNTRL_EDG_BOTH:
108252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		s = "rising & falling edges";
108352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		break;
108452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	default:
108552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		s = "??? edge";
108652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		break;
108752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
108852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tPulse timers' start/stop trigger:  %s\n", s);
108952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n",
109052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_R ? "not loaded" : "overflow marker");
109152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
109252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_RIC ? "not empty" : "half full or greater");
109352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tLoopback mode:                     %s\n",
109452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_LBM ? "loopback active" : "normal receive");
109552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (cntrl & CNTRL_DMD) {
109652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_info(sd, "\tExpected carrier (16 clocks):      %u Hz\n",
109752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  clock_divider_to_carrier_freq(rxclk));
109852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		switch (cntrl & CNTRL_WIN) {
109952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		case CNTRL_WIN_3_3:
110052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			i = 3;
110152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			j = 3;
110252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			break;
110352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		case CNTRL_WIN_4_3:
110452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			i = 4;
110552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			j = 3;
110652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			break;
110752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		case CNTRL_WIN_3_4:
110852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			i = 3;
110952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			j = 4;
111052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			break;
111152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		case CNTRL_WIN_4_4:
111252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			i = 4;
111352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			j = 4;
111452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			break;
111552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		default:
111652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			i = 0;
111752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			j = 0;
111852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			break;
111952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		}
112052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_info(sd, "\tNext carrier edge window:          16 clocks "
112152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  "-%1d/+%1d, %u to %u Hz\n", i, j,
112252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  clock_divider_to_freq(rxclk, 16 + j),
112352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  clock_divider_to_freq(rxclk, 16 - i));
112452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
1125ceb152add687db152d90ba64b54687b3975963cfAndy Walls	v4l2_info(sd, "\tMax measurable pulse width:        %u us, %llu ns\n",
1126ceb152add687db152d90ba64b54687b3975963cfAndy Walls		  pulse_width_count_to_us(FIFO_RXTX, rxclk),
1127ceb152add687db152d90ba64b54687b3975963cfAndy Walls		  pulse_width_count_to_ns(FIFO_RXTX, rxclk));
112852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tLow pass filter:                   %s\n",
112952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  filtr ? "enabled" : "disabled");
113052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (filtr)
113152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_info(sd, "\tMin acceptable pulse width (LPF):  %u us, "
113252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  "%u ns\n",
113352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  lpf_count_to_us(filtr),
113452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  lpf_count_to_ns(filtr));
113552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tPulse width timer timed-out:       %s\n",
113652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  stats & STATS_RTO ? "yes" : "no");
113752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tPulse width timer time-out intr:   %s\n",
113852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  irqen & IRQEN_RTE ? "enabled" : "disabled");
113952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO overrun:                      %s\n",
114052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  stats & STATS_ROR ? "yes" : "no");
114152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO overrun interrupt:            %s\n",
114252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  irqen & IRQEN_ROE ? "enabled" : "disabled");
114352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tBusy:                              %s\n",
114452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  stats & STATS_RBY ? "yes" : "no");
114552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO service requested:            %s\n",
114652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  stats & STATS_RSR ? "yes" : "no");
114752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
114852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  irqen & IRQEN_RSE ? "enabled" : "disabled");
114952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
115052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "IR Transmitter:\n");
115152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tEnabled:                           %s\n",
115252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_TXE ? "yes" : "no");
115352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tModulation onto a carrier:         %s\n",
115452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_MOD ? "enabled" : "disabled");
115552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO:                              %s\n",
115652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_TFE ? "enabled" : "disabled");
115752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO interrupt watermark:          %s\n",
115852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_TIC ? "not empty" : "half full or less");
115952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tCarrier polarity:                  %s\n",
116052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  cntrl & CNTRL_CPL ? "space:burst mark:noburst"
116152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls				    : "space:noburst mark:burst");
116252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (cntrl & CNTRL_MOD) {
116352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_info(sd, "\tCarrier (16 clocks):               %u Hz\n",
116452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  clock_divider_to_carrier_freq(txclk));
116552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		v4l2_info(sd, "\tCarrier duty cycle:                %2u/16\n",
116652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			  cduty + 1);
116752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
1168ceb152add687db152d90ba64b54687b3975963cfAndy Walls	v4l2_info(sd, "\tMax pulse width:                   %u us, %llu ns\n",
1169ceb152add687db152d90ba64b54687b3975963cfAndy Walls		  pulse_width_count_to_us(FIFO_RXTX, txclk),
1170ceb152add687db152d90ba64b54687b3975963cfAndy Walls		  pulse_width_count_to_ns(FIFO_RXTX, txclk));
117152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tBusy:                              %s\n",
117252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  stats & STATS_TBY ? "yes" : "no");
117352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO service requested:            %s\n",
117452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  stats & STATS_TSR ? "yes" : "no");
117552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_info(sd, "\tFIFO service request interrupt:    %s\n",
117652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		  irqen & IRQEN_TSE ? "enabled" : "disabled");
117752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
117852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
117952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
118052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
118152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
118252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsconst struct v4l2_subdev_ir_ops cx25840_ir_ops = {
118352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.rx_read = cx25840_ir_rx_read,
118452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.rx_g_parameters = cx25840_ir_rx_g_parameters,
118552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.rx_s_parameters = cx25840_ir_rx_s_parameters,
118652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
118752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.tx_write = cx25840_ir_tx_write,
118852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.tx_g_parameters = cx25840_ir_tx_g_parameters,
118952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.tx_s_parameters = cx25840_ir_tx_s_parameters,
119052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls};
119152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
119252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
119352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic const struct v4l2_subdev_ir_parameters default_rx_params = {
1194c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	.bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
119552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
119652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
119752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.enable = false,
119852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.interrupt_enable = false,
119952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.shutdown = true,
120052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
120152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.modulation = true,
120252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */
120352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
120452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
120552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
120652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.noise_filter_min_width = 333333, /* ns */
120752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.carrier_range_lower = 35000,
120852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.carrier_range_upper = 37000,
120952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.invert_level = false,
121052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls};
121152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
121252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsstatic const struct v4l2_subdev_ir_parameters default_tx_params = {
1213c02e0d12a9a0a913dee5efd695603b73ee4b729aAndy Walls	.bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
121452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
121552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
121652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.enable = false,
121752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.interrupt_enable = false,
121852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.shutdown = true,
121952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
122052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.modulation = true,
122152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
122252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.duty_cycle = 25,      /* 25 %   - RC-5 carrier */
122352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.invert_level = false,
122452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	.invert_carrier_sense = false,
122552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls};
122652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
122752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsint cx25840_ir_probe(struct v4l2_subdev *sd)
122852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
122952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
123052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state;
123152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct v4l2_subdev_ir_parameters default_params;
123252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
123352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Only init the IR controller for the CX2388[57] AV Core for now */
123452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (!(is_cx23885(state) || is_cx23887(state)))
123552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return 0;
123652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
123752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL);
123852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
123952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENOMEM;
124052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
124152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	spin_lock_init(&ir_state->rx_kfifo_lock);
124252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (kfifo_alloc(&ir_state->rx_kfifo,
124352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls			CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) {
124452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		kfree(ir_state);
124552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENOMEM;
124652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	}
124752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
124852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	ir_state->c = state->c;
124952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	state->ir_state = ir_state;
125052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
125152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	/* Ensure no interrupts arrive yet */
125252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (is_cx23885(state) || is_cx23887(state))
125352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK);
125452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	else
125552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0);
125652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
125752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_init(&ir_state->rx_params_lock);
125852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	memcpy(&default_params, &default_rx_params,
125952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		       sizeof(struct v4l2_subdev_ir_parameters));
126052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
126152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
126252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	mutex_init(&ir_state->tx_params_lock);
126352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	memcpy(&default_params, &default_tx_params,
126452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		       sizeof(struct v4l2_subdev_ir_parameters));
126552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
126652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
126752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
126852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
126952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
127052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Wallsint cx25840_ir_remove(struct v4l2_subdev *sd)
127152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls{
127252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_state *state = to_state(sd);
127352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	struct cx25840_ir_state *ir_state = to_ir_state(sd);
127452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
127552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	if (ir_state == NULL)
127652fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls		return -ENODEV;
127752fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
127852fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_ir_rx_shutdown(sd);
127952fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	cx25840_ir_tx_shutdown(sd);
128052fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls
128152fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	kfifo_free(&ir_state->rx_kfifo);
128252fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	kfree(ir_state);
128352fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	state->ir_state = NULL;
128452fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls	return 0;
128552fd3dda130d03ae5c2bbdcbe81f6e083c051e12Andy Walls}
1286