Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/dvb-usb/ce6230.c
15111 views
1
/*
2
* DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
3
*
4
* Copyright (C) 2009 Antti Palosaari <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
*
20
*/
21
22
#include "ce6230.h"
23
#include "zl10353.h"
24
#include "mxl5005s.h"
25
26
/* debug */
27
static int dvb_usb_ce6230_debug;
28
module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
29
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
30
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
31
32
static struct zl10353_config ce6230_zl10353_config;
33
34
static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
35
{
36
int ret;
37
unsigned int pipe;
38
u8 request;
39
u8 requesttype;
40
u16 value;
41
u16 index;
42
u8 *buf;
43
44
request = req->cmd;
45
value = req->value;
46
index = req->index;
47
48
switch (req->cmd) {
49
case I2C_READ:
50
case DEMOD_READ:
51
case REG_READ:
52
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
53
break;
54
case I2C_WRITE:
55
case DEMOD_WRITE:
56
case REG_WRITE:
57
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
58
break;
59
default:
60
err("unknown command:%02x", req->cmd);
61
ret = -EPERM;
62
goto error;
63
}
64
65
buf = kmalloc(req->data_len, GFP_KERNEL);
66
if (!buf) {
67
ret = -ENOMEM;
68
goto error;
69
}
70
71
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
72
/* write */
73
memcpy(buf, req->data, req->data_len);
74
pipe = usb_sndctrlpipe(udev, 0);
75
} else {
76
/* read */
77
pipe = usb_rcvctrlpipe(udev, 0);
78
}
79
80
msleep(1); /* avoid I2C errors */
81
82
ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
83
buf, req->data_len, CE6230_USB_TIMEOUT);
84
85
ce6230_debug_dump(request, requesttype, value, index, buf,
86
req->data_len, deb_xfer);
87
88
if (ret < 0)
89
deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
90
else
91
ret = 0;
92
93
/* read request, copy returned data to return buf */
94
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
95
memcpy(req->data, buf, req->data_len);
96
97
kfree(buf);
98
error:
99
return ret;
100
}
101
102
static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
103
{
104
return ce6230_rw_udev(d->udev, req);
105
}
106
107
/* I2C */
108
static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
109
int num)
110
{
111
struct dvb_usb_device *d = i2c_get_adapdata(adap);
112
int i = 0;
113
struct req_t req;
114
int ret = 0;
115
memset(&req, 0, sizeof(req));
116
117
if (num > 2)
118
return -EINVAL;
119
120
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
121
return -EAGAIN;
122
123
while (i < num) {
124
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
125
if (msg[i].addr ==
126
ce6230_zl10353_config.demod_address) {
127
req.cmd = DEMOD_READ;
128
req.value = msg[i].addr >> 1;
129
req.index = msg[i].buf[0];
130
req.data_len = msg[i+1].len;
131
req.data = &msg[i+1].buf[0];
132
ret = ce6230_ctrl_msg(d, &req);
133
} else {
134
err("i2c read not implemented");
135
ret = -EPERM;
136
}
137
i += 2;
138
} else {
139
if (msg[i].addr ==
140
ce6230_zl10353_config.demod_address) {
141
req.cmd = DEMOD_WRITE;
142
req.value = msg[i].addr >> 1;
143
req.index = msg[i].buf[0];
144
req.data_len = msg[i].len-1;
145
req.data = &msg[i].buf[1];
146
ret = ce6230_ctrl_msg(d, &req);
147
} else {
148
req.cmd = I2C_WRITE;
149
req.value = 0x2000 + (msg[i].addr >> 1);
150
req.index = 0x0000;
151
req.data_len = msg[i].len;
152
req.data = &msg[i].buf[0];
153
ret = ce6230_ctrl_msg(d, &req);
154
}
155
i += 1;
156
}
157
if (ret)
158
break;
159
}
160
161
mutex_unlock(&d->i2c_mutex);
162
return ret ? ret : i;
163
}
164
165
static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
166
{
167
return I2C_FUNC_I2C;
168
}
169
170
static struct i2c_algorithm ce6230_i2c_algo = {
171
.master_xfer = ce6230_i2c_xfer,
172
.functionality = ce6230_i2c_func,
173
};
174
175
/* Callbacks for DVB USB */
176
static struct zl10353_config ce6230_zl10353_config = {
177
.demod_address = 0x1e,
178
.adc_clock = 450000,
179
.if2 = 45700,
180
.no_tuner = 1,
181
.parallel_ts = 1,
182
.clock_ctl_1 = 0x34,
183
.pll_0 = 0x0e,
184
};
185
186
static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
187
{
188
deb_info("%s:\n", __func__);
189
adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
190
&adap->dev->i2c_adap);
191
if (adap->fe == NULL)
192
return -ENODEV;
193
return 0;
194
}
195
196
static struct mxl5005s_config ce6230_mxl5003s_config = {
197
.i2c_address = 0xc6,
198
.if_freq = IF_FREQ_4570000HZ,
199
.xtal_freq = CRYSTAL_FREQ_16000000HZ,
200
.agc_mode = MXL_SINGLE_AGC,
201
.tracking_filter = MXL_TF_DEFAULT,
202
.rssi_enable = MXL_RSSI_ENABLE,
203
.cap_select = MXL_CAP_SEL_ENABLE,
204
.div_out = MXL_DIV_OUT_4,
205
.clock_out = MXL_CLOCK_OUT_DISABLE,
206
.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
207
.top = MXL5005S_TOP_25P2,
208
.mod_mode = MXL_DIGITAL_MODE,
209
.if_mode = MXL_ZERO_IF,
210
.AgcMasterByte = 0x00,
211
};
212
213
static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
214
{
215
int ret;
216
deb_info("%s:\n", __func__);
217
ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
218
&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
219
return ret;
220
}
221
222
static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
223
{
224
int ret;
225
deb_info("%s: onoff:%d\n", __func__, onoff);
226
227
/* InterfaceNumber 1 / AlternateSetting 0 idle
228
InterfaceNumber 1 / AlternateSetting 1 streaming */
229
ret = usb_set_interface(d->udev, 1, onoff);
230
if (ret)
231
err("usb_set_interface failed with error:%d", ret);
232
233
return ret;
234
}
235
236
/* DVB USB Driver stuff */
237
static struct dvb_usb_device_properties ce6230_properties;
238
239
static int ce6230_probe(struct usb_interface *intf,
240
const struct usb_device_id *id)
241
{
242
int ret = 0;
243
struct dvb_usb_device *d = NULL;
244
245
deb_info("%s: interface:%d\n", __func__,
246
intf->cur_altsetting->desc.bInterfaceNumber);
247
248
if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
249
ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
250
&d, adapter_nr);
251
if (ret)
252
err("init failed with error:%d\n", ret);
253
}
254
255
return ret;
256
}
257
258
static struct usb_device_id ce6230_table[] = {
259
{ USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
260
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
261
{ } /* Terminating entry */
262
};
263
MODULE_DEVICE_TABLE(usb, ce6230_table);
264
265
static struct dvb_usb_device_properties ce6230_properties = {
266
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
267
268
.usb_ctrl = DEVICE_SPECIFIC,
269
.no_reconnect = 1,
270
271
.size_of_priv = 0,
272
273
.num_adapters = 1,
274
.adapter = {
275
{
276
.frontend_attach = ce6230_zl10353_frontend_attach,
277
.tuner_attach = ce6230_mxl5003s_tuner_attach,
278
.stream = {
279
.type = USB_BULK,
280
.count = 6,
281
.endpoint = 0x82,
282
.u = {
283
.bulk = {
284
.buffersize = (16*512),
285
}
286
}
287
},
288
}
289
},
290
291
.power_ctrl = ce6230_power_ctrl,
292
293
.i2c_algo = &ce6230_i2c_algo,
294
295
.num_device_descs = 2,
296
.devices = {
297
{
298
.name = "Intel CE9500 reference design",
299
.cold_ids = {NULL},
300
.warm_ids = {&ce6230_table[0], NULL},
301
},
302
{
303
.name = "AVerMedia A310 USB 2.0 DVB-T tuner",
304
.cold_ids = {NULL},
305
.warm_ids = {&ce6230_table[1], NULL},
306
},
307
}
308
};
309
310
static struct usb_driver ce6230_driver = {
311
.name = "dvb_usb_ce6230",
312
.probe = ce6230_probe,
313
.disconnect = dvb_usb_device_exit,
314
.id_table = ce6230_table,
315
};
316
317
/* module stuff */
318
static int __init ce6230_module_init(void)
319
{
320
int ret;
321
deb_info("%s:\n", __func__);
322
ret = usb_register(&ce6230_driver);
323
if (ret)
324
err("usb_register failed with error:%d", ret);
325
326
return ret;
327
}
328
329
static void __exit ce6230_module_exit(void)
330
{
331
deb_info("%s:\n", __func__);
332
/* deregister this driver from the USB subsystem */
333
usb_deregister(&ce6230_driver);
334
}
335
336
module_init(ce6230_module_init);
337
module_exit(ce6230_module_exit);
338
339
MODULE_AUTHOR("Antti Palosaari <[email protected]>");
340
MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
341
MODULE_LICENSE("GPL");
342
343