1*74ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2e4aab64cSIgor M. Liplianin /* 3e4aab64cSIgor M. Liplianin Driver for ST STV0288 demodulator 4e4aab64cSIgor M. Liplianin Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de 5e4aab64cSIgor M. Liplianin for Reel Multimedia 6e4aab64cSIgor M. Liplianin Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com> 7e4aab64cSIgor M. Liplianin Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> 8e4aab64cSIgor M. Liplianin Removed stb6000 specific tuner code and revised some 9e4aab64cSIgor M. Liplianin procedures. 10352a587cSMalcolm Priestley 2010-09-01 Josef Pavlik <josef@pavlik.it> 11352a587cSMalcolm Priestley Fixed diseqc_msg, diseqc_burst and set_tone problems 12e4aab64cSIgor M. Liplianin 13e4aab64cSIgor M. Liplianin 14e4aab64cSIgor M. Liplianin */ 15e4aab64cSIgor M. Liplianin 16e4aab64cSIgor M. Liplianin #include <linux/init.h> 17e4aab64cSIgor M. Liplianin #include <linux/kernel.h> 18e4aab64cSIgor M. Liplianin #include <linux/module.h> 19e4aab64cSIgor M. Liplianin #include <linux/string.h> 20e4aab64cSIgor M. Liplianin #include <linux/slab.h> 21e4aab64cSIgor M. Liplianin #include <linux/jiffies.h> 22e4aab64cSIgor M. Liplianin #include <asm/div64.h> 23e4aab64cSIgor M. Liplianin 24fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 25e4aab64cSIgor M. Liplianin #include "stv0288.h" 26e4aab64cSIgor M. Liplianin 27e4aab64cSIgor M. Liplianin struct stv0288_state { 28e4aab64cSIgor M. Liplianin struct i2c_adapter *i2c; 29e4aab64cSIgor M. Liplianin const struct stv0288_config *config; 30e4aab64cSIgor M. Liplianin struct dvb_frontend frontend; 31e4aab64cSIgor M. Liplianin 32e4aab64cSIgor M. Liplianin u8 initialised:1; 33e4aab64cSIgor M. Liplianin u32 tuner_frequency; 34e4aab64cSIgor M. Liplianin u32 symbol_rate; 350df289a2SMauro Carvalho Chehab enum fe_code_rate fec_inner; 36e4aab64cSIgor M. Liplianin int errmode; 37e4aab64cSIgor M. Liplianin }; 38e4aab64cSIgor M. Liplianin 39e4aab64cSIgor M. Liplianin #define STATUS_BER 0 40e4aab64cSIgor M. Liplianin #define STATUS_UCBLOCKS 1 41e4aab64cSIgor M. Liplianin 42e4aab64cSIgor M. Liplianin static int debug; 43e4aab64cSIgor M. Liplianin static int debug_legacy_dish_switch; 44e4aab64cSIgor M. Liplianin #define dprintk(args...) \ 45e4aab64cSIgor M. Liplianin do { \ 46e4aab64cSIgor M. Liplianin if (debug) \ 47e4aab64cSIgor M. Liplianin printk(KERN_DEBUG "stv0288: " args); \ 48e4aab64cSIgor M. Liplianin } while (0) 49e4aab64cSIgor M. Liplianin 50e4aab64cSIgor M. Liplianin 51e4aab64cSIgor M. Liplianin static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) 52e4aab64cSIgor M. Liplianin { 53e4aab64cSIgor M. Liplianin int ret; 54e4aab64cSIgor M. Liplianin u8 buf[] = { reg, data }; 55e4aab64cSIgor M. Liplianin struct i2c_msg msg = { 56e4aab64cSIgor M. Liplianin .addr = state->config->demod_address, 57e4aab64cSIgor M. Liplianin .flags = 0, 58e4aab64cSIgor M. Liplianin .buf = buf, 59e4aab64cSIgor M. Liplianin .len = 2 60e4aab64cSIgor M. Liplianin }; 61e4aab64cSIgor M. Liplianin 62e4aab64cSIgor M. Liplianin ret = i2c_transfer(state->i2c, &msg, 1); 63e4aab64cSIgor M. Liplianin 64e4aab64cSIgor M. Liplianin if (ret != 1) 654bd69e7bSMauro Carvalho Chehab dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", 664bd69e7bSMauro Carvalho Chehab __func__, reg, data, ret); 67e4aab64cSIgor M. Liplianin 68e4aab64cSIgor M. Liplianin return (ret != 1) ? -EREMOTEIO : 0; 69e4aab64cSIgor M. Liplianin } 70e4aab64cSIgor M. Liplianin 712e4e98e7Slawrence rust static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len) 72e4aab64cSIgor M. Liplianin { 73e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 74e4aab64cSIgor M. Liplianin 75e4aab64cSIgor M. Liplianin if (len != 2) 76e4aab64cSIgor M. Liplianin return -EINVAL; 77e4aab64cSIgor M. Liplianin 78e4aab64cSIgor M. Liplianin return stv0288_writeregI(state, buf[0], buf[1]); 79e4aab64cSIgor M. Liplianin } 80e4aab64cSIgor M. Liplianin 81e4aab64cSIgor M. Liplianin static u8 stv0288_readreg(struct stv0288_state *state, u8 reg) 82e4aab64cSIgor M. Liplianin { 83e4aab64cSIgor M. Liplianin int ret; 84e4aab64cSIgor M. Liplianin u8 b0[] = { reg }; 85e4aab64cSIgor M. Liplianin u8 b1[] = { 0 }; 86e4aab64cSIgor M. Liplianin struct i2c_msg msg[] = { 87e4aab64cSIgor M. Liplianin { 88e4aab64cSIgor M. Liplianin .addr = state->config->demod_address, 89e4aab64cSIgor M. Liplianin .flags = 0, 90e4aab64cSIgor M. Liplianin .buf = b0, 91e4aab64cSIgor M. Liplianin .len = 1 92e4aab64cSIgor M. Liplianin }, { 93e4aab64cSIgor M. Liplianin .addr = state->config->demod_address, 94e4aab64cSIgor M. Liplianin .flags = I2C_M_RD, 95e4aab64cSIgor M. Liplianin .buf = b1, 96e4aab64cSIgor M. Liplianin .len = 1 97e4aab64cSIgor M. Liplianin } 98e4aab64cSIgor M. Liplianin }; 99e4aab64cSIgor M. Liplianin 100e4aab64cSIgor M. Liplianin ret = i2c_transfer(state->i2c, msg, 2); 101e4aab64cSIgor M. Liplianin 102e4aab64cSIgor M. Liplianin if (ret != 2) 103e4aab64cSIgor M. Liplianin dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", 104e4aab64cSIgor M. Liplianin __func__, reg, ret); 105e4aab64cSIgor M. Liplianin 106e4aab64cSIgor M. Liplianin return b1[0]; 107e4aab64cSIgor M. Liplianin } 108e4aab64cSIgor M. Liplianin 109e4aab64cSIgor M. Liplianin static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) 110e4aab64cSIgor M. Liplianin { 111e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 112e4aab64cSIgor M. Liplianin unsigned int temp; 113e4aab64cSIgor M. Liplianin unsigned char b[3]; 114e4aab64cSIgor M. Liplianin 115e4aab64cSIgor M. Liplianin if ((srate < 1000000) || (srate > 45000000)) 116e4aab64cSIgor M. Liplianin return -EINVAL; 117e4aab64cSIgor M. Liplianin 11859152b1cStvboxspy stv0288_writeregI(state, 0x22, 0); 11959152b1cStvboxspy stv0288_writeregI(state, 0x23, 0); 12059152b1cStvboxspy stv0288_writeregI(state, 0x2b, 0xff); 12159152b1cStvboxspy stv0288_writeregI(state, 0x2c, 0xf7); 12259152b1cStvboxspy 123e4aab64cSIgor M. Liplianin temp = (unsigned int)srate / 1000; 124e4aab64cSIgor M. Liplianin 125e4aab64cSIgor M. Liplianin temp = temp * 32768; 126e4aab64cSIgor M. Liplianin temp = temp / 25; 127e4aab64cSIgor M. Liplianin temp = temp / 125; 128e4aab64cSIgor M. Liplianin b[0] = (unsigned char)((temp >> 12) & 0xff); 129e4aab64cSIgor M. Liplianin b[1] = (unsigned char)((temp >> 4) & 0xff); 130e4aab64cSIgor M. Liplianin b[2] = (unsigned char)((temp << 4) & 0xf0); 131e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ 132e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x29, 0); /* SFRM */ 133e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x2a, 0); /* SFRL */ 134e4aab64cSIgor M. Liplianin 135e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x28, b[0]); 136e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x29, b[1]); 137e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x2a, b[2]); 138e4aab64cSIgor M. Liplianin dprintk("stv0288: stv0288_set_symbolrate\n"); 139e4aab64cSIgor M. Liplianin 140e4aab64cSIgor M. Liplianin return 0; 141e4aab64cSIgor M. Liplianin } 142e4aab64cSIgor M. Liplianin 143e4aab64cSIgor M. Liplianin static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, 144e4aab64cSIgor M. Liplianin struct dvb_diseqc_master_cmd *m) 145e4aab64cSIgor M. Liplianin { 146e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 147e4aab64cSIgor M. Liplianin 148e4aab64cSIgor M. Liplianin int i; 149e4aab64cSIgor M. Liplianin 150e4aab64cSIgor M. Liplianin dprintk("%s\n", __func__); 151e4aab64cSIgor M. Liplianin 152e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x09, 0); 153e4aab64cSIgor M. Liplianin msleep(30); 154352a587cSMalcolm Priestley stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */ 155e4aab64cSIgor M. Liplianin 156e4aab64cSIgor M. Liplianin for (i = 0; i < m->msg_len; i++) { 157e4aab64cSIgor M. Liplianin if (stv0288_writeregI(state, 0x06, m->msg[i])) 158e4aab64cSIgor M. Liplianin return -EREMOTEIO; 159e4aab64cSIgor M. Liplianin } 160352a587cSMalcolm Priestley msleep(m->msg_len*12); 161e4aab64cSIgor M. Liplianin return 0; 162e4aab64cSIgor M. Liplianin } 163e4aab64cSIgor M. Liplianin 164e4aab64cSIgor M. Liplianin static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, 1650df289a2SMauro Carvalho Chehab enum fe_sec_mini_cmd burst) 166e4aab64cSIgor M. Liplianin { 167e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 168e4aab64cSIgor M. Liplianin 169e4aab64cSIgor M. Liplianin dprintk("%s\n", __func__); 170e4aab64cSIgor M. Liplianin 171352a587cSMalcolm Priestley if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */ 172e4aab64cSIgor M. Liplianin return -EREMOTEIO; 173e4aab64cSIgor M. Liplianin 174e4aab64cSIgor M. Liplianin if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff)) 175e4aab64cSIgor M. Liplianin return -EREMOTEIO; 176e4aab64cSIgor M. Liplianin 177352a587cSMalcolm Priestley msleep(15); 178352a587cSMalcolm Priestley if (stv0288_writeregI(state, 0x05, 0x12)) 179e4aab64cSIgor M. Liplianin return -EREMOTEIO; 180e4aab64cSIgor M. Liplianin 181e4aab64cSIgor M. Liplianin return 0; 182e4aab64cSIgor M. Liplianin } 183e4aab64cSIgor M. Liplianin 1840df289a2SMauro Carvalho Chehab static int stv0288_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) 185e4aab64cSIgor M. Liplianin { 186e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 187e4aab64cSIgor M. Liplianin 188e4aab64cSIgor M. Liplianin switch (tone) { 189e4aab64cSIgor M. Liplianin case SEC_TONE_ON: 190352a587cSMalcolm Priestley if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */ 191e4aab64cSIgor M. Liplianin return -EREMOTEIO; 192352a587cSMalcolm Priestley break; 193e4aab64cSIgor M. Liplianin 194e4aab64cSIgor M. Liplianin case SEC_TONE_OFF: 195352a587cSMalcolm Priestley if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/ 196e4aab64cSIgor M. Liplianin return -EREMOTEIO; 197352a587cSMalcolm Priestley break; 198e4aab64cSIgor M. Liplianin 199e4aab64cSIgor M. Liplianin default: 200e4aab64cSIgor M. Liplianin return -EINVAL; 201e4aab64cSIgor M. Liplianin } 202352a587cSMalcolm Priestley return 0; 203e4aab64cSIgor M. Liplianin } 204e4aab64cSIgor M. Liplianin 205e4aab64cSIgor M. Liplianin static u8 stv0288_inittab[] = { 206e4aab64cSIgor M. Liplianin 0x01, 0x15, 207e4aab64cSIgor M. Liplianin 0x02, 0x20, 208e4aab64cSIgor M. Liplianin 0x09, 0x0, 209e4aab64cSIgor M. Liplianin 0x0a, 0x4, 210e4aab64cSIgor M. Liplianin 0x0b, 0x0, 211e4aab64cSIgor M. Liplianin 0x0c, 0x0, 212e4aab64cSIgor M. Liplianin 0x0d, 0x0, 213e4aab64cSIgor M. Liplianin 0x0e, 0xd4, 214e4aab64cSIgor M. Liplianin 0x0f, 0x30, 215e4aab64cSIgor M. Liplianin 0x11, 0x80, 216e4aab64cSIgor M. Liplianin 0x12, 0x03, 217e4aab64cSIgor M. Liplianin 0x13, 0x48, 218e4aab64cSIgor M. Liplianin 0x14, 0x84, 219e4aab64cSIgor M. Liplianin 0x15, 0x45, 220e4aab64cSIgor M. Liplianin 0x16, 0xb7, 221e4aab64cSIgor M. Liplianin 0x17, 0x9c, 222e4aab64cSIgor M. Liplianin 0x18, 0x0, 223e4aab64cSIgor M. Liplianin 0x19, 0xa6, 224e4aab64cSIgor M. Liplianin 0x1a, 0x88, 225e4aab64cSIgor M. Liplianin 0x1b, 0x8f, 226e4aab64cSIgor M. Liplianin 0x1c, 0xf0, 227e4aab64cSIgor M. Liplianin 0x20, 0x0b, 228e4aab64cSIgor M. Liplianin 0x21, 0x54, 229e4aab64cSIgor M. Liplianin 0x22, 0x0, 230e4aab64cSIgor M. Liplianin 0x23, 0x0, 231e4aab64cSIgor M. Liplianin 0x2b, 0xff, 232e4aab64cSIgor M. Liplianin 0x2c, 0xf7, 233e4aab64cSIgor M. Liplianin 0x30, 0x0, 234e4aab64cSIgor M. Liplianin 0x31, 0x1e, 235e4aab64cSIgor M. Liplianin 0x32, 0x14, 236e4aab64cSIgor M. Liplianin 0x33, 0x0f, 237e4aab64cSIgor M. Liplianin 0x34, 0x09, 238e4aab64cSIgor M. Liplianin 0x35, 0x0c, 239e4aab64cSIgor M. Liplianin 0x36, 0x05, 240e4aab64cSIgor M. Liplianin 0x37, 0x2f, 241e4aab64cSIgor M. Liplianin 0x38, 0x16, 242e4aab64cSIgor M. Liplianin 0x39, 0xbe, 243e4aab64cSIgor M. Liplianin 0x3a, 0x0, 244e4aab64cSIgor M. Liplianin 0x3b, 0x13, 245e4aab64cSIgor M. Liplianin 0x3c, 0x11, 246e4aab64cSIgor M. Liplianin 0x3d, 0x30, 247e4aab64cSIgor M. Liplianin 0x40, 0x63, 248e4aab64cSIgor M. Liplianin 0x41, 0x04, 249bb19a421SMalcolm Priestley 0x42, 0x20, 250e4aab64cSIgor M. Liplianin 0x43, 0x00, 251e4aab64cSIgor M. Liplianin 0x44, 0x00, 252e4aab64cSIgor M. Liplianin 0x45, 0x00, 253e4aab64cSIgor M. Liplianin 0x46, 0x00, 254e4aab64cSIgor M. Liplianin 0x47, 0x00, 255e4aab64cSIgor M. Liplianin 0x4a, 0x00, 256e4aab64cSIgor M. Liplianin 0x50, 0x10, 257e4aab64cSIgor M. Liplianin 0x51, 0x38, 258e4aab64cSIgor M. Liplianin 0x52, 0x21, 259e4aab64cSIgor M. Liplianin 0x58, 0x54, 260e4aab64cSIgor M. Liplianin 0x59, 0x86, 261e4aab64cSIgor M. Liplianin 0x5a, 0x0, 262e4aab64cSIgor M. Liplianin 0x5b, 0x9b, 263e4aab64cSIgor M. Liplianin 0x5c, 0x08, 264e4aab64cSIgor M. Liplianin 0x5d, 0x7f, 265e4aab64cSIgor M. Liplianin 0x5e, 0x0, 266e4aab64cSIgor M. Liplianin 0x5f, 0xff, 267e4aab64cSIgor M. Liplianin 0x70, 0x0, 268e4aab64cSIgor M. Liplianin 0x71, 0x0, 269e4aab64cSIgor M. Liplianin 0x72, 0x0, 270e4aab64cSIgor M. Liplianin 0x74, 0x0, 271e4aab64cSIgor M. Liplianin 0x75, 0x0, 272e4aab64cSIgor M. Liplianin 0x76, 0x0, 273e4aab64cSIgor M. Liplianin 0x81, 0x0, 274e4aab64cSIgor M. Liplianin 0x82, 0x3f, 275e4aab64cSIgor M. Liplianin 0x83, 0x3f, 276e4aab64cSIgor M. Liplianin 0x84, 0x0, 277e4aab64cSIgor M. Liplianin 0x85, 0x0, 278e4aab64cSIgor M. Liplianin 0x88, 0x0, 279e4aab64cSIgor M. Liplianin 0x89, 0x0, 280e4aab64cSIgor M. Liplianin 0x8a, 0x0, 281e4aab64cSIgor M. Liplianin 0x8b, 0x0, 282e4aab64cSIgor M. Liplianin 0x8c, 0x0, 283e4aab64cSIgor M. Liplianin 0x90, 0x0, 284e4aab64cSIgor M. Liplianin 0x91, 0x0, 285e4aab64cSIgor M. Liplianin 0x92, 0x0, 286e4aab64cSIgor M. Liplianin 0x93, 0x0, 287e4aab64cSIgor M. Liplianin 0x94, 0x1c, 288e4aab64cSIgor M. Liplianin 0x97, 0x0, 289e4aab64cSIgor M. Liplianin 0xa0, 0x48, 290e4aab64cSIgor M. Liplianin 0xa1, 0x0, 291e4aab64cSIgor M. Liplianin 0xb0, 0xb8, 292e4aab64cSIgor M. Liplianin 0xb1, 0x3a, 293e4aab64cSIgor M. Liplianin 0xb2, 0x10, 294e4aab64cSIgor M. Liplianin 0xb3, 0x82, 295e4aab64cSIgor M. Liplianin 0xb4, 0x80, 296e4aab64cSIgor M. Liplianin 0xb5, 0x82, 297e4aab64cSIgor M. Liplianin 0xb6, 0x82, 298e4aab64cSIgor M. Liplianin 0xb7, 0x82, 299e4aab64cSIgor M. Liplianin 0xb8, 0x20, 300e4aab64cSIgor M. Liplianin 0xb9, 0x0, 301e4aab64cSIgor M. Liplianin 0xf0, 0x0, 302e4aab64cSIgor M. Liplianin 0xf1, 0x0, 303e4aab64cSIgor M. Liplianin 0xf2, 0xc0, 304e4aab64cSIgor M. Liplianin 0x51, 0x36, 305e4aab64cSIgor M. Liplianin 0x52, 0x09, 306e4aab64cSIgor M. Liplianin 0x53, 0x94, 307e4aab64cSIgor M. Liplianin 0x54, 0x62, 308e4aab64cSIgor M. Liplianin 0x55, 0x29, 309e4aab64cSIgor M. Liplianin 0x56, 0x64, 310e4aab64cSIgor M. Liplianin 0x57, 0x2b, 311e4aab64cSIgor M. Liplianin 0xff, 0xff, 312e4aab64cSIgor M. Liplianin }; 313e4aab64cSIgor M. Liplianin 3140df289a2SMauro Carvalho Chehab static int stv0288_set_voltage(struct dvb_frontend *fe, 3150df289a2SMauro Carvalho Chehab enum fe_sec_voltage volt) 316e4aab64cSIgor M. Liplianin { 317e4aab64cSIgor M. Liplianin dprintk("%s: %s\n", __func__, 318e4aab64cSIgor M. Liplianin volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : 319e4aab64cSIgor M. Liplianin volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); 320e4aab64cSIgor M. Liplianin 321e4aab64cSIgor M. Liplianin return 0; 322e4aab64cSIgor M. Liplianin } 323e4aab64cSIgor M. Liplianin 324e4aab64cSIgor M. Liplianin static int stv0288_init(struct dvb_frontend *fe) 325e4aab64cSIgor M. Liplianin { 326e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 327e4aab64cSIgor M. Liplianin int i; 328de9be0eaSIgor M. Liplianin u8 reg; 329de9be0eaSIgor M. Liplianin u8 val; 330e4aab64cSIgor M. Liplianin 331e4aab64cSIgor M. Liplianin dprintk("stv0288: init chip\n"); 332e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x41, 0x04); 333e4aab64cSIgor M. Liplianin msleep(50); 334e4aab64cSIgor M. Liplianin 335de9be0eaSIgor M. Liplianin /* we have default inittab */ 336de9be0eaSIgor M. Liplianin if (state->config->inittab == NULL) { 337e4aab64cSIgor M. Liplianin for (i = 0; !(stv0288_inittab[i] == 0xff && 338e4aab64cSIgor M. Liplianin stv0288_inittab[i + 1] == 0xff); i += 2) 339e4aab64cSIgor M. Liplianin stv0288_writeregI(state, stv0288_inittab[i], 340e4aab64cSIgor M. Liplianin stv0288_inittab[i + 1]); 341de9be0eaSIgor M. Liplianin } else { 342de9be0eaSIgor M. Liplianin for (i = 0; ; i += 2) { 343de9be0eaSIgor M. Liplianin reg = state->config->inittab[i]; 344de9be0eaSIgor M. Liplianin val = state->config->inittab[i+1]; 345de9be0eaSIgor M. Liplianin if (reg == 0xff && val == 0xff) 346de9be0eaSIgor M. Liplianin break; 347de9be0eaSIgor M. Liplianin stv0288_writeregI(state, reg, val); 348de9be0eaSIgor M. Liplianin } 349de9be0eaSIgor M. Liplianin } 350e4aab64cSIgor M. Liplianin return 0; 351e4aab64cSIgor M. Liplianin } 352e4aab64cSIgor M. Liplianin 3530df289a2SMauro Carvalho Chehab static int stv0288_read_status(struct dvb_frontend *fe, enum fe_status *status) 354e4aab64cSIgor M. Liplianin { 355e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 356e4aab64cSIgor M. Liplianin 357e4aab64cSIgor M. Liplianin u8 sync = stv0288_readreg(state, 0x24); 358e4aab64cSIgor M. Liplianin if (sync == 255) 359e4aab64cSIgor M. Liplianin sync = 0; 360e4aab64cSIgor M. Liplianin 361e4aab64cSIgor M. Liplianin dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); 362e4aab64cSIgor M. Liplianin 363e4aab64cSIgor M. Liplianin *status = 0; 364b50b3a1aSMalcolm Priestley if (sync & 0x80) 365b50b3a1aSMalcolm Priestley *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 366b50b3a1aSMalcolm Priestley if (sync & 0x10) 367b50b3a1aSMalcolm Priestley *status |= FE_HAS_VITERBI; 368b50b3a1aSMalcolm Priestley if (sync & 0x08) { 369e4aab64cSIgor M. Liplianin *status |= FE_HAS_LOCK; 370e4aab64cSIgor M. Liplianin dprintk("stv0288 has locked\n"); 371e4aab64cSIgor M. Liplianin } 372e4aab64cSIgor M. Liplianin 373e4aab64cSIgor M. Liplianin return 0; 374e4aab64cSIgor M. Liplianin } 375e4aab64cSIgor M. Liplianin 376e4aab64cSIgor M. Liplianin static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber) 377e4aab64cSIgor M. Liplianin { 378e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 379e4aab64cSIgor M. Liplianin 380e4aab64cSIgor M. Liplianin if (state->errmode != STATUS_BER) 381e4aab64cSIgor M. Liplianin return 0; 382e4aab64cSIgor M. Liplianin *ber = (stv0288_readreg(state, 0x26) << 8) | 383e4aab64cSIgor M. Liplianin stv0288_readreg(state, 0x27); 384e4aab64cSIgor M. Liplianin dprintk("stv0288_read_ber %d\n", *ber); 385e4aab64cSIgor M. Liplianin 386e4aab64cSIgor M. Liplianin return 0; 387e4aab64cSIgor M. Liplianin } 388e4aab64cSIgor M. Liplianin 389e4aab64cSIgor M. Liplianin 390e4aab64cSIgor M. Liplianin static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 391e4aab64cSIgor M. Liplianin { 392e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 393e4aab64cSIgor M. Liplianin 394e4aab64cSIgor M. Liplianin s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8)); 395e4aab64cSIgor M. Liplianin 396e4aab64cSIgor M. Liplianin 397e4aab64cSIgor M. Liplianin signal = signal * 5 / 4; 398e4aab64cSIgor M. Liplianin *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; 399e4aab64cSIgor M. Liplianin dprintk("stv0288_read_signal_strength %d\n", *strength); 400e4aab64cSIgor M. Liplianin 401e4aab64cSIgor M. Liplianin return 0; 402e4aab64cSIgor M. Liplianin } 403e4aab64cSIgor M. Liplianin static int stv0288_sleep(struct dvb_frontend *fe) 404e4aab64cSIgor M. Liplianin { 405e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 406e4aab64cSIgor M. Liplianin 407e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x41, 0x84); 408e4aab64cSIgor M. Liplianin state->initialised = 0; 409e4aab64cSIgor M. Liplianin 410e4aab64cSIgor M. Liplianin return 0; 411e4aab64cSIgor M. Liplianin } 412e4aab64cSIgor M. Liplianin static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr) 413e4aab64cSIgor M. Liplianin { 414e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 415e4aab64cSIgor M. Liplianin 416e4aab64cSIgor M. Liplianin s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8) 417e4aab64cSIgor M. Liplianin | stv0288_readreg(state, 0x2e)); 418e4aab64cSIgor M. Liplianin xsnr = 3 * (xsnr - 0xa100); 419e4aab64cSIgor M. Liplianin *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; 420e4aab64cSIgor M. Liplianin dprintk("stv0288_read_snr %d\n", *snr); 421e4aab64cSIgor M. Liplianin 422e4aab64cSIgor M. Liplianin return 0; 423e4aab64cSIgor M. Liplianin } 424e4aab64cSIgor M. Liplianin 425e4aab64cSIgor M. Liplianin static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 426e4aab64cSIgor M. Liplianin { 427e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 428e4aab64cSIgor M. Liplianin 429e4aab64cSIgor M. Liplianin if (state->errmode != STATUS_BER) 430e4aab64cSIgor M. Liplianin return 0; 431e4aab64cSIgor M. Liplianin *ucblocks = (stv0288_readreg(state, 0x26) << 8) | 432e4aab64cSIgor M. Liplianin stv0288_readreg(state, 0x27); 433e4aab64cSIgor M. Liplianin dprintk("stv0288_read_ber %d\n", *ucblocks); 434e4aab64cSIgor M. Liplianin 435e4aab64cSIgor M. Liplianin return 0; 436e4aab64cSIgor M. Liplianin } 437e4aab64cSIgor M. Liplianin 4385c6b4e2bSMauro Carvalho Chehab static int stv0288_set_frontend(struct dvb_frontend *fe) 439e4aab64cSIgor M. Liplianin { 440e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 441e4aab64cSIgor M. Liplianin struct dtv_frontend_properties *c = &fe->dtv_property_cache; 442e4aab64cSIgor M. Liplianin 443e4aab64cSIgor M. Liplianin char tm; 444e4aab64cSIgor M. Liplianin unsigned char tda[3]; 44559152b1cStvboxspy u8 reg, time_out = 0; 446e4aab64cSIgor M. Liplianin 447e4aab64cSIgor M. Liplianin dprintk("%s : FE_SET_FRONTEND\n", __func__); 448e4aab64cSIgor M. Liplianin 449e4aab64cSIgor M. Liplianin if (c->delivery_system != SYS_DVBS) { 4504bd69e7bSMauro Carvalho Chehab dprintk("%s: unsupported delivery system selected (%d)\n", 451e4aab64cSIgor M. Liplianin __func__, c->delivery_system); 452e4aab64cSIgor M. Liplianin return -EOPNOTSUPP; 453e4aab64cSIgor M. Liplianin } 454e4aab64cSIgor M. Liplianin 455e4aab64cSIgor M. Liplianin if (state->config->set_ts_params) 456e4aab64cSIgor M. Liplianin state->config->set_ts_params(fe, 0); 457e4aab64cSIgor M. Liplianin 458e4aab64cSIgor M. Liplianin /* only frequency & symbol_rate are used for tuner*/ 459e4aab64cSIgor M. Liplianin if (fe->ops.tuner_ops.set_params) { 46014d24d14SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 461e4aab64cSIgor M. Liplianin if (fe->ops.i2c_gate_ctrl) 462e4aab64cSIgor M. Liplianin fe->ops.i2c_gate_ctrl(fe, 0); 463e4aab64cSIgor M. Liplianin } 464e4aab64cSIgor M. Liplianin 465e4aab64cSIgor M. Liplianin udelay(10); 466e4aab64cSIgor M. Liplianin stv0288_set_symbolrate(fe, c->symbol_rate); 467e4aab64cSIgor M. Liplianin /* Carrier lock control register */ 468e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x15, 0xc5); 469e4aab64cSIgor M. Liplianin 470e4aab64cSIgor M. Liplianin tda[2] = 0x0; /* CFRL */ 47159152b1cStvboxspy for (tm = -9; tm < 7;) { 472e4aab64cSIgor M. Liplianin /* Viterbi status */ 47359152b1cStvboxspy reg = stv0288_readreg(state, 0x24); 47459152b1cStvboxspy if (reg & 0x8) 475e4aab64cSIgor M. Liplianin break; 47659152b1cStvboxspy if (reg & 0x80) { 47759152b1cStvboxspy time_out++; 47859152b1cStvboxspy if (time_out > 10) 47959152b1cStvboxspy break; 480e4aab64cSIgor M. Liplianin tda[2] += 40; 481e4aab64cSIgor M. Liplianin if (tda[2] < 40) 482e4aab64cSIgor M. Liplianin tm++; 48359152b1cStvboxspy } else { 48459152b1cStvboxspy tm++; 48559152b1cStvboxspy tda[2] = 0; 48659152b1cStvboxspy time_out = 0; 48759152b1cStvboxspy } 488e4aab64cSIgor M. Liplianin tda[1] = (unsigned char)tm; 489e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x2b, tda[1]); 490e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x2c, tda[2]); 49177768e4bSMalcolm Priestley msleep(30); 492e4aab64cSIgor M. Liplianin } 493e4aab64cSIgor M. Liplianin state->tuner_frequency = c->frequency; 494e4aab64cSIgor M. Liplianin state->fec_inner = FEC_AUTO; 495e4aab64cSIgor M. Liplianin state->symbol_rate = c->symbol_rate; 496e4aab64cSIgor M. Liplianin 497e4aab64cSIgor M. Liplianin return 0; 498e4aab64cSIgor M. Liplianin } 499e4aab64cSIgor M. Liplianin 500e4aab64cSIgor M. Liplianin static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 501e4aab64cSIgor M. Liplianin { 502e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 503e4aab64cSIgor M. Liplianin 504e4aab64cSIgor M. Liplianin if (enable) 505e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x01, 0xb5); 506e4aab64cSIgor M. Liplianin else 507e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x01, 0x35); 508e4aab64cSIgor M. Liplianin 509e4aab64cSIgor M. Liplianin udelay(1); 510e4aab64cSIgor M. Liplianin 511e4aab64cSIgor M. Liplianin return 0; 512e4aab64cSIgor M. Liplianin } 513e4aab64cSIgor M. Liplianin 514e4aab64cSIgor M. Liplianin static void stv0288_release(struct dvb_frontend *fe) 515e4aab64cSIgor M. Liplianin { 516e4aab64cSIgor M. Liplianin struct stv0288_state *state = fe->demodulator_priv; 517e4aab64cSIgor M. Liplianin kfree(state); 518e4aab64cSIgor M. Liplianin } 519e4aab64cSIgor M. Liplianin 520bd336e63SMax Kellermann static const struct dvb_frontend_ops stv0288_ops = { 5215c6b4e2bSMauro Carvalho Chehab .delsys = { SYS_DVBS }, 522e4aab64cSIgor M. Liplianin .info = { 523e4aab64cSIgor M. Liplianin .name = "ST STV0288 DVB-S", 524f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 950 * MHz, 525f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 2150 * MHz, 526f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 1 * MHz, 527e4aab64cSIgor M. Liplianin .symbol_rate_min = 1000000, 528e4aab64cSIgor M. Liplianin .symbol_rate_max = 45000000, 529e4aab64cSIgor M. Liplianin .symbol_rate_tolerance = 500, /* ppm */ 530e4aab64cSIgor M. Liplianin .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 531e4aab64cSIgor M. Liplianin FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 532e4aab64cSIgor M. Liplianin FE_CAN_QPSK | 533e4aab64cSIgor M. Liplianin FE_CAN_FEC_AUTO 534e4aab64cSIgor M. Liplianin }, 535e4aab64cSIgor M. Liplianin 536e4aab64cSIgor M. Liplianin .release = stv0288_release, 537e4aab64cSIgor M. Liplianin .init = stv0288_init, 538e4aab64cSIgor M. Liplianin .sleep = stv0288_sleep, 539e4aab64cSIgor M. Liplianin .write = stv0288_write, 540e4aab64cSIgor M. Liplianin .i2c_gate_ctrl = stv0288_i2c_gate_ctrl, 541e4aab64cSIgor M. Liplianin .read_status = stv0288_read_status, 542e4aab64cSIgor M. Liplianin .read_ber = stv0288_read_ber, 543e4aab64cSIgor M. Liplianin .read_signal_strength = stv0288_read_signal_strength, 544e4aab64cSIgor M. Liplianin .read_snr = stv0288_read_snr, 545e4aab64cSIgor M. Liplianin .read_ucblocks = stv0288_read_ucblocks, 546e4aab64cSIgor M. Liplianin .diseqc_send_master_cmd = stv0288_send_diseqc_msg, 547e4aab64cSIgor M. Liplianin .diseqc_send_burst = stv0288_send_diseqc_burst, 548e4aab64cSIgor M. Liplianin .set_tone = stv0288_set_tone, 549e4aab64cSIgor M. Liplianin .set_voltage = stv0288_set_voltage, 550e4aab64cSIgor M. Liplianin 5515c6b4e2bSMauro Carvalho Chehab .set_frontend = stv0288_set_frontend, 552e4aab64cSIgor M. Liplianin }; 553e4aab64cSIgor M. Liplianin 554e4aab64cSIgor M. Liplianin struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, 555e4aab64cSIgor M. Liplianin struct i2c_adapter *i2c) 556e4aab64cSIgor M. Liplianin { 557e4aab64cSIgor M. Liplianin struct stv0288_state *state = NULL; 558e4aab64cSIgor M. Liplianin int id; 559e4aab64cSIgor M. Liplianin 560e4aab64cSIgor M. Liplianin /* allocate memory for the internal state */ 561084e24acSMatthias Schwarzott state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL); 562e4aab64cSIgor M. Liplianin if (state == NULL) 563e4aab64cSIgor M. Liplianin goto error; 564e4aab64cSIgor M. Liplianin 565e4aab64cSIgor M. Liplianin /* setup the state */ 566e4aab64cSIgor M. Liplianin state->config = config; 567e4aab64cSIgor M. Liplianin state->i2c = i2c; 568e4aab64cSIgor M. Liplianin state->initialised = 0; 569e4aab64cSIgor M. Liplianin state->tuner_frequency = 0; 570e4aab64cSIgor M. Liplianin state->symbol_rate = 0; 571e4aab64cSIgor M. Liplianin state->fec_inner = 0; 572e4aab64cSIgor M. Liplianin state->errmode = STATUS_BER; 573e4aab64cSIgor M. Liplianin 574e4aab64cSIgor M. Liplianin stv0288_writeregI(state, 0x41, 0x04); 575e4aab64cSIgor M. Liplianin msleep(200); 576e4aab64cSIgor M. Liplianin id = stv0288_readreg(state, 0x00); 577e4aab64cSIgor M. Liplianin dprintk("stv0288 id %x\n", id); 578e4aab64cSIgor M. Liplianin 579e4aab64cSIgor M. Liplianin /* register 0x00 contains 0x11 for STV0288 */ 580e4aab64cSIgor M. Liplianin if (id != 0x11) 581e4aab64cSIgor M. Liplianin goto error; 582e4aab64cSIgor M. Liplianin 583e4aab64cSIgor M. Liplianin /* create dvb_frontend */ 584e4aab64cSIgor M. Liplianin memcpy(&state->frontend.ops, &stv0288_ops, 585e4aab64cSIgor M. Liplianin sizeof(struct dvb_frontend_ops)); 586e4aab64cSIgor M. Liplianin state->frontend.demodulator_priv = state; 587e4aab64cSIgor M. Liplianin return &state->frontend; 588e4aab64cSIgor M. Liplianin 589e4aab64cSIgor M. Liplianin error: 590e4aab64cSIgor M. Liplianin kfree(state); 591e4aab64cSIgor M. Liplianin 592e4aab64cSIgor M. Liplianin return NULL; 593e4aab64cSIgor M. Liplianin } 594e4aab64cSIgor M. Liplianin EXPORT_SYMBOL(stv0288_attach); 595e4aab64cSIgor M. Liplianin 596e4aab64cSIgor M. Liplianin module_param(debug_legacy_dish_switch, int, 0444); 597e4aab64cSIgor M. Liplianin MODULE_PARM_DESC(debug_legacy_dish_switch, 598e4aab64cSIgor M. Liplianin "Enable timing analysis for Dish Network legacy switches"); 599e4aab64cSIgor M. Liplianin 600e4aab64cSIgor M. Liplianin module_param(debug, int, 0644); 601e4aab64cSIgor M. Liplianin MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 602e4aab64cSIgor M. Liplianin 603e4aab64cSIgor M. Liplianin MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver"); 604e4aab64cSIgor M. Liplianin MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin"); 605e4aab64cSIgor M. Liplianin MODULE_LICENSE("GPL"); 606e4aab64cSIgor M. Liplianin 607