V4L/DVB: cx18, cx23885, v4l2 doc, MAINTAINERS: Update Andy Walls' email address
[safe/jmp/linux-2.6] / drivers / media / video / cx23885 / cx23888-ir.c
index e8d949a..f63d378 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  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
@@ -22,6 +22,7 @@
  */
 
 #include <linux/kfifo.h>
+#include <linux/slab.h>
 
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
@@ -108,7 +109,7 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
 #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))
@@ -124,15 +125,12 @@ struct cx23888_ir_state {
        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)
@@ -171,7 +169,7 @@ static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr,
  */
 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;
@@ -183,14 +181,14 @@ static inline u16 count_to_clock_divider(unsigned int d)
 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)
@@ -237,19 +235,20 @@ static inline u16 count_to_lpf_count(unsigned int d)
 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);
 }
 
 /*
@@ -263,7 +262,7 @@ static u32 clock_divider_to_resolution(u16 divider)
         * 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)
@@ -276,8 +275,8 @@ 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;
 }
@@ -291,9 +290,9 @@ static unsigned int pulse_width_count_to_us(u16 count, u16 divider)
         * 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;
 }
@@ -310,9 +309,9 @@ static u64 ns_to_pulse_clocks(u32 ns)
 {
        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;
 }
@@ -324,7 +323,7 @@ static u16 pulse_clocks_to_clock_divider(u64 count)
        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;
@@ -484,7 +483,7 @@ static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev,
        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);
 }
 
 /*
@@ -521,6 +520,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
 {
        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);
@@ -593,8 +593,9 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
                        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 */
                }
@@ -630,8 +631,11 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
                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);
@@ -656,7 +660,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                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);
@@ -784,7 +788,12 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
        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);
@@ -891,7 +900,6 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
        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);
@@ -1167,18 +1175,8 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                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;
@@ -1210,8 +1208,7 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                       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;
 }
@@ -1230,8 +1227,7 @@ int cx23888_ir_remove(struct cx23885_dev *dev)
 
        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;