aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx23885/cx23888-ir.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-09-26 22:17:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:40:16 -0500
commit29f8a0a50ac32ac4bc1937dcfdf8de6c406a5f10 (patch)
tree8a7406ebbb15dd7743543901eaeafc00708d31c5 /drivers/media/video/cx23885/cx23888-ir.c
parent74618244003a5a9e11240af8c5795ae747d9a2e0 (diff)
V4L/DVB (13086): cx23885: Add skeleton v4l2_subdev for the CX23888 integrated IR controller
This change adds a skeletal implementation of a v4l2_subdevice to provide encapsulation and abstraction of the CX23888's integrated consumer infrared controller. This change also instantiates the cx23888_ir subdev for the HVR-1850 which has IR hardware physically wired up to a CX23888. The cx23888_ir subdev code is being written with long-term objectives to: 1. port it to the cx25840 module for the CX2584x, CX2583x, CX23885, & CX231xx IR controllers 2. possibly port it to the cx18 module for the CX23418 IR controller 3. have the IR subdevice accessed abstractly in the cx23885 module, so the driver can ignore the difference between the CX23885 and CX23888. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx23885/cx23888-ir.c')
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
new file mode 100644
index 000000000000..12df0e3a2354
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -0,0 +1,233 @@
1/*
2 * Driver for the Conexant CX23885/7/8 PCIe bridge
3 *
4 * CX23888 Integrated Consumer Infrared Controller
5 *
6 * Copyright (C) 2009 Andy Walls <awalls@radix.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 <media/v4l2-device.h>
25#include <media/v4l2-chip-ident.h>
26
27#include "cx23885.h"
28
29#define CX23888_IR_REG_BASE 0x170000
30/*
31 * These CX23888 register offsets have a straightforward one to one mapping
32 * to the CX23885 register offsets of 0x200 through 0x218
33 */
34#define CX23888_IR_CNTRL_REG 0x170000
35#define CX23888_IR_TXCLK_REG 0x170004
36#define CX23888_IR_RXCLK_REG 0x170008
37#define CX23888_IR_CDUTY_REG 0x17000C
38#define CX23888_IR_STATS_REG 0x170010
39#define CX23888_IR_IRQEN_REG 0x170014
40#define CX23888_IR_FILTR_REG 0x170018
41/* This register doesn't follow the pattern; it's 0x23C on a CX23885 */
42#define CX23888_IR_FIFO_REG 0x170040
43
44/* CX23888 unique registers */
45#define CX23888_IR_SEEDP_REG 0x17001C
46#define CX23888_IR_TIMOL_REG 0x170020
47#define CX23888_IR_WAKE0_REG 0x170024
48#define CX23888_IR_WAKE1_REG 0x170028
49#define CX23888_IR_WAKE2_REG 0x17002C
50#define CX23888_IR_MASK0_REG 0x170030
51#define CX23888_IR_MASK1_REG 0x170034
52#define CX23888_IR_MAKS2_REG 0x170038
53#define CX23888_IR_DPIPG_REG 0x17003C
54#define CX23888_IR_LEARN_REG 0x170044
55
56
57struct cx23888_ir_state {
58 struct v4l2_subdev sd;
59 struct cx23885_dev *dev;
60 u32 id;
61 u32 rev;
62};
63
64static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
65{
66 return v4l2_get_subdevdata(sd);
67}
68
69static int cx23888_ir_write(struct cx23885_dev *dev, u32 addr, u8 value)
70{
71 u32 reg = (addr & ~3);
72 int shift = (addr & 3) * 8;
73 u32 x = cx_read(reg);
74
75 x = (x & ~(0xff << shift)) | ((u32)value << shift);
76 cx_write(reg, x);
77 return 0;
78}
79
80static
81inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value)
82{
83 cx_write(addr, value);
84 return 0;
85}
86
87static u8 cx23888_ir_read(struct cx23885_dev *dev, u32 addr)
88{
89 u32 x = cx_read((addr & ~3));
90 int shift = (addr & 3) * 8;
91
92 return (x >> shift) & 0xff;
93}
94
95static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr)
96{
97 return cx_read(addr);
98}
99
100static int cx23888_ir_and_or(struct cx23885_dev *dev, u32 addr,
101 unsigned and_mask, u8 or_value)
102{
103 return cx23888_ir_write(dev, addr,
104 (cx23888_ir_read(dev, addr) & and_mask) |
105 or_value);
106}
107
108static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr,
109 u32 and_mask, u32 or_value)
110{
111 cx_andor(addr, and_mask, or_value);
112 return 0;
113}
114
115static int cx23888_ir_log_status(struct v4l2_subdev *sd)
116{
117 struct cx23888_ir_state *state = to_state(sd);
118 struct cx23885_dev *dev = state->dev;
119 u8 cntrl = cx23888_ir_read(dev, CX23888_IR_CNTRL_REG+1);
120 v4l2_info(sd, "receiver %sabled\n", cntrl & 0x1 ? "en" : "dis");
121 v4l2_info(sd, "transmitter %sabled\n", cntrl & 0x2 ? "en" : "dis");
122 return 0;
123}
124
125static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match)
126{
127 return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2;
128}
129
130static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd,
131 struct v4l2_dbg_chip_ident *chip)
132{
133 struct cx23888_ir_state *state = to_state(sd);
134
135 if (cx23888_ir_dbg_match(&chip->match)) {
136 chip->ident = state->id;
137 chip->revision = state->rev;
138 }
139 return 0;
140}
141
142#ifdef CONFIG_VIDEO_ADV_DEBUG
143static int cx23888_ir_g_register(struct v4l2_subdev *sd,
144 struct v4l2_dbg_register *reg)
145{
146 struct cx23888_ir_state *state = to_state(sd);
147 u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
148
149 if (!cx23888_ir_dbg_match(&reg->match))
150 return -EINVAL;
151 if ((addr & 0x3) != 0)
152 return -EINVAL;
153 if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
154 return -EINVAL;
155 if (!capable(CAP_SYS_ADMIN))
156 return -EPERM;
157 reg->size = 4;
158 reg->val = cx23888_ir_read4(state->dev, addr);
159 return 0;
160}
161
162static int cx23888_ir_s_register(struct v4l2_subdev *sd,
163 struct v4l2_dbg_register *reg)
164{
165 struct cx23888_ir_state *state = to_state(sd);
166 u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
167
168 if (!cx23888_ir_dbg_match(&reg->match))
169 return -EINVAL;
170 if ((addr & 0x3) != 0)
171 return -EINVAL;
172 if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG)
173 return -EINVAL;
174 if (!capable(CAP_SYS_ADMIN))
175 return -EPERM;
176 cx23888_ir_write4(state->dev, addr, reg->val);
177 return 0;
178}
179#endif
180
181static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = {
182 .g_chip_ident = cx23888_ir_g_chip_ident,
183 .log_status = cx23888_ir_log_status,
184#ifdef CONFIG_VIDEO_ADV_DEBUG
185 .g_register = cx23888_ir_g_register,
186 .s_register = cx23888_ir_s_register,
187#endif
188};
189
190static const struct v4l2_subdev_ops cx23888_ir_controller_ops = {
191 .core = &cx23888_ir_core_ops,
192};
193
194int cx23888_ir_probe(struct cx23885_dev *dev)
195{
196 struct cx23888_ir_state *state;
197 struct v4l2_subdev *sd;
198
199 state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL);
200 if (state == NULL)
201 return -ENOMEM;
202
203 state->dev = dev;
204 state->id = V4L2_IDENT_CX23888_IR;
205 state->rev = 0;
206 sd = &state->sd;
207
208 v4l2_subdev_init(sd, &cx23888_ir_controller_ops);
209 v4l2_set_subdevdata(sd, state);
210 /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */
211 snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name);
212 sd->grp_id = CX23885_HW_888_IR;
213 return v4l2_device_register_subdev(&dev->v4l2_dev, sd);
214}
215
216int cx23888_ir_remove(struct cx23885_dev *dev)
217{
218 struct v4l2_subdev *sd;
219 struct cx23888_ir_state *state;
220
221 sd = cx23885_find_hw(dev, CX23885_HW_888_IR);
222 if (sd == NULL)
223 return -ENODEV;
224
225 /* Disable receiver and transmitter */
226 cx23888_ir_and_or(dev, CX23888_IR_CNTRL_REG+1, 0xfc, 0);
227
228 state = to_state(sd);
229 v4l2_device_unregister_subdev(sd);
230 kfree(state);
231 /* Nothing more to free() as state held the actual v4l2_subdev object */
232 return 0;
233}