linux/drivers/media/tuners/tda18250.c
Uwe Kleine-König ed5c2f5fd1 i2c: Make remove callback return void
The value returned by an i2c driver's remove function is mostly ignored.
(Only an error message is printed if the value is non-zero that the
error is ignored.)

So change the prototype of the remove function to return no value. This
way driver authors are not tempted to assume that passing an error to
the upper layer is a good idea. All drivers are adapted accordingly.
There is no intended change of behaviour, all callbacks were prepared to
return 0 before.

Reviewed-by: Peter Senna Tschudin <peter.senna@gmail.com>
Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Crt Mori <cmo@melexis.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Marek Behún <kabel@kernel.org> # for leds-turris-omnia
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Petr Machata <petrm@nvidia.com> # for mlxsw
Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> # for surface3_power
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> # for bmc150-accel-i2c + kxcjk-1013
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> # for media/* + staging/media/*
Acked-by: Miguel Ojeda <ojeda@kernel.org> # for auxdisplay/ht16k33 + auxdisplay/lcd2s
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # for versaclock5
Reviewed-by: Ajay Gupta <ajayg@nvidia.com> # for ucsi_ccg
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> # for iio
Acked-by: Peter Rosin <peda@axentia.se> # for i2c-mux-*, max9860
Acked-by: Adrien Grassein <adrien.grassein@gmail.com> # for lontium-lt8912b
Reviewed-by: Jean Delvare <jdelvare@suse.de> # for hwmon, i2c-core and i2c/muxes
Acked-by: Corey Minyard <cminyard@mvista.com> # for IPMI
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com> # for drivers/power
Acked-by: Krzysztof Hałasa <khalasa@piap.pl>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
2022-08-16 12:46:26 +02:00

