Linux-libre 2.6.32.6-gnu1
[librecmc/linux-libre.git] / drivers / media / video / hdpvr / hdpvr-i2c.c
1
2 /*
3  * Hauppauge HD PVR USB driver
4  *
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>
14
15 #include "hdpvr.h"
16
17 #define CTRL_READ_REQUEST       0xb8
18 #define CTRL_WRITE_REQUEST      0x38
19
20 #define REQTYPE_I2C_READ        0xb1
21 #define REQTYPE_I2C_WRITE       0xb0
22 #define REQTYPE_I2C_WRITE_STATT 0xd0
23
24 static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
25                           char *data, int len)
26 {
27         int ret;
28         char *buf = kmalloc(len, GFP_KERNEL);
29         if (!buf)
30                 return -ENOMEM;
31
32         ret = usb_control_msg(dev->udev,
33                               usb_rcvctrlpipe(dev->udev, 0),
34                               REQTYPE_I2C_READ, CTRL_READ_REQUEST,
35                               0x100|addr, 0, buf, len, 1000);
36
37         if (ret == len) {
38                 memcpy(data, buf, len);
39                 ret = 0;
40         } else if (ret >= 0)
41                 ret = -EIO;
42
43         kfree(buf);
44
45         return ret;
46 }
47
48 static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
49                            char *data, int len)
50 {
51         int ret;
52         char *buf = kmalloc(len, GFP_KERNEL);
53         if (!buf)
54                 return -ENOMEM;
55
56         memcpy(buf, data, len);
57         ret = usb_control_msg(dev->udev,
58                               usb_sndctrlpipe(dev->udev, 0),
59                               REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
60                               0x100|addr, 0, buf, len, 1000);
61
62         if (ret < 0)
63                 goto error;
64
65         ret = usb_control_msg(dev->udev,
66                               usb_rcvctrlpipe(dev->udev, 0),
67                               REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
68                               0, 0, buf, 2, 1000);
69
70         if (ret == 2)
71                 ret = 0;
72         else if (ret >= 0)
73                 ret = -EIO;
74
75 error:
76         kfree(buf);
77         return ret;
78 }
79
80 static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
81                           int num)
82 {
83         struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
84         int retval = 0, i, addr;
85
86         if (num <= 0)
87                 return 0;
88
89         mutex_lock(&dev->i2c_mutex);
90
91         for (i = 0; i < num && !retval; i++) {
92                 addr = msgs[i].addr << 1;
93
94                 if (msgs[i].flags & I2C_M_RD)
95                         retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
96                                                 msgs[i].len);
97                 else
98                         retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
99                                                  msgs[i].len);
100         }
101
102         mutex_unlock(&dev->i2c_mutex);
103
104         return retval ? retval : num;
105 }
106
107 static u32 hdpvr_functionality(struct i2c_adapter *adapter)
108 {
109         return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
110 }
111
112 static struct i2c_algorithm hdpvr_algo = {
113         .master_xfer   = hdpvr_transfer,
114         .functionality = hdpvr_functionality,
115 };
116
117 int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
118 {
119         struct i2c_adapter *i2c_adap;
120         int retval = -ENOMEM;
121
122         i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
123         if (i2c_adap == NULL)
124                 goto error;
125
126         strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
127                 sizeof(i2c_adap->name));
128         i2c_adap->algo  = &hdpvr_algo;
129         i2c_adap->class = I2C_CLASS_TV_ANALOG;
130         i2c_adap->owner = THIS_MODULE;
131         i2c_adap->dev.parent = &dev->udev->dev;
132
133         i2c_set_adapdata(i2c_adap, dev);
134
135         retval = i2c_add_adapter(i2c_adap);
136
137         if (!retval)
138                 dev->i2c_adapter = i2c_adap;
139         else
140                 kfree(i2c_adap);
141
142 error:
143         return retval;
144 }