*
* CX23888 Integrated Consumer Infrared Controller
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
*/
#include <linux/kfifo.h>
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#define CX23888_IR_LEARN_REG 0x170044
#define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
-#define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ/2)
+#define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ / 2)
#define CX23888_IR_RX_KFIFO_SIZE (512 * sizeof(u32))
#define CX23888_IR_TX_KFIFO_SIZE (512 * sizeof(u32))
atomic_t rxclk_divider;
atomic_t rx_invert;
- struct kfifo *rx_kfifo;
+ struct kfifo rx_kfifo;
spinlock_t rx_kfifo_lock;
struct v4l2_subdev_ir_parameters tx_params;
struct mutex tx_params_lock;
atomic_t txclk_divider;
-
- struct kfifo *tx_kfifo;
- spinlock_t tx_kfifo_lock;
};
static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
*/
static inline u16 count_to_clock_divider(unsigned int d)
{
- if (d > RXCLK_RCD+1)
+ if (d > RXCLK_RCD + 1)
d = RXCLK_RCD;
else if (d < 2)
d = 1;
static inline u16 ns_to_clock_divider(unsigned int ns)
{
return count_to_clock_divider(
- DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ/1000000 * ns, 1000));
+ DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
}
static inline unsigned int clock_divider_to_ns(unsigned int divider)
{
/* Period of the Rx or Tx clock in ns */
return DIV_ROUND_CLOSEST((divider + 1) * 1000,
- CX23888_IR_REFCLK_FREQ/1000000);
+ CX23888_IR_REFCLK_FREQ / 1000000);
}
static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
static inline u16 ns_to_lpf_count(unsigned int ns)
{
return count_to_lpf_count(
- DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ/1000000 * ns, 1000));
+ DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000));
}
static inline unsigned int lpf_count_to_ns(unsigned int count)
{
/* Duration of the Low Pass Filter rejection window in ns */
- return DIV_ROUND_CLOSEST(count * 1000, CX23888_IR_REFCLK_FREQ/1000000);
+ return DIV_ROUND_CLOSEST(count * 1000,
+ CX23888_IR_REFCLK_FREQ / 1000000);
}
static inline unsigned int lpf_count_to_us(unsigned int count)
{
/* Duration of the Low Pass Filter rejection window in us */
- return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ/1000000);
+ return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000);
}
/*
* not readable, hence the << 2. This function returns ns.
*/
return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000,
- CX23888_IR_REFCLK_FREQ/1000000);
+ CX23888_IR_REFCLK_FREQ / 1000000);
}
static u64 pulse_width_count_to_ns(u16 count, u16 divider)
* the (count << 2) | 0x3
*/
n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
- rem = do_div(n, CX23888_IR_REFCLK_FREQ/1000000); /* / MHz => ns */
- if (rem >= CX23888_IR_REFCLK_FREQ/1000000/2)
+ rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */
+ if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2)
n++;
return n;
}
* The 2 lsb's of the pulse width timer count are not readable, hence
* the (count << 2) | 0x3
*/
- n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */
- rem = do_div(n, CX23888_IR_REFCLK_FREQ/1000000); /* / MHz => us */
- if (rem >= CX23888_IR_REFCLK_FREQ/1000000/2)
+ n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */
+ rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
+ if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2)
n++;
return (unsigned int) n;
}
{
u64 clocks;
u32 rem;
- clocks = CX23888_IR_REFCLK_FREQ/1000000 * (u64) ns; /* millicycles */
+ clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */
rem = do_div(clocks, 1000); /* /1000 = cycles */
- if (rem >= 1000/2)
+ if (rem >= 1000 / 2)
clocks++;
return clocks;
}
rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
/* net result needs to be rounded down and decremented by 1 */
- if (count > RXCLK_RCD+1)
+ if (count > RXCLK_RCD + 1)
count = RXCLK_RCD;
else if (count < 2)
count = 1;
if (n > 15)
n = 15;
cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n);
- return DIV_ROUND_CLOSEST((n+1) * 100, 16);
+ return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
}
/*
{
struct cx23888_ir_state *state = to_state(sd);
struct cx23885_dev *dev = state->dev;
+ unsigned long flags;
u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
if (i == 0)
break;
j = i * sizeof(u32);
- k = kfifo_put(state->rx_kfifo,
- (unsigned char *) rx_data, j);
+ k = kfifo_in_locked(&state->rx_kfifo,
+ (unsigned char *) rx_data, j,
+ &state->rx_kfifo_lock);
if (k != j)
kror++; /* rx_kfifo over run */
}
cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl);
*handled = true;
}
- if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE/2)
+
+ spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+ if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+ spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
if (events)
v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
return 0;
}
- n = kfifo_get(state->rx_kfifo, buf, n);
+ n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
n /= sizeof(u32);
*num = n * sizeof(u32);
o->interrupt_enable = p->interrupt_enable;
o->enable = p->enable;
if (p->enable) {
- kfifo_reset(state->rx_kfifo);
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+ kfifo_reset(&state->rx_kfifo);
+ /* reset tx_fifo too if there is one... */
+ spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
if (p->interrupt_enable)
irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
control_rx_enable(dev, p->enable);
o->interrupt_enable = p->interrupt_enable;
o->enable = p->enable;
if (p->enable) {
- kfifo_reset(state->tx_kfifo);
if (p->interrupt_enable)
irqenable_tx(dev, IRQEN_TSE);
control_tx_enable(dev, p->enable);
return -ENOMEM;
spin_lock_init(&state->rx_kfifo_lock);
- state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL,
- &state->rx_kfifo_lock);
- if (state->rx_kfifo == NULL)
- return -ENOMEM;
-
- spin_lock_init(&state->tx_kfifo_lock);
- state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL,
- &state->tx_kfifo_lock);
- if (state->tx_kfifo == NULL) {
- kfifo_free(state->rx_kfifo);
+ if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
return -ENOMEM;
- }
state->dev = dev;
state->id = V4L2_IDENT_CX23888_IR;
sizeof(struct v4l2_subdev_ir_parameters));
v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
} else {
- kfifo_free(state->rx_kfifo);
- kfifo_free(state->tx_kfifo);
+ kfifo_free(&state->rx_kfifo);
}
return ret;
}
state = to_state(sd);
v4l2_device_unregister_subdev(sd);
- kfifo_free(state->rx_kfifo);
- kfifo_free(state->tx_kfifo);
+ kfifo_free(&state->rx_kfifo);
kfree(state);
/* Nothing more to free() as state held the actual v4l2_subdev object */
return 0;