|
@@ -24,6 +24,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/kfifo.h>
|
|
#include <linux/kfifo.h>
|
|
#include <media/cx25840.h>
|
|
#include <media/cx25840.h>
|
|
|
|
+#include <media/ir-core.h>
|
|
|
|
|
|
#include "cx25840-core.h"
|
|
#include "cx25840-core.h"
|
|
|
|
|
|
@@ -94,8 +95,18 @@ MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
|
|
#define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
|
|
#define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
|
|
#define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2)
|
|
#define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2)
|
|
|
|
|
|
-#define CX25840_IR_RX_KFIFO_SIZE (512 * sizeof(u32))
|
|
|
|
-#define CX25840_IR_TX_KFIFO_SIZE (512 * sizeof(u32))
|
|
|
|
|
|
+/*
|
|
|
|
+ * We use this union internally for convenience, but callers to tx_write
|
|
|
|
+ * and rx_read will be expecting records of type struct ir_raw_event.
|
|
|
|
+ * Always ensure the size of this union is dictated by struct ir_raw_event.
|
|
|
|
+ */
|
|
|
|
+union cx25840_ir_fifo_rec {
|
|
|
|
+ u32 hw_fifo_data;
|
|
|
|
+ struct ir_raw_event ir_core_data;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
|
|
|
|
+#define CX25840_IR_TX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
|
|
|
|
|
|
struct cx25840_ir_state {
|
|
struct cx25840_ir_state {
|
|
struct i2c_client *c;
|
|
struct i2c_client *c;
|
|
@@ -435,8 +446,8 @@ static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns,
|
|
{
|
|
{
|
|
u64 pulse_clocks;
|
|
u64 pulse_clocks;
|
|
|
|
|
|
- if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
|
|
|
|
- ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
|
|
|
|
|
|
+ if (ns > IR_MAX_DURATION)
|
|
|
|
+ ns = IR_MAX_DURATION;
|
|
pulse_clocks = ns_to_pulse_clocks(ns);
|
|
pulse_clocks = ns_to_pulse_clocks(ns);
|
|
*divider = pulse_clocks_to_clock_divider(pulse_clocks);
|
|
*divider = pulse_clocks_to_clock_divider(pulse_clocks);
|
|
cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
|
|
cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
|
|
@@ -448,8 +459,8 @@ static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns,
|
|
{
|
|
{
|
|
u64 pulse_clocks;
|
|
u64 pulse_clocks;
|
|
|
|
|
|
- if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
|
|
|
|
- ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
|
|
|
|
|
|
+ if (ns > IR_MAX_DURATION)
|
|
|
|
+ ns = IR_MAX_DURATION;
|
|
pulse_clocks = ns_to_pulse_clocks(ns);
|
|
pulse_clocks = ns_to_pulse_clocks(ns);
|
|
*divider = pulse_clocks_to_clock_divider(pulse_clocks);
|
|
*divider = pulse_clocks_to_clock_divider(pulse_clocks);
|
|
cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
|
|
cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
|
|
@@ -516,8 +527,8 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
|
|
struct i2c_client *c = NULL;
|
|
struct i2c_client *c = NULL;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
- u32 rx_data[FIFO_RX_DEPTH];
|
|
|
|
- int i, j, k;
|
|
|
|
|
|
+ union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH];
|
|
|
|
+ unsigned int i, j, k;
|
|
u32 events, v;
|
|
u32 events, v;
|
|
int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
|
|
int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
|
|
u32 cntrl, irqen, stats;
|
|
u32 cntrl, irqen, stats;
|
|
@@ -594,11 +605,12 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
|
|
for (j = 0;
|
|
for (j = 0;
|
|
(v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
|
|
(v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
|
|
v = cx25840_read4(c, CX25840_IR_FIFO_REG);
|
|
v = cx25840_read4(c, CX25840_IR_FIFO_REG);
|
|
- rx_data[i++] = v & ~FIFO_RX_NDV;
|
|
|
|
|
|
+ rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV;
|
|
|
|
+ i++;
|
|
}
|
|
}
|
|
if (i == 0)
|
|
if (i == 0)
|
|
break;
|
|
break;
|
|
- j = i * sizeof(u32);
|
|
|
|
|
|
+ j = i * sizeof(union cx25840_ir_fifo_rec);
|
|
k = kfifo_in_locked(&ir_state->rx_kfifo,
|
|
k = kfifo_in_locked(&ir_state->rx_kfifo,
|
|
(unsigned char *) rx_data, j,
|
|
(unsigned char *) rx_data, j,
|
|
&ir_state->rx_kfifo_lock);
|
|
&ir_state->rx_kfifo_lock);
|
|
@@ -655,8 +667,8 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
|
|
bool invert;
|
|
bool invert;
|
|
u16 divider;
|
|
u16 divider;
|
|
unsigned int i, n;
|
|
unsigned int i, n;
|
|
- u32 *p;
|
|
|
|
- u32 u, v;
|
|
|
|
|
|
+ union cx25840_ir_fifo_rec *p;
|
|
|
|
+ unsigned u, v;
|
|
|
|
|
|
if (ir_state == NULL)
|
|
if (ir_state == NULL)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
@@ -664,7 +676,8 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
|
|
invert = (bool) atomic_read(&ir_state->rx_invert);
|
|
invert = (bool) atomic_read(&ir_state->rx_invert);
|
|
divider = (u16) atomic_read(&ir_state->rxclk_divider);
|
|
divider = (u16) atomic_read(&ir_state->rxclk_divider);
|
|
|
|
|
|
- n = count / sizeof(u32) * sizeof(u32);
|
|
|
|
|
|
+ n = count / sizeof(union cx25840_ir_fifo_rec)
|
|
|
|
+ * sizeof(union cx25840_ir_fifo_rec);
|
|
if (n == 0) {
|
|
if (n == 0) {
|
|
*num = 0;
|
|
*num = 0;
|
|
return 0;
|
|
return 0;
|
|
@@ -673,28 +686,28 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
|
|
n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
|
|
n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
|
|
&ir_state->rx_kfifo_lock);
|
|
&ir_state->rx_kfifo_lock);
|
|
|
|
|
|
- n /= sizeof(u32);
|
|
|
|
- *num = n * sizeof(u32);
|
|
|
|
|
|
+ n /= sizeof(union cx25840_ir_fifo_rec);
|
|
|
|
+ *num = n * sizeof(union cx25840_ir_fifo_rec);
|
|
|
|
|
|
- for (p = (u32 *) buf, i = 0; i < n; p++, i++) {
|
|
|
|
|
|
+ for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
|
|
|
|
|
|
- if ((*p & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
|
|
|
|
|
|
+ if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
|
|
/* Assume RTO was because of no IR light input */
|
|
/* Assume RTO was because of no IR light input */
|
|
u = 0;
|
|
u = 0;
|
|
v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
|
|
v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
|
|
} else {
|
|
} else {
|
|
- u = (*p & FIFO_RXTX_LVL)
|
|
|
|
- ? V4L2_SUBDEV_IR_PULSE_LEVEL_MASK : 0;
|
|
|
|
|
|
+ u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
|
|
if (invert)
|
|
if (invert)
|
|
- u = u ? 0 : V4L2_SUBDEV_IR_PULSE_LEVEL_MASK;
|
|
|
|
|
|
+ u = u ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
|
|
- v = (u32) pulse_width_count_to_ns((u16) (*p & FIFO_RXTX),
|
|
|
|
- divider);
|
|
|
|
- if (v >= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
|
|
|
|
- v = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS - 1;
|
|
|
|
|
|
+ v = (unsigned) pulse_width_count_to_ns(
|
|
|
|
+ (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
|
|
|
|
+ if (v > IR_MAX_DURATION)
|
|
|
|
+ v = IR_MAX_DURATION;
|
|
|
|
|
|
- *p = u | v;
|
|
|
|
|
|
+ p->ir_core_data.pulse = u;
|
|
|
|
+ p->ir_core_data.duration = v;
|
|
|
|
|
|
v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n",
|
|
v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n",
|
|
v, u ? "mark" : "space");
|
|
v, u ? "mark" : "space");
|
|
@@ -769,7 +782,7 @@ static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd,
|
|
p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
|
|
p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
|
|
o->mode = p->mode;
|
|
o->mode = p->mode;
|
|
|
|
|
|
- p->bytes_per_data_element = sizeof(u32);
|
|
|
|
|
|
+ p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
|
|
o->bytes_per_data_element = p->bytes_per_data_element;
|
|
o->bytes_per_data_element = p->bytes_per_data_element;
|
|
|
|
|
|
/* Before we tweak the hardware, we have to disable the receiver */
|
|
/* Before we tweak the hardware, we have to disable the receiver */
|
|
@@ -958,7 +971,7 @@ static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd,
|
|
p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
|
|
p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
|
|
o->mode = p->mode;
|
|
o->mode = p->mode;
|
|
|
|
|
|
- p->bytes_per_data_element = sizeof(u32);
|
|
|
|
|
|
+ p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
|
|
o->bytes_per_data_element = p->bytes_per_data_element;
|
|
o->bytes_per_data_element = p->bytes_per_data_element;
|
|
|
|
|
|
/* Before we tweak the hardware, we have to disable the transmitter */
|
|
/* Before we tweak the hardware, we have to disable the transmitter */
|
|
@@ -1172,7 +1185,7 @@ const struct v4l2_subdev_ir_ops cx25840_ir_ops = {
|
|
|
|
|
|
|
|
|
|
static const struct v4l2_subdev_ir_parameters default_rx_params = {
|
|
static const struct v4l2_subdev_ir_parameters default_rx_params = {
|
|
- .bytes_per_data_element = sizeof(u32),
|
|
|
|
|
|
+ .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
|
|
.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
|
|
.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
|
|
|
|
|
|
.enable = false,
|
|
.enable = false,
|
|
@@ -1191,7 +1204,7 @@ static const struct v4l2_subdev_ir_parameters default_rx_params = {
|
|
};
|
|
};
|
|
|
|
|
|
static const struct v4l2_subdev_ir_parameters default_tx_params = {
|
|
static const struct v4l2_subdev_ir_parameters default_tx_params = {
|
|
- .bytes_per_data_element = sizeof(u32),
|
|
|
|
|
|
+ .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
|
|
.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
|
|
.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
|
|
|
|
|
|
.enable = false,
|
|
.enable = false,
|