]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/cx18/cx18-i2c.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6-omap-h63xx.git] / drivers / media / video / cx18 / cx18-i2c.c
index 680bc4e35b79a3c67d38e072af2471fb30e35e2d..8941f58bed7f042ce5cce8a97bbfeb33ef20bd79 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-i2c.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 
 #include "cx18-driver.h"
+#include "cx18-io.h"
 #include "cx18-cards.h"
 #include "cx18-gpio.h"
 #include "cx18-av-core.h"
 #include "cx18-i2c.h"
-
-#include <media/ir-kbd-i2c.h>
+#include "cx18-irq.h"
 
 #define CX18_REG_I2C_1_WR   0xf15000
 #define CX18_REG_I2C_1_RD   0xf15008
 #define GETSCL_BIT      0x0004
 #define GETSDL_BIT      0x0008
 
-#ifndef I2C_ADAP_CLASS_TV_ANALOG
-#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
-#endif
-
 #define CX18_CS5345_I2C_ADDR           0x4c
 
 /* This array should match the CX18_HW_ defines */
@@ -162,12 +159,12 @@ static void cx18_setscl(void *data, int state)
        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
-       u32 r = read_reg(addr);
+       u32 r = cx18_read_reg(cx, addr);
 
        if (state)
-               write_reg_sync(r | SETSCL_BIT, addr);
+               cx18_write_reg(cx, r | SETSCL_BIT, addr);
        else
-               write_reg_sync(r & ~SETSCL_BIT, addr);
+               cx18_write_reg(cx, r & ~SETSCL_BIT, addr);
 }
 
 static void cx18_setsda(void *data, int state)
@@ -175,12 +172,12 @@ static void cx18_setsda(void *data, int state)
        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
-       u32 r = read_reg(addr);
+       u32 r = cx18_read_reg(cx, addr);
 
        if (state)
-               write_reg_sync(r | SETSDL_BIT, addr);
+               cx18_write_reg(cx, r | SETSDL_BIT, addr);
        else
-               write_reg_sync(r & ~SETSDL_BIT, addr);
+               cx18_write_reg(cx, r & ~SETSDL_BIT, addr);
 }
 
 static int cx18_getscl(void *data)
@@ -189,7 +186,7 @@ static int cx18_getscl(void *data)
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 
-       return read_reg(addr) & GETSCL_BIT;
+       return cx18_read_reg(cx, addr) & GETSCL_BIT;
 }
 
 static int cx18_getsda(void *data)
@@ -198,7 +195,7 @@ static int cx18_getsda(void *data)
        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
        u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 
-       return read_reg(addr) & GETSDL_BIT;
+       return cx18_read_reg(cx, addr) & GETSDL_BIT;
 }
 
 /* template for i2c-bit-algo */
@@ -311,8 +308,12 @@ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
 {
        int addr;
 
-       if (hw == CX18_HW_GPIO || hw == 0)
+       if (hw == 0)
                return 0;
+
+       if (hw == CX18_HW_GPIO)
+               return cx18_gpio(cx, cmd, arg);
+
        if (hw == CX18_HW_CX23418)
                return cx18_av_cmd(cx, cmd, arg);
 
@@ -350,6 +351,8 @@ void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
        cx18_av_cmd(cx, cmd, arg);
        i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
        i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+       if (cx->hw_flags & CX18_HW_GPIO)
+               cx18_gpio(cx, cmd, arg);
 }
 
 /* init + register i2c algo-bit adapter */
@@ -358,6 +361,18 @@ int init_cx18_i2c(struct cx18 *cx)
        int i;
        CX18_DEBUG_I2C("i2c init\n");
 
+       /* Sanity checks for the I2C hardware arrays. They must be the
+        * same size and GPIO/CX23418 must be the last entries.
+        */
+       if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+           ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+           CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) ||
+           CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+           hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+               CX18_ERR("Mismatched I2C hardware arrays\n");
+               return -ENODEV;
+       }
+
        for (i = 0; i < 2; i++) {
                memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
                        sizeof(struct i2c_adapter));
@@ -380,28 +395,36 @@ int init_cx18_i2c(struct cx18 *cx)
                cx->i2c_adap[i].dev.parent = &cx->dev->dev;
        }
 
-       if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
+       if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
                /* Reset/Unreset I2C hardware block */
-               write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
-               write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
+               /* Clock select 220MHz */
+               cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
+                                         0x00000000, 0x10001000);
+               /* Clock Enable */
+               cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
+                                         0x00001000, 0x10001000);
        }
        /* courtesy of Steven Toth <stoth@hauppauge.com> */
-       write_reg_sync(0x00c00000, 0xc7001c);
+       cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
+       mdelay(10);
+       cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
        mdelay(10);
-       write_reg_sync(0x00c000c0, 0xc7001c);
+       cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
        mdelay(10);
-       write_reg_sync(0x00c00000, 0xc7001c);
 
-       write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
-       write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
+       /* Set to edge-triggered intrs. */
+       cx18_write_reg(cx, 0x00c00000, 0xc730c8);
+       /* Clear any stale intrs */
+       cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
+                      ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);
 
        /* Hw I2C1 Clock Freq ~100kHz */
-       write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+       cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
        cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
 
        /* Hw I2C2 Clock Freq ~100kHz */
-       write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+       cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
        cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 
@@ -415,8 +438,10 @@ void exit_cx18_i2c(struct cx18 *cx)
 {
        int i;
        CX18_DEBUG_I2C("i2c exit\n");
-       write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
-       write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
+       cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
+                                                       CX18_REG_I2C_1_WR);
+       cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
+                                                       CX18_REG_I2C_2_WR);
 
        for (i = 0; i < 2; i++) {
                i2c_del_adapter(&cx->i2c_adap[i]);