1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | |
3 | /* |
4 | * Hauppauge HD PVR USB driver |
5 | * |
6 | * Copyright (C) 2008 Janne Grunau (j@jannau.net) |
7 | * |
8 | * IR device registration code is |
9 | * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> |
10 | */ |
11 | |
12 | #if IS_ENABLED(CONFIG_I2C) |
13 | |
14 | #include <linux/i2c.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/export.h> |
17 | |
18 | #include "hdpvr.h" |
19 | |
20 | #define CTRL_READ_REQUEST 0xb8 |
21 | #define CTRL_WRITE_REQUEST 0x38 |
22 | |
23 | #define REQTYPE_I2C_READ 0xb1 |
24 | #define REQTYPE_I2C_WRITE 0xb0 |
25 | #define REQTYPE_I2C_WRITE_STATT 0xd0 |
26 | |
27 | #define Z8F0811_IR_TX_I2C_ADDR 0x70 |
28 | #define Z8F0811_IR_RX_I2C_ADDR 0x71 |
29 | |
30 | |
31 | struct i2c_client *hdpvr_register_ir_i2c(struct hdpvr_device *dev) |
32 | { |
33 | struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; |
34 | struct i2c_board_info info = { |
35 | I2C_BOARD_INFO("ir_z8f0811_hdpvr" , Z8F0811_IR_RX_I2C_ADDR), |
36 | }; |
37 | |
38 | /* Our default information for ir-kbd-i2c.c to use */ |
39 | init_data->ir_codes = RC_MAP_HAUPPAUGE; |
40 | init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; |
41 | init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | |
42 | RC_PROTO_BIT_RC6_6A_32; |
43 | init_data->name = "HD-PVR" ; |
44 | init_data->polling_interval = 405; /* ms, duplicated from Windows */ |
45 | info.platform_data = init_data; |
46 | |
47 | return i2c_new_client_device(adap: &dev->i2c_adapter, info: &info); |
48 | } |
49 | |
50 | static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, |
51 | unsigned char addr, char *wdata, int wlen, |
52 | char *data, int len) |
53 | { |
54 | int ret; |
55 | |
56 | if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf))) |
57 | return -EINVAL; |
58 | |
59 | if (wlen) { |
60 | memcpy(dev->i2c_buf, wdata, wlen); |
61 | ret = usb_control_msg(dev: dev->udev, usb_sndctrlpipe(dev->udev, 0), |
62 | REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, |
63 | value: (bus << 8) | addr, index: 0, data: dev->i2c_buf, |
64 | size: wlen, timeout: 1000); |
65 | if (ret < 0) |
66 | return ret; |
67 | } |
68 | |
69 | ret = usb_control_msg(dev: dev->udev, usb_rcvctrlpipe(dev->udev, 0), |
70 | REQTYPE_I2C_READ, CTRL_READ_REQUEST, |
71 | value: (bus << 8) | addr, index: 0, data: dev->i2c_buf, size: len, timeout: 1000); |
72 | |
73 | if (ret == len) { |
74 | memcpy(data, dev->i2c_buf, len); |
75 | ret = 0; |
76 | } else if (ret >= 0) |
77 | ret = -EIO; |
78 | |
79 | return ret; |
80 | } |
81 | |
82 | static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, |
83 | unsigned char addr, char *data, int len) |
84 | { |
85 | int ret; |
86 | |
87 | if (len > sizeof(dev->i2c_buf)) |
88 | return -EINVAL; |
89 | |
90 | memcpy(dev->i2c_buf, data, len); |
91 | ret = usb_control_msg(dev: dev->udev, usb_sndctrlpipe(dev->udev, 0), |
92 | REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, |
93 | value: (bus << 8) | addr, index: 0, data: dev->i2c_buf, size: len, timeout: 1000); |
94 | |
95 | if (ret < 0) |
96 | return ret; |
97 | |
98 | ret = usb_control_msg(dev: dev->udev, usb_rcvctrlpipe(dev->udev, 0), |
99 | REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, |
100 | value: 0, index: 0, data: dev->i2c_buf, size: 2, timeout: 1000); |
101 | |
102 | if ((ret == 2) && (dev->i2c_buf[1] == (len - 1))) |
103 | ret = 0; |
104 | else if (ret >= 0) |
105 | ret = -EIO; |
106 | |
107 | return ret; |
108 | } |
109 | |
110 | static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, |
111 | int num) |
112 | { |
113 | struct hdpvr_device *dev = i2c_get_adapdata(adap: i2c_adapter); |
114 | int retval = 0, addr; |
115 | |
116 | mutex_lock(&dev->i2c_mutex); |
117 | |
118 | addr = msgs[0].addr << 1; |
119 | |
120 | if (num == 1) { |
121 | if (msgs[0].flags & I2C_M_RD) |
122 | retval = hdpvr_i2c_read(dev, bus: 1, addr, NULL, wlen: 0, |
123 | data: msgs[0].buf, len: msgs[0].len); |
124 | else |
125 | retval = hdpvr_i2c_write(dev, bus: 1, addr, data: msgs[0].buf, |
126 | len: msgs[0].len); |
127 | } else if (num == 2) { |
128 | if (msgs[0].addr != msgs[1].addr) { |
129 | v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n" ); |
130 | retval = -EINVAL; |
131 | goto out; |
132 | } |
133 | |
134 | if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { |
135 | v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n" , |
136 | msgs[0].flags & I2C_M_RD, |
137 | msgs[1].flags & I2C_M_RD); |
138 | retval = -EINVAL; |
139 | goto out; |
140 | } |
141 | |
142 | /* |
143 | * Write followed by atomic read is the only complex xfer that |
144 | * we actually support here. |
145 | */ |
146 | retval = hdpvr_i2c_read(dev, bus: 1, addr, wdata: msgs[0].buf, wlen: msgs[0].len, |
147 | data: msgs[1].buf, len: msgs[1].len); |
148 | } else { |
149 | v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n" , num); |
150 | } |
151 | |
152 | out: |
153 | mutex_unlock(lock: &dev->i2c_mutex); |
154 | |
155 | return retval ? retval : num; |
156 | } |
157 | |
158 | static u32 hdpvr_functionality(struct i2c_adapter *adapter) |
159 | { |
160 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
161 | } |
162 | |
163 | static const struct i2c_algorithm hdpvr_algo = { |
164 | .master_xfer = hdpvr_transfer, |
165 | .functionality = hdpvr_functionality, |
166 | }; |
167 | |
168 | static const struct i2c_adapter hdpvr_i2c_adapter_template = { |
169 | .name = "Hauppauge HD PVR I2C" , |
170 | .owner = THIS_MODULE, |
171 | .algo = &hdpvr_algo, |
172 | }; |
173 | |
174 | static int hdpvr_activate_ir(struct hdpvr_device *dev) |
175 | { |
176 | char buffer[2]; |
177 | |
178 | mutex_lock(&dev->i2c_mutex); |
179 | |
180 | hdpvr_i2c_read(dev, bus: 0, addr: 0x54, NULL, wlen: 0, data: buffer, len: 1); |
181 | |
182 | buffer[0] = 0; |
183 | buffer[1] = 0x8; |
184 | hdpvr_i2c_write(dev, bus: 1, addr: 0x54, data: buffer, len: 2); |
185 | |
186 | buffer[1] = 0x18; |
187 | hdpvr_i2c_write(dev, bus: 1, addr: 0x54, data: buffer, len: 2); |
188 | |
189 | mutex_unlock(lock: &dev->i2c_mutex); |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) |
195 | { |
196 | hdpvr_activate_ir(dev); |
197 | |
198 | dev->i2c_adapter = hdpvr_i2c_adapter_template; |
199 | dev->i2c_adapter.dev.parent = &dev->udev->dev; |
200 | |
201 | i2c_set_adapdata(adap: &dev->i2c_adapter, data: dev); |
202 | |
203 | return i2c_add_adapter(adap: &dev->i2c_adapter); |
204 | } |
205 | |
206 | #endif |
207 | |