blob: 4720d79b0282398d06feb6c85dbdfd42d06e5ea8 [file] [log] [blame]
Janne Grunau9aba42e2009-03-18 18:10:04 -03001
2/*
Janne Grunaue86da6f2009-03-19 19:00:35 -03003 * Hauppauge HD PVR USB driver
Janne Grunau9aba42e2009-03-18 18:10:04 -03004 *
5 * Copyright (C) 2008 Janne Grunau (j@jannau.net)
6 *
Andy Wallsea6c0602010-12-28 22:46:13 -03007 * IR device registration code is
8 * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
9 *
Janne Grunau9aba42e2009-03-18 18:10:04 -030010 * 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
Peter Senna Tschudin6a29b802013-01-19 19:41:30 -030016#if IS_ENABLED(CONFIG_I2C)
Jarod Wilson324b04b2011-01-14 16:25:21 -030017
Janne Grunau9aba42e2009-03-18 18:10:04 -030018#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
Paul Gortmaker35a24632011-08-01 15:26:38 -040020#include <linux/export.h>
Janne Grunau9aba42e2009-03-18 18:10:04 -030021
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
Andy Wallsea6c0602010-12-28 22:46:13 -030031#define Z8F0811_IR_TX_I2C_ADDR 0x70
32#define Z8F0811_IR_RX_I2C_ADDR 0x71
33
Jarod Wilson324b04b2011-01-14 16:25:21 -030034
Sean Youngab5222e2017-10-12 18:02:57 -040035struct i2c_client *hdpvr_register_ir_i2c(struct hdpvr_device *dev)
Andy Wallsea6c0602010-12-28 22:46:13 -030036{
Jarod Wilson324b04b2011-01-14 16:25:21 -030037 struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
Sean Youngab5222e2017-10-12 18:02:57 -040038 struct i2c_board_info info = {
39 I2C_BOARD_INFO("ir_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
Jarod Wilson7f2a06d2011-01-19 18:10:14 -030040 };
Andy Wallsea6c0602010-12-28 22:46:13 -030041
Jarod Wilson324b04b2011-01-14 16:25:21 -030042 /* Our default information for ir-kbd-i2c.c to use */
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -030043 init_data->ir_codes = RC_MAP_HAUPPAUGE;
Jarod Wilson324b04b2011-01-14 16:25:21 -030044 init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
Sean Young6d741bf2017-08-07 16:20:58 -040045 init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
46 RC_PROTO_BIT_RC6_6A_32;
Jarod Wilson7f2a06d2011-01-19 18:10:14 -030047 init_data->name = "HD-PVR";
Jarod Wilsondc8e2aa2011-03-04 17:31:11 -030048 init_data->polling_interval = 405; /* ms, duplicated from Windows */
Sean Youngab5222e2017-10-12 18:02:57 -040049 info.platform_data = init_data;
Andy Wallsea6c0602010-12-28 22:46:13 -030050
Sean Youngab5222e2017-10-12 18:02:57 -040051 return i2c_new_device(&dev->i2c_adapter, &info);
Andy Wallsea6c0602010-12-28 22:46:13 -030052}
53
Jarod Wilson324b04b2011-01-14 16:25:21 -030054static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
Jarod Wilsonb443ac52011-03-02 13:23:52 -030055 unsigned char addr, char *wdata, int wlen,
56 char *data, int len)
Janne Grunau9aba42e2009-03-18 18:10:04 -030057{
58 int ret;
Jarod Wilson559d1622011-01-14 16:40:32 -030059
Jarod Wilsonb443ac52011-03-02 13:23:52 -030060 if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf)))
Jarod Wilson559d1622011-01-14 16:40:32 -030061 return -EINVAL;
Janne Grunau9aba42e2009-03-18 18:10:04 -030062
Jarod Wilsonb443ac52011-03-02 13:23:52 -030063 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),
Janne Grunau9aba42e2009-03-18 18:10:04 -030074 REQTYPE_I2C_READ, CTRL_READ_REQUEST,
Jarod Wilson559d1622011-01-14 16:40:32 -030075 (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
Janne Grunau9aba42e2009-03-18 18:10:04 -030076
77 if (ret == len) {
Jarod Wilson559d1622011-01-14 16:40:32 -030078 memcpy(data, &dev->i2c_buf, len);
Janne Grunau9aba42e2009-03-18 18:10:04 -030079 ret = 0;
80 } else if (ret >= 0)
81 ret = -EIO;
82
Janne Grunau9aba42e2009-03-18 18:10:04 -030083 return ret;
84}
85
Jarod Wilson324b04b2011-01-14 16:25:21 -030086static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
87 unsigned char addr, char *data, int len)
Janne Grunau9aba42e2009-03-18 18:10:04 -030088{
89 int ret;
Janne Grunau9aba42e2009-03-18 18:10:04 -030090
Jarod Wilson559d1622011-01-14 16:40:32 -030091 if (len > sizeof(dev->i2c_buf))
92 return -EINVAL;
93
94 memcpy(&dev->i2c_buf, data, len);
Jarod Wilsonb443ac52011-03-02 13:23:52 -030095 ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
Janne Grunau9aba42e2009-03-18 18:10:04 -030096 REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
Jarod Wilson559d1622011-01-14 16:40:32 -030097 (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
Janne Grunau9aba42e2009-03-18 18:10:04 -030098
99 if (ret < 0)
Jarod Wilson559d1622011-01-14 16:40:32 -0300100 return ret;
Janne Grunau9aba42e2009-03-18 18:10:04 -0300101
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300102 ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
Janne Grunau9aba42e2009-03-18 18:10:04 -0300103 REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
Jarod Wilson559d1622011-01-14 16:40:32 -0300104 0, 0, &dev->i2c_buf, 2, 1000);
Janne Grunau9aba42e2009-03-18 18:10:04 -0300105
Jarod Wilson559d1622011-01-14 16:40:32 -0300106 if ((ret == 2) && (dev->i2c_buf[1] == (len - 1)))
Janne Grunau9aba42e2009-03-18 18:10:04 -0300107 ret = 0;
108 else if (ret >= 0)
109 ret = -EIO;
110
Janne Grunau9aba42e2009-03-18 18:10:04 -0300111 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);
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300118 int retval = 0, addr;
Janne Grunau9aba42e2009-03-18 18:10:04 -0300119
120 if (num <= 0)
121 return 0;
122
123 mutex_lock(&dev->i2c_mutex);
124
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300125 addr = msgs[0].addr << 1;
Janne Grunau9aba42e2009-03-18 18:10:04 -0300126
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300127 if (num == 1) {
128 if (msgs[0].flags & I2C_M_RD)
129 retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0,
130 msgs[0].buf, msgs[0].len);
Janne Grunau9aba42e2009-03-18 18:10:04 -0300131 else
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300132 retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf,
133 msgs[0].len);
134 } else if (num == 2) {
135 if (msgs[0].addr != msgs[1].addr) {
Mauro Carvalho Chehab4d5ded72016-10-18 17:44:17 -0200136 v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n");
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300137 retval = -EINVAL;
138 goto out;
139 }
140
141 if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) {
Mauro Carvalho Chehab4d5ded72016-10-18 17:44:17 -0200142 v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n",
143 msgs[0].flags & I2C_M_RD,
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300144 msgs[1].flags & I2C_M_RD);
145 retval = -EINVAL;
146 goto out;
147 }
148
149 /*
150 * Write followed by atomic read is the only complex xfer that
151 * we actually support here.
152 */
153 retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len,
154 msgs[1].buf, msgs[1].len);
155 } else {
156 v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num);
Janne Grunau9aba42e2009-03-18 18:10:04 -0300157 }
158
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300159out:
Janne Grunau9aba42e2009-03-18 18:10:04 -0300160 mutex_unlock(&dev->i2c_mutex);
161
162 return retval ? retval : num;
163}
164
165static u32 hdpvr_functionality(struct i2c_adapter *adapter)
166{
167 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
168}
169
Julia Lawall78f2c502016-08-29 10:12:01 -0300170static const struct i2c_algorithm hdpvr_algo = {
Janne Grunau9aba42e2009-03-18 18:10:04 -0300171 .master_xfer = hdpvr_transfer,
172 .functionality = hdpvr_functionality,
173};
174
Bhumika Goyal68438682017-08-19 06:34:15 -0400175static const struct i2c_adapter hdpvr_i2c_adapter_template = {
Jarod Wilson324b04b2011-01-14 16:25:21 -0300176 .name = "Hauppage HD PVR I2C",
177 .owner = THIS_MODULE,
178 .algo = &hdpvr_algo,
179};
180
181static int hdpvr_activate_ir(struct hdpvr_device *dev)
182{
Jarod Wilsondc8e2aa2011-03-04 17:31:11 -0300183 char buffer[2];
Jarod Wilson324b04b2011-01-14 16:25:21 -0300184
185 mutex_lock(&dev->i2c_mutex);
186
Jarod Wilsonb443ac52011-03-02 13:23:52 -0300187 hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1);
Jarod Wilson324b04b2011-01-14 16:25:21 -0300188
189 buffer[0] = 0;
190 buffer[1] = 0x8;
191 hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
192
193 buffer[1] = 0x18;
194 hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
195
196 mutex_unlock(&dev->i2c_mutex);
197
198 return 0;
199}
200
Janne Grunau9aba42e2009-03-18 18:10:04 -0300201int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
202{
Janne Grunau9aba42e2009-03-18 18:10:04 -0300203 int retval = -ENOMEM;
204
Jarod Wilson324b04b2011-01-14 16:25:21 -0300205 hdpvr_activate_ir(dev);
Janne Grunau9aba42e2009-03-18 18:10:04 -0300206
Ezequiel Garciad486b942012-10-23 15:57:10 -0300207 dev->i2c_adapter = hdpvr_i2c_adapter_template;
Jarod Wilson324b04b2011-01-14 16:25:21 -0300208 dev->i2c_adapter.dev.parent = &dev->udev->dev;
Janne Grunau9aba42e2009-03-18 18:10:04 -0300209
Jarod Wilson324b04b2011-01-14 16:25:21 -0300210 i2c_set_adapdata(&dev->i2c_adapter, dev);
Janne Grunau9aba42e2009-03-18 18:10:04 -0300211
Jarod Wilson324b04b2011-01-14 16:25:21 -0300212 retval = i2c_add_adapter(&dev->i2c_adapter);
Janne Grunau9aba42e2009-03-18 18:10:04 -0300213
Janne Grunau9aba42e2009-03-18 18:10:04 -0300214 return retval;
215}
Jarod Wilson324b04b2011-01-14 16:25:21 -0300216
217#endif