diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-10-09 21:00:54 +0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-10-09 21:00:54 +0400 |
commit | a66d05d504a24894a8fdf11e4569752f313e5764 (patch) | |
tree | 2bb40c1f6c301b231d7aeaad08c190aa5a82ba1f /drivers/media/tuners | |
parent | bfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (diff) | |
parent | 5563caaf8b8cd22e35997d5d74cb3609df86b223 (diff) | |
download | linux-a66d05d504a24894a8fdf11e4569752f313e5764.tar.xz |
Merge branch 'patchwork' into v4l_for_linus
* patchwork: (544 commits)
[media] ir-hix5hd2: fix build on c6x arch
[media] pt3: fix DTV FE I2C driver load error paths
Revert "[media] media: em28xx - remove reset_resume interface"
[media] exynos4-is: fix some warnings when compiling on arm64
[media] usb drivers: use %zu instead of %zd
[media] pci drivers: use %zu instead of %zd
[media] dvb-frontends: use %zu instead of %zd
[media] s5p-mfc: Fix several printk warnings
[media] s5p_mfc_opr: Fix warnings
[media] ti-vpe: Fix typecast
[media] s3c-camif: fix dma_addr_t printks
[media] s5p_mfc_opr_v6: get rid of warnings when compiled with 64 bits
[media] s5p_mfc_opr_v5: Fix lots of warnings on x86_64
[media] em28xx: Fix identation
[media] drxd: remove a dead code
[media] saa7146: remove return after BUG()
[media] cx88: remove return after BUG()
[media] cx88: fix cards table CodingStyle
[media] radio-sf16fmr2: declare some structs as static
[media] radio-sf16fmi: declare pnp_attached as static
...
Conflicts:
Documentation/DocBook/media/v4l/compat.xml
Diffstat (limited to 'drivers/media/tuners')
27 files changed, 1997 insertions, 1228 deletions
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index d79fd1ce5a18..f039dc2a21cf 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -204,6 +204,7 @@ config MEDIA_TUNER_FC0013 config MEDIA_TUNER_TDA18212 tristate "NXP TDA18212 silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help NXP TDA18212 silicon tuner driver. @@ -226,6 +227,7 @@ config MEDIA_TUNER_FC2580 config MEDIA_TUNER_M88TS2022 tristate "Montage M88TS2022 silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Montage M88TS2022 silicon tuner driver. @@ -247,6 +249,7 @@ config MEDIA_TUNER_SI2157 config MEDIA_TUNER_IT913X tristate "ITE Tech IT913x silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help ITE Tech IT913x silicon tuner driver. @@ -257,4 +260,18 @@ config MEDIA_TUNER_R820T default m if !MEDIA_SUBDRV_AUTOSELECT help Rafael Micro R820T silicon tuner driver. + +config MEDIA_TUNER_MXL301RF + tristate "MaxLinear MxL301RF tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + MaxLinear MxL301RF OFDM tuner driver. + +config MEDIA_TUNER_QM1D1C0042 + tristate "Sharp QM1D1C0042 tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Sharp QM1D1C0042 trellis coded 8PSK tuner driver. endmenu diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 5591699755ba..49fcf8033848 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -37,8 +37,10 @@ obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o -obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o +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 ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 90d93348f20c..510239f80c0d 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -26,7 +26,7 @@ static int e4000_init(struct dvb_frontend *fe) struct e4000 *s = fe->tuner_priv; int ret; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); /* dummy I2C to ensure I2C wakes up */ ret = regmap_write(s->regmap, 0x02, 0x40); @@ -87,7 +87,7 @@ static int e4000_init(struct dvb_frontend *fe) s->active = true; err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -97,7 +97,7 @@ static int e4000_sleep(struct dvb_frontend *fe) struct e4000 *s = fe->tuner_priv; int ret; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); s->active = false; @@ -106,7 +106,7 @@ static int e4000_sleep(struct dvb_frontend *fe) goto err; err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -121,9 +121,8 @@ static int e4000_set_params(struct dvb_frontend *fe) u8 buf[5], i_data[4], q_data[4]; dev_dbg(&s->client->dev, - "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", - __func__, c->delivery_system, c->frequency, - c->bandwidth_hz); + "delivery_system=%d frequency=%u bandwidth_hz=%u\n", + c->delivery_system, c->frequency, c->bandwidth_hz); /* gain control manual */ ret = regmap_write(s->regmap, 0x1a, 0x00); @@ -150,9 +149,8 @@ static int e4000_set_params(struct dvb_frontend *fe) buf[3] = 0x00; buf[4] = e4000_pll_lut[i].div; - dev_dbg(&s->client->dev, - "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n", - __func__, f_vco, buf[0], sigma_delta); + dev_dbg(&s->client->dev, "f_vco=%llu pll div=%d sigma_delta=%04x\n", + f_vco, buf[0], sigma_delta); ret = regmap_bulk_write(s->regmap, 0x09, buf, 5); if (ret) @@ -253,7 +251,7 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -262,7 +260,7 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { struct e4000 *s = fe->tuner_priv; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); *frequency = 0; /* Zero-IF */ @@ -276,10 +274,9 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) int ret; u8 u8tmp; - dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n", - __func__, s->lna_gain_auto->cur.val, - s->lna_gain_auto->val, s->lna_gain->cur.val, - s->lna_gain->val); + dev_dbg(&s->client->dev, "lna auto=%d->%d val=%d->%d\n", + s->lna_gain_auto->cur.val, s->lna_gain_auto->val, + s->lna_gain->cur.val, s->lna_gain->val); if (s->lna_gain_auto->val && s->if_gain_auto->cur.val) u8tmp = 0x17; @@ -301,7 +298,7 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -312,10 +309,9 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) int ret; u8 u8tmp; - dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n", - __func__, s->mixer_gain_auto->cur.val, - s->mixer_gain_auto->val, s->mixer_gain->cur.val, - s->mixer_gain->val); + dev_dbg(&s->client->dev, "mixer auto=%d->%d val=%d->%d\n", + s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val, + s->mixer_gain->cur.val, s->mixer_gain->val); if (s->mixer_gain_auto->val) u8tmp = 0x15; @@ -333,7 +329,7 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -345,10 +341,9 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) u8 buf[2]; u8 u8tmp; - dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n", - __func__, s->if_gain_auto->cur.val, - s->if_gain_auto->val, s->if_gain->cur.val, - s->if_gain->val); + dev_dbg(&s->client->dev, "if auto=%d->%d val=%d->%d\n", + s->if_gain_auto->cur.val, s->if_gain_auto->val, + s->if_gain->cur.val, s->if_gain->val); if (s->if_gain_auto->val && s->lna_gain_auto->cur.val) u8tmp = 0x17; @@ -372,7 +367,7 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -390,7 +385,7 @@ static int e4000_pll_lock(struct dvb_frontend *fe) s->pll_lock->val = (utmp & 0x01); err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -400,7 +395,7 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl); int ret; - if (s->active == false) + if (!s->active) return 0; switch (ctrl->id) { @@ -408,8 +403,8 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ret = e4000_pll_lock(s->fe); break; default: - dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n", - __func__, ctrl->id, ctrl->name); + dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -423,7 +418,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - if (s->active == false) + if (!s->active) return 0; switch (ctrl->id) { @@ -445,8 +440,8 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) ret = e4000_set_if_gain(s->fe); break; default: - dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n", - __func__, ctrl->id, ctrl->name); + dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -494,7 +489,7 @@ static int e4000_probe(struct i2c_client *client, s = kzalloc(sizeof(struct e4000), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -512,7 +507,7 @@ static int e4000_probe(struct i2c_client *client, if (ret) goto err; - dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp); + dev_dbg(&s->client->dev, "chip id=%02x\n", utmp); if (utmp != 0x40) { ret = -ENODEV; @@ -559,9 +554,7 @@ static int e4000_probe(struct i2c_client *client, s->sd.ctrl_handler = &s->hdl; #endif - dev_info(&s->client->dev, - "%s: Elonics E4000 successfully identified\n", - KBUILD_MODNAME); + dev_info(&s->client->dev, "Elonics E4000 successfully identified\n"); fe->tuner_priv = s; memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops, @@ -573,7 +566,7 @@ static int e4000_probe(struct i2c_client *client, return 0; err: if (ret) { - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); kfree(s); } @@ -586,7 +579,7 @@ static int e4000_remove(struct i2c_client *client) struct e4000 *s = container_of(sd, struct e4000, sd); struct dvb_frontend *fe = s->fe; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); #if IS_ENABLED(CONFIG_VIDEO_V4L2) v4l2_ctrl_handler_free(&s->hdl); diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c new file mode 100644 index 000000000000..a076c87eda7a --- /dev/null +++ b/drivers/media/tuners/it913x.c @@ -0,0 +1,478 @@ +/* + * ITE IT913X silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * 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 "it913x.h" +#include <linux/regmap.h> + +struct it913x_dev { + struct i2c_client *client; + struct regmap *regmap; + struct dvb_frontend *fe; + u8 chip_ver:2; + u8 role:2; + u16 xtal; + u8 fdiv; + u8 clk_mode; + u32 fn_min; + bool active; +}; + +static int it913x_init(struct dvb_frontend *fe) +{ + struct it913x_dev *dev = fe->tuner_priv; + int ret; + unsigned int utmp; + u8 iqik_m_cal, nv_val, buf[2]; + static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; + unsigned long timeout; + + dev_dbg(&dev->client->dev, "role %u\n", dev->role); + + ret = regmap_write(dev->regmap, 0x80ec4c, 0x68); + if (ret) + goto err; + + usleep_range(10000, 100000); + + ret = regmap_read(dev->regmap, 0x80ec86, &utmp); + if (ret) + goto err; + + switch (utmp) { + case 0: + /* 12.000 MHz */ + dev->clk_mode = utmp; + dev->xtal = 2000; + dev->fdiv = 3; + iqik_m_cal = 16; + break; + case 1: + /* 20.480 MHz */ + dev->clk_mode = utmp; + dev->xtal = 640; + dev->fdiv = 1; + iqik_m_cal = 6; + break; + default: + dev_err(&dev->client->dev, "unknown clock identifier %d\n", utmp); + goto err; + } + + ret = regmap_read(dev->regmap, 0x80ed03, &utmp); + if (ret) + goto err; + + else if (utmp < ARRAY_SIZE(nv)) + nv_val = nv[utmp]; + else + nv_val = 2; + + #define TIMEOUT 50 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2); + if (ret) + goto err; + + utmp = (buf[1] << 8) | (buf[0] << 0); + if (utmp) + break; + } + + dev_dbg(&dev->client->dev, "r_fbc_m_bdry took %u ms, val %u\n", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - TIMEOUT), utmp); + + dev->fn_min = dev->xtal * utmp; + dev->fn_min /= (dev->fdiv * nv_val); + dev->fn_min *= 1000; + dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min); + + /* + * Chip version BX never sets that flag so we just wait 50ms in that + * case. It is possible poll BX similarly than AX and then timeout in + * order to get 50ms delay, but that causes about 120 extra I2C + * messages. As for now, we just wait and reduce IO. + */ + if (dev->chip_ver == 1) { + #define TIMEOUT 50 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { + ret = regmap_read(dev->regmap, 0x80ec82, &utmp); + if (ret) + goto err; + + if (utmp) + break; + } + + dev_dbg(&dev->client->dev, "p_tsm_init_mode took %u ms, val %u\n", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - TIMEOUT), utmp); + } else { + msleep(50); + } + + ret = regmap_write(dev->regmap, 0x80ed81, iqik_m_cal); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec57, 0x00); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec58, 0x00); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec40, 0x01); + if (ret) + goto err; + + dev->active = true; + + return 0; +err: + dev_dbg(&dev->client->dev, "failed %d\n", ret); + return ret; +} + +static int it913x_sleep(struct dvb_frontend *fe) +{ + struct it913x_dev *dev = fe->tuner_priv; + int ret, len; + + dev_dbg(&dev->client->dev, "role %u\n", dev->role); + + dev->active = false; + + ret = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1); + if (ret) + goto err; + + /* + * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner + * communication lost. Due to that, we cannot put master full sleep. + */ + if (dev->role == IT913X_ROLE_DUAL_MASTER) + len = 4; + else + len = 15; + + dev_dbg(&dev->client->dev, "role %u, len %d\n", dev->role, len); + + ret = regmap_bulk_write(dev->regmap, 0x80ec02, + "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + len); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec12, "\x00\x00\x00\x00", 4); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec17, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec22, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec20, "\x00", 1); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec3f, "\x01", 1); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&dev->client->dev, "failed %d\n", ret); + return ret; +} + +static int it913x_set_params(struct dvb_frontend *fe) +{ + struct it913x_dev *dev = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + unsigned int utmp; + u32 pre_lo_freq, t_cal_freq; + u16 iqik_m_cal, n_div; + u8 u8tmp, n, l_band, lna_band; + + dev_dbg(&dev->client->dev, "role=%u, frequency %u, bandwidth_hz %u\n", + dev->role, c->frequency, c->bandwidth_hz); + + if (!dev->active) { + ret = -EINVAL; + goto err; + } + + if (c->frequency <= 74000000) { + n_div = 48; + n = 0; + } else if (c->frequency <= 111000000) { + n_div = 32; + n = 1; + } else if (c->frequency <= 148000000) { + n_div = 24; + n = 2; + } else if (c->frequency <= 222000000) { + n_div = 16; + n = 3; + } else if (c->frequency <= 296000000) { + n_div = 12; + n = 4; + } else if (c->frequency <= 445000000) { + n_div = 8; + n = 5; + } else if (c->frequency <= dev->fn_min) { + n_div = 6; + n = 6; + } else if (c->frequency <= 950000000) { + n_div = 4; + n = 7; + } else { + n_div = 2; + n = 0; + } + + ret = regmap_read(dev->regmap, 0x80ed81, &utmp); + if (ret) + goto err; + + iqik_m_cal = utmp * n_div; + + if (utmp < 0x20) { + if (dev->clk_mode == 0) + iqik_m_cal = (iqik_m_cal * 9) >> 5; + else + iqik_m_cal >>= 1; + } else { + iqik_m_cal = 0x40 - iqik_m_cal; + if (dev->clk_mode == 0) + iqik_m_cal = ~((iqik_m_cal * 9) >> 5); + else + iqik_m_cal = ~(iqik_m_cal >> 1); + } + + t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv; + pre_lo_freq = t_cal_freq / dev->xtal; + utmp = pre_lo_freq * dev->xtal; + + if ((t_cal_freq - utmp) >= (dev->xtal >> 1)) + pre_lo_freq++; + + pre_lo_freq += (u32) n << 13; + /* Frequency OMEGA_IQIK_M_CAL_MID*/ + t_cal_freq = pre_lo_freq + (u32)iqik_m_cal; + dev_dbg(&dev->client->dev, "t_cal_freq %u, pre_lo_freq %u\n", + t_cal_freq, pre_lo_freq); + + if (c->frequency <= 440000000) { + l_band = 0; + lna_band = 0; + } else if (c->frequency <= 484000000) { + l_band = 1; + lna_band = 1; + } else if (c->frequency <= 533000000) { + l_band = 1; + lna_band = 2; + } else if (c->frequency <= 587000000) { + l_band = 1; + lna_band = 3; + } else if (c->frequency <= 645000000) { + l_band = 1; + lna_band = 4; + } else if (c->frequency <= 710000000) { + l_band = 1; + lna_band = 5; + } else if (c->frequency <= 782000000) { + l_band = 1; + lna_band = 6; + } else if (c->frequency <= 860000000) { + l_band = 1; + lna_band = 7; + } else if (c->frequency <= 1492000000) { + l_band = 1; + lna_band = 0; + } else if (c->frequency <= 1685000000) { + l_band = 1; + lna_band = 1; + } else { + ret = -EINVAL; + goto err; + } + + /* XXX: latest windows driver does not set that at all */ + ret = regmap_write(dev->regmap, 0x80ee06, lna_band); + if (ret) + goto err; + + if (c->bandwidth_hz <= 5000000) + u8tmp = 0; + else if (c->bandwidth_hz <= 6000000) + u8tmp = 2; + else if (c->bandwidth_hz <= 7000000) + u8tmp = 4; + else + u8tmp = 6; /* 8000000 */ + + ret = regmap_write(dev->regmap, 0x80ec56, u8tmp); + if (ret) + goto err; + + /* XXX: latest windows driver sets different value (a8 != 68) */ + ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3)); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec4d, (t_cal_freq >> 0) & 0xff); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec4e, (t_cal_freq >> 8) & 0xff); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80011e, (pre_lo_freq >> 0) & 0xff); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80011f, (pre_lo_freq >> 8) & 0xff); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&dev->client->dev, "failed %d\n", ret); + return ret; +} + +static const struct dvb_tuner_ops it913x_tuner_ops = { + .info = { + .name = "ITE IT913X", + .frequency_min = 174000000, + .frequency_max = 862000000, + }, + + .init = it913x_init, + .sleep = it913x_sleep, + .set_params = it913x_set_params, +}; + +static int it913x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct it913x_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct it913x_dev *dev; + int ret; + char *chip_ver_str; + static const struct regmap_config regmap_config = { + .reg_bits = 24, + .val_bits = 8, + }; + + dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; + } + + dev->client = client; + dev->fe = cfg->fe; + dev->chip_ver = cfg->chip_ver; + dev->role = cfg->role; + dev->regmap = regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } + + fe->tuner_priv = dev; + memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, + sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, dev); + + if (dev->chip_ver == 1) + chip_ver_str = "AX"; + else if (dev->chip_ver == 2) + chip_ver_str = "BX"; + else + chip_ver_str = "??"; + + dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n", + chip_ver_str); + dev_dbg(&dev->client->dev, "chip_ver %u, role %u\n", + dev->chip_ver, dev->role); + return 0; + +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int it913x_remove(struct i2c_client *client) +{ + struct it913x_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; + regmap_exit(dev->regmap); + kfree(dev); + + return 0; +} + +static const struct i2c_device_id it913x_id_table[] = { + {"it913x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, it913x_id_table); + +static struct i2c_driver it913x_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "it913x", + }, + .probe = it913x_probe, + .remove = it913x_remove, + .id_table = it913x_id_table, +}; + +module_i2c_driver(it913x_driver); + +MODULE_DESCRIPTION("ITE IT913X silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tuner_it913x.h b/drivers/media/tuners/it913x.h index 12dd36bd9e79..33de53d4a566 100644 --- a/drivers/media/tuners/tuner_it913x.h +++ b/drivers/media/tuners/it913x.h @@ -25,21 +25,30 @@ #include "dvb_frontend.h" -#if defined(CONFIG_MEDIA_TUNER_IT913X) || \ - (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE)) -extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - u8 config); -#else -static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - u8 config) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif +/* + * I2C address + * 0x38, 0x3a, 0x3c, 0x3e + */ +struct it913x_config { + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; + + /* + * chip version + * 1 = IT9135 AX + * 2 = IT9135 BX + */ + unsigned int chip_ver:2; + + /* + * tuner role + */ +#define IT913X_ROLE_SINGLE 0 +#define IT913X_ROLE_DUAL_MASTER 1 +#define IT913X_ROLE_DUAL_SLAVE 2 + unsigned int role:2; +}; #endif diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index 40c42dec721b..caa542346891 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -18,120 +18,11 @@ #include "m88ts2022_priv.h" -/* write multiple registers */ -static int m88ts2022_wr_regs(struct m88ts2022_priv *priv, - u8 reg, const u8 *val, int len) +static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg, + u8 mask, u8 val, u8 *reg_val) { -#define MAX_WR_LEN 3 -#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) - int ret; - u8 buf[MAX_WR_XFER_LEN]; - struct i2c_msg msg[1] = { - { - .addr = priv->client->addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_WR_LEN)) - return -EINVAL; - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->client->adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->client->dev, - "%s: i2c wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* read multiple registers */ -static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg, - u8 *val, int len) -{ -#define MAX_RD_LEN 1 -#define MAX_RD_XFER_LEN (MAX_RD_LEN) - int ret; - u8 buf[MAX_RD_XFER_LEN]; - struct i2c_msg msg[2] = { - { - .addr = priv->client->addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_RD_LEN)) - return -EINVAL; - - ret = i2c_transfer(priv->client->adapter, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&priv->client->dev, - "%s: i2c rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val) -{ - return m88ts2022_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ -static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val) -{ - return m88ts2022_rd_regs(priv, reg, val, 1); -} - -/* write single register with mask */ -static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv, - u8 reg, u8 val, u8 mask) -{ - int ret; - u8 u8tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1); - if (ret) - return ret; - - val &= mask; - u8tmp &= ~mask; - val |= u8tmp; - } - - return m88ts2022_wr_regs(priv, reg, &val, 1); -} - -static int m88ts2022_cmd(struct dvb_frontend *fe, - int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val) -{ - struct m88ts2022_priv *priv = fe->tuner_priv; int ret, i; - u8 u8tmp; + unsigned int utmp; struct m88ts2022_reg_val reg_vals[] = { {0x51, 0x1f - op}, {0x51, 0x1f}, @@ -140,12 +31,12 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, }; for (i = 0; i < 2; i++) { - dev_dbg(&priv->client->dev, - "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n", - __func__, i, op, reg, mask, val); + dev_dbg(&dev->client->dev, + "i=%d op=%02x reg=%02x mask=%02x val=%02x\n", + i, op, reg, mask, val); for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, + ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val); if (ret) goto err; @@ -153,37 +44,38 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, usleep_range(sleep * 1000, sleep * 10000); - ret = m88ts2022_rd_reg(priv, reg, &u8tmp); + ret = regmap_read(dev->regmap, reg, &utmp); if (ret) goto err; - if ((u8tmp & mask) != val) + if ((utmp & mask) != val) break; } if (reg_val) - *reg_val = u8tmp; + *reg_val = utmp; err: return ret; } static int m88ts2022_set_params(struct dvb_frontend *fe) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - unsigned int frequency_khz, frequency_offset_khz, f_3db_hz; + unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz; unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28; u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min; u16 u16tmp; - dev_dbg(&priv->client->dev, - "%s: frequency=%d symbol_rate=%d rolloff=%d\n", - __func__, c->frequency, c->symbol_rate, c->rolloff); + + dev_dbg(&dev->client->dev, + "frequency=%d symbol_rate=%d rolloff=%d\n", + c->frequency, c->symbol_rate, c->rolloff); /* * Integer-N PLL synthesizer * kHz is used for all calculations to keep calculations within 32-bit */ - f_ref_khz = DIV_ROUND_CLOSEST(priv->cfg.clock, 1000); + f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000); div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000); if (c->symbol_rate < 5000000) @@ -203,14 +95,14 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) buf[0] = u8tmp; buf[1] = 0x40; - ret = m88ts2022_wr_regs(priv, 0x10, buf, 2); + ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2); if (ret) goto err; f_vco_khz = frequency_khz * div_out; pll_n = f_vco_khz * div_ref / f_ref_khz; pll_n += pll_n % 2; - priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; + dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; if (pll_n < 4095) u16tmp = pll_n - 1024; @@ -222,88 +114,87 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) buf[0] = (u16tmp >> 8) & 0x3f; buf[1] = (u16tmp >> 0) & 0xff; buf[2] = div_ref - 8; - ret = m88ts2022_wr_regs(priv, 0x01, buf, 3); + ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3); if (ret) goto err; - dev_dbg(&priv->client->dev, - "%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", - __func__, priv->frequency_khz, - priv->frequency_khz - c->frequency, f_vco_khz, pll_n, - div_ref, div_out); + dev_dbg(&dev->client->dev, + "frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", + dev->frequency_khz, dev->frequency_khz - c->frequency, + f_vco_khz, pll_n, div_ref, div_out); - ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL); if (ret) goto err; - ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp); + ret = regmap_read(dev->regmap, 0x14, &utmp); if (ret) goto err; - u8tmp &= 0x7f; - if (u8tmp < 64) { - ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80); + utmp &= 0x7f; + if (utmp < 64) { + ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x11, 0x6f); + ret = regmap_write(dev->regmap, 0x11, 0x6f); if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL); if (ret) goto err; } - ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp); + ret = regmap_read(dev->regmap, 0x14, &utmp); if (ret) goto err; - u8tmp &= 0x1f; - if (u8tmp > 19) { - ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02); + utmp &= 0x1f; + if (utmp > 19) { + ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00); if (ret) goto err; } - ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x25, 0x00); + ret = regmap_write(dev->regmap, 0x25, 0x00); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x27, 0x70); + ret = regmap_write(dev->regmap, 0x27, 0x70); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x41, 0x09); + ret = regmap_write(dev->regmap, 0x41, 0x09); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x08, 0x0b); + ret = regmap_write(dev->regmap, 0x08, 0x0b); if (ret) goto err; /* filters */ gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U); - ret = m88ts2022_wr_reg(priv, 0x04, gdiv28); + ret = regmap_write(dev->regmap, 0x04, gdiv28); if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; cap_code = u8tmp & 0x3f; - ret = m88ts2022_wr_reg(priv, 0x41, 0x0d); + ret = regmap_write(dev->regmap, 0x41, 0x0d); if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; @@ -314,7 +205,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) div_min = gdiv28 * 78 / 100; div_max = clamp_val(div_max, 0U, 63U); - f_3db_hz = c->symbol_rate * 135UL / 200UL; + f_3db_hz = mult_frac(c->symbol_rate, 135, 200); f_3db_hz += 2000000U + (frequency_offset_khz * 1000U); f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U); @@ -327,25 +218,25 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max); - ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv); + ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm); + ret = regmap_write(dev->regmap, 0x06, lpf_gm); if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; cap_code = u8tmp & 0x3f; - ret = m88ts2022_wr_reg(priv, 0x41, 0x09); + ret = regmap_write(dev->regmap, 0x41, 0x09); if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; @@ -353,31 +244,31 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = (cap_code + u8tmp) / 2; u8tmp = cap_code | 0x80; - ret = m88ts2022_wr_reg(priv, 0x25, u8tmp); + ret = regmap_write(dev->regmap, 0x25, u8tmp); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x27, 0x30); + ret = regmap_write(dev->regmap, 0x27, 0x30); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x08, 0x09); + ret = regmap_write(dev->regmap, 0x08, 0x09); if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL); if (ret) goto err; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int m88ts2022_init(struct dvb_frontend *fe) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret, i; u8 u8tmp; static const struct m88ts2022_reg_val reg_vals[] = { @@ -393,23 +284,24 @@ static int m88ts2022_init(struct dvb_frontend *fe) {0x24, 0x02}, {0x12, 0xa0}, }; - dev_dbg(&priv->client->dev, "%s:\n", __func__); - ret = m88ts2022_wr_reg(priv, 0x00, 0x01); + dev_dbg(&dev->client->dev, "\n"); + + ret = regmap_write(dev->regmap, 0x00, 0x01); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x00, 0x03); + ret = regmap_write(dev->regmap, 0x00, 0x03); if (ret) goto err; - switch (priv->cfg.clock_out) { + switch (dev->cfg.clock_out) { case M88TS2022_CLOCK_OUT_DISABLED: u8tmp = 0x60; break; case M88TS2022_CLOCK_OUT_ENABLED: u8tmp = 0x70; - ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div); + ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div); if (ret) goto err; break; @@ -420,58 +312,61 @@ static int m88ts2022_init(struct dvb_frontend *fe) goto err; } - ret = m88ts2022_wr_reg(priv, 0x42, u8tmp); + ret = regmap_write(dev->regmap, 0x42, u8tmp); if (ret) goto err; - if (priv->cfg.loop_through) + if (dev->cfg.loop_through) u8tmp = 0xec; else u8tmp = 0x6c; - ret = m88ts2022_wr_reg(priv, 0x62, u8tmp); + ret = regmap_write(dev->regmap, 0x62, u8tmp); if (ret) goto err; for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val); + ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val); if (ret) goto err; } err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int m88ts2022_sleep(struct dvb_frontend *fe) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret; - dev_dbg(&priv->client->dev, "%s:\n", __func__); - ret = m88ts2022_wr_reg(priv, 0x00, 0x00); + dev_dbg(&dev->client->dev, "\n"); + + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) goto err; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct m88ts2022_priv *priv = fe->tuner_priv; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + struct m88ts2022_dev *dev = fe->tuner_priv; - *frequency = priv->frequency_khz; + dev_dbg(&dev->client->dev, "\n"); + + *frequency = dev->frequency_khz; return 0; } static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct m88ts2022_priv *priv = fe->tuner_priv; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + struct m88ts2022_dev *dev = fe->tuner_priv; + + dev_dbg(&dev->client->dev, "\n"); *frequency = 0; /* Zero-IF */ return 0; @@ -479,31 +374,30 @@ static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret; - u8 u8tmp; u16 gain, u16tmp; - unsigned int gain1, gain2, gain3; + unsigned int utmp, gain1, gain2, gain3; - ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp); + ret = regmap_read(dev->regmap, 0x3d, &utmp); if (ret) goto err; - gain1 = (u8tmp >> 0) & 0x1f; + gain1 = (utmp >> 0) & 0x1f; gain1 = clamp(gain1, 0U, 15U); - ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp); + ret = regmap_read(dev->regmap, 0x21, &utmp); if (ret) goto err; - gain2 = (u8tmp >> 0) & 0x1f; + gain2 = (utmp >> 0) & 0x1f; gain2 = clamp(gain2, 2U, 16U); - ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp); + ret = regmap_read(dev->regmap, 0x66, &utmp); if (ret) goto err; - gain3 = (u8tmp >> 3) & 0x07; + gain3 = (utmp >> 3) & 0x07; gain3 = clamp(gain3, 0U, 6U); gain = gain1 * 265 + gain2 * 338 + gain3 * 285; @@ -515,7 +409,7 @@ static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000); err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -540,46 +434,56 @@ static int m88ts2022_probe(struct i2c_client *client, { struct m88ts2022_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct m88ts2022_priv *priv; + struct m88ts2022_dev *dev; int ret; - u8 chip_id, u8tmp; + u8 u8tmp; + unsigned int utmp; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config)); - priv->client = client; + memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_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; + } /* check if the tuner is there */ - ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp); + ret = regmap_read(dev->regmap, 0x00, &utmp); if (ret) goto err; - if ((u8tmp & 0x03) == 0x00) { - ret = m88ts2022_wr_reg(priv, 0x00, 0x01); - if (ret < 0) + if ((utmp & 0x03) == 0x00) { + ret = regmap_write(dev->regmap, 0x00, 0x01); + if (ret) goto err; usleep_range(2000, 50000); } - ret = m88ts2022_wr_reg(priv, 0x00, 0x03); + ret = regmap_write(dev->regmap, 0x00, 0x03); if (ret) goto err; usleep_range(2000, 50000); - ret = m88ts2022_rd_reg(priv, 0x00, &chip_id); + ret = regmap_read(dev->regmap, 0x00, &utmp); if (ret) goto err; - dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp); - switch (chip_id) { + switch (utmp) { case 0xc3: case 0x83: break; @@ -587,13 +491,13 @@ static int m88ts2022_probe(struct i2c_client *client, goto err; } - switch (priv->cfg.clock_out) { + switch (dev->cfg.clock_out) { case M88TS2022_CLOCK_OUT_DISABLED: u8tmp = 0x60; break; case M88TS2022_CLOCK_OUT_ENABLED: u8tmp = 0x70; - ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div); + ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div); if (ret) goto err; break; @@ -604,49 +508,48 @@ static int m88ts2022_probe(struct i2c_client *client, goto err; } - ret = m88ts2022_wr_reg(priv, 0x42, u8tmp); + ret = regmap_write(dev->regmap, 0x42, u8tmp); if (ret) goto err; - if (priv->cfg.loop_through) + if (dev->cfg.loop_through) u8tmp = 0xec; else u8tmp = 0x6c; - ret = m88ts2022_wr_reg(priv, 0x62, u8tmp); + ret = regmap_write(dev->regmap, 0x62, u8tmp); if (ret) goto err; /* sleep */ - ret = m88ts2022_wr_reg(priv, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) goto err; - dev_info(&priv->client->dev, - "%s: Montage M88TS2022 successfully identified\n", - KBUILD_MODNAME); + dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n"); - fe->tuner_priv = priv; + fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops, sizeof(struct dvb_tuner_ops)); - i2c_set_clientdata(client, priv); + i2c_set_clientdata(client, dev); return 0; err: - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); + dev_dbg(&client->dev, "failed=%d\n", ret); + kfree(dev); return ret; } static int m88ts2022_remove(struct i2c_client *client) { - struct m88ts2022_priv *priv = i2c_get_clientdata(client); - struct dvb_frontend *fe = priv->cfg.fe; - dev_dbg(&client->dev, "%s:\n", __func__); + struct m88ts2022_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(priv); + kfree(dev); return 0; } diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h index 0363dd866a2d..feeb5ad6beef 100644 --- a/drivers/media/tuners/m88ts2022_priv.h +++ b/drivers/media/tuners/m88ts2022_priv.h @@ -18,11 +18,12 @@ #define M88TS2022_PRIV_H #include "m88ts2022.h" +#include <linux/regmap.h> -struct m88ts2022_priv { +struct m88ts2022_dev { struct m88ts2022_config cfg; struct i2c_client *client; - struct dvb_frontend *fe; + struct regmap *regmap; u32 frequency_khz; }; diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index ee99e372c943..26019e731993 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -67,7 +67,8 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, { int ret; u32 reg; - dev_dbg(&s->spi->dev, "%s: lna=%d mixer=%d if=%d\n", __func__, + + dev_dbg(&s->spi->dev, "lna=%d mixer=%d if=%d\n", lna_gain, mixer_gain, if_gain); reg = 1 << 0; @@ -83,7 +84,7 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, return 0; err: - dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&s->spi->dev, "failed %d\n", ret); return ret; }; @@ -94,6 +95,7 @@ static int msi001_set_tuner(struct msi001 *s) u32 reg; u64 f_vco, tmp64; u8 mode, filter_mode, lo_div; + static const struct { u32 rf; u8 mode; @@ -145,9 +147,7 @@ static int msi001_set_tuner(struct msi001 *s) #define R_REF 4 #define F_OUT_STEP 1 - dev_dbg(&s->spi->dev, - "%s: f_rf=%d f_if=%d\n", - __func__, f_rf, f_if); + dev_dbg(&s->spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if); for (i = 0; i < ARRAY_SIZE(band_lut); i++) { if (f_rf <= band_lut[i].rf) { @@ -198,8 +198,7 @@ static int msi001_set_tuner(struct msi001 *s) s->bandwidth->val = bandwidth_lut[i].freq; - dev_dbg(&s->spi->dev, "%s: bandwidth selected=%d\n", - __func__, bandwidth_lut[i].freq); + dev_dbg(&s->spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq); f_vco = (u64) (f_rf + f_if + f_if1) * lo_div; tmp64 = f_vco; @@ -225,9 +224,8 @@ static int msi001_set_tuner(struct msi001 *s) tmp += 1ul * F_REF * R_REF * frac / thresh; tmp /= lo_div; - dev_dbg(&s->spi->dev, - "%s: rf=%u:%u n=%d thresh=%d frac=%d\n", - __func__, f_rf, tmp, n, thresh, frac); + dev_dbg(&s->spi->dev, "rf=%u:%u n=%d thresh=%d frac=%d\n", + f_rf, tmp, n, thresh, frac); ret = msi001_wreg(s, 0x00000e); if (ret) @@ -276,7 +274,7 @@ static int msi001_set_tuner(struct msi001 *s) return 0; err: - dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&s->spi->dev, "failed %d\n", ret); return ret; }; @@ -284,7 +282,8 @@ static int msi001_s_power(struct v4l2_subdev *sd, int on) { struct msi001 *s = sd_to_msi001(sd); int ret; - dev_dbg(&s->spi->dev, "%s: on=%d\n", __func__, on); + + dev_dbg(&s->spi->dev, "on=%d\n", on); if (on) ret = 0; @@ -301,7 +300,8 @@ static const struct v4l2_subdev_core_ops msi001_core_ops = { static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index); + + dev_dbg(&s->spi->dev, "index=%d\n", v->index); strlcpy(v->name, "Mirics MSi001", sizeof(v->name)); v->type = V4L2_TUNER_RF; @@ -315,14 +315,16 @@ static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index); + + dev_dbg(&s->spi->dev, "index=%d\n", v->index); return 0; } static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: tuner=%d\n", __func__, f->tuner); + + dev_dbg(&s->spi->dev, "tuner=%d\n", f->tuner); f->frequency = s->f_tuner; return 0; } @@ -332,8 +334,9 @@ static int msi001_s_frequency(struct v4l2_subdev *sd, { struct msi001 *s = sd_to_msi001(sd); unsigned int band; - dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d frequency=%u\n", - __func__, f->tuner, f->type, f->frequency); + + dev_dbg(&s->spi->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2)) band = 0; @@ -349,8 +352,9 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd, struct v4l2_frequency_band *band) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d index=%d\n", - __func__, band->tuner, band->type, band->index); + + dev_dbg(&s->spi->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->index >= ARRAY_SIZE(bands)) return -EINVAL; @@ -380,9 +384,10 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl) struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl); int ret; + dev_dbg(&s->spi->dev, - "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", - __func__, ctrl->id, ctrl->name, ctrl->val, + "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", + ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum, ctrl->step); switch (ctrl->id) { @@ -403,8 +408,7 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl) s->mixer_gain->cur.val, s->if_gain->val); break; default: - dev_dbg(&s->spi->dev, "%s: unkown control %d\n", - __func__, ctrl->id); + dev_dbg(&s->spi->dev, "unkown control %d\n", ctrl->id); ret = -EINVAL; } @@ -419,7 +423,8 @@ static int msi001_probe(struct spi_device *spi) { struct msi001 *s; int ret; - dev_dbg(&spi->dev, "%s:\n", __func__); + + dev_dbg(&spi->dev, "\n"); s = kzalloc(sizeof(struct msi001), GFP_KERNEL); if (s == NULL) { @@ -466,7 +471,8 @@ static int msi001_remove(struct spi_device *spi) { struct v4l2_subdev *sd = spi_get_drvdata(spi); struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&spi->dev, "%s:\n", __func__); + + dev_dbg(&spi->dev, "\n"); /* * Registered by v4l2_spi_new_subdev() from master driver, but we must diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c index 13381de58a84..b87b2549d58d 100644 --- a/drivers/media/tuners/mt2060.c +++ b/drivers/media/tuners/mt2060.c @@ -157,7 +157,6 @@ static int mt2060_set_params(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2060_priv *priv; - int ret=0; int i=0; u32 freq; u8 lnaband; @@ -240,7 +239,7 @@ static int mt2060_set_params(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - return ret; + return 0; } static void mt2060_calibrate(struct mt2060_priv *priv) diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index f640dcf4a81d..9e9c5eb4cb66 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1216,7 +1216,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, if (status >= 0) { val = (state-> - reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] + reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode] ? 0x40 : 0x00); if (state->reg[MT2063_REG_PD1_TGT] != val) @@ -1225,7 +1225,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* LNARin */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | + u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) | (LNARIN[Mode] & 0x03); if (state->reg[MT2063_REG_CTRL_2C] != val) status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); @@ -1235,19 +1235,19 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, if (status >= 0) { val = (state-> - reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | + reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) | (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { status |= mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); /* trigger FIFF calibration, needed after changing FIFFQ */ val = - (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); + (state->reg[MT2063_REG_FIFF_CTRL] | 0x01); status |= mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); val = (state-> - reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); + reg[MT2063_REG_FIFF_CTRL] & ~0x01); status |= mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); } @@ -1259,7 +1259,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* acLNAmax */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | + u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) | (ACLNAMAX[Mode] & 0x1F); if (state->reg[MT2063_REG_LNA_OV] != val) status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); @@ -1267,7 +1267,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* LNATGT */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | + u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) | (LNATGT[Mode] & 0x3F); if (state->reg[MT2063_REG_LNA_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); @@ -1275,7 +1275,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* ACRF */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | + u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) | (ACRFMAX[Mode] & 0x1F); if (state->reg[MT2063_REG_RF_OV] != val) status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); @@ -1283,7 +1283,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* PD1TGT */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | + u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) | (PD1TGT[Mode] & 0x3F); if (state->reg[MT2063_REG_PD1_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); @@ -1294,7 +1294,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, u8 val = ACFIFMAX[Mode]; if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) val = 5; - val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | + val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) | (val & 0x1F); if (state->reg[MT2063_REG_FIF_OV] != val) status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); @@ -1302,7 +1302,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* PD2TGT */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | + u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) | (PD2TGT[Mode] & 0x3F); if (state->reg[MT2063_REG_PD2_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); @@ -1310,7 +1310,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* Ignore ATN Overload */ if (status >= 0) { - val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | + val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) | (RFOVDIS[Mode] ? 0x80 : 0x00); if (state->reg[MT2063_REG_LNA_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); @@ -1318,7 +1318,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* Ignore FIF Overload */ if (status >= 0) { - val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | + val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) | (FIFOVDIS[Mode] ? 0x80 : 0x00); if (state->reg[MT2063_REG_PD1_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c new file mode 100644 index 000000000000..1575a5db776a --- /dev/null +++ b/drivers/media/tuners/mxl301rf.c @@ -0,0 +1,349 @@ +/* + * MaxLinear MxL301RF OFDM tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada <tskd08@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 version 2. + * + * + * 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. + */ + +/* + * NOTICE: + * This driver is incomplete and lacks init/config of the chips, + * as the necessary info is not disclosed. + * Other features like get_if_frequency() are missing as well. + * It assumes that users of this driver (such as a PCI bridge of + * DTV receiver cards) properly init and configure the chip + * via I2C *before* calling this driver's init() function. + * + * Currently, PT3 driver is the only one that uses this driver, + * and contains init/config code in its firmware. + * Thus some part of the code might be dependent on PT3 specific config. + */ + +#include <linux/kernel.h> +#include "mxl301rf.h" + +struct mxl301rf_state { + struct mxl301rf_config cfg; + struct i2c_client *i2c; +}; + +static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c) +{ + return container_of(c, struct mxl301rf_state, cfg); +} + +static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len) +{ + int ret; + + ret = i2c_master_send(state->i2c, buf, len); + if (ret >= 0 && ret < len) + ret = -EIO; + return (ret == len) ? 0 : ret; +} + +static int reg_write(struct mxl301rf_state *state, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + + return raw_write(state, buf, 2); +} + +static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val) +{ + u8 wbuf[2] = { 0xfb, reg }; + int ret; + + ret = raw_write(state, wbuf, sizeof(wbuf)); + if (ret == 0) + ret = i2c_master_recv(state->i2c, val, 1); + if (ret >= 0 && ret < 1) + ret = -EIO; + return (ret == 1) ? 0 : ret; +} + +/* tuner_ops */ + +/* get RSSI and update propery cache, set to *out in % */ +static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out) +{ + struct mxl301rf_state *state; + int ret; + u8 rf_in1, rf_in2, rf_off1, rf_off2; + u16 rf_in, rf_off; + s64 level; + struct dtv_fe_stats *rssi; + + rssi = &fe->dtv_property_cache.strength; + rssi->len = 1; + rssi->stat[0].scale = FE_SCALE_NOT_AVAILABLE; + *out = 0; + + state = fe->tuner_priv; + ret = reg_write(state, 0x14, 0x01); + if (ret < 0) + return ret; + usleep_range(1000, 2000); + + ret = reg_read(state, 0x18, &rf_in1); + if (ret == 0) + ret = reg_read(state, 0x19, &rf_in2); + if (ret == 0) + ret = reg_read(state, 0xd6, &rf_off1); + if (ret == 0) + ret = reg_read(state, 0xd7, &rf_off2); + if (ret != 0) + return ret; + + rf_in = (rf_in2 & 0x07) << 8 | rf_in1; + rf_off = (rf_off2 & 0x0f) << 5 | (rf_off1 >> 3); + level = rf_in - rf_off - (113 << 3); /* x8 dBm */ + level = level * 1000 / 8; + rssi->stat[0].svalue = level; + rssi->stat[0].scale = FE_SCALE_DECIBEL; + /* *out = (level - min) * 100 / (max - min) */ + *out = (rf_in - rf_off + (1 << 9) - 1) * 100 / ((5 << 9) - 2); + return 0; +} + +/* spur shift parameters */ +struct shf { + u32 freq; /* Channel center frequency */ + u32 ofst_th; /* Offset frequency threshold */ + u8 shf_val; /* Spur shift value */ + u8 shf_dir; /* Spur shift direction */ +}; + +static const struct shf shf_tab[] = { + { 64500, 500, 0x92, 0x07 }, + { 191500, 300, 0xe2, 0x07 }, + { 205500, 500, 0x2c, 0x04 }, + { 212500, 500, 0x1e, 0x04 }, + { 226500, 500, 0xd4, 0x07 }, + { 99143, 500, 0x9c, 0x07 }, + { 173143, 500, 0xd4, 0x07 }, + { 191143, 300, 0xd4, 0x07 }, + { 207143, 500, 0xce, 0x07 }, + { 225143, 500, 0xce, 0x07 }, + { 243143, 500, 0xd4, 0x07 }, + { 261143, 500, 0xd4, 0x07 }, + { 291143, 500, 0xd4, 0x07 }, + { 339143, 500, 0x2c, 0x04 }, + { 117143, 500, 0x7a, 0x07 }, + { 135143, 300, 0x7a, 0x07 }, + { 153143, 500, 0x01, 0x07 } +}; + +struct reg_val { + u8 reg; + u8 val; +} __attribute__ ((__packed__)); + +static const struct reg_val set_idac[] = { + { 0x0d, 0x00 }, + { 0x0c, 0x67 }, + { 0x6f, 0x89 }, + { 0x70, 0x0c }, + { 0x6f, 0x8a }, + { 0x70, 0x0e }, + { 0x6f, 0x8b }, + { 0x70, 0x1c }, +}; + +static int mxl301rf_set_params(struct dvb_frontend *fe) +{ + struct reg_val tune0[] = { + { 0x13, 0x00 }, /* abort tuning */ + { 0x3b, 0xc0 }, + { 0x3b, 0x80 }, + { 0x10, 0x95 }, /* BW */ + { 0x1a, 0x05 }, + { 0x61, 0x00 }, /* spur shift value (placeholder) */ + { 0x62, 0xa0 } /* spur shift direction (placeholder) */ + }; + + struct reg_val tune1[] = { + { 0x11, 0x40 }, /* RF frequency L (placeholder) */ + { 0x12, 0x0e }, /* RF frequency H (placeholder) */ + { 0x13, 0x01 } /* start tune */ + }; + + struct mxl301rf_state *state; + u32 freq; + u16 f; + u32 tmp, div; + int i, ret; + + state = fe->tuner_priv; + freq = fe->dtv_property_cache.frequency; + + /* spur shift function (for analog) */ + for (i = 0; i < ARRAY_SIZE(shf_tab); i++) { + if (freq >= (shf_tab[i].freq - shf_tab[i].ofst_th) * 1000 && + freq <= (shf_tab[i].freq + shf_tab[i].ofst_th) * 1000) { + tune0[5].val = shf_tab[i].shf_val; + tune0[6].val = 0xa0 | shf_tab[i].shf_dir; + break; + } + } + ret = raw_write(state, (u8 *) tune0, sizeof(tune0)); + if (ret < 0) + goto failed; + usleep_range(3000, 4000); + + /* convert freq to 10.6 fixed point float [MHz] */ + f = freq / 1000000; + tmp = freq % 1000000; + div = 1000000; + for (i = 0; i < 6; i++) { + f <<= 1; + div >>= 1; + if (tmp > div) { + tmp -= div; + f |= 1; + } + } + if (tmp > 7812) + f++; + tune1[0].val = f & 0xff; + tune1[1].val = f >> 8; + ret = raw_write(state, (u8 *) tune1, sizeof(tune1)); + if (ret < 0) + goto failed; + msleep(31); + + ret = reg_write(state, 0x1a, 0x0d); + if (ret < 0) + goto failed; + ret = raw_write(state, (u8 *) set_idac, sizeof(set_idac)); + if (ret < 0) + goto failed; + return 0; + +failed: + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static const struct reg_val standby_data[] = { + { 0x01, 0x00 }, + { 0x13, 0x00 } +}; + +static int mxl301rf_sleep(struct dvb_frontend *fe) +{ + struct mxl301rf_state *state; + int ret; + + state = fe->tuner_priv; + ret = raw_write(state, (u8 *)standby_data, sizeof(standby_data)); + if (ret < 0) + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + + +/* init sequence is not public. + * the parent must have init'ed the device. + * just wake up here. + */ +static int mxl301rf_init(struct dvb_frontend *fe) +{ + struct mxl301rf_state *state; + int ret; + + state = fe->tuner_priv; + + ret = reg_write(state, 0x01, 0x01); + if (ret < 0) { + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; + } + return 0; +} + +/* I2C driver functions */ + +static const struct dvb_tuner_ops mxl301rf_ops = { + .info = { + .name = "MaxLinear MxL301RF", + + .frequency_min = 93000000, + .frequency_max = 803142857, + }, + + .init = mxl301rf_init, + .sleep = mxl301rf_sleep, + + .set_params = mxl301rf_set_params, + .get_rf_strength = mxl301rf_get_rf_strength, +}; + + +static int mxl301rf_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mxl301rf_state *state; + struct mxl301rf_config *cfg; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->i2c = client; + cfg = client->dev.platform_data; + + memcpy(&state->cfg, cfg, sizeof(state->cfg)); + fe = cfg->fe; + fe->tuner_priv = state; + memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops)); + + i2c_set_clientdata(client, &state->cfg); + dev_info(&client->dev, "MaxLinear MxL301RF attached.\n"); + return 0; +} + +static int mxl301rf_remove(struct i2c_client *client) +{ + struct mxl301rf_state *state; + + state = cfg_to_state(i2c_get_clientdata(client)); + state->cfg.fe->tuner_priv = NULL; + kfree(state); + return 0; +} + + +static const struct i2c_device_id mxl301rf_id[] = { + {"mxl301rf", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mxl301rf_id); + +static struct i2c_driver mxl301rf_driver = { + .driver = { + .name = "mxl301rf", + }, + .probe = mxl301rf_probe, + .remove = mxl301rf_remove, + .id_table = mxl301rf_id, +}; + +module_i2c_driver(mxl301rf_driver); + +MODULE_DESCRIPTION("MaxLinear MXL301RF tuner"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h new file mode 100644 index 000000000000..19e68405f00d --- /dev/null +++ b/drivers/media/tuners/mxl301rf.h @@ -0,0 +1,26 @@ +/* + * MaxLinear MxL301RF OFDM tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada <tskd08@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 version 2. + * + * + * 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 MXL301RF_H +#define MXL301RF_H + +#include "dvb_frontend.h" + +struct mxl301rf_config { + struct dvb_frontend *fe; +}; + +#endif /* MXL301RF_H */ diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index b473b76cb278..92a3be4fde87 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -1692,7 +1692,6 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, ) { struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; state->Mode = Mode; state->IF_Mode = IF_mode; @@ -1715,7 +1714,7 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, /* Synthesizer LO frequency calculation */ MXL_SynthIFLO_Calc(fe); - return status; + return 0; } static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c new file mode 100644 index 000000000000..18bc745ed108 --- /dev/null +++ b/drivers/media/tuners/qm1d1c0042.c @@ -0,0 +1,448 @@ +/* + * Sharp QM1D1C0042 8PSK tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada <tskd08@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 version 2. + * + * + * 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. + */ + +/* + * NOTICE: + * As the disclosed information on the chip is very limited, + * this driver lacks some features, including chip config like IF freq. + * It assumes that users of this driver (such as a PCI bridge of + * DTV receiver cards) know the relevant info and + * configure the chip via I2C if necessary. + * + * Currently, PT3 driver is the only one that uses this driver, + * and contains init/config code in its firmware. + * Thus some part of the code might be dependent on PT3 specific config. + */ + +#include <linux/kernel.h> +#include <linux/math64.h> +#include "qm1d1c0042.h" + +#define QM1D1C0042_NUM_REGS 0x20 + +static const u8 reg_initval[QM1D1C0042_NUM_REGS] = { + 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86, + 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00 +}; + +static const struct qm1d1c0042_config default_cfg = { + .xtal_freq = 16000, + .lpf = 1, + .fast_srch = 0, + .lpf_wait = 20, + .fast_srch_wait = 4, + .normal_srch_wait = 15, +}; + +struct qm1d1c0042_state { + struct qm1d1c0042_config cfg; + struct i2c_client *i2c; + u8 regs[QM1D1C0042_NUM_REGS]; +}; + +static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c) +{ + return container_of(c, struct qm1d1c0042_state, cfg); +} + +static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val) +{ + u8 wbuf[2] = { reg, val }; + int ret; + + ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf)); + if (ret >= 0 && ret < sizeof(wbuf)) + ret = -EIO; + return (ret == sizeof(wbuf)) ? 0 : ret; +} + +static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val) +{ + struct i2c_msg msgs[2] = { + { + .addr = state->i2c->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, + { + .addr = state->i2c->addr, + .flags = I2C_M_RD, + .buf = val, + .len = 1, + }, + }; + int ret; + + ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret >= 0 && ret < ARRAY_SIZE(msgs)) + ret = -EIO; + return (ret == ARRAY_SIZE(msgs)) ? 0 : ret; +} + + +static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast) +{ + if (fast) + state->regs[0x03] |= 0x01; /* set fast search mode */ + else + state->regs[0x03] &= ~0x01 & 0xff; + + return reg_write(state, 0x03, state->regs[0x03]); +} + +static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state) +{ + int ret; + + state->regs[0x01] |= 1 << 3; /* BB_Reg_enable */ + state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */ + state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */ + ret = reg_write(state, 0x01, state->regs[0x01]); + if (ret == 0) + ret = reg_write(state, 0x05, state->regs[0x05]); + + if (ret < 0) + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, state->cfg.fe->dvb->num, state->cfg.fe->id); + return ret; +} + +/* tuner_ops */ + +static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct qm1d1c0042_state *state; + struct qm1d1c0042_config *cfg; + + state = fe->tuner_priv; + cfg = priv_cfg; + + if (cfg->fe) + state->cfg.fe = cfg->fe; + + if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT) + dev_warn(&state->i2c->dev, + "(%s) changing xtal_freq not supported. ", __func__); + state->cfg.xtal_freq = default_cfg.xtal_freq; + + state->cfg.lpf = cfg->lpf; + state->cfg.fast_srch = cfg->fast_srch; + + if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT) + state->cfg.lpf_wait = cfg->lpf_wait; + else + state->cfg.lpf_wait = default_cfg.lpf_wait; + + if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT) + state->cfg.fast_srch_wait = cfg->fast_srch_wait; + else + state->cfg.fast_srch_wait = default_cfg.fast_srch_wait; + + if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT) + state->cfg.normal_srch_wait = cfg->normal_srch_wait; + else + state->cfg.normal_srch_wait = default_cfg.normal_srch_wait; + return 0; +} + +/* divisor, vco_band parameters */ +/* {maxfreq, param1(band?), param2(div?) */ +static const u32 conv_table[9][3] = { + { 2151000, 1, 7 }, + { 1950000, 1, 6 }, + { 1800000, 1, 5 }, + { 1600000, 1, 4 }, + { 1450000, 1, 3 }, + { 1250000, 1, 2 }, + { 1200000, 0, 7 }, + { 975000, 0, 6 }, + { 950000, 0, 0 } +}; + +static int qm1d1c0042_set_params(struct dvb_frontend *fe) +{ + struct qm1d1c0042_state *state; + u32 freq; + int i, ret; + u8 val, mask; + u32 a, sd; + s32 b; + + state = fe->tuner_priv; + freq = fe->dtv_property_cache.frequency; + + state->regs[0x08] &= 0xf0; + state->regs[0x08] |= 0x09; + + state->regs[0x13] &= 0x9f; + state->regs[0x13] |= 0x20; + + /* div2/vco_band */ + val = state->regs[0x02] & 0x0f; + for (i = 0; i < 8; i++) + if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) { + val |= conv_table[i][1] << 7; + val |= conv_table[i][2] << 4; + break; + } + ret = reg_write(state, 0x02, val); + if (ret < 0) + return ret; + + a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq; + + state->regs[0x06] &= 0x40; + state->regs[0x06] |= (a - 12) / 4; + ret = reg_write(state, 0x06, state->regs[0x06]); + if (ret < 0) + return ret; + + state->regs[0x07] &= 0xf0; + state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f; + ret = reg_write(state, 0x07, state->regs[0x07]); + if (ret < 0) + return ret; + + /* LPF */ + val = state->regs[0x08]; + if (state->cfg.lpf) { + /* LPF_CLK, LPF_FC */ + val &= 0xf0; + val |= 0x02; + } + ret = reg_write(state, 0x08, val); + if (ret < 0) + return ret; + + /* + * b = (freq / state->cfg.xtal_freq - a) << 20; + * sd = b (b >= 0) + * 1<<22 + b (b < 0) + */ + b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq) + - (((s64) a) << 20); + + if (b >= 0) + sd = b; + else + sd = (1 << 22) + b; + + state->regs[0x09] &= 0xc0; + state->regs[0x09] |= (sd >> 16) & 0x3f; + state->regs[0x0a] = (sd >> 8) & 0xff; + state->regs[0x0b] = sd & 0xff; + ret = reg_write(state, 0x09, state->regs[0x09]); + if (ret == 0) + ret = reg_write(state, 0x0a, state->regs[0x0a]); + if (ret == 0) + ret = reg_write(state, 0x0b, state->regs[0x0b]); + if (ret != 0) + return ret; + + if (!state->cfg.lpf) { + /* CSEL_Offset */ + ret = reg_write(state, 0x13, state->regs[0x13]); + if (ret < 0) + return ret; + } + + /* VCO_TM, LPF_TM */ + mask = state->cfg.lpf ? 0x3f : 0x7f; + val = state->regs[0x0c] & mask; + ret = reg_write(state, 0x0c, val); + if (ret < 0) + return ret; + usleep_range(2000, 3000); + val = state->regs[0x0c] | ~mask; + ret = reg_write(state, 0x0c, val); + if (ret < 0) + return ret; + + if (state->cfg.lpf) + msleep(state->cfg.lpf_wait); + else if (state->regs[0x03] & 0x01) + msleep(state->cfg.fast_srch_wait); + else + msleep(state->cfg.normal_srch_wait); + + if (state->cfg.lpf) { + /* LPF_FC */ + ret = reg_write(state, 0x08, 0x09); + if (ret < 0) + return ret; + + /* CSEL_Offset */ + ret = reg_write(state, 0x13, state->regs[0x13]); + if (ret < 0) + return ret; + } + return 0; +} + +static int qm1d1c0042_sleep(struct dvb_frontend *fe) +{ + struct qm1d1c0042_state *state; + int ret; + + state = fe->tuner_priv; + state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */ + state->regs[0x01] |= 1 << 0; /* STDBY */ + state->regs[0x05] |= 1 << 3; /* pfd_rst STANDBY */ + ret = reg_write(state, 0x05, state->regs[0x05]); + if (ret == 0) + ret = reg_write(state, 0x01, state->regs[0x01]); + if (ret < 0) + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static int qm1d1c0042_init(struct dvb_frontend *fe) +{ + struct qm1d1c0042_state *state; + u8 val; + int i, ret; + + state = fe->tuner_priv; + memcpy(state->regs, reg_initval, sizeof(reg_initval)); + + reg_write(state, 0x01, 0x0c); + reg_write(state, 0x01, 0x0c); + + ret = reg_write(state, 0x01, 0x0c); /* soft reset on */ + if (ret < 0) + goto failed; + usleep_range(2000, 3000); + + val = state->regs[0x01] | 0x10; + ret = reg_write(state, 0x01, val); /* soft reset off */ + if (ret < 0) + goto failed; + + /* check ID */ + ret = reg_read(state, 0x00, &val); + if (ret < 0 || val != 0x48) + goto failed; + usleep_range(2000, 3000); + + state->regs[0x0c] |= 0x40; + ret = reg_write(state, 0x0c, state->regs[0x0c]); + if (ret < 0) + goto failed; + msleep(state->cfg.lpf_wait); + + /* set all writable registers */ + for (i = 1; i <= 0x0c ; i++) { + ret = reg_write(state, i, state->regs[i]); + if (ret < 0) + goto failed; + } + for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) { + ret = reg_write(state, i, state->regs[i]); + if (ret < 0) + goto failed; + } + + ret = qm1d1c0042_wakeup(state); + if (ret < 0) + goto failed; + + ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch); + if (ret < 0) + goto failed; + + return ret; + +failed: + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +/* I2C driver functions */ + +static const struct dvb_tuner_ops qm1d1c0042_ops = { + .info = { + .name = "Sharp QM1D1C0042", + + .frequency_min = 950000, + .frequency_max = 2150000, + }, + + .init = qm1d1c0042_init, + .sleep = qm1d1c0042_sleep, + .set_config = qm1d1c0042_set_config, + .set_params = qm1d1c0042_set_params, +}; + + +static int qm1d1c0042_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct qm1d1c0042_state *state; + struct qm1d1c0042_config *cfg; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + state->i2c = client; + + cfg = client->dev.platform_data; + fe = cfg->fe; + fe->tuner_priv = state; + qm1d1c0042_set_config(fe, cfg); + memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops)); + + i2c_set_clientdata(client, &state->cfg); + dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n"); + return 0; +} + +static int qm1d1c0042_remove(struct i2c_client *client) +{ + struct qm1d1c0042_state *state; + + state = cfg_to_state(i2c_get_clientdata(client)); + state->cfg.fe->tuner_priv = NULL; + kfree(state); + return 0; +} + + +static const struct i2c_device_id qm1d1c0042_id[] = { + {"qm1d1c0042", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id); + +static struct i2c_driver qm1d1c0042_driver = { + .driver = { + .name = "qm1d1c0042", + }, + .probe = qm1d1c0042_probe, + .remove = qm1d1c0042_remove, + .id_table = qm1d1c0042_id, +}; + +module_i2c_driver(qm1d1c0042_driver); + +MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/qm1d1c0042.h b/drivers/media/tuners/qm1d1c0042.h new file mode 100644 index 000000000000..4f5c18816c44 --- /dev/null +++ b/drivers/media/tuners/qm1d1c0042.h @@ -0,0 +1,37 @@ +/* + * Sharp QM1D1C0042 8PSK tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada <tskd08@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 version 2. + * + * + * 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 QM1D1C0042_H +#define QM1D1C0042_H + +#include "dvb_frontend.h" + + +struct qm1d1c0042_config { + struct dvb_frontend *fe; + + u32 xtal_freq; /* [kHz] */ /* currently ignored */ + bool lpf; /* enable LPF */ + bool fast_srch; /* enable fast search mode, no LPF */ + u32 lpf_wait; /* wait in tuning with LPF enabled. [ms] */ + u32 fast_srch_wait; /* with fast-search mode, no LPF. [ms] */ + u32 normal_srch_wait; /* with no LPF/fast-search mode. [ms] */ +}; +/* special values indicating to use the default in qm1d1c0042_config */ +#define QM1D1C0042_CFG_XTAL_DFLT 0 +#define QM1D1C0042_CFG_WAIT_DFLT 0 + +#endif /* QM1D1C0042_H */ diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 6c53edb73a63..cf97142e01e6 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2157/2158 silicon tuner driver + * Silicon Labs Si2147/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> * @@ -55,8 +55,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) break; } - dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", - __func__, + dev_dbg(&s->client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -75,7 +74,7 @@ err_mutex_unlock: return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -88,9 +87,12 @@ static int si2157_init(struct dvb_frontend *fe) u8 *fw_file; unsigned int chip_id; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); - /* configure? */ + if (s->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; cmd.rlen = 1; @@ -111,45 +113,47 @@ static int si2157_init(struct dvb_frontend *fe) #define SI2158_A20 ('A' << 24 | 58 << 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) switch (chip_id) { case SI2158_A20: fw_file = SI2158_A20_FIRMWARE; break; case SI2157_A30: + case SI2147_A30: goto skip_fw_download; break; default: dev_err(&s->client->dev, - "%s: unkown chip version Si21%d-%c%c%c\n", - KBUILD_MODNAME, cmd.args[2], cmd.args[1], + "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, "%s: found a '%s' in cold state\n", - KBUILD_MODNAME, si2157_ops.info.name); + dev_info(&s->client->dev, "found a '%s' in cold state\n", + si2157_ops.info.name); /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &s->client->dev); if (ret) { - dev_err(&s->client->dev, "%s: firmware file '%s' not found\n", - KBUILD_MODNAME, fw_file); + dev_err(&s->client->dev, "firmware file '%s' not found\n", + fw_file); goto err; } /* firmware should be n chunks of 17 bytes */ if (fw->size % 17 != 0) { - dev_err(&s->client->dev, "%s: firmware file '%s' is invalid\n", - KBUILD_MODNAME, fw_file); + dev_err(&s->client->dev, "firmware file '%s' is invalid\n", + fw_file); ret = -EINVAL; goto err; } - dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, fw_file); + dev_info(&s->client->dev, "downloading firmware from file '%s'\n", + fw_file); for (remaining = fw->size; remaining > 0; remaining -= 17) { len = fw->data[fw->size - remaining]; @@ -159,8 +163,8 @@ static int si2157_init(struct dvb_frontend *fe) ret = si2157_cmd_execute(s, &cmd); if (ret) { dev_err(&s->client->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); + "firmware download failed=%d\n", + ret); goto err; } } @@ -177,14 +181,17 @@ skip_fw_download: if (ret) goto err; - s->active = true; + s->fw_loaded = true; +warm: + s->active = true; return 0; + err: if (fw) release_firmware(fw); - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -194,20 +201,21 @@ static int si2157_sleep(struct dvb_frontend *fe) int ret; struct si2157_cmd cmd; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); s->active = false; - memcpy(cmd.args, "\x13", 1); - cmd.wlen = 1; - cmd.rlen = 0; + /* standby */ + memcpy(cmd.args, "\x16\x00", 2); + cmd.wlen = 2; + cmd.rlen = 1; ret = si2157_cmd_execute(s, &cmd); if (ret) goto err; return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -220,8 +228,8 @@ static int si2157_set_params(struct dvb_frontend *fe) u8 bandwidth, delivery_system; dev_dbg(&s->client->dev, - "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", - __func__, c->delivery_system, c->frequency, + "delivery_system=%d frequency=%u bandwidth_hz=%u\n", + c->delivery_system, c->frequency, c->bandwidth_hz); if (!s->active) { @@ -239,6 +247,9 @@ static int si2157_set_params(struct dvb_frontend *fe) bandwidth = 0x0f; switch (c->delivery_system) { + case SYS_ATSC: + delivery_system = 0x00; + break; case SYS_DVBT: case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */ delivery_system = 0x20; @@ -256,7 +267,14 @@ static int si2157_set_params(struct dvb_frontend *fe) if (s->inversion) cmd.args[5] = 0x01; cmd.wlen = 6; - cmd.rlen = 1; + cmd.rlen = 4; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; ret = si2157_cmd_execute(s, &cmd); if (ret) goto err; @@ -275,7 +293,7 @@ static int si2157_set_params(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -310,13 +328,14 @@ static int si2157_probe(struct i2c_client *client, s = kzalloc(sizeof(struct si2157), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + 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); /* check if the tuner is there */ @@ -333,11 +352,10 @@ static int si2157_probe(struct i2c_client *client, i2c_set_clientdata(client, s); dev_info(&s->client->dev, - "%s: Silicon Labs Si2157/Si2158 successfully attached\n", - KBUILD_MODNAME); + "Silicon Labs Si2157/Si2158 successfully attached\n"); return 0; err: - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); kfree(s); return ret; @@ -348,7 +366,7 @@ static int si2157_remove(struct i2c_client *client) struct si2157 *s = i2c_get_clientdata(client); struct dvb_frontend *fe = s->fe; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index 6da4d5d1c817..d3b19cadb4a1 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2157/2158 silicon tuner driver + * Silicon Labs Si2147/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 3ddab5e6b500..e71ffafed951 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2157/2158 silicon tuner driver + * Silicon Labs Si2147/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> * @@ -26,6 +26,7 @@ struct si2157 { struct i2c_client *client; struct dvb_frontend *fe; bool active; + bool fw_loaded; bool inversion; }; diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 05a4ac9edb6b..d93e0667b46b 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -19,125 +19,19 @@ */ #include "tda18212.h" +#include <linux/regmap.h> -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 - -struct tda18212_priv { - struct tda18212_config *cfg; - struct i2c_adapter *i2c; +struct tda18212_dev { + struct tda18212_config cfg; + struct i2c_client *client; + struct regmap *regmap; u32 if_frequency; }; -/* write multiple registers */ -static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, - int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (1 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, - int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[2] = { - { - .addr = priv->cfg->i2c_address, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, - "%s: i2c rd reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) -{ - return tda18212_wr_regs(priv, reg, &val, 1); -} - -/* read single register */ -static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) -{ - return tda18212_rd_regs(priv, reg, val, 1); -} - -#if 0 /* keep, useful when developing driver */ -static void tda18212_dump_regs(struct tda18212_priv *priv) -{ - int i; - u8 buf[256]; - - #define TDA18212_RD_LEN 32 - for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) - tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); - - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, - sizeof(buf), true); - - return; -} -#endif - static int tda18212_set_params(struct dvb_frontend *fe) { - struct tda18212_priv *priv = fe->tuner_priv; + struct tda18212_dev *dev = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_khz; @@ -166,9 +60,9 @@ static int tda18212_set_params(struct dvb_frontend *fe) [ATSC_QAM] = { 0x7d, 0x20, 0x63 }, }; - dev_dbg(&priv->i2c->dev, - "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", - __func__, c->delivery_system, c->frequency, + dev_dbg(&dev->client->dev, + "delivery_system=%d frequency=%d bandwidth_hz=%d\n", + c->delivery_system, c->frequency, c->bandwidth_hz); if (fe->ops.i2c_gate_ctrl) @@ -176,25 +70,25 @@ static int tda18212_set_params(struct dvb_frontend *fe) switch (c->delivery_system) { case SYS_ATSC: - if_khz = priv->cfg->if_atsc_vsb; + if_khz = dev->cfg.if_atsc_vsb; i = ATSC_VSB; break; case SYS_DVBC_ANNEX_B: - if_khz = priv->cfg->if_atsc_qam; + if_khz = dev->cfg.if_atsc_qam; i = ATSC_QAM; break; case SYS_DVBT: switch (c->bandwidth_hz) { case 6000000: - if_khz = priv->cfg->if_dvbt_6; + if_khz = dev->cfg.if_dvbt_6; i = DVBT_6; break; case 7000000: - if_khz = priv->cfg->if_dvbt_7; + if_khz = dev->cfg.if_dvbt_7; i = DVBT_7; break; case 8000000: - if_khz = priv->cfg->if_dvbt_8; + if_khz = dev->cfg.if_dvbt_8; i = DVBT_8; break; default: @@ -205,15 +99,15 @@ static int tda18212_set_params(struct dvb_frontend *fe) case SYS_DVBT2: switch (c->bandwidth_hz) { case 6000000: - if_khz = priv->cfg->if_dvbt2_6; + if_khz = dev->cfg.if_dvbt2_6; i = DVBT2_6; break; case 7000000: - if_khz = priv->cfg->if_dvbt2_7; + if_khz = dev->cfg.if_dvbt2_7; i = DVBT2_7; break; case 8000000: - if_khz = priv->cfg->if_dvbt2_8; + if_khz = dev->cfg.if_dvbt2_8; i = DVBT2_8; break; default: @@ -223,7 +117,7 @@ static int tda18212_set_params(struct dvb_frontend *fe) break; case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C: - if_khz = priv->cfg->if_dvbc; + if_khz = dev->cfg.if_dvbc; i = DVBC_8; break; default: @@ -231,15 +125,15 @@ static int tda18212_set_params(struct dvb_frontend *fe) goto error; } - ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); + ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]); if (ret) goto error; - ret = tda18212_wr_reg(priv, 0x06, 0x00); + ret = regmap_write(dev->regmap, 0x06, 0x00); if (ret) goto error; - ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); + ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]); if (ret) goto error; @@ -252,12 +146,12 @@ static int tda18212_set_params(struct dvb_frontend *fe) buf[6] = ((c->frequency / 1000) >> 0) & 0xff; buf[7] = 0xc1; buf[8] = 0x01; - ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); + ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf)); if (ret) goto error; /* actual IF rounded as it is on register */ - priv->if_frequency = buf[3] * 50 * 1000; + dev->if_frequency = buf[3] * 50 * 1000; exit: if (fe->ops.i2c_gate_ctrl) @@ -266,26 +160,19 @@ exit: return ret; error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); goto exit; } static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct tda18212_priv *priv = fe->tuner_priv; + struct tda18212_dev *dev = fe->tuner_priv; - *frequency = priv->if_frequency; + *frequency = dev->if_frequency; return 0; } -static int tda18212_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops tda18212_tuner_ops = { .info = { .name = "NXP TDA18212", @@ -295,53 +182,110 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = { .frequency_step = 1000, }, - .release = tda18212_release, - .set_params = tda18212_set_params, .get_if_frequency = tda18212_get_if_frequency, }; -struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg) +static int tda18212_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct tda18212_priv *priv = NULL; + struct tda18212_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct tda18212_dev *dev; int ret; - u8 val; + unsigned int chip_id; + char *version; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; - priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; + } - priv->cfg = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; + memcpy(&dev->cfg, cfg, sizeof(struct tda18212_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; + } + /* check if the tuner is there */ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - /* check if the tuner is there */ - ret = tda18212_rd_reg(priv, 0x00, &val); + ret = regmap_read(dev->regmap, 0x00, &chip_id); + dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - if (!ret) - dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val); - if (ret || val != 0xc7) { - kfree(priv); - return NULL; + if (ret) + goto err; + + switch (chip_id) { + case 0xc7: + version = "M"; /* master */ + break; + case 0x47: + version = "S"; /* slave */ + break; + default: + ret = -ENODEV; + goto err; } - dev_info(&priv->i2c->dev, - "%s: NXP TDA18212HN successfully identified\n", - KBUILD_MODNAME); + dev_info(&dev->client->dev, + "NXP TDA18212HN/%s successfully identified\n", version); + fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, - sizeof(struct dvb_tuner_ops)); + sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, dev); - return fe; + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + kfree(dev); + return ret; } -EXPORT_SYMBOL(tda18212_attach); + +static int tda18212_remove(struct i2c_client *client) +{ + struct tda18212_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 tda18212_id[] = { + {"tda18212", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tda18212_id); + +static struct i2c_driver tda18212_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tda18212", + }, + .probe = tda18212_probe, + .remove = tda18212_remove, + .id_table = tda18212_id, +}; + +module_i2c_driver(tda18212_driver); MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h index c36b49e4b274..e58c9096d79c 100644 --- a/drivers/media/tuners/tda18212.h +++ b/drivers/media/tuners/tda18212.h @@ -25,8 +25,6 @@ #include "dvb_frontend.h" struct tda18212_config { - u8 i2c_address; - u16 if_dvbt_6; u16 if_dvbt_7; u16 if_dvbt_8; @@ -37,18 +35,11 @@ struct tda18212_config { u16 if_dvbc; u16 if_atsc_vsb; u16 if_atsc_qam; -}; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212) -extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg); -#else -static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; +}; #endif diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 18c77afe2e4f..86e5e3110118 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -714,12 +714,11 @@ fail: return ret; } -int _tda_printk(struct tda18271_priv *state, const char *level, - const char *func, const char *fmt, ...) +void _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...) { struct va_format vaf; va_list args; - int rtn; va_start(args, fmt); @@ -727,15 +726,13 @@ int _tda_printk(struct tda18271_priv *state, const char *level, vaf.va = &args; if (state) - rtn = printk("%s%s: [%d-%04x|%c] %pV", - level, func, i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr, - (state->role == TDA18271_MASTER) ? 'M' : 'S', - &vaf); + printk("%s%s: [%d-%04x|%c] %pV", + level, func, i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr, + (state->role == TDA18271_MASTER) ? 'M' : 'S', + &vaf); else - rtn = printk("%s%s: %pV", level, func, &vaf); + printk("%s%s: %pV", level, func, &vaf); va_end(args); - - return rtn; } diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h index 454c152ccaa0..b36a7b754772 100644 --- a/drivers/media/tuners/tda18271-priv.h +++ b/drivers/media/tuners/tda18271-priv.h @@ -139,8 +139,8 @@ extern int tda18271_debug; #define DBG_CAL 16 __attribute__((format(printf, 4, 5))) -int _tda_printk(struct tda18271_priv *state, const char *level, - const char *func, const char *fmt, ...); +void _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...); #define tda_printk(st, lvl, fmt, arg...) \ _tda_printk(st, lvl, __func__, fmt, ##arg) diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 565eeebb3aeb..d12f5e4ad8bf 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -178,67 +178,67 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { - if (type & BASE) + if (type & BASE) printk("BASE "); - if (type & INIT1) + if (type & INIT1) printk("INIT1 "); - if (type & F8MHZ) + if (type & F8MHZ) printk("F8MHZ "); - if (type & MTS) + if (type & MTS) printk("MTS "); - if (type & D2620) + if (type & D2620) printk("D2620 "); - if (type & D2633) + if (type & D2633) printk("D2633 "); - if (type & DTV6) + if (type & DTV6) printk("DTV6 "); - if (type & QAM) + if (type & QAM) printk("QAM "); - if (type & DTV7) + if (type & DTV7) printk("DTV7 "); - if (type & DTV78) + if (type & DTV78) printk("DTV78 "); - if (type & DTV8) + if (type & DTV8) printk("DTV8 "); - if (type & FM) + if (type & FM) printk("FM "); - if (type & INPUT1) + if (type & INPUT1) printk("INPUT1 "); - if (type & LCD) + if (type & LCD) printk("LCD "); - if (type & NOGD) + if (type & NOGD) printk("NOGD "); - if (type & MONO) + if (type & MONO) printk("MONO "); - if (type & ATSC) + if (type & ATSC) printk("ATSC "); - if (type & IF) + if (type & IF) printk("IF "); - if (type & LG60) + if (type & LG60) printk("LG60 "); - if (type & ATI638) + if (type & ATI638) printk("ATI638 "); - if (type & OREN538) + if (type & OREN538) printk("OREN538 "); - if (type & OREN36) + if (type & OREN36) printk("OREN36 "); - if (type & TOYOTA388) + if (type & TOYOTA388) printk("TOYOTA388 "); - if (type & TOYOTA794) + if (type & TOYOTA794) printk("TOYOTA794 "); - if (type & DIBCOM52) + if (type & DIBCOM52) printk("DIBCOM52 "); - if (type & ZARLINK456) + if (type & ZARLINK456) printk("ZARLINK456 "); - if (type & CHINA) + if (type & CHINA) printk("CHINA "); - if (type & F6MHZ) + if (type & F6MHZ) printk("F6MHZ "); - if (type & INPUT2) + if (type & INPUT2) printk("INPUT2 "); - if (type & SCODE) + if (type & SCODE) printk("SCODE "); - if (type & HAS_IF) + if (type & HAS_IF) printk("HAS_IF_%d ", int_freq); } diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c deleted file mode 100644 index 3d83c425bccf..000000000000 --- a/drivers/media/tuners/tuner_it913x.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * ITE Tech IT9137 silicon tuner driver - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9137 Copyright (C) ITE Tech Inc. - * - * 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 "tuner_it913x_priv.h" - -struct it913x_state { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - u8 chip_ver; - u8 tuner_type; - u8 firmware_ver; - u16 tun_xtal; - u8 tun_fdiv; - u8 tun_clk_mode; - u32 tun_fn_min; -}; - -/* read multiple registers */ -static int it913x_rd_regs(struct it913x_state *state, - u32 reg, u8 *data, u8 count) -{ - int ret; - u8 b[3]; - struct i2c_msg msg[2] = { - { .addr = state->i2c_addr, .flags = 0, - .buf = b, .len = sizeof(b) }, - { .addr = state->i2c_addr, .flags = I2C_M_RD, - .buf = data, .len = count } - }; - b[0] = (u8)(reg >> 16) & 0xff; - b[1] = (u8)(reg >> 8) & 0xff; - b[2] = (u8) reg & 0xff; - b[0] |= 0x80; /* All reads from demodulator */ - - ret = i2c_transfer(state->i2c_adap, msg, 2); - - return ret; -} - -/* read single register */ -static int it913x_rd_reg(struct it913x_state *state, u32 reg) -{ - int ret; - u8 b[1]; - ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); - return (ret < 0) ? -ENODEV : b[0]; -} - -/* write multiple registers */ -static int it913x_wr_regs(struct it913x_state *state, - u8 pro, u32 reg, u8 buf[], u8 count) -{ - u8 b[256]; - struct i2c_msg msg[1] = { - { .addr = state->i2c_addr, .flags = 0, - .buf = b, .len = 3 + count } - }; - int ret; - b[0] = (u8)(reg >> 16) & 0xff; - b[1] = (u8)(reg >> 8) & 0xff; - b[2] = (u8) reg & 0xff; - memcpy(&b[3], buf, count); - - if (pro == PRO_DMOD) - b[0] |= 0x80; - - ret = i2c_transfer(state->i2c_adap, msg, 1); - - if (ret < 0) - return -EIO; - - return 0; -} - -/* write single register */ -static int it913x_wr_reg(struct it913x_state *state, - u8 pro, u32 reg, u32 data) -{ - int ret; - u8 b[4]; - u8 s; - - b[0] = data >> 24; - b[1] = (data >> 16) & 0xff; - b[2] = (data >> 8) & 0xff; - b[3] = data & 0xff; - /* expand write as needed */ - if (data < 0x100) - s = 3; - else if (data < 0x1000) - s = 2; - else if (data < 0x100000) - s = 1; - else - s = 0; - - ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s); - - return ret; -} - -static int it913x_script_loader(struct it913x_state *state, - struct it913xset *loadscript) -{ - int ret, i; - if (loadscript == NULL) - return -EINVAL; - - for (i = 0; i < 1000; ++i) { - if (loadscript[i].pro == 0xff) - break; - ret = it913x_wr_regs(state, loadscript[i].pro, - loadscript[i].address, - loadscript[i].reg, loadscript[i].count); - if (ret < 0) - return -ENODEV; - } - return 0; -} - -static int it913x_init(struct dvb_frontend *fe) -{ - struct it913x_state *state = fe->tuner_priv; - int ret, i, reg; - u8 val, nv_val; - u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; - u8 b[2]; - - reg = it913x_rd_reg(state, 0xec86); - switch (reg) { - case 0: - state->tun_clk_mode = reg; - state->tun_xtal = 2000; - state->tun_fdiv = 3; - val = 16; - break; - case -ENODEV: - return -ENODEV; - case 1: - default: - state->tun_clk_mode = reg; - state->tun_xtal = 640; - state->tun_fdiv = 1; - val = 6; - break; - } - - reg = it913x_rd_reg(state, 0xed03); - - if (reg < 0) - return -ENODEV; - else if (reg < ARRAY_SIZE(nv)) - nv_val = nv[reg]; - else - nv_val = 2; - - for (i = 0; i < 50; i++) { - ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b)); - reg = (b[1] << 8) + b[0]; - if (reg > 0) - break; - if (ret < 0) - return -ENODEV; - udelay(2000); - } - state->tun_fn_min = state->tun_xtal * reg; - state->tun_fn_min /= (state->tun_fdiv * nv_val); - dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, - state->tun_fn_min); - - if (state->chip_ver > 1) - msleep(50); - else { - for (i = 0; i < 50; i++) { - reg = it913x_rd_reg(state, 0xec82); - if (reg > 0) - break; - if (reg < 0) - return -ENODEV; - udelay(2000); - } - } - - /* Power Up Tuner - common all versions */ - ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0); - - return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); -} - -static int it9137_set_params(struct dvb_frontend *fe) -{ - struct it913x_state *state = fe->tuner_priv; - struct it913xset *set_tuner = set_it9137_template; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 bandwidth = p->bandwidth_hz; - u32 frequency_m = p->frequency; - int ret, reg; - u32 frequency = frequency_m / 1000; - u32 freq, temp_f, tmp; - u16 iqik_m_cal; - u16 n_div; - u8 n; - u8 l_band; - u8 lna_band; - u8 bw; - - if (state->firmware_ver == 1) - set_tuner = set_it9135_template; - else - set_tuner = set_it9137_template; - - dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", - __func__, frequency, bandwidth); - - if (frequency >= 51000 && frequency <= 440000) { - l_band = 0; - lna_band = 0; - } else if (frequency > 440000 && frequency <= 484000) { - l_band = 1; - lna_band = 1; - } else if (frequency > 484000 && frequency <= 533000) { - l_band = 1; - lna_band = 2; - } else if (frequency > 533000 && frequency <= 587000) { - l_band = 1; - lna_band = 3; - } else if (frequency > 587000 && frequency <= 645000) { - l_band = 1; - lna_band = 4; - } else if (frequency > 645000 && frequency <= 710000) { - l_band = 1; - lna_band = 5; - } else if (frequency > 710000 && frequency <= 782000) { - l_band = 1; - lna_band = 6; - } else if (frequency > 782000 && frequency <= 860000) { - l_band = 1; - lna_band = 7; - } else if (frequency > 1450000 && frequency <= 1492000) { - l_band = 1; - lna_band = 0; - } else if (frequency > 1660000 && frequency <= 1685000) { - l_band = 1; - lna_band = 1; - } else - return -EINVAL; - set_tuner[0].reg[0] = lna_band; - - switch (bandwidth) { - case 5000000: - bw = 0; - break; - case 6000000: - bw = 2; - break; - case 7000000: - bw = 4; - break; - default: - case 8000000: - bw = 6; - break; - } - - set_tuner[1].reg[0] = bw; - set_tuner[2].reg[0] = 0xa0 | (l_band << 3); - - if (frequency > 53000 && frequency <= 74000) { - n_div = 48; - n = 0; - } else if (frequency > 74000 && frequency <= 111000) { - n_div = 32; - n = 1; - } else if (frequency > 111000 && frequency <= 148000) { - n_div = 24; - n = 2; - } else if (frequency > 148000 && frequency <= 222000) { - n_div = 16; - n = 3; - } else if (frequency > 222000 && frequency <= 296000) { - n_div = 12; - n = 4; - } else if (frequency > 296000 && frequency <= 445000) { - n_div = 8; - n = 5; - } else if (frequency > 445000 && frequency <= state->tun_fn_min) { - n_div = 6; - n = 6; - } else if (frequency > state->tun_fn_min && frequency <= 950000) { - n_div = 4; - n = 7; - } else if (frequency > 1450000 && frequency <= 1680000) { - n_div = 2; - n = 0; - } else - return -EINVAL; - - reg = it913x_rd_reg(state, 0xed81); - iqik_m_cal = (u16)reg * n_div; - - if (reg < 0x20) { - if (state->tun_clk_mode == 0) - iqik_m_cal = (iqik_m_cal * 9) >> 5; - else - iqik_m_cal >>= 1; - } else { - iqik_m_cal = 0x40 - iqik_m_cal; - if (state->tun_clk_mode == 0) - iqik_m_cal = ~((iqik_m_cal * 9) >> 5); - else - iqik_m_cal = ~(iqik_m_cal >> 1); - } - - temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv; - freq = temp_f / state->tun_xtal; - tmp = freq * state->tun_xtal; - - if ((temp_f - tmp) >= (state->tun_xtal >> 1)) - freq++; - - freq += (u32) n << 13; - /* Frequency OMEGA_IQIK_M_CAL_MID*/ - temp_f = freq + (u32)iqik_m_cal; - - set_tuner[3].reg[0] = temp_f & 0xff; - set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; - - dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", - __func__, temp_f); - - /* Lower frequency */ - set_tuner[5].reg[0] = freq & 0xff; - set_tuner[6].reg[0] = (freq >> 8) & 0xff; - - dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n", - __func__, freq); - - ret = it913x_script_loader(state, set_tuner); - - return (ret < 0) ? -ENODEV : 0; -} - -/* Power sequence */ -/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ -/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ - -static int it913x_sleep(struct dvb_frontend *fe) -{ - struct it913x_state *state = fe->tuner_priv; - return it913x_script_loader(state, it9137_tuner_off); -} - -static int it913x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - return 0; -} - -static const struct dvb_tuner_ops it913x_tuner_ops = { - .info = { - .name = "ITE Tech IT913X", - .frequency_min = 174000000, - .frequency_max = 862000000, - }, - - .release = it913x_release, - - .init = it913x_init, - .sleep = it913x_sleep, - .set_params = it9137_set_params, -}; - -struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config) -{ - struct it913x_state *state = NULL; - int ret; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->i2c_adap = i2c_adap; - state->i2c_addr = i2c_addr; - - switch (config) { - case AF9033_TUNER_IT9135_38: - case AF9033_TUNER_IT9135_51: - case AF9033_TUNER_IT9135_52: - state->chip_ver = 0x01; - break; - case AF9033_TUNER_IT9135_60: - case AF9033_TUNER_IT9135_61: - case AF9033_TUNER_IT9135_62: - state->chip_ver = 0x02; - break; - default: - dev_dbg(&i2c_adap->dev, - "%s: invalid config=%02x\n", __func__, config); - goto error; - } - - state->tuner_type = config; - state->firmware_ver = 1; - - /* tuner RF initial */ - ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); - if (ret < 0) - goto error; - - fe->tuner_priv = state; - memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - dev_info(&i2c_adap->dev, - "%s: ITE Tech IT913X successfully attached\n", - KBUILD_MODNAME); - dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n", - __func__, config, state->chip_ver); - - return fe; -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(it913x_attach); - -MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h deleted file mode 100644 index ce652108aa5d..000000000000 --- a/drivers/media/tuners/tuner_it913x_priv.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ITE Tech IT9137 silicon tuner driver - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9137 Copyright (C) ITE Tech Inc. - * - * 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 IT913X_PRIV_H -#define IT913X_PRIV_H - -#include "tuner_it913x.h" -#include "af9033.h" - -#define PRO_LINK 0x0 -#define PRO_DMOD 0x1 -#define TRIGGER_OFSM 0x0000 - -struct it913xset { u32 pro; - u32 address; - u8 reg[15]; - u8 count; -}; - -/* Tuner setting scripts (still keeping it9137) */ -static struct it913xset it9137_tuner_off[] = { - {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ - {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ - {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, - {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}, 0x0c}, - {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, - {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}, 0x09}, - {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00}, 0x0a}, - {PRO_DMOD, 0xec20, {0x00}, 0x01}, - {PRO_DMOD, 0xec3f, {0x01}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -static struct it913xset set_it9135_template[] = { - {PRO_DMOD, 0xee06, {0x00}, 0x01}, - {PRO_DMOD, 0xec56, {0x00}, 0x01}, - {PRO_DMOD, 0xec4c, {0x00}, 0x01}, - {PRO_DMOD, 0xec4d, {0x00}, 0x01}, - {PRO_DMOD, 0xec4e, {0x00}, 0x01}, - {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */ - {PRO_DMOD, 0x011f, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -static struct it913xset set_it9137_template[] = { - {PRO_DMOD, 0xee06, {0x00}, 0x01}, - {PRO_DMOD, 0xec56, {0x00}, 0x01}, - {PRO_DMOD, 0xec4c, {0x00}, 0x01}, - {PRO_DMOD, 0xec4d, {0x00}, 0x01}, - {PRO_DMOD, 0xec4e, {0x00}, 0x01}, - {PRO_DMOD, 0xec4f, {0x00}, 0x01}, - {PRO_DMOD, 0xec50, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -#endif diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index f9ab79e3432d..219ebafae70f 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -569,67 +569,67 @@ static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { - if (type & BASE) + if (type & BASE) printk(KERN_CONT "BASE "); - if (type & INIT1) + if (type & INIT1) printk(KERN_CONT "INIT1 "); - if (type & F8MHZ) + if (type & F8MHZ) printk(KERN_CONT "F8MHZ "); - if (type & MTS) + if (type & MTS) printk(KERN_CONT "MTS "); - if (type & D2620) + if (type & D2620) printk(KERN_CONT "D2620 "); - if (type & D2633) + if (type & D2633) printk(KERN_CONT "D2633 "); - if (type & DTV6) + if (type & DTV6) printk(KERN_CONT "DTV6 "); - if (type & QAM) + if (type & QAM) printk(KERN_CONT "QAM "); - if (type & DTV7) + if (type & DTV7) printk(KERN_CONT "DTV7 "); - if (type & DTV78) + if (type & DTV78) printk(KERN_CONT "DTV78 "); - if (type & DTV8) + if (type & DTV8) printk(KERN_CONT "DTV8 "); - if (type & FM) + if (type & FM) printk(KERN_CONT "FM "); - if (type & INPUT1) + if (type & INPUT1) printk(KERN_CONT "INPUT1 "); - if (type & LCD) + if (type & LCD) printk(KERN_CONT "LCD "); - if (type & NOGD) + if (type & NOGD) printk(KERN_CONT "NOGD "); - if (type & MONO) + if (type & MONO) printk(KERN_CONT "MONO "); - if (type & ATSC) + if (type & ATSC) printk(KERN_CONT "ATSC "); - if (type & IF) + if (type & IF) printk(KERN_CONT "IF "); - if (type & LG60) + if (type & LG60) printk(KERN_CONT "LG60 "); - if (type & ATI638) + if (type & ATI638) printk(KERN_CONT "ATI638 "); - if (type & OREN538) + if (type & OREN538) printk(KERN_CONT "OREN538 "); - if (type & OREN36) + if (type & OREN36) printk(KERN_CONT "OREN36 "); - if (type & TOYOTA388) + if (type & TOYOTA388) printk(KERN_CONT "TOYOTA388 "); - if (type & TOYOTA794) + if (type & TOYOTA794) printk(KERN_CONT "TOYOTA794 "); - if (type & DIBCOM52) + if (type & DIBCOM52) printk(KERN_CONT "DIBCOM52 "); - if (type & ZARLINK456) + if (type & ZARLINK456) printk(KERN_CONT "ZARLINK456 "); - if (type & CHINA) + if (type & CHINA) printk(KERN_CONT "CHINA "); - if (type & F6MHZ) + if (type & F6MHZ) printk(KERN_CONT "F6MHZ "); - if (type & INPUT2) + if (type & INPUT2) printk(KERN_CONT "INPUT2 "); - if (type & SCODE) + if (type & SCODE) printk(KERN_CONT "SCODE "); - if (type & HAS_IF) + if (type & HAS_IF) printk(KERN_CONT "HAS_IF_%d ", int_freq); } diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index e135760f7d48..e44c8aba6074 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -59,6 +59,7 @@ struct xc5000_priv { u32 freq_hz, freq_offset; u32 bandwidth; u8 video_standard; + unsigned int mode; u8 rf_mode; u8 radio_input; @@ -69,6 +70,8 @@ struct xc5000_priv { struct dvb_frontend *fe; struct delayed_work timer_sleep; + + const struct firmware *firmware; }; /* Misc Defines */ @@ -712,9 +715,50 @@ static void xc_debug_dump(struct xc5000_priv *priv) } } -static int xc5000_set_params(struct dvb_frontend *fe) +static int xc5000_tune_digital(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR + "xc5000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_set_tv_standard(priv, + xc5000_standard[priv->video_standard].video_mode, + xc5000_standard[priv->video_standard].audio_mode, 0); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->if_khz); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->if_khz); + return -EIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); + + if (debug) + xc_debug_dump(priv); + + priv->bandwidth = bw; + + return 0; +} + +static int xc5000_set_digital_params(struct dvb_frontend *fe) { - int ret, b; + int b; struct xc5000_priv *priv = fe->tuner_priv; u32 bw = fe->dtv_property_cache.bandwidth_hz; u32 freq = fe->dtv_property_cache.frequency; @@ -794,43 +838,12 @@ static int xc5000_set_params(struct dvb_frontend *fe) } priv->freq_hz = freq - priv->freq_offset; + priv->mode = V4L2_TUNER_DIGITAL_TV; dprintk(1, "%s() frequency=%d (compensated to %d)\n", __func__, freq, priv->freq_hz); - ret = xc_set_signal_source(priv, priv->rf_mode); - if (ret != 0) { - printk(KERN_ERR - "xc5000: xc_set_signal_source(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_set_tv_standard(priv, - xc5000_standard[priv->video_standard].video_mode, - xc5000_standard[priv->video_standard].audio_mode, 0); - if (ret != 0) { - printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); - return -EREMOTEIO; - } - - ret = xc_set_IF_frequency(priv, priv->if_khz); - if (ret != 0) { - printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", - priv->if_khz); - return -EIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); - - if (debug) - xc_debug_dump(priv); - - priv->bandwidth = bw; - - return 0; + return xc5000_tune_digital(fe); } static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) @@ -852,12 +865,10 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) return ret; } -static int xc5000_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static void xc5000_config_tv(struct dvb_frontend *fe, + struct analog_parameters *params) { struct xc5000_priv *priv = fe->tuner_priv; - u16 pll_lock_status; - int ret; dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", __func__, params->frequency); @@ -876,42 +887,49 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe, if (params->std & V4L2_STD_MN) { /* default to BTSC audio standard */ priv->video_standard = MN_NTSC_PAL_BTSC; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_BG) { /* default to NICAM audio standard */ priv->video_standard = BG_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_I) { /* default to NICAM audio standard */ priv->video_standard = I_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_DK) { /* default to NICAM audio standard */ priv->video_standard = DK_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_DK) { /* default to A2 DK1 audio standard */ priv->video_standard = DK_SECAM_A2DK1; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_L) { priv->video_standard = L_SECAM_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_LC) { priv->video_standard = LC_SECAM_NICAM; - goto tune_channel; + return; } +} + +static int xc5000_set_tv_freq(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 pll_lock_status; + int ret; tune_channel: ret = xc_set_signal_source(priv, priv->rf_mode); @@ -955,12 +973,11 @@ tune_channel: return 0; } -static int xc5000_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static int xc5000_config_radio(struct dvb_frontend *fe, + struct analog_parameters *params) + { struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - u8 radio_input; dprintk(1, "%s() frequency=%d (in units of khz)\n", __func__, params->frequency); @@ -970,6 +987,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EINVAL; } + priv->freq_hz = params->frequency * 125 / 2; + priv->rf_mode = XC_RF_MODE_AIR; + + return 0; +} + +static int xc5000_set_radio_freq(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u8 radio_input; + if (priv->radio_input == XC5000_RADIO_FM1) radio_input = FM_RADIO_INPUT1; else if (priv->radio_input == XC5000_RADIO_FM2) @@ -982,10 +1011,6 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EINVAL; } - priv->freq_hz = params->frequency * 125 / 2; - - priv->rf_mode = XC_RF_MODE_AIR; - ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode, xc5000_standard[radio_input].audio_mode, radio_input); @@ -1013,34 +1038,53 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return 0; } -static int xc5000_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static int xc5000_set_params(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - if (priv->i2c_props.adap == NULL) - return -EINVAL; if (xc_load_fw_and_init_tuner(fe, 0) != 0) { dprintk(1, "Unable to load firmware and init tuner\n"); return -EINVAL; } + switch (priv->mode) { + case V4L2_TUNER_RADIO: + return xc5000_set_radio_freq(fe); + case V4L2_TUNER_ANALOG_TV: + return xc5000_set_tv_freq(fe); + case V4L2_TUNER_DIGITAL_TV: + return xc5000_tune_digital(fe); + } + + return 0; +} + +static int xc5000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + if (priv->i2c_props.adap == NULL) + return -EINVAL; + switch (params->mode) { case V4L2_TUNER_RADIO: - ret = xc5000_set_radio_freq(fe, params); + ret = xc5000_config_radio(fe, params); + if (ret) + return ret; break; case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = xc5000_set_tv_freq(fe, params); + xc5000_config_tv(fe, params); + break; + default: break; } + priv->mode = params->mode; - return ret; + return xc5000_set_params(fe); } - static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1094,20 +1138,23 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) if (!force && xc5000_is_firmware_loaded(fe) == 0) return 0; - ret = request_firmware(&fw, desired_fw->name, - priv->i2c_props.adap->dev.parent); - if (ret) { - printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); - return ret; - } - - dprintk(1, "firmware read %Zu bytes.\n", fw->size); + if (!priv->firmware) { + ret = request_firmware(&fw, desired_fw->name, + priv->i2c_props.adap->dev.parent); + if (ret) { + pr_err("xc5000: Upload failed. rc %d\n", ret); + return ret; + } + dprintk(1, "firmware read %Zu bytes.\n", fw->size); - if (fw->size != desired_fw->size) { - printk(KERN_ERR "xc5000: Firmware file with incorrect size\n"); - ret = -EINVAL; - goto err; - } + if (fw->size != desired_fw->size) { + pr_err("xc5000: Firmware file with incorrect size\n"); + release_firmware(fw); + return -EINVAL; + } + priv->firmware = fw; + } else + fw = priv->firmware; /* Try up to 5 times to load firmware */ for (i = 0; i < 5; i++) { @@ -1190,7 +1237,6 @@ err: else printk(KERN_CONT " - too many retries. Giving up\n"); - release_firmware(fw); return ret; } @@ -1229,6 +1275,38 @@ static int xc5000_sleep(struct dvb_frontend *fe) return 0; } +static int xc5000_suspend(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + cancel_delayed_work(&priv->timer_sleep); + + ret = xc5000_tuner_reset(fe); + if (ret != 0) + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __func__); + + return 0; +} + +static int xc5000_resume(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + /* suspended before firmware is loaded. + Avoid firmware load in resume path. */ + if (!priv->firmware) + return 0; + + return xc5000_set_params(fe); +} + static int xc5000_init(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1256,6 +1334,8 @@ static int xc5000_release(struct dvb_frontend *fe) if (priv) { cancel_delayed_work(&priv->timer_sleep); hybrid_tuner_release_state(priv); + if (priv->firmware) + release_firmware(priv->firmware); } mutex_unlock(&xc5000_list_mutex); @@ -1293,9 +1373,11 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .release = xc5000_release, .init = xc5000_init, .sleep = xc5000_sleep, + .suspend = xc5000_suspend, + .resume = xc5000_resume, .set_config = xc5000_set_config, - .set_params = xc5000_set_params, + .set_params = xc5000_set_digital_params, .set_analog_params = xc5000_set_analog_params, .get_frequency = xc5000_get_frequency, .get_if_frequency = xc5000_get_if_frequency, |