1 /* 2 * horus3a.h 3 * 4 * Sony Horus3A DVB-S/S2 tuner driver 5 * 6 * Copyright 2012 Sony Corporation 7 * Copyright (C) 2014 NetUP Inc. 8 * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru> 9 * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 */ 21 22 #include <linux/slab.h> 23 #include <linux/module.h> 24 #include <linux/dvb/frontend.h> 25 #include <linux/types.h> 26 #include "horus3a.h" 27 #include <media/dvb_frontend.h> 28 29 #define MAX_WRITE_REGSIZE 5 30 31 enum horus3a_state { 32 STATE_UNKNOWN, 33 STATE_SLEEP, 34 STATE_ACTIVE 35 }; 36 37 struct horus3a_priv { 38 u32 frequency; 39 u8 i2c_address; 40 struct i2c_adapter *i2c; 41 enum horus3a_state state; 42 void *set_tuner_data; 43 int (*set_tuner)(void *, int); 44 }; 45 46 static void horus3a_i2c_debug(struct horus3a_priv *priv, 47 u8 reg, u8 write, const u8 *data, u32 len) 48 { 49 dev_dbg(&priv->i2c->dev, "horus3a: I2C %s reg 0x%02x size %d\n", 50 (write == 0 ? "read" : "write"), reg, len); 51 print_hex_dump_bytes("horus3a: I2C data: ", 52 DUMP_PREFIX_OFFSET, data, len); 53 } 54 55 static int horus3a_write_regs(struct horus3a_priv *priv, 56 u8 reg, const u8 *data, u32 len) 57 { 58 int ret; 59 u8 buf[MAX_WRITE_REGSIZE + 1]; 60 struct i2c_msg msg[1] = { 61 { 62 .addr = priv->i2c_address, 63 .flags = 0, 64 .len = len + 1, 65 .buf = buf, 66 } 67 }; 68 69 if (len + 1 > sizeof(buf)) { 70 dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", 71 reg, len + 1); 72 return -E2BIG; 73 } 74 75 horus3a_i2c_debug(priv, reg, 1, data, len); 76 buf[0] = reg; 77 memcpy(&buf[1], data, len); 78 ret = i2c_transfer(priv->i2c, msg, 1); 79 if (ret >= 0 && ret != 1) 80 ret = -EREMOTEIO; 81 if (ret < 0) { 82 dev_warn(&priv->i2c->dev, 83 "%s: i2c wr failed=%d reg=%02x len=%d\n", 84 KBUILD_MODNAME, ret, reg, len); 85 return ret; 86 } 87 return 0; 88 } 89 90 static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val) 91 { 92 u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */ 93 94 return horus3a_write_regs(priv, reg, &tmp, 1); 95 } 96 97 static int horus3a_enter_power_save(struct horus3a_priv *priv) 98 { 99 u8 data[2]; 100 101 dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 102 if (priv->state == STATE_SLEEP) 103 return 0; 104 /* IQ Generator disable */ 105 horus3a_write_reg(priv, 0x2a, 0x79); 106 /* MDIV_EN = 0 */ 107 horus3a_write_reg(priv, 0x29, 0x70); 108 /* VCO disable preparation */ 109 horus3a_write_reg(priv, 0x28, 0x3e); 110 /* VCO buffer disable */ 111 horus3a_write_reg(priv, 0x2a, 0x19); 112 /* VCO calibration disable */ 113 horus3a_write_reg(priv, 0x1c, 0x00); 114 /* Power save setting (xtal is not stopped) */ 115 data[0] = 0xC0; 116 /* LNA is Disabled */ 117 data[1] = 0xA7; 118 /* 0x11 - 0x12 */ 119 horus3a_write_regs(priv, 0x11, data, sizeof(data)); 120 priv->state = STATE_SLEEP; 121 return 0; 122 } 123 124 static int horus3a_leave_power_save(struct horus3a_priv *priv) 125 { 126 u8 data[2]; 127 128 dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 129 if (priv->state == STATE_ACTIVE) 130 return 0; 131 /* Leave power save */ 132 data[0] = 0x00; 133 /* LNA is Disabled */ 134 data[1] = 0xa7; 135 /* 0x11 - 0x12 */ 136 horus3a_write_regs(priv, 0x11, data, sizeof(data)); 137 /* VCO buffer enable */ 138 horus3a_write_reg(priv, 0x2a, 0x79); 139 /* VCO calibration enable */ 140 horus3a_write_reg(priv, 0x1c, 0xc0); 141 /* MDIV_EN = 1 */ 142 horus3a_write_reg(priv, 0x29, 0x71); 143 usleep_range(5000, 7000); 144 priv->state = STATE_ACTIVE; 145 return 0; 146 } 147 148 static int horus3a_init(struct dvb_frontend *fe) 149 { 150 struct horus3a_priv *priv = fe->tuner_priv; 151 152 dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 153 return 0; 154 } 155 156 static void horus3a_release(struct dvb_frontend *fe) 157 { 158 struct horus3a_priv *priv = fe->tuner_priv; 159 160 dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 161 kfree(fe->tuner_priv); 162 fe->tuner_priv = NULL; 163 } 164 165 static int horus3a_sleep(struct dvb_frontend *fe) 166 { 167 struct horus3a_priv *priv = fe->tuner_priv; 168 169 dev_dbg(&priv->i2c->dev, "%s()\n", __func__); 170 horus3a_enter_power_save(priv); 171 return 0; 172 } 173 174 static int horus3a_set_params(struct dvb_frontend *fe) 175 { 176 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 177 struct horus3a_priv *priv = fe->tuner_priv; 178 u32 frequency = p->frequency; 179 u32 symbol_rate = p->symbol_rate/1000; 180 u8 mixdiv = 0; 181 u8 mdiv = 0; 182 u32 ms = 0; 183 u8 f_ctl = 0; 184 u8 g_ctl = 0; 185 u8 fc_lpf = 0; 186 u8 data[5]; 187 188 dev_dbg(&priv->i2c->dev, "%s(): frequency %dkHz symbol_rate %dksps\n", 189 __func__, frequency, symbol_rate); 190 if (priv->set_tuner) 191 priv->set_tuner(priv->set_tuner_data, 0); 192 if (priv->state == STATE_SLEEP) 193 horus3a_leave_power_save(priv); 194 195 /* frequency should be X MHz (X : integer) */ 196 frequency = DIV_ROUND_CLOSEST(frequency, 1000) * 1000; 197 if (frequency <= 1155000) { 198 mixdiv = 4; 199 mdiv = 1; 200 } else { 201 mixdiv = 2; 202 mdiv = 0; 203 } 204 /* Assumed that fREF == 1MHz (1000kHz) */ 205 ms = DIV_ROUND_CLOSEST((frequency * mixdiv) / 2, 1000); 206 if (ms > 0x7FFF) { /* 15 bit */ 207 dev_err(&priv->i2c->dev, "horus3a: invalid frequency %d\n", 208 frequency); 209 return -EINVAL; 210 } 211 if (frequency < 975000) { 212 /* F_CTL=11100 G_CTL=001 */ 213 f_ctl = 0x1C; 214 g_ctl = 0x01; 215 } else if (frequency < 1050000) { 216 /* F_CTL=11000 G_CTL=010 */ 217 f_ctl = 0x18; 218 g_ctl = 0x02; 219 } else if (frequency < 1150000) { 220 /* F_CTL=10100 G_CTL=010 */ 221 f_ctl = 0x14; 222 g_ctl = 0x02; 223 } else if (frequency < 1250000) { 224 /* F_CTL=10000 G_CTL=011 */ 225 f_ctl = 0x10; 226 g_ctl = 0x03; 227 } else if (frequency < 1350000) { 228 /* F_CTL=01100 G_CTL=100 */ 229 f_ctl = 0x0C; 230 g_ctl = 0x04; 231 } else if (frequency < 1450000) { 232 /* F_CTL=01010 G_CTL=100 */ 233 f_ctl = 0x0A; 234 g_ctl = 0x04; 235 } else if (frequency < 1600000) { 236 /* F_CTL=00111 G_CTL=101 */ 237 f_ctl = 0x07; 238 g_ctl = 0x05; 239 } else if (frequency < 1800000) { 240 /* F_CTL=00100 G_CTL=010 */ 241 f_ctl = 0x04; 242 g_ctl = 0x02; 243 } else if (frequency < 2000000) { 244 /* F_CTL=00010 G_CTL=001 */ 245 f_ctl = 0x02; 246 g_ctl = 0x01; 247 } else { 248 /* F_CTL=00000 G_CTL=000 */ 249 f_ctl = 0x00; 250 g_ctl = 0x00; 251 } 252 /* LPF cutoff frequency setting */ 253 if (p->delivery_system == SYS_DVBS) { 254 /* 255 * rolloff = 0.35 256 * SR <= 4.3 257 * fc_lpf = 5 258 * 4.3 < SR <= 10 259 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2 = 260 * SR * 1.175 = SR * (47/40) 261 * 10 < SR 262 * fc_lpf = SR * (1 + rolloff) / 2 + 5 = 263 * SR * 0.675 + 5 = SR * (27/40) + 5 264 * NOTE: The result should be round up. 265 */ 266 if (symbol_rate <= 4300) 267 fc_lpf = 5; 268 else if (symbol_rate <= 10000) 269 fc_lpf = (u8)DIV_ROUND_UP(symbol_rate * 47, 40000); 270 else 271 fc_lpf = (u8)DIV_ROUND_UP(symbol_rate * 27, 40000) + 5; 272 /* 5 <= fc_lpf <= 36 */ 273 if (fc_lpf > 36) 274 fc_lpf = 36; 275 } else if (p->delivery_system == SYS_DVBS2) { 276 /* 277 * SR <= 4.5: 278 * fc_lpf = 5 279 * 4.5 < SR <= 10: 280 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2 281 * 10 < SR: 282 * fc_lpf = SR * (1 + rolloff) / 2 + 5 283 * NOTE: The result should be round up. 284 */ 285 if (symbol_rate <= 4500) 286 fc_lpf = 5; 287 else if (symbol_rate <= 10000) 288 fc_lpf = (u8)((symbol_rate * 11 + (10000-1)) / 10000); 289 else 290 fc_lpf = (u8)((symbol_rate * 3 + (5000-1)) / 5000 + 5); 291 /* 5 <= fc_lpf <= 36 is valid */ 292 if (fc_lpf > 36) 293 fc_lpf = 36; 294 } else { 295 dev_err(&priv->i2c->dev, 296 "horus3a: invalid delivery system %d\n", 297 p->delivery_system); 298 return -EINVAL; 299 } 300 /* 0x00 - 0x04 */ 301 data[0] = (u8)((ms >> 7) & 0xFF); 302 data[1] = (u8)((ms << 1) & 0xFF); 303 data[2] = 0x00; 304 data[3] = 0x00; 305 data[4] = (u8)(mdiv << 7); 306 horus3a_write_regs(priv, 0x00, data, sizeof(data)); 307 /* Write G_CTL, F_CTL */ 308 horus3a_write_reg(priv, 0x09, (u8)((g_ctl << 5) | f_ctl)); 309 /* Write LPF cutoff frequency */ 310 horus3a_write_reg(priv, 0x37, (u8)(0x80 | (fc_lpf << 1))); 311 /* Start Calibration */ 312 horus3a_write_reg(priv, 0x05, 0x80); 313 /* IQ Generator enable */ 314 horus3a_write_reg(priv, 0x2a, 0x7b); 315 /* tuner stabilization time */ 316 msleep(60); 317 /* Store tuned frequency to the struct */ 318 priv->frequency = ms * 2 * 1000 / mixdiv; 319 return 0; 320 } 321 322 static int horus3a_get_frequency(struct dvb_frontend *fe, u32 *frequency) 323 { 324 struct horus3a_priv *priv = fe->tuner_priv; 325 326 *frequency = priv->frequency; 327 return 0; 328 } 329 330 static const struct dvb_tuner_ops horus3a_tuner_ops = { 331 .info = { 332 .name = "Sony Horus3a", 333 .frequency_min_hz = 950 * MHz, 334 .frequency_max_hz = 2150 * MHz, 335 .frequency_step_hz = 1 * MHz, 336 }, 337 .init = horus3a_init, 338 .release = horus3a_release, 339 .sleep = horus3a_sleep, 340 .set_params = horus3a_set_params, 341 .get_frequency = horus3a_get_frequency, 342 }; 343 344 struct dvb_frontend *horus3a_attach(struct dvb_frontend *fe, 345 const struct horus3a_config *config, 346 struct i2c_adapter *i2c) 347 { 348 u8 buf[3], val; 349 struct horus3a_priv *priv = NULL; 350 351 priv = kzalloc(sizeof(struct horus3a_priv), GFP_KERNEL); 352 if (priv == NULL) 353 return NULL; 354 priv->i2c_address = (config->i2c_address >> 1); 355 priv->i2c = i2c; 356 priv->set_tuner_data = config->set_tuner_priv; 357 priv->set_tuner = config->set_tuner_callback; 358 359 if (fe->ops.i2c_gate_ctrl) 360 fe->ops.i2c_gate_ctrl(fe, 1); 361 362 /* wait 4ms after power on */ 363 usleep_range(4000, 6000); 364 /* IQ Generator disable */ 365 horus3a_write_reg(priv, 0x2a, 0x79); 366 /* REF_R = Xtal Frequency */ 367 buf[0] = config->xtal_freq_mhz; 368 buf[1] = config->xtal_freq_mhz; 369 buf[2] = 0; 370 /* 0x6 - 0x8 */ 371 horus3a_write_regs(priv, 0x6, buf, 3); 372 /* IQ Out = Single Ended */ 373 horus3a_write_reg(priv, 0x0a, 0x40); 374 switch (config->xtal_freq_mhz) { 375 case 27: 376 val = 0x1f; 377 break; 378 case 24: 379 val = 0x10; 380 break; 381 case 16: 382 val = 0xc; 383 break; 384 default: 385 val = 0; 386 dev_warn(&priv->i2c->dev, 387 "horus3a: invalid xtal frequency %dMHz\n", 388 config->xtal_freq_mhz); 389 break; 390 } 391 val <<= 2; 392 horus3a_write_reg(priv, 0x0e, val); 393 horus3a_enter_power_save(priv); 394 usleep_range(3000, 5000); 395 396 if (fe->ops.i2c_gate_ctrl) 397 fe->ops.i2c_gate_ctrl(fe, 0); 398 399 memcpy(&fe->ops.tuner_ops, &horus3a_tuner_ops, 400 sizeof(struct dvb_tuner_ops)); 401 fe->tuner_priv = priv; 402 dev_info(&priv->i2c->dev, 403 "Sony HORUS3A attached on addr=%x at I2C adapter %p\n", 404 priv->i2c_address, priv->i2c); 405 return fe; 406 } 407 EXPORT_SYMBOL(horus3a_attach); 408 409 MODULE_DESCRIPTION("Sony HORUS3A satellite tuner driver"); 410 MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>"); 411 MODULE_LICENSE("GPL"); 412