diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-06 20:27:48 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-06 20:27:48 +0100 |
commit | 68c5735eaa5e680e701c9a2d1e3c7880bdf5ab66 (patch) | |
tree | 4f584693638bf257b66a1646cc30d823cacc0a58 /drivers/media/dvb-frontends/si2165.c | |
parent | Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma (diff) | |
parent | media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs (diff) | |
download | linux-68c5735eaa5e680e701c9a2d1e3c7880bdf5ab66.tar.xz linux-68c5735eaa5e680e701c9a2d1e3c7880bdf5ab66.zip |
Merge tag 'media/v4.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- videobuf2 was moved to a media/common dir, as it is now used by the
DVB subsystem too
- Digital TV core memory mapped support interface
- new sensor driver: ov7740
- several improvements at ddbridge driver
- new V4L2 driver: IPU3 CIO2 CSI-2 receiver unit, found on some Intel
SoCs
- new tuner driver: tda18250
- finally got rid of all LIRC staging drivers
- as we don't have old lirc drivers anymore, restruct the lirc device
code
- add support for UVC metadata
- add a new staging driver for NVIDIA Tegra Video Decoder Engine
- DVB kAPI headers moved to include/media
- synchronize the kAPI and uAPI for the DVB subsystem, removing the gap
for non-legacy APIs
- reduce the kAPI gap for V4L2
- lots of other driver enhancements, cleanups, etc.
* tag 'media/v4.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (407 commits)
media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
media: v4l2-compat-ioctl32.c: avoid sizeof(type)
media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
media: v4l2-compat-ioctl32.c: fix the indentation
media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
media: v4l2-ioctl.c: use check_fmt for enum/g/s/try_fmt
media: vivid: fix module load error when enabling fb and no_error_inj=1
media: dvb_demux: improve debug messages
media: dvb_demux: Better handle discontinuity errors
media: cxusb, dib0700: ignore XC2028_I2C_FLUSH
media: ts2020: avoid integer overflows on 32 bit machines
media: i2c: ov7740: use gpio/consumer.h instead of gpio.h
media: entity: Add a nop variant of media_entity_cleanup
...
Diffstat (limited to 'drivers/media/dvb-frontends/si2165.c')
-rw-r--r-- | drivers/media/dvb-frontends/si2165.c | 613 |
1 files changed, 373 insertions, 240 deletions
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 528b82a5dd46..2dd336f95cbf 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -1,7 +1,7 @@ /* * Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator * - * Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org> + * Copyright (C) 2013-2017 Matthias Schwarzott <zzam@gentoo.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 @@ -27,8 +27,8 @@ #include <linux/firmware.h> #include <linux/regmap.h> -#include "dvb_frontend.h" -#include "dvb_math.h" +#include <media/dvb_frontend.h> +#include <media/dvb_math.h> #include "si2165_priv.h" #include "si2165.h" @@ -57,63 +57,21 @@ struct si2165_state { u32 sys_clk; u32 adc_clk; + /* DVBv3 stats */ + u64 ber_prev; + bool has_dvbc; bool has_dvbt; bool firmware_loaded; }; -#define DEBUG_OTHER 0x01 -#define DEBUG_I2C_WRITE 0x02 -#define DEBUG_I2C_READ 0x04 -#define DEBUG_REG_READ 0x08 -#define DEBUG_REG_WRITE 0x10 -#define DEBUG_FW_LOAD 0x20 - -static int debug = 0x00; - -#define dprintk(args...) \ - do { \ - if (debug & DEBUG_OTHER) \ - printk(KERN_DEBUG "si2165: " args); \ - } while (0) - -#define deb_i2c_write(args...) \ - do { \ - if (debug & DEBUG_I2C_WRITE) \ - printk(KERN_DEBUG "si2165: i2c write: " args); \ - } while (0) - -#define deb_i2c_read(args...) \ - do { \ - if (debug & DEBUG_I2C_READ) \ - printk(KERN_DEBUG "si2165: i2c read: " args); \ - } while (0) - -#define deb_readreg(args...) \ - do { \ - if (debug & DEBUG_REG_READ) \ - printk(KERN_DEBUG "si2165: reg read: " args); \ - } while (0) - -#define deb_writereg(args...) \ - do { \ - if (debug & DEBUG_REG_WRITE) \ - printk(KERN_DEBUG "si2165: reg write: " args); \ - } while (0) - -#define deb_fw_load(args...) \ - do { \ - if (debug & DEBUG_FW_LOAD) \ - printk(KERN_DEBUG "si2165: fw load: " args); \ - } while (0) - static int si2165_write(struct si2165_state *state, const u16 reg, - const u8 *src, const int count) + const u8 *src, const int count) { int ret; - if (debug & DEBUG_I2C_WRITE) - deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src); + dev_dbg(&state->client->dev, "i2c write: reg: 0x%04x, data: %*ph\n", + reg, count, src); ret = regmap_bulk_write(state->regmap, reg, src, count); @@ -134,30 +92,41 @@ static int si2165_read(struct si2165_state *state, return ret; } - if (debug & DEBUG_I2C_READ) - deb_i2c_read("reg: 0x%04x, data: %*ph\n", reg, count, val); + dev_dbg(&state->client->dev, "i2c read: reg: 0x%04x, data: %*ph\n", + reg, count, val); return 0; } static int si2165_readreg8(struct si2165_state *state, - const u16 reg, u8 *val) + const u16 reg, u8 *val) { unsigned int val_tmp; int ret = regmap_read(state->regmap, reg, &val_tmp); *val = (u8)val_tmp; - deb_readreg("R(0x%04x)=0x%02x\n", reg, *val); + dev_dbg(&state->client->dev, "reg read: R(0x%04x)=0x%02x\n", reg, *val); return ret; } static int si2165_readreg16(struct si2165_state *state, - const u16 reg, u16 *val) + const u16 reg, u16 *val) { u8 buf[2]; int ret = si2165_read(state, reg, buf, 2); *val = buf[0] | buf[1] << 8; - deb_readreg("R(0x%04x)=0x%04x\n", reg, *val); + dev_dbg(&state->client->dev, "reg read: R(0x%04x)=0x%04x\n", reg, *val); + return ret; +} + +static int si2165_readreg24(struct si2165_state *state, + const u16 reg, u32 *val) +{ + u8 buf[3]; + + int ret = si2165_read(state, reg, buf, 3); + *val = buf[0] | buf[1] << 8 | buf[2] << 16; + dev_dbg(&state->client->dev, "reg read: R(0x%04x)=0x%06x\n", reg, *val); return ret; } @@ -208,7 +177,9 @@ static int si2165_writereg_mask8(struct si2165_state *state, const u16 reg, return si2165_writereg8(state, reg, val); } -#define REG16(reg, val) { (reg), (val) & 0xff }, { (reg)+1, (val)>>8 & 0xff } +#define REG16(reg, val) \ + { (reg), (val) & 0xff }, \ + { (reg) + 1, (val) >> 8 & 0xff } struct si2165_reg_value_pair { u16 reg; u8 val; @@ -238,7 +209,7 @@ static int si2165_get_tune_settings(struct dvb_frontend *fe, static int si2165_init_pll(struct si2165_state *state) { - u32 ref_freq_Hz = state->config.ref_freq_Hz; + u32 ref_freq_hz = state->config.ref_freq_hz; u8 divr = 1; /* 1..7 */ u8 divp = 1; /* only 1 or 4 */ u8 divn = 56; /* 1..63 */ @@ -250,7 +221,7 @@ static int si2165_init_pll(struct si2165_state *state) * hardcoded values can be deleted if calculation is verified * or it yields the same values as the windows driver */ - switch (ref_freq_Hz) { + switch (ref_freq_hz) { case 16000000u: divn = 56; break; @@ -261,39 +232,39 @@ static int si2165_init_pll(struct si2165_state *state) break; default: /* ref_freq / divr must be between 4 and 16 MHz */ - if (ref_freq_Hz > 16000000u) + if (ref_freq_hz > 16000000u) divr = 2; /* * now select divn and divp such that * fvco is in 1624..1824 MHz */ - if (1624000000u * divr > ref_freq_Hz * 2u * 63u) + if (1624000000u * divr > ref_freq_hz * 2u * 63u) divp = 4; /* is this already correct regarding rounding? */ - divn = 1624000000u * divr / (ref_freq_Hz * 2u * divp); + divn = 1624000000u * divr / (ref_freq_hz * 2u * divp); break; } /* adc_clk and sys_clk depend on xtal and pll settings */ - state->fvco_hz = ref_freq_Hz / divr + state->fvco_hz = ref_freq_hz / divr * 2u * divn * divp; state->adc_clk = state->fvco_hz / (divm * 4u); state->sys_clk = state->fvco_hz / (divl * 2u); - /* write pll registers 0x00a0..0x00a3 at once */ + /* write all 4 pll registers 0x00a0..0x00a3 at once */ buf[0] = divl; buf[1] = divm; buf[2] = (divn & 0x3f) | ((divp == 1) ? 0x40 : 0x00) | 0x80; buf[3] = divr; - return si2165_write(state, 0x00a0, buf, 4); + return si2165_write(state, REG_PLL_DIVL, buf, 4); } static int si2165_adjust_pll_divl(struct si2165_state *state, u8 divl) { state->sys_clk = state->fvco_hz / (divl * 2u); - return si2165_writereg8(state, 0x00a0, divl); /* pll_divl */ + return si2165_writereg8(state, REG_PLL_DIVL, divl); } static u32 si2165_get_fe_clk(struct si2165_state *state) @@ -309,18 +280,18 @@ static int si2165_wait_init_done(struct si2165_state *state) int i; for (i = 0; i < 3; ++i) { - si2165_readreg8(state, 0x0054, &val); + si2165_readreg8(state, REG_INIT_DONE, &val); if (val == 0x01) return 0; usleep_range(1000, 50000); } - dev_err(&state->client->dev, "%s: init_done was not set\n", - KBUILD_MODNAME); + dev_err(&state->client->dev, "init_done was not set\n"); return ret; } static int si2165_upload_firmware_block(struct si2165_state *state, - const u8 *data, u32 len, u32 *poffset, u32 block_count) + const u8 *data, u32 len, u32 *poffset, + u32 block_count) { int ret; u8 buf_ctrl[4] = { 0x00, 0x00, 0x00, 0xc0 }; @@ -333,42 +304,43 @@ static int si2165_upload_firmware_block(struct si2165_state *state, if (len % 4 != 0) return -EINVAL; - deb_fw_load( - "si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n", - len, offset, block_count); - while (offset+12 <= len && cur_block < block_count) { - deb_fw_load( - "si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", - len, offset, cur_block, block_count); + dev_dbg(&state->client->dev, + "fw load: %s: called with len=0x%x offset=0x%x blockcount=0x%x\n", + __func__, len, offset, block_count); + while (offset + 12 <= len && cur_block < block_count) { + dev_dbg(&state->client->dev, + "fw load: %s: in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", + __func__, len, offset, cur_block, block_count); wordcount = data[offset]; - if (wordcount < 1 || data[offset+1] || - data[offset+2] || data[offset+3]) { + if (wordcount < 1 || data[offset + 1] || + data[offset + 2] || data[offset + 3]) { dev_warn(&state->client->dev, - "%s: bad fw data[0..3] = %*ph\n", - KBUILD_MODNAME, 4, data); + "bad fw data[0..3] = %*ph\n", + 4, data); return -EINVAL; } if (offset + 8 + wordcount * 4 > len) { dev_warn(&state->client->dev, - "%s: len is too small for block len=%d, wordcount=%d\n", - KBUILD_MODNAME, len, wordcount); + "len is too small for block len=%d, wordcount=%d\n", + len, wordcount); return -EINVAL; } buf_ctrl[0] = wordcount - 1; - ret = si2165_write(state, 0x0364, buf_ctrl, 4); + ret = si2165_write(state, REG_DCOM_CONTROL_BYTE, buf_ctrl, 4); if (ret < 0) goto error; - ret = si2165_write(state, 0x0368, data+offset+4, 4); + ret = si2165_write(state, REG_DCOM_ADDR, data + offset + 4, 4); if (ret < 0) goto error; offset += 8; while (wordcount > 0) { - ret = si2165_write(state, 0x36c, data+offset, 4); + ret = si2165_write(state, REG_DCOM_DATA, + data + offset, 4); if (ret < 0) goto error; wordcount--; @@ -377,15 +349,16 @@ static int si2165_upload_firmware_block(struct si2165_state *state, cur_block++; } - deb_fw_load( - "si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", - len, offset, cur_block, block_count); + dev_dbg(&state->client->dev, + "fw load: %s: after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", + __func__, len, offset, cur_block, block_count); if (poffset) *poffset = offset; - deb_fw_load("si2165_upload_firmware_block returned offset=0x%x\n", - offset); + dev_dbg(&state->client->dev, + "fw load: %s: returned offset=0x%x\n", + __func__, offset); return 0; error: @@ -413,43 +386,40 @@ static int si2165_upload_firmware(struct si2165_state *state) fw_file = SI2165_FIRMWARE_REV_D; break; default: - dev_info(&state->client->dev, "%s: no firmware file for revision=%d\n", - KBUILD_MODNAME, state->chip_revcode); + dev_info(&state->client->dev, "no firmware file for revision=%d\n", + state->chip_revcode); return 0; } /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &state->client->dev); if (ret) { - dev_warn(&state->client->dev, "%s: firmware file '%s' not found\n", - KBUILD_MODNAME, fw_file); + dev_warn(&state->client->dev, "firmware file '%s' not found\n", + fw_file); goto error; } data = fw->data; len = fw->size; - dev_info(&state->client->dev, "%s: downloading firmware from file '%s' size=%d\n", - KBUILD_MODNAME, fw_file, len); + dev_info(&state->client->dev, "downloading firmware from file '%s' size=%d\n", + fw_file, len); if (len % 4 != 0) { - dev_warn(&state->client->dev, "%s: firmware size is not multiple of 4\n", - KBUILD_MODNAME); + dev_warn(&state->client->dev, "firmware size is not multiple of 4\n"); ret = -EINVAL; goto error; } /* check header (8 bytes) */ if (len < 8) { - dev_warn(&state->client->dev, "%s: firmware header is missing\n", - KBUILD_MODNAME); + dev_warn(&state->client->dev, "firmware header is missing\n"); ret = -EINVAL; goto error; } if (data[0] != 1 || data[1] != 0) { - dev_warn(&state->client->dev, "%s: firmware file version is wrong\n", - KBUILD_MODNAME); + dev_warn(&state->client->dev, "firmware file version is wrong\n"); ret = -EINVAL; goto error; } @@ -460,45 +430,45 @@ static int si2165_upload_firmware(struct si2165_state *state) /* start uploading fw */ /* boot/wdog status */ - ret = si2165_writereg8(state, 0x0341, 0x00); + ret = si2165_writereg8(state, REG_WDOG_AND_BOOT, 0x00); if (ret < 0) goto error; /* reset */ - ret = si2165_writereg8(state, 0x00c0, 0x00); + ret = si2165_writereg8(state, REG_RST_ALL, 0x00); if (ret < 0) goto error; /* boot/wdog status */ - ret = si2165_readreg8(state, 0x0341, val); + ret = si2165_readreg8(state, REG_WDOG_AND_BOOT, val); if (ret < 0) goto error; /* enable reset on error */ - ret = si2165_readreg8(state, 0x035c, val); + ret = si2165_readreg8(state, REG_EN_RST_ERROR, val); if (ret < 0) goto error; - ret = si2165_readreg8(state, 0x035c, val); + ret = si2165_readreg8(state, REG_EN_RST_ERROR, val); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x035c, 0x02); + ret = si2165_writereg8(state, REG_EN_RST_ERROR, 0x02); if (ret < 0) goto error; /* start right after the header */ offset = 8; - dev_info(&state->client->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n", - KBUILD_MODNAME, patch_version, block_count, crc_expected); + dev_info(&state->client->dev, "%s: extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n", + __func__, patch_version, block_count, crc_expected); ret = si2165_upload_firmware_block(state, data, len, &offset, 1); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x0344, patch_version); + ret = si2165_writereg8(state, REG_PATCH_VERSION, patch_version); if (ret < 0) goto error; /* reset crc */ - ret = si2165_writereg8(state, 0x0379, 0x01); + ret = si2165_writereg8(state, REG_RST_CRC, 0x01); if (ret) goto error; @@ -506,20 +476,19 @@ static int si2165_upload_firmware(struct si2165_state *state) &offset, block_count); if (ret < 0) { dev_err(&state->client->dev, - "%s: firmware could not be uploaded\n", - KBUILD_MODNAME); + "firmware could not be uploaded\n"); goto error; } /* read crc */ - ret = si2165_readreg16(state, 0x037a, &val16); + ret = si2165_readreg16(state, REG_CRC, &val16); if (ret) goto error; if (val16 != crc_expected) { dev_err(&state->client->dev, - "%s: firmware crc mismatch %04x != %04x\n", - KBUILD_MODNAME, val16, crc_expected); + "firmware crc mismatch %04x != %04x\n", + val16, crc_expected); ret = -EINVAL; goto error; } @@ -530,23 +499,23 @@ static int si2165_upload_firmware(struct si2165_state *state) if (len != offset) { dev_err(&state->client->dev, - "%s: firmware len mismatch %04x != %04x\n", - KBUILD_MODNAME, len, offset); + "firmware len mismatch %04x != %04x\n", + len, offset); ret = -EINVAL; goto error; } /* reset watchdog error register */ - ret = si2165_writereg_mask8(state, 0x0341, 0x02, 0x02); + ret = si2165_writereg_mask8(state, REG_WDOG_AND_BOOT, 0x02, 0x02); if (ret < 0) goto error; /* enable reset on error */ - ret = si2165_writereg_mask8(state, 0x035c, 0x01, 0x01); + ret = si2165_writereg_mask8(state, REG_EN_RST_ERROR, 0x01, 0x01); if (ret < 0) goto error; - dev_info(&state->client->dev, "%s: fw load finished\n", KBUILD_MODNAME); + dev_info(&state->client->dev, "fw load finished\n"); ret = 0; state->firmware_loaded = true; @@ -563,46 +532,47 @@ static int si2165_init(struct dvb_frontend *fe) { int ret = 0; struct si2165_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 val; u8 patch_version = 0x00; - dprintk("%s: called\n", __func__); + dev_dbg(&state->client->dev, "%s: called\n", __func__); /* powerup */ - ret = si2165_writereg8(state, 0x0000, state->config.chip_mode); + ret = si2165_writereg8(state, REG_CHIP_MODE, state->config.chip_mode); if (ret < 0) goto error; /* dsp_clock_enable */ - ret = si2165_writereg8(state, 0x0104, 0x01); + ret = si2165_writereg8(state, REG_DSP_CLOCK, 0x01); if (ret < 0) goto error; - ret = si2165_readreg8(state, 0x0000, &val); /* verify chip_mode */ + /* verify chip_mode */ + ret = si2165_readreg8(state, REG_CHIP_MODE, &val); if (ret < 0) goto error; if (val != state->config.chip_mode) { - dev_err(&state->client->dev, "%s: could not set chip_mode\n", - KBUILD_MODNAME); + dev_err(&state->client->dev, "could not set chip_mode\n"); return -EINVAL; } /* agc */ - ret = si2165_writereg8(state, 0x018b, 0x00); + ret = si2165_writereg8(state, REG_AGC_IF_TRI, 0x00); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x0190, 0x01); + ret = si2165_writereg8(state, REG_AGC_IF_SLR, 0x01); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x0170, 0x00); + ret = si2165_writereg8(state, REG_AGC2_OUTPUT, 0x00); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x0171, 0x07); + ret = si2165_writereg8(state, REG_AGC2_CLKDIV, 0x07); if (ret < 0) goto error; /* rssi pad */ - ret = si2165_writereg8(state, 0x0646, 0x00); + ret = si2165_writereg8(state, REG_RSSI_PAD_CTRL, 0x00); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x0641, 0x00); + ret = si2165_writereg8(state, REG_RSSI_ENABLE, 0x00); if (ret < 0) goto error; @@ -611,11 +581,11 @@ static int si2165_init(struct dvb_frontend *fe) goto error; /* enable chip_init */ - ret = si2165_writereg8(state, 0x0050, 0x01); + ret = si2165_writereg8(state, REG_CHIP_INIT, 0x01); if (ret < 0) goto error; /* set start_init */ - ret = si2165_writereg8(state, 0x0096, 0x01); + ret = si2165_writereg8(state, REG_START_INIT, 0x01); if (ret < 0) goto error; ret = si2165_wait_init_done(state); @@ -623,29 +593,30 @@ static int si2165_init(struct dvb_frontend *fe) goto error; /* disable chip_init */ - ret = si2165_writereg8(state, 0x0050, 0x00); + ret = si2165_writereg8(state, REG_CHIP_INIT, 0x00); if (ret < 0) goto error; - /* ber_pkt */ - ret = si2165_writereg16(state, 0x0470, 0x7530); + /* ber_pkt - default 65535 */ + ret = si2165_writereg16(state, REG_BER_PKT, + STATISTICS_PERIOD_PKT_COUNT); if (ret < 0) goto error; - ret = si2165_readreg8(state, 0x0344, &patch_version); + ret = si2165_readreg8(state, REG_PATCH_VERSION, &patch_version); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x00cb, 0x00); + ret = si2165_writereg8(state, REG_AUTO_RESET, 0x00); if (ret < 0) goto error; /* dsp_addr_jump */ - ret = si2165_writereg32(state, 0x0348, 0xf4000000); + ret = si2165_writereg32(state, REG_ADDR_JUMP, 0xf4000000); if (ret < 0) goto error; /* boot/wdog status */ - ret = si2165_readreg8(state, 0x0341, &val); + ret = si2165_readreg8(state, REG_WDOG_AND_BOOT, &val); if (ret < 0) goto error; @@ -656,19 +627,30 @@ static int si2165_init(struct dvb_frontend *fe) } /* ts output config */ - ret = si2165_writereg8(state, 0x04e4, 0x20); + ret = si2165_writereg8(state, REG_TS_DATA_MODE, 0x20); + if (ret < 0) + return ret; + ret = si2165_writereg16(state, REG_TS_TRI, 0x00fe); if (ret < 0) return ret; - ret = si2165_writereg16(state, 0x04ef, 0x00fe); + ret = si2165_writereg24(state, REG_TS_SLR, 0x555555); if (ret < 0) return ret; - ret = si2165_writereg24(state, 0x04f4, 0x555555); + ret = si2165_writereg8(state, REG_TS_CLK_MODE, 0x01); if (ret < 0) return ret; - ret = si2165_writereg8(state, 0x04e5, 0x01); + ret = si2165_writereg8(state, REG_TS_PARALLEL_MODE, 0x00); if (ret < 0) return ret; + c = &state->fe.dtv_property_cache; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; error: return ret; @@ -680,11 +662,11 @@ static int si2165_sleep(struct dvb_frontend *fe) struct si2165_state *state = fe->demodulator_priv; /* dsp clock disable */ - ret = si2165_writereg8(state, 0x0104, 0x00); + ret = si2165_writereg8(state, REG_DSP_CLOCK, 0x00); if (ret < 0) return ret; /* chip mode */ - ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF); + ret = si2165_writereg8(state, REG_CHIP_MODE, SI2165_MODE_OFF); if (ret < 0) return ret; return 0; @@ -693,18 +675,48 @@ static int si2165_sleep(struct dvb_frontend *fe) static int si2165_read_status(struct dvb_frontend *fe, enum fe_status *status) { int ret; - u8 fec_lock = 0; + u8 u8tmp; + u32 u32tmp; struct si2165_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; - if (!state->has_dvbt) - return -EINVAL; + *status = 0; + + switch (delsys) { + case SYS_DVBT: + /* check fast signal type */ + ret = si2165_readreg8(state, REG_CHECK_SIGNAL, &u8tmp); + if (ret < 0) + return ret; + switch (u8tmp & 0x3) { + case 0: /* searching */ + case 1: /* nothing */ + break; + case 2: /* digital signal */ + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + } + break; + case SYS_DVBC_ANNEX_A: + /* check packet sync lock */ + ret = si2165_readreg8(state, REG_PS_LOCK, &u8tmp); + if (ret < 0) + return ret; + if (u8tmp & 0x01) { + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + } + break; + } /* check fec_lock */ - ret = si2165_readreg8(state, 0x4e0, &fec_lock); + ret = si2165_readreg8(state, REG_FEC_LOCK, &u8tmp); if (ret < 0) return ret; - *status = 0; - if (fec_lock & 0x01) { + if (u8tmp & 0x01) { *status |= FE_HAS_SIGNAL; *status |= FE_HAS_CARRIER; *status |= FE_HAS_VITERBI; @@ -712,6 +724,109 @@ static int si2165_read_status(struct dvb_frontend *fe, enum fe_status *status) *status |= FE_HAS_LOCK; } + /* CNR */ + if (delsys == SYS_DVBC_ANNEX_A && *status & FE_HAS_VITERBI) { + ret = si2165_readreg24(state, REG_C_N, &u32tmp); + if (ret < 0) + return ret; + /* + * svalue = + * 1000 * c_n/dB = + * 1000 * 10 * log10(2^24 / regval) = + * 1000 * 10 * (log10(2^24) - log10(regval)) = + * 1000 * 10 * (intlog10(2^24) - intlog10(regval)) / 2^24 + * + * intlog10(x) = log10(x) * 2^24 + * intlog10(2^24) = log10(2^24) * 2^24 = 121210686 + */ + u32tmp = (1000 * 10 * (121210686 - (u64)intlog10(u32tmp))) + >> 24; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = u32tmp; + } else + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + /* BER */ + if (*status & FE_HAS_VITERBI) { + if (c->post_bit_error.stat[0].scale == FE_SCALE_NOT_AVAILABLE) { + /* start new sampling period to get rid of old data*/ + ret = si2165_writereg8(state, REG_BER_RST, 0x01); + if (ret < 0) + return ret; + + /* set scale to enter read code on next call */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + + /* + * reset DVBv3 value to deliver a good result + * for the first call + */ + state->ber_prev = 0; + + } else { + ret = si2165_readreg8(state, REG_BER_AVAIL, &u8tmp); + if (ret < 0) + return ret; + + if (u8tmp & 1) { + u32 biterrcnt; + + ret = si2165_readreg24(state, REG_BER_BIT, + &biterrcnt); + if (ret < 0) + return ret; + + c->post_bit_error.stat[0].uvalue += + biterrcnt; + c->post_bit_count.stat[0].uvalue += + STATISTICS_PERIOD_BIT_COUNT; + + /* start new sampling period */ + ret = si2165_writereg8(state, + REG_BER_RST, 0x01); + if (ret < 0) + return ret; + + dev_dbg(&state->client->dev, + "post_bit_error=%u post_bit_count=%u\n", + biterrcnt, STATISTICS_PERIOD_BIT_COUNT); + } + } + } else { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + return 0; +} + +static int si2165_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) + *snr = div_s64(c->cnr.stat[0].svalue, 100); + else + *snr = 0; + return 0; +} + +static int si2165_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct si2165_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (c->post_bit_error.stat[0].scale != FE_SCALE_COUNTER) { + *ber = 0; + return 0; + } + + *ber = c->post_bit_error.stat[0].uvalue - state->ber_prev; + state->ber_prev = c->post_bit_error.stat[0].uvalue; + return 0; } @@ -728,8 +843,8 @@ static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate) do_div(oversamp, dvb_rate); reg_value = oversamp & 0x3fffffff; - dprintk("%s: Write oversamp=%#x\n", __func__, reg_value); - return si2165_writereg32(state, 0x00e4, reg_value); + dev_dbg(&state->client->dev, "Write oversamp=%#x\n", reg_value); + return si2165_writereg32(state, REG_OVERSAMP, reg_value); } static int si2165_set_if_freq_shift(struct si2165_state *state) @@ -742,8 +857,7 @@ static int si2165_set_if_freq_shift(struct si2165_state *state) if (!fe->ops.tuner_ops.get_if_frequency) { dev_err(&state->client->dev, - "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n", - KBUILD_MODNAME); + "Error: get_if_frequency() not defined at tuner. Can't work without it!\n"); return -EINVAL; } @@ -763,30 +877,29 @@ static int si2165_set_if_freq_shift(struct si2165_state *state) reg_value = reg_value & 0x1fffffff; /* if_freq_shift, usbdump contained 0x023ee08f; */ - return si2165_writereg32(state, 0x00e8, reg_value); + return si2165_writereg32(state, REG_IF_FREQ_SHIFT, reg_value); } static const struct si2165_reg_value_pair dvbt_regs[] = { /* standard = DVB-T */ - { 0x00ec, 0x01 }, - { 0x08f8, 0x00 }, + { REG_DVB_STANDARD, 0x01 }, /* impulsive_noise_remover */ - { 0x031c, 0x01 }, - { 0x00cb, 0x00 }, + { REG_IMPULSIVE_NOISE_REM, 0x01 }, + { REG_AUTO_RESET, 0x00 }, /* agc2 */ - { 0x016e, 0x41 }, - { 0x016c, 0x0e }, - { 0x016d, 0x10 }, + { REG_AGC2_MIN, 0x41 }, + { REG_AGC2_KACQ, 0x0e }, + { REG_AGC2_KLOC, 0x10 }, /* agc */ - { 0x015b, 0x03 }, - { 0x0150, 0x78 }, + { REG_AGC_UNFREEZE_THR, 0x03 }, + { REG_AGC_CRESTF_DBX8, 0x78 }, /* agc */ - { 0x01a0, 0x78 }, - { 0x01c8, 0x68 }, + { REG_AAF_CRESTF_DBX8, 0x78 }, + { REG_ACI_CRESTF_DBX8, 0x68 }, /* freq_sync_range */ - REG16(0x030c, 0x0064), + REG16(REG_FREQ_SYNC_RANGE, 0x0064), /* gp_reg0 */ - { 0x0387, 0x00 } + { REG_GP_REG0_MSB, 0x00 } }; static int si2165_set_frontend_dvbt(struct dvb_frontend *fe) @@ -798,7 +911,7 @@ static int si2165_set_frontend_dvbt(struct dvb_frontend *fe) u16 bw10k; u32 bw_hz = p->bandwidth_hz; - dprintk("%s: called\n", __func__); + dev_dbg(&state->client->dev, "%s: called\n", __func__); if (!state->has_dvbt) return -EINVAL; @@ -815,7 +928,7 @@ static int si2165_set_frontend_dvbt(struct dvb_frontend *fe) return ret; /* bandwidth in 10KHz steps */ - ret = si2165_writereg16(state, 0x0308, bw10k); + ret = si2165_writereg16(state, REG_T_BANDWIDTH, bw10k); if (ret < 0) return ret; ret = si2165_set_oversamp(state, dvb_rate); @@ -831,33 +944,30 @@ static int si2165_set_frontend_dvbt(struct dvb_frontend *fe) static const struct si2165_reg_value_pair dvbc_regs[] = { /* standard = DVB-C */ - { 0x00ec, 0x05 }, - { 0x08f8, 0x00 }, + { REG_DVB_STANDARD, 0x05 }, /* agc2 */ - { 0x016e, 0x50 }, - { 0x016c, 0x0e }, - { 0x016d, 0x10 }, + { REG_AGC2_MIN, 0x50 }, + { REG_AGC2_KACQ, 0x0e }, + { REG_AGC2_KLOC, 0x10 }, /* agc */ - { 0x015b, 0x03 }, - { 0x0150, 0x68 }, + { REG_AGC_UNFREEZE_THR, 0x03 }, + { REG_AGC_CRESTF_DBX8, 0x68 }, /* agc */ - { 0x01a0, 0x68 }, - { 0x01c8, 0x50 }, - - { 0x0278, 0x0d }, - - { 0x023a, 0x05 }, - { 0x0261, 0x09 }, - REG16(0x0350, 0x3e80), - { 0x02f4, 0x00 }, - - { 0x00cb, 0x01 }, - REG16(0x024c, 0x0000), - REG16(0x027c, 0x0000), - { 0x0232, 0x03 }, - { 0x02f4, 0x0b }, - { 0x018b, 0x00 }, + { REG_AAF_CRESTF_DBX8, 0x68 }, + { REG_ACI_CRESTF_DBX8, 0x50 }, + + { REG_EQ_AUTO_CONTROL, 0x0d }, + + { REG_KP_LOCK, 0x05 }, + { REG_CENTRAL_TAP, 0x09 }, + REG16(REG_UNKNOWN_350, 0x3e80), + + { REG_AUTO_RESET, 0x01 }, + REG16(REG_UNKNOWN_24C, 0x0000), + REG16(REG_UNKNOWN_27C, 0x0000), + { REG_SWEEP_STEP, 0x03 }, + { REG_AGC_IF_TRI, 0x00 }, }; static int si2165_set_frontend_dvbc(struct dvb_frontend *fe) @@ -866,7 +976,7 @@ static int si2165_set_frontend_dvbc(struct dvb_frontend *fe) int ret; struct dtv_frontend_properties *p = &fe->dtv_property_cache; const u32 dvb_rate = p->symbol_rate; - const u32 bw_hz = p->bandwidth_hz; + u8 u8tmp; if (!state->has_dvbc) return -EINVAL; @@ -883,7 +993,32 @@ static int si2165_set_frontend_dvbc(struct dvb_frontend *fe) if (ret < 0) return ret; - ret = si2165_writereg32(state, 0x00c4, bw_hz); + switch (p->modulation) { + case QPSK: + u8tmp = 0x3; + break; + case QAM_16: + u8tmp = 0x7; + break; + case QAM_32: + u8tmp = 0x8; + break; + case QAM_64: + u8tmp = 0x9; + break; + case QAM_128: + u8tmp = 0xa; + break; + case QAM_256: + default: + u8tmp = 0xb; + break; + } + ret = si2165_writereg8(state, REG_REQ_CONSTELLATION, u8tmp); + if (ret < 0) + return ret; + + ret = si2165_writereg32(state, REG_LOCK_TIMEOUT, 0x007a1200); if (ret < 0) return ret; @@ -894,12 +1029,12 @@ static int si2165_set_frontend_dvbc(struct dvb_frontend *fe) return 0; } -static const struct si2165_reg_value_pair agc_rewrite[] = { - { 0x012a, 0x46 }, - { 0x012c, 0x00 }, - { 0x012e, 0x0a }, - { 0x012f, 0xff }, - { 0x0123, 0x70 } +static const struct si2165_reg_value_pair adc_rewrite[] = { + { REG_ADC_RI1, 0x46 }, + { REG_ADC_RI3, 0x00 }, + { REG_ADC_RI5, 0x0a }, + { REG_ADC_RI6, 0xff }, + { REG_ADC_RI8, 0x70 } }; static int si2165_set_frontend(struct dvb_frontend *fe) @@ -931,7 +1066,7 @@ static int si2165_set_frontend(struct dvb_frontend *fe) } /* dsp_addr_jump */ - ret = si2165_writereg32(state, 0x0348, 0xf4000000); + ret = si2165_writereg32(state, REG_ADDR_JUMP, 0xf4000000); if (ret < 0) return ret; @@ -944,34 +1079,34 @@ static int si2165_set_frontend(struct dvb_frontend *fe) return ret; /* boot/wdog status */ - ret = si2165_readreg8(state, 0x0341, val); + ret = si2165_readreg8(state, REG_WDOG_AND_BOOT, val); if (ret < 0) return ret; - ret = si2165_writereg8(state, 0x0341, 0x00); + ret = si2165_writereg8(state, REG_WDOG_AND_BOOT, 0x00); if (ret < 0) return ret; /* reset all */ - ret = si2165_writereg8(state, 0x00c0, 0x00); + ret = si2165_writereg8(state, REG_RST_ALL, 0x00); if (ret < 0) return ret; /* gp_reg0 */ - ret = si2165_writereg32(state, 0x0384, 0x00000000); + ret = si2165_writereg32(state, REG_GP_REG0_LSB, 0x00000000); if (ret < 0) return ret; /* write adc values after each reset*/ - ret = si2165_write_reg_list(state, agc_rewrite, - ARRAY_SIZE(agc_rewrite)); + ret = si2165_write_reg_list(state, adc_rewrite, + ARRAY_SIZE(adc_rewrite)); if (ret < 0) return ret; /* start_synchro */ - ret = si2165_writereg8(state, 0x02e0, 0x01); + ret = si2165_writereg8(state, REG_START_SYNCHRO, 0x01); if (ret < 0) return ret; /* boot/wdog status */ - ret = si2165_readreg8(state, 0x0341, val); + ret = si2165_readreg8(state, REG_WDOG_AND_BOOT, val); if (ret < 0) return ret; @@ -998,7 +1133,6 @@ static const struct dvb_frontend_ops si2165_ops = { FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_MUTE_TS | @@ -1013,10 +1147,12 @@ static const struct dvb_frontend_ops si2165_ops = { .set_frontend = si2165_set_frontend, .read_status = si2165_read_status, + .read_snr = si2165_read_snr, + .read_ber = si2165_read_ber, }; static int si2165_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct si2165_state *state = NULL; struct si2165_platform_data *pdata = client->dev.platform_data; @@ -1032,8 +1168,8 @@ static int si2165_probe(struct i2c_client *client, }; /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL); - if (state == NULL) { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { ret = -ENOMEM; goto error; } @@ -1049,45 +1185,45 @@ static int si2165_probe(struct i2c_client *client, state->client = client; state->config.i2c_addr = client->addr; state->config.chip_mode = pdata->chip_mode; - state->config.ref_freq_Hz = pdata->ref_freq_Hz; + state->config.ref_freq_hz = pdata->ref_freq_hz; state->config.inversion = pdata->inversion; - if (state->config.ref_freq_Hz < 4000000 - || state->config.ref_freq_Hz > 27000000) { - dev_err(&state->client->dev, "%s: ref_freq of %d Hz not supported by this driver\n", - KBUILD_MODNAME, state->config.ref_freq_Hz); + if (state->config.ref_freq_hz < 4000000 || + state->config.ref_freq_hz > 27000000) { + dev_err(&state->client->dev, "ref_freq of %d Hz not supported by this driver\n", + state->config.ref_freq_hz); ret = -EINVAL; goto error; } /* create dvb_frontend */ memcpy(&state->fe.ops, &si2165_ops, - sizeof(struct dvb_frontend_ops)); + sizeof(struct dvb_frontend_ops)); state->fe.ops.release = NULL; state->fe.demodulator_priv = state; i2c_set_clientdata(client, state); /* powerup */ - ret = si2165_writereg8(state, 0x0000, state->config.chip_mode); + ret = si2165_writereg8(state, REG_CHIP_MODE, state->config.chip_mode); if (ret < 0) goto nodev_error; - ret = si2165_readreg8(state, 0x0000, &val); + ret = si2165_readreg8(state, REG_CHIP_MODE, &val); if (ret < 0) goto nodev_error; if (val != state->config.chip_mode) goto nodev_error; - ret = si2165_readreg8(state, 0x0023, &state->chip_revcode); + ret = si2165_readreg8(state, REG_CHIP_REVCODE, &state->chip_revcode); if (ret < 0) goto nodev_error; - ret = si2165_readreg8(state, 0x0118, &state->chip_type); + ret = si2165_readreg8(state, REV_CHIP_TYPE, &state->chip_type); if (ret < 0) goto nodev_error; /* powerdown */ - ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF); + ret = si2165_writereg8(state, REG_CHIP_MODE, SI2165_MODE_OFF); if (ret < 0) goto nodev_error; @@ -1107,18 +1243,18 @@ static int si2165_probe(struct i2c_client *client, state->has_dvbc = true; break; default: - dev_err(&state->client->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n", - KBUILD_MODNAME, state->chip_type, state->chip_revcode); + dev_err(&state->client->dev, "Unsupported Silicon Labs chip (type %d, rev %d)\n", + state->chip_type, state->chip_revcode); goto nodev_error; } dev_info(&state->client->dev, - "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n", - KBUILD_MODNAME, chip_name, rev_char, state->chip_type, + "Detected Silicon Labs %s-%c (type %d, rev %d)\n", + chip_name, rev_char, state->chip_type, state->chip_revcode); strlcat(state->fe.ops.info.name, chip_name, - sizeof(state->fe.ops.info.name)); + sizeof(state->fe.ops.info.name)); n = 0; if (state->has_dvbt) { @@ -1173,9 +1309,6 @@ static struct i2c_driver si2165_driver = { module_i2c_driver(si2165_driver); -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver"); MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>"); MODULE_LICENSE("GPL"); |