linux/drivers/media/pci/cx18/cx18-i2c.c
<<
>>
Prefs
   1/*
   2 *  cx18 I2C functions
   3 *
   4 *  Derived from ivtv-i2c.c
   5 *
   6 *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
   7 *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.net>
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or
  12 *  (at your option) any later version.
  13 *
  14 *  This program is distributed in the hope that it will be useful,
  15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *  GNU General Public License for more details.
  18 */
  19
  20#include "cx18-driver.h"
  21#include "cx18-io.h"
  22#include "cx18-cards.h"
  23#include "cx18-gpio.h"
  24#include "cx18-i2c.h"
  25#include "cx18-irq.h"
  26
  27#define CX18_REG_I2C_1_WR   0xf15000
  28#define CX18_REG_I2C_1_RD   0xf15008
  29#define CX18_REG_I2C_2_WR   0xf25100
  30#define CX18_REG_I2C_2_RD   0xf25108
  31
  32#define SETSCL_BIT      0x0001
  33#define SETSDL_BIT      0x0002
  34#define GETSCL_BIT      0x0004
  35#define GETSDL_BIT      0x0008
  36
  37#define CX18_CS5345_I2C_ADDR            0x4c
  38#define CX18_Z8F0811_IR_TX_I2C_ADDR     0x70
  39#define CX18_Z8F0811_IR_RX_I2C_ADDR     0x71
  40
  41/* This array should match the CX18_HW_ defines */
  42static const u8 hw_addrs[] = {
  43        0,                              /* CX18_HW_TUNER */
  44        0,                              /* CX18_HW_TVEEPROM */
  45        CX18_CS5345_I2C_ADDR,           /* CX18_HW_CS5345 */
  46        0,                              /* CX18_HW_DVB */
  47        0,                              /* CX18_HW_418_AV */
  48        0,                              /* CX18_HW_GPIO_MUX */
  49        0,                              /* CX18_HW_GPIO_RESET_CTRL */
  50        CX18_Z8F0811_IR_RX_I2C_ADDR,    /* CX18_HW_Z8F0811_IR_HAUP */
  51};
  52
  53/* This array should match the CX18_HW_ defines */
  54/* This might well become a card-specific array */
  55static const u8 hw_bus[] = {
  56        1,      /* CX18_HW_TUNER */
  57        0,      /* CX18_HW_TVEEPROM */
  58        0,      /* CX18_HW_CS5345 */
  59        0,      /* CX18_HW_DVB */
  60        0,      /* CX18_HW_418_AV */
  61        0,      /* CX18_HW_GPIO_MUX */
  62        0,      /* CX18_HW_GPIO_RESET_CTRL */
  63        0,      /* CX18_HW_Z8F0811_IR_HAUP */
  64};
  65
  66/* This array should match the CX18_HW_ defines */
  67static const char * const hw_devicenames[] = {
  68        "tuner",
  69        "tveeprom",
  70        "cs5345",
  71        "cx23418_DTV",
  72        "cx23418_AV",
  73        "gpio_mux",
  74        "gpio_reset_ctrl",
  75        "ir_z8f0811_haup",
  76};
  77
  78static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
  79                           const char *type, u8 addr)
  80{
  81        struct i2c_board_info info;
  82        struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data;
  83        unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
  84
  85        memset(&info, 0, sizeof(struct i2c_board_info));
  86        strlcpy(info.type, type, I2C_NAME_SIZE);
  87
  88        /* Our default information for ir-kbd-i2c.c to use */
  89        switch (hw) {
  90        case CX18_HW_Z8F0811_IR_HAUP:
  91                init_data->ir_codes = RC_MAP_HAUPPAUGE;
  92                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
  93                init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
  94                                                        RC_PROTO_BIT_RC6_6A_32;
  95                init_data->name = cx->card_name;
  96                info.platform_data = init_data;
  97                break;
  98        }
  99
 100        return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
 101               -1 : 0;
 102}
 103
 104int cx18_i2c_register(struct cx18 *cx, unsigned idx)
 105{
 106        struct v4l2_subdev *sd;
 107        int bus = hw_bus[idx];
 108        struct i2c_adapter *adap = &cx->i2c_adap[bus];
 109        const char *type = hw_devicenames[idx];
 110        u32 hw = 1 << idx;
 111
 112        if (hw == CX18_HW_TUNER) {
 113                /* special tuner group handling */
 114                sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
 115                                adap, type, 0, cx->card_i2c->radio);
 116                if (sd != NULL)
 117                        sd->grp_id = hw;
 118                sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
 119                                adap, type, 0, cx->card_i2c->demod);
 120                if (sd != NULL)
 121                        sd->grp_id = hw;
 122                sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
 123                                adap, type, 0, cx->card_i2c->tv);
 124                if (sd != NULL)
 125                        sd->grp_id = hw;
 126                return sd != NULL ? 0 : -1;
 127        }
 128
 129        if (hw == CX18_HW_Z8F0811_IR_HAUP)
 130                return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]);
 131
 132        /* Is it not an I2C device or one we do not wish to register? */
 133        if (!hw_addrs[idx])
 134                return -1;
 135
 136        /* It's an I2C device other than an analog tuner or IR chip */
 137        sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx],
 138                                 NULL);
 139        if (sd != NULL)
 140                sd->grp_id = hw;
 141        return sd != NULL ? 0 : -1;
 142}
 143
 144/* Find the first member of the subdev group id in hw */
 145struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw)
 146{
 147        struct v4l2_subdev *result = NULL;
 148        struct v4l2_subdev *sd;
 149
 150        spin_lock(&cx->v4l2_dev.lock);
 151        v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) {
 152                if (sd->grp_id == hw) {
 153                        result = sd;
 154                        break;
 155                }
 156        }
 157        spin_unlock(&cx->v4l2_dev.lock);
 158        return result;
 159}
 160
 161static void cx18_setscl(void *data, int state)
 162{
 163        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
 164        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 165        u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
 166        u32 r = cx18_read_reg(cx, addr);
 167
 168        if (state)
 169                cx18_write_reg(cx, r | SETSCL_BIT, addr);
 170        else
 171                cx18_write_reg(cx, r & ~SETSCL_BIT, addr);
 172}
 173
 174static void cx18_setsda(void *data, int state)
 175{
 176        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
 177        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 178        u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
 179        u32 r = cx18_read_reg(cx, addr);
 180
 181        if (state)
 182                cx18_write_reg(cx, r | SETSDL_BIT, addr);
 183        else
 184                cx18_write_reg(cx, r & ~SETSDL_BIT, addr);
 185}
 186
 187static int cx18_getscl(void *data)
 188{
 189        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
 190        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 191        u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 192
 193        return cx18_read_reg(cx, addr) & GETSCL_BIT;
 194}
 195
 196static int cx18_getsda(void *data)
 197{
 198        struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
 199        int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
 200        u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
 201
 202        return cx18_read_reg(cx, addr) & GETSDL_BIT;
 203}
 204
 205/* template for i2c-bit-algo */
 206static const struct i2c_adapter cx18_i2c_adap_template = {
 207        .name = "cx18 i2c driver",
 208        .algo = NULL,                   /* set by i2c-algo-bit */
 209        .algo_data = NULL,              /* filled from template */
 210        .owner = THIS_MODULE,
 211};
 212
 213#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
 214#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
 215
 216static const struct i2c_algo_bit_data cx18_i2c_algo_template = {
 217        .setsda         = cx18_setsda,
 218        .setscl         = cx18_setscl,
 219        .getsda         = cx18_getsda,
 220        .getscl         = cx18_getscl,
 221        .udelay         = CX18_SCL_PERIOD/2,       /* 1/2 clock period in usec*/
 222        .timeout        = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
 223};
 224
 225/* init + register i2c adapter */
 226int init_cx18_i2c(struct cx18 *cx)
 227{
 228        int i, err;
 229        CX18_DEBUG_I2C("i2c init\n");
 230
 231        for (i = 0; i < 2; i++) {
 232                /* Setup algorithm for adapter */
 233                cx->i2c_algo[i] = cx18_i2c_algo_template;
 234                cx->i2c_algo_cb_data[i].cx = cx;
 235                cx->i2c_algo_cb_data[i].bus_index = i;
 236                cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
 237
 238                /* Setup adapter */
 239                cx->i2c_adap[i] = cx18_i2c_adap_template;
 240                cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
 241                sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
 242                                " #%d-%d", cx->instance, i);
 243                i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev);
 244                cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev;
 245        }
 246
 247        if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
 248                /* Reset/Unreset I2C hardware block */
 249                /* Clock select 220MHz */
 250                cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
 251                                          0x00000000, 0x10001000);
 252                /* Clock Enable */
 253                cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
 254                                          0x00001000, 0x10001000);
 255        }
 256        /* courtesy of Steven Toth <stoth@hauppauge.com> */
 257        cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
 258        mdelay(10);
 259        cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
 260        mdelay(10);
 261        cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
 262        mdelay(10);
 263
 264        /* Set to edge-triggered intrs. */
 265        cx18_write_reg(cx, 0x00c00000, 0xc730c8);
 266        /* Clear any stale intrs */
 267        cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
 268                       ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);
 269
 270        /* Hw I2C1 Clock Freq ~100kHz */
 271        cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
 272        cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
 273        cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
 274
 275        /* Hw I2C2 Clock Freq ~100kHz */
 276        cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
 277        cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
 278        cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 279
 280        cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
 281                     core, reset, (u32) CX18_GPIO_RESET_I2C);
 282
 283        err = i2c_bit_add_bus(&cx->i2c_adap[0]);
 284        if (err)
 285                goto err;
 286        err = i2c_bit_add_bus(&cx->i2c_adap[1]);
 287        if (err)
 288                goto err_del_bus_0;
 289        return 0;
 290
 291 err_del_bus_0:
 292        i2c_del_adapter(&cx->i2c_adap[0]);
 293 err:
 294        return err;
 295}
 296
 297void exit_cx18_i2c(struct cx18 *cx)
 298{
 299        int i;
 300        CX18_DEBUG_I2C("i2c exit\n");
 301        cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4,
 302                                                        CX18_REG_I2C_1_WR);
 303        cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4,
 304                                                        CX18_REG_I2C_2_WR);
 305
 306        for (i = 0; i < 2; i++) {
 307                i2c_del_adapter(&cx->i2c_adap[i]);
 308        }
 309}
 310
 311/*
 312   Hauppauge HVR1600 should have:
 313   32 cx24227
 314   98 unknown
 315   a0 eeprom
 316   c2 tuner
 317   e? zilog ir
 318   */
 319