Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PCTV 452e DVB driver
0004  *
0005  * Copyright (c) 2006-2008 Dominik Kuhlen <dkuhlen@gmx.net>
0006  *
0007  * TT connect S2-3650-CI Common Interface support, MAC readout
0008  * Copyright (C) 2008 Michael H. Schimek <mschimek@gmx.at>
0009  */
0010 
0011 /* dvb usb framework */
0012 #define DVB_USB_LOG_PREFIX "pctv452e"
0013 #include "dvb-usb.h"
0014 
0015 /* Demodulator */
0016 #include "stb0899_drv.h"
0017 #include "stb0899_reg.h"
0018 #include "stb0899_cfg.h"
0019 /* Tuner */
0020 #include "stb6100.h"
0021 #include "stb6100_cfg.h"
0022 /* FE Power */
0023 #include "isl6423.h"
0024 #include "lnbp22.h"
0025 
0026 #include <media/dvb_ca_en50221.h>
0027 #include "ttpci-eeprom.h"
0028 
0029 static int debug;
0030 module_param(debug, int, 0644);
0031 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
0032 
0033 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
0034 
0035 #define ISOC_INTERFACE_ALTERNATIVE 3
0036 
0037 #define SYNC_BYTE_OUT 0xaa
0038 #define SYNC_BYTE_IN  0x55
0039 
0040 /* guessed: (copied from ttusb-budget) */
0041 #define PCTV_CMD_RESET 0x15
0042 /* command to poll IR receiver */
0043 #define PCTV_CMD_IR    0x1b
0044 /* command to send I2C  */
0045 #define PCTV_CMD_I2C   0x31
0046 
0047 #define I2C_ADDR_STB0899 (0xd0 >> 1)
0048 #define I2C_ADDR_STB6100 (0xc0 >> 1)
0049 #define I2C_ADDR_LNBP22  (0x10 >> 1)
0050 #define I2C_ADDR_24C16   (0xa0 >> 1)
0051 #define I2C_ADDR_24C64   (0xa2 >> 1)
0052 
0053 
0054 /* pctv452e sends us this amount of data for each issued usb-command */
0055 #define PCTV_ANSWER_LEN 64
0056 /* Wait up to 1000ms for device  */
0057 #define PCTV_TIMEOUT 1000
0058 
0059 
0060 #define PCTV_LED_GPIO   STB0899_GPIO01
0061 #define PCTV_LED_GREEN  0x82
0062 #define PCTV_LED_ORANGE 0x02
0063 
0064 #define ci_dbg(format, arg...)              \
0065 do {                            \
0066     if (0)                      \
0067         printk(KERN_DEBUG DVB_USB_LOG_PREFIX    \
0068             ": " format "\n" , ## arg); \
0069 } while (0)
0070 
0071 enum {
0072     TT3650_CMD_CI_TEST = 0x40,
0073     TT3650_CMD_CI_RD_CTRL,
0074     TT3650_CMD_CI_WR_CTRL,
0075     TT3650_CMD_CI_RD_ATTR,
0076     TT3650_CMD_CI_WR_ATTR,
0077     TT3650_CMD_CI_RESET,
0078     TT3650_CMD_CI_SET_VIDEO_PORT
0079 };
0080 
0081 
0082 static struct stb0899_postproc pctv45e_postproc[] = {
0083     { PCTV_LED_GPIO, STB0899_GPIOPULLUP },
0084     { 0, 0 }
0085 };
0086 
0087 static struct isl6423_config pctv452e_isl6423_config = {
0088     .current_max        = SEC_CURRENT_515m,
0089     .curlim         = SEC_CURRENT_LIM_ON,
0090     .mod_extern     = 1,
0091     .addr           = 0x08,
0092 };
0093 
0094 /*
0095  * stores all private variables for communication with the PCTV452e DVB-S2
0096  */
0097 struct pctv452e_state {
0098     struct dvb_ca_en50221 ca;
0099     struct mutex ca_mutex;
0100 
0101     u8 c;      /* transaction counter, wraps around...  */
0102     u8 initialized; /* set to 1 if 0x15 has been sent */
0103     u16 last_rc_key;
0104 };
0105 
0106 static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
0107              unsigned int write_len, unsigned int read_len)
0108 {
0109     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0110     u8 *buf;
0111     u8 id;
0112     unsigned int rlen;
0113     int ret;
0114 
0115     if (!data || (write_len > 64 - 4) || (read_len > 64 - 4)) {
0116         err("%s: transfer data invalid", __func__);
0117         return -EIO;
0118     }
0119 
0120     buf = kmalloc(64, GFP_KERNEL);
0121     if (!buf)
0122         return -ENOMEM;
0123 
0124     id = state->c++;
0125 
0126     buf[0] = SYNC_BYTE_OUT;
0127     buf[1] = id;
0128     buf[2] = cmd;
0129     buf[3] = write_len;
0130 
0131     memcpy(buf + 4, data, write_len);
0132 
0133     rlen = (read_len > 0) ? 64 : 0;
0134     ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
0135                   buf, rlen, /* delay_ms */ 0);
0136     if (0 != ret)
0137         goto failed;
0138 
0139     ret = -EIO;
0140     if (SYNC_BYTE_IN != buf[0] || id != buf[1])
0141         goto failed;
0142 
0143     memcpy(data, buf + 4, read_len);
0144 
0145     kfree(buf);
0146     return 0;
0147 
0148 failed:
0149     err("CI error %d; %02X %02X %02X -> %*ph.",
0150          ret, SYNC_BYTE_OUT, id, cmd, 3, buf);
0151 
0152     kfree(buf);
0153     return ret;
0154 }
0155 
0156 static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
0157                 u8 cmd, u8 *data, unsigned int write_len,
0158                 unsigned int read_len)
0159 {
0160     struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
0161     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0162     int ret;
0163 
0164     mutex_lock(&state->ca_mutex);
0165     ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
0166     mutex_unlock(&state->ca_mutex);
0167 
0168     return ret;
0169 }
0170 
0171 static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
0172                  int slot, int address)
0173 {
0174     u8 buf[3];
0175     int ret;
0176 
0177     if (0 != slot)
0178         return -EINVAL;
0179 
0180     buf[0] = (address >> 8) & 0x0F;
0181     buf[1] = address;
0182 
0183     ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
0184 
0185     ci_dbg("%s %04x -> %d 0x%02x",
0186         __func__, address, ret, buf[2]);
0187 
0188     if (ret < 0)
0189         return ret;
0190 
0191     return buf[2];
0192 }
0193 
0194 static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
0195                  int slot, int address, u8 value)
0196 {
0197     u8 buf[3];
0198 
0199     ci_dbg("%s %d 0x%04x 0x%02x",
0200         __func__, slot, address, value);
0201 
0202     if (0 != slot)
0203         return -EINVAL;
0204 
0205     buf[0] = (address >> 8) & 0x0F;
0206     buf[1] = address;
0207     buf[2] = value;
0208 
0209     return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
0210 }
0211 
0212 static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca,
0213                  int            slot,
0214                  u8         address)
0215 {
0216     u8 buf[2];
0217     int ret;
0218 
0219     if (0 != slot)
0220         return -EINVAL;
0221 
0222     buf[0] = address & 3;
0223 
0224     ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
0225 
0226     ci_dbg("%s 0x%02x -> %d 0x%02x",
0227         __func__, address, ret, buf[1]);
0228 
0229     if (ret < 0)
0230         return ret;
0231 
0232     return buf[1];
0233 }
0234 
0235 static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca,
0236                  int            slot,
0237                  u8         address,
0238                  u8         value)
0239 {
0240     u8 buf[2];
0241 
0242     ci_dbg("%s %d 0x%02x 0x%02x",
0243         __func__, slot, address, value);
0244 
0245     if (0 != slot)
0246         return -EINVAL;
0247 
0248     buf[0] = address;
0249     buf[1] = value;
0250 
0251     return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
0252 }
0253 
0254 static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca,
0255                  int            slot,
0256                  int            enable)
0257 {
0258     u8 buf[1];
0259     int ret;
0260 
0261     ci_dbg("%s %d %d", __func__, slot, enable);
0262 
0263     if (0 != slot)
0264         return -EINVAL;
0265 
0266     enable = !!enable;
0267     buf[0] = enable;
0268 
0269     ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
0270     if (ret < 0)
0271         return ret;
0272 
0273     if (enable != buf[0]) {
0274         err("CI not %sabled.", enable ? "en" : "dis");
0275         return -EIO;
0276     }
0277 
0278     return 0;
0279 }
0280 
0281 static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
0282 {
0283     return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
0284 }
0285 
0286 static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
0287 {
0288     return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
0289 }
0290 
0291 static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
0292 {
0293     struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
0294     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0295     u8 buf[1];
0296     int ret;
0297 
0298     ci_dbg("%s %d", __func__, slot);
0299 
0300     if (0 != slot)
0301         return -EINVAL;
0302 
0303     buf[0] = 0;
0304 
0305     mutex_lock(&state->ca_mutex);
0306 
0307     ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
0308     if (0 != ret)
0309         goto failed;
0310 
0311     msleep(500);
0312 
0313     buf[0] = 1;
0314 
0315     ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
0316     if (0 != ret)
0317         goto failed;
0318 
0319     msleep(500);
0320 
0321     buf[0] = 0; /* FTA */
0322 
0323     ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
0324 
0325  failed:
0326     mutex_unlock(&state->ca_mutex);
0327 
0328     return ret;
0329 }
0330 
0331 static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca,
0332                  int            slot,
0333                  int            open)
0334 {
0335     u8 buf[1];
0336     int ret;
0337 
0338     if (0 != slot)
0339         return -EINVAL;
0340 
0341     ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
0342     if (0 != ret)
0343         return ret;
0344 
0345     if (1 == buf[0])
0346         return DVB_CA_EN50221_POLL_CAM_PRESENT |
0347             DVB_CA_EN50221_POLL_CAM_READY;
0348 
0349     return 0;
0350 
0351 }
0352 
0353 static void tt3650_ci_uninit(struct dvb_usb_device *d)
0354 {
0355     struct pctv452e_state *state;
0356 
0357     ci_dbg("%s", __func__);
0358 
0359     if (NULL == d)
0360         return;
0361 
0362     state = (struct pctv452e_state *)d->priv;
0363     if (NULL == state)
0364         return;
0365 
0366     if (NULL == state->ca.data)
0367         return;
0368 
0369     /* Error ignored. */
0370     tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
0371 
0372     dvb_ca_en50221_release(&state->ca);
0373 
0374     memset(&state->ca, 0, sizeof(state->ca));
0375 }
0376 
0377 static int tt3650_ci_init(struct dvb_usb_adapter *a)
0378 {
0379     struct dvb_usb_device *d = a->dev;
0380     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0381     int ret;
0382 
0383     ci_dbg("%s", __func__);
0384 
0385     mutex_init(&state->ca_mutex);
0386 
0387     state->ca.owner = THIS_MODULE;
0388     state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
0389     state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
0390     state->ca.read_cam_control = tt3650_ci_read_cam_control;
0391     state->ca.write_cam_control = tt3650_ci_write_cam_control;
0392     state->ca.slot_reset = tt3650_ci_slot_reset;
0393     state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
0394     state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
0395     state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
0396     state->ca.data = d;
0397 
0398     ret = dvb_ca_en50221_init(&a->dvb_adap,
0399                    &state->ca,
0400                    /* flags */ 0,
0401                    /* n_slots */ 1);
0402     if (0 != ret) {
0403         err("Cannot initialize CI: Error %d.", ret);
0404         memset(&state->ca, 0, sizeof(state->ca));
0405         return ret;
0406     }
0407 
0408     info("CI initialized.");
0409 
0410     return 0;
0411 }
0412 
0413 #define CMD_BUFFER_SIZE 0x28
0414 static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
0415                 const u8 *snd_buf, u8 snd_len,
0416                 u8 *rcv_buf, u8 rcv_len)
0417 {
0418     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0419     u8 *buf;
0420     u8 id;
0421     int ret;
0422 
0423     buf = kmalloc(64, GFP_KERNEL);
0424     if (!buf)
0425         return -ENOMEM;
0426 
0427     id = state->c++;
0428 
0429     ret = -EINVAL;
0430     if (snd_len > 64 - 7 || rcv_len > 64 - 7)
0431         goto failed;
0432 
0433     buf[0] = SYNC_BYTE_OUT;
0434     buf[1] = id;
0435     buf[2] = PCTV_CMD_I2C;
0436     buf[3] = snd_len + 3;
0437     buf[4] = addr << 1;
0438     buf[5] = snd_len;
0439     buf[6] = rcv_len;
0440 
0441     memcpy(buf + 7, snd_buf, snd_len);
0442 
0443     ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
0444                   buf, /* rcv_len */ 64,
0445                   /* delay_ms */ 0);
0446     if (ret < 0)
0447         goto failed;
0448 
0449     /* TT USB protocol error. */
0450     ret = -EIO;
0451     if (SYNC_BYTE_IN != buf[0] || id != buf[1])
0452         goto failed;
0453 
0454     /* I2C device didn't respond as expected. */
0455     ret = -EREMOTEIO;
0456     if (buf[5] < snd_len || buf[6] < rcv_len)
0457         goto failed;
0458 
0459     memcpy(rcv_buf, buf + 7, rcv_len);
0460 
0461     kfree(buf);
0462     return rcv_len;
0463 
0464 failed:
0465     err("I2C error %d; %02X %02X  %02X %02X %02X -> %*ph",
0466          ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
0467          7, buf);
0468 
0469     kfree(buf);
0470     return ret;
0471 }
0472 
0473 static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
0474                 int num)
0475 {
0476     struct dvb_usb_device *d = i2c_get_adapdata(adapter);
0477     int i;
0478 
0479     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0480         return -EAGAIN;
0481 
0482     for (i = 0; i < num; i++) {
0483         u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
0484         int ret;
0485 
0486         if (msg[i].flags & I2C_M_RD) {
0487             addr = msg[i].addr;
0488             snd_buf = NULL;
0489             snd_len = 0;
0490             rcv_buf = msg[i].buf;
0491             rcv_len = msg[i].len;
0492         } else {
0493             addr = msg[i].addr;
0494             snd_buf = msg[i].buf;
0495             snd_len = msg[i].len;
0496             rcv_buf = NULL;
0497             rcv_len = 0;
0498         }
0499 
0500         ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf,
0501                     rcv_len);
0502         if (ret < rcv_len)
0503             break;
0504     }
0505 
0506     mutex_unlock(&d->i2c_mutex);
0507     return i;
0508 }
0509 
0510 static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
0511 {
0512     return I2C_FUNC_I2C;
0513 }
0514 
0515 static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
0516 {
0517     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0518     u8 *b0, *rx;
0519     int ret;
0520 
0521     info("%s: %d\n", __func__, i);
0522 
0523     if (!i)
0524         return 0;
0525 
0526     if (state->initialized)
0527         return 0;
0528 
0529     b0 = kmalloc(5 + PCTV_ANSWER_LEN, GFP_KERNEL);
0530     if (!b0)
0531         return -ENOMEM;
0532 
0533     rx = b0 + 5;
0534 
0535     /* hmm where should this should go? */
0536     ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
0537     if (ret != 0)
0538         info("%s: Warning set interface returned: %d\n",
0539             __func__, ret);
0540 
0541     /* this is a one-time initialization, don't know where to put */
0542     b0[0] = 0xaa;
0543     b0[1] = state->c++;
0544     b0[2] = PCTV_CMD_RESET;
0545     b0[3] = 1;
0546     b0[4] = 0;
0547     /* reset board */
0548     ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0);
0549     if (ret)
0550         goto ret;
0551 
0552     b0[1] = state->c++;
0553     b0[4] = 1;
0554     /* reset board (again?) */
0555     ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0);
0556     if (ret)
0557         goto ret;
0558 
0559     state->initialized = 1;
0560 
0561 ret:
0562     kfree(b0);
0563     return ret;
0564 }
0565 
0566 static int pctv452e_rc_query(struct dvb_usb_device *d)
0567 {
0568     struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
0569     u8 *b, *rx;
0570     int ret, i;
0571     u8 id;
0572 
0573     b = kmalloc(CMD_BUFFER_SIZE + PCTV_ANSWER_LEN, GFP_KERNEL);
0574     if (!b)
0575         return -ENOMEM;
0576 
0577     rx = b + CMD_BUFFER_SIZE;
0578 
0579     id = state->c++;
0580 
0581     /* prepare command header  */
0582     b[0] = SYNC_BYTE_OUT;
0583     b[1] = id;
0584     b[2] = PCTV_CMD_IR;
0585     b[3] = 0;
0586 
0587     /* send ir request */
0588     ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
0589     if (ret != 0)
0590         goto ret;
0591 
0592     if (debug > 3) {
0593         info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx);
0594         for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
0595             info(" %02x", rx[i+3]);
0596 
0597         info("\n");
0598     }
0599 
0600     if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
0601         /* got a "press" event */
0602         state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]);
0603         if (debug > 2)
0604             info("%s: cmd=0x%02x sys=0x%02x\n",
0605                 __func__, rx[6], rx[7]);
0606 
0607         rc_keydown(d->rc_dev, RC_PROTO_RC5, state->last_rc_key, 0);
0608     } else if (state->last_rc_key) {
0609         rc_keyup(d->rc_dev);
0610         state->last_rc_key = 0;
0611     }
0612 ret:
0613     kfree(b);
0614     return ret;
0615 }
0616 
0617 static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
0618 {
0619     const u8 mem_addr[] = { 0x1f, 0xcc };
0620     u8 encoded_mac[20];
0621     int ret;
0622 
0623     ret = -EAGAIN;
0624     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0625         goto failed;
0626 
0627     ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16,
0628                 mem_addr + 1, /* snd_len */ 1,
0629                 encoded_mac, /* rcv_len */ 20);
0630     if (-EREMOTEIO == ret)
0631         /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a
0632            byte write if /WC is low. */
0633         ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64,
0634                     mem_addr, 2,
0635                     encoded_mac, 20);
0636 
0637     mutex_unlock(&d->i2c_mutex);
0638 
0639     if (20 != ret)
0640         goto failed;
0641 
0642     ret = ttpci_eeprom_decode_mac(mac, encoded_mac);
0643     if (0 != ret)
0644         goto failed;
0645 
0646     return 0;
0647 
0648 failed:
0649     eth_zero_addr(mac);
0650 
0651     return ret;
0652 }
0653 
0654 static const struct stb0899_s1_reg pctv452e_init_dev[] = {
0655     { STB0899_DISCNTRL1,    0x26 },
0656     { STB0899_DISCNTRL2,    0x80 },
0657     { STB0899_DISRX_ST0,    0x04 },
0658     { STB0899_DISRX_ST1,    0x20 },
0659     { STB0899_DISPARITY,    0x00 },
0660     { STB0899_DISFIFO,  0x00 },
0661     { STB0899_DISF22,   0x99 },
0662     { STB0899_DISF22RX, 0x85 }, /* 0xa8 */
0663     { STB0899_ACRPRESC, 0x11 },
0664     { STB0899_ACRDIV1,  0x0a },
0665     { STB0899_ACRDIV2,  0x05 },
0666     { STB0899_DACR1 ,   0x00 },
0667     { STB0899_DACR2 ,   0x00 },
0668     { STB0899_OUTCFG,   0x00 },
0669     { STB0899_MODECFG,  0x00 }, /* Inversion */
0670     { STB0899_IRQMSK_3, 0xf3 },
0671     { STB0899_IRQMSK_2, 0xfc },
0672     { STB0899_IRQMSK_1, 0xff },
0673     { STB0899_IRQMSK_0, 0xff },
0674     { STB0899_I2CCFG,   0x88 },
0675     { STB0899_I2CRPT,   0x58 },
0676     { STB0899_GPIO00CFG,    0x82 },
0677     { STB0899_GPIO01CFG,    0x82 }, /* LED: 0x02 green, 0x82 orange */
0678     { STB0899_GPIO02CFG,    0x82 },
0679     { STB0899_GPIO03CFG,    0x82 },
0680     { STB0899_GPIO04CFG,    0x82 },
0681     { STB0899_GPIO05CFG,    0x82 },
0682     { STB0899_GPIO06CFG,    0x82 },
0683     { STB0899_GPIO07CFG,    0x82 },
0684     { STB0899_GPIO08CFG,    0x82 },
0685     { STB0899_GPIO09CFG,    0x82 },
0686     { STB0899_GPIO10CFG,    0x82 },
0687     { STB0899_GPIO11CFG,    0x82 },
0688     { STB0899_GPIO12CFG,    0x82 },
0689     { STB0899_GPIO13CFG,    0x82 },
0690     { STB0899_GPIO14CFG,    0x82 },
0691     { STB0899_GPIO15CFG,    0x82 },
0692     { STB0899_GPIO16CFG,    0x82 },
0693     { STB0899_GPIO17CFG,    0x82 },
0694     { STB0899_GPIO18CFG,    0x82 },
0695     { STB0899_GPIO19CFG,    0x82 },
0696     { STB0899_GPIO20CFG,    0x82 },
0697     { STB0899_SDATCFG,  0xb8 },
0698     { STB0899_SCLTCFG,  0xba },
0699     { STB0899_AGCRFCFG, 0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */
0700     { STB0899_GPIO22,   0x82 },
0701     { STB0899_GPIO21,   0x91 },
0702     { STB0899_DIRCLKCFG,    0x82 },
0703     { STB0899_CLKOUT27CFG,  0x7e },
0704     { STB0899_STDBYCFG, 0x82 },
0705     { STB0899_CS0CFG,   0x82 },
0706     { STB0899_CS1CFG,   0x82 },
0707     { STB0899_DISEQCOCFG,   0x20 },
0708     { STB0899_NCOARSE,  0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */
0709     { STB0899_SYNTCTRL, 0x00 }, /* 0x00 CLKI, 0x02 XTALI */
0710     { STB0899_FILTCTRL, 0x00 },
0711     { STB0899_SYSCTRL,  0x00 },
0712     { STB0899_STOPCLK1, 0x20 }, /* orig: 0x00 budget-ci: 0x20 */
0713     { STB0899_STOPCLK2, 0x00 },
0714     { STB0899_INTBUFCTRL,   0x0a },
0715     { STB0899_AGC2I1,   0x00 },
0716     { STB0899_AGC2I2,   0x00 },
0717     { STB0899_AGCIQIN,  0x00 },
0718     { STB0899_TSTRES,   0x40 }, /* rjkm */
0719     { 0xffff,       0xff },
0720 };
0721 
0722 static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = {
0723     { STB0899_DEMOD,    0x00 },
0724     { STB0899_RCOMPC,   0xc9 },
0725     { STB0899_AGC1CN,   0x01 },
0726     { STB0899_AGC1REF,  0x10 },
0727     { STB0899_RTC,      0x23 },
0728     { STB0899_TMGCFG,   0x4e },
0729     { STB0899_AGC2REF,  0x34 },
0730     { STB0899_TLSR,     0x84 },
0731     { STB0899_CFD,      0xf7 },
0732     { STB0899_ACLC,     0x87 },
0733     { STB0899_BCLC,     0x94 },
0734     { STB0899_EQON,     0x41 },
0735     { STB0899_LDT,      0xf1 },
0736     { STB0899_LDT2,     0xe3 },
0737     { STB0899_EQUALREF, 0xb4 },
0738     { STB0899_TMGRAMP,  0x10 },
0739     { STB0899_TMGTHD,   0x30 },
0740     { STB0899_IDCCOMP,  0xfd },
0741     { STB0899_QDCCOMP,  0xff },
0742     { STB0899_POWERI,   0x0c },
0743     { STB0899_POWERQ,   0x0f },
0744     { STB0899_RCOMP,    0x6c },
0745     { STB0899_AGCIQIN,  0x80 },
0746     { STB0899_AGC2I1,   0x06 },
0747     { STB0899_AGC2I2,   0x00 },
0748     { STB0899_TLIR,     0x30 },
0749     { STB0899_RTF,      0x7f },
0750     { STB0899_DSTATUS,  0x00 },
0751     { STB0899_LDI,      0xbc },
0752     { STB0899_CFRM,     0xea },
0753     { STB0899_CFRL,     0x31 },
0754     { STB0899_NIRM,     0x2b },
0755     { STB0899_NIRL,     0x80 },
0756     { STB0899_ISYMB,    0x1d },
0757     { STB0899_QSYMB,    0xa6 },
0758     { STB0899_SFRH,     0x2f },
0759     { STB0899_SFRM,     0x68 },
0760     { STB0899_SFRL,     0x40 },
0761     { STB0899_SFRUPH,   0x2f },
0762     { STB0899_SFRUPM,   0x68 },
0763     { STB0899_SFRUPL,   0x40 },
0764     { STB0899_EQUAI1,   0x02 },
0765     { STB0899_EQUAQ1,   0xff },
0766     { STB0899_EQUAI2,   0x04 },
0767     { STB0899_EQUAQ2,   0x05 },
0768     { STB0899_EQUAI3,   0x02 },
0769     { STB0899_EQUAQ3,   0xfd },
0770     { STB0899_EQUAI4,   0x03 },
0771     { STB0899_EQUAQ4,   0x07 },
0772     { STB0899_EQUAI5,   0x08 },
0773     { STB0899_EQUAQ5,   0xf5 },
0774     { STB0899_DSTATUS2, 0x00 },
0775     { STB0899_VSTATUS,  0x00 },
0776     { STB0899_VERROR,   0x86 },
0777     { STB0899_IQSWAP,   0x2a },
0778     { STB0899_ECNT1M,   0x00 },
0779     { STB0899_ECNT1L,   0x00 },
0780     { STB0899_ECNT2M,   0x00 },
0781     { STB0899_ECNT2L,   0x00 },
0782     { STB0899_ECNT3M,   0x0a },
0783     { STB0899_ECNT3L,   0xad },
0784     { STB0899_FECAUTO1, 0x06 },
0785     { STB0899_FECM,     0x01 },
0786     { STB0899_VTH12,    0xb0 },
0787     { STB0899_VTH23,    0x7a },
0788     { STB0899_VTH34,    0x58 },
0789     { STB0899_VTH56,    0x38 },
0790     { STB0899_VTH67,    0x34 },
0791     { STB0899_VTH78,    0x24 },
0792     { STB0899_PRVIT,    0xff },
0793     { STB0899_VITSYNC,  0x19 },
0794     { STB0899_RSULC,    0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
0795     { STB0899_TSULC,    0x42 },
0796     { STB0899_RSLLC,    0x41 },
0797     { STB0899_TSLPL,    0x12 },
0798     { STB0899_TSCFGH,   0x0c },
0799     { STB0899_TSCFGM,   0x00 },
0800     { STB0899_TSCFGL,   0x00 },
0801     { STB0899_TSOUT,    0x69 }, /* 0x0d for CAM */
0802     { STB0899_RSSYNCDEL,    0x00 },
0803     { STB0899_TSINHDELH,    0x02 },
0804     { STB0899_TSINHDELM,    0x00 },
0805     { STB0899_TSINHDELL,    0x00 },
0806     { STB0899_TSLLSTKM, 0x1b },
0807     { STB0899_TSLLSTKL, 0xb3 },
0808     { STB0899_TSULSTKM, 0x00 },
0809     { STB0899_TSULSTKL, 0x00 },
0810     { STB0899_PCKLENUL, 0xbc },
0811     { STB0899_PCKLENLL, 0xcc },
0812     { STB0899_RSPCKLEN, 0xbd },
0813     { STB0899_TSSTATUS, 0x90 },
0814     { STB0899_ERRCTRL1, 0xb6 },
0815     { STB0899_ERRCTRL2, 0x95 },
0816     { STB0899_ERRCTRL3, 0x8d },
0817     { STB0899_DMONMSK1, 0x27 },
0818     { STB0899_DMONMSK0, 0x03 },
0819     { STB0899_DEMAPVIT, 0x5c },
0820     { STB0899_PLPARM,   0x19 },
0821     { STB0899_PDELCTRL, 0x48 },
0822     { STB0899_PDELCTRL2,    0x00 },
0823     { STB0899_BBHCTRL1, 0x00 },
0824     { STB0899_BBHCTRL2, 0x00 },
0825     { STB0899_HYSTTHRESH,   0x77 },
0826     { STB0899_MATCSTM,  0x00 },
0827     { STB0899_MATCSTL,  0x00 },
0828     { STB0899_UPLCSTM,  0x00 },
0829     { STB0899_UPLCSTL,  0x00 },
0830     { STB0899_DFLCSTM,  0x00 },
0831     { STB0899_DFLCSTL,  0x00 },
0832     { STB0899_SYNCCST,  0x00 },
0833     { STB0899_SYNCDCSTM,    0x00 },
0834     { STB0899_SYNCDCSTL,    0x00 },
0835     { STB0899_ISI_ENTRY,    0x00 },
0836     { STB0899_ISI_BIT_EN,   0x00 },
0837     { STB0899_MATSTRM,  0xf0 },
0838     { STB0899_MATSTRL,  0x02 },
0839     { STB0899_UPLSTRM,  0x45 },
0840     { STB0899_UPLSTRL,  0x60 },
0841     { STB0899_DFLSTRM,  0xe3 },
0842     { STB0899_DFLSTRL,  0x00 },
0843     { STB0899_SYNCSTR,  0x47 },
0844     { STB0899_SYNCDSTRM,    0x05 },
0845     { STB0899_SYNCDSTRL,    0x18 },
0846     { STB0899_CFGPDELSTATUS1, 0x19 },
0847     { STB0899_CFGPDELSTATUS2, 0x2b },
0848     { STB0899_BBFERRORM,    0x00 },
0849     { STB0899_BBFERRORL,    0x01 },
0850     { STB0899_UPKTERRORM,   0x00 },
0851     { STB0899_UPKTERRORL,   0x00 },
0852     { 0xffff,       0xff },
0853 };
0854 
0855 static struct stb0899_config stb0899_config = {
0856     .init_dev   = pctv452e_init_dev,
0857     .init_s2_demod  = stb0899_s2_init_2,
0858     .init_s1_demod  = pctv452e_init_s1_demod,
0859     .init_s2_fec    = stb0899_s2_init_4,
0860     .init_tst   = stb0899_s1_init_5,
0861 
0862     .demod_address   = I2C_ADDR_STB0899, /* I2C Address */
0863     .block_sync_mode = STB0899_SYNC_FORCED, /* ? */
0864 
0865     .xtal_freq       = 27000000,     /* Assume Hz ? */
0866     .inversion       = IQ_SWAP_ON,
0867 
0868     .lo_clk   = 76500000,
0869     .hi_clk   = 99000000,
0870 
0871     .ts_output_mode  = 0,   /* Use parallel mode */
0872     .clock_polarity  = 0,
0873     .data_clk_parity = 0,
0874     .fec_mode   = 0,
0875 
0876     .esno_ave       = STB0899_DVBS2_ESNO_AVE,
0877     .esno_quant   = STB0899_DVBS2_ESNO_QUANT,
0878     .avframes_coarse     = STB0899_DVBS2_AVFRAMES_COARSE,
0879     .avframes_fine       = STB0899_DVBS2_AVFRAMES_FINE,
0880     .miss_threshold      = STB0899_DVBS2_MISS_THRESHOLD,
0881     .uwp_threshold_acq   = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
0882     .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
0883     .uwp_threshold_sof   = STB0899_DVBS2_UWP_THRESHOLD_SOF,
0884     .sof_search_timeout  = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
0885 
0886     .btr_nco_bits     = STB0899_DVBS2_BTR_NCO_BITS,
0887     .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
0888     .crl_nco_bits     = STB0899_DVBS2_CRL_NCO_BITS,
0889     .ldpc_max_iter   = STB0899_DVBS2_LDPC_MAX_ITER,
0890 
0891     .tuner_get_frequency    = stb6100_get_frequency,
0892     .tuner_set_frequency    = stb6100_set_frequency,
0893     .tuner_set_bandwidth    = stb6100_set_bandwidth,
0894     .tuner_get_bandwidth    = stb6100_get_bandwidth,
0895     .tuner_set_rfsiggain    = NULL,
0896 
0897     /* helper for switching LED green/orange */
0898     .postproc = pctv45e_postproc
0899 };
0900 
0901 static struct stb6100_config stb6100_config = {
0902     .tuner_address = I2C_ADDR_STB6100,
0903     .refclock      = 27000000
0904 };
0905 
0906 
0907 static struct i2c_algorithm pctv452e_i2c_algo = {
0908     .master_xfer   = pctv452e_i2c_xfer,
0909     .functionality = pctv452e_i2c_func
0910 };
0911 
0912 static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
0913 {
0914     struct usb_device_id *id;
0915 
0916     a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config,
0917                         &a->dev->i2c_adap);
0918     if (!a->fe_adap[0].fe)
0919         return -ENODEV;
0920 
0921     id = a->dev->desc->warm_ids[0];
0922     if (id->idVendor == USB_VID_TECHNOTREND &&
0923         id->idProduct == USB_PID_TECHNOTREND_CONNECT_S2_3650_CI) {
0924         if (dvb_attach(lnbp22_attach,
0925                    a->fe_adap[0].fe,
0926                    &a->dev->i2c_adap) == NULL) {
0927             err("Cannot attach lnbp22\n");
0928         }
0929         /* Error ignored. */
0930         tt3650_ci_init(a);
0931     } else if (dvb_attach(isl6423_attach,
0932                   a->fe_adap[0].fe,
0933                   &a->dev->i2c_adap,
0934                   &pctv452e_isl6423_config) == NULL) {
0935         err("Cannot attach isl6423\n");
0936     }
0937 
0938     return 0;
0939 }
0940 
0941 static int pctv452e_tuner_attach(struct dvb_usb_adapter *a)
0942 {
0943     if (!a->fe_adap[0].fe)
0944         return -ENODEV;
0945     if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
0946                     &a->dev->i2c_adap) == NULL) {
0947         err("%s failed\n", __func__);
0948         return -ENODEV;
0949     }
0950 
0951     return 0;
0952 }
0953 
0954 enum {
0955     PINNACLE_PCTV_452E,
0956     TECHNOTREND_CONNECT_S2_3600,
0957     TECHNOTREND_CONNECT_S2_3650_CI,
0958 };
0959 
0960 static struct usb_device_id pctv452e_usb_table[] = {
0961     DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_452E),
0962     DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3600),
0963     DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3650_CI),
0964     { }
0965 };
0966 
0967 MODULE_DEVICE_TABLE(usb, pctv452e_usb_table);
0968 
0969 static struct dvb_usb_device_properties pctv452e_properties = {
0970     .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
0971     .usb_ctrl = DEVICE_SPECIFIC,
0972 
0973     .size_of_priv     = sizeof(struct pctv452e_state),
0974 
0975     .power_ctrl       = pctv452e_power_ctrl,
0976 
0977     .rc.core = {
0978         .rc_codes   = RC_MAP_DIB0700_RC5_TABLE,
0979         .allowed_protos = RC_PROTO_BIT_RC5,
0980         .rc_query   = pctv452e_rc_query,
0981         .rc_interval    = 100,
0982     },
0983 
0984     .num_adapters     = 1,
0985     .adapter = {{
0986         .num_frontends = 1,
0987         .fe = {{
0988             .frontend_attach  = pctv452e_frontend_attach,
0989             .tuner_attach     = pctv452e_tuner_attach,
0990 
0991             /* parameter for the MPEG2-data transfer */
0992             .stream = {
0993                 .type     = USB_ISOC,
0994                 .count    = 4,
0995                 .endpoint = 0x02,
0996                 .u = {
0997                     .isoc = {
0998                         .framesperurb = 4,
0999                         .framesize    = 940,
1000                         .interval     = 1
1001                     }
1002                 }
1003             },
1004         } },
1005     } },
1006 
1007     .i2c_algo = &pctv452e_i2c_algo,
1008 
1009     .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */
1010 
1011     .num_device_descs = 1,
1012     .devices = {
1013         { .name = "PCTV HDTV USB",
1014           .cold_ids = { NULL, NULL }, /* this is a warm only device */
1015           .warm_ids = { &pctv452e_usb_table[PINNACLE_PCTV_452E], NULL }
1016         },
1017         { NULL },
1018     }
1019 };
1020 
1021 static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
1022     .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */
1023     .usb_ctrl = DEVICE_SPECIFIC,
1024 
1025     .size_of_priv       = sizeof(struct pctv452e_state),
1026 
1027     .power_ctrl     = pctv452e_power_ctrl,
1028     .read_mac_address   = pctv452e_read_mac_address,
1029 
1030     .rc.core = {
1031         .rc_codes   = RC_MAP_TT_1500,
1032         .allowed_protos = RC_PROTO_BIT_RC5,
1033         .rc_query   = pctv452e_rc_query,
1034         .rc_interval    = 100,
1035     },
1036 
1037     .num_adapters       = 1,
1038     .adapter = {{
1039         .num_frontends = 1,
1040         .fe = {{
1041             .frontend_attach = pctv452e_frontend_attach,
1042             .tuner_attach = pctv452e_tuner_attach,
1043 
1044             /* parameter for the MPEG2-data transfer */
1045             .stream = {
1046                 .type = USB_ISOC,
1047                 .count = 4,
1048                 .endpoint = 0x02,
1049                 .u = {
1050                     .isoc = {
1051                         .framesperurb = 64,
1052                         .framesize = 940,
1053                         .interval = 1
1054                     }
1055                 }
1056             },
1057 
1058         } },
1059     } },
1060 
1061     .i2c_algo = &pctv452e_i2c_algo,
1062 
1063     .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/
1064 
1065     .num_device_descs = 2,
1066     .devices = {
1067         { .name = "Technotrend TT Connect S2-3600",
1068           .cold_ids = { NULL, NULL }, /* this is a warm only device */
1069           .warm_ids = { &pctv452e_usb_table[TECHNOTREND_CONNECT_S2_3600], NULL }
1070         },
1071         { .name = "Technotrend TT Connect S2-3650-CI",
1072           .cold_ids = { NULL, NULL },
1073           .warm_ids = { &pctv452e_usb_table[TECHNOTREND_CONNECT_S2_3650_CI], NULL }
1074         },
1075         { NULL },
1076     }
1077 };
1078 
1079 static void pctv452e_usb_disconnect(struct usb_interface *intf)
1080 {
1081     struct dvb_usb_device *d = usb_get_intfdata(intf);
1082 
1083     tt3650_ci_uninit(d);
1084     dvb_usb_device_exit(intf);
1085 }
1086 
1087 static int pctv452e_usb_probe(struct usb_interface *intf,
1088                 const struct usb_device_id *id)
1089 {
1090     if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
1091                     THIS_MODULE, NULL, adapter_nr) ||
1092         0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
1093                     THIS_MODULE, NULL, adapter_nr))
1094         return 0;
1095 
1096     return -ENODEV;
1097 }
1098 
1099 static struct usb_driver pctv452e_usb_driver = {
1100     .name       = "pctv452e",
1101     .probe      = pctv452e_usb_probe,
1102     .disconnect = pctv452e_usb_disconnect,
1103     .id_table   = pctv452e_usb_table,
1104 };
1105 
1106 module_usb_driver(pctv452e_usb_driver);
1107 
1108 MODULE_AUTHOR("Dominik Kuhlen <dkuhlen@gmx.net>");
1109 MODULE_AUTHOR("Andre Weidemann <Andre.Weidemann@web.de>");
1110 MODULE_AUTHOR("Michael H. Schimek <mschimek@gmx.at>");
1111 MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver");
1112 MODULE_LICENSE("GPL");