linux/drivers/media/usb/hdpvr/hdpvr-i2c.c
<<
>>
Prefs
   1
   2/*
   3 * Hauppauge HD PVR USB driver
   4 *
   5 * Copyright (C) 2008      Janne Grunau (j@jannau.net)
   6 *
   7 * IR device registration code is
   8 * Copyright (C) 2010   Andy Walls <awalls@md.metrocast.net>
   9 *
  10 *      This program is free software; you can redistribute it and/or
  11 *      modify it under the terms of the GNU General Public License as
  12 *      published by the Free Software Foundation, version 2.
  13 *
  14 */
  15
  16#if IS_ENABLED(CONFIG_I2C)
  17
  18#include <linux/i2c.h>
  19#include <linux/slab.h>
  20#include <linux/export.h>
  21
  22#include "hdpvr.h"
  23
  24#define CTRL_READ_REQUEST       0xb8
  25#define CTRL_WRITE_REQUEST      0x38
  26
  27#define REQTYPE_I2C_READ        0xb1
  28#define REQTYPE_I2C_WRITE       0xb0
  29#define REQTYPE_I2C_WRITE_STATT 0xd0
  30
  31#define Z8F0811_IR_TX_I2C_ADDR  0x70
  32#define Z8F0811_IR_RX_I2C_ADDR  0x71
  33
  34
  35struct i2c_client *hdpvr_register_ir_i2c(struct hdpvr_device *dev)
  36{
  37        struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
  38        struct i2c_board_info info = {
  39                I2C_BOARD_INFO("ir_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
  40        };
  41
  42        /* Our default information for ir-kbd-i2c.c to use */
  43        init_data->ir_codes = RC_MAP_HAUPPAUGE;
  44        init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
  45        init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
  46                          RC_PROTO_BIT_RC6_6A_32;
  47        init_data->name = "HD-PVR";
  48        init_data->polling_interval = 405; /* ms, duplicated from Windows */
  49        info.platform_data = init_data;
  50
  51        return i2c_new_device(&dev->i2c_adapter, &info);
  52}
  53
  54static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
  55                          unsigned char addr, char *wdata, int wlen,
  56                          char *data, int len)
  57{
  58        int ret;
  59
  60        if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf)))
  61                return -EINVAL;
  62
  63        if (wlen) {
  64                memcpy(&dev->i2c_buf, wdata, wlen);
  65                ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
  66                                      REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
  67                                      (bus << 8) | addr, 0, &dev->i2c_buf,
  68                                      wlen, 1000);
  69                if (ret < 0)
  70                        return ret;
  71        }
  72
  73        ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
  74                              REQTYPE_I2C_READ, CTRL_READ_REQUEST,
  75                              (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
  76
  77        if (ret == len) {
  78                memcpy(data, &dev->i2c_buf, len);
  79                ret = 0;
  80        } else if (ret >= 0)
  81                ret = -EIO;
  82
  83        return ret;
  84}
  85
  86static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
  87                           unsigned char addr, char *data, int len)
  88{
  89        int ret;
  90
  91        if (len > sizeof(dev->i2c_buf))
  92                return -EINVAL;
  93
  94        memcpy(&dev->i2c_buf, data, len);
  95        ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
  96                              REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
  97                              (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
  98
  99        if (ret < 0)
 100                return ret;
 101
 102        ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
 103                              REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
 104                              0, 0, &dev->i2c_buf, 2, 1000);
 105
 106        if ((ret == 2) && (dev->i2c_buf[1] == (len - 1)))
 107                ret = 0;
 108        else if (ret >= 0)
 109                ret = -EIO;
 110
 111        return ret;
 112}
 113
 114static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
 115                          int num)
 116{
 117        struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
 118        int retval = 0, addr;
 119
 120        mutex_lock(&dev->i2c_mutex);
 121
 122        addr = msgs[0].addr << 1;
 123
 124        if (num == 1) {
 125                if (msgs[0].flags & I2C_M_RD)
 126                        retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0,
 127                                                msgs[0].buf, msgs[0].len);
 128                else
 129                        retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf,
 130                                                 msgs[0].len);
 131        } else if (num == 2) {
 132                if (msgs[0].addr != msgs[1].addr) {
 133                        v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n");
 134                        retval = -EINVAL;
 135                        goto out;
 136                }
 137
 138                if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) {
 139                        v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n",
 140                                  msgs[0].flags & I2C_M_RD,
 141                                  msgs[1].flags & I2C_M_RD);
 142                        retval = -EINVAL;
 143                        goto out;
 144                }
 145
 146                /*
 147                 * Write followed by atomic read is the only complex xfer that
 148                 * we actually support here.
 149                 */
 150                retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len,
 151                                        msgs[1].buf, msgs[1].len);
 152        } else {
 153                v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num);
 154        }
 155
 156out:
 157        mutex_unlock(&dev->i2c_mutex);
 158
 159        return retval ? retval : num;
 160}
 161
 162static u32 hdpvr_functionality(struct i2c_adapter *adapter)
 163{
 164        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 165}
 166
 167static const struct i2c_algorithm hdpvr_algo = {
 168        .master_xfer   = hdpvr_transfer,
 169        .functionality = hdpvr_functionality,
 170};
 171
 172static const struct i2c_adapter hdpvr_i2c_adapter_template = {
 173        .name   = "Hauppauge HD PVR I2C",
 174        .owner  = THIS_MODULE,
 175        .algo   = &hdpvr_algo,
 176};
 177
 178static int hdpvr_activate_ir(struct hdpvr_device *dev)
 179{
 180        char buffer[2];
 181
 182        mutex_lock(&dev->i2c_mutex);
 183
 184        hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1);
 185
 186        buffer[0] = 0;
 187        buffer[1] = 0x8;
 188        hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
 189
 190        buffer[1] = 0x18;
 191        hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
 192
 193        mutex_unlock(&dev->i2c_mutex);
 194
 195        return 0;
 196}
 197
 198int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
 199{
 200        int retval = -ENOMEM;
 201
 202        hdpvr_activate_ir(dev);
 203
 204        dev->i2c_adapter = hdpvr_i2c_adapter_template;
 205        dev->i2c_adapter.dev.parent = &dev->udev->dev;
 206
 207        i2c_set_adapdata(&dev->i2c_adapter, dev);
 208
 209        retval = i2c_add_adapter(&dev->i2c_adapter);
 210
 211        return retval;
 212}
 213
 214#endif
 215