18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Zarlink DVB-T ZL10353 demodulator 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <asm/div64.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 178c2ecf20Sopenharmony_ci#include "zl10353_priv.h" 188c2ecf20Sopenharmony_ci#include "zl10353.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct zl10353_state { 218c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 228c2ecf20Sopenharmony_ci struct dvb_frontend frontend; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci struct zl10353_config config; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci u32 bandwidth; 278c2ecf20Sopenharmony_ci u32 ucblocks; 288c2ecf20Sopenharmony_ci u32 frequency; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int debug; 328c2ecf20Sopenharmony_ci#define dprintk(args...) \ 338c2ecf20Sopenharmony_ci do { \ 348c2ecf20Sopenharmony_ci if (debug) printk(KERN_DEBUG "zl10353: " args); \ 358c2ecf20Sopenharmony_ci } while (0) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int debug_regs; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 428c2ecf20Sopenharmony_ci u8 buf[2] = { reg, val }; 438c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, 448c2ecf20Sopenharmony_ci .buf = buf, .len = 2 }; 458c2ecf20Sopenharmony_ci int err = i2c_transfer(state->i2c, &msg, 1); 468c2ecf20Sopenharmony_ci if (err != 1) { 478c2ecf20Sopenharmony_ci printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err); 488c2ecf20Sopenharmony_ci return err; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci int err, i; 568c2ecf20Sopenharmony_ci for (i = 0; i < ilen - 1; i++) 578c2ecf20Sopenharmony_ci if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1]))) 588c2ecf20Sopenharmony_ci return err; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int zl10353_read_register(struct zl10353_state *state, u8 reg) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int ret; 668c2ecf20Sopenharmony_ci u8 b0[1] = { reg }; 678c2ecf20Sopenharmony_ci u8 b1[1] = { 0 }; 688c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { { .addr = state->config.demod_address, 698c2ecf20Sopenharmony_ci .flags = 0, 708c2ecf20Sopenharmony_ci .buf = b0, .len = 1 }, 718c2ecf20Sopenharmony_ci { .addr = state->config.demod_address, 728c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 738c2ecf20Sopenharmony_ci .buf = b1, .len = 1 } }; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, msg, 2); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (ret != 2) { 788c2ecf20Sopenharmony_ci printk("%s: readreg error (reg=%d, ret==%i)\n", 798c2ecf20Sopenharmony_ci __func__, reg, ret); 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return b1[0]; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void zl10353_dump_regs(struct dvb_frontend *fe) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 898c2ecf20Sopenharmony_ci int ret; 908c2ecf20Sopenharmony_ci u8 reg; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* Dump all registers. */ 938c2ecf20Sopenharmony_ci for (reg = 0; ; reg++) { 948c2ecf20Sopenharmony_ci if (reg % 16 == 0) { 958c2ecf20Sopenharmony_ci if (reg) 968c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 978c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%02x:", reg); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci ret = zl10353_read_register(state, reg); 1008c2ecf20Sopenharmony_ci if (ret >= 0) 1018c2ecf20Sopenharmony_ci printk(KERN_CONT " %02x", (u8)ret); 1028c2ecf20Sopenharmony_ci else 1038c2ecf20Sopenharmony_ci printk(KERN_CONT " --"); 1048c2ecf20Sopenharmony_ci if (reg == 0xff) 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void zl10353_calc_nominal_rate(struct dvb_frontend *fe, 1118c2ecf20Sopenharmony_ci u32 bandwidth, 1128c2ecf20Sopenharmony_ci u16 *nominal_rate) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 1158c2ecf20Sopenharmony_ci u32 adc_clock = 450560; /* 45.056 MHz */ 1168c2ecf20Sopenharmony_ci u64 value; 1178c2ecf20Sopenharmony_ci u8 bw = bandwidth / 1000000; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (state->config.adc_clock) 1208c2ecf20Sopenharmony_ci adc_clock = state->config.adc_clock; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci value = (u64)10 * (1 << 23) / 7 * 125; 1238c2ecf20Sopenharmony_ci value = (bw * value) + adc_clock / 2; 1248c2ecf20Sopenharmony_ci *nominal_rate = div_u64(value, adc_clock); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci dprintk("%s: bw %d, adc_clock %d => 0x%x\n", 1278c2ecf20Sopenharmony_ci __func__, bw, adc_clock, *nominal_rate); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void zl10353_calc_input_freq(struct dvb_frontend *fe, 1318c2ecf20Sopenharmony_ci u16 *input_freq) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 1348c2ecf20Sopenharmony_ci u32 adc_clock = 450560; /* 45.056 MHz */ 1358c2ecf20Sopenharmony_ci int if2 = 361667; /* 36.1667 MHz */ 1368c2ecf20Sopenharmony_ci int ife; 1378c2ecf20Sopenharmony_ci u64 value; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (state->config.adc_clock) 1408c2ecf20Sopenharmony_ci adc_clock = state->config.adc_clock; 1418c2ecf20Sopenharmony_ci if (state->config.if2) 1428c2ecf20Sopenharmony_ci if2 = state->config.if2; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (adc_clock >= if2 * 2) 1458c2ecf20Sopenharmony_ci ife = if2; 1468c2ecf20Sopenharmony_ci else { 1478c2ecf20Sopenharmony_ci ife = adc_clock - (if2 % adc_clock); 1488c2ecf20Sopenharmony_ci if (ife > adc_clock / 2) 1498c2ecf20Sopenharmony_ci ife = adc_clock - ife; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci value = div_u64((u64)65536 * ife + adc_clock / 2, adc_clock); 1528c2ecf20Sopenharmony_ci *input_freq = -value; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", 1558c2ecf20Sopenharmony_ci __func__, if2, ife, adc_clock, -(int)value, *input_freq); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int zl10353_sleep(struct dvb_frontend *fe) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 }; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown)); 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int zl10353_set_parameters(struct dvb_frontend *fe) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1698c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 1708c2ecf20Sopenharmony_ci u16 nominal_rate, input_freq; 1718c2ecf20Sopenharmony_ci u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; 1728c2ecf20Sopenharmony_ci u16 tps = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci state->frequency = c->frequency; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci zl10353_single_write(fe, RESET, 0x80); 1778c2ecf20Sopenharmony_ci udelay(200); 1788c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0xEA, 0x01); 1798c2ecf20Sopenharmony_ci udelay(200); 1808c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0xEA, 0x00); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci zl10353_single_write(fe, AGC_TARGET, 0x28); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (c->transmission_mode != TRANSMISSION_MODE_AUTO) 1858c2ecf20Sopenharmony_ci acq_ctl |= (1 << 0); 1868c2ecf20Sopenharmony_ci if (c->guard_interval != GUARD_INTERVAL_AUTO) 1878c2ecf20Sopenharmony_ci acq_ctl |= (1 << 1); 1888c2ecf20Sopenharmony_ci zl10353_single_write(fe, ACQ_CTL, acq_ctl); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci switch (c->bandwidth_hz) { 1918c2ecf20Sopenharmony_ci case 6000000: 1928c2ecf20Sopenharmony_ci /* These are extrapolated from the 7 and 8MHz values */ 1938c2ecf20Sopenharmony_ci zl10353_single_write(fe, MCLK_RATIO, 0x97); 1948c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0x64, 0x34); 1958c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0xcc, 0xdd); 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case 7000000: 1988c2ecf20Sopenharmony_ci zl10353_single_write(fe, MCLK_RATIO, 0x86); 1998c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0x64, 0x35); 2008c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0xcc, 0x73); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci default: 2038c2ecf20Sopenharmony_ci c->bandwidth_hz = 8000000; 2048c2ecf20Sopenharmony_ci fallthrough; 2058c2ecf20Sopenharmony_ci case 8000000: 2068c2ecf20Sopenharmony_ci zl10353_single_write(fe, MCLK_RATIO, 0x75); 2078c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0x64, 0x36); 2088c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0xcc, 0x73); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate); 2128c2ecf20Sopenharmony_ci zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); 2138c2ecf20Sopenharmony_ci zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); 2148c2ecf20Sopenharmony_ci state->bandwidth = c->bandwidth_hz; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci zl10353_calc_input_freq(fe, &input_freq); 2178c2ecf20Sopenharmony_ci zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); 2188c2ecf20Sopenharmony_ci zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Hint at TPS settings */ 2218c2ecf20Sopenharmony_ci switch (c->code_rate_HP) { 2228c2ecf20Sopenharmony_ci case FEC_2_3: 2238c2ecf20Sopenharmony_ci tps |= (1 << 7); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case FEC_3_4: 2268c2ecf20Sopenharmony_ci tps |= (2 << 7); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case FEC_5_6: 2298c2ecf20Sopenharmony_ci tps |= (3 << 7); 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case FEC_7_8: 2328c2ecf20Sopenharmony_ci tps |= (4 << 7); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci case FEC_1_2: 2358c2ecf20Sopenharmony_ci case FEC_AUTO: 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci default: 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci switch (c->code_rate_LP) { 2428c2ecf20Sopenharmony_ci case FEC_2_3: 2438c2ecf20Sopenharmony_ci tps |= (1 << 4); 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci case FEC_3_4: 2468c2ecf20Sopenharmony_ci tps |= (2 << 4); 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci case FEC_5_6: 2498c2ecf20Sopenharmony_ci tps |= (3 << 4); 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case FEC_7_8: 2528c2ecf20Sopenharmony_ci tps |= (4 << 4); 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case FEC_1_2: 2558c2ecf20Sopenharmony_ci case FEC_AUTO: 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case FEC_NONE: 2588c2ecf20Sopenharmony_ci if (c->hierarchy == HIERARCHY_AUTO || 2598c2ecf20Sopenharmony_ci c->hierarchy == HIERARCHY_NONE) 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci fallthrough; 2628c2ecf20Sopenharmony_ci default: 2638c2ecf20Sopenharmony_ci return -EINVAL; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci switch (c->modulation) { 2678c2ecf20Sopenharmony_ci case QPSK: 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci case QAM_AUTO: 2708c2ecf20Sopenharmony_ci case QAM_16: 2718c2ecf20Sopenharmony_ci tps |= (1 << 13); 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case QAM_64: 2748c2ecf20Sopenharmony_ci tps |= (2 << 13); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci default: 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci switch (c->transmission_mode) { 2818c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: 2828c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_AUTO: 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: 2858c2ecf20Sopenharmony_ci tps |= (1 << 0); 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci default: 2888c2ecf20Sopenharmony_ci return -EINVAL; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (c->guard_interval) { 2928c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: 2938c2ecf20Sopenharmony_ci case GUARD_INTERVAL_AUTO: 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: 2968c2ecf20Sopenharmony_ci tps |= (1 << 2); 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: 2998c2ecf20Sopenharmony_ci tps |= (2 << 2); 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: 3028c2ecf20Sopenharmony_ci tps |= (3 << 2); 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci default: 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci switch (c->hierarchy) { 3098c2ecf20Sopenharmony_ci case HIERARCHY_AUTO: 3108c2ecf20Sopenharmony_ci case HIERARCHY_NONE: 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci case HIERARCHY_1: 3138c2ecf20Sopenharmony_ci tps |= (1 << 10); 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci case HIERARCHY_2: 3168c2ecf20Sopenharmony_ci tps |= (2 << 10); 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case HIERARCHY_4: 3198c2ecf20Sopenharmony_ci tps |= (3 << 10); 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci default: 3228c2ecf20Sopenharmony_ci return -EINVAL; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci zl10353_single_write(fe, TPS_GIVEN_1, msb(tps)); 3268c2ecf20Sopenharmony_ci zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps)); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3298c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* 3328c2ecf20Sopenharmony_ci * If there is no tuner attached to the secondary I2C bus, we call 3338c2ecf20Sopenharmony_ci * set_params to program a potential tuner attached somewhere else. 3348c2ecf20Sopenharmony_ci * Otherwise, we update the PLL registers via calc_regs. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci if (state->config.no_tuner) { 3378c2ecf20Sopenharmony_ci if (fe->ops.tuner_ops.set_params) { 3388c2ecf20Sopenharmony_ci fe->ops.tuner_ops.set_params(fe); 3398c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3408c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci } else if (fe->ops.tuner_ops.calc_regs) { 3438c2ecf20Sopenharmony_ci fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5); 3448c2ecf20Sopenharmony_ci pllbuf[1] <<= 1; 3458c2ecf20Sopenharmony_ci zl10353_write(fe, pllbuf, sizeof(pllbuf)); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci zl10353_single_write(fe, 0x5F, 0x13); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* If no attached tuner or invalid PLL registers, just start the FSM. */ 3518c2ecf20Sopenharmony_ci if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL) 3528c2ecf20Sopenharmony_ci zl10353_single_write(fe, FSM_GO, 0x01); 3538c2ecf20Sopenharmony_ci else 3548c2ecf20Sopenharmony_ci zl10353_single_write(fe, TUNER_GO, 0x01); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int zl10353_get_parameters(struct dvb_frontend *fe, 3608c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 3638c2ecf20Sopenharmony_ci int s6, s9; 3648c2ecf20Sopenharmony_ci u16 tps; 3658c2ecf20Sopenharmony_ci static const u8 tps_fec_to_api[8] = { 3668c2ecf20Sopenharmony_ci FEC_1_2, 3678c2ecf20Sopenharmony_ci FEC_2_3, 3688c2ecf20Sopenharmony_ci FEC_3_4, 3698c2ecf20Sopenharmony_ci FEC_5_6, 3708c2ecf20Sopenharmony_ci FEC_7_8, 3718c2ecf20Sopenharmony_ci FEC_AUTO, 3728c2ecf20Sopenharmony_ci FEC_AUTO, 3738c2ecf20Sopenharmony_ci FEC_AUTO 3748c2ecf20Sopenharmony_ci }; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci s6 = zl10353_read_register(state, STATUS_6); 3778c2ecf20Sopenharmony_ci s9 = zl10353_read_register(state, STATUS_9); 3788c2ecf20Sopenharmony_ci if (s6 < 0 || s9 < 0) 3798c2ecf20Sopenharmony_ci return -EREMOTEIO; 3808c2ecf20Sopenharmony_ci if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0) 3818c2ecf20Sopenharmony_ci return -EINVAL; /* no FE or TPS lock */ 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | 3848c2ecf20Sopenharmony_ci zl10353_read_register(state, TPS_RECEIVED_0); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; 3878c2ecf20Sopenharmony_ci c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci switch ((tps >> 13) & 3) { 3908c2ecf20Sopenharmony_ci case 0: 3918c2ecf20Sopenharmony_ci c->modulation = QPSK; 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci case 1: 3948c2ecf20Sopenharmony_ci c->modulation = QAM_16; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case 2: 3978c2ecf20Sopenharmony_ci c->modulation = QAM_64; 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci default: 4008c2ecf20Sopenharmony_ci c->modulation = QAM_AUTO; 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : 4058c2ecf20Sopenharmony_ci TRANSMISSION_MODE_2K; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci switch ((tps >> 2) & 3) { 4088c2ecf20Sopenharmony_ci case 0: 4098c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_32; 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci case 1: 4128c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_16; 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case 2: 4158c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_8; 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci case 3: 4188c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_1_4; 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci default: 4218c2ecf20Sopenharmony_ci c->guard_interval = GUARD_INTERVAL_AUTO; 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci switch ((tps >> 10) & 7) { 4268c2ecf20Sopenharmony_ci case 0: 4278c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_NONE; 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case 1: 4308c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_1; 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case 2: 4338c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_2; 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci case 3: 4368c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_4; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci default: 4398c2ecf20Sopenharmony_ci c->hierarchy = HIERARCHY_AUTO; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci c->frequency = state->frequency; 4448c2ecf20Sopenharmony_ci c->bandwidth_hz = state->bandwidth; 4458c2ecf20Sopenharmony_ci c->inversion = INVERSION_AUTO; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int zl10353_read_status(struct dvb_frontend *fe, enum fe_status *status) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 4538c2ecf20Sopenharmony_ci int s6, s7, s8; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if ((s6 = zl10353_read_register(state, STATUS_6)) < 0) 4568c2ecf20Sopenharmony_ci return -EREMOTEIO; 4578c2ecf20Sopenharmony_ci if ((s7 = zl10353_read_register(state, STATUS_7)) < 0) 4588c2ecf20Sopenharmony_ci return -EREMOTEIO; 4598c2ecf20Sopenharmony_ci if ((s8 = zl10353_read_register(state, STATUS_8)) < 0) 4608c2ecf20Sopenharmony_ci return -EREMOTEIO; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci *status = 0; 4638c2ecf20Sopenharmony_ci if (s6 & (1 << 2)) 4648c2ecf20Sopenharmony_ci *status |= FE_HAS_CARRIER; 4658c2ecf20Sopenharmony_ci if (s6 & (1 << 1)) 4668c2ecf20Sopenharmony_ci *status |= FE_HAS_VITERBI; 4678c2ecf20Sopenharmony_ci if (s6 & (1 << 5)) 4688c2ecf20Sopenharmony_ci *status |= FE_HAS_LOCK; 4698c2ecf20Sopenharmony_ci if (s7 & (1 << 4)) 4708c2ecf20Sopenharmony_ci *status |= FE_HAS_SYNC; 4718c2ecf20Sopenharmony_ci if (s8 & (1 << 6)) 4728c2ecf20Sopenharmony_ci *status |= FE_HAS_SIGNAL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != 4758c2ecf20Sopenharmony_ci (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) 4768c2ecf20Sopenharmony_ci *status &= ~FE_HAS_LOCK; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci *ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 | 4868c2ecf20Sopenharmony_ci zl10353_read_register(state, RS_ERR_CNT_1) << 8 | 4878c2ecf20Sopenharmony_ci zl10353_read_register(state, RS_ERR_CNT_0); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 | 4978c2ecf20Sopenharmony_ci zl10353_read_register(state, AGC_GAIN_0) << 2 | 3; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci *strength = ~signal; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 5078c2ecf20Sopenharmony_ci u8 _snr; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (debug_regs) 5108c2ecf20Sopenharmony_ci zl10353_dump_regs(fe); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci _snr = zl10353_read_register(state, SNR); 5138c2ecf20Sopenharmony_ci *snr = 10 * _snr / 8; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 5218c2ecf20Sopenharmony_ci u32 ubl = 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci ubl = zl10353_read_register(state, RS_UBC_1) << 8 | 5248c2ecf20Sopenharmony_ci zl10353_read_register(state, RS_UBC_0); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci state->ucblocks += ubl; 5278c2ecf20Sopenharmony_ci *ucblocks = state->ucblocks; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int zl10353_get_tune_settings(struct dvb_frontend *fe, 5338c2ecf20Sopenharmony_ci struct dvb_frontend_tune_settings 5348c2ecf20Sopenharmony_ci *fe_tune_settings) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci fe_tune_settings->min_delay_ms = 1000; 5378c2ecf20Sopenharmony_ci fe_tune_settings->step_size = 0; 5388c2ecf20Sopenharmony_ci fe_tune_settings->max_drift = 0; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int zl10353_init(struct dvb_frontend *fe) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 5468c2ecf20Sopenharmony_ci u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F }; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (debug_regs) 5498c2ecf20Sopenharmony_ci zl10353_dump_regs(fe); 5508c2ecf20Sopenharmony_ci if (state->config.parallel_ts) 5518c2ecf20Sopenharmony_ci zl10353_reset_attach[2] &= ~0x20; 5528c2ecf20Sopenharmony_ci if (state->config.clock_ctl_1) 5538c2ecf20Sopenharmony_ci zl10353_reset_attach[3] = state->config.clock_ctl_1; 5548c2ecf20Sopenharmony_ci if (state->config.pll_0) 5558c2ecf20Sopenharmony_ci zl10353_reset_attach[4] = state->config.pll_0; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Do a "hard" reset if not already done */ 5588c2ecf20Sopenharmony_ci if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] || 5598c2ecf20Sopenharmony_ci zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) { 5608c2ecf20Sopenharmony_ci zl10353_write(fe, zl10353_reset_attach, 5618c2ecf20Sopenharmony_ci sizeof(zl10353_reset_attach)); 5628c2ecf20Sopenharmony_ci if (debug_regs) 5638c2ecf20Sopenharmony_ci zl10353_dump_regs(fe); 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 5728c2ecf20Sopenharmony_ci u8 val = 0x0a; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (state->config.disable_i2c_gate_ctrl) { 5758c2ecf20Sopenharmony_ci /* No tuner attached to the internal I2C bus */ 5768c2ecf20Sopenharmony_ci /* If set enable I2C bridge, the main I2C bus stopped hardly */ 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (enable) 5818c2ecf20Sopenharmony_ci val |= 0x10; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return zl10353_single_write(fe, 0x62, val); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic void zl10353_release(struct dvb_frontend *fe) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct zl10353_state *state = fe->demodulator_priv; 5898c2ecf20Sopenharmony_ci kfree(state); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops zl10353_ops; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistruct dvb_frontend *zl10353_attach(const struct zl10353_config *config, 5958c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct zl10353_state *state = NULL; 5988c2ecf20Sopenharmony_ci int id; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* allocate memory for the internal state */ 6018c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL); 6028c2ecf20Sopenharmony_ci if (state == NULL) 6038c2ecf20Sopenharmony_ci goto error; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* setup the state */ 6068c2ecf20Sopenharmony_ci state->i2c = i2c; 6078c2ecf20Sopenharmony_ci memcpy(&state->config, config, sizeof(struct zl10353_config)); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* check if the demod is there */ 6108c2ecf20Sopenharmony_ci id = zl10353_read_register(state, CHIP_ID); 6118c2ecf20Sopenharmony_ci if ((id != ID_ZL10353) && (id != ID_CE6230) && (id != ID_CE6231)) 6128c2ecf20Sopenharmony_ci goto error; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* create dvb_frontend */ 6158c2ecf20Sopenharmony_ci memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops)); 6168c2ecf20Sopenharmony_ci state->frontend.demodulator_priv = state; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return &state->frontend; 6198c2ecf20Sopenharmony_cierror: 6208c2ecf20Sopenharmony_ci kfree(state); 6218c2ecf20Sopenharmony_ci return NULL; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops zl10353_ops = { 6258c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 6268c2ecf20Sopenharmony_ci .info = { 6278c2ecf20Sopenharmony_ci .name = "Zarlink ZL10353 DVB-T", 6288c2ecf20Sopenharmony_ci .frequency_min_hz = 174 * MHz, 6298c2ecf20Sopenharmony_ci .frequency_max_hz = 862 * MHz, 6308c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 166667, 6318c2ecf20Sopenharmony_ci .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | 6328c2ecf20Sopenharmony_ci FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | 6338c2ecf20Sopenharmony_ci FE_CAN_FEC_AUTO | 6348c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 6358c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | 6368c2ecf20Sopenharmony_ci FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | 6378c2ecf20Sopenharmony_ci FE_CAN_MUTE_TS 6388c2ecf20Sopenharmony_ci }, 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci .release = zl10353_release, 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci .init = zl10353_init, 6438c2ecf20Sopenharmony_ci .sleep = zl10353_sleep, 6448c2ecf20Sopenharmony_ci .i2c_gate_ctrl = zl10353_i2c_gate_ctrl, 6458c2ecf20Sopenharmony_ci .write = zl10353_write, 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci .set_frontend = zl10353_set_parameters, 6488c2ecf20Sopenharmony_ci .get_frontend = zl10353_get_parameters, 6498c2ecf20Sopenharmony_ci .get_tune_settings = zl10353_get_tune_settings, 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci .read_status = zl10353_read_status, 6528c2ecf20Sopenharmony_ci .read_ber = zl10353_read_ber, 6538c2ecf20Sopenharmony_ci .read_signal_strength = zl10353_read_signal_strength, 6548c2ecf20Sopenharmony_ci .read_snr = zl10353_read_snr, 6558c2ecf20Sopenharmony_ci .read_ucblocks = zl10353_read_ucblocks, 6568c2ecf20Sopenharmony_ci}; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 6598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cimodule_param(debug_regs, int, 0644); 6628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off)."); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver"); 6658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chris Pascoe"); 6668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zl10353_attach); 669