diff options
-rw-r--r-- | drivers/media/video/cx23885/cx23888-ir.c | 1063 |
1 files changed, 1034 insertions, 29 deletions
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c index 12df0e3a2354..e8d949ae06b9 100644 --- a/drivers/media/video/cx23885/cx23888-ir.c +++ b/drivers/media/video/cx23885/cx23888-ir.c | |||
@@ -21,25 +21,79 @@ | |||
21 | * 02110-1301, USA. | 21 | * 02110-1301, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/kfifo.h> | ||
25 | |||
24 | #include <media/v4l2-device.h> | 26 | #include <media/v4l2-device.h> |
25 | #include <media/v4l2-chip-ident.h> | 27 | #include <media/v4l2-chip-ident.h> |
26 | 28 | ||
27 | #include "cx23885.h" | 29 | #include "cx23885.h" |
28 | 30 | ||
31 | static unsigned int ir_888_debug; | ||
32 | module_param(ir_888_debug, int, 0644); | ||
33 | MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]"); | ||
34 | |||
29 | #define CX23888_IR_REG_BASE 0x170000 | 35 | #define CX23888_IR_REG_BASE 0x170000 |
30 | /* | 36 | /* |
31 | * These CX23888 register offsets have a straightforward one to one mapping | 37 | * These CX23888 register offsets have a straightforward one to one mapping |
32 | * to the CX23885 register offsets of 0x200 through 0x218 | 38 | * to the CX23885 register offsets of 0x200 through 0x218 |
33 | */ | 39 | */ |
34 | #define CX23888_IR_CNTRL_REG 0x170000 | 40 | #define CX23888_IR_CNTRL_REG 0x170000 |
41 | #define CNTRL_WIN_3_3 0x00000000 | ||
42 | #define CNTRL_WIN_4_3 0x00000001 | ||
43 | #define CNTRL_WIN_3_4 0x00000002 | ||
44 | #define CNTRL_WIN_4_4 0x00000003 | ||
45 | #define CNTRL_WIN 0x00000003 | ||
46 | #define CNTRL_EDG_NONE 0x00000000 | ||
47 | #define CNTRL_EDG_FALL 0x00000004 | ||
48 | #define CNTRL_EDG_RISE 0x00000008 | ||
49 | #define CNTRL_EDG_BOTH 0x0000000C | ||
50 | #define CNTRL_EDG 0x0000000C | ||
51 | #define CNTRL_DMD 0x00000010 | ||
52 | #define CNTRL_MOD 0x00000020 | ||
53 | #define CNTRL_RFE 0x00000040 | ||
54 | #define CNTRL_TFE 0x00000080 | ||
55 | #define CNTRL_RXE 0x00000100 | ||
56 | #define CNTRL_TXE 0x00000200 | ||
57 | #define CNTRL_RIC 0x00000400 | ||
58 | #define CNTRL_TIC 0x00000800 | ||
59 | #define CNTRL_CPL 0x00001000 | ||
60 | #define CNTRL_LBM 0x00002000 | ||
61 | #define CNTRL_R 0x00004000 | ||
62 | |||
35 | #define CX23888_IR_TXCLK_REG 0x170004 | 63 | #define CX23888_IR_TXCLK_REG 0x170004 |
64 | #define TXCLK_TCD 0x0000FFFF | ||
65 | |||
36 | #define CX23888_IR_RXCLK_REG 0x170008 | 66 | #define CX23888_IR_RXCLK_REG 0x170008 |
67 | #define RXCLK_RCD 0x0000FFFF | ||
68 | |||
37 | #define CX23888_IR_CDUTY_REG 0x17000C | 69 | #define CX23888_IR_CDUTY_REG 0x17000C |
70 | #define CDUTY_CDC 0x0000000F | ||
71 | |||
38 | #define CX23888_IR_STATS_REG 0x170010 | 72 | #define CX23888_IR_STATS_REG 0x170010 |
73 | #define STATS_RTO 0x00000001 | ||
74 | #define STATS_ROR 0x00000002 | ||
75 | #define STATS_RBY 0x00000004 | ||
76 | #define STATS_TBY 0x00000008 | ||
77 | #define STATS_RSR 0x00000010 | ||
78 | #define STATS_TSR 0x00000020 | ||
79 | |||
39 | #define CX23888_IR_IRQEN_REG 0x170014 | 80 | #define CX23888_IR_IRQEN_REG 0x170014 |
81 | #define IRQEN_RTE 0x00000001 | ||
82 | #define IRQEN_ROE 0x00000002 | ||
83 | #define IRQEN_RSE 0x00000010 | ||
84 | #define IRQEN_TSE 0x00000020 | ||
85 | |||
40 | #define CX23888_IR_FILTR_REG 0x170018 | 86 | #define CX23888_IR_FILTR_REG 0x170018 |
87 | #define FILTR_LPF 0x0000FFFF | ||
88 | |||
41 | /* This register doesn't follow the pattern; it's 0x23C on a CX23885 */ | 89 | /* This register doesn't follow the pattern; it's 0x23C on a CX23885 */ |
42 | #define CX23888_IR_FIFO_REG 0x170040 | 90 | #define CX23888_IR_FIFO_REG 0x170040 |
91 | #define FIFO_RXTX 0x0000FFFF | ||
92 | #define FIFO_RXTX_LVL 0x00010000 | ||
93 | #define FIFO_RXTX_RTO 0x0001FFFF | ||
94 | #define FIFO_RX_NDV 0x00020000 | ||
95 | #define FIFO_RX_DEPTH 8 | ||
96 | #define FIFO_TX_DEPTH 8 | ||
43 | 97 | ||
44 | /* CX23888 unique registers */ | 98 | /* CX23888 unique registers */ |
45 | #define CX23888_IR_SEEDP_REG 0x17001C | 99 | #define CX23888_IR_SEEDP_REG 0x17001C |
@@ -53,12 +107,32 @@ | |||
53 | #define CX23888_IR_DPIPG_REG 0x17003C | 107 | #define CX23888_IR_DPIPG_REG 0x17003C |
54 | #define CX23888_IR_LEARN_REG 0x170044 | 108 | #define CX23888_IR_LEARN_REG 0x170044 |
55 | 109 | ||
110 | #define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ | ||
111 | #define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ/2) | ||
112 | |||
113 | #define CX23888_IR_RX_KFIFO_SIZE (512 * sizeof(u32)) | ||
114 | #define CX23888_IR_TX_KFIFO_SIZE (512 * sizeof(u32)) | ||
56 | 115 | ||
57 | struct cx23888_ir_state { | 116 | struct cx23888_ir_state { |
58 | struct v4l2_subdev sd; | 117 | struct v4l2_subdev sd; |
59 | struct cx23885_dev *dev; | 118 | struct cx23885_dev *dev; |
60 | u32 id; | 119 | u32 id; |
61 | u32 rev; | 120 | u32 rev; |
121 | |||
122 | struct v4l2_subdev_ir_parameters rx_params; | ||
123 | struct mutex rx_params_lock; | ||
124 | atomic_t rxclk_divider; | ||
125 | atomic_t rx_invert; | ||
126 | |||
127 | struct kfifo *rx_kfifo; | ||
128 | spinlock_t rx_kfifo_lock; | ||
129 | |||
130 | struct v4l2_subdev_ir_parameters tx_params; | ||
131 | struct mutex tx_params_lock; | ||
132 | atomic_t txclk_divider; | ||
133 | |||
134 | struct kfifo *tx_kfifo; | ||
135 | spinlock_t tx_kfifo_lock; | ||
62 | }; | 136 | }; |
63 | 137 | ||
64 | static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) | 138 | static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) |
@@ -66,59 +140,903 @@ static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) | |||
66 | return v4l2_get_subdevdata(sd); | 140 | return v4l2_get_subdevdata(sd); |
67 | } | 141 | } |
68 | 142 | ||
69 | static int cx23888_ir_write(struct cx23885_dev *dev, u32 addr, u8 value) | 143 | /* |
144 | * IR register block read and write functions | ||
145 | */ | ||
146 | static | ||
147 | inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value) | ||
70 | { | 148 | { |
71 | u32 reg = (addr & ~3); | 149 | cx_write(addr, value); |
72 | int shift = (addr & 3) * 8; | 150 | return 0; |
73 | u32 x = cx_read(reg); | 151 | } |
152 | |||
153 | static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr) | ||
154 | { | ||
155 | return cx_read(addr); | ||
156 | } | ||
74 | 157 | ||
75 | x = (x & ~(0xff << shift)) | ((u32)value << shift); | 158 | static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr, |
76 | cx_write(reg, x); | 159 | u32 and_mask, u32 or_value) |
160 | { | ||
161 | cx_andor(addr, ~and_mask, or_value); | ||
77 | return 0; | 162 | return 0; |
78 | } | 163 | } |
79 | 164 | ||
80 | static | 165 | /* |
81 | inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value) | 166 | * Rx and Tx Clock Divider register computations |
167 | * | ||
168 | * Note the largest clock divider value of 0xffff corresponds to: | ||
169 | * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns | ||
170 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
171 | */ | ||
172 | static inline u16 count_to_clock_divider(unsigned int d) | ||
82 | { | 173 | { |
83 | cx_write(addr, value); | 174 | if (d > RXCLK_RCD+1) |
175 | d = RXCLK_RCD; | ||
176 | else if (d < 2) | ||
177 | d = 1; | ||
178 | else | ||
179 | d--; | ||
180 | return (u16) d; | ||
181 | } | ||
182 | |||
183 | static inline u16 ns_to_clock_divider(unsigned int ns) | ||
184 | { | ||
185 | return count_to_clock_divider( | ||
186 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ/1000000 * ns, 1000)); | ||
187 | } | ||
188 | |||
189 | static inline unsigned int clock_divider_to_ns(unsigned int divider) | ||
190 | { | ||
191 | /* Period of the Rx or Tx clock in ns */ | ||
192 | return DIV_ROUND_CLOSEST((divider + 1) * 1000, | ||
193 | CX23888_IR_REFCLK_FREQ/1000000); | ||
194 | } | ||
195 | |||
196 | static inline u16 carrier_freq_to_clock_divider(unsigned int freq) | ||
197 | { | ||
198 | return count_to_clock_divider( | ||
199 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16)); | ||
200 | } | ||
201 | |||
202 | static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) | ||
203 | { | ||
204 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); | ||
205 | } | ||
206 | |||
207 | static inline u16 freq_to_clock_divider(unsigned int freq, | ||
208 | unsigned int rollovers) | ||
209 | { | ||
210 | return count_to_clock_divider( | ||
211 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers)); | ||
212 | } | ||
213 | |||
214 | static inline unsigned int clock_divider_to_freq(unsigned int divider, | ||
215 | unsigned int rollovers) | ||
216 | { | ||
217 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, | ||
218 | (divider + 1) * rollovers); | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * Low Pass Filter register calculations | ||
223 | * | ||
224 | * Note the largest count value of 0xffff corresponds to: | ||
225 | * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns | ||
226 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
227 | */ | ||
228 | static inline u16 count_to_lpf_count(unsigned int d) | ||
229 | { | ||
230 | if (d > FILTR_LPF) | ||
231 | d = FILTR_LPF; | ||
232 | else if (d < 4) | ||
233 | d = 0; | ||
234 | return (u16) d; | ||
235 | } | ||
236 | |||
237 | static inline u16 ns_to_lpf_count(unsigned int ns) | ||
238 | { | ||
239 | return count_to_lpf_count( | ||
240 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ/1000000 * ns, 1000)); | ||
241 | } | ||
242 | |||
243 | static inline unsigned int lpf_count_to_ns(unsigned int count) | ||
244 | { | ||
245 | /* Duration of the Low Pass Filter rejection window in ns */ | ||
246 | return DIV_ROUND_CLOSEST(count * 1000, CX23888_IR_REFCLK_FREQ/1000000); | ||
247 | } | ||
248 | |||
249 | static inline unsigned int lpf_count_to_us(unsigned int count) | ||
250 | { | ||
251 | /* Duration of the Low Pass Filter rejection window in us */ | ||
252 | return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ/1000000); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * FIFO register pulse width count compuations | ||
257 | */ | ||
258 | static u32 clock_divider_to_resolution(u16 divider) | ||
259 | { | ||
260 | /* | ||
261 | * Resolution is the duration of 1 tick of the readable portion of | ||
262 | * of the pulse width counter as read from the FIFO. The two lsb's are | ||
263 | * not readable, hence the << 2. This function returns ns. | ||
264 | */ | ||
265 | return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, | ||
266 | CX23888_IR_REFCLK_FREQ/1000000); | ||
267 | } | ||
268 | |||
269 | static u64 pulse_width_count_to_ns(u16 count, u16 divider) | ||
270 | { | ||
271 | u64 n; | ||
272 | u32 rem; | ||
273 | |||
274 | /* | ||
275 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
276 | * the (count << 2) | 0x3 | ||
277 | */ | ||
278 | n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ | ||
279 | rem = do_div(n, CX23888_IR_REFCLK_FREQ/1000000); /* / MHz => ns */ | ||
280 | if (rem >= CX23888_IR_REFCLK_FREQ/1000000/2) | ||
281 | n++; | ||
282 | return n; | ||
283 | } | ||
284 | |||
285 | static unsigned int pulse_width_count_to_us(u16 count, u16 divider) | ||
286 | { | ||
287 | u64 n; | ||
288 | u32 rem; | ||
289 | |||
290 | /* | ||
291 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
292 | * the (count << 2) | 0x3 | ||
293 | */ | ||
294 | n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ | ||
295 | rem = do_div(n, CX23888_IR_REFCLK_FREQ/1000000); /* / MHz => us */ | ||
296 | if (rem >= CX23888_IR_REFCLK_FREQ/1000000/2) | ||
297 | n++; | ||
298 | return (unsigned int) n; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts | ||
303 | * | ||
304 | * The total pulse clock count is an 18 bit pulse width timer count as the most | ||
305 | * significant part and (up to) 16 bit clock divider count as a modulus. | ||
306 | * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse | ||
307 | * width timer count's least significant bit. | ||
308 | */ | ||
309 | static u64 ns_to_pulse_clocks(u32 ns) | ||
310 | { | ||
311 | u64 clocks; | ||
312 | u32 rem; | ||
313 | clocks = CX23888_IR_REFCLK_FREQ/1000000 * (u64) ns; /* millicycles */ | ||
314 | rem = do_div(clocks, 1000); /* /1000 = cycles */ | ||
315 | if (rem >= 1000/2) | ||
316 | clocks++; | ||
317 | return clocks; | ||
318 | } | ||
319 | |||
320 | static u16 pulse_clocks_to_clock_divider(u64 count) | ||
321 | { | ||
322 | u32 rem; | ||
323 | |||
324 | rem = do_div(count, (FIFO_RXTX << 2) | 0x3); | ||
325 | |||
326 | /* net result needs to be rounded down and decremented by 1 */ | ||
327 | if (count > RXCLK_RCD+1) | ||
328 | count = RXCLK_RCD; | ||
329 | else if (count < 2) | ||
330 | count = 1; | ||
331 | else | ||
332 | count--; | ||
333 | return (u16) count; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * IR Control Register helpers | ||
338 | */ | ||
339 | enum tx_fifo_watermark { | ||
340 | TX_FIFO_HALF_EMPTY = 0, | ||
341 | TX_FIFO_EMPTY = CNTRL_TIC, | ||
342 | }; | ||
343 | |||
344 | enum rx_fifo_watermark { | ||
345 | RX_FIFO_HALF_FULL = 0, | ||
346 | RX_FIFO_NOT_EMPTY = CNTRL_RIC, | ||
347 | }; | ||
348 | |||
349 | static inline void control_tx_irq_watermark(struct cx23885_dev *dev, | ||
350 | enum tx_fifo_watermark level) | ||
351 | { | ||
352 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level); | ||
353 | } | ||
354 | |||
355 | static inline void control_rx_irq_watermark(struct cx23885_dev *dev, | ||
356 | enum rx_fifo_watermark level) | ||
357 | { | ||
358 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level); | ||
359 | } | ||
360 | |||
361 | static inline void control_tx_enable(struct cx23885_dev *dev, bool enable) | ||
362 | { | ||
363 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), | ||
364 | enable ? (CNTRL_TXE | CNTRL_TFE) : 0); | ||
365 | } | ||
366 | |||
367 | static inline void control_rx_enable(struct cx23885_dev *dev, bool enable) | ||
368 | { | ||
369 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), | ||
370 | enable ? (CNTRL_RXE | CNTRL_RFE) : 0); | ||
371 | } | ||
372 | |||
373 | static inline void control_tx_modulation_enable(struct cx23885_dev *dev, | ||
374 | bool enable) | ||
375 | { | ||
376 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD, | ||
377 | enable ? CNTRL_MOD : 0); | ||
378 | } | ||
379 | |||
380 | static inline void control_rx_demodulation_enable(struct cx23885_dev *dev, | ||
381 | bool enable) | ||
382 | { | ||
383 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD, | ||
384 | enable ? CNTRL_DMD : 0); | ||
385 | } | ||
386 | |||
387 | static inline void control_rx_s_edge_detection(struct cx23885_dev *dev, | ||
388 | u32 edge_types) | ||
389 | { | ||
390 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, | ||
391 | edge_types & CNTRL_EDG_BOTH); | ||
392 | } | ||
393 | |||
394 | static void control_rx_s_carrier_window(struct cx23885_dev *dev, | ||
395 | unsigned int carrier, | ||
396 | unsigned int *carrier_range_low, | ||
397 | unsigned int *carrier_range_high) | ||
398 | { | ||
399 | u32 v; | ||
400 | unsigned int c16 = carrier * 16; | ||
401 | |||
402 | if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { | ||
403 | v = CNTRL_WIN_3_4; | ||
404 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); | ||
405 | } else { | ||
406 | v = CNTRL_WIN_3_3; | ||
407 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); | ||
408 | } | ||
409 | |||
410 | if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { | ||
411 | v |= CNTRL_WIN_4_3; | ||
412 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); | ||
413 | } else { | ||
414 | v |= CNTRL_WIN_3_3; | ||
415 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); | ||
416 | } | ||
417 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v); | ||
418 | } | ||
419 | |||
420 | static inline void control_tx_polarity_invert(struct cx23885_dev *dev, | ||
421 | bool invert) | ||
422 | { | ||
423 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL, | ||
424 | invert ? CNTRL_CPL : 0); | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * IR Rx & Tx Clock Register helpers | ||
429 | */ | ||
430 | static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev, | ||
431 | unsigned int freq, | ||
432 | u16 *divider) | ||
433 | { | ||
434 | *divider = carrier_freq_to_clock_divider(freq); | ||
435 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
436 | return clock_divider_to_carrier_freq(*divider); | ||
437 | } | ||
438 | |||
439 | static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev, | ||
440 | unsigned int freq, | ||
441 | u16 *divider) | ||
442 | { | ||
443 | *divider = carrier_freq_to_clock_divider(freq); | ||
444 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
445 | return clock_divider_to_carrier_freq(*divider); | ||
446 | } | ||
447 | |||
448 | static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
449 | u16 *divider) | ||
450 | { | ||
451 | u64 pulse_clocks; | ||
452 | |||
453 | if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS) | ||
454 | ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; | ||
455 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
456 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
457 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
458 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
459 | } | ||
460 | |||
461 | static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
462 | u16 *divider) | ||
463 | { | ||
464 | u64 pulse_clocks; | ||
465 | |||
466 | if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS) | ||
467 | ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; | ||
468 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
469 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
470 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
471 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * IR Tx Carrier Duty Cycle register helpers | ||
476 | */ | ||
477 | static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev, | ||
478 | unsigned int duty_cycle) | ||
479 | { | ||
480 | u32 n; | ||
481 | n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ | ||
482 | if (n != 0) | ||
483 | n--; | ||
484 | if (n > 15) | ||
485 | n = 15; | ||
486 | cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n); | ||
487 | return DIV_ROUND_CLOSEST((n+1) * 100, 16); | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * IR Filter Register helpers | ||
492 | */ | ||
493 | static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns) | ||
494 | { | ||
495 | u32 count = ns_to_lpf_count(min_width_ns); | ||
496 | cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count); | ||
497 | return lpf_count_to_ns(count); | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * IR IRQ Enable Register helpers | ||
502 | */ | ||
503 | static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask) | ||
504 | { | ||
505 | mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); | ||
506 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, | ||
507 | ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); | ||
508 | } | ||
509 | |||
510 | static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask) | ||
511 | { | ||
512 | mask &= IRQEN_TSE; | ||
513 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask); | ||
514 | } | ||
515 | |||
516 | /* | ||
517 | * V4L2 Subdevice IR Ops | ||
518 | */ | ||
519 | static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, | ||
520 | bool *handled) | ||
521 | { | ||
522 | struct cx23888_ir_state *state = to_state(sd); | ||
523 | struct cx23885_dev *dev = state->dev; | ||
524 | |||
525 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
526 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
527 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
528 | |||
529 | u32 rx_data[FIFO_RX_DEPTH]; | ||
530 | int i, j, k; | ||
531 | u32 events, v; | ||
532 | int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; | ||
533 | |||
534 | tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ | ||
535 | rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ | ||
536 | rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ | ||
537 | ror = stats & STATS_ROR; /* Rx FIFO Over Run */ | ||
538 | |||
539 | tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ | ||
540 | rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ | ||
541 | rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ | ||
542 | roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ | ||
543 | |||
544 | *handled = false; | ||
545 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Status: %s %s %s %s %s %s\n", | ||
546 | tsr ? "tsr" : " ", rsr ? "rsr" : " ", | ||
547 | rto ? "rto" : " ", ror ? "ror" : " ", | ||
548 | stats & STATS_TBY ? "tby" : " ", | ||
549 | stats & STATS_RBY ? "rby" : " "); | ||
550 | |||
551 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n", | ||
552 | tse ? "tse" : " ", rse ? "rse" : " ", | ||
553 | rte ? "rte" : " ", roe ? "roe" : " "); | ||
554 | |||
555 | /* | ||
556 | * Transmitter interrupt service | ||
557 | */ | ||
558 | if (tse && tsr) { | ||
559 | /* | ||
560 | * TODO: | ||
561 | * Check the watermark threshold setting | ||
562 | * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo | ||
563 | * Push the data to the hardware FIFO. | ||
564 | * If there was nothing more to send in the tx_kfifo, disable | ||
565 | * the TSR IRQ and notify the v4l2_device. | ||
566 | * If there was something in the tx_kfifo, check the tx_kfifo | ||
567 | * level and notify the v4l2_device, if it is low. | ||
568 | */ | ||
569 | /* For now, inhibit TSR interrupt until Tx is implemented */ | ||
570 | irqenable_tx(dev, 0); | ||
571 | events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
572 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); | ||
573 | *handled = true; | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * Receiver interrupt service | ||
578 | */ | ||
579 | kror = 0; | ||
580 | if ((rse && rsr) || (rte && rto)) { | ||
581 | /* | ||
582 | * Receive data on RSR to clear the STATS_RSR. | ||
583 | * Receive data on RTO, since we may not have yet hit the RSR | ||
584 | * watermark when we receive the RTO. | ||
585 | */ | ||
586 | for (i = 0, v = FIFO_RX_NDV; | ||
587 | (v & FIFO_RX_NDV) && !kror; i = 0) { | ||
588 | for (j = 0; | ||
589 | (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { | ||
590 | v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG); | ||
591 | rx_data[i++] = v & ~FIFO_RX_NDV; | ||
592 | } | ||
593 | if (i == 0) | ||
594 | break; | ||
595 | j = i * sizeof(u32); | ||
596 | k = kfifo_put(state->rx_kfifo, | ||
597 | (unsigned char *) rx_data, j); | ||
598 | if (k != j) | ||
599 | kror++; /* rx_kfifo over run */ | ||
600 | } | ||
601 | *handled = true; | ||
602 | } | ||
603 | |||
604 | events = 0; | ||
605 | v = 0; | ||
606 | if (kror) { | ||
607 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
608 | v4l2_err(sd, "IR receiver software FIFO overrun\n"); | ||
609 | } | ||
610 | if (roe && ror) { | ||
611 | /* | ||
612 | * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear | ||
613 | * the Rx FIFO Over Run status (STATS_ROR) | ||
614 | */ | ||
615 | v |= CNTRL_RFE; | ||
616 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
617 | v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); | ||
618 | } | ||
619 | if (rte && rto) { | ||
620 | /* | ||
621 | * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear | ||
622 | * the Rx Pulse Width Timer Time Out (STATS_RTO) | ||
623 | */ | ||
624 | v |= CNTRL_RXE; | ||
625 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
626 | } | ||
627 | if (v) { | ||
628 | /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ | ||
629 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); | ||
630 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); | ||
631 | *handled = true; | ||
632 | } | ||
633 | if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE/2) | ||
634 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
635 | |||
636 | if (events) | ||
637 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); | ||
84 | return 0; | 638 | return 0; |
85 | } | 639 | } |
86 | 640 | ||
87 | static u8 cx23888_ir_read(struct cx23885_dev *dev, u32 addr) | 641 | /* Receiver */ |
642 | static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
643 | ssize_t *num) | ||
88 | { | 644 | { |
89 | u32 x = cx_read((addr & ~3)); | 645 | struct cx23888_ir_state *state = to_state(sd); |
90 | int shift = (addr & 3) * 8; | 646 | bool invert = (bool) atomic_read(&state->rx_invert); |
647 | u16 divider = (u16) atomic_read(&state->rxclk_divider); | ||
648 | |||
649 | unsigned int i, n; | ||
650 | u32 *p; | ||
651 | u32 u, v; | ||
652 | |||
653 | n = count / sizeof(u32) * sizeof(u32); | ||
654 | if (n == 0) { | ||
655 | *num = 0; | ||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | n = kfifo_get(state->rx_kfifo, buf, n); | ||
660 | |||
661 | n /= sizeof(u32); | ||
662 | *num = n * sizeof(u32); | ||
663 | |||
664 | for (p = (u32 *) buf, i = 0; i < n; p++, i++) { | ||
665 | if ((*p & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { | ||
666 | *p = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; | ||
667 | v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); | ||
668 | continue; | ||
669 | } | ||
670 | |||
671 | u = (*p & FIFO_RXTX_LVL) ? V4L2_SUBDEV_IR_PULSE_LEVEL_MASK : 0; | ||
672 | if (invert) | ||
673 | u = u ? 0 : V4L2_SUBDEV_IR_PULSE_LEVEL_MASK; | ||
91 | 674 | ||
92 | return (x >> shift) & 0xff; | 675 | v = (u32) pulse_width_count_to_ns((u16) (*p & FIFO_RXTX), |
676 | divider); | ||
677 | if (v >= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS) | ||
678 | v = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS - 1; | ||
679 | |||
680 | *p = u | v; | ||
681 | |||
682 | v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", | ||
683 | v, u ? "mark" : "space"); | ||
684 | } | ||
685 | return 0; | ||
93 | } | 686 | } |
94 | 687 | ||
95 | static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr) | 688 | static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd, |
689 | struct v4l2_subdev_ir_parameters *p) | ||
96 | { | 690 | { |
97 | return cx_read(addr); | 691 | struct cx23888_ir_state *state = to_state(sd); |
692 | mutex_lock(&state->rx_params_lock); | ||
693 | memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
694 | mutex_unlock(&state->rx_params_lock); | ||
695 | return 0; | ||
98 | } | 696 | } |
99 | 697 | ||
100 | static int cx23888_ir_and_or(struct cx23885_dev *dev, u32 addr, | 698 | static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd) |
101 | unsigned and_mask, u8 or_value) | ||
102 | { | 699 | { |
103 | return cx23888_ir_write(dev, addr, | 700 | struct cx23888_ir_state *state = to_state(sd); |
104 | (cx23888_ir_read(dev, addr) & and_mask) | | 701 | struct cx23885_dev *dev = state->dev; |
105 | or_value); | 702 | |
703 | mutex_lock(&state->rx_params_lock); | ||
704 | |||
705 | /* Disable or slow down all IR Rx circuits and counters */ | ||
706 | irqenable_rx(dev, 0); | ||
707 | control_rx_enable(dev, false); | ||
708 | control_rx_demodulation_enable(dev, false); | ||
709 | control_rx_s_edge_detection(dev, CNTRL_EDG_NONE); | ||
710 | filter_rx_s_min_width(dev, 0); | ||
711 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD); | ||
712 | |||
713 | state->rx_params.shutdown = true; | ||
714 | |||
715 | mutex_unlock(&state->rx_params_lock); | ||
716 | return 0; | ||
106 | } | 717 | } |
107 | 718 | ||
108 | static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr, | 719 | static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, |
109 | u32 and_mask, u32 or_value) | 720 | struct v4l2_subdev_ir_parameters *p) |
110 | { | 721 | { |
111 | cx_andor(addr, and_mask, or_value); | 722 | struct cx23888_ir_state *state = to_state(sd); |
723 | struct cx23885_dev *dev = state->dev; | ||
724 | struct v4l2_subdev_ir_parameters *o = &state->rx_params; | ||
725 | u16 rxclk_divider; | ||
726 | |||
727 | if (p->shutdown) | ||
728 | return cx23888_ir_rx_shutdown(sd); | ||
729 | |||
730 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
731 | return -ENOSYS; | ||
732 | |||
733 | mutex_lock(&state->rx_params_lock); | ||
734 | |||
735 | o->shutdown = p->shutdown; | ||
736 | |||
737 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
738 | |||
739 | o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32); | ||
740 | |||
741 | /* Before we tweak the hardware, we have to disable the receiver */ | ||
742 | irqenable_rx(dev, 0); | ||
743 | control_rx_enable(dev, false); | ||
744 | |||
745 | control_rx_demodulation_enable(dev, p->modulation); | ||
746 | o->modulation = p->modulation; | ||
747 | |||
748 | if (p->modulation) { | ||
749 | p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq, | ||
750 | &rxclk_divider); | ||
751 | |||
752 | o->carrier_freq = p->carrier_freq; | ||
753 | |||
754 | o->duty_cycle = p->duty_cycle = 50; | ||
755 | |||
756 | control_rx_s_carrier_window(dev, p->carrier_freq, | ||
757 | &p->carrier_range_lower, | ||
758 | &p->carrier_range_upper); | ||
759 | o->carrier_range_lower = p->carrier_range_lower; | ||
760 | o->carrier_range_upper = p->carrier_range_upper; | ||
761 | } else { | ||
762 | p->max_pulse_width = | ||
763 | rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width, | ||
764 | &rxclk_divider); | ||
765 | o->max_pulse_width = p->max_pulse_width; | ||
766 | } | ||
767 | atomic_set(&state->rxclk_divider, rxclk_divider); | ||
768 | |||
769 | p->noise_filter_min_width = | ||
770 | filter_rx_s_min_width(dev, p->noise_filter_min_width); | ||
771 | o->noise_filter_min_width = p->noise_filter_min_width; | ||
772 | |||
773 | p->resolution = clock_divider_to_resolution(rxclk_divider); | ||
774 | o->resolution = p->resolution; | ||
775 | |||
776 | /* FIXME - make this dependent on resolution for better performance */ | ||
777 | control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL); | ||
778 | |||
779 | control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH); | ||
780 | |||
781 | o->invert = p->invert; | ||
782 | atomic_set(&state->rx_invert, p->invert); | ||
783 | |||
784 | o->interrupt_enable = p->interrupt_enable; | ||
785 | o->enable = p->enable; | ||
786 | if (p->enable) { | ||
787 | kfifo_reset(state->rx_kfifo); | ||
788 | if (p->interrupt_enable) | ||
789 | irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); | ||
790 | control_rx_enable(dev, p->enable); | ||
791 | } | ||
792 | |||
793 | mutex_unlock(&state->rx_params_lock); | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | /* Transmitter */ | ||
798 | static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
799 | ssize_t *num) | ||
800 | { | ||
801 | struct cx23888_ir_state *state = to_state(sd); | ||
802 | struct cx23885_dev *dev = state->dev; | ||
803 | /* For now enable the Tx FIFO Service interrupt & pretend we did work */ | ||
804 | irqenable_tx(dev, IRQEN_TSE); | ||
805 | *num = count; | ||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd, | ||
810 | struct v4l2_subdev_ir_parameters *p) | ||
811 | { | ||
812 | struct cx23888_ir_state *state = to_state(sd); | ||
813 | mutex_lock(&state->tx_params_lock); | ||
814 | memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
815 | mutex_unlock(&state->tx_params_lock); | ||
112 | return 0; | 816 | return 0; |
113 | } | 817 | } |
114 | 818 | ||
819 | static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd) | ||
820 | { | ||
821 | struct cx23888_ir_state *state = to_state(sd); | ||
822 | struct cx23885_dev *dev = state->dev; | ||
823 | |||
824 | mutex_lock(&state->tx_params_lock); | ||
825 | |||
826 | /* Disable or slow down all IR Tx circuits and counters */ | ||
827 | irqenable_tx(dev, 0); | ||
828 | control_tx_enable(dev, false); | ||
829 | control_tx_modulation_enable(dev, false); | ||
830 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD); | ||
831 | |||
832 | state->tx_params.shutdown = true; | ||
833 | |||
834 | mutex_unlock(&state->tx_params_lock); | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, | ||
839 | struct v4l2_subdev_ir_parameters *p) | ||
840 | { | ||
841 | struct cx23888_ir_state *state = to_state(sd); | ||
842 | struct cx23885_dev *dev = state->dev; | ||
843 | struct v4l2_subdev_ir_parameters *o = &state->tx_params; | ||
844 | u16 txclk_divider; | ||
845 | |||
846 | if (p->shutdown) | ||
847 | return cx23888_ir_tx_shutdown(sd); | ||
848 | |||
849 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
850 | return -ENOSYS; | ||
851 | |||
852 | mutex_lock(&state->tx_params_lock); | ||
853 | |||
854 | o->shutdown = p->shutdown; | ||
855 | |||
856 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
857 | |||
858 | o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32); | ||
859 | |||
860 | /* Before we tweak the hardware, we have to disable the transmitter */ | ||
861 | irqenable_tx(dev, 0); | ||
862 | control_tx_enable(dev, false); | ||
863 | |||
864 | control_tx_modulation_enable(dev, p->modulation); | ||
865 | o->modulation = p->modulation; | ||
866 | |||
867 | if (p->modulation) { | ||
868 | p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq, | ||
869 | &txclk_divider); | ||
870 | o->carrier_freq = p->carrier_freq; | ||
871 | |||
872 | p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle); | ||
873 | o->duty_cycle = p->duty_cycle; | ||
874 | } else { | ||
875 | p->max_pulse_width = | ||
876 | txclk_tx_s_max_pulse_width(dev, p->max_pulse_width, | ||
877 | &txclk_divider); | ||
878 | o->max_pulse_width = p->max_pulse_width; | ||
879 | } | ||
880 | atomic_set(&state->txclk_divider, txclk_divider); | ||
881 | |||
882 | p->resolution = clock_divider_to_resolution(txclk_divider); | ||
883 | o->resolution = p->resolution; | ||
884 | |||
885 | /* FIXME - make this dependent on resolution for better performance */ | ||
886 | control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY); | ||
887 | |||
888 | control_tx_polarity_invert(dev, p->invert); | ||
889 | o->invert = p->invert; | ||
890 | |||
891 | o->interrupt_enable = p->interrupt_enable; | ||
892 | o->enable = p->enable; | ||
893 | if (p->enable) { | ||
894 | kfifo_reset(state->tx_kfifo); | ||
895 | if (p->interrupt_enable) | ||
896 | irqenable_tx(dev, IRQEN_TSE); | ||
897 | control_tx_enable(dev, p->enable); | ||
898 | } | ||
899 | |||
900 | mutex_unlock(&state->tx_params_lock); | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | |||
905 | /* | ||
906 | * V4L2 Subdevice Core Ops | ||
907 | */ | ||
115 | static int cx23888_ir_log_status(struct v4l2_subdev *sd) | 908 | static int cx23888_ir_log_status(struct v4l2_subdev *sd) |
116 | { | 909 | { |
117 | struct cx23888_ir_state *state = to_state(sd); | 910 | struct cx23888_ir_state *state = to_state(sd); |
118 | struct cx23885_dev *dev = state->dev; | 911 | struct cx23885_dev *dev = state->dev; |
119 | u8 cntrl = cx23888_ir_read(dev, CX23888_IR_CNTRL_REG+1); | 912 | char *s; |
120 | v4l2_info(sd, "receiver %sabled\n", cntrl & 0x1 ? "en" : "dis"); | 913 | int i, j; |
121 | v4l2_info(sd, "transmitter %sabled\n", cntrl & 0x2 ? "en" : "dis"); | 914 | |
915 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
916 | u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD; | ||
917 | u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD; | ||
918 | u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC; | ||
919 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
920 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
921 | u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF; | ||
922 | |||
923 | v4l2_info(sd, "IR Receiver:\n"); | ||
924 | v4l2_info(sd, "\tEnabled: %s\n", | ||
925 | cntrl & CNTRL_RXE ? "yes" : "no"); | ||
926 | v4l2_info(sd, "\tDemodulation from a carrier: %s\n", | ||
927 | cntrl & CNTRL_DMD ? "enabled" : "disabled"); | ||
928 | v4l2_info(sd, "\tFIFO: %s\n", | ||
929 | cntrl & CNTRL_RFE ? "enabled" : "disabled"); | ||
930 | switch (cntrl & CNTRL_EDG) { | ||
931 | case CNTRL_EDG_NONE: | ||
932 | s = "disabled"; | ||
933 | break; | ||
934 | case CNTRL_EDG_FALL: | ||
935 | s = "falling edge"; | ||
936 | break; | ||
937 | case CNTRL_EDG_RISE: | ||
938 | s = "rising edge"; | ||
939 | break; | ||
940 | case CNTRL_EDG_BOTH: | ||
941 | s = "rising & falling edges"; | ||
942 | break; | ||
943 | default: | ||
944 | s = "??? edge"; | ||
945 | break; | ||
946 | } | ||
947 | v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); | ||
948 | v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", | ||
949 | cntrl & CNTRL_R ? "not loaded" : "overflow marker"); | ||
950 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
951 | cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); | ||
952 | v4l2_info(sd, "\tLoopback mode: %s\n", | ||
953 | cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); | ||
954 | if (cntrl & CNTRL_DMD) { | ||
955 | v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", | ||
956 | clock_divider_to_carrier_freq(rxclk)); | ||
957 | switch (cntrl & CNTRL_WIN) { | ||
958 | case CNTRL_WIN_3_3: | ||
959 | i = 3; | ||
960 | j = 3; | ||
961 | break; | ||
962 | case CNTRL_WIN_4_3: | ||
963 | i = 4; | ||
964 | j = 3; | ||
965 | break; | ||
966 | case CNTRL_WIN_3_4: | ||
967 | i = 3; | ||
968 | j = 4; | ||
969 | break; | ||
970 | case CNTRL_WIN_4_4: | ||
971 | i = 4; | ||
972 | j = 4; | ||
973 | break; | ||
974 | default: | ||
975 | i = 0; | ||
976 | j = 0; | ||
977 | break; | ||
978 | } | ||
979 | v4l2_info(sd, "\tNext carrier edge window: 16 clocks " | ||
980 | "-%1d/+%1d, %u to %u Hz\n", i, j, | ||
981 | clock_divider_to_freq(rxclk, 16 + j), | ||
982 | clock_divider_to_freq(rxclk, 16 - i)); | ||
983 | } else { | ||
984 | v4l2_info(sd, "\tMax measurable pulse width: %u us, " | ||
985 | "%llu ns\n", | ||
986 | pulse_width_count_to_us(FIFO_RXTX, rxclk), | ||
987 | pulse_width_count_to_ns(FIFO_RXTX, rxclk)); | ||
988 | } | ||
989 | v4l2_info(sd, "\tLow pass filter: %s\n", | ||
990 | filtr ? "enabled" : "disabled"); | ||
991 | if (filtr) | ||
992 | v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " | ||
993 | "%u ns\n", | ||
994 | lpf_count_to_us(filtr), | ||
995 | lpf_count_to_ns(filtr)); | ||
996 | v4l2_info(sd, "\tPulse width timer timed-out: %s\n", | ||
997 | stats & STATS_RTO ? "yes" : "no"); | ||
998 | v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", | ||
999 | irqen & IRQEN_RTE ? "enabled" : "disabled"); | ||
1000 | v4l2_info(sd, "\tFIFO overrun: %s\n", | ||
1001 | stats & STATS_ROR ? "yes" : "no"); | ||
1002 | v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", | ||
1003 | irqen & IRQEN_ROE ? "enabled" : "disabled"); | ||
1004 | v4l2_info(sd, "\tBusy: %s\n", | ||
1005 | stats & STATS_RBY ? "yes" : "no"); | ||
1006 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1007 | stats & STATS_RSR ? "yes" : "no"); | ||
1008 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1009 | irqen & IRQEN_RSE ? "enabled" : "disabled"); | ||
1010 | |||
1011 | v4l2_info(sd, "IR Transmitter:\n"); | ||
1012 | v4l2_info(sd, "\tEnabled: %s\n", | ||
1013 | cntrl & CNTRL_TXE ? "yes" : "no"); | ||
1014 | v4l2_info(sd, "\tModulation onto a carrier: %s\n", | ||
1015 | cntrl & CNTRL_MOD ? "enabled" : "disabled"); | ||
1016 | v4l2_info(sd, "\tFIFO: %s\n", | ||
1017 | cntrl & CNTRL_TFE ? "enabled" : "disabled"); | ||
1018 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
1019 | cntrl & CNTRL_TIC ? "not empty" : "half full or less"); | ||
1020 | v4l2_info(sd, "\tSignal polarity: %s\n", | ||
1021 | cntrl & CNTRL_CPL ? "0:mark 1:space" : "0:space 1:mark"); | ||
1022 | if (cntrl & CNTRL_MOD) { | ||
1023 | v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", | ||
1024 | clock_divider_to_carrier_freq(txclk)); | ||
1025 | v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", | ||
1026 | cduty + 1); | ||
1027 | } else { | ||
1028 | v4l2_info(sd, "\tMax pulse width: %u us, " | ||
1029 | "%llu ns\n", | ||
1030 | pulse_width_count_to_us(FIFO_RXTX, txclk), | ||
1031 | pulse_width_count_to_ns(FIFO_RXTX, txclk)); | ||
1032 | } | ||
1033 | v4l2_info(sd, "\tBusy: %s\n", | ||
1034 | stats & STATS_TBY ? "yes" : "no"); | ||
1035 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1036 | stats & STATS_TSR ? "yes" : "no"); | ||
1037 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1038 | irqen & IRQEN_TSE ? "enabled" : "disabled"); | ||
1039 | |||
122 | return 0; | 1040 | return 0; |
123 | } | 1041 | } |
124 | 1042 | ||
@@ -187,19 +1105,81 @@ static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { | |||
187 | #endif | 1105 | #endif |
188 | }; | 1106 | }; |
189 | 1107 | ||
1108 | static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { | ||
1109 | .interrupt_service_routine = cx23888_ir_irq_handler, | ||
1110 | |||
1111 | .rx_read = cx23888_ir_rx_read, | ||
1112 | .rx_g_parameters = cx23888_ir_rx_g_parameters, | ||
1113 | .rx_s_parameters = cx23888_ir_rx_s_parameters, | ||
1114 | |||
1115 | .tx_write = cx23888_ir_tx_write, | ||
1116 | .tx_g_parameters = cx23888_ir_tx_g_parameters, | ||
1117 | .tx_s_parameters = cx23888_ir_tx_s_parameters, | ||
1118 | }; | ||
1119 | |||
190 | static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { | 1120 | static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { |
191 | .core = &cx23888_ir_core_ops, | 1121 | .core = &cx23888_ir_core_ops, |
1122 | .ir = &cx23888_ir_ir_ops, | ||
1123 | }; | ||
1124 | |||
1125 | static const struct v4l2_subdev_ir_parameters default_rx_params = { | ||
1126 | .bytes_per_data_element = sizeof(u32), | ||
1127 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1128 | |||
1129 | .enable = false, | ||
1130 | .interrupt_enable = false, | ||
1131 | .shutdown = true, | ||
1132 | |||
1133 | .modulation = true, | ||
1134 | .carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */ | ||
1135 | |||
1136 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
1137 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
1138 | .noise_filter_min_width = 333333, /* ns */ | ||
1139 | .carrier_range_lower = 35000, | ||
1140 | .carrier_range_upper = 37000, | ||
1141 | .invert = false, | ||
1142 | }; | ||
1143 | |||
1144 | static const struct v4l2_subdev_ir_parameters default_tx_params = { | ||
1145 | .bytes_per_data_element = sizeof(u32), | ||
1146 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1147 | |||
1148 | .enable = false, | ||
1149 | .interrupt_enable = false, | ||
1150 | .shutdown = true, | ||
1151 | |||
1152 | .modulation = true, | ||
1153 | .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ | ||
1154 | .duty_cycle = 25, /* 25 % - RC-5 carrier */ | ||
1155 | .invert = false, | ||
192 | }; | 1156 | }; |
193 | 1157 | ||
194 | int cx23888_ir_probe(struct cx23885_dev *dev) | 1158 | int cx23888_ir_probe(struct cx23885_dev *dev) |
195 | { | 1159 | { |
196 | struct cx23888_ir_state *state; | 1160 | struct cx23888_ir_state *state; |
197 | struct v4l2_subdev *sd; | 1161 | struct v4l2_subdev *sd; |
1162 | struct v4l2_subdev_ir_parameters default_params; | ||
1163 | int ret; | ||
198 | 1164 | ||
199 | state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); | 1165 | state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); |
200 | if (state == NULL) | 1166 | if (state == NULL) |
201 | return -ENOMEM; | 1167 | return -ENOMEM; |
202 | 1168 | ||
1169 | spin_lock_init(&state->rx_kfifo_lock); | ||
1170 | state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL, | ||
1171 | &state->rx_kfifo_lock); | ||
1172 | if (state->rx_kfifo == NULL) | ||
1173 | return -ENOMEM; | ||
1174 | |||
1175 | spin_lock_init(&state->tx_kfifo_lock); | ||
1176 | state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL, | ||
1177 | &state->tx_kfifo_lock); | ||
1178 | if (state->tx_kfifo == NULL) { | ||
1179 | kfifo_free(state->rx_kfifo); | ||
1180 | return -ENOMEM; | ||
1181 | } | ||
1182 | |||
203 | state->dev = dev; | 1183 | state->dev = dev; |
204 | state->id = V4L2_IDENT_CX23888_IR; | 1184 | state->id = V4L2_IDENT_CX23888_IR; |
205 | state->rev = 0; | 1185 | state->rev = 0; |
@@ -210,7 +1190,30 @@ int cx23888_ir_probe(struct cx23885_dev *dev) | |||
210 | /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ | 1190 | /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ |
211 | snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); | 1191 | snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); |
212 | sd->grp_id = CX23885_HW_888_IR; | 1192 | sd->grp_id = CX23885_HW_888_IR; |
213 | return v4l2_device_register_subdev(&dev->v4l2_dev, sd); | 1193 | |
1194 | ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd); | ||
1195 | if (ret == 0) { | ||
1196 | /* | ||
1197 | * Ensure no interrupts arrive from '888 specific conditions, | ||
1198 | * since we ignore them in this driver to have commonality with | ||
1199 | * similar IR controller cores. | ||
1200 | */ | ||
1201 | cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0); | ||
1202 | |||
1203 | mutex_init(&state->rx_params_lock); | ||
1204 | memcpy(&default_params, &default_rx_params, | ||
1205 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1206 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); | ||
1207 | |||
1208 | mutex_init(&state->tx_params_lock); | ||
1209 | memcpy(&default_params, &default_tx_params, | ||
1210 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1211 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); | ||
1212 | } else { | ||
1213 | kfifo_free(state->rx_kfifo); | ||
1214 | kfifo_free(state->tx_kfifo); | ||
1215 | } | ||
1216 | return ret; | ||
214 | } | 1217 | } |
215 | 1218 | ||
216 | int cx23888_ir_remove(struct cx23885_dev *dev) | 1219 | int cx23888_ir_remove(struct cx23885_dev *dev) |
@@ -222,11 +1225,13 @@ int cx23888_ir_remove(struct cx23885_dev *dev) | |||
222 | if (sd == NULL) | 1225 | if (sd == NULL) |
223 | return -ENODEV; | 1226 | return -ENODEV; |
224 | 1227 | ||
225 | /* Disable receiver and transmitter */ | 1228 | cx23888_ir_rx_shutdown(sd); |
226 | cx23888_ir_and_or(dev, CX23888_IR_CNTRL_REG+1, 0xfc, 0); | 1229 | cx23888_ir_tx_shutdown(sd); |
227 | 1230 | ||
228 | state = to_state(sd); | 1231 | state = to_state(sd); |
229 | v4l2_device_unregister_subdev(sd); | 1232 | v4l2_device_unregister_subdev(sd); |
1233 | kfifo_free(state->rx_kfifo); | ||
1234 | kfifo_free(state->tx_kfifo); | ||
230 | kfree(state); | 1235 | kfree(state); |
231 | /* Nothing more to free() as state held the actual v4l2_subdev object */ | 1236 | /* Nothing more to free() as state held the actual v4l2_subdev object */ |
232 | return 0; | 1237 | return 0; |