1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T 4 * 5 * Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com> 6 * http://royale.zerezo.com/dtv5100/ 7 * 8 * Inspired by gl861.c and au6610.c drivers 9 */ 10 11 #include "dtv5100.h" 12 #include "zl10353.h" 13 #include "qt1010.h" 14 15 /* debug */ 16 static int dvb_usb_dtv5100_debug; 17 module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); 18 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); 19 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 20 21 struct dtv5100_state { 22 unsigned char data[80]; 23 }; 24 25 static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, 26 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) 27 { 28 struct dtv5100_state *st = d->priv; 29 u8 request; 30 u8 type; 31 u16 value; 32 u16 index; 33 34 switch (wlen) { 35 case 1: 36 /* write { reg }, read { value } */ 37 request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : 38 DTV5100_TUNER_READ); 39 type = USB_TYPE_VENDOR | USB_DIR_IN; 40 value = 0; 41 break; 42 case 2: 43 /* write { reg, value } */ 44 request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : 45 DTV5100_TUNER_WRITE); 46 type = USB_TYPE_VENDOR | USB_DIR_OUT; 47 value = wbuf[1]; 48 break; 49 default: 50 warn("wlen = %x, aborting.", wlen); 51 return -EINVAL; 52 } 53 index = (addr << 8) + wbuf[0]; 54 55 memcpy(st->data, rbuf, rlen); 56 msleep(1); /* avoid I2C errors */ 57 return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, 58 type, value, index, st->data, rlen, 59 DTV5100_USB_TIMEOUT); 60 } 61 62 /* I2C */ 63 static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], 64 int num) 65 { 66 struct dvb_usb_device *d = i2c_get_adapdata(adap); 67 int i; 68 69 if (num > 2) 70 return -EINVAL; 71 72 if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 73 return -EAGAIN; 74 75 for (i = 0; i < num; i++) { 76 /* write/read request */ 77 if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { 78 if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, 79 msg[i].len, msg[i+1].buf, 80 msg[i+1].len) < 0) 81 break; 82 i++; 83 } else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, 84 msg[i].len, NULL, 0) < 0) 85 break; 86 } 87 88 mutex_unlock(&d->i2c_mutex); 89 return i; 90 } 91 92 static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) 93 { 94 return I2C_FUNC_I2C; 95 } 96 97 static struct i2c_algorithm dtv5100_i2c_algo = { 98 .master_xfer = dtv5100_i2c_xfer, 99 .functionality = dtv5100_i2c_func, 100 }; 101 102 /* Callbacks for DVB USB */ 103 static struct zl10353_config dtv5100_zl10353_config = { 104 .demod_address = DTV5100_DEMOD_ADDR, 105 .no_tuner = 1, 106 .parallel_ts = 1, 107 }; 108 109 static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) 110 { 111 adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, 112 &adap->dev->i2c_adap); 113 if (adap->fe_adap[0].fe == NULL) 114 return -EIO; 115 116 /* disable i2c gate, or it won't work... is this safe? */ 117 adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; 118 119 return 0; 120 } 121 122 static struct qt1010_config dtv5100_qt1010_config = { 123 .i2c_address = DTV5100_TUNER_ADDR 124 }; 125 126 static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) 127 { 128 return dvb_attach(qt1010_attach, 129 adap->fe_adap[0].fe, &adap->dev->i2c_adap, 130 &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; 131 } 132 133 /* DVB USB Driver stuff */ 134 static struct dvb_usb_device_properties dtv5100_properties; 135 136 static int dtv5100_probe(struct usb_interface *intf, 137 const struct usb_device_id *id) 138 { 139 int i, ret; 140 struct usb_device *udev = interface_to_usbdev(intf); 141 142 /* initialize non qt1010/zl10353 part? */ 143 for (i = 0; dtv5100_init[i].request; i++) { 144 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 145 dtv5100_init[i].request, 146 USB_TYPE_VENDOR | USB_DIR_OUT, 147 dtv5100_init[i].value, 148 dtv5100_init[i].index, NULL, 0, 149 DTV5100_USB_TIMEOUT); 150 if (ret) 151 return ret; 152 } 153 154 ret = dvb_usb_device_init(intf, &dtv5100_properties, 155 THIS_MODULE, NULL, adapter_nr); 156 if (ret) 157 return ret; 158 159 return 0; 160 } 161 162 static struct usb_device_id dtv5100_table[] = { 163 { USB_DEVICE(0x06be, 0xa232) }, 164 { } /* Terminating entry */ 165 }; 166 MODULE_DEVICE_TABLE(usb, dtv5100_table); 167 168 static struct dvb_usb_device_properties dtv5100_properties = { 169 .caps = DVB_USB_IS_AN_I2C_ADAPTER, 170 .usb_ctrl = DEVICE_SPECIFIC, 171 172 .size_of_priv = sizeof(struct dtv5100_state), 173 174 .num_adapters = 1, 175 .adapter = {{ 176 .num_frontends = 1, 177 .fe = {{ 178 .frontend_attach = dtv5100_frontend_attach, 179 .tuner_attach = dtv5100_tuner_attach, 180 181 .stream = { 182 .type = USB_BULK, 183 .count = 8, 184 .endpoint = 0x82, 185 .u = { 186 .bulk = { 187 .buffersize = 4096, 188 } 189 } 190 }, 191 }}, 192 } }, 193 194 .i2c_algo = &dtv5100_i2c_algo, 195 196 .num_device_descs = 1, 197 .devices = { 198 { 199 .name = "AME DTV-5100 USB2.0 DVB-T", 200 .cold_ids = { NULL }, 201 .warm_ids = { &dtv5100_table[0], NULL }, 202 }, 203 } 204 }; 205 206 static struct usb_driver dtv5100_driver = { 207 .name = "dvb_usb_dtv5100", 208 .probe = dtv5100_probe, 209 .disconnect = dvb_usb_device_exit, 210 .id_table = dtv5100_table, 211 }; 212 213 module_usb_driver(dtv5100_driver); 214 215 MODULE_AUTHOR(DRIVER_AUTHOR); 216 MODULE_DESCRIPTION(DRIVER_DESC); 217 MODULE_LICENSE("GPL"); 218