diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 17:21:51 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 17:21:51 (GMT) |
commit | ab11ca34eea8fda7a1a9302d86f6ef6108ffd68f (patch) | |
tree | 987ec6c263f3dfa4a7a6f9ce4d5ece47cbc12e29 /drivers/media/dvb/frontends | |
parent | f9369910a6225b8d4892c3f20ae740a711cd5ace (diff) | |
parent | 71006fb22b0f5a2045605b3887ee99a0e9adafe4 (diff) | |
download | linux-ab11ca34eea8fda7a1a9302d86f6ef6108ffd68f.tar.xz |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- some V4L2 API updates needed by embedded devices
- DVB API extensions for ATSC-MH delivery system, used in US for mobile
TV
- new tuners for fc0011/0012/0013 and tua9001
- a new dvb driver for af9033/9035
- a new ATSC-MH frontend (lg2160)
- new remote controller keymaps
- Removal of a few legacy webcam driver that got replaced by gspca on
several kernel versions ago
- a new driver for Exynos 4/5 webcams(s5pp fimc-lite)
- a new webcam sensor driver (smiapp)
- a new video input driver for embedded (sta2x1xx)
- several improvements, fixes, cleanups, etc inside the drivers.
Manually fix up conflicts due to err() -> dev_err() conversion in
drivers/staging/media/easycap/easycap_main.c
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (484 commits)
[media] saa7134-cards: Remove a PCI entry added by mistake
[media] radio-sf16fmi: add support for SF16-FMD
[media] rc-loopback: remove duplicate line
[media] patch for Asus My Cinema PS3-100 (1043:48cd)
[media] au0828: Move the Kconfig knob under V4L_USB_DRIVERS
[media] em28xx: simple comment fix
[media] [resend] radio-sf16fmr2: add PnP support for SF16-FMD2
[media] smiapp: Use v4l2_ctrl_new_int_menu() instead of v4l2_ctrl_new_custom()
[media] smiapp: Add support for 8-bit uncompressed formats
[media] smiapp: Allow generic quirk registers
[media] smiapp: Use non-binning limits if the binning limit is zero
[media] smiapp: Initialise rval in smiapp_read_nvm()
[media] smiapp: Round minimum pre_pll up rather than down in ip_clk_freq check
[media] smiapp: Use 8-bit reads only before identifying the sensor
[media] smiapp: Quirk for sensors that only do 8-bit reads
[media] smiapp: Pass struct sensor to register writing commands instead of i2c_client
[media] smiapp: Allow using external clock from the clock framework
[media] zl10353: change .read_snr() to report SNR as a 0.1 dB
[media] media: add support to gspca/pac7302.c for 093a:2627 (Genius FaceCam 300)
[media] m88rs2000 - only flip bit 2 on reg 0x70 on 16th try
...
Diffstat (limited to 'drivers/media/dvb/frontends')
30 files changed, 3713 insertions, 363 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 2124670..b98ebb2 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -531,6 +531,14 @@ config DVB_LGDT3305 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LG2160 + tristate "LG Electronics LG216x based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC/MH demodulator module. Say Y when you want + to support this frontend. + config DVB_S5H1409 tristate "Samsung S5H1409 based" depends on DVB_CORE && I2C @@ -540,12 +548,26 @@ config DVB_S5H1409 to support this frontend. config DVB_AU8522 - tristate "Auvitek AU8522 based" - depends on DVB_CORE && I2C && VIDEO_V4L2 + depends on I2C + tristate + +config DVB_AU8522_DTV + tristate "Auvitek AU8522 based DTV demod" + depends on DVB_CORE && I2C + select DVB_AU8522 default m if DVB_FE_CUSTOMISE help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. + An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when + you want to enable DTV demodulation support for this frontend. + +config DVB_AU8522_V4L + tristate "Auvitek AU8522 based ATV demod" + depends on VIDEO_V4L2 && I2C + select DVB_AU8522 + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when + you want to enable ATV demodulation support for this frontend. config DVB_S5H1411 tristate "Samsung S5H1411 based" @@ -713,6 +735,11 @@ config DVB_M88RS2000 A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_AF9033 + tristate "Afatech AF9033 DVB-T demodulator" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 86fa808..cd1ac2f 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -7,7 +7,6 @@ ccflags-y += -I$(srctree)/drivers/media/common/tuners/ stb0899-objs = stb0899_drv.o stb0899_algo.o stv0900-objs = stv0900_core.o stv0900_sw.o -au8522-objs = au8522_dig.o au8522_decoder.o drxd-objs = drxd_firm.o drxd_hard.o cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o drxk-objs := drxk_hard.o @@ -50,6 +49,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o +obj-$(CONFIG_DVB_LG2160) += lg2160.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_LNBP22) += lnbp22.o @@ -63,7 +63,9 @@ obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o -obj-$(CONFIG_DVB_AU8522) += au8522.o +obj-$(CONFIG_DVB_AU8522) += au8522_common.o +obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o +obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o @@ -98,4 +100,5 @@ obj-$(CONFIG_DVB_A8293) += a8293.o obj-$(CONFIG_DVB_TDA10071) += tda10071.o obj-$(CONFIG_DVB_RTL2830) += rtl2830.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o +obj-$(CONFIG_DVB_AF9033) += af9033.o diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 6bcbcf5..5bc570d 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -514,7 +514,6 @@ err: static void af9013_statistics_work(struct work_struct *work) { - int ret; struct af9013_state *state = container_of(work, struct af9013_state, statistics_work.work); unsigned int next_msec; @@ -530,27 +529,27 @@ static void af9013_statistics_work(struct work_struct *work) default: state->statistics_step = 0; case 0: - ret = af9013_statistics_signal_strength(&state->fe); + af9013_statistics_signal_strength(&state->fe); state->statistics_step++; next_msec = 300; break; case 1: - ret = af9013_statistics_snr_start(&state->fe); + af9013_statistics_snr_start(&state->fe); state->statistics_step++; next_msec = 200; break; case 2: - ret = af9013_statistics_ber_unc_start(&state->fe); + af9013_statistics_ber_unc_start(&state->fe); state->statistics_step++; next_msec = 1000; break; case 3: - ret = af9013_statistics_snr_result(&state->fe); + af9013_statistics_snr_result(&state->fe); state->statistics_step++; next_msec = 400; break; case 4: - ret = af9013_statistics_ber_unc_result(&state->fe); + af9013_statistics_ber_unc_result(&state->fe); state->statistics_step++; next_msec = 100; break; @@ -558,8 +557,6 @@ static void af9013_statistics_work(struct work_struct *work) schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(next_msec)); - - return; } static int af9013_get_tune_settings(struct dvb_frontend *fe, diff --git a/drivers/media/dvb/frontends/af9033.c b/drivers/media/dvb/frontends/af9033.c new file mode 100644 index 0000000..a389982 --- /dev/null +++ b/drivers/media/dvb/frontends/af9033.c @@ -0,0 +1,980 @@ +/* + * Afatech AF9033 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "af9033_priv.h" + +struct af9033_state { + struct i2c_adapter *i2c; + struct dvb_frontend fe; + struct af9033_config cfg; + + u32 bandwidth_hz; + bool ts_mode_parallel; + bool ts_mode_serial; + + u32 ber; + u32 ucb; + unsigned long last_stat_check; +}; + +/* write multiple registers */ +static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, + int len) +{ + int ret; + u8 buf[3 + len]; + struct i2c_msg msg[1] = { + { + .addr = state->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = (reg >> 16) & 0xff; + buf[1] = (reg >> 8) & 0xff; + buf[2] = (reg >> 0) & 0xff; + memcpy(&buf[3], val, len); + + ret = i2c_transfer(state->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n", + __func__, ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* read multiple registers */ +static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) +{ + int ret; + u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff, + (reg >> 0) & 0xff }; + struct i2c_msg msg[2] = { + { + .addr = state->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf + }, { + .addr = state->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n", + __func__, ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + + +/* write single register */ +static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val) +{ + return af9033_wr_regs(state, reg, &val, 1); +} + +/* read single register */ +static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val) +{ + return af9033_rd_regs(state, reg, val, 1); +} + +/* write single register with mask */ +static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, + u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = af9033_rd_regs(state, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return af9033_wr_regs(state, reg, &val, 1); +} + +/* read single register with mask */ +static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, + u8 mask) +{ + int ret, i; + u8 tmp; + + ret = af9033_rd_regs(state, reg, &tmp, 1); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +static u32 af9033_div(u32 a, u32 b, u32 x) +{ + u32 r = 0, c = 0, i; + + pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x); + + if (a > b) { + c = a / b; + a = a - c * b; + } + + for (i = 0; i < x; i++) { + if (a >= b) { + r += 1; + a -= b; + } + a <<= 1; + r <<= 1; + } + r = (c << (u32)x) + r; + + pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r); + + return r; +} + +static void af9033_release(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + + kfree(state); +} + +static int af9033_init(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret, i, len; + const struct reg_val *init; + u8 buf[4]; + u32 adc_cw, clock_cw; + struct reg_val_mask tab[] = { + { 0x80fb24, 0x00, 0x08 }, + { 0x80004c, 0x00, 0xff }, + { 0x00f641, state->cfg.tuner, 0xff }, + { 0x80f5ca, 0x01, 0x01 }, + { 0x80f715, 0x01, 0x01 }, + { 0x00f41f, 0x04, 0x04 }, + { 0x00f41a, 0x01, 0x01 }, + { 0x80f731, 0x00, 0x01 }, + { 0x00d91e, 0x00, 0x01 }, + { 0x00d919, 0x00, 0x01 }, + { 0x80f732, 0x00, 0x01 }, + { 0x00d91f, 0x00, 0x01 }, + { 0x00d91a, 0x00, 0x01 }, + { 0x80f730, 0x00, 0x01 }, + { 0x80f778, 0x00, 0xff }, + { 0x80f73c, 0x01, 0x01 }, + { 0x80f776, 0x00, 0x01 }, + { 0x00d8fd, 0x01, 0xff }, + { 0x00d830, 0x01, 0xff }, + { 0x00d831, 0x00, 0xff }, + { 0x00d832, 0x00, 0xff }, + { 0x80f985, state->ts_mode_serial, 0x01 }, + { 0x80f986, state->ts_mode_parallel, 0x01 }, + { 0x00d827, 0x00, 0xff }, + { 0x00d829, 0x00, 0xff }, + }; + + /* program clock control */ + clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul); + buf[0] = (clock_cw >> 0) & 0xff; + buf[1] = (clock_cw >> 8) & 0xff; + buf[2] = (clock_cw >> 16) & 0xff; + buf[3] = (clock_cw >> 24) & 0xff; + + pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock, + clock_cw); + + ret = af9033_wr_regs(state, 0x800025, buf, 4); + if (ret < 0) + goto err; + + /* program ADC control */ + for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { + if (clock_adc_lut[i].clock == state->cfg.clock) + break; + } + + adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul); + buf[0] = (adc_cw >> 0) & 0xff; + buf[1] = (adc_cw >> 8) & 0xff; + buf[2] = (adc_cw >> 16) & 0xff; + + pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc, + adc_cw); + + ret = af9033_wr_regs(state, 0x80f1cd, buf, 3); + if (ret < 0) + goto err; + + /* program register table */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret < 0) + goto err; + } + + /* settings for TS interface */ + if (state->cfg.ts_mode == AF9033_TS_MODE_USB) { + ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01); + if (ret < 0) + goto err; + } else { + ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01); + if (ret < 0) + goto err; + } + + /* load OFSM settings */ + pr_debug("%s: load ofsm settings\n", __func__); + len = ARRAY_SIZE(ofsm_init); + init = ofsm_init; + for (i = 0; i < len; i++) { + ret = af9033_wr_reg(state, init[i].reg, init[i].val); + if (ret < 0) + goto err; + } + + /* load tuner specific settings */ + pr_debug("%s: load tuner specific settings\n", + __func__); + switch (state->cfg.tuner) { + case AF9033_TUNER_TUA9001: + len = ARRAY_SIZE(tuner_init_tua9001); + init = tuner_init_tua9001; + break; + case AF9033_TUNER_FC0011: + len = ARRAY_SIZE(tuner_init_fc0011); + init = tuner_init_fc0011; + break; + case AF9033_TUNER_MXL5007T: + len = ARRAY_SIZE(tuner_init_mxl5007t); + init = tuner_init_mxl5007t; + break; + case AF9033_TUNER_TDA18218: + len = ARRAY_SIZE(tuner_init_tda18218); + init = tuner_init_tda18218; + break; + default: + pr_debug("%s: unsupported tuner ID=%d\n", __func__, + state->cfg.tuner); + ret = -ENODEV; + goto err; + } + + for (i = 0; i < len; i++) { + ret = af9033_wr_reg(state, init[i].reg, init[i].val); + if (ret < 0) + goto err; + } + + state->bandwidth_hz = 0; /* force to program all parameters */ + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_sleep(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret, i; + u8 tmp; + + ret = af9033_wr_reg(state, 0x80004c, 1); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800000, 0); + if (ret < 0) + goto err; + + for (i = 100, tmp = 1; i && tmp; i--) { + ret = af9033_rd_reg(state, 0x80004c, &tmp); + if (ret < 0) + goto err; + + usleep_range(200, 10000); + } + + pr_debug("%s: loop=%d\n", __func__, i); + + if (i == 0) { + ret = -ETIMEDOUT; + goto err; + } + + ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08); + if (ret < 0) + goto err; + + /* prevent current leak (?) */ + if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { + /* enable parallel TS */ + ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01); + if (ret < 0) + goto err; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int af9033_set_frontend(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i, spec_inv; + u8 tmp, buf[3], bandwidth_reg_val; + u32 if_frequency, freq_cw, adc_freq; + + pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency, + c->bandwidth_hz); + + /* check bandwidth */ + switch (c->bandwidth_hz) { + case 6000000: + bandwidth_reg_val = 0x00; + break; + case 7000000: + bandwidth_reg_val = 0x01; + break; + case 8000000: + bandwidth_reg_val = 0x02; + break; + default: + pr_debug("%s: invalid bandwidth_hz\n", __func__); + ret = -EINVAL; + goto err; + } + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + /* program CFOE coefficients */ + if (c->bandwidth_hz != state->bandwidth_hz) { + for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { + if (coeff_lut[i].clock == state->cfg.clock && + coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { + break; + } + } + ret = af9033_wr_regs(state, 0x800001, + coeff_lut[i].val, sizeof(coeff_lut[i].val)); + } + + /* program frequency control */ + if (c->bandwidth_hz != state->bandwidth_hz) { + spec_inv = state->cfg.spec_inv ? -1 : 1; + + for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { + if (clock_adc_lut[i].clock == state->cfg.clock) + break; + } + adc_freq = clock_adc_lut[i].adc; + + /* get used IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); + else + if_frequency = 0; + + while (if_frequency > (adc_freq / 2)) + if_frequency -= adc_freq; + + if (if_frequency >= 0) + spec_inv *= -1; + else + if_frequency *= -1; + + freq_cw = af9033_div(if_frequency, adc_freq, 23ul); + + if (spec_inv == -1) + freq_cw *= -1; + + /* get adc multiplies */ + ret = af9033_rd_reg(state, 0x800045, &tmp); + if (ret < 0) + goto err; + + if (tmp == 1) + freq_cw /= 2; + + buf[0] = (freq_cw >> 0) & 0xff; + buf[1] = (freq_cw >> 8) & 0xff; + buf[2] = (freq_cw >> 16) & 0x7f; + ret = af9033_wr_regs(state, 0x800029, buf, 3); + if (ret < 0) + goto err; + + state->bandwidth_hz = c->bandwidth_hz; + } + + ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800040, 0x00); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800047, 0x00); + if (ret < 0) + goto err; + + ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01); + if (ret < 0) + goto err; + + if (c->frequency <= 230000000) + tmp = 0x00; /* VHF */ + else + tmp = 0x01; /* UHF */ + + ret = af9033_wr_reg(state, 0x80004b, tmp); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800000, 0x00); + if (ret < 0) + goto err; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_get_frontend(struct dvb_frontend *fe) +{ + struct af9033_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[8]; + + pr_debug("%s\n", __func__); + + /* read all needed registers */ + ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf)); + if (ret < 0) + goto err; + + switch ((buf[0] >> 0) & 3) { + case 0: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + switch ((buf[1] >> 0) & 3) { + case 0: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[2] >> 0) & 7) { + case 0: + c->hierarchy = HIERARCHY_NONE; + break; + case 1: + c->hierarchy = HIERARCHY_1; + break; + case 2: + c->hierarchy = HIERARCHY_2; + break; + case 3: + c->hierarchy = HIERARCHY_4; + break; + } + + switch ((buf[3] >> 0) & 3) { + case 0: + c->modulation = QPSK; + break; + case 1: + c->modulation = QAM_16; + break; + case 2: + c->modulation = QAM_64; + break; + } + + switch ((buf[4] >> 0) & 3) { + case 0: + c->bandwidth_hz = 6000000; + break; + case 1: + c->bandwidth_hz = 7000000; + break; + case 2: + c->bandwidth_hz = 8000000; + break; + } + + switch ((buf[6] >> 0) & 7) { + case 0: + c->code_rate_HP = FEC_1_2; + break; + case 1: + c->code_rate_HP = FEC_2_3; + break; + case 2: + c->code_rate_HP = FEC_3_4; + break; + case 3: + c->code_rate_HP = FEC_5_6; + break; + case 4: + c->code_rate_HP = FEC_7_8; + break; + case 5: + c->code_rate_HP = FEC_NONE; + break; + } + + switch ((buf[7] >> 0) & 7) { + case 0: + c->code_rate_LP = FEC_1_2; + break; + case 1: + c->code_rate_LP = FEC_2_3; + break; + case 2: + c->code_rate_LP = FEC_3_4; + break; + case 3: + c->code_rate_LP = FEC_5_6; + break; + case 4: + c->code_rate_LP = FEC_7_8; + break; + case 5: + c->code_rate_LP = FEC_NONE; + break; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + u8 tmp; + + *status = 0; + + /* radio channel status, 0=no result, 1=has signal, 2=no signal */ + ret = af9033_rd_reg(state, 0x800047, &tmp); + if (ret < 0) + goto err; + + /* has signal */ + if (tmp == 0x01) + *status |= FE_HAS_SIGNAL; + + if (tmp != 0x02) { + /* TPS lock */ + ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01); + if (ret < 0) + goto err; + + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + + /* full lock */ + ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01); + if (ret < 0) + goto err; + + if (tmp) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret, i, len; + u8 buf[3], tmp; + u32 snr_val; + const struct val_snr *uninitialized_var(snr_lut); + + /* read value */ + ret = af9033_rd_regs(state, 0x80002c, buf, 3); + if (ret < 0) + goto err; + + snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + /* read current modulation */ + ret = af9033_rd_reg(state, 0x80f903, &tmp); + if (ret < 0) + goto err; + + switch ((tmp >> 0) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_lut); + snr_lut = qpsk_snr_lut; + break; + case 1: + len = ARRAY_SIZE(qam16_snr_lut); + snr_lut = qam16_snr_lut; + break; + case 2: + len = ARRAY_SIZE(qam64_snr_lut); + snr_lut = qam64_snr_lut; + break; + default: + goto err; + } + + for (i = 0; i < len; i++) { + tmp = snr_lut[i].snr; + + if (snr_val < snr_lut[i].val) + break; + } + + *snr = tmp * 10; /* dB/10 */ + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + u8 strength2; + + /* read signal strength of 0-100 scale */ + ret = af9033_rd_reg(state, 0x800048, &strength2); + if (ret < 0) + goto err; + + /* scale value to 0x0000-0xffff */ + *strength = strength2 * 0xffff / 100; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_update_ch_stat(struct af9033_state *state) +{ + int ret = 0; + u32 err_cnt, bit_cnt; + u16 abort_cnt; + u8 buf[7]; + + /* only update data every half second */ + if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) { + ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf)); + if (ret < 0) + goto err; + /* in 8 byte packets? */ + abort_cnt = (buf[1] << 8) + buf[0]; + /* in bits */ + err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2]; + /* in 8 byte packets? always(?) 0x2710 = 10000 */ + bit_cnt = (buf[6] << 8) + buf[5]; + + if (bit_cnt < abort_cnt) { + abort_cnt = 1000; + state->ber = 0xffffffff; + } else { + /* 8 byte packets, that have not been rejected already */ + bit_cnt -= (u32)abort_cnt; + if (bit_cnt == 0) { + state->ber = 0xffffffff; + } else { + err_cnt -= (u32)abort_cnt * 8 * 8; + bit_cnt *= 8 * 8; + state->ber = err_cnt * (0xffffffff / bit_cnt); + } + } + state->ucb += abort_cnt; + state->last_stat_check = jiffies; + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + ret = af9033_update_ch_stat(state); + if (ret < 0) + return ret; + + *ber = state->ber; + + return 0; +} + +static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + ret = af9033_update_ch_stat(state); + if (ret < 0) + return ret; + + *ucblocks = state->ucb; + + return 0; +} + +static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + pr_debug("%s: enable=%d\n", __func__, enable); + + ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01); + if (ret < 0) + goto err; + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +static struct dvb_frontend_ops af9033_ops; + +struct dvb_frontend *af9033_attach(const struct af9033_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct af9033_state *state; + u8 buf[8]; + + pr_debug("%s:\n", __func__); + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL); + if (state == NULL) + goto err; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->cfg, config, sizeof(struct af9033_config)); + + if (state->cfg.clock != 12000000) { + printk(KERN_INFO "af9033: unsupported clock=%d, only " \ + "12000000 Hz is supported currently\n", + state->cfg.clock); + goto err; + } + + /* firmware version */ + ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4); + if (ret < 0) + goto err; + + ret = af9033_rd_regs(state, 0x804191, &buf[4], 4); + if (ret < 0) + goto err; + + printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \ + "OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + /* configure internal TS mode */ + switch (state->cfg.ts_mode) { + case AF9033_TS_MODE_PARALLEL: + state->ts_mode_parallel = true; + break; + case AF9033_TS_MODE_SERIAL: + state->ts_mode_serial = true; + break; + case AF9033_TS_MODE_USB: + /* usb mode for AF9035 */ + default: + break; + } + + /* create dvb_frontend */ + memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); + state->fe.demodulator_priv = state; + + return &state->fe; + +err: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(af9033_attach); + +static struct dvb_frontend_ops af9033_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Afatech AF9033 (DVB-T)", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 250000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = af9033_release, + + .init = af9033_init, + .sleep = af9033_sleep, + + .get_tune_settings = af9033_get_tune_settings, + .set_frontend = af9033_set_frontend, + .get_frontend = af9033_get_frontend, + + .read_status = af9033_read_status, + .read_snr = af9033_read_snr, + .read_signal_strength = af9033_read_signal_strength, + .read_ber = af9033_read_ber, + .read_ucblocks = af9033_read_ucblocks, + + .i2c_gate_ctrl = af9033_i2c_gate_ctrl, +}; + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/af9033.h b/drivers/media/dvb/frontends/af9033.h new file mode 100644 index 0000000..9e302c3 --- /dev/null +++ b/drivers/media/dvb/frontends/af9033.h @@ -0,0 +1,75 @@ +/* + * Afatech AF9033 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9033_H +#define AF9033_H + +struct af9033_config { + /* + * I2C address + */ + u8 i2c_addr; + + /* + * clock Hz + * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000, + * 30000000, 36000000, 20480000, 16384000 + */ + u32 clock; + + /* + * tuner + */ +#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */ +#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */ +#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */ +#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */ + u8 tuner; + + /* + * TS settings + */ +#define AF9033_TS_MODE_USB 0 +#define AF9033_TS_MODE_PARALLEL 1 +#define AF9033_TS_MODE_SERIAL 2 + u8 ts_mode:2; + + /* + * input spectrum inversion + */ + bool spec_inv; +}; + + +#if defined(CONFIG_DVB_AF9033) || \ + (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE)) +extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *af9033_attach( + const struct af9033_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* AF9033_H */ diff --git a/drivers/media/dvb/frontends/af9033_priv.h b/drivers/media/dvb/frontends/af9033_priv.h new file mode 100644 index 0000000..0b783b9 --- /dev/null +++ b/drivers/media/dvb/frontends/af9033_priv.h @@ -0,0 +1,470 @@ +/* + * Afatech AF9033 demodulator driver + * + * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef AF9033_PRIV_H +#define AF9033_PRIV_H + +#include "dvb_frontend.h" +#include "af9033.h" + +struct reg_val { + u32 reg; + u8 val; +}; + +struct reg_val_mask { + u32 reg; + u8 val; + u8 mask; +}; + +struct coeff { + u32 clock; + u32 bandwidth_hz; + u8 val[36]; +}; + +struct clock_adc { + u32 clock; + u32 adc; +}; + +struct val_snr { + u32 val; + u8 snr; +}; + +/* Xtal clock vs. ADC clock lookup table */ +static const struct clock_adc clock_adc_lut[] = { + { 16384000, 20480000 }, + { 20480000, 20480000 }, + { 36000000, 20250000 }, + { 30000000, 20156250 }, + { 26000000, 20583333 }, + { 28000000, 20416667 }, + { 32000000, 20500000 }, + { 34000000, 20187500 }, + { 24000000, 20500000 }, + { 22000000, 20625000 }, + { 12000000, 20250000 }, +}; + +/* pre-calculated coeff lookup table */ +static const struct coeff coeff_lut[] = { + /* 12.000 MHz */ + { 12000000, 8000000, { + 0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, + 0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5, + 0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, + 0x95, 0x72, 0x37, 0x02, 0xce, 0x01 } + }, + { 12000000, 7000000, { + 0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, + 0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b, + 0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, + 0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 } + }, + { 12000000, 6000000, { + 0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, + 0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60, + 0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, + 0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 } + }, +}; + +/* QPSK SNR lookup table */ +static const struct val_snr qpsk_snr_lut[] = { + { 0x0b4771, 0 }, + { 0x0c1aed, 1 }, + { 0x0d0d27, 2 }, + { 0x0e4d19, 3 }, + { 0x0e5da8, 4 }, + { 0x107097, 5 }, + { 0x116975, 6 }, + { 0x1252d9, 7 }, + { 0x131fa4, 8 }, + { 0x13d5e1, 9 }, + { 0x148e53, 10 }, + { 0x15358b, 11 }, + { 0x15dd29, 12 }, + { 0x168112, 13 }, + { 0x170b61, 14 }, + { 0x17a532, 15 }, + { 0x180f94, 16 }, + { 0x186ed2, 17 }, + { 0x18b271, 18 }, + { 0x18e118, 19 }, + { 0x18ff4b, 20 }, + { 0x190af1, 21 }, + { 0x191451, 22 }, + { 0xffffff, 23 }, +}; + +/* QAM16 SNR lookup table */ +static const struct val_snr qam16_snr_lut[] = { + { 0x04f0d5, 0 }, + { 0x05387a, 1 }, + { 0x0573a4, 2 }, + { 0x05a99e, 3 }, + { 0x05cc80, 4 }, + { 0x05eb62, 5 }, + { 0x05fecf, 6 }, + { 0x060b80, 7 }, + { 0x062501, 8 }, + { 0x064865, 9 }, + { 0x069604, 10 }, + { 0x06f356, 11 }, + { 0x07706a, 12 }, + { 0x0804d3, 13 }, + { 0x089d1a, 14 }, + { 0x093e3d, 15 }, + { 0x09e35d, 16 }, + { 0x0a7c3c, 17 }, + { 0x0afaf8, 18 }, + { 0x0b719d, 19 }, + { 0x0bda6a, 20 }, + { 0x0c0c75, 21 }, + { 0x0c3f7d, 22 }, + { 0x0c5e62, 23 }, + { 0x0c6c31, 24 }, + { 0x0c7925, 25 }, + { 0xffffff, 26 }, +}; + +/* QAM64 SNR lookup table */ +static const struct val_snr qam64_snr_lut[] = { + { 0x0256d0, 0 }, + { 0x027a65, 1 }, + { 0x029873, 2 }, + { 0x02b7fe, 3 }, + { 0x02cf1e, 4 }, + { 0x02e234, 5 }, + { 0x02f409, 6 }, + { 0x030046, 7 }, + { 0x030844, 8 }, + { 0x030a02, 9 }, + { 0x030cde, 10 }, + { 0x031031, 11 }, + { 0x03144c, 12 }, + { 0x0315dd, 13 }, + { 0x031920, 14 }, + { 0x0322d0, 15 }, + { 0x0339fc, 16 }, + { 0x0364a1, 17 }, + { 0x038bcc, 18 }, + { 0x03c7d3, 19 }, + { 0x0408cc, 20 }, + { 0x043bed, 21 }, + { 0x048061, 22 }, + { 0x04be95, 23 }, + { 0x04fa7d, 24 }, + { 0x052405, 25 }, + { 0x05570d, 26 }, + { 0x059feb, 27 }, + { 0x05bf38, 28 }, + { 0xffffff, 29 }, +}; + +static const struct reg_val ofsm_init[] = { + { 0x800051, 0x01 }, + { 0x800070, 0x0a }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800099, 0x01 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000ab, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000c0, 0x05 }, + { 0x8000c4, 0x19 }, + { 0x80f000, 0x0f }, + { 0x80f016, 0x10 }, + { 0x80f017, 0x04 }, + { 0x80f018, 0x05 }, + { 0x80f019, 0x04 }, + { 0x80f01a, 0x05 }, + { 0x80f021, 0x03 }, + { 0x80f022, 0x0a }, + { 0x80f023, 0x0a }, + { 0x80f02b, 0x00 }, + { 0x80f02c, 0x01 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5df, 0xfb }, + { 0x80f5e0, 0x00 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f5f8, 0x01 }, + { 0x80f5fd, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + +/* Infineon TUA 9001 tuner init + AF9033_TUNER_TUA9001 = 0x27 */ +static const struct reg_val tuner_init_tua9001[] = { + { 0x800046, 0x27 }, + { 0x800057, 0x00 }, + { 0x800058, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x80006d, 0x00 }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800074, 0x01 }, + { 0x800075, 0x03 }, + { 0x800076, 0x02 }, + { 0x800077, 0x00 }, + { 0x800078, 0x01 }, + { 0x800079, 0x00 }, + { 0x80007a, 0x7e }, + { 0x80007b, 0x3e }, + { 0x800093, 0x00 }, + { 0x800094, 0x01 }, + { 0x800095, 0x02 }, + { 0x800096, 0x01 }, + { 0x800098, 0x0a }, + { 0x80009b, 0x05 }, + { 0x80009c, 0x80 }, + { 0x8000b3, 0x00 }, + { 0x8000c1, 0x01 }, + { 0x8000c2, 0x00 }, + { 0x80f007, 0x00 }, + { 0x80f01f, 0x82 }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x82 }, + { 0x80f02a, 0x00 }, + { 0x80f047, 0x00 }, + { 0x80f054, 0x00 }, + { 0x80f055, 0x00 }, + { 0x80f077, 0x01 }, + { 0x80f1e6, 0x00 }, +}; + +/* Fitipower fc0011 tuner init + AF9033_TUNER_FC0011 = 0x28 */ +static const struct reg_val tuner_init_fc0011[] = { + { 0x800046, AF9033_TUNER_FC0011 }, + { 0x800057, 0x00 }, + { 0x800058, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0xa5 }, + { 0x80006e, 0x01 }, + { 0x800071, 0x0A }, + { 0x800072, 0x02 }, + { 0x800074, 0x01 }, + { 0x800079, 0x01 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x80009b, 0x2D }, + { 0x80009c, 0x60 }, + { 0x80009d, 0x23 }, + { 0x8000a4, 0x50 }, + { 0x8000ad, 0x50 }, + { 0x8000b3, 0x01 }, + { 0x8000b7, 0x88 }, + { 0x8000b8, 0xa6 }, + { 0x8000c3, 0x01 }, + { 0x8000c4, 0x01 }, + { 0x8000c7, 0x69 }, + { 0x80F007, 0x00 }, + { 0x80F00A, 0x1B }, + { 0x80F00B, 0x1B }, + { 0x80F00C, 0x1B }, + { 0x80F00D, 0x1B }, + { 0x80F00E, 0xFF }, + { 0x80F00F, 0x01 }, + { 0x80F010, 0x00 }, + { 0x80F011, 0x02 }, + { 0x80F012, 0xFF }, + { 0x80F013, 0x01 }, + { 0x80F014, 0x00 }, + { 0x80F015, 0x02 }, + { 0x80F01B, 0xEF }, + { 0x80F01C, 0x01 }, + { 0x80F01D, 0x0f }, + { 0x80F01E, 0x02 }, + { 0x80F01F, 0x6E }, + { 0x80F020, 0x00 }, + { 0x80F025, 0xDE }, + { 0x80F026, 0x00 }, + { 0x80F027, 0x0A }, + { 0x80F028, 0x03 }, + { 0x80F029, 0x6E }, + { 0x80F02A, 0x00 }, + { 0x80F047, 0x00 }, + { 0x80F054, 0x00 }, + { 0x80F055, 0x00 }, + { 0x80F077, 0x01 }, + { 0x80F1E6, 0x00 }, +}; + +/* MaxLinear MxL5007T tuner init + AF9033_TUNER_MXL5007T = 0xa0 */ +static const struct reg_val tuner_init_mxl5007t[] = { + { 0x800046, 0x1b }, + { 0x800057, 0x01 }, + { 0x800058, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x96 }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800074, 0x01 }, + { 0x800079, 0x01 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x8000b3, 0x01 }, + { 0x8000c1, 0x01 }, + { 0x8000c2, 0x00 }, + { 0x80f007, 0x00 }, + { 0x80f00c, 0x19 }, + { 0x80f00d, 0x1a }, + { 0x80f012, 0xda }, + { 0x80f013, 0x00 }, + { 0x80f014, 0x00 }, + { 0x80f015, 0x02 }, + { 0x80f01f, 0x82 }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x82 }, + { 0x80f02a, 0x00 }, + { 0x80f077, 0x02 }, + { 0x80f1e6, 0x00 }, +}; + +/* NXP TDA 18218HN tuner init + AF9033_TUNER_TDA18218 = 0xa1 */ +static const struct reg_val tuner_init_tda18218[] = { + {0x800046, 0xa1}, + {0x800057, 0x01}, + {0x800058, 0x01}, + {0x80005f, 0x00}, + {0x800060, 0x00}, + {0x800071, 0x05}, + {0x800072, 0x02}, + {0x800074, 0x01}, + {0x800079, 0x01}, + {0x800093, 0x00}, + {0x800094, 0x00}, + {0x800095, 0x00}, + {0x800096, 0x00}, + {0x8000b3, 0x01}, + {0x8000c3, 0x01}, + {0x8000c4, 0x00}, + {0x80f007, 0x00}, + {0x80f00c, 0x19}, + {0x80f00d, 0x1a}, + {0x80f012, 0xda}, + {0x80f013, 0x00}, + {0x80f014, 0x00}, + {0x80f015, 0x02}, + {0x80f01f, 0x82}, + {0x80f020, 0x00}, + {0x80f029, 0x82}, + {0x80f02a, 0x00}, + {0x80f077, 0x02}, + {0x80f1e6, 0x00}, +}; + +#endif /* AF9033_PRIV_H */ + diff --git a/drivers/media/dvb/frontends/au8522_common.c b/drivers/media/dvb/frontends/au8522_common.c new file mode 100644 index 0000000..5cfe151 --- /dev/null +++ b/drivers/media/dvb/frontends/au8522_common.c @@ -0,0 +1,259 @@ +/* + Auvitek AU8522 QAM/8VSB demodulator driver + + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> + Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org> + Copyright (C) 2005-2008 Auvitek International, Ltd. + Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <linux/i2c.h> +#include "dvb_frontend.h" +#include "au8522_priv.h" + +MODULE_LICENSE("GPL"); + +static int debug; + +#define dprintk(arg...)\ + do { if (debug)\ + printk(arg);\ + } while (0) + +/* Despite the name "hybrid_tuner", the framework works just as well for + hybrid demodulators as well... */ +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(au8522_list_mutex); + +/* 16 bit registers, 8 bit values */ +int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) +{ + int ret; + u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; + + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} +EXPORT_SYMBOL(au8522_writereg); + +u8 au8522_readreg(struct au8522_state *state, u16 reg) +{ + int ret; + u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); + return b1[0]; +} +EXPORT_SYMBOL(au8522_readreg); + +int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct au8522_state *state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __func__, enable); + + if (state->operational_mode == AU8522_ANALOG_MODE) { + /* We're being asked to manage the gate even though we're + not in digital mode. This can occur if we get switched + over to analog mode before the dvb_frontend kernel thread + has completely shutdown */ + return 0; + } + + if (enable) + return au8522_writereg(state, 0x106, 1); + else + return au8522_writereg(state, 0x106, 0); +} +EXPORT_SYMBOL(au8522_i2c_gate_ctrl); + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, + u8 client_address) +{ + int ret; + + mutex_lock(&au8522_list_mutex); + ret = hybrid_tuner_request_state(struct au8522_state, (*state), + hybrid_tuner_instance_list, + i2c, client_address, "au8522"); + mutex_unlock(&au8522_list_mutex); + + return ret; +} +EXPORT_SYMBOL(au8522_get_state); + +void au8522_release_state(struct au8522_state *state) +{ + mutex_lock(&au8522_list_mutex); + if (state != NULL) + hybrid_tuner_release_state(state); + mutex_unlock(&au8522_list_mutex); +} +EXPORT_SYMBOL(au8522_release_state); + +static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + u8 val; + + /* bail out if we can't control an LED */ + if (!led_config || !led_config->gpio_output || + !led_config->gpio_output_enable || !led_config->gpio_output_disable) + return 0; + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_output & ~0xc000)); + if (onoff) { + /* enable GPIO output */ + val &= ~((led_config->gpio_output_enable >> 8) & 0xff); + val |= (led_config->gpio_output_enable & 0xff); + } else { + /* disable GPIO output */ + val &= ~((led_config->gpio_output_disable >> 8) & 0xff); + val |= (led_config->gpio_output_disable & 0xff); + } + return au8522_writereg(state, 0x8000 | + (led_config->gpio_output & ~0xc000), val); +} + +/* led = 0 | off + * led = 1 | signal ok + * led = 2 | signal strong + * led < 0 | only light led if leds are currently off + */ +int au8522_led_ctrl(struct au8522_state *state, int led) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + int i, ret = 0; + + /* bail out if we can't control an LED */ + if (!led_config || !led_config->gpio_leds || + !led_config->num_led_states || !led_config->led_states) + return 0; + + if (led < 0) { + /* if LED is already lit, then leave it as-is */ + if (state->led_state) + return 0; + else + led *= -1; + } + + /* toggle LED if changing state */ + if (state->led_state != led) { + u8 val; + + dprintk("%s: %d\n", __func__, led); + + au8522_led_gpio_enable(state, 1); + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_leds & ~0xc000)); + + /* start with all leds off */ + for (i = 0; i < led_config->num_led_states; i++) + val &= ~led_config->led_states[i]; + + /* set selected LED state */ + if (led < led_config->num_led_states) + val |= led_config->led_states[led]; + else if (led_config->num_led_states) + val |= + led_config->led_states[led_config->num_led_states - 1]; + + ret = au8522_writereg(state, 0x8000 | + (led_config->gpio_leds & ~0xc000), val); + if (ret < 0) + return ret; + + state->led_state = led; + + if (led == 0) + au8522_led_gpio_enable(state, 0); + } + + return 0; +} +EXPORT_SYMBOL(au8522_led_ctrl); + +int au8522_init(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + state->operational_mode = AU8522_DIGITAL_MODE; + + /* Clear out any state associated with the digital side of the + chip, so that when it gets powered back up it won't think + that it is already tuned */ + state->current_frequency = 0; + + au8522_writereg(state, 0xa4, 1 << 5); + + au8522_i2c_gate_ctrl(fe, 1); + + return 0; +} +EXPORT_SYMBOL(au8522_init); + +int au8522_sleep(struct dvb_frontend *fe) +{ + struct au8522_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + + /* Only power down if the digital side is currently using the chip */ + if (state->operational_mode == AU8522_ANALOG_MODE) { + /* We're not in one of the expected power modes, which means + that the DVB thread is probably telling us to go to sleep + even though the analog frontend has already started using + the chip. So ignore the request */ + return 0; + } + + /* turn off led */ + au8522_led_ctrl(state, 0); + + /* Power down the chip */ + au8522_writereg(state, 0xa4, 1 << 5); + + state->current_frequency = 0; + + return 0; +} +EXPORT_SYMBOL(au8522_sleep); diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index 25f6509..5fc70d6 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c @@ -30,74 +30,11 @@ static int debug; -/* Despite the name "hybrid_tuner", the framework works just as well for - hybrid demodulators as well... */ -static LIST_HEAD(hybrid_tuner_instance_list); -static DEFINE_MUTEX(au8522_list_mutex); - #define dprintk(arg...)\ do { if (debug)\ printk(arg);\ } while (0) -/* 16 bit registers, 8 bit values */ -int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) -{ - int ret; - u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; - - struct i2c_msg msg = { .addr = state->config->demod_address, - .flags = 0, .buf = buf, .len = 3 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " - "ret == %i)\n", __func__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -u8 au8522_readreg(struct au8522_state *state, u16 reg) -{ - int ret; - u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; - u8 b1[] = { 0 }; - - struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, - .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, - .buf = b1, .len = 1 } }; - - ret = i2c_transfer(state->i2c, msg, 2); - - if (ret != 2) - printk(KERN_ERR "%s: readreg error (ret == %i)\n", - __func__, ret); - return b1[0]; -} - -static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct au8522_state *state = fe->demodulator_priv; - - dprintk("%s(%d)\n", __func__, enable); - - if (state->operational_mode == AU8522_ANALOG_MODE) { - /* We're being asked to manage the gate even though we're - not in digital mode. This can occur if we get switched - over to analog mode before the dvb_frontend kernel thread - has completely shutdown */ - return 0; - } - - if (enable) - return au8522_writereg(state, 0x106, 1); - else - return au8522_writereg(state, 0x106, 0); -} - struct mse2snr_tab { u16 val; u16 data; @@ -609,136 +546,6 @@ static int au8522_set_frontend(struct dvb_frontend *fe) return 0; } -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -int au8522_init(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - state->operational_mode = AU8522_DIGITAL_MODE; - - /* Clear out any state associated with the digital side of the - chip, so that when it gets powered back up it won't think - that it is already tuned */ - state->current_frequency = 0; - - au8522_writereg(state, 0xa4, 1 << 5); - - au8522_i2c_gate_ctrl(fe, 1); - - return 0; -} - -static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - u8 val; - - /* bail out if we can't control an LED */ - if (!led_config || !led_config->gpio_output || - !led_config->gpio_output_enable || !led_config->gpio_output_disable) - return 0; - - val = au8522_readreg(state, 0x4000 | - (led_config->gpio_output & ~0xc000)); - if (onoff) { - /* enable GPIO output */ - val &= ~((led_config->gpio_output_enable >> 8) & 0xff); - val |= (led_config->gpio_output_enable & 0xff); - } else { - /* disable GPIO output */ - val &= ~((led_config->gpio_output_disable >> 8) & 0xff); - val |= (led_config->gpio_output_disable & 0xff); - } - return au8522_writereg(state, 0x8000 | - (led_config->gpio_output & ~0xc000), val); -} - -/* led = 0 | off - * led = 1 | signal ok - * led = 2 | signal strong - * led < 0 | only light led if leds are currently off - */ -static int au8522_led_ctrl(struct au8522_state *state, int led) -{ - struct au8522_led_config *led_config = state->config->led_cfg; - int i, ret = 0; - - /* bail out if we can't control an LED */ - if (!led_config || !led_config->gpio_leds || - !led_config->num_led_states || !led_config->led_states) - return 0; - - if (led < 0) { - /* if LED is already lit, then leave it as-is */ - if (state->led_state) - return 0; - else - led *= -1; - } - - /* toggle LED if changing state */ - if (state->led_state != led) { - u8 val; - - dprintk("%s: %d\n", __func__, led); - - au8522_led_gpio_enable(state, 1); - - val = au8522_readreg(state, 0x4000 | - (led_config->gpio_leds & ~0xc000)); - - /* start with all leds off */ - for (i = 0; i < led_config->num_led_states; i++) - val &= ~led_config->led_states[i]; - - /* set selected LED state */ - if (led < led_config->num_led_states) - val |= led_config->led_states[led]; - else if (led_config->num_led_states) - val |= - led_config->led_states[led_config->num_led_states - 1]; - - ret = au8522_writereg(state, 0x8000 | - (led_config->gpio_leds & ~0xc000), val); - if (ret < 0) - return ret; - - state->led_state = led; - - if (led == 0) - au8522_led_gpio_enable(state, 0); - } - - return 0; -} - -int au8522_sleep(struct dvb_frontend *fe) -{ - struct au8522_state *state = fe->demodulator_priv; - dprintk("%s()\n", __func__); - - /* Only power down if the digital side is currently using the chip */ - if (state->operational_mode == AU8522_ANALOG_MODE) { - /* We're not in one of the expected power modes, which means - that the DVB thread is probably telling us to go to sleep - even though the analog frontend has already started using - the chip. So ignore the request */ - return 0; - } - - /* turn off led */ - au8522_led_ctrl(state, 0); - - /* Power down the chip */ - au8522_writereg(state, 0xa4, 1 << 5); - - state->current_frequency = 0; - - return 0; -} - static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct au8522_state *state = fe->demodulator_priv; @@ -931,28 +738,6 @@ static int au8522_get_tune_settings(struct dvb_frontend *fe, static struct dvb_frontend_ops au8522_ops; -int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, - u8 client_address) -{ - int ret; - - mutex_lock(&au8522_list_mutex); - ret = hybrid_tuner_request_state(struct au8522_state, (*state), - hybrid_tuner_instance_list, - i2c, client_address, "au8522"); - mutex_unlock(&au8522_list_mutex); - - return ret; -} - -void au8522_release_state(struct au8522_state *state) -{ - mutex_lock(&au8522_list_mutex); - if (state != NULL) - hybrid_tuner_release_state(state); - mutex_unlock(&au8522_list_mutex); -} - static void au8522_release(struct dvb_frontend *fe) { diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h index 751e17d..6e4a438 100644 --- a/drivers/media/dvb/frontends/au8522_priv.h +++ b/drivers/media/dvb/frontends/au8522_priv.h @@ -81,6 +81,8 @@ int au8522_sleep(struct dvb_frontend *fe); int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, u8 client_address); void au8522_release_state(struct au8522_state *state); +int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); +int au8522_led_ctrl(struct au8522_state *state, int led); /* REGISTERS */ #define AU8522_INPUT_CONTROL_REG081H 0x081 diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 5101f10..98ecaf0 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -512,14 +512,13 @@ static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct cx24110_state *state = fe->demodulator_priv; - u32 lastbyer; if(cx24110_readreg(state,0x10)&0x40) { /* the RS error counter has finished one counting window */ cx24110_writereg(state,0x10,0x60); /* select the byer reg */ - lastbyer=cx24110_readreg(state,0x12)| - (cx24110_readreg(state,0x13)<<8)| - (cx24110_readreg(state,0x14)<<16); + cx24110_readreg(state, 0x12) | + (cx24110_readreg(state, 0x13) << 8) | + (cx24110_readreg(state, 0x14) << 16); cx24110_writereg(state,0x10,0x70); /* select the bler reg */ state->lastbler=cx24110_readreg(state,0x12)| (cx24110_readreg(state,0x13)<<8)| diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index 5c7c2aa..3bba37d 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -526,12 +526,12 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) if (ret) goto error; - if (status & FE_HAS_SIGNAL) + if (status & FE_HAS_LOCK) break; } /* check if we have a valid signal */ - if (status) { + if (status & FE_HAS_LOCK) { priv->last_tune_failed = 0; return DVBFE_ALGO_SEARCH_SUCCESS; } else { diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 5ceadc2..3e1eefa 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -2396,11 +2396,6 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, more common) */ st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; - /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ - st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; - dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); /* init 7090 tuner adapter */ diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index 80848b4..6201c59 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -31,13 +31,6 @@ struct i2c_device { u8 *i2c_write_buffer; }; -/* lock */ -#define DIB_LOCK struct mutex -#define DibAcquireLock(lock) mutex_lock_interruptible(lock) -#define DibReleaseLock(lock) mutex_unlock(lock) -#define DibInitLock(lock) mutex_init(lock) -#define DibFreeLock(lock) - struct dib9000_pid_ctrl { #define DIB9000_PID_FILTER_CTRL 0 #define DIB9000_PID_FILTER 1 @@ -82,11 +75,11 @@ struct dib9000_state { } fe_mm[18]; u8 memcmd; - DIB_LOCK mbx_if_lock; /* to protect read/write operations */ - DIB_LOCK mbx_lock; /* to protect the whole mailbox handling */ + struct mutex mbx_if_lock; /* to protect read/write operations */ + struct mutex mbx_lock; /* to protect the whole mailbox handling */ - DIB_LOCK mem_lock; /* to protect the memory accesses */ - DIB_LOCK mem_mbx_lock; /* to protect the memory-based mailbox */ + struct mutex mem_lock; /* to protect the memory accesses */ + struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */ #define MBX_MAX_WORDS (256 - 200 - 2) #define DIB9000_MSG_CACHE_SIZE 2 @@ -108,7 +101,7 @@ struct dib9000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[255]; u8 i2c_read_buffer[255]; - DIB_LOCK demod_lock; + struct mutex demod_lock; u8 get_frontend_internal; struct dib9000_pid_ctrl pid_ctrl[10]; s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ @@ -446,13 +439,13 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1 if (!state->platform.risc.fw_is_running) return -EIO; - if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } dib9000_risc_mem_setup(state, cmd | 0x80); dib9000_risc_mem_read_chunks(state, b, len); - DibReleaseLock(&state->platform.risc.mem_lock); + mutex_unlock(&state->platform.risc.mem_lock); return 0; } @@ -462,13 +455,13 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 if (!state->platform.risc.fw_is_running) return -EIO; - if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } dib9000_risc_mem_setup(state, cmd); dib9000_risc_mem_write_chunks(state, b, m->size); - DibReleaseLock(&state->platform.risc.mem_lock); + mutex_unlock(&state->platform.risc.mem_lock); return 0; } @@ -537,7 +530,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, if (!state->platform.risc.fw_is_running) return -EINVAL; - if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -584,7 +577,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); out: - DibReleaseLock(&state->platform.risc.mbx_if_lock); + mutex_unlock(&state->platform.risc.mbx_if_lock); return ret; } @@ -602,7 +595,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, if (!state->platform.risc.fw_is_running) return 0; - if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { dprintk("could not get the lock"); return 0; } @@ -643,7 +636,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, /* Update register nb_mes_in_TX */ dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); - DibReleaseLock(&state->platform.risc.mbx_if_lock); + mutex_unlock(&state->platform.risc.mbx_if_lock); return size + 1; } @@ -708,12 +701,11 @@ static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) { int ret = 0; - u16 tmp; if (!state->platform.risc.fw_is_running) return -1; - if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) { dprintk("could not get the lock"); return -1; } @@ -721,10 +713,10 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ ret = dib9000_mbx_fetch_to_cache(state, attr); - tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ + dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ /* if (tmp) */ /* dprintk( "cleared IRQ: %x", tmp); */ - DibReleaseLock(&state->platform.risc.mbx_lock); + mutex_unlock(&state->platform.risc.mbx_lock); return ret; } @@ -1193,7 +1185,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe) struct dibDVBTChannel *ch; int ret = 0; - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1323,7 +1315,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe) } error: - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return ret; } @@ -1678,7 +1670,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 p[12] = 0; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); return 0; } @@ -1692,7 +1684,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 /* do the transaction */ if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return 0; } @@ -1700,7 +1692,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 if ((num > 1) && (msg[1].flags & I2C_M_RD)) dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return num; } @@ -1789,7 +1781,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) return 0; } - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1799,7 +1791,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) dprintk("PID filter enabled %d", onoff); ret = dib9000_write_word(state, 294 + 1, val); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -1824,14 +1816,14 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) return 0; } - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); ret = dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } EXPORT_SYMBOL(dib9000_fw_pid_filter); @@ -1851,11 +1843,6 @@ static void dib9000_release(struct dvb_frontend *demod) for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) dvb_frontend_detach(st->fe[index_frontend]); - DibFreeLock(&state->platform.risc.mbx_if_lock); - DibFreeLock(&state->platform.risc.mbx_lock); - DibFreeLock(&state->platform.risc.mem_lock); - DibFreeLock(&state->platform.risc.mem_mbx_lock); - DibFreeLock(&state->demod_lock); dibx000_exit_i2c_master(&st->i2c_master); i2c_del_adapter(&st->tuner_adap); @@ -1875,7 +1862,7 @@ static int dib9000_sleep(struct dvb_frontend *fe) u8 index_frontend; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1887,7 +1874,7 @@ static int dib9000_sleep(struct dvb_frontend *fe) ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -1905,7 +1892,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe) int ret = 0; if (state->get_frontend_internal == 0) { - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -1964,7 +1951,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe) return_value: if (state->get_frontend_internal == 0) - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2012,7 +1999,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) } state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return 0; } @@ -2081,7 +2068,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) /* check the tune result */ if (exit_condition == 1) { /* tune failed */ dprintk("tune failed"); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); /* tune failed; put all the pid filtering cmd to junk */ state->pid_ctrl_index = -1; return 0; @@ -2137,7 +2124,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) /* turn off the diversity for the last frontend */ dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); if (state->pid_ctrl_index >= 0) { u8 index_pid_filter_cmd; u8 pid_ctrl_index = state->pid_ctrl_index; @@ -2175,7 +2162,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u8 index_frontend; u16 lock = 0, lock_slave = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -2197,7 +2184,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) if ((lock & 0x0008) || (lock_slave & 0x0008)) *stat |= FE_HAS_LOCK; - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return 0; } @@ -2208,30 +2195,30 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) u16 *c; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); ret = -EINTR; goto error; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, state->i2c_read_buffer, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); c = (u16 *)state->i2c_read_buffer; *ber = c[10] << 16 | c[11]; error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2243,7 +2230,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u16 val; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -2256,18 +2243,18 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength += val; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); ret = -EINTR; goto error; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); val = 65535 - c[4]; if (val > 65535 - *strength) @@ -2276,7 +2263,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength += val; error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2287,16 +2274,16 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe) u32 n, s, exp; u16 val; - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); return 0; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); return 0; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); val = c[7]; n = (val >> 4) & 0xff; @@ -2326,7 +2313,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u8 index_frontend; u32 snr_master; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } @@ -2340,7 +2327,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) } else *snr = 0; - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return 0; } @@ -2351,27 +2338,27 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) u16 *c = (u16 *)state->i2c_read_buffer; int ret = 0; - if (DibAcquireLock(&state->demod_lock) < 0) { + if (mutex_lock_interruptible(&state->demod_lock) < 0) { dprintk("could not get the lock"); return -EINTR; } - if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { + if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { dprintk("could not get the lock"); ret = -EINTR; goto error; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); + mutex_unlock(&state->platform.risc.mem_mbx_lock); *unc = c[12]; error: - DibReleaseLock(&state->demod_lock); + mutex_unlock(&state->demod_lock); return ret; } @@ -2514,11 +2501,11 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; - DibInitLock(&st->platform.risc.mbx_if_lock); - DibInitLock(&st->platform.risc.mbx_lock); - DibInitLock(&st->platform.risc.mem_lock); - DibInitLock(&st->platform.risc.mem_mbx_lock); - DibInitLock(&st->demod_lock); + mutex_init(&st->platform.risc.mbx_if_lock); + mutex_init(&st->platform.risc.mbx_lock); + mutex_init(&st->platform.risc.mem_lock); + mutex_init(&st->platform.risc.mem_mbx_lock); + mutex_init(&st->demod_lock); st->get_frontend_internal = 0; st->pid_ctrl_index = -2; diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h index 3439873..216c8c3 100644 --- a/drivers/media/dvb/frontends/drxd.h +++ b/drivers/media/dvb/frontends/drxd.h @@ -51,9 +51,23 @@ struct drxd_config { s16(*osc_deviation) (void *priv, s16 dev, int flag); }; +#if defined(CONFIG_DVB_DRXD) || \ + (defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE)) extern struct dvb_frontend *drxd_attach(const struct drxd_config *config, void *priv, struct i2c_adapter *i2c, struct device *dev); +#else +static inline +struct dvb_frontend *drxd_attach(const struct drxd_config *config, + void *priv, struct i2c_adapter *i2c, + struct device *dev) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __func__); + return NULL; +} +#endif + extern int drxd_config_i2c(struct dvb_frontend *, int); #endif diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index a414b1f..60b868f 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -1380,20 +1380,20 @@ static int DownloadMicrocode(struct drxk_state *state, const u8 pMCImage[], u32 Length) { const u8 *pSrc = pMCImage; - u16 Flags; - u16 Drain; u32 Address; u16 nBlocks; u16 BlockSize; - u16 BlockCRC; u32 offset = 0; u32 i; int status = 0; dprintk(1, "\n"); - /* down the drain (we don care about MAGIC_WORD) */ + /* down the drain (we don't care about MAGIC_WORD) */ +#if 0 + /* For future reference */ Drain = (pSrc[0] << 8) | pSrc[1]; +#endif pSrc += sizeof(u16); offset += sizeof(u16); nBlocks = (pSrc[0] << 8) | pSrc[1]; @@ -1410,11 +1410,17 @@ static int DownloadMicrocode(struct drxk_state *state, pSrc += sizeof(u16); offset += sizeof(u16); +#if 0 + /* For future reference */ Flags = (pSrc[0] << 8) | pSrc[1]; +#endif pSrc += sizeof(u16); offset += sizeof(u16); +#if 0 + /* For future reference */ BlockCRC = (pSrc[0] << 8) | pSrc[1]; +#endif pSrc += sizeof(u16); offset += sizeof(u16); @@ -5829,7 +5835,7 @@ static int WriteGPIO(struct drxk_state *state) } if (state->UIO_mask & 0x0002) { /* UIO-2 */ /* write to io pad configuration register - output mode */ - status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg); if (status < 0) goto error; @@ -5848,7 +5854,7 @@ static int WriteGPIO(struct drxk_state *state) } if (state->UIO_mask & 0x0004) { /* UIO-3 */ /* write to io pad configuration register - output mode */ - status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg); + status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg); if (status < 0) goto error; diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h index 9b11a83..23e16c1 100644 --- a/drivers/media/dvb/frontends/drxk_map.h +++ b/drivers/media/dvb/frontends/drxk_map.h @@ -432,6 +432,7 @@ #define SIO_PDR_UIO_OUT_LO__A 0x7F0016 #define SIO_PDR_OHW_CFG__A 0x7F001F #define SIO_PDR_OHW_CFG_FREF_SEL__M 0x3 +#define SIO_PDR_GPIO_CFG__A 0x7F0021 #define SIO_PDR_MSTRT_CFG__A 0x7F0025 #define SIO_PDR_MERR_CFG__A 0x7F0026 #define SIO_PDR_MCLK_CFG__A 0x7F0028 @@ -446,4 +447,5 @@ #define SIO_PDR_MD5_CFG__A 0x7F0030 #define SIO_PDR_MD6_CFG__A 0x7F0031 #define SIO_PDR_MD7_CFG__A 0x7F0032 +#define SIO_PDR_SMA_RX_CFG__A 0x7F0037 #define SIO_PDR_SMA_TX_CFG__A 0x7F0038 diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index af65d01..4c8ac26 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -1114,7 +1114,10 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) ds3000_writereg(state, ds3000_dvbs2_init_tab[i], ds3000_dvbs2_init_tab[i + 1]); - ds3000_writereg(state, 0xfe, 0x98); + if (c->symbol_rate >= 30000000) + ds3000_writereg(state, 0xfe, 0x54); + else + ds3000_writereg(state, 0xfe, 0x98); break; default: return 1; diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index 84df03c..708cbf1 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -633,10 +633,9 @@ static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber) { struct it913x_fe_state *state = fe->demodulator_priv; - int ret; u8 reg[5]; /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */ - ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); + it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); state->ucblocks += (u32)(reg[1] << 8) | reg[0]; *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2]; return 0; @@ -658,10 +657,9 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; - int ret; u8 reg[8]; - ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); + it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); if (reg[3] < 3) p->modulation = fe_con[reg[3]]; @@ -691,25 +689,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; - int ret, i; + int i; u8 empty_ch, last_ch; state->it913x_status = 0; /* Set bw*/ - ret = it913x_fe_select_bw(state, p->bandwidth_hz, + it913x_fe_select_bw(state, p->bandwidth_hz, state->adcFrequency); /* Training Mode Off */ - ret = it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0); + it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0); /* Clear Empty Channel */ - ret = it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0); + it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0); /* Clear bits */ - ret = it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0); + it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0); /* LED on */ - ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); + it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); /* Select Band*/ if ((p->frequency >= 51000000) && (p->frequency <= 230000000)) i = 0; @@ -720,7 +718,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) else return -EOPNOTSUPP; - ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); + it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); deb_info("Frontend Set Tuner Type %02x", state->tuner_type); switch (state->tuner_type) { @@ -730,7 +728,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) case IT9135_60: case IT9135_61: case IT9135_62: - ret = it9137_set_tuner(state, + it9137_set_tuner(state, p->bandwidth_hz, p->frequency); break; default: @@ -742,9 +740,9 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe) break; } /* LED off */ - ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); + it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); /* Trigger ofsm */ - ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); + it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); last_ch = 2; for (i = 0; i < 40; ++i) { empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS); diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb/frontends/lg2160.c new file mode 100644 index 0000000..a3ab1a5 --- /dev/null +++ b/drivers/media/dvb/frontends/lg2160.c @@ -0,0 +1,1468 @@ +/* + * Support for LG2160 - ATSC/MH + * + * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/jiffies.h> +#include <linux/dvb/frontend.h> +#include "lg2160.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); + +#define DBG_INFO 1 +#define DBG_REG 2 + +#define lg_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt, __func__, ##arg) + +#define lg_info(fmt, arg...) printk(KERN_INFO "lg2160: " fmt, ##arg) +#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg) +#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg) +#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \ + lg_printk(KERN_DEBUG, fmt, ##arg) +#define lg_reg(fmt, arg...) if (debug & DBG_REG) \ + lg_printk(KERN_DEBUG, fmt, ##arg) + +#define lg_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + lg_err("error %d on line %d\n", ret, __LINE__); \ + __ret; \ +}) + +struct lg216x_state { + struct i2c_adapter *i2c_adap; + const struct lg2160_config *cfg; + + struct dvb_frontend frontend; + + u32 current_frequency; + u8 parade_id; + u8 fic_ver; + unsigned int last_reset; +}; + +/* ------------------------------------------------------------------------ */ + +static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val) +{ + int ret; + u8 buf[] = { reg >> 8, reg & 0xff, val }; + struct i2c_msg msg = { + .addr = state->cfg->i2c_addr, .flags = 0, + .buf = buf, .len = 3, + }; + + lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); + + ret = i2c_transfer(state->i2c_adap, &msg, 1); + + if (ret != 1) { + lg_err("error (addr %02x %02x <- %02x, err = %i)\n", + msg.buf[0], msg.buf[1], msg.buf[2], ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val) +{ + int ret; + u8 reg_buf[] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[] = { + { .addr = state->cfg->i2c_addr, + .flags = 0, .buf = reg_buf, .len = 2 }, + { .addr = state->cfg->i2c_addr, + .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + lg_reg("reg: 0x%04x\n", reg); + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + if (ret != 2) { + lg_err("error (addr %02x reg %04x error (ret == %i)\n", + state->cfg->i2c_addr, reg, ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +struct lg216x_reg { + u16 reg; + u8 val; +}; + +static int lg216x_write_regs(struct lg216x_state *state, + struct lg216x_reg *regs, int len) +{ + int i, ret; + + lg_reg("writing %d registers...\n", len); + + for (i = 0; i < len - 1; i++) { + ret = lg216x_write_reg(state, regs[i].reg, regs[i].val); + if (lg_fail(ret)) + return ret; + } + return 0; +} + +static int lg216x_set_reg_bit(struct lg216x_state *state, + u16 reg, int bit, int onoff) +{ + u8 val; + int ret; + + lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); + + ret = lg216x_read_reg(state, reg, &val); + if (lg_fail(ret)) + goto fail; + + val &= ~(1 << bit); + val |= (onoff & 1) << bit; + + ret = lg216x_write_reg(state, reg, val); + lg_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + if (state->cfg->deny_i2c_rptr) + return 0; + + lg_dbg("(%d)\n", enable); + + ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1); + + msleep(1); + + return ret; +} + +static int lg216x_soft_reset(struct lg216x_state *state) +{ + int ret; + + lg_dbg("\n"); + + ret = lg216x_write_reg(state, 0x0002, 0x00); + if (lg_fail(ret)) + goto fail; + + msleep(20); + ret = lg216x_write_reg(state, 0x0002, 0x01); + if (lg_fail(ret)) + goto fail; + + state->last_reset = jiffies_to_msecs(jiffies); +fail: + return ret; +} + +static int lg216x_initialize(struct lg216x_state *state) +{ + int ret; + + static struct lg216x_reg lg2160_init[] = { +#if 0 + { .reg = 0x0015, .val = 0xe6 }, +#else + { .reg = 0x0015, .val = 0xf7 }, + { .reg = 0x001b, .val = 0x52 }, + { .reg = 0x0208, .val = 0x00 }, + { .reg = 0x0209, .val = 0x82 }, + { .reg = 0x0210, .val = 0xf9 }, + { .reg = 0x020a, .val = 0x00 }, + { .reg = 0x020b, .val = 0x82 }, + { .reg = 0x020d, .val = 0x28 }, + { .reg = 0x020f, .val = 0x14 }, +#endif + }; + + static struct lg216x_reg lg2161_init[] = { + { .reg = 0x0000, .val = 0x41 }, + { .reg = 0x0001, .val = 0xfb }, + { .reg = 0x0216, .val = 0x00 }, + { .reg = 0x0219, .val = 0x00 }, + { .reg = 0x021b, .val = 0x55 }, + { .reg = 0x0606, .val = 0x0a }, + }; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_write_regs(state, + lg2160_init, ARRAY_SIZE(lg2160_init)); + break; + case LG2161: + ret = lg216x_write_regs(state, + lg2161_init, ARRAY_SIZE(lg2161_init)); + break; + default: + ret = -EINVAL; + break; + } + if (lg_fail(ret)) + goto fail; + + ret = lg216x_soft_reset(state); + lg_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_set_if(struct lg216x_state *state) +{ + u8 val; + int ret; + + lg_dbg("%d KHz\n", state->cfg->if_khz); + + ret = lg216x_read_reg(state, 0x0132, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfb; + val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00; + + ret = lg216x_write_reg(state, 0x0132, val); + lg_fail(ret); + + /* if NOT zero IF, 6 MHz is the default */ +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg2160_agc_fix(struct lg216x_state *state, + int if_agc_fix, int rf_agc_fix) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0100, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xf3; + val |= (if_agc_fix) ? 0x08 : 0x00; + val |= (rf_agc_fix) ? 0x04 : 0x00; + + ret = lg216x_write_reg(state, 0x0100, val); + lg_fail(ret); +fail: + return ret; +} + +#if 0 +static int lg2160_agc_freeze(struct lg216x_state *state, + int if_agc_freeze, int rf_agc_freeze) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0100, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xcf; + val |= (if_agc_freeze) ? 0x20 : 0x00; + val |= (rf_agc_freeze) ? 0x10 : 0x00; + + ret = lg216x_write_reg(state, 0x0100, val); + lg_fail(ret); +fail: + return ret; +} +#endif + +static int lg2160_agc_polarity(struct lg216x_state *state, + int if_agc_polarity, int rf_agc_polarity) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0100, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfc; + val |= (if_agc_polarity) ? 0x02 : 0x00; + val |= (rf_agc_polarity) ? 0x01 : 0x00; + + ret = lg216x_write_reg(state, 0x0100, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state, + int polarity) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0008, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfe; + val |= (polarity) ? 0x01 : 0x00; + + ret = lg216x_write_reg(state, 0x0008, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2160_spectrum_polarity(struct lg216x_state *state, + int inverted) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0132, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfd; + val |= (inverted) ? 0x02 : 0x00; + + ret = lg216x_write_reg(state, 0x0132, val); + lg_fail(ret); +fail: + return lg216x_soft_reset(state); +} + +static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0007, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xbf; + val |= (onoff) ? 0x40 : 0x00; + + ret = lg216x_write_reg(state, 0x0007, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg216x_set_parade(struct lg216x_state *state, int id) +{ + int ret; + + ret = lg216x_write_reg(state, 0x013e, id & 0x7f); + if (lg_fail(ret)) + goto fail; + + state->parade_id = id & 0x7f; +fail: + return ret; +} + +static int lg216x_set_ensemble(struct lg216x_state *state, int id) +{ + int ret; + u16 reg; + u8 val; + + switch (state->cfg->lg_chip) { + case LG2160: + reg = 0x0400; + break; + case LG2161: + default: + reg = 0x0500; + break; + } + + ret = lg216x_read_reg(state, reg, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xfe; + val |= (id) ? 0x01 : 0x00; + + ret = lg216x_write_reg(state, reg, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2160_set_spi_clock(struct lg216x_state *state) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0014, &val); + if (lg_fail(ret)) + goto fail; + + val &= 0xf3; + val |= (state->cfg->spi_clock << 2); + + ret = lg216x_write_reg(state, 0x0014, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg2161_set_output_interface(struct lg216x_state *state) +{ + u8 val; + int ret; + + ret = lg216x_read_reg(state, 0x0014, &val); + if (lg_fail(ret)) + goto fail; + + val &= ~0x07; + val |= state->cfg->output_if; /* FIXME: needs sanity check */ + + ret = lg216x_write_reg(state, 0x0014, val); + lg_fail(ret); +fail: + return ret; +} + +static int lg216x_enable_fic(struct lg216x_state *state, int onoff) +{ + int ret; + + ret = lg216x_write_reg(state, 0x0017, 0x23); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_write_reg(state, 0x0016, 0xfc); + if (lg_fail(ret)) + goto fail; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_write_reg(state, 0x0016, + 0xfc | ((onoff) ? 0x02 : 0x00)); + break; + case LG2161: + ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00); + break; + } + if (lg_fail(ret)) + goto fail; + + ret = lg216x_initialize(state); + if (lg_fail(ret)) + goto fail; + + if (onoff) { + ret = lg216x_write_reg(state, 0x0017, 0x03); + lg_fail(ret); + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver) +{ + u8 val; + int ret; + + *ficver = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0128, &val); + if (lg_fail(ret)) + goto fail; + + *ficver = (val >> 3) & 0x1f; +fail: + return ret; +} + +#if 0 +static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id) +{ + u8 val; + int ret; + + *id = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0123, &val); + if (lg_fail(ret)) + goto fail; + + *id = val & 0x7f; +fail: + return ret; +} +#endif + +static int lg216x_get_nog(struct lg216x_state *state, u8 *nog) +{ + u8 val; + int ret; + + *nog = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0124, &val); + if (lg_fail(ret)) + goto fail; + + *nog = ((val >> 4) & 0x07) + 1; +fail: + return ret; +} + +static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog) +{ + u8 val; + int ret; + + *tnog = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0125, &val); + if (lg_fail(ret)) + goto fail; + + *tnog = val & 0x1f; +fail: + return ret; +} + +static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn) +{ + u8 val; + int ret; + + *sgn = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0124, &val); + if (lg_fail(ret)) + goto fail; + + *sgn = val & 0x0f; +fail: + return ret; +} + +static int lg216x_get_prc(struct lg216x_state *state, u8 *prc) +{ + u8 val; + int ret; + + *prc = 0xff; /* invalid value */ + + ret = lg216x_read_reg(state, 0x0125, &val); + if (lg_fail(ret)) + goto fail; + + *prc = ((val >> 5) & 0x07) + 1; +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_get_rs_frame_mode(struct lg216x_state *state, + enum atscmh_rs_frame_mode *rs_framemode) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0410, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0513, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + switch ((val >> 4) & 0x03) { +#if 1 + default: +#endif + case 0x00: + *rs_framemode = ATSCMH_RSFRAME_PRI_ONLY; + break; + case 0x01: + *rs_framemode = ATSCMH_RSFRAME_PRI_SEC; + break; +#if 0 + default: + *rs_framemode = ATSCMH_RSFRAME_RES; + break; +#endif + } +fail: + return ret; +} + +static +int lg216x_get_rs_frame_ensemble(struct lg216x_state *state, + enum atscmh_rs_frame_ensemble *rs_frame_ens) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0400, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0500, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + val &= 0x01; + *rs_frame_ens = (enum atscmh_rs_frame_ensemble) val; +fail: + return ret; +} + +static int lg216x_get_rs_code_mode(struct lg216x_state *state, + enum atscmh_rs_code_mode *rs_code_pri, + enum atscmh_rs_code_mode *rs_code_sec) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0410, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0513, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + *rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03); + *rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03); +fail: + return ret; +} + +static int lg216x_get_sccc_block_mode(struct lg216x_state *state, + enum atscmh_sccc_block_mode *sccc_block) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0315, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0511, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + switch (val & 0x03) { + case 0x00: + *sccc_block = ATSCMH_SCCC_BLK_SEP; + break; + case 0x01: + *sccc_block = ATSCMH_SCCC_BLK_COMB; + break; + default: + *sccc_block = ATSCMH_SCCC_BLK_RES; + break; + } +fail: + return ret; +} + +static int lg216x_get_sccc_code_mode(struct lg216x_state *state, + enum atscmh_sccc_code_mode *mode_a, + enum atscmh_sccc_code_mode *mode_b, + enum atscmh_sccc_code_mode *mode_c, + enum atscmh_sccc_code_mode *mode_d) +{ + u8 val; + int ret; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0316, &val); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x0512, &val); + break; + default: + ret = -EINVAL; + } + if (lg_fail(ret)) + goto fail; + + switch ((val >> 6) & 0x03) { + case 0x00: + *mode_a = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_a = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_a = ATSCMH_SCCC_CODE_RES; + break; + } + + switch ((val >> 4) & 0x03) { + case 0x00: + *mode_b = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_b = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_b = ATSCMH_SCCC_CODE_RES; + break; + } + + switch ((val >> 2) & 0x03) { + case 0x00: + *mode_c = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_c = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_c = ATSCMH_SCCC_CODE_RES; + break; + } + + switch (val & 0x03) { + case 0x00: + *mode_d = ATSCMH_SCCC_CODE_HLF; + break; + case 0x01: + *mode_d = ATSCMH_SCCC_CODE_QTR; + break; + default: + *mode_d = ATSCMH_SCCC_CODE_RES; + break; + } +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err) +{ + u8 fic_err; + int ret; + + *err = 0; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg216x_read_reg(state, 0x0012, &fic_err); + break; + case LG2161: + ret = lg216x_read_reg(state, 0x001e, &fic_err); + break; + } + if (lg_fail(ret)) + goto fail; + + *err = fic_err; +fail: + return ret; +} + +static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err) +{ + u8 crc_err1, crc_err2; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0411, &crc_err1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0412, &crc_err2); + if (lg_fail(ret)) + goto fail; + + *err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1); +fail: + return ret; +} + +static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err) +{ + u8 crc_err; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0612, &crc_err); + if (lg_fail(ret)) + goto fail; + + *err = (u16)crc_err; +fail: + return ret; +} + +static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err) +{ + int ret; + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_read_crc_err_count(state, err); + break; + case LG2161: + ret = lg2161_read_crc_err_count(state, err); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err) +{ + u8 rs_err1, rs_err2; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0413, &rs_err1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0414, &rs_err2); + if (lg_fail(ret)) + goto fail; + + *err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1); +fail: + return ret; +} + +static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err) +{ + u8 rs_err1, rs_err2; + int ret; + + *err = 0; + + ret = lg216x_read_reg(state, 0x0613, &rs_err1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0614, &rs_err2); + if (lg_fail(ret)) + goto fail; + + *err = (u16)((rs_err1 << 8) | rs_err2); +fail: + return ret; +} + +static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err) +{ + int ret; + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_read_rs_err_count(state, err); + break; + case LG2161: + ret = lg2161_read_rs_err_count(state, err); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int lg216x_get_frontend(struct dvb_frontend *fe) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + lg_dbg("\n"); + + fe->dtv_property_cache.modulation = VSB_8; + fe->dtv_property_cache.frequency = state->current_frequency; + fe->dtv_property_cache.delivery_system = SYS_ATSCMH; + + ret = lg216x_get_fic_version(state, + &fe->dtv_property_cache.atscmh_fic_ver); + if (lg_fail(ret)) + goto fail; + if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) { + state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver; + +#if 0 + ret = lg2160_get_parade_id(state, + &fe->dtv_property_cache.atscmh_parade_id); + if (lg_fail(ret)) + goto fail; +/* #else */ + fe->dtv_property_cache.atscmh_parade_id = state->parade_id; +#endif + ret = lg216x_get_nog(state, + &fe->dtv_property_cache.atscmh_nog); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_tnog(state, + &fe->dtv_property_cache.atscmh_tnog); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_sgn(state, + &fe->dtv_property_cache.atscmh_sgn); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_prc(state, + &fe->dtv_property_cache.atscmh_prc); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_get_rs_frame_mode(state, + (enum atscmh_rs_frame_mode *) + &fe->dtv_property_cache.atscmh_rs_frame_mode); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_rs_frame_ensemble(state, + (enum atscmh_rs_frame_ensemble *) + &fe->dtv_property_cache.atscmh_rs_frame_ensemble); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_rs_code_mode(state, + (enum atscmh_rs_code_mode *) + &fe->dtv_property_cache.atscmh_rs_code_mode_pri, + (enum atscmh_rs_code_mode *) + &fe->dtv_property_cache.atscmh_rs_code_mode_sec); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_sccc_block_mode(state, + (enum atscmh_sccc_block_mode *) + &fe->dtv_property_cache.atscmh_sccc_block_mode); + if (lg_fail(ret)) + goto fail; + ret = lg216x_get_sccc_code_mode(state, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_a, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_b, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_c, + (enum atscmh_sccc_code_mode *) + &fe->dtv_property_cache.atscmh_sccc_code_mode_d); + if (lg_fail(ret)) + goto fail; + } +#if 0 + ret = lg216x_read_fic_err_count(state, + (u8 *)&fe->dtv_property_cache.atscmh_fic_err); + if (lg_fail(ret)) + goto fail; + ret = lg216x_read_crc_err_count(state, + &fe->dtv_property_cache.atscmh_crc_err); + if (lg_fail(ret)) + goto fail; + ret = lg216x_read_rs_err_count(state, + &fe->dtv_property_cache.atscmh_rs_err); + if (lg_fail(ret)) + goto fail; + + switch (state->cfg->lg_chip) { + case LG2160: + if (((fe->dtv_property_cache.atscmh_rs_err >= 240) && + (fe->dtv_property_cache.atscmh_crc_err >= 240)) && + ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000)) + ret = lg216x_soft_reset(state); + break; + case LG2161: + /* no fix needed here (as far as we know) */ + ret = 0; + break; + } + lg_fail(ret); +#endif +fail: + return ret; +} + +static int lg216x_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) +{ + return (DTV_ATSCMH_FIC_VER == tvp->cmd) ? + lg216x_get_frontend(fe) : 0; +} + + +static int lg2160_set_frontend(struct dvb_frontend *fe) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + lg_dbg("(%d)\n", fe->dtv_property_cache.frequency); + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + if (lg_fail(ret)) + goto fail; + state->current_frequency = fe->dtv_property_cache.frequency; + } + + ret = lg2160_agc_fix(state, 0, 0); + if (lg_fail(ret)) + goto fail; + ret = lg2160_agc_polarity(state, 0, 0); + if (lg_fail(ret)) + goto fail; + ret = lg2160_tuner_pwr_save_polarity(state, 1); + if (lg_fail(ret)) + goto fail; + ret = lg216x_set_if(state); + if (lg_fail(ret)) + goto fail; + ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion); + if (lg_fail(ret)) + goto fail; + + /* be tuned before this point */ + ret = lg216x_soft_reset(state); + if (lg_fail(ret)) + goto fail; + + ret = lg2160_tuner_pwr_save(state, 0); + if (lg_fail(ret)) + goto fail; + + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_set_spi_clock(state); + if (lg_fail(ret)) + goto fail; + break; + case LG2161: + ret = lg2161_set_output_interface(state); + if (lg_fail(ret)) + goto fail; + break; + } + + ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_set_ensemble(state, + fe->dtv_property_cache.atscmh_rs_frame_ensemble); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_initialize(state); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_enable_fic(state, 1); + lg_fail(ret); + + lg216x_get_frontend(fe); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg2160_read_lock_status(struct lg216x_state *state, + int *acq_lock, int *sync_lock) +{ + u8 val; + int ret; + + *acq_lock = 0; + *sync_lock = 0; + + ret = lg216x_read_reg(state, 0x011b, &val); + if (lg_fail(ret)) + goto fail; + + *sync_lock = (val & 0x20) ? 0 : 1; + *acq_lock = (val & 0x40) ? 0 : 1; +fail: + return ret; +} + +#ifdef USE_LG2161_LOCK_BITS +static int lg2161_read_lock_status(struct lg216x_state *state, + int *acq_lock, int *sync_lock) +{ + u8 val; + int ret; + + *acq_lock = 0; + *sync_lock = 0; + + ret = lg216x_read_reg(state, 0x0304, &val); + if (lg_fail(ret)) + goto fail; + + *sync_lock = (val & 0x80) ? 0 : 1; + + ret = lg216x_read_reg(state, 0x011b, &val); + if (lg_fail(ret)) + goto fail; + + *acq_lock = (val & 0x40) ? 0 : 1; +fail: + return ret; +} +#endif + +static int lg216x_read_lock_status(struct lg216x_state *state, + int *acq_lock, int *sync_lock) +{ +#ifdef USE_LG2161_LOCK_BITS + int ret; + switch (state->cfg->lg_chip) { + case LG2160: + ret = lg2160_read_lock_status(state, acq_lock, sync_lock); + break; + case LG2161: + ret = lg2161_read_lock_status(state, acq_lock, sync_lock); + break; + default: + ret = -EINVAL; + break; + } + return ret; +#else + return lg2160_read_lock_status(state, acq_lock, sync_lock); +#endif +} + +static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lg216x_state *state = fe->demodulator_priv; + int ret, acq_lock, sync_lock; + + *status = 0; + + ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock); + if (lg_fail(ret)) + goto fail; + + lg_dbg("%s%s\n", + acq_lock ? "SIGNALEXIST " : "", + sync_lock ? "SYNCLOCK" : ""); + + if (acq_lock) + *status |= FE_HAS_SIGNAL; + if (sync_lock) + *status |= FE_HAS_SYNC; + + if (*status) + *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; + +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lg216x_state *state = fe->demodulator_priv; + u8 snr1, snr2; + int ret; + + *snr = 0; + + ret = lg216x_read_reg(state, 0x0202, &snr1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0203, &snr2); + if (lg_fail(ret)) + goto fail; + + if ((snr1 == 0xba) || (snr2 == 0xdf)) + *snr = 0; + else +#if 1 + *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4); +#else /* BCD */ + *snr = (snr2 | (snr1 << 8)); +#endif +fail: + return ret; +} + +static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lg216x_state *state = fe->demodulator_priv; + u8 snr1, snr2; + int ret; + + *snr = 0; + + ret = lg216x_read_reg(state, 0x0302, &snr1); + if (lg_fail(ret)) + goto fail; + + ret = lg216x_read_reg(state, 0x0303, &snr2); + if (lg_fail(ret)) + goto fail; + + if ((snr1 == 0xba) || (snr2 == 0xfd)) + *snr = 0; + else + + *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f); +fail: + return ret; +} + +static int lg216x_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ +#if 0 + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + struct lg216x_state *state = fe->demodulator_priv; + u16 snr; + int ret; +#endif + *strength = 0; +#if 0 + ret = fe->ops.read_snr(fe, &snr); + if (lg_fail(ret)) + goto fail; + /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ + /* scale the range 0 - 35*2^24 into 0 - 65535 */ + if (state->snr >= 8960 * 0x10000) + *strength = 0xffff; + else + *strength = state->snr / 8960; +fail: + return ret; +#else + return 0; +#endif +} + +/* ------------------------------------------------------------------------ */ + +static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ +#if 0 + struct lg216x_state *state = fe->demodulator_priv; + int ret; + + ret = lg216x_read_rs_err_count(state, + &fe->dtv_property_cache.atscmh_rs_err); + if (lg_fail(ret)) + goto fail; + + *ucblocks = fe->dtv_property_cache.atscmh_rs_err; +fail: +#else + *ucblocks = 0; +#endif + return 0; +} + +static int lg216x_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 500; + lg_dbg("\n"); + return 0; +} + +static void lg216x_release(struct dvb_frontend *fe) +{ + struct lg216x_state *state = fe->demodulator_priv; + lg_dbg("\n"); + kfree(state); +} + +static struct dvb_frontend_ops lg2160_ops = { + .delsys = { SYS_ATSCMH }, + .info = { + .name = "LG Electronics LG2160 ATSC/MH Frontend", + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + }, + .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, +#if 0 + .init = lg216x_init, + .sleep = lg216x_sleep, +#endif + .get_property = lg216x_get_property, + + .set_frontend = lg2160_set_frontend, + .get_frontend = lg216x_get_frontend, + .get_tune_settings = lg216x_get_tune_settings, + .read_status = lg216x_read_status, +#if 0 + .read_ber = lg216x_read_ber, +#endif + .read_signal_strength = lg216x_read_signal_strength, + .read_snr = lg2160_read_snr, + .read_ucblocks = lg216x_read_ucblocks, + .release = lg216x_release, +}; + +static struct dvb_frontend_ops lg2161_ops = { + .delsys = { SYS_ATSCMH }, + .info = { + .name = "LG Electronics LG2161 ATSC/MH Frontend", + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + }, + .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, +#if 0 + .init = lg216x_init, + .sleep = lg216x_sleep, +#endif + .get_property = lg216x_get_property, + + .set_frontend = lg2160_set_frontend, + .get_frontend = lg216x_get_frontend, + .get_tune_settings = lg216x_get_tune_settings, + .read_status = lg216x_read_status, +#if 0 + .read_ber = lg216x_read_ber, +#endif + .read_signal_strength = lg216x_read_signal_strength, + .read_snr = lg2161_read_snr, + .read_ucblocks = lg216x_read_ucblocks, + .release = lg216x_release, +}; + +struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + struct i2c_adapter *i2c_adap) +{ + struct lg216x_state *state = NULL; + + lg_dbg("(%d-%04x)\n", + i2c_adap ? i2c_adapter_id(i2c_adap) : 0, + config ? config->i2c_addr : 0); + + state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL); + if (state == NULL) + goto fail; + + state->cfg = config; + state->i2c_adap = i2c_adap; + state->fic_ver = 0xff; + state->parade_id = 0xff; + + switch (config->lg_chip) { + default: + lg_warn("invalid chip requested, defaulting to LG2160"); + /* fall-thru */ + case LG2160: + memcpy(&state->frontend.ops, &lg2160_ops, + sizeof(struct dvb_frontend_ops)); + break; + case LG2161: + memcpy(&state->frontend.ops, &lg2161_ops, + sizeof(struct dvb_frontend_ops)); + break; + } + + state->frontend.demodulator_priv = state; + state->current_frequency = -1; + /* parade 1 by default */ + state->frontend.dtv_property_cache.atscmh_parade_id = 1; + + return &state->frontend; +fail: + lg_warn("unable to detect LG216x hardware\n"); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lg2160_attach); + +MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.3"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/lg2160.h b/drivers/media/dvb/frontends/lg2160.h new file mode 100644 index 0000000..9e2c0f4 --- /dev/null +++ b/drivers/media/dvb/frontends/lg2160.h @@ -0,0 +1,84 @@ +/* + * Support for LG2160 - ATSC/MH + * + * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LG2160_H_ +#define _LG2160_H_ + +#include <linux/i2c.h> +#include "dvb_frontend.h" + +enum lg_chip_type { + LG2160 = 0, + LG2161 = 1, +}; + +#define LG2161_1019 LG2161 +#define LG2161_1040 LG2161 + +enum lg2160_spi_clock { + LG2160_SPI_3_125_MHZ = 0, + LG2160_SPI_6_25_MHZ = 1, + LG2160_SPI_12_5_MHZ = 2, +}; + +#if 0 +enum lg2161_oif { + LG2161_OIF_EBI2_SLA = 1, + LG2161_OIF_SDIO_SLA = 2, + LG2161_OIF_SPI_SLA = 3, + LG2161_OIF_SPI_MAS = 4, + LG2161_OIF_SERIAL_TS = 7, +}; +#endif + +struct lg2160_config { + u8 i2c_addr; + + /* user defined IF frequency in KHz */ + u16 if_khz; + + /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ + int deny_i2c_rptr:1; + + /* spectral inversion - 0:disabled 1:enabled */ + int spectral_inversion:1; + + unsigned int output_if; + enum lg2160_spi_clock spi_clock; + enum lg_chip_type lg_chip; +}; + +#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \ + defined(MODULE)) +extern +struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + struct i2c_adapter *i2c_adap); +#else +static inline +struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, + struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LG2160 */ + +#endif /* _LG2160_H_ */ diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index 4de1d35..568363a 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -262,7 +262,6 @@ static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv) static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) { - int ret = 0; u8 t; if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { @@ -296,7 +295,7 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) if (priv->config->prod == LGS8GXX_PROD_LGS8913) lgs8gxx_write_reg(priv, 0xC1, 0); - ret = lgs8gxx_read_reg(priv, 0xC5, &t); + lgs8gxx_read_reg(priv, 0xC5, &t); t = (t & 0xE0) | 0x06; lgs8gxx_write_reg(priv, 0xC5, t); diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c index 045ee5a..312588e 100644 --- a/drivers/media/dvb/frontends/m88rs2000.c +++ b/drivers/media/dvb/frontends/m88rs2000.c @@ -416,9 +416,25 @@ static int m88rs2000_tab_set(struct m88rs2000_state *state, static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) { - deb_info("%s: %s\n", __func__, - volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : - volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + struct m88rs2000_state *state = fe->demodulator_priv; + u8 data; + + data = m88rs2000_demod_read(state, 0xb2); + data |= 0x03; /* bit0 V/H, bit1 off/on */ + + switch (volt) { + case SEC_VOLTAGE_18: + data &= ~0x03; + break; + case SEC_VOLTAGE_13: + data &= ~0x03; + data |= 0x01; + break; + case SEC_VOLTAGE_OFF: + break; + } + + m88rs2000_demod_write(state, 0xb2, data); return 0; } @@ -654,7 +670,6 @@ static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset) static int m88rs2000_set_fec(struct m88rs2000_state *state, fe_code_rate_t fec) { - int ret; u16 fec_set; switch (fec) { /* This is not confirmed kept for reference */ @@ -677,7 +692,7 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state, default: fec_set = 0x08; } - ret = m88rs2000_demod_write(state, 0x76, fec_set); + m88rs2000_demod_write(state, 0x76, fec_set); return 0; } @@ -772,13 +787,13 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) return -ENODEV; for (i = 0; i < 25; i++) { - u8 reg = m88rs2000_demod_read(state, 0x8c); + reg = m88rs2000_demod_read(state, 0x8c); if ((reg & 0x7) == 0x7) { status = FE_HAS_LOCK; break; } state->no_lock_count++; - if (state->no_lock_count > 15) { + if (state->no_lock_count == 15) { reg = m88rs2000_demod_read(state, 0x70); reg ^= 0x4; m88rs2000_demod_write(state, 0x70, reg); diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c index 45196c5..93612eb 100644 --- a/drivers/media/dvb/frontends/rtl2830.c +++ b/drivers/media/dvb/frontends/rtl2830.c @@ -374,6 +374,118 @@ err: return ret; } +static int rtl2830_get_frontend(struct dvb_frontend *fe) +{ + struct rtl2830_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u8 buf[3]; + + if (priv->sleeping) + return 0; + + ret = rtl2830_rd_regs(priv, 0x33c, buf, 2); + if (ret) + goto err; + + ret = rtl2830_rd_reg(priv, 0x351, &buf[2]); + if (ret) + goto err; + + dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]); + + switch ((buf[0] >> 2) & 3) { + case 0: + c->modulation = QPSK; + break; + case 1: + c->modulation = QAM_16; + break; + case 2: + c->modulation = QAM_64; + break; + } + + switch ((buf[2] >> 2) & 1) { + case 0: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + c->transmission_mode = TRANSMISSION_MODE_8K; + } + + switch ((buf[2] >> 0) & 3) { + case 0: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[0] >> 4) & 7) { + case 0: + c->hierarchy = HIERARCHY_NONE; + break; + case 1: + c->hierarchy = HIERARCHY_1; + break; + case 2: + c->hierarchy = HIERARCHY_2; + break; + case 3: + c->hierarchy = HIERARCHY_4; + break; + } + + switch ((buf[1] >> 3) & 7) { + case 0: + c->code_rate_HP = FEC_1_2; + break; + case 1: + c->code_rate_HP = FEC_2_3; + break; + case 2: + c->code_rate_HP = FEC_3_4; + break; + case 3: + c->code_rate_HP = FEC_5_6; + break; + case 4: + c->code_rate_HP = FEC_7_8; + break; + } + + switch ((buf[1] >> 0) & 7) { + case 0: + c->code_rate_LP = FEC_1_2; + break; + case 1: + c->code_rate_LP = FEC_2_3; + break; + case 2: + c->code_rate_LP = FEC_3_4; + break; + case 3: + c->code_rate_LP = FEC_5_6; + break; + case 4: + c->code_rate_LP = FEC_7_8; + break; + } + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct rtl2830_priv *priv = fe->demodulator_priv; @@ -404,14 +516,72 @@ err: static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) { - *snr = 0; + struct rtl2830_priv *priv = fe->demodulator_priv; + int ret, hierarchy, constellation; + u8 buf[2], tmp; + u16 tmp16; +#define CONSTELLATION_NUM 3 +#define HIERARCHY_NUM 4 + static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { + { 70705899, 70705899, 70705899, 70705899 }, + { 82433173, 82433173, 87483115, 94445660 }, + { 92888734, 92888734, 95487525, 99770748 }, + }; + + if (priv->sleeping) + return 0; + + /* reports SNR in resolution of 0.1 dB */ + + ret = rtl2830_rd_reg(priv, 0x33c, &tmp); + if (ret) + goto err; + + constellation = (tmp >> 2) & 0x03; /* [3:2] */ + if (constellation > CONSTELLATION_NUM - 1) + goto err; + + hierarchy = (tmp >> 4) & 0x07; /* [6:4] */ + if (hierarchy > HIERARCHY_NUM - 1) + goto err; + + ret = rtl2830_rd_regs(priv, 0x40c, buf, 2); + if (ret) + goto err; + + tmp16 = buf[0] << 8 | buf[1]; + + if (tmp16) + *snr = (snr_constant[constellation][hierarchy] - + intlog10(tmp16)) / ((1 << 24) / 100); + else + *snr = 0; + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; } static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) { - *ber = 0; + struct rtl2830_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + + if (priv->sleeping) + return 0; + + ret = rtl2830_rd_regs(priv, 0x34e, buf, 2); + if (ret) + goto err; + + *ber = buf[0] << 8 | buf[1]; + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; } static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -422,8 +592,32 @@ static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - *strength = 0; + struct rtl2830_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + u16 if_agc_raw, if_agc; + + if (priv->sleeping) + return 0; + + ret = rtl2830_rd_regs(priv, 0x359, buf, 2); + if (ret) + goto err; + + if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff; + + if (if_agc_raw & (1 << 9)) + if_agc = -(~(if_agc_raw - 1) & 0x1ff); + else + if_agc = if_agc_raw; + + *strength = (u8) (55 - if_agc / 182); + *strength |= *strength << 8; + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; } static struct dvb_frontend_ops rtl2830_ops; @@ -549,6 +743,7 @@ static struct dvb_frontend_ops rtl2830_ops = { .get_tune_settings = rtl2830_get_tune_settings, .set_frontend = rtl2830_set_frontend, + .get_frontend = rtl2830_get_frontend, .read_status = rtl2830_read_status, .read_snr = rtl2830_read_snr, diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h index 4a46476..9b20557 100644 --- a/drivers/media/dvb/frontends/rtl2830_priv.h +++ b/drivers/media/dvb/frontends/rtl2830_priv.h @@ -22,6 +22,7 @@ #define RTL2830_PRIV_H #include "dvb_frontend.h" +#include "dvb_math.h" #include "rtl2830.h" #define LOG_PREFIX "rtl2830" diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index dd08f4a..8b0dc74 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -637,11 +637,9 @@ static void stb0899_init_calc(struct stb0899_state *state) struct stb0899_internal *internal = &state->internal; int master_clk; u8 agc[2]; - u8 agc1cn; u32 reg; /* Read registers (in burst mode) */ - agc1cn = stb0899_read_reg(state, STB0899_AGC1CN); stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */ /* Initial calculations */ @@ -823,15 +821,12 @@ static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t static int stb0899_diseqc_init(struct stb0899_state *state) { - struct dvb_diseqc_master_cmd tx_data; /* struct dvb_diseqc_slave_reply rx_data; */ - u8 f22_tx, f22_rx, reg; + u8 f22_tx, reg; u32 mclk, tx_freq = 22000;/* count = 0, i; */ - tx_data.msg[0] = 0xe2; - tx_data.msg_len = 3; reg = stb0899_read_reg(state, STB0899_DISCNTRL2); STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0); stb0899_write_reg(state, STB0899_DISCNTRL2, reg); @@ -849,7 +844,6 @@ static int stb0899_diseqc_init(struct stb0899_state *state) f22_tx = mclk / (tx_freq * 32); stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */ state->rx_freq = 20000; - f22_rx = mclk / (state->rx_freq * 32); return 0; } diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index def88ab..2e93e65 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c @@ -158,7 +158,6 @@ static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) static int stb6100_read_reg(struct stb6100_state *state, u8 reg) { u8 regs[STB6100_NUMREGS]; - int rc; struct i2c_msg msg = { .addr = state->config->tuner_address + reg, @@ -167,7 +166,7 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg) .len = 1 }; - rc = i2c_transfer(state->i2c, &msg, 1); + i2c_transfer(state->i2c, &msg, 1); if (unlikely(reg >= STB6100_NUMREGS)) { dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 85c157a..d40f226 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -414,7 +414,6 @@ static int stv0297_set_frontend(struct dvb_frontend *fe) int delay; int sweeprate; int carrieroffset; - unsigned long starttime; unsigned long timeout; fe_spectral_inversion_t inversion; @@ -543,7 +542,6 @@ static int stv0297_set_frontend(struct dvb_frontend *fe) stv0297_writereg_mask(state, 0x43, 0x10, 0x10); /* wait for WGAGC lock */ - starttime = jiffies; timeout = jiffies + msecs_to_jiffies(2000); while (time_before(jiffies, timeout)) { msleep(10); diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c index ba0709b..4af2078 100644 --- a/drivers/media/dvb/frontends/stv0900_sw.c +++ b/drivers/media/dvb/frontends/stv0900_sw.c @@ -835,7 +835,6 @@ static void stv0900_track_optimization(struct dvb_frontend *fe) blind_tun_sw = 0, modulation; - enum fe_stv0900_rolloff rolloff; enum fe_stv0900_modcode foundModcod; dprintk("%s\n", __func__); @@ -940,7 +939,6 @@ static void stv0900_track_optimization(struct dvb_frontend *fe) freq1 = stv0900_read_reg(intp, CFR2); freq0 = stv0900_read_reg(intp, CFR1); - rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS); if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) { stv0900_write_reg(intp, SFRSTEP, 0x00); stv0900_write_bits(intp, SCAN_ENABLE, 0); diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 4aef187..d79e69f 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -2842,7 +2842,6 @@ static int stv090x_optimize_track(struct stv090x_state *state) { struct dvb_frontend *fe = &state->frontend; - enum stv090x_rolloff rolloff; enum stv090x_modcod modcod; s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0; @@ -2966,7 +2965,6 @@ static int stv090x_optimize_track(struct stv090x_state *state) f_1 = STV090x_READ_DEMOD(state, CFR2); f_0 = STV090x_READ_DEMOD(state, CFR1); reg = STV090x_READ_DEMOD(state, TMGOBS); - rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); if (state->algo == STV090x_BLIND_SEARCH) { STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00); diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index ac72378..82946cd 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -525,7 +525,7 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr) zl10353_dump_regs(fe); _snr = zl10353_read_register(state, SNR); - *snr = (_snr << 8) | _snr; + *snr = 10 * _snr / 8; return 0; } @@ -559,7 +559,6 @@ static int zl10353_init(struct dvb_frontend *fe) { struct zl10353_state *state = fe->demodulator_priv; u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F }; - int rc = 0; if (debug_regs) zl10353_dump_regs(fe); @@ -573,7 +572,7 @@ static int zl10353_init(struct dvb_frontend *fe) /* Do a "hard" reset if not already done */ if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] || zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) { - rc = zl10353_write(fe, zl10353_reset_attach, + zl10353_write(fe, zl10353_reset_attach, sizeof(zl10353_reset_attach)); if (debug_regs) zl10353_dump_regs(fe); |