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