blob: 463b81bef6e29585e2c3f0802adc40863f9845f2 [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 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, version 2.
10 *
11 */
12
13#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Janne Grunau9aba42e2009-03-18 18:10:04 -030015
16#include "hdpvr.h"
17
18#define CTRL_READ_REQUEST 0xb8
19#define CTRL_WRITE_REQUEST 0x38
20
21#define REQTYPE_I2C_READ 0xb1
22#define REQTYPE_I2C_WRITE 0xb0
23#define REQTYPE_I2C_WRITE_STATT 0xd0
24
25static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
26 char *data, int len)
27{
28 int ret;
29 char *buf = kmalloc(len, GFP_KERNEL);
30 if (!buf)
31 return -ENOMEM;
32
33 ret = usb_control_msg(dev->udev,
34 usb_rcvctrlpipe(dev->udev, 0),
35 REQTYPE_I2C_READ, CTRL_READ_REQUEST,
36 0x100|addr, 0, buf, len, 1000);
37
38 if (ret == len) {
39 memcpy(data, buf, len);
40 ret = 0;
41 } else if (ret >= 0)
42 ret = -EIO;
43
44 kfree(buf);
45
46 return ret;
47}
48
49static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
50 char *data, int len)
51{
52 int ret;
53 char *buf = kmalloc(len, GFP_KERNEL);
54 if (!buf)
55 return -ENOMEM;
56
57 memcpy(buf, data, len);
58 ret = usb_control_msg(dev->udev,
59 usb_sndctrlpipe(dev->udev, 0),
60 REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
61 0x100|addr, 0, buf, len, 1000);
62
63 if (ret < 0)
64 goto error;
65
66 ret = usb_control_msg(dev->udev,
67 usb_rcvctrlpipe(dev->udev, 0),
68 REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
69 0, 0, buf, 2, 1000);
70
71 if (ret == 2)
72 ret = 0;
73 else if (ret >= 0)
74 ret = -EIO;
75
76error:
77 kfree(buf);
78 return ret;
79}
80
81static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
82 int num)
83{
84 struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
85 int retval = 0, i, addr;
86
87 if (num <= 0)
88 return 0;
89
90 mutex_lock(&dev->i2c_mutex);
91
92 for (i = 0; i < num && !retval; i++) {
93 addr = msgs[i].addr << 1;
94
95 if (msgs[i].flags & I2C_M_RD)
96 retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
97 msgs[i].len);
98 else
99 retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
100 msgs[i].len);
101 }
102
103 mutex_unlock(&dev->i2c_mutex);
104
105 return retval ? retval : num;
106}
107
108static u32 hdpvr_functionality(struct i2c_adapter *adapter)
109{
110 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
111}
112
113static struct i2c_algorithm hdpvr_algo = {
114 .master_xfer = hdpvr_transfer,
115 .functionality = hdpvr_functionality,
116};
117
118int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
119{
120 struct i2c_adapter *i2c_adap;
121 int retval = -ENOMEM;
122
123 i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
124 if (i2c_adap == NULL)
125 goto error;
126
127 strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
128 sizeof(i2c_adap->name));
129 i2c_adap->algo = &hdpvr_algo;
130 i2c_adap->class = I2C_CLASS_TV_ANALOG;
Janne Grunau9aba42e2009-03-18 18:10:04 -0300131 i2c_adap->owner = THIS_MODULE;
132 i2c_adap->dev.parent = &dev->udev->dev;
133
134 i2c_set_adapdata(i2c_adap, dev);
135
136 retval = i2c_add_adapter(i2c_adap);
137
138 if (!retval)
139 dev->i2c_adapter = i2c_adap;
140 else
141 kfree(i2c_adap);
142
143error:
144 return retval;
145}