diff options
Diffstat (limited to 'drivers/media/tuners')
25 files changed, 963 insertions, 203 deletions
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index f039dc2a21cf..42e5a01b9192 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -232,6 +232,14 @@ config MEDIA_TUNER_M88TS2022 help Montage M88TS2022 silicon tuner driver. +config MEDIA_TUNER_M88RS6000T + tristate "Montage M88RS6000 internal tuner" + depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Montage M88RS6000 internal tuner. + config MEDIA_TUNER_TUA9001 tristate "Infineon TUA 9001 silicon tuner" depends on MEDIA_SUPPORT && I2C diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 49fcf8033848..da4fe6ef73e7 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o +obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/m88rs6000t.c b/drivers/media/tuners/m88rs6000t.c new file mode 100644 index 000000000000..d4c13fe6e7b3 --- /dev/null +++ b/drivers/media/tuners/m88rs6000t.c @@ -0,0 +1,744 @@ +/* + * Driver for the internal tuner of Montage M88RS6000 + * + * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> + * + * 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. + */ + +#include "m88rs6000t.h" +#include <linux/regmap.h> + +struct m88rs6000t_dev { + struct m88rs6000t_config cfg; + struct i2c_client *client; + struct regmap *regmap; + u32 frequency_khz; +}; + +struct m88rs6000t_reg_val { + u8 reg; + u8 val; +}; + +/* set demod main mclk and ts mclk */ +static int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 reg11, reg15, reg16, reg1D, reg1E, reg1F; + u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0; + u16 pll_div_fb; + u32 div, ts_mclk; + unsigned int utmp; + int ret; + + /* select demod main mclk */ + ret = regmap_read(dev->regmap, 0x15, &utmp); + if (ret) + goto err; + reg15 = utmp; + if (c->symbol_rate > 45010000) { + reg11 = 0x0E; + reg15 |= 0x02; + reg16 = 115; /* mclk = 110.25MHz */ + } else { + reg11 = 0x0A; + reg15 &= ~0x02; + reg16 = 96; /* mclk = 96MHz */ + } + + /* set ts mclk */ + if (c->delivery_system == SYS_DVBS) + ts_mclk = 96000; + else + ts_mclk = 144000; + + pll_div_fb = (reg15 & 0x01) << 8; + pll_div_fb += reg16; + pll_div_fb += 32; + + div = 36000 * pll_div_fb; + div /= ts_mclk; + + if (div <= 32) { + N = 2; + f0 = 0; + f1 = div / 2; + f2 = div - f1; + f3 = 0; + } else if (div <= 48) { + N = 3; + f0 = div / 3; + f1 = (div - f0) / 2; + f2 = div - f0 - f1; + f3 = 0; + } else if (div <= 64) { + N = 4; + f0 = div / 4; + f1 = (div - f0) / 3; + f2 = (div - f0 - f1) / 2; + f3 = div - f0 - f1 - f2; + } else { + N = 4; + f0 = 16; + f1 = 16; + f2 = 16; + f3 = 16; + } + + if (f0 == 16) + f0 = 0; + if (f1 == 16) + f1 = 0; + if (f2 == 16) + f2 = 0; + if (f3 == 16) + f3 = 0; + + ret = regmap_read(dev->regmap, 0x1D, &utmp); + if (ret) + goto err; + reg1D = utmp; + reg1D &= ~0x03; + reg1D |= N - 1; + reg1E = ((f3 << 4) + f2) & 0xFF; + reg1F = ((f1 << 4) + f0) & 0xFF; + + /* program and recalibrate demod PLL */ + ret = regmap_write(dev->regmap, 0x05, 0x40); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x11, 0x08); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x15, reg15); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x16, reg16); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x1D, reg1D); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x1E, reg1E); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x1F, reg1F); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x17, 0xc1); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x17, 0x81); + if (ret) + goto err; + usleep_range(5000, 50000); + ret = regmap_write(dev->regmap, 0x05, 0x00); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x11, reg11); + if (ret) + goto err; + usleep_range(5000, 50000); +err: + if (ret) + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + return ret; +} + +static int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev, + u32 tuner_freq_MHz) +{ + u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv; + u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod; + u8 reg27, reg29, reg42, reg42buf; + unsigned int utmp; + int ret; + + fcry_KHz = 27000; /* in kHz */ + refDiv = 27; + + ret = regmap_write(dev->regmap, 0x36, (refDiv - 8)); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x31, 0x00); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x2c, 0x02); + if (ret) + goto err; + + if (tuner_freq_MHz >= 1550) { + ucLoDiv1 = 2; + ucLomod1 = 0; + ucLoDiv2 = 2; + ucLomod2 = 0; + } else if (tuner_freq_MHz >= 1380) { + ucLoDiv1 = 3; + ucLomod1 = 16; + ucLoDiv2 = 2; + ucLomod2 = 0; + } else if (tuner_freq_MHz >= 1070) { + ucLoDiv1 = 3; + ucLomod1 = 16; + ucLoDiv2 = 3; + ucLomod2 = 16; + } else if (tuner_freq_MHz >= 1000) { + ucLoDiv1 = 3; + ucLomod1 = 16; + ucLoDiv2 = 4; + ucLomod2 = 64; + } else if (tuner_freq_MHz >= 775) { + ucLoDiv1 = 4; + ucLomod1 = 64; + ucLoDiv2 = 4; + ucLomod2 = 64; + } else if (tuner_freq_MHz >= 700) { + ucLoDiv1 = 6; + ucLomod1 = 48; + ucLoDiv2 = 4; + ucLomod2 = 64; + } else if (tuner_freq_MHz >= 520) { + ucLoDiv1 = 6; + ucLomod1 = 48; + ucLoDiv2 = 6; + ucLomod2 = 48; + } else { + ucLoDiv1 = 8; + ucLomod1 = 96; + ucLoDiv2 = 8; + ucLomod2 = 96; + } + + ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv + / fcry_KHz - 1024) / 2; + ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv + / fcry_KHz - 1024) / 2; + + reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F; + ret = regmap_write(dev->regmap, 0x27, reg27); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF)); + if (ret) + goto err; + reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f; + ret = regmap_write(dev->regmap, 0x29, reg29); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF)); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x2F, 0xf5); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x30, 0x05); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x08, 0x1f); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x08, 0x3f); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x09, 0x20); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x09, 0x00); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x3e, 0x11); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x08, 0x2f); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x08, 0x3f); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x09, 0x10); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x09, 0x00); + if (ret) + goto err; + usleep_range(2000, 50000); + + ret = regmap_read(dev->regmap, 0x42, &utmp); + if (ret) + goto err; + reg42 = utmp; + + ret = regmap_write(dev->regmap, 0x3e, 0x10); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x08, 0x2f); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x08, 0x3f); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x09, 0x10); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x09, 0x00); + if (ret) + goto err; + usleep_range(2000, 50000); + + ret = regmap_read(dev->regmap, 0x42, &utmp); + if (ret) + goto err; + reg42buf = utmp; + if (reg42buf < reg42) { + ret = regmap_write(dev->regmap, 0x3e, 0x11); + if (ret) + goto err; + } + usleep_range(5000, 50000); + + ret = regmap_read(dev->regmap, 0x2d, &utmp); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x2d, utmp); + if (ret) + goto err; + ret = regmap_read(dev->regmap, 0x2e, &utmp); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x2e, utmp); + if (ret) + goto err; + + ret = regmap_read(dev->regmap, 0x27, &utmp); + if (ret) + goto err; + reg27 = utmp & 0x70; + ret = regmap_read(dev->regmap, 0x83, &utmp); + if (ret) + goto err; + if (reg27 == (utmp & 0x70)) { + ucLoDiv = ucLoDiv1; + ulNDiv = ulNDiv1; + ucLomod = ucLomod1 / 16; + } else { + ucLoDiv = ucLoDiv2; + ulNDiv = ulNDiv2; + ucLomod = ucLomod2 / 16; + } + + if ((ucLoDiv == 3) || (ucLoDiv == 6)) { + refDiv = 18; + ret = regmap_write(dev->regmap, 0x36, (refDiv - 8)); + if (ret) + goto err; + ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv + / fcry_KHz - 1024) / 2; + } + + reg27 = (0x80 + ((ucLomod << 4) & 0x70) + + ((ulNDiv >> 8) & 0x0F)) & 0xFF; + ret = regmap_write(dev->regmap, 0x27, reg27); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF)); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x29, 0x80); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x31, 0x03); + if (ret) + goto err; + + if (ucLoDiv == 3) + utmp = 0xCE; + else + utmp = 0x8A; + ret = regmap_write(dev->regmap, 0x3b, utmp); + if (ret) + goto err; + + dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv; + + dev_dbg(&dev->client->dev, + "actual tune frequency=%d\n", dev->frequency_khz); +err: + if (ret) + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + return ret; +} + +static int m88rs6000t_set_bb(struct m88rs6000t_dev *dev, + u32 symbol_rate_KSs, s32 lpf_offset_KHz) +{ + u32 f3dB; + u8 reg40; + + f3dB = symbol_rate_KSs * 9 / 14 + 2000; + f3dB += lpf_offset_KHz; + f3dB = clamp_val(f3dB, 6000U, 43000U); + reg40 = f3dB / 1000; + return regmap_write(dev->regmap, 0x40, reg40); +} + +static int m88rs6000t_set_params(struct dvb_frontend *fe) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + s32 lpf_offset_KHz; + u32 realFreq, freq_MHz; + + dev_dbg(&dev->client->dev, + "frequency=%d symbol_rate=%d\n", + c->frequency, c->symbol_rate); + + if (c->symbol_rate < 5000000) + lpf_offset_KHz = 3000; + else + lpf_offset_KHz = 0; + + realFreq = c->frequency + lpf_offset_KHz; + /* set tuner pll.*/ + freq_MHz = (realFreq + 500) / 1000; + ret = m88rs6000t_set_pll_freq(dev, freq_MHz); + if (ret) + goto err; + ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x00, 0x01); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x00, 0x00); + if (ret) + goto err; + /* set demod mlck */ + ret = m88rs6000t_set_demod_mclk(fe); +err: + if (ret) + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + return ret; +} + +static int m88rs6000t_init(struct dvb_frontend *fe) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + int ret; + + dev_dbg(&dev->client->dev, "%s:\n", __func__); + + ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08); + if (ret) + goto err; + usleep_range(5000, 50000); + ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01); + if (ret) + goto err; + usleep_range(10000, 50000); + ret = regmap_write(dev->regmap, 0x07, 0x7d); +err: + if (ret) + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + return ret; +} + +static int m88rs6000t_sleep(struct dvb_frontend *fe) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + int ret; + + dev_dbg(&dev->client->dev, "%s:\n", __func__); + + ret = regmap_write(dev->regmap, 0x07, 0x6d); + if (ret) + goto err; + usleep_range(5000, 10000); +err: + if (ret) + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + return ret; +} + +static int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + + dev_dbg(&dev->client->dev, "\n"); + + *frequency = dev->frequency_khz; + return 0; +} + +static int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + + dev_dbg(&dev->client->dev, "\n"); + + *frequency = 0; /* Zero-IF */ + return 0; +} + + +static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct m88rs6000t_dev *dev = fe->tuner_priv; + unsigned int val, i; + int ret; + u16 gain; + u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290; + u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300; + u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0; + u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0; + u32 RFGS[13] = {0, 245, 266, 268, 270, 285, + 298, 295, 283, 285, 285, 300, 300}; + u32 IFGS[12] = {0, 300, 230, 270, 270, 285, + 295, 285, 290, 295, 295, 310}; + u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290, + 290, 285, 283, 260, 295, 290, 260}; + + ret = regmap_read(dev->regmap, 0x5A, &val); + if (ret) + goto err; + RF_GC = val & 0x0f; + + ret = regmap_read(dev->regmap, 0x5F, &val); + if (ret) + goto err; + IF_GC = val & 0x0f; + + ret = regmap_read(dev->regmap, 0x3F, &val); + if (ret) + goto err; + TIA_GC = (val >> 4) & 0x07; + + ret = regmap_read(dev->regmap, 0x77, &val); + if (ret) + goto err; + BB_GC = (val >> 4) & 0x0f; + + ret = regmap_read(dev->regmap, 0x76, &val); + if (ret) + goto err; + PGA2_GC = val & 0x3f; + PGA2_cri = PGA2_GC >> 2; + PGA2_crf = PGA2_GC & 0x03; + + for (i = 0; i <= RF_GC; i++) + RFG += RFGS[i]; + + if (RF_GC == 0) + RFG += 400; + if (RF_GC == 1) + RFG += 300; + if (RF_GC == 2) + RFG += 200; + if (RF_GC == 3) + RFG += 100; + + for (i = 0; i <= IF_GC; i++) + IFG += IFGS[i]; + + TIAG = TIA_GC * TIA_GS; + + for (i = 0; i <= BB_GC; i++) + BBG += BBGS[i]; + + PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS; + + gain = RFG + IFG - TIAG + BBG + PGA2G; + + /* scale value to 0x0000-0xffff */ + gain = clamp_val(gain, 1000U, 10500U); + *strength = (10500 - gain) * 0xffff / (10500 - 1000); +err: + if (ret) + dev_dbg(&dev->client->dev, "failed=%d\n", ret); + return ret; +} + +static const struct dvb_tuner_ops m88rs6000t_tuner_ops = { + .info = { + .name = "Montage M88RS6000 Internal Tuner", + .frequency_min = 950000, + .frequency_max = 2150000, + }, + + .init = m88rs6000t_init, + .sleep = m88rs6000t_sleep, + .set_params = m88rs6000t_set_params, + .get_frequency = m88rs6000t_get_frequency, + .get_if_frequency = m88rs6000t_get_if_frequency, + .get_rf_strength = m88rs6000t_get_rf_strength, +}; + +static int m88rs6000t_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct m88rs6000t_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct m88rs6000t_dev *dev; + int ret, i; + unsigned int utmp; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + static const struct m88rs6000t_reg_val reg_vals[] = { + {0x10, 0xfb}, + {0x24, 0x38}, + {0x11, 0x0a}, + {0x12, 0x00}, + {0x2b, 0x1c}, + {0x44, 0x48}, + {0x54, 0x24}, + {0x55, 0x06}, + {0x59, 0x00}, + {0x5b, 0x4c}, + {0x60, 0x8b}, + {0x61, 0xf4}, + {0x65, 0x07}, + {0x6d, 0x6f}, + {0x6e, 0x31}, + {0x3c, 0xf3}, + {0x37, 0x0f}, + {0x48, 0x28}, + {0x49, 0xd8}, + {0x70, 0x66}, + {0x71, 0xCF}, + {0x72, 0x81}, + {0x73, 0xA7}, + {0x74, 0x4F}, + {0x75, 0xFC}, + }; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; + } + + memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config)); + dev->client = client; + dev->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err; + } + + ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08); + if (ret) + goto err; + usleep_range(5000, 50000); + ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01); + if (ret) + goto err; + usleep_range(10000, 50000); + ret = regmap_write(dev->regmap, 0x07, 0x7d); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x04, 0x01); + if (ret) + goto err; + + /* check tuner chip id */ + ret = regmap_read(dev->regmap, 0x01, &utmp); + if (ret) + goto err; + dev_info(&dev->client->dev, "chip_id=%02x\n", utmp); + if (utmp != 0x64) { + ret = -ENODEV; + goto err; + } + + /* tuner init. */ + ret = regmap_write(dev->regmap, 0x05, 0x40); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x11, 0x08); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x15, 0x6c); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x17, 0xc1); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x17, 0x81); + if (ret) + goto err; + usleep_range(10000, 50000); + ret = regmap_write(dev->regmap, 0x05, 0x00); + if (ret) + goto err; + ret = regmap_write(dev->regmap, 0x11, 0x0a); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { + ret = regmap_write(dev->regmap, + reg_vals[i].reg, reg_vals[i].val); + if (ret) + goto err; + } + + dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n"); + + fe->tuner_priv = dev; + memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops, + sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, dev); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + kfree(dev); + return ret; +} + +static int m88rs6000t_remove(struct i2c_client *client) +{ + struct m88rs6000t_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->cfg.fe; + + dev_dbg(&client->dev, "\n"); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; + kfree(dev); + + return 0; +} + +static const struct i2c_device_id m88rs6000t_id[] = { + {"m88rs6000t", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, m88rs6000t_id); + +static struct i2c_driver m88rs6000t_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "m88rs6000t", + }, + .probe = m88rs6000t_probe, + .remove = m88rs6000t_remove, + .id_table = m88rs6000t_id, +}; + +module_i2c_driver(m88rs6000t_driver); + +MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); +MODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/m88rs6000t.h b/drivers/media/tuners/m88rs6000t.h new file mode 100644 index 000000000000..264c13e2cd39 --- /dev/null +++ b/drivers/media/tuners/m88rs6000t.h @@ -0,0 +1,29 @@ +/* + * Driver for the internal tuner of Montage M88RS6000 + * + * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> + * + * 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. + */ + +#ifndef _M88RS6000T_H_ +#define _M88RS6000T_H_ + +#include "dvb_frontend.h" + +struct m88rs6000t_config { + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; +}; + +#endif diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index caa542346891..066e5431da93 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -488,6 +488,7 @@ static int m88ts2022_probe(struct i2c_client *client, case 0x83: break; default: + ret = -ENODEV; goto err; } @@ -505,6 +506,7 @@ static int m88ts2022_probe(struct i2c_client *client, u8tmp = 0x6c; break; default: + ret = -EINVAL; goto err; } diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 0e74e97e0d1a..9e031040c13f 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c @@ -660,11 +660,3 @@ EXPORT_SYMBOL_GPL(microtune_attach); MODULE_DESCRIPTION("Microtune tuner driver"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c index f83b0c1ea6c8..6e2cdd2b6175 100644 --- a/drivers/media/tuners/mt2131.c +++ b/drivers/media/tuners/mt2131.c @@ -294,8 +294,3 @@ EXPORT_SYMBOL(mt2131_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h index 09ceaf68e47c..837c854b9c65 100644 --- a/drivers/media/tuners/mt2131.h +++ b/drivers/media/tuners/mt2131.h @@ -47,8 +47,3 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, #endif /* CONFIG_MEDIA_TUNER_MT2131 */ #endif /* __MT2131_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h index 62aeedf5c550..91283b599cb3 100644 --- a/drivers/media/tuners/mt2131_priv.h +++ b/drivers/media/tuners/mt2131_priv.h @@ -41,8 +41,3 @@ struct mt2131_priv { }; #endif /* __MT2131_PRIV_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c index 69e453ef0a1a..f4ae04c3328a 100644 --- a/drivers/media/tuners/mxl5007t.c +++ b/drivers/media/tuners/mxl5007t.c @@ -374,7 +374,6 @@ static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); - set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); @@ -531,10 +530,6 @@ static int mxl5007t_tuner_init(struct mxl5007t_state *state, struct reg_pair_t *init_regs; int ret; - ret = mxl5007t_soft_reset(state); - if (mxl_fail(ret)) - goto fail; - /* calculate initialization reg array */ init_regs = mxl5007t_calc_init_regs(state, mode); @@ -900,7 +895,32 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, /* existing tuner instance */ break; } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_soft_reset(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (mxl_fail(ret)) + goto fail; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_write_reg(state, 0x04, + state->config->loop_thru_enable); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (mxl_fail(ret)) + goto fail; + fe->tuner_priv = state; + mutex_unlock(&mxl5007t_list_mutex); memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, @@ -918,11 +938,3 @@ MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.2"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h index 37b0942e2385..ae7037d681c5 100644 --- a/drivers/media/tuners/mxl5007t.h +++ b/drivers/media/tuners/mxl5007t.h @@ -93,12 +93,3 @@ static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, #endif #endif /* __MXL5007T_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index a759742cae7b..8e040cf9cf13 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -959,6 +959,18 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, lt_att = 0x00; /* r31[7], lt att enable */ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ polyfil_cur = 0x60; /* r25[6:5]:min */ + } else if (delsys == SYS_DVBC_ANNEX_A) { + if_khz = 5070; + filt_cal_lo = 73500; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */ + ext_enable = 0x40; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ } else { if (bw <= 6) { if_khz = 3570; diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index cf97142e01e6..fcf139dfdec6 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2147/2157/2158 silicon tuner driver + * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> * @@ -19,16 +19,17 @@ static const struct dvb_tuner_ops si2157_ops; /* execute firmware command */ -static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) +static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd) { + struct si2157_dev *dev = i2c_get_clientdata(client); int ret; unsigned long timeout; - mutex_lock(&s->i2c_mutex); + mutex_lock(&dev->i2c_mutex); if (cmd->wlen) { /* write cmd and args for firmware */ - ret = i2c_master_send(s->client, cmd->args, cmd->wlen); + ret = i2c_master_send(client, cmd->args, cmd->wlen); if (ret < 0) { goto err_mutex_unlock; } else if (ret != cmd->wlen) { @@ -42,7 +43,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) #define TIMEOUT 80 timeout = jiffies + msecs_to_jiffies(TIMEOUT); while (!time_after(jiffies, timeout)) { - ret = i2c_master_recv(s->client, cmd->args, cmd->rlen); + ret = i2c_master_recv(client, cmd->args, cmd->rlen); if (ret < 0) { goto err_mutex_unlock; } else if (ret != cmd->rlen) { @@ -55,7 +56,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) break; } - dev_dbg(&s->client->dev, "cmd execution took %d ms\n", + dev_dbg(&client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -65,38 +66,40 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) } } - ret = 0; + mutex_unlock(&dev->i2c_mutex); + return 0; err_mutex_unlock: - mutex_unlock(&s->i2c_mutex); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + mutex_unlock(&dev->i2c_mutex); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2157_init(struct dvb_frontend *fe) { - struct si2157 *s = fe->tuner_priv; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); int ret, len, remaining; struct si2157_cmd cmd; - const struct firmware *fw = NULL; - u8 *fw_file; + const struct firmware *fw; + const char *fw_name; unsigned int chip_id; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); - if (s->fw_loaded) + if (dev->fw_loaded) goto warm; /* power up */ - memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); - cmd.wlen = 15; + if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { + memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); + cmd.wlen = 9; + } else { + memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); + cmd.wlen = 15; + } cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; @@ -104,7 +107,7 @@ static int si2157_init(struct dvb_frontend *fe) memcpy(cmd.args, "\x02", 1); cmd.wlen = 1; cmd.rlen = 13; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; @@ -112,127 +115,141 @@ static int si2157_init(struct dvb_frontend *fe) cmd.args[4] << 0; #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) + #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0) #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) + #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) switch (chip_id) { case SI2158_A20: - fw_file = SI2158_A20_FIRMWARE; + case SI2148_A20: + fw_name = SI2158_A20_FIRMWARE; break; case SI2157_A30: case SI2147_A30: - goto skip_fw_download; + case SI2146_A10: + fw_name = NULL; break; default: - dev_err(&s->client->dev, - "unknown chip version Si21%d-%c%c%c\n", + dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); ret = -EINVAL; goto err; } - /* cold state - try to download firmware */ - dev_info(&s->client->dev, "found a '%s' in cold state\n", - si2157_ops.info.name); + dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n", + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); + + if (fw_name == NULL) + goto skip_fw_download; /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &s->client->dev); + ret = request_firmware(&fw, fw_name, &client->dev); if (ret) { - dev_err(&s->client->dev, "firmware file '%s' not found\n", - fw_file); + dev_err(&client->dev, "firmware file '%s' not found\n", + fw_name); goto err; } /* firmware should be n chunks of 17 bytes */ if (fw->size % 17 != 0) { - dev_err(&s->client->dev, "firmware file '%s' is invalid\n", - fw_file); + dev_err(&client->dev, "firmware file '%s' is invalid\n", + fw_name); ret = -EINVAL; - goto err; + goto err_release_firmware; } - dev_info(&s->client->dev, "downloading firmware from file '%s'\n", - fw_file); + dev_info(&client->dev, "downloading firmware from file '%s'\n", + fw_name); for (remaining = fw->size; remaining > 0; remaining -= 17) { len = fw->data[fw->size - remaining]; memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); cmd.wlen = len; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) { - dev_err(&s->client->dev, - "firmware download failed=%d\n", + dev_err(&client->dev, "firmware download failed %d\n", ret); - goto err; + goto err_release_firmware; } } release_firmware(fw); - fw = NULL; skip_fw_download: /* reboot the tuner with new firmware? */ memcpy(cmd.args, "\x01\x01", 2); cmd.wlen = 2; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + /* query firmware version */ + memcpy(cmd.args, "\x11", 1); + cmd.wlen = 1; + cmd.rlen = 10; + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; - s->fw_loaded = true; + dev_info(&client->dev, "firmware version: %c.%c.%d\n", + cmd.args[6], cmd.args[7], cmd.args[8]); + + dev->fw_loaded = true; warm: - s->active = true; + dev->active = true; return 0; +err_release_firmware: + release_firmware(fw); err: - if (fw) - release_firmware(fw); - - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2157_sleep(struct dvb_frontend *fe) { - struct si2157 *s = fe->tuner_priv; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); int ret; struct si2157_cmd cmd; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); - s->active = false; + dev->active = false; /* standby */ memcpy(cmd.args, "\x16\x00", 2); cmd.wlen = 2; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2157_set_params(struct dvb_frontend *fe) { - struct si2157 *s = fe->tuner_priv; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; struct si2157_cmd cmd; u8 bandwidth, delivery_system; - dev_dbg(&s->client->dev, + dev_dbg(&client->dev, "delivery_system=%d frequency=%u bandwidth_hz=%u\n", - c->delivery_system, c->frequency, - c->bandwidth_hz); + c->delivery_system, c->frequency, c->bandwidth_hz); - if (!s->active) { + if (!dev->active) { ret = -EAGAIN; goto err; } @@ -250,6 +267,9 @@ static int si2157_set_params(struct dvb_frontend *fe) case SYS_ATSC: delivery_system = 0x00; break; + case SYS_DVBC_ANNEX_B: + delivery_system = 0x10; + break; case SYS_DVBT: case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */ delivery_system = 0x20; @@ -264,18 +284,21 @@ static int si2157_set_params(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6); cmd.args[4] = delivery_system | bandwidth; - if (s->inversion) + if (dev->inversion) cmd.args[5] = 0x01; cmd.wlen = 6; cmd.rlen = 4; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6); + if (dev->chiptype == SI2157_CHIPTYPE_SI2146) + memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6); + else + memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; @@ -287,13 +310,13 @@ static int si2157_set_params(struct dvb_frontend *fe) cmd.args[7] = (c->frequency >> 24) & 0xff; cmd.wlen = 8; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -305,7 +328,7 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) static const struct dvb_tuner_ops si2157_ops = { .info = { - .name = "Silicon Labs Si2157/Si2158", + .name = "Silicon Labs Si2146/2147/2148/2157/2158", .frequency_min = 110000000, .frequency_max = 862000000, }, @@ -321,65 +344,67 @@ static int si2157_probe(struct i2c_client *client, { struct si2157_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct si2157 *s; + struct si2157_dev *dev; struct si2157_cmd cmd; int ret; - s = kzalloc(sizeof(struct si2157), GFP_KERNEL); - if (!s) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - s->client = client; - s->fe = cfg->fe; - s->inversion = cfg->inversion; - s->fw_loaded = false; - mutex_init(&s->i2c_mutex); + i2c_set_clientdata(client, dev); + dev->fe = cfg->fe; + dev->inversion = cfg->inversion; + dev->fw_loaded = false; + dev->chiptype = (u8)id->driver_data; + mutex_init(&dev->i2c_mutex); /* check if the tuner is there */ cmd.wlen = 0; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) - goto err; + goto err_kfree; - fe->tuner_priv = s; - memcpy(&fe->ops.tuner_ops, &si2157_ops, - sizeof(struct dvb_tuner_ops)); + memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = client; - i2c_set_clientdata(client, s); + dev_info(&client->dev, "Silicon Labs %s successfully attached\n", + dev->chiptype == SI2157_CHIPTYPE_SI2146 ? + "Si2146" : "Si2147/2148/2157/2158"); - dev_info(&s->client->dev, - "Silicon Labs Si2157/Si2158 successfully attached\n"); return 0; + +err_kfree: + kfree(dev); err: dev_dbg(&client->dev, "failed=%d\n", ret); - kfree(s); - return ret; } static int si2157_remove(struct i2c_client *client) { - struct si2157 *s = i2c_get_clientdata(client); - struct dvb_frontend *fe = s->fe; + struct si2157_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->fe; dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; - kfree(s); + kfree(dev); return 0; } -static const struct i2c_device_id si2157_id[] = { - {"si2157", 0}, +static const struct i2c_device_id si2157_id_table[] = { + {"si2157", SI2157_CHIPTYPE_SI2157}, + {"si2146", SI2157_CHIPTYPE_SI2146}, {} }; -MODULE_DEVICE_TABLE(i2c, si2157_id); +MODULE_DEVICE_TABLE(i2c, si2157_id_table); static struct i2c_driver si2157_driver = { .driver = { @@ -388,12 +413,12 @@ static struct i2c_driver si2157_driver = { }, .probe = si2157_probe, .remove = si2157_remove, - .id_table = si2157_id, + .id_table = si2157_id_table, }; module_i2c_driver(si2157_driver); -MODULE_DESCRIPTION("Silicon Labs Si2157/Si2158 silicon tuner driver"); +MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index d3b19cadb4a1..a564c4a9fba7 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2147/2157/2158 silicon tuner driver + * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> * diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index e71ffafed951..7aa53bce5593 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2147/2157/2158 silicon tuner driver + * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> * @@ -21,16 +21,19 @@ #include "si2157.h" /* state struct */ -struct si2157 { +struct si2157_dev { struct mutex i2c_mutex; - struct i2c_client *client; struct dvb_frontend *fe; bool active; bool fw_loaded; bool inversion; + u8 chiptype; }; -/* firmare command struct */ +#define SI2157_CHIPTYPE_SI2157 0 +#define SI2157_CHIPTYPE_SI2146 1 + +/* firmware command struct */ #define SI2157_ARGLEN 30 struct si2157_cmd { u8 args[SI2157_ARGLEN]; diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 86e5e3110118..a26bb33102b8 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -178,7 +178,7 @@ int tda18271_read_extended(struct dvb_frontend *fe) (i != R_EB17) && (i != R_EB19) && (i != R_EB20)) - regs[i] = regdump[i]; + regs[i] = regdump[i]; } if (tda18271_debug & DBG_REG) diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index 4995b890c164..f8620741bb5f 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -1355,11 +1355,3 @@ MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.4"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c index b62e925f643f..1e89dd93c4bb 100644 --- a/drivers/media/tuners/tda18271-maps.c +++ b/drivers/media/tuners/tda18271-maps.c @@ -1305,11 +1305,3 @@ int tda18271_assign_map_layout(struct dvb_frontend *fe) return ret; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h index b36a7b754772..cc80f544af34 100644 --- a/drivers/media/tuners/tda18271-priv.h +++ b/drivers/media/tuners/tda18271-priv.h @@ -226,11 +226,3 @@ extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); #endif /* __TDA18271_PRIV_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index 73453a255cdc..edcb4a723aa1 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c @@ -907,11 +907,3 @@ MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index ab4106c17b4c..998e82bba9c0 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -881,11 +881,3 @@ EXPORT_SYMBOL_GPL(tda829x_probe); MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c index 9823248d743f..56be6c29399b 100644 --- a/drivers/media/tuners/tda9887.c +++ b/drivers/media/tuners/tda9887.c @@ -707,11 +707,3 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, EXPORT_SYMBOL_GPL(tda9887_attach); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index ca274c2d8c70..8e9ce144da9a 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -1148,11 +1148,3 @@ EXPORT_SYMBOL_GPL(simple_tuner_attach); MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 803a0e63d47e..2a039de8ab9a 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -62,6 +62,7 @@ struct xc5000_priv { unsigned int mode; u8 rf_mode; u8 radio_input; + u16 output_amp; int chip_id; u16 pll_register_no; @@ -744,7 +745,9 @@ static int xc5000_tune_digital(struct dvb_frontend *fe) return -EIO; } - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + dprintk(1, "%s() setting OUTPUT_AMP to 0x%x\n", + __func__, priv->output_amp); + xc_write_reg(priv, XREG_OUTPUT_AMP, priv->output_amp); xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); @@ -1333,8 +1336,7 @@ static int xc5000_release(struct dvb_frontend *fe) if (priv) { cancel_delayed_work(&priv->timer_sleep); - if (priv->firmware) - release_firmware(priv->firmware); + release_firmware(priv->firmware); hybrid_tuner_release_state(priv); } @@ -1358,6 +1360,9 @@ static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) if (p->radio_input) priv->radio_input = p->radio_input; + if (p->output_amp) + priv->output_amp = p->output_amp; + return 0; } @@ -1438,6 +1443,12 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, it can be overridden if this is a hybrid driver */ priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; + /* don't override output_amp if it's already been set + unless explicitly specified */ + if ((priv->output_amp == 0) || (cfg->output_amp)) + /* use default output_amp value if none specified */ + priv->output_amp = (cfg->output_amp) ? cfg->output_amp : 0x8a; + /* Check if firmware has been loaded. It is possible that another instance of the driver has loaded the firmware. */ diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h index 7245cae19f0c..6aa534f17a30 100644 --- a/drivers/media/tuners/xc5000.h +++ b/drivers/media/tuners/xc5000.h @@ -36,6 +36,7 @@ struct xc5000_config { u32 if_khz; u8 radio_input; u16 xtal_khz; + u16 output_amp; int chip_id; }; |