Merge branch 'fix/asoc' into for-linus
[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  * 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 #include <linux/i2c.h>
17 #include <linux/slab.h>
18
19 #include "hdpvr.h"
20
21 #define CTRL_READ_REQUEST       0xb8
22 #define CTRL_WRITE_REQUEST      0x38
23
24 #define REQTYPE_I2C_READ        0xb1
25 #define REQTYPE_I2C_WRITE       0xb0
26 #define REQTYPE_I2C_WRITE_STATT 0xd0
27
28 #define Z8F0811_IR_TX_I2C_ADDR  0x70
29 #define Z8F0811_IR_RX_I2C_ADDR  0x71
30
31 static const u8 ir_i2c_addrs[] = {
32         Z8F0811_IR_TX_I2C_ADDR,
33         Z8F0811_IR_RX_I2C_ADDR,
34 };
35
36 static const char * const ir_devicenames[] = {
37         "ir_tx_z8f0811_hdpvr",
38         "ir_rx_z8f0811_hdpvr",
39 };
40
41 static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,
42                             const char *type, u8 addr)
43 {
44         struct i2c_board_info info;
45         struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
46         unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
47
48         memset(&info, 0, sizeof(struct i2c_board_info));
49         strlcpy(info.type, type, I2C_NAME_SIZE);
50
51         /* Our default information for ir-kbd-i2c.c to use */
52         switch (addr) {
53         case Z8F0811_IR_RX_I2C_ADDR:
54                 init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
55                 init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
56                 init_data->type = RC_TYPE_RC5;
57                 init_data->name = "HD PVR";
58                 info.platform_data = init_data;
59                 break;
60         }
61
62         return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
63                -1 : 0;
64 }
65
66 int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
67 {
68         int i;
69         int ret = 0;
70
71         for (i = 0; i < ARRAY_SIZE(ir_i2c_addrs); i++)
72                 ret += hdpvr_new_i2c_ir(dev, dev->i2c_adapter,
73                                         ir_devicenames[i], ir_i2c_addrs[i]);
74
75         return ret;
76 }
77
78 static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
79                           char *data, int len)
80 {
81         int ret;
82         char *buf = kmalloc(len, GFP_KERNEL);
83         if (!buf)
84                 return -ENOMEM;
85
86         ret = usb_control_msg(dev->udev,
87                               usb_rcvctrlpipe(dev->udev, 0),
88                               REQTYPE_I2C_READ, CTRL_READ_REQUEST,
89                               0x100|addr, 0, buf, len, 1000);
90
91         if (ret == len) {
92                 memcpy(data, buf, len);
93                 ret = 0;
94         } else if (ret >= 0)
95                 ret = -EIO;
96
97         kfree(buf);
98
99         return ret;
100 }
101
102 static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
103                            char *data, int len)
104 {
105         int ret;
106         char *buf = kmalloc(len, GFP_KERNEL);
107         if (!buf)
108                 return -ENOMEM;
109
110         memcpy(buf, data, len);
111         ret = usb_control_msg(dev->udev,
112                               usb_sndctrlpipe(dev->udev, 0),
113                               REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
114                               0x100|addr, 0, buf, len, 1000);
115
116         if (ret < 0)
117                 goto error;
118
119         ret = usb_control_msg(dev->udev,
120                               usb_rcvctrlpipe(dev->udev, 0),
121                               REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
122                               0, 0, buf, 2, 1000);
123
124         if (ret == 2)
125                 ret = 0;
126         else if (ret >= 0)
127                 ret = -EIO;
128
129 error:
130         kfree(buf);
131         return ret;
132 }
133
134 static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
135                           int num)
136 {
137         struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
138         int retval = 0, i, addr;
139
140         if (num <= 0)
141                 return 0;
142
143         mutex_lock(&dev->i2c_mutex);
144
145         for (i = 0; i < num && !retval; i++) {
146                 addr = msgs[i].addr << 1;
147
148                 if (msgs[i].flags & I2C_M_RD)
149                         retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
150                                                 msgs[i].len);
151                 else
152                         retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
153                                                  msgs[i].len);
154         }
155
156         mutex_unlock(&dev->i2c_mutex);
157
158         return retval ? retval : num;
159 }
160
161 static u32 hdpvr_functionality(struct i2c_adapter *adapter)
162 {
163         return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
164 }
165
166 static struct i2c_algorithm hdpvr_algo = {
167         .master_xfer   = hdpvr_transfer,
168         .functionality = hdpvr_functionality,
169 };
170
171 int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
172 {
173         struct i2c_adapter *i2c_adap;
174         int retval = -ENOMEM;
175
176         i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
177         if (i2c_adap == NULL)
178                 goto error;
179
180         strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
181                 sizeof(i2c_adap->name));
182         i2c_adap->algo  = &hdpvr_algo;
183         i2c_adap->owner = THIS_MODULE;
184         i2c_adap->dev.parent = &dev->udev->dev;
185
186         i2c_set_adapdata(i2c_adap, dev);
187
188         retval = i2c_add_adapter(i2c_adap);
189
190         if (!retval)
191                 dev->i2c_adapter = i2c_adap;
192         else
193                 kfree(i2c_adap);
194
195 error:
196         return retval;
197 }