aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840
diff options
context:
space:
mode:
authorAndy Walls <awalls@md.metrocast.net>2010-07-18 21:08:03 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-08 22:42:55 -0400
commit52fd3dda130d03ae5c2bbdcbe81f6e083c051e12 (patch)
tree1b391a39d888314fe8ed3ac968a2384898938b3b /drivers/media/video/cx25840
parent260e689ba237fb513b49e98841d98e93ea639c75 (diff)
V4L/DVB: cx25840: Add support for CX2388[57] A/V core integrated IR controllers
This patch is primarily a port of the integrated IR controller code in cx23885/cx23888-ir.c. Right now, only the CX2388[57] AV core will really try to set up IR. This IR support, by design, still requires the bridge driver to do final IO pin mux configuration and setup of the IR controller parameters. For the CX2388[578] chips, enabling the AV Core for IR also starts sending Audio and Video interrupts to the bridge driver. For CX2388[578] chips audio and video interrupts are ignored and acknowledged when they happen. IR interrupt handling and status logging is exluded for the CX23888 which does not have an IR controller on the AV core. Note that experimentation reveals that the IR irq enables on the CX23885 have an inverted logic sense. The CX23887 likely suffers from the same quirk. For these chips, those irq enable bits are handled as interrupt disables. Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r--drivers/media/video/cx25840/Makefile2
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c128
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h28
-rw-r--r--drivers/media/video/cx25840/cx25840-ir.c1262
4 files changed, 1419 insertions, 1 deletions
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
index 6e8665be8954..2ee96d3973b8 100644
--- a/drivers/media/video/cx25840/Makefile
+++ b/drivers/media/video/cx25840/Makefile
@@ -1,5 +1,5 @@
1cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ 1cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
2 cx25840-vbi.o 2 cx25840-vbi.o cx25840-ir.o
3 3
4obj-$(CONFIG_VIDEO_CX25840) += cx25840.o 4obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
5 5
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 46a046d6405e..9fab0b170846 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -15,6 +15,9 @@
15 * 15 *
16 * CX23885 support by Steven Toth <stoth@linuxtv.org>. 16 * CX23885 support by Steven Toth <stoth@linuxtv.org>.
17 * 17 *
18 * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
19 * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
20 *
18 * This program is free software; you can redistribute it and/or 21 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License 22 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2 23 * as published by the Free Software Foundation; either version 2
@@ -48,6 +51,28 @@ MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
48MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); 51MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
49MODULE_LICENSE("GPL"); 52MODULE_LICENSE("GPL");
50 53
54#define CX25840_VID_INT_STAT_REG 0x410
55#define CX25840_VID_INT_STAT_BITS 0x0000ffff
56#define CX25840_VID_INT_MASK_BITS 0xffff0000
57#define CX25840_VID_INT_MASK_SHFT 16
58#define CX25840_VID_INT_MASK_REG 0x412
59
60#define CX23885_AUD_MC_INT_MASK_REG 0x80c
61#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000
62#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff
63#define CX23885_AUD_MC_INT_STAT_SHFT 16
64
65#define CX25840_AUD_INT_CTRL_REG 0x812
66#define CX25840_AUD_INT_STAT_REG 0x813
67
68#define CX23885_PIN_CTRL_IRQ_REG 0x123
69#define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40
70#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20
71#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10
72
73#define CX25840_IR_STATS_REG 0x210
74#define CX25840_IR_IRQEN_REG 0x214
75
51static int cx25840_debug; 76static int cx25840_debug;
52 77
53module_param_named(debug,cx25840_debug, int, 0644); 78module_param_named(debug,cx25840_debug, int, 0644);
@@ -137,6 +162,14 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
137 or_value); 162 or_value);
138} 163}
139 164
165int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
166 u32 or_value)
167{
168 return cx25840_write4(client, addr,
169 (cx25840_read4(client, addr) & and_mask) |
170 or_value);
171}
172
140/* ----------------------------------------------------------------------- */ 173/* ----------------------------------------------------------------------- */
141 174
142static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, 175static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
@@ -592,6 +625,13 @@ static void cx23885_initialize(struct i2c_client *client)
592 625
593 /* start microcontroller */ 626 /* start microcontroller */
594 cx25840_and_or(client, 0x803, ~0x10, 0x10); 627 cx25840_and_or(client, 0x803, ~0x10, 0x10);
628
629 /* Disable and clear video interrupts - we don't use them */
630 cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
631
632 /* Disable and clear audio interrupts - we don't use them */
633 cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
634 cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
595} 635}
596 636
597/* ----------------------------------------------------------------------- */ 637/* ----------------------------------------------------------------------- */
@@ -1748,9 +1788,93 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
1748 log_video_status(client); 1788 log_video_status(client);
1749 if (!is_cx2583x(state)) 1789 if (!is_cx2583x(state))
1750 log_audio_status(client); 1790 log_audio_status(client);
1791 cx25840_ir_log_status(sd);
1751 return 0; 1792 return 0;
1752} 1793}
1753 1794
1795static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
1796 bool *handled)
1797{
1798 struct cx25840_state *state = to_state(sd);
1799 struct i2c_client *c = v4l2_get_subdevdata(sd);
1800 u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en;
1801 u32 vid_stat, aud_mc_stat;
1802 bool block_handled;
1803 int ret = 0;
1804
1805 irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
1806 v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n",
1807 irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
1808 irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
1809 irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
1810
1811 if ((is_cx23885(state) || is_cx23887(state))) {
1812 ir_stat = cx25840_read(c, CX25840_IR_STATS_REG);
1813 ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG);
1814 v4l_dbg(2, cx25840_debug, c,
1815 "AV Core ir IRQ status: %#04x disables: %#04x\n",
1816 ir_stat, ir_en);
1817 if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) {
1818 block_handled = false;
1819 ret = cx25840_ir_irq_handler(sd,
1820 status, &block_handled);
1821 if (block_handled)
1822 *handled = true;
1823 }
1824 }
1825
1826 aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG);
1827 aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG);
1828 v4l_dbg(2, cx25840_debug, c,
1829 "AV Core audio IRQ status: %#04x disables: %#04x\n",
1830 aud_stat, aud_en);
1831 aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG);
1832 v4l_dbg(2, cx25840_debug, c,
1833 "AV Core audio MC IRQ status: %#06x enables: %#06x\n",
1834 aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT,
1835 aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS);
1836 if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) {
1837 if (aud_stat) {
1838 cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat);
1839 *handled = true;
1840 }
1841 }
1842
1843 vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG);
1844 v4l_dbg(2, cx25840_debug, c,
1845 "AV Core video IRQ status: %#06x disables: %#06x\n",
1846 vid_stat & CX25840_VID_INT_STAT_BITS,
1847 vid_stat >> CX25840_VID_INT_MASK_SHFT);
1848 if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) {
1849 if (vid_stat & CX25840_VID_INT_STAT_BITS) {
1850 cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat);
1851 *handled = true;
1852 }
1853 }
1854
1855 irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
1856 v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n",
1857 irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
1858 irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
1859 irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
1860
1861 return ret;
1862}
1863
1864static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
1865 bool *handled)
1866{
1867 struct cx25840_state *state = to_state(sd);
1868
1869 *handled = false;
1870
1871 /* Only support the CX2388[578] AV Core for now */
1872 if (is_cx2388x(state))
1873 return cx23885_irq_handler(sd, status, handled);
1874
1875 return -ENODEV;
1876}
1877
1754/* ----------------------------------------------------------------------- */ 1878/* ----------------------------------------------------------------------- */
1755 1879
1756static const struct v4l2_subdev_core_ops cx25840_core_ops = { 1880static const struct v4l2_subdev_core_ops cx25840_core_ops = {
@@ -1767,6 +1891,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
1767 .g_register = cx25840_g_register, 1891 .g_register = cx25840_g_register,
1768 .s_register = cx25840_s_register, 1892 .s_register = cx25840_s_register,
1769#endif 1893#endif
1894 .interrupt_service_routine = cx25840_irq_handler,
1770}; 1895};
1771 1896
1772static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { 1897static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
@@ -1801,6 +1926,7 @@ static const struct v4l2_subdev_ops cx25840_ops = {
1801 .audio = &cx25840_audio_ops, 1926 .audio = &cx25840_audio_ops,
1802 .video = &cx25840_video_ops, 1927 .video = &cx25840_video_ops,
1803 .vbi = &cx25840_vbi_ops, 1928 .vbi = &cx25840_vbi_ops,
1929 .ir = &cx25840_ir_ops,
1804}; 1930};
1805 1931
1806/* ----------------------------------------------------------------------- */ 1932/* ----------------------------------------------------------------------- */
@@ -1942,6 +2068,7 @@ static int cx25840_probe(struct i2c_client *client,
1942 state->id = id; 2068 state->id = id;
1943 state->rev = device_id; 2069 state->rev = device_id;
1944 2070
2071 cx25840_ir_probe(sd);
1945 return 0; 2072 return 0;
1946} 2073}
1947 2074
@@ -1949,6 +2076,7 @@ static int cx25840_remove(struct i2c_client *client)
1949{ 2076{
1950 struct v4l2_subdev *sd = i2c_get_clientdata(client); 2077 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1951 2078
2079 cx25840_ir_remove(sd);
1952 v4l2_device_unregister_subdev(sd); 2080 v4l2_device_unregister_subdev(sd);
1953 kfree(to_state(sd)); 2081 kfree(to_state(sd));
1954 return 0; 2082 return 0;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 04393b971567..8f47322c003d 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -34,6 +34,8 @@
34 providing this information. */ 34 providing this information. */
35#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) 35#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
36 36
37struct cx25840_ir_state;
38
37struct cx25840_state { 39struct cx25840_state {
38 struct i2c_client *c; 40 struct i2c_client *c;
39 struct v4l2_subdev sd; 41 struct v4l2_subdev sd;
@@ -52,6 +54,7 @@ struct cx25840_state {
52 int is_initialized; 54 int is_initialized;
53 wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ 55 wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
54 struct work_struct fw_work; /* work entry for fw load */ 56 struct work_struct fw_work; /* work entry for fw load */
57 struct cx25840_ir_state *ir_state;
55}; 58};
56 59
57static inline struct cx25840_state *to_state(struct v4l2_subdev *sd) 60static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
@@ -77,6 +80,21 @@ static inline bool is_cx2388x(struct cx25840_state *state)
77 state->id == V4L2_IDENT_CX23888_AV; 80 state->id == V4L2_IDENT_CX23888_AV;
78} 81}
79 82
83static inline bool is_cx23885(struct cx25840_state *state)
84{
85 return state->id == V4L2_IDENT_CX23885_AV;
86}
87
88static inline bool is_cx23887(struct cx25840_state *state)
89{
90 return state->id == V4L2_IDENT_CX23887_AV;
91}
92
93static inline bool is_cx23888(struct cx25840_state *state)
94{
95 return state->id == V4L2_IDENT_CX23888_AV;
96}
97
80/* ----------------------------------------------------------------------- */ 98/* ----------------------------------------------------------------------- */
81/* cx25850-core.c */ 99/* cx25850-core.c */
82int cx25840_write(struct i2c_client *client, u16 addr, u8 value); 100int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
@@ -84,6 +102,8 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
84u8 cx25840_read(struct i2c_client *client, u16 addr); 102u8 cx25840_read(struct i2c_client *client, u16 addr);
85u32 cx25840_read4(struct i2c_client *client, u16 addr); 103u32 cx25840_read4(struct i2c_client *client, u16 addr);
86int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); 104int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
105int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
106 u32 or_value);
87void cx25840_std_setup(struct i2c_client *client); 107void cx25840_std_setup(struct i2c_client *client);
88 108
89/* ----------------------------------------------------------------------- */ 109/* ----------------------------------------------------------------------- */
@@ -104,4 +124,12 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
104int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); 124int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
105int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi); 125int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
106 126
127/* ----------------------------------------------------------------------- */
128/* cx25850-ir.c */
129extern const struct v4l2_subdev_ir_ops cx25840_ir_ops;
130int cx25840_ir_log_status(struct v4l2_subdev *sd);
131int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled);
132int cx25840_ir_probe(struct v4l2_subdev *sd);
133int cx25840_ir_remove(struct v4l2_subdev *sd);
134
107#endif 135#endif
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
new file mode 100644
index 000000000000..308e87e9fae7
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -0,0 +1,1262 @@
1/*
2 * Driver for the Conexant CX2584x Audio/Video decoder chip and related cores
3 *
4 * Integrated Consumer Infrared Controller
5 *
6 * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <linux/slab.h>
25#include <linux/kfifo.h>
26#include <media/cx25840.h>
27
28#include "cx25840-core.h"
29
30static unsigned int ir_debug;
31module_param(ir_debug, int, 0644);
32MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
33
34#define CX25840_IR_REG_BASE 0x200
35
36#define CX25840_IR_CNTRL_REG 0x200
37#define CNTRL_WIN_3_3 0x00000000
38#define CNTRL_WIN_4_3 0x00000001
39#define CNTRL_WIN_3_4 0x00000002
40#define CNTRL_WIN_4_4 0x00000003
41#define CNTRL_WIN 0x00000003
42#define CNTRL_EDG_NONE 0x00000000
43#define CNTRL_EDG_FALL 0x00000004
44#define CNTRL_EDG_RISE 0x00000008
45#define CNTRL_EDG_BOTH 0x0000000C
46#define CNTRL_EDG 0x0000000C
47#define CNTRL_DMD 0x00000010
48#define CNTRL_MOD 0x00000020
49#define CNTRL_RFE 0x00000040
50#define CNTRL_TFE 0x00000080
51#define CNTRL_RXE 0x00000100
52#define CNTRL_TXE 0x00000200
53#define CNTRL_RIC 0x00000400
54#define CNTRL_TIC 0x00000800
55#define CNTRL_CPL 0x00001000
56#define CNTRL_LBM 0x00002000
57#define CNTRL_R 0x00004000
58
59#define CX25840_IR_TXCLK_REG 0x204
60#define TXCLK_TCD 0x0000FFFF
61
62#define CX25840_IR_RXCLK_REG 0x208
63#define RXCLK_RCD 0x0000FFFF
64
65#define CX25840_IR_CDUTY_REG 0x20C
66#define CDUTY_CDC 0x0000000F
67
68#define CX25840_IR_STATS_REG 0x210
69#define STATS_RTO 0x00000001
70#define STATS_ROR 0x00000002
71#define STATS_RBY 0x00000004
72#define STATS_TBY 0x00000008
73#define STATS_RSR 0x00000010
74#define STATS_TSR 0x00000020
75
76#define CX25840_IR_IRQEN_REG 0x214
77#define IRQEN_RTE 0x00000001
78#define IRQEN_ROE 0x00000002
79#define IRQEN_RSE 0x00000010
80#define IRQEN_TSE 0x00000020
81#define IRQEN_MSK 0x00000033
82
83#define CX25840_IR_FILTR_REG 0x218
84#define FILTR_LPF 0x0000FFFF
85
86#define CX25840_IR_FIFO_REG 0x23C
87#define FIFO_RXTX 0x0000FFFF
88#define FIFO_RXTX_LVL 0x00010000
89#define FIFO_RXTX_RTO 0x0001FFFF
90#define FIFO_RX_NDV 0x00020000
91#define FIFO_RX_DEPTH 8
92#define FIFO_TX_DEPTH 8
93
94#define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
95#define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2)
96
97#define CX25840_IR_RX_KFIFO_SIZE (512 * sizeof(u32))
98#define CX25840_IR_TX_KFIFO_SIZE (512 * sizeof(u32))
99
100struct cx25840_ir_state {
101 struct i2c_client *c;
102
103 struct v4l2_subdev_ir_parameters rx_params;
104 struct mutex rx_params_lock; /* protects Rx parameter settings cache */
105 atomic_t rxclk_divider;
106 atomic_t rx_invert;
107
108 struct kfifo rx_kfifo;
109 spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */
110
111 struct v4l2_subdev_ir_parameters tx_params;
112 struct mutex tx_params_lock; /* protects Tx parameter settings cache */
113 atomic_t txclk_divider;
114};
115
116static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd)
117{
118 struct cx25840_state *state = to_state(sd);
119 return state ? state->ir_state : NULL;
120}
121
122
123/*
124 * Rx and Tx Clock Divider register computations
125 *
126 * Note the largest clock divider value of 0xffff corresponds to:
127 * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
128 * which fits in 21 bits, so we'll use unsigned int for time arguments.
129 */
130static inline u16 count_to_clock_divider(unsigned int d)
131{
132 if (d > RXCLK_RCD + 1)
133 d = RXCLK_RCD;
134 else if (d < 2)
135 d = 1;
136 else
137 d--;
138 return (u16) d;
139}
140
141static inline u16 ns_to_clock_divider(unsigned int ns)
142{
143 return count_to_clock_divider(
144 DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
145}
146
147static inline unsigned int clock_divider_to_ns(unsigned int divider)
148{
149 /* Period of the Rx or Tx clock in ns */
150 return DIV_ROUND_CLOSEST((divider + 1) * 1000,
151 CX25840_IR_REFCLK_FREQ / 1000000);
152}
153
154static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
155{
156 return count_to_clock_divider(
157 DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16));
158}
159
160static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
161{
162 return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16);
163}
164
165static inline u16 freq_to_clock_divider(unsigned int freq,
166 unsigned int rollovers)
167{
168 return count_to_clock_divider(
169 DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers));
170}
171
172static inline unsigned int clock_divider_to_freq(unsigned int divider,
173 unsigned int rollovers)
174{
175 return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ,
176 (divider + 1) * rollovers);
177}
178
179/*
180 * Low Pass Filter register calculations
181 *
182 * Note the largest count value of 0xffff corresponds to:
183 * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
184 * which fits in 21 bits, so we'll use unsigned int for time arguments.
185 */
186static inline u16 count_to_lpf_count(unsigned int d)
187{
188 if (d > FILTR_LPF)
189 d = FILTR_LPF;
190 else if (d < 4)
191 d = 0;
192 return (u16) d;
193}
194
195static inline u16 ns_to_lpf_count(unsigned int ns)
196{
197 return count_to_lpf_count(
198 DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
199}
200
201static inline unsigned int lpf_count_to_ns(unsigned int count)
202{
203 /* Duration of the Low Pass Filter rejection window in ns */
204 return DIV_ROUND_CLOSEST(count * 1000,
205 CX25840_IR_REFCLK_FREQ / 1000000);
206}
207
208static inline unsigned int lpf_count_to_us(unsigned int count)
209{
210 /* Duration of the Low Pass Filter rejection window in us */
211 return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000);
212}
213
214/*
215 * FIFO register pulse width count compuations
216 */
217static u32 clock_divider_to_resolution(u16 divider)
218{
219 /*
220 * Resolution is the duration of 1 tick of the readable portion of
221 * of the pulse width counter as read from the FIFO. The two lsb's are
222 * not readable, hence the << 2. This function returns ns.
223 */
224 return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000,
225 CX25840_IR_REFCLK_FREQ / 1000000);
226}
227
228static u64 pulse_width_count_to_ns(u16 count, u16 divider)
229{
230 u64 n;
231 u32 rem;
232
233 /*
234 * The 2 lsb's of the pulse width timer count are not readable, hence
235 * the (count << 2) | 0x3
236 */
237 n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
238 rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */
239 if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
240 n++;
241 return n;
242}
243
244#if 0
245/* Keep as we will need this for Transmit functionality */
246static u16 ns_to_pulse_width_count(u32 ns, u16 divider)
247{
248 u64 n;
249 u32 d;
250 u32 rem;
251
252 /*
253 * The 2 lsb's of the pulse width timer count are not accessable, hence
254 * the (1 << 2)
255 */
256 n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */
257 d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */
258 rem = do_div(n, d);
259 if (rem >= d / 2)
260 n++;
261
262 if (n > FIFO_RXTX)
263 n = FIFO_RXTX;
264 else if (n == 0)
265 n = 1;
266 return (u16) n;
267}
268
269#endif
270static unsigned int pulse_width_count_to_us(u16 count, u16 divider)
271{
272 u64 n;
273 u32 rem;
274
275 /*
276 * The 2 lsb's of the pulse width timer count are not readable, hence
277 * the (count << 2) | 0x3
278 */
279 n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */
280 rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
281 if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
282 n++;
283 return (unsigned int) n;
284}
285
286/*
287 * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
288 *
289 * The total pulse clock count is an 18 bit pulse width timer count as the most
290 * significant part and (up to) 16 bit clock divider count as a modulus.
291 * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
292 * width timer count's least significant bit.
293 */
294static u64 ns_to_pulse_clocks(u32 ns)
295{
296 u64 clocks;
297 u32 rem;
298 clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */
299 rem = do_div(clocks, 1000); /* /1000 = cycles */
300 if (rem >= 1000 / 2)
301 clocks++;
302 return clocks;
303}
304
305static u16 pulse_clocks_to_clock_divider(u64 count)
306{
307 u32 rem;
308
309 rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
310
311 /* net result needs to be rounded down and decremented by 1 */
312 if (count > RXCLK_RCD + 1)
313 count = RXCLK_RCD;
314 else if (count < 2)
315 count = 1;
316 else
317 count--;
318 return (u16) count;
319}
320
321/*
322 * IR Control Register helpers
323 */
324enum tx_fifo_watermark {
325 TX_FIFO_HALF_EMPTY = 0,
326 TX_FIFO_EMPTY = CNTRL_TIC,
327};
328
329enum rx_fifo_watermark {
330 RX_FIFO_HALF_FULL = 0,
331 RX_FIFO_NOT_EMPTY = CNTRL_RIC,
332};
333
334static inline void control_tx_irq_watermark(struct i2c_client *c,
335 enum tx_fifo_watermark level)
336{
337 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level);
338}
339
340static inline void control_rx_irq_watermark(struct i2c_client *c,
341 enum rx_fifo_watermark level)
342{
343 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level);
344}
345
346static inline void control_tx_enable(struct i2c_client *c, bool enable)
347{
348 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE),
349 enable ? (CNTRL_TXE | CNTRL_TFE) : 0);
350}
351
352static inline void control_rx_enable(struct i2c_client *c, bool enable)
353{
354 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE),
355 enable ? (CNTRL_RXE | CNTRL_RFE) : 0);
356}
357
358static inline void control_tx_modulation_enable(struct i2c_client *c,
359 bool enable)
360{
361 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD,
362 enable ? CNTRL_MOD : 0);
363}
364
365static inline void control_rx_demodulation_enable(struct i2c_client *c,
366 bool enable)
367{
368 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD,
369 enable ? CNTRL_DMD : 0);
370}
371
372static inline void control_rx_s_edge_detection(struct i2c_client *c,
373 u32 edge_types)
374{
375 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH,
376 edge_types & CNTRL_EDG_BOTH);
377}
378
379static void control_rx_s_carrier_window(struct i2c_client *c,
380 unsigned int carrier,
381 unsigned int *carrier_range_low,
382 unsigned int *carrier_range_high)
383{
384 u32 v;
385 unsigned int c16 = carrier * 16;
386
387 if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) {
388 v = CNTRL_WIN_3_4;
389 *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4);
390 } else {
391 v = CNTRL_WIN_3_3;
392 *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3);
393 }
394
395 if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) {
396 v |= CNTRL_WIN_4_3;
397 *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4);
398 } else {
399 v |= CNTRL_WIN_3_3;
400 *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3);
401 }
402 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v);
403}
404
405static inline void control_tx_polarity_invert(struct i2c_client *c,
406 bool invert)
407{
408 cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL,
409 invert ? CNTRL_CPL : 0);
410}
411
412/*
413 * IR Rx & Tx Clock Register helpers
414 */
415static unsigned int txclk_tx_s_carrier(struct i2c_client *c,
416 unsigned int freq,
417 u16 *divider)
418{
419 *divider = carrier_freq_to_clock_divider(freq);
420 cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
421 return clock_divider_to_carrier_freq(*divider);
422}
423
424static unsigned int rxclk_rx_s_carrier(struct i2c_client *c,
425 unsigned int freq,
426 u16 *divider)
427{
428 *divider = carrier_freq_to_clock_divider(freq);
429 cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
430 return clock_divider_to_carrier_freq(*divider);
431}
432
433static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns,
434 u16 *divider)
435{
436 u64 pulse_clocks;
437
438 if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
439 ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
440 pulse_clocks = ns_to_pulse_clocks(ns);
441 *divider = pulse_clocks_to_clock_divider(pulse_clocks);
442 cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
443 return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
444}
445
446static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns,
447 u16 *divider)
448{
449 u64 pulse_clocks;
450
451 if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
452 ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
453 pulse_clocks = ns_to_pulse_clocks(ns);
454 *divider = pulse_clocks_to_clock_divider(pulse_clocks);
455 cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
456 return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
457}
458
459/*
460 * IR Tx Carrier Duty Cycle register helpers
461 */
462static unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c,
463 unsigned int duty_cycle)
464{
465 u32 n;
466 n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */
467 if (n != 0)
468 n--;
469 if (n > 15)
470 n = 15;
471 cx25840_write4(c, CX25840_IR_CDUTY_REG, n);
472 return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
473}
474
475/*
476 * IR Filter Register helpers
477 */
478static u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns)
479{
480 u32 count = ns_to_lpf_count(min_width_ns);
481 cx25840_write4(c, CX25840_IR_FILTR_REG, count);
482 return lpf_count_to_ns(count);
483}
484
485/*
486 * IR IRQ Enable Register helpers
487 */
488static inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask)
489{
490 struct cx25840_state *state = to_state(sd);
491
492 if (is_cx23885(state) || is_cx23887(state))
493 mask ^= IRQEN_MSK;
494 mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE);
495 cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG,
496 ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask);
497}
498
499static inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask)
500{
501 struct cx25840_state *state = to_state(sd);
502
503 if (is_cx23885(state) || is_cx23887(state))
504 mask ^= IRQEN_MSK;
505 mask &= IRQEN_TSE;
506 cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask);
507}
508
509/*
510 * V4L2 Subdevice IR Ops
511 */
512int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
513{
514 struct cx25840_state *state = to_state(sd);
515 struct cx25840_ir_state *ir_state = to_ir_state(sd);
516 struct i2c_client *c = NULL;
517 unsigned long flags;
518
519 u32 rx_data[FIFO_RX_DEPTH];
520 int i, j, k;
521 u32 events, v;
522 int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
523 u32 cntrl, irqen, stats;
524
525 *handled = false;
526 if (ir_state == NULL)
527 return -ENODEV;
528
529 c = ir_state->c;
530
531 /* Only support the IR controller for the CX2388[57] AV Core for now */
532 if (!(is_cx23885(state) || is_cx23887(state)))
533 return -ENODEV;
534
535 cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
536 irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
537 if (is_cx23885(state) || is_cx23887(state))
538 irqen ^= IRQEN_MSK;
539 stats = cx25840_read4(c, CX25840_IR_STATS_REG);
540
541 tsr = stats & STATS_TSR; /* Tx FIFO Service Request */
542 rsr = stats & STATS_RSR; /* Rx FIFO Service Request */
543 rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */
544 ror = stats & STATS_ROR; /* Rx FIFO Over Run */
545
546 tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */
547 rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */
548 rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */
549 roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */
550
551 v4l2_dbg(2, ir_debug, sd, "IR IRQ Status: %s %s %s %s %s %s\n",
552 tsr ? "tsr" : " ", rsr ? "rsr" : " ",
553 rto ? "rto" : " ", ror ? "ror" : " ",
554 stats & STATS_TBY ? "tby" : " ",
555 stats & STATS_RBY ? "rby" : " ");
556
557 v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n",
558 tse ? "tse" : " ", rse ? "rse" : " ",
559 rte ? "rte" : " ", roe ? "roe" : " ");
560
561 /*
562 * Transmitter interrupt service
563 */
564 if (tse && tsr) {
565 /*
566 * TODO:
567 * Check the watermark threshold setting
568 * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo
569 * Push the data to the hardware FIFO.
570 * If there was nothing more to send in the tx_kfifo, disable
571 * the TSR IRQ and notify the v4l2_device.
572 * If there was something in the tx_kfifo, check the tx_kfifo
573 * level and notify the v4l2_device, if it is low.
574 */
575 /* For now, inhibit TSR interrupt until Tx is implemented */
576 irqenable_tx(sd, 0);
577 events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
578 v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events);
579 *handled = true;
580 }
581
582 /*
583 * Receiver interrupt service
584 */
585 kror = 0;
586 if ((rse && rsr) || (rte && rto)) {
587 /*
588 * Receive data on RSR to clear the STATS_RSR.
589 * Receive data on RTO, since we may not have yet hit the RSR
590 * watermark when we receive the RTO.
591 */
592 for (i = 0, v = FIFO_RX_NDV;
593 (v & FIFO_RX_NDV) && !kror; i = 0) {
594 for (j = 0;
595 (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
596 v = cx25840_read4(c, CX25840_IR_FIFO_REG);
597 rx_data[i++] = v & ~FIFO_RX_NDV;
598 }
599 if (i == 0)
600 break;
601 j = i * sizeof(u32);
602 k = kfifo_in_locked(&ir_state->rx_kfifo,
603 (unsigned char *) rx_data, j,
604 &ir_state->rx_kfifo_lock);
605 if (k != j)
606 kror++; /* rx_kfifo over run */
607 }
608 *handled = true;
609 }
610
611 events = 0;
612 v = 0;
613 if (kror) {
614 events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
615 v4l2_err(sd, "IR receiver software FIFO overrun\n");
616 }
617 if (roe && ror) {
618 /*
619 * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear
620 * the Rx FIFO Over Run status (STATS_ROR)
621 */
622 v |= CNTRL_RFE;
623 events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
624 v4l2_err(sd, "IR receiver hardware FIFO overrun\n");
625 }
626 if (rte && rto) {
627 /*
628 * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear
629 * the Rx Pulse Width Timer Time Out (STATS_RTO)
630 */
631 v |= CNTRL_RXE;
632 events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
633 }
634 if (v) {
635 /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */
636 cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v);
637 cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl);
638 *handled = true;
639 }
640 spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
641 if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2)
642 events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
643 spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
644
645 if (events)
646 v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
647 return 0;
648}
649
650/* Receiver */
651static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
652 ssize_t *num)
653{
654 struct cx25840_ir_state *ir_state = to_ir_state(sd);
655 bool invert;
656 u16 divider;
657 unsigned int i, n;
658 u32 *p;
659 u32 u, v;
660
661 if (ir_state == NULL)
662 return -ENODEV;
663
664 invert = (bool) atomic_read(&ir_state->rx_invert);
665 divider = (u16) atomic_read(&ir_state->rxclk_divider);
666
667 n = count / sizeof(u32) * sizeof(u32);
668 if (n == 0) {
669 *num = 0;
670 return 0;
671 }
672
673 n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
674 &ir_state->rx_kfifo_lock);
675
676 n /= sizeof(u32);
677 *num = n * sizeof(u32);
678
679 for (p = (u32 *) buf, i = 0; i < n; p++, i++) {
680 if ((*p & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
681 *p = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
682 v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
683 continue;
684 }
685
686 u = (*p & FIFO_RXTX_LVL) ? V4L2_SUBDEV_IR_PULSE_LEVEL_MASK : 0;
687 if (invert)
688 u = u ? 0 : V4L2_SUBDEV_IR_PULSE_LEVEL_MASK;
689
690 v = (u32) pulse_width_count_to_ns((u16) (*p & FIFO_RXTX),
691 divider);
692 if (v >= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
693 v = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS - 1;
694
695 *p = u | v;
696
697 v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n",
698 v, u ? "mark" : "space");
699 }
700 return 0;
701}
702
703static int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd,
704 struct v4l2_subdev_ir_parameters *p)
705{
706 struct cx25840_ir_state *ir_state = to_ir_state(sd);
707
708 if (ir_state == NULL)
709 return -ENODEV;
710
711 mutex_lock(&ir_state->rx_params_lock);
712 memcpy(p, &ir_state->rx_params,
713 sizeof(struct v4l2_subdev_ir_parameters));
714 mutex_unlock(&ir_state->rx_params_lock);
715 return 0;
716}
717
718static int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd)
719{
720 struct cx25840_ir_state *ir_state = to_ir_state(sd);
721 struct i2c_client *c;
722
723 if (ir_state == NULL)
724 return -ENODEV;
725
726 c = ir_state->c;
727 mutex_lock(&ir_state->rx_params_lock);
728
729 /* Disable or slow down all IR Rx circuits and counters */
730 irqenable_rx(sd, 0);
731 control_rx_enable(c, false);
732 control_rx_demodulation_enable(c, false);
733 control_rx_s_edge_detection(c, CNTRL_EDG_NONE);
734 filter_rx_s_min_width(c, 0);
735 cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD);
736
737 ir_state->rx_params.shutdown = true;
738
739 mutex_unlock(&ir_state->rx_params_lock);
740 return 0;
741}
742
743static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd,
744 struct v4l2_subdev_ir_parameters *p)
745{
746 struct cx25840_ir_state *ir_state = to_ir_state(sd);
747 struct i2c_client *c;
748 struct v4l2_subdev_ir_parameters *o;
749 u16 rxclk_divider;
750
751 if (ir_state == NULL)
752 return -ENODEV;
753
754 if (p->shutdown)
755 return cx25840_ir_rx_shutdown(sd);
756
757 if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
758 return -ENOSYS;
759
760 c = ir_state->c;
761 o = &ir_state->rx_params;
762
763 mutex_lock(&ir_state->rx_params_lock);
764
765 o->shutdown = p->shutdown;
766
767 p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
768 o->mode = p->mode;
769
770 p->bytes_per_data_element = sizeof(u32);
771 o->bytes_per_data_element = p->bytes_per_data_element;
772
773 /* Before we tweak the hardware, we have to disable the receiver */
774 irqenable_rx(sd, 0);
775 control_rx_enable(c, false);
776
777 control_rx_demodulation_enable(c, p->modulation);
778 o->modulation = p->modulation;
779
780 if (p->modulation) {
781 p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq,
782 &rxclk_divider);
783
784 o->carrier_freq = p->carrier_freq;
785
786 p->duty_cycle = 50;
787 o->duty_cycle = p->duty_cycle;
788
789 control_rx_s_carrier_window(c, p->carrier_freq,
790 &p->carrier_range_lower,
791 &p->carrier_range_upper);
792 o->carrier_range_lower = p->carrier_range_lower;
793 o->carrier_range_upper = p->carrier_range_upper;
794 } else {
795 p->max_pulse_width =
796 rxclk_rx_s_max_pulse_width(c, p->max_pulse_width,
797 &rxclk_divider);
798 o->max_pulse_width = p->max_pulse_width;
799 }
800 atomic_set(&ir_state->rxclk_divider, rxclk_divider);
801
802 p->noise_filter_min_width =
803 filter_rx_s_min_width(c, p->noise_filter_min_width);
804 o->noise_filter_min_width = p->noise_filter_min_width;
805
806 p->resolution = clock_divider_to_resolution(rxclk_divider);
807 o->resolution = p->resolution;
808
809 /* FIXME - make this dependent on resolution for better performance */
810 control_rx_irq_watermark(c, RX_FIFO_HALF_FULL);
811
812 control_rx_s_edge_detection(c, CNTRL_EDG_BOTH);
813
814 o->invert_level = p->invert_level;
815 atomic_set(&ir_state->rx_invert, p->invert_level);
816
817 o->interrupt_enable = p->interrupt_enable;
818 o->enable = p->enable;
819 if (p->enable) {
820 unsigned long flags;
821
822 spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
823 kfifo_reset(&ir_state->rx_kfifo);
824 spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
825 if (p->interrupt_enable)
826 irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
827 control_rx_enable(c, p->enable);
828 }
829
830 mutex_unlock(&ir_state->rx_params_lock);
831 return 0;
832}
833
834/* Transmitter */
835static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
836 ssize_t *num)
837{
838 struct cx25840_ir_state *ir_state = to_ir_state(sd);
839 struct i2c_client *c;
840
841 if (ir_state == NULL)
842 return -ENODEV;
843
844 c = ir_state->c;
845#if 0
846 /*
847 * FIXME - the code below is an incomplete and untested sketch of what
848 * may need to be done. The critical part is to get 4 (or 8) pulses
849 * from the tx_kfifo, or converted from ns to the proper units from the
850 * input, and push them off to the hardware Tx FIFO right away, if the
851 * HW TX fifo needs service. The rest can be pushed to the tx_kfifo in
852 * a less critical timeframe. Also watch out for overruning the
853 * tx_kfifo - don't let it happen and let the caller know not all his
854 * pulses were written.
855 */
856 u32 *ns_pulse = (u32 *) buf;
857 unsigned int n;
858 u32 fifo_pulse[FIFO_TX_DEPTH];
859 u32 mark;
860
861 /* Compute how much we can fit in the tx kfifo */
862 n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo);
863 n = min(n, (unsigned int) count);
864 n /= sizeof(u32);
865
866 /* FIXME - turn on Tx Fifo service interrupt
867 * check hardware fifo level, and other stuff
868 */
869 for (i = 0; i < n; ) {
870 for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) {
871 mark = ns_pulse[i] & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK;
872 fifo_pulse[j] = ns_to_pulse_width_count(
873 ns_pulse[i] &
874 ~V4L2_SUBDEV_IR_PULSE_LEVEL_MASK,
875 ir_state->txclk_divider);
876 if (mark)
877 fifo_pulse[j] &= FIFO_RXTX_LVL;
878 i++;
879 }
880 kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse,
881 j * sizeof(u32));
882 }
883 *num = n * sizeof(u32);
884#else
885 /* For now enable the Tx FIFO Service interrupt & pretend we did work */
886 irqenable_tx(sd, IRQEN_TSE);
887 *num = count;
888#endif
889 return 0;
890}
891
892static int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd,
893 struct v4l2_subdev_ir_parameters *p)
894{
895 struct cx25840_ir_state *ir_state = to_ir_state(sd);
896
897 if (ir_state == NULL)
898 return -ENODEV;
899
900 mutex_lock(&ir_state->tx_params_lock);
901 memcpy(p, &ir_state->tx_params,
902 sizeof(struct v4l2_subdev_ir_parameters));
903 mutex_unlock(&ir_state->tx_params_lock);
904 return 0;
905}
906
907static int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd)
908{
909 struct cx25840_ir_state *ir_state = to_ir_state(sd);
910 struct i2c_client *c;
911
912 if (ir_state == NULL)
913 return -ENODEV;
914
915 c = ir_state->c;
916 mutex_lock(&ir_state->tx_params_lock);
917
918 /* Disable or slow down all IR Tx circuits and counters */
919 irqenable_tx(sd, 0);
920 control_tx_enable(c, false);
921 control_tx_modulation_enable(c, false);
922 cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD);
923
924 ir_state->tx_params.shutdown = true;
925
926 mutex_unlock(&ir_state->tx_params_lock);
927 return 0;
928}
929
930static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd,
931 struct v4l2_subdev_ir_parameters *p)
932{
933 struct cx25840_ir_state *ir_state = to_ir_state(sd);
934 struct i2c_client *c;
935 struct v4l2_subdev_ir_parameters *o;
936 u16 txclk_divider;
937
938 if (ir_state == NULL)
939 return -ENODEV;
940
941 if (p->shutdown)
942 return cx25840_ir_tx_shutdown(sd);
943
944 if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
945 return -ENOSYS;
946
947 c = ir_state->c;
948 o = &ir_state->tx_params;
949 mutex_lock(&ir_state->tx_params_lock);
950
951 o->shutdown = p->shutdown;
952
953 p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
954 o->mode = p->mode;
955
956 p->bytes_per_data_element = sizeof(u32);
957 o->bytes_per_data_element = p->bytes_per_data_element;
958
959 /* Before we tweak the hardware, we have to disable the transmitter */
960 irqenable_tx(sd, 0);
961 control_tx_enable(c, false);
962
963 control_tx_modulation_enable(c, p->modulation);
964 o->modulation = p->modulation;
965
966 if (p->modulation) {
967 p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq,
968 &txclk_divider);
969 o->carrier_freq = p->carrier_freq;
970
971 p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle);
972 o->duty_cycle = p->duty_cycle;
973 } else {
974 p->max_pulse_width =
975 txclk_tx_s_max_pulse_width(c, p->max_pulse_width,
976 &txclk_divider);
977 o->max_pulse_width = p->max_pulse_width;
978 }
979 atomic_set(&ir_state->txclk_divider, txclk_divider);
980
981 p->resolution = clock_divider_to_resolution(txclk_divider);
982 o->resolution = p->resolution;
983
984 /* FIXME - make this dependent on resolution for better performance */
985 control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY);
986
987 control_tx_polarity_invert(c, p->invert_carrier_sense);
988 o->invert_carrier_sense = p->invert_carrier_sense;
989
990 /*
991 * FIXME: we don't have hardware help for IO pin level inversion
992 * here like we have on the CX23888.
993 * Act on this with some mix of logical inversion of data levels,
994 * carrier polarity, and carrier duty cycle.
995 */
996 o->invert_level = p->invert_level;
997
998 o->interrupt_enable = p->interrupt_enable;
999 o->enable = p->enable;
1000 if (p->enable) {
1001 /* reset tx_fifo here */
1002 if (p->interrupt_enable)
1003 irqenable_tx(sd, IRQEN_TSE);
1004 control_tx_enable(c, p->enable);
1005 }
1006
1007 mutex_unlock(&ir_state->tx_params_lock);
1008 return 0;
1009}
1010
1011
1012/*
1013 * V4L2 Subdevice Core Ops support
1014 */
1015int cx25840_ir_log_status(struct v4l2_subdev *sd)
1016{
1017 struct cx25840_state *state = to_state(sd);
1018 struct i2c_client *c = state->c;
1019 char *s;
1020 int i, j;
1021 u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr;
1022
1023 /* The CX23888 chip doesn't have an IR controller on the A/V core */
1024 if (is_cx23888(state))
1025 return 0;
1026
1027 cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
1028 txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD;
1029 rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD;
1030 cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC;
1031 stats = cx25840_read4(c, CX25840_IR_STATS_REG);
1032 irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
1033 if (is_cx23885(state) || is_cx23887(state))
1034 irqen ^= IRQEN_MSK;
1035 filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF;
1036
1037 v4l2_info(sd, "IR Receiver:\n");
1038 v4l2_info(sd, "\tEnabled: %s\n",
1039 cntrl & CNTRL_RXE ? "yes" : "no");
1040 v4l2_info(sd, "\tDemodulation from a carrier: %s\n",
1041 cntrl & CNTRL_DMD ? "enabled" : "disabled");
1042 v4l2_info(sd, "\tFIFO: %s\n",
1043 cntrl & CNTRL_RFE ? "enabled" : "disabled");
1044 switch (cntrl & CNTRL_EDG) {
1045 case CNTRL_EDG_NONE:
1046 s = "disabled";
1047 break;
1048 case CNTRL_EDG_FALL:
1049 s = "falling edge";
1050 break;
1051 case CNTRL_EDG_RISE:
1052 s = "rising edge";
1053 break;
1054 case CNTRL_EDG_BOTH:
1055 s = "rising & falling edges";
1056 break;
1057 default:
1058 s = "??? edge";
1059 break;
1060 }
1061 v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s);
1062 v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n",
1063 cntrl & CNTRL_R ? "not loaded" : "overflow marker");
1064 v4l2_info(sd, "\tFIFO interrupt watermark: %s\n",
1065 cntrl & CNTRL_RIC ? "not empty" : "half full or greater");
1066 v4l2_info(sd, "\tLoopback mode: %s\n",
1067 cntrl & CNTRL_LBM ? "loopback active" : "normal receive");
1068 if (cntrl & CNTRL_DMD) {
1069 v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n",
1070 clock_divider_to_carrier_freq(rxclk));
1071 switch (cntrl & CNTRL_WIN) {
1072 case CNTRL_WIN_3_3:
1073 i = 3;
1074 j = 3;
1075 break;
1076 case CNTRL_WIN_4_3:
1077 i = 4;
1078 j = 3;
1079 break;
1080 case CNTRL_WIN_3_4:
1081 i = 3;
1082 j = 4;
1083 break;
1084 case CNTRL_WIN_4_4:
1085 i = 4;
1086 j = 4;
1087 break;
1088 default:
1089 i = 0;
1090 j = 0;
1091 break;
1092 }
1093 v4l2_info(sd, "\tNext carrier edge window: 16 clocks "
1094 "-%1d/+%1d, %u to %u Hz\n", i, j,
1095 clock_divider_to_freq(rxclk, 16 + j),
1096 clock_divider_to_freq(rxclk, 16 - i));
1097 } else {
1098 v4l2_info(sd, "\tMax measurable pulse width: %u us, "
1099 "%llu ns\n",
1100 pulse_width_count_to_us(FIFO_RXTX, rxclk),
1101 pulse_width_count_to_ns(FIFO_RXTX, rxclk));
1102 }
1103 v4l2_info(sd, "\tLow pass filter: %s\n",
1104 filtr ? "enabled" : "disabled");
1105 if (filtr)
1106 v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, "
1107 "%u ns\n",
1108 lpf_count_to_us(filtr),
1109 lpf_count_to_ns(filtr));
1110 v4l2_info(sd, "\tPulse width timer timed-out: %s\n",
1111 stats & STATS_RTO ? "yes" : "no");
1112 v4l2_info(sd, "\tPulse width timer time-out intr: %s\n",
1113 irqen & IRQEN_RTE ? "enabled" : "disabled");
1114 v4l2_info(sd, "\tFIFO overrun: %s\n",
1115 stats & STATS_ROR ? "yes" : "no");
1116 v4l2_info(sd, "\tFIFO overrun interrupt: %s\n",
1117 irqen & IRQEN_ROE ? "enabled" : "disabled");
1118 v4l2_info(sd, "\tBusy: %s\n",
1119 stats & STATS_RBY ? "yes" : "no");
1120 v4l2_info(sd, "\tFIFO service requested: %s\n",
1121 stats & STATS_RSR ? "yes" : "no");
1122 v4l2_info(sd, "\tFIFO service request interrupt: %s\n",
1123 irqen & IRQEN_RSE ? "enabled" : "disabled");
1124
1125 v4l2_info(sd, "IR Transmitter:\n");
1126 v4l2_info(sd, "\tEnabled: %s\n",
1127 cntrl & CNTRL_TXE ? "yes" : "no");
1128 v4l2_info(sd, "\tModulation onto a carrier: %s\n",
1129 cntrl & CNTRL_MOD ? "enabled" : "disabled");
1130 v4l2_info(sd, "\tFIFO: %s\n",
1131 cntrl & CNTRL_TFE ? "enabled" : "disabled");
1132 v4l2_info(sd, "\tFIFO interrupt watermark: %s\n",
1133 cntrl & CNTRL_TIC ? "not empty" : "half full or less");
1134 v4l2_info(sd, "\tCarrier polarity: %s\n",
1135 cntrl & CNTRL_CPL ? "space:burst mark:noburst"
1136 : "space:noburst mark:burst");
1137 if (cntrl & CNTRL_MOD) {
1138 v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n",
1139 clock_divider_to_carrier_freq(txclk));
1140 v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n",
1141 cduty + 1);
1142 } else {
1143 v4l2_info(sd, "\tMax pulse width: %u us, "
1144 "%llu ns\n",
1145 pulse_width_count_to_us(FIFO_RXTX, txclk),
1146 pulse_width_count_to_ns(FIFO_RXTX, txclk));
1147 }
1148 v4l2_info(sd, "\tBusy: %s\n",
1149 stats & STATS_TBY ? "yes" : "no");
1150 v4l2_info(sd, "\tFIFO service requested: %s\n",
1151 stats & STATS_TSR ? "yes" : "no");
1152 v4l2_info(sd, "\tFIFO service request interrupt: %s\n",
1153 irqen & IRQEN_TSE ? "enabled" : "disabled");
1154
1155 return 0;
1156}
1157
1158
1159const struct v4l2_subdev_ir_ops cx25840_ir_ops = {
1160 .rx_read = cx25840_ir_rx_read,
1161 .rx_g_parameters = cx25840_ir_rx_g_parameters,
1162 .rx_s_parameters = cx25840_ir_rx_s_parameters,
1163
1164 .tx_write = cx25840_ir_tx_write,
1165 .tx_g_parameters = cx25840_ir_tx_g_parameters,
1166 .tx_s_parameters = cx25840_ir_tx_s_parameters,
1167};
1168
1169
1170static const struct v4l2_subdev_ir_parameters default_rx_params = {
1171 .bytes_per_data_element = sizeof(u32),
1172 .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
1173
1174 .enable = false,
1175 .interrupt_enable = false,
1176 .shutdown = true,
1177
1178 .modulation = true,
1179 .carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */
1180
1181 /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
1182 /* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
1183 .noise_filter_min_width = 333333, /* ns */
1184 .carrier_range_lower = 35000,
1185 .carrier_range_upper = 37000,
1186 .invert_level = false,
1187};
1188
1189static const struct v4l2_subdev_ir_parameters default_tx_params = {
1190 .bytes_per_data_element = sizeof(u32),
1191 .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
1192
1193 .enable = false,
1194 .interrupt_enable = false,
1195 .shutdown = true,
1196
1197 .modulation = true,
1198 .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
1199 .duty_cycle = 25, /* 25 % - RC-5 carrier */
1200 .invert_level = false,
1201 .invert_carrier_sense = false,
1202};
1203
1204int cx25840_ir_probe(struct v4l2_subdev *sd)
1205{
1206 struct cx25840_state *state = to_state(sd);
1207 struct cx25840_ir_state *ir_state;
1208 struct v4l2_subdev_ir_parameters default_params;
1209
1210 /* Only init the IR controller for the CX2388[57] AV Core for now */
1211 if (!(is_cx23885(state) || is_cx23887(state)))
1212 return 0;
1213
1214 ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL);
1215 if (ir_state == NULL)
1216 return -ENOMEM;
1217
1218 spin_lock_init(&ir_state->rx_kfifo_lock);
1219 if (kfifo_alloc(&ir_state->rx_kfifo,
1220 CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) {
1221 kfree(ir_state);
1222 return -ENOMEM;
1223 }
1224
1225 ir_state->c = state->c;
1226 state->ir_state = ir_state;
1227
1228 /* Ensure no interrupts arrive yet */
1229 if (is_cx23885(state) || is_cx23887(state))
1230 cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK);
1231 else
1232 cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0);
1233
1234 mutex_init(&ir_state->rx_params_lock);
1235 memcpy(&default_params, &default_rx_params,
1236 sizeof(struct v4l2_subdev_ir_parameters));
1237 v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
1238
1239 mutex_init(&ir_state->tx_params_lock);
1240 memcpy(&default_params, &default_tx_params,
1241 sizeof(struct v4l2_subdev_ir_parameters));
1242 v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
1243
1244 return 0;
1245}
1246
1247int cx25840_ir_remove(struct v4l2_subdev *sd)
1248{
1249 struct cx25840_state *state = to_state(sd);
1250 struct cx25840_ir_state *ir_state = to_ir_state(sd);
1251
1252 if (ir_state == NULL)
1253 return -ENODEV;
1254
1255 cx25840_ir_rx_shutdown(sd);
1256 cx25840_ir_tx_shutdown(sd);
1257
1258 kfifo_free(&ir_state->rx_kfifo);
1259 kfree(ir_state);
1260 state->ir_state = NULL;
1261 return 0;
1262}