891 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* NXP TDA18250 silicon tuner driver
*
* Copyright (C) 2017 Olli Salonen <olli.salonen@iki.fi>
*/
#include "tda18250_priv.h"
#include <linux/regmap.h>
static const struct dvb_tuner_ops tda18250_ops;
static int tda18250_power_control(struct dvb_frontend *fe,
unsigned int power_state)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
int ret;
unsigned int utmp;
dev_dbg(&client->dev, "power state: %d", power_state);
switch (power_state) {
case TDA18250_POWER_NORMAL:
ret = regmap_write_bits(dev->regmap, R06_POWER2, 0x07, 0x00);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R25_REF, 0xc0, 0xc0);
if (ret)
goto err;
break;
case TDA18250_POWER_STANDBY:
if (dev->loopthrough) {
ret = regmap_write_bits(dev->regmap,
R25_REF, 0xc0, 0x80);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R06_POWER2, 0x07, 0x02);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R10_LT1, 0x80, 0x00);
if (ret)
goto err;
} else {
ret = regmap_write_bits(dev->regmap,
R25_REF, 0xc0, 0x80);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R06_POWER2, 0x07, 0x01);
if (ret)
goto err;
ret = regmap_read(dev->regmap,
R0D_AGC12, &utmp);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R0D_AGC12, 0x03, 0x03);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R10_LT1, 0x80, 0x80);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R0D_AGC12, 0x03, utmp & 0x03);
if (ret)
goto err;
}
break;
default:
ret = -EINVAL;
goto err;
}
return 0;
err:
return ret;
}
static int tda18250_wait_for_irq(struct dvb_frontend *fe,
int maxwait, int step, u8 irq)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
int ret;
unsigned long timeout;
bool triggered;
unsigned int utmp;
triggered = false;
timeout = jiffies + msecs_to_jiffies(maxwait);
while (!time_after(jiffies, timeout)) {
// check for the IRQ
ret = regmap_read(dev->regmap, R08_IRQ1, &utmp);
if (ret)
goto err;
if ((utmp & irq) == irq) {
triggered = true;
break;
}
msleep(step);
}
dev_dbg(&client->dev, "waited IRQ (0x%02x) %d ms, triggered: %s", irq,
jiffies_to_msecs(jiffies) -
(jiffies_to_msecs(timeout) - maxwait),
triggered ? "true" : "false");
if (!triggered)
return -ETIMEDOUT;
return 0;
err:
return ret;
}
static int tda18250_init(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
int ret, i;
/* default values for various regs */
static const u8 init_regs[][2] = {
{ R0C_AGC11, 0xc7 },
{ R0D_AGC12, 0x5d },
{ R0E_AGC13, 0x40 },
{ R0F_AGC14, 0x0e },
{ R10_LT1, 0x47 },
{ R11_LT2, 0x4e },
{ R12_AGC21, 0x26 },
{ R13_AGC22, 0x60 },
{ R18_AGC32, 0x37 },
{ R19_AGC33, 0x09 },
{ R1A_AGCK, 0x00 },
{ R1E_WI_FI, 0x29 },
{ R1F_RF_BPF, 0x06 },
{ R20_IR_MIX, 0xc6 },
{ R21_IF_AGC, 0x00 },
{ R2C_PS1, 0x75 },
{ R2D_PS2, 0x06 },
{ R2E_PS3, 0x07 },
{ R30_RSSI2, 0x0e },
{ R31_IRQ_CTRL, 0x00 },
{ R39_SD5, 0x00 },
{ R3B_REGU, 0x55 },
{ R3C_RCCAL1, 0xa7 },
{ R3F_IRCAL2, 0x85 },
{ R40_IRCAL3, 0x87 },
{ R41_IRCAL4, 0xc0 },
{ R43_PD1, 0x40 },
{ R44_PD2, 0xc0 },
{ R46_CPUMP, 0x0c },
{ R47_LNAPOL, 0x64 },
{ R4B_XTALOSC1, 0x30 },
{ R59_AGC2_UP2, 0x05 },
{ R5B_AGC_AUTO, 0x07 },
{ R5C_AGC_DEBUG, 0x00 },
};
/* crystal related regs depend on frequency */
static const u8 xtal_regs[][5] = {
/* reg: 4d 4e 4f 50 51 */
[TDA18250_XTAL_FREQ_16MHZ] = { 0x3e, 0x80, 0x50, 0x00, 0x20 },
[TDA18250_XTAL_FREQ_24MHZ] = { 0x5d, 0xc0, 0xec, 0x00, 0x18 },
[TDA18250_XTAL_FREQ_25MHZ] = { 0x61, 0xa8, 0xec, 0x80, 0x19 },
[TDA18250_XTAL_FREQ_27MHZ] = { 0x69, 0x78, 0x8d, 0x80, 0x1b },
[TDA18250_XTAL_FREQ_30MHZ] = { 0x75, 0x30, 0x8f, 0x00, 0x1e },
};
dev_dbg(&client->dev, "\n");
ret = tda18250_power_control(fe, TDA18250_POWER_NORMAL);
if (ret)
goto err;
msleep(20);
if (dev->warm)
goto warm;
/* set initial register values */
for (i = 0; i < ARRAY_SIZE(init_regs); i++) {
ret = regmap_write(dev->regmap, init_regs[i][0],
init_regs[i][1]);
if (ret)
goto err;
}
/* set xtal related regs */
ret = regmap_bulk_write(dev->regmap, R4D_XTALFLX1,
xtal_regs[dev->xtal_freq], 5);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R10_LT1, 0x80,
dev->loopthrough ? 0x00 : 0x80);
if (ret)
goto err;
/* clear IRQ */
ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_HW_INIT);
if (ret)
goto err;
/* start HW init */
ret = regmap_write(dev->regmap, R2A_MSM1, 0x70);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0x01);
if (ret)
goto err;
ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_HW_INIT);
if (ret)
goto err;
/* tuner calibration */
ret = regmap_write(dev->regmap, R2A_MSM1, 0x02);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0x01);
if (ret)
goto err;
ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_CAL);
if (ret)
goto err;
dev->warm = true;
warm:
/* power up LNA */
ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00);
if (ret)
goto err;
return 0;
err:
dev_dbg(&client->dev, "failed=%d", ret);
return ret;
}
static int tda18250_set_agc(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 utmp, utmp2;
dev_dbg(&client->dev, "\n");
ret = regmap_write_bits(dev->regmap, R1F_RF_BPF, 0x87, 0x06);
if (ret)
goto err;
utmp = ((c->frequency < 100000000) &&
((c->delivery_system == SYS_DVBC_ANNEX_A) ||
(c->delivery_system == SYS_DVBC_ANNEX_C)) &&
(c->bandwidth_hz == 6000000)) ? 0x80 : 0x00;
ret = regmap_write(dev->regmap, R5A_H3H5, utmp);
if (ret)
goto err;
/* AGC1 */
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
utmp = 4;
break;
default: /* DVB-C/QAM */
switch (c->bandwidth_hz) {
case 6000000:
utmp = (c->frequency < 800000000) ? 6 : 4;
break;
default: /* 7.935 and 8 MHz */
utmp = (c->frequency < 100000000) ? 2 : 3;
break;
}
break;
}
ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x07, utmp);
if (ret)
goto err;
/* AGC2 */
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
utmp = (c->frequency < 320000000) ? 20 : 16;
utmp2 = (c->frequency < 320000000) ? 22 : 18;
break;
default: /* DVB-C/QAM */
switch (c->bandwidth_hz) {
case 6000000:
if (c->frequency < 600000000) {
utmp = 18;
utmp2 = 22;
} else if (c->frequency < 800000000) {
utmp = 16;
utmp2 = 20;
} else {
utmp = 14;
utmp2 = 16;
}
break;
default: /* 7.935 and 8 MHz */
utmp = (c->frequency < 320000000) ? 16 : 18;
utmp2 = (c->frequency < 320000000) ? 18 : 20;
break;
}
break;
}
ret = regmap_write_bits(dev->regmap, R58_AGC2_UP1, 0x1f, utmp2+8);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R13_AGC22, 0x1f, utmp);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x1f, utmp2);
if (ret)
goto err;
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
utmp = 98;
break;
default: /* DVB-C/QAM */
utmp = 90;
break;
}
ret = regmap_write_bits(dev->regmap, R16_AGC25, 0xf8, utmp);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R12_AGC21, 0x60,
(c->frequency > 800000000) ? 0x40 : 0x20);
if (ret)
goto err;
/* AGC3 */
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
utmp = (c->frequency < 320000000) ? 5 : 7;
utmp2 = (c->frequency < 320000000) ? 10 : 12;
break;
default: /* DVB-C/QAM */
utmp = 7;
utmp2 = 12;
break;
}
ret = regmap_write(dev->regmap, R17_AGC31, (utmp << 4) | utmp2);
if (ret)
goto err;
/* S2D */
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
if (c->bandwidth_hz == 8000000)
utmp = 0x04;
else
utmp = (c->frequency < 320000000) ? 0x04 : 0x02;
break;
default: /* DVB-C/QAM */
if (c->bandwidth_hz == 6000000)
utmp = ((c->frequency > 172544000) &&
(c->frequency < 320000000)) ? 0x04 : 0x02;
else /* 7.935 and 8 MHz */
utmp = ((c->frequency > 320000000) &&
(c->frequency < 600000000)) ? 0x02 : 0x04;
break;
}
ret = regmap_write_bits(dev->regmap, R20_IR_MIX, 0x06, utmp);
if (ret)
goto err;
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
utmp = 0;
break;
default: /* DVB-C/QAM */
utmp = (c->frequency < 600000000) ? 0 : 3;
break;
}
ret = regmap_write_bits(dev->regmap, R16_AGC25, 0x03, utmp);
if (ret)
goto err;
utmp = 0x09;
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
if (c->bandwidth_hz == 8000000)
utmp = 0x0c;
break;
default: /* DVB-C/QAM */
utmp = 0x0c;
break;
}
ret = regmap_write_bits(dev->regmap, R0F_AGC14, 0x3f, utmp);
if (ret)
goto err;
return 0;
err:
dev_dbg(&client->dev, "failed=%d", ret);
return ret;
}
static int tda18250_pll_calc(struct dvb_frontend *fe, u8 *rdiv,
u8 *ndiv, u8 *icp)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
unsigned int uval, exp, lopd, scale;
unsigned long fvco;
ret = regmap_read(dev->regmap, R34_MD1, &uval);
if (ret)
goto err;
exp = (uval & 0x70) >> 4;
if (exp > 5)
exp = 0;
lopd = 1 << (exp - 1);
scale = uval & 0x0f;
fvco = lopd * scale * ((c->frequency / 1000) + dev->if_frequency);
switch (dev->xtal_freq) {
case TDA18250_XTAL_FREQ_16MHZ:
*rdiv = 1;
*ndiv = 0;
*icp = (fvco < 6622000) ? 0x05 : 0x02;
break;
case TDA18250_XTAL_FREQ_24MHZ:
case TDA18250_XTAL_FREQ_25MHZ:
*rdiv = 3;
*ndiv = 1;
*icp = (fvco < 6622000) ? 0x05 : 0x02;
break;
case TDA18250_XTAL_FREQ_27MHZ:
if (fvco < 6643000) {
*rdiv = 2;
*ndiv = 0;
*icp = 0x05;
} else if (fvco < 6811000) {
*rdiv = 2;
*ndiv = 0;
*icp = 0x06;
} else {
*rdiv = 3;
*ndiv = 1;
*icp = 0x02;
}
break;
case TDA18250_XTAL_FREQ_30MHZ:
*rdiv = 2;
*ndiv = 0;
*icp = (fvco < 6811000) ? 0x05 : 0x02;
break;
default:
return -EINVAL;
}
dev_dbg(&client->dev,
"lopd=%d scale=%u fvco=%lu, rdiv=%d ndiv=%d icp=%d",
lopd, scale, fvco, *rdiv, *ndiv, *icp);
return 0;
err:
return ret;
}
static int tda18250_set_params(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 if_khz;
int ret;
unsigned int i, j;
u8 utmp;
u8 buf[3];
#define REG 0
#define MASK 1
#define DVBT_6 2
#define DVBT_7 3
#define DVBT_8 4
#define DVBC_6 5
#define DVBC_8 6
#define ATSC 7
static const u8 delsys_params[][16] = {
[REG] = { 0x22, 0x23, 0x24, 0x21, 0x0d, 0x0c, 0x0f, 0x14,
0x0e, 0x12, 0x58, 0x59, 0x1a, 0x19, 0x1e, 0x30 },
[MASK] = { 0x77, 0xff, 0xff, 0x87, 0xf0, 0x78, 0x07, 0xe0,
0x60, 0x0f, 0x60, 0x0f, 0x33, 0x30, 0x80, 0x06 },
[DVBT_6] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0,
0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 },
[DVBT_7] = { 0x52, 0x03, 0x85, 0x82, 0x40, 0x48, 0x01, 0xe0,
0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 },
[DVBT_8] = { 0x53, 0x03, 0x87, 0x82, 0x40, 0x48, 0x06, 0xe0,
0x60, 0x07, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 },
[DVBC_6] = { 0x32, 0x05, 0x86, 0x82, 0x50, 0x00, 0x06, 0x60,
0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 },
[DVBC_8] = { 0x53, 0x03, 0x88, 0x82, 0x50, 0x00, 0x06, 0x60,
0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 },
[ATSC] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0,
0x40, 0x0e, 0x60, 0x05, 0x03, 0x00, 0x80, 0x04 },
};
dev_dbg(&client->dev,
"delivery_system=%d frequency=%u bandwidth_hz=%u",
c->delivery_system, c->frequency, c->bandwidth_hz);
switch (c->delivery_system) {
case SYS_ATSC:
j = ATSC;
if_khz = dev->if_atsc;
break;
case SYS_DVBT:
case SYS_DVBT2:
if (c->bandwidth_hz == 0) {
ret = -EINVAL;
goto err;
} else if (c->bandwidth_hz <= 6000000) {
j = DVBT_6;
if_khz = dev->if_dvbt_6;
} else if (c->bandwidth_hz <= 7000000) {
j = DVBT_7;
if_khz = dev->if_dvbt_7;
} else if (c->bandwidth_hz <= 8000000) {
j = DVBT_8;
if_khz = dev->if_dvbt_8;
} else {
ret = -EINVAL;
goto err;
}
break;
case SYS_DVBC_ANNEX_A:
case SYS_DVBC_ANNEX_C:
if (c->bandwidth_hz == 0) {
ret = -EINVAL;
goto err;
} else if (c->bandwidth_hz <= 6000000) {
j = DVBC_6;
if_khz = dev->if_dvbc_6;
} else if (c->bandwidth_hz <= 8000000) {
j = DVBC_8;
if_khz = dev->if_dvbc_8;
} else {
ret = -EINVAL;
goto err;
}
break;
default:
ret = -EINVAL;
dev_err(&client->dev, "unsupported delivery system=%d",
c->delivery_system);
goto err;
}
/* set delivery system dependent registers */
for (i = 0; i < 16; i++) {
ret = regmap_write_bits(dev->regmap, delsys_params[REG][i],
delsys_params[MASK][i], delsys_params[j][i]);
if (ret)
goto err;
}
/* set IF if needed */
if (dev->if_frequency != if_khz) {
utmp = DIV_ROUND_CLOSEST(if_khz, 50);
ret = regmap_write(dev->regmap, R26_IF, utmp);
if (ret)
goto err;
dev->if_frequency = if_khz;
dev_dbg(&client->dev, "set IF=%u kHz", if_khz);
}
ret = tda18250_set_agc(fe);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x01);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x00);
if (ret)
goto err;
/* set frequency */
buf[0] = ((c->frequency / 1000) >> 16) & 0xff;
buf[1] = ((c->frequency / 1000) >> 8) & 0xff;
buf[2] = ((c->frequency / 1000) >> 0) & 0xff;
ret = regmap_bulk_write(dev->regmap, R27_RF1, buf, 3);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE);
if (ret)
goto err;
/* initial tune */
ret = regmap_write(dev->regmap, R2A_MSM1, 0x01);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0x01);
if (ret)
goto err;
ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE);
if (ret)
goto err;
/* calc ndiv and rdiv */
ret = tda18250_pll_calc(fe, &buf[0], &buf[1], &buf[2]);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R4F_XTALFLX3, 0xe0,
(buf[0] << 6) | (buf[1] << 5));
if (ret)
goto err;
/* clear IRQ */
ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, 0x00);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R39_SD5, 0x03, 0x00);
if (ret)
goto err;
/* tune again */
ret = regmap_write(dev->regmap, R2A_MSM1, 0x01); /* tune */
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); /* go */
if (ret)
goto err;
ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE);
if (ret)
goto err;
/* pll locking */
msleep(20);
ret = regmap_write_bits(dev->regmap, R2B_MSM2, 0x04, 0x04);
if (ret)
goto err;
msleep(20);
/* restore AGCK */
ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x03);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x40);
if (ret)
goto err;
/* charge pump */
ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, buf[2]);
return 0;
err:
return ret;
}
static int tda18250_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
*frequency = dev->if_frequency * 1000;
return 0;
}
static int tda18250_sleep(struct dvb_frontend *fe)
{
struct i2c_client *client = fe->tuner_priv;
struct tda18250_dev *dev = i2c_get_clientdata(client);
int ret;
dev_dbg(&client->dev, "\n");
/* power down LNA */
ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00);
if (ret)
return ret;
/* set if freq to 0 in order to make sure it's set after wake up */
dev->if_frequency = 0;
ret = tda18250_power_control(fe, TDA18250_POWER_STANDBY);
return ret;
}
static const struct dvb_tuner_ops tda18250_ops = {
.info = {
.name = "NXP TDA18250",
.frequency_min_hz = 42 * MHz,
.frequency_max_hz = 870 * MHz,
},
.init = tda18250_init,
.set_params = tda18250_set_params,
.get_if_frequency = tda18250_get_if_frequency,
.sleep = tda18250_sleep,
};
static int tda18250_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tda18250_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
struct tda18250_dev *dev;
int ret;
unsigned char chip_id[3];
/* some registers are always read from HW */
static const struct regmap_range tda18250_yes_ranges[] = {
regmap_reg_range(R05_POWER1, R0B_IRQ4),
regmap_reg_range(R21_IF_AGC, R21_IF_AGC),
regmap_reg_range(R2A_MSM1, R2B_MSM2),
regmap_reg_range(R2F_RSSI1, R31_IRQ_CTRL),
};
static const struct regmap_access_table tda18250_volatile_table = {
.yes_ranges = tda18250_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(tda18250_yes_ranges),
};
static const struct regmap_config tda18250_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = TDA18250_NUM_REGS - 1,
.volatile_table = &tda18250_volatile_table,
};
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
ret = -ENOMEM;
goto err;
}
i2c_set_clientdata(client, dev);
dev->fe = cfg->fe;
dev->loopthrough = cfg->loopthrough;
if (cfg->xtal_freq < TDA18250_XTAL_FREQ_MAX) {
dev->xtal_freq = cfg->xtal_freq;
} else {
ret = -EINVAL;
dev_err(&client->dev, "xtal_freq invalid=%d", cfg->xtal_freq);
goto err_kfree;
}
dev->if_dvbt_6 = cfg->if_dvbt_6;
dev->if_dvbt_7 = cfg->if_dvbt_7;
dev->if_dvbt_8 = cfg->if_dvbt_8;
dev->if_dvbc_6 = cfg->if_dvbc_6;
dev->if_dvbc_8 = cfg->if_dvbc_8;
dev->if_atsc = cfg->if_atsc;
dev->if_frequency = 0;
dev->warm = false;
dev->regmap = devm_regmap_init_i2c(client, &tda18250_regmap_config);
if (IS_ERR(dev->regmap)) {
ret = PTR_ERR(dev->regmap);
goto err_kfree;
}
/* read the three chip ID registers */
regmap_bulk_read(dev->regmap, R00_ID1, &chip_id, 3);
dev_dbg(&client->dev, "chip_id=%02x:%02x:%02x",
chip_id[0], chip_id[1], chip_id[2]);
switch (chip_id[0]) {
case 0xc7:
dev->slave = false;
break;
case 0x47:
dev->slave = true;
break;
default:
ret = -ENODEV;
goto err_kfree;
}
if (chip_id[1] != 0x4a) {
ret = -ENODEV;
goto err_kfree;
}
switch (chip_id[2]) {
case 0x20:
dev_info(&client->dev,
"NXP TDA18250AHN/%s successfully identified",
dev->slave ? "S" : "M");
break;
case 0x21:
dev_info(&client->dev,
"NXP TDA18250BHN/%s successfully identified",
dev->slave ? "S" : "M");
break;
default:
ret = -ENODEV;
goto err_kfree;
}
fe->tuner_priv = client;
memcpy(&fe->ops.tuner_ops, &tda18250_ops,
sizeof(struct dvb_tuner_ops));
/* put the tuner in standby */
tda18250_power_control(fe, TDA18250_POWER_STANDBY);
return 0;
err_kfree:
kfree(dev);
err:
dev_dbg(&client->dev, "failed=%d", ret);
return ret;
}
static void tda18250_remove(struct i2c_client *client)
{
struct tda18250_dev *dev = i2c_get_clientdata(client);
struct dvb_frontend *fe = dev->fe;
dev_dbg(&client->dev, "\n");
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
kfree(dev);
}
static const struct i2c_device_id tda18250_id_table[] = {
{"tda18250", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, tda18250_id_table);
static struct i2c_driver tda18250_driver = {
.driver = {
.name = "tda18250",
},
.probe = tda18250_probe,
.remove = tda18250_remove,
.id_table = tda18250_id_table,
};
module_i2c_driver(tda18250_driver);
MODULE_DESCRIPTION("NXP TDA18250 silicon tuner driver");
MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
MODULE_LICENSE("GPL");