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