]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/cx18/cx18-gpio.c
Merge branch 'linus' into core/futexes
[linux-2.6-omap-h63xx.git] / drivers / media / video / cx18 / cx18-gpio.c
index b302833f6f9dd8d8250f4e716ed5fa9084d515d6..0e560421989e4bb69f124a0ce28047d7c10665a3 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "tuner-xc2028.h"
@@ -49,11 +50,11 @@ static void gpio_write(struct cx18 *cx)
        u32 dir = cx->gpio_dir;
        u32 val = cx->gpio_val;
 
-       write_reg((dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
-       write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
+       cx18_write_reg(cx, (dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+       cx18_write_reg(cx, ((dir & 0xffff) << 16) | (val & 0xffff),
                        CX18_REG_GPIO_OUT1);
-       write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
-       write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
+       cx18_write_reg(cx, dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+       cx18_write_reg_sync(cx, (dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
                        CX18_REG_GPIO_OUT2);
 }
 
@@ -69,6 +70,7 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
        /* Assuming that the masks are a subset of the bits in gpio_dir */
 
        /* Assert */
+       mutex_lock(&cx->gpio_lock);
        cx->gpio_val =
                (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
        gpio_write(cx);
@@ -79,10 +81,53 @@ void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
                (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
        gpio_write(cx);
        schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+       mutex_unlock(&cx->gpio_lock);
 }
 
+void cx18_reset_ir_gpio(void *data)
+{
+       struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+       const struct cx18_gpio_i2c_slave_reset *p;
+
+       p = &cx->card->gpio_i2c_slave_reset;
+
+       if (p->ir_reset_mask == 0)
+               return;
+
+       CX18_DEBUG_INFO("Resetting IR microcontroller\n");
+
+       /*
+          Assert timing for the Z8F0811 on HVR-1600 boards:
+          1. Assert RESET for min of 4 clock cycles at 18.432 MHz to initiate
+          2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock cycles
+               (6,601,085 nanoseconds ~= 7 milliseconds)
+          3. DBG pin must be high before chip exits reset for normal operation.
+               DBG is open drain and hopefully pulled high since we don't
+               normally drive it (GPIO 1?) for the HVR-1600
+          4. Z8F0811 won't exit reset until RESET is deasserted
+       */
+       mutex_lock(&cx->gpio_lock);
+       cx->gpio_val = cx->gpio_val & ~p->ir_reset_mask;
+       gpio_write(cx);
+       mutex_unlock(&cx->gpio_lock);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+       /*
+          Zilog comes out of reset, loads reset vector address and executes
+          from there. Required recovery delay unknown.
+       */
+       mutex_lock(&cx->gpio_lock);
+       cx->gpio_val = cx->gpio_val | p->ir_reset_mask;
+       gpio_write(cx);
+       mutex_unlock(&cx->gpio_lock);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+EXPORT_SYMBOL(cx18_reset_ir_gpio);
+/* This symbol is exported for use by an infrared module for the IR-blaster */
+
 void cx18_gpio_init(struct cx18 *cx)
 {
+       mutex_lock(&cx->gpio_lock);
        cx->gpio_dir = cx->card->gpio_init.direction;
        cx->gpio_val = cx->card->gpio_init.initial_value;
 
@@ -91,18 +136,23 @@ void cx18_gpio_init(struct cx18 *cx)
                cx->gpio_val |= 1 << cx->card->xceive_pin;
        }
 
-       if (cx->gpio_dir == 0)
+       if (cx->gpio_dir == 0) {
+               mutex_unlock(&cx->gpio_lock);
                return;
+       }
 
        CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
-                  read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
-                  read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
+                       cx18_read_reg(cx, CX18_REG_GPIO_DIR1),
+                       cx18_read_reg(cx, CX18_REG_GPIO_DIR2),
+                       cx18_read_reg(cx, CX18_REG_GPIO_OUT1),
+                       cx18_read_reg(cx, CX18_REG_GPIO_OUT2));
 
        gpio_write(cx);
+       mutex_unlock(&cx->gpio_lock);
 }
 
 /* Xceive tuner reset function */
-int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
+int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
 {
        struct i2c_algo_bit_data *algo = dev;
        struct cx18_i2c_algo_callback_data *cb_data = algo->data;
@@ -112,13 +162,52 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
                return 0;
        CX18_DEBUG_INFO("Resetting tuner\n");
 
+       mutex_lock(&cx->gpio_lock);
        cx->gpio_val &= ~(1 << cx->card->xceive_pin);
-
        gpio_write(cx);
+       mutex_unlock(&cx->gpio_lock);
        schedule_timeout_interruptible(msecs_to_jiffies(1));
 
+       mutex_lock(&cx->gpio_lock);
        cx->gpio_val |= 1 << cx->card->xceive_pin;
        gpio_write(cx);
+       mutex_unlock(&cx->gpio_lock);
        schedule_timeout_interruptible(msecs_to_jiffies(1));
        return 0;
 }
+
+int cx18_gpio(struct cx18 *cx, unsigned int command, void *arg)
+{
+       struct v4l2_routing *route = arg;
+       u32 mask, data;
+
+       switch (command) {
+       case VIDIOC_INT_S_AUDIO_ROUTING:
+               if (route->input > 2)
+                       return -EINVAL;
+               mask = cx->card->gpio_audio_input.mask;
+               switch (route->input) {
+               case 0:
+                       data = cx->card->gpio_audio_input.tuner;
+                       break;
+               case 1:
+                       data = cx->card->gpio_audio_input.linein;
+                       break;
+               case 2:
+               default:
+                       data = cx->card->gpio_audio_input.radio;
+                       break;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       if (mask) {
+               mutex_lock(&cx->gpio_lock);
+               cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask);
+               gpio_write(cx);
+               mutex_unlock(&cx->gpio_lock);
+       }
+       return 0;
+}