Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.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 #include <linux/slab.h>
15
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
25 static 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
49 static 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
76 error:
77         kfree(buf);
78         return ret;
79 }
80
81 static 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
108 static u32 hdpvr_functionality(struct i2c_adapter *adapter)
109 {
110         return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
111 }
112
113 static struct i2c_algorithm hdpvr_algo = {
114         .master_xfer   = hdpvr_transfer,
115         .functionality = hdpvr_functionality,
116 };
117
118 int 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->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 }