// 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, 0 x07, 0 x00);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R25_REF, 0 xc0, 0 xc0);
if (ret)
goto err;
break ;
case TDA18250_POWER_STANDBY:
if (dev->loopthrough) {
ret = regmap_write_bits(dev->regmap,
R25_REF, 0 xc0, 0 x80);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R06_POWER2, 0 x07, 0 x02);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R10_LT1, 0 x80, 0 x00);
if (ret)
goto err;
} else {
ret = regmap_write_bits(dev->regmap,
R25_REF, 0 xc0, 0 x80);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R06_POWER2, 0 x07, 0 x01);
if (ret)
goto err;
ret = regmap_read(dev->regmap,
R0D_AGC12, &utmp);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R0D_AGC12, 0 x03, 0 x03);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R10_LT1, 0 x80, 0 x80);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap,
R0D_AGC12, 0 x03, utmp & 0 x03);
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, 0 xc7 },
{ R0D_AGC12, 0 x5d },
{ R0E_AGC13, 0 x40 },
{ R0F_AGC14, 0 x0e },
{ R10_LT1, 0 x47 },
{ R11_LT2, 0 x4e },
{ R12_AGC21, 0 x26 },
{ R13_AGC22, 0 x60 },
{ R18_AGC32, 0 x37 },
{ R19_AGC33, 0 x09 },
{ R1A_AGCK, 0 x00 },
{ R1E_WI_FI, 0 x29 },
{ R1F_RF_BPF, 0 x06 },
{ R20_IR_MIX, 0 xc6 },
{ R21_IF_AGC, 0 x00 },
{ R2C_PS1, 0 x75 },
{ R2D_PS2, 0 x06 },
{ R2E_PS3, 0 x07 },
{ R30_RSSI2, 0 x0e },
{ R31_IRQ_CTRL, 0 x00 },
{ R39_SD5, 0 x00 },
{ R3B_REGU, 0 x55 },
{ R3C_RCCAL1, 0 xa7 },
{ R3F_IRCAL2, 0 x85 },
{ R40_IRCAL3, 0 x87 },
{ R41_IRCAL4, 0 xc0 },
{ R43_PD1, 0 x40 },
{ R44_PD2, 0 xc0 },
{ R46_CPUMP, 0 x0c },
{ R47_LNAPOL, 0 x64 },
{ R4B_XTALOSC1, 0 x30 },
{ R59_AGC2_UP2, 0 x05 },
{ R5B_AGC_AUTO, 0 x07 },
{ R5C_AGC_DEBUG, 0 x00 },
};
/* crystal related regs depend on frequency */
static const u8 xtal_regs[][5 ] = {
/* reg: 4d 4e 4f 50 51 */
[TDA18250_XTAL_FREQ_16MHZ] = { 0 x3e, 0 x80, 0 x50, 0 x00, 0 x20 },
[TDA18250_XTAL_FREQ_24MHZ] = { 0 x5d, 0 xc0, 0 xec, 0 x00, 0 x18 },
[TDA18250_XTAL_FREQ_25MHZ] = { 0 x61, 0 xa8, 0 xec, 0 x80, 0 x19 },
[TDA18250_XTAL_FREQ_27MHZ] = { 0 x69, 0 x78, 0 x8d, 0 x80, 0 x1b },
[TDA18250_XTAL_FREQ_30MHZ] = { 0 x75, 0 x30, 0 x8f, 0 x00, 0 x1e },
};
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, 0 x80,
dev->loopthrough ? 0 x00 : 0 x80);
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, 0 x70);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0 x01);
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, 0 x02);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0 x01);
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, 0 x80, 0 x00);
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, 0 x87, 0 x06);
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 )) ? 0 x80 : 0 x00;
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, 0 x07, 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, 0 x1f, utmp2+8 );
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R13_AGC22, 0 x1f, utmp);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R14_AGC23, 0 x1f, 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, 0 xf8, utmp);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R12_AGC21, 0 x60,
(c->frequency > 800000000 ) ? 0 x40 : 0 x20);
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 = 0 x04;
else
utmp = (c->frequency < 320000000 ) ? 0 x04 : 0 x02;
break ;
default : /* DVB-C/QAM */
if (c->bandwidth_hz == 6000000 )
utmp = ((c->frequency > 172544000 ) &&
(c->frequency < 320000000 )) ? 0 x04 : 0 x02;
else /* 7.935 and 8 MHz */
utmp = ((c->frequency > 320000000 ) &&
(c->frequency < 600000000 )) ? 0 x02 : 0 x04;
break ;
}
ret = regmap_write_bits(dev->regmap, R20_IR_MIX, 0 x06, 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, 0 x03, utmp);
if (ret)
goto err;
utmp = 0 x09;
switch (c->delivery_system) {
case SYS_ATSC:
case SYS_DVBT:
case SYS_DVBT2:
if (c->bandwidth_hz == 8000000 )
utmp = 0 x0c;
break ;
default : /* DVB-C/QAM */
utmp = 0 x0c;
break ;
}
ret = regmap_write_bits(dev->regmap, R0F_AGC14, 0 x3f, 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 & 0 x70) >> 4 ;
if (exp > 5 )
exp = 0 ;
lopd = 1 << (exp - 1 );
scale = uval & 0 x0f;
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 ) ? 0 x05 : 0 x02;
break ;
case TDA18250_XTAL_FREQ_24MHZ:
case TDA18250_XTAL_FREQ_25MHZ:
*rdiv = 3 ;
*ndiv = 1 ;
*icp = (fvco < 6622000 ) ? 0 x05 : 0 x02;
break ;
case TDA18250_XTAL_FREQ_27MHZ:
if (fvco < 6643000 ) {
*rdiv = 2 ;
*ndiv = 0 ;
*icp = 0 x05;
} else if (fvco < 6811000 ) {
*rdiv = 2 ;
*ndiv = 0 ;
*icp = 0 x06;
} else {
*rdiv = 3 ;
*ndiv = 1 ;
*icp = 0 x02;
}
break ;
case TDA18250_XTAL_FREQ_30MHZ:
*rdiv = 2 ;
*ndiv = 0 ;
*icp = (fvco < 6811000 ) ? 0 x05 : 0 x02;
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] = { 0 x22, 0 x23, 0 x24, 0 x21, 0 x0d, 0 x0c, 0 x0f, 0 x14,
0 x0e, 0 x12, 0 x58, 0 x59, 0 x1a, 0 x19, 0 x1e, 0 x30 },
[MASK] = { 0 x77, 0 xff, 0 xff, 0 x87, 0 xf0, 0 x78, 0 x07, 0 xe0,
0 x60, 0 x0f, 0 x60, 0 x0f, 0 x33, 0 x30, 0 x80, 0 x06 },
[DVBT_6] = { 0 x51, 0 x03, 0 x83, 0 x82, 0 x40, 0 x48, 0 x01, 0 xe0,
0 x60, 0 x0f, 0 x60, 0 x05, 0 x03, 0 x10, 0 x00, 0 x04 },
[DVBT_7] = { 0 x52, 0 x03, 0 x85, 0 x82, 0 x40, 0 x48, 0 x01, 0 xe0,
0 x60, 0 x0f, 0 x60, 0 x05, 0 x03, 0 x10, 0 x00, 0 x04 },
[DVBT_8] = { 0 x53, 0 x03, 0 x87, 0 x82, 0 x40, 0 x48, 0 x06, 0 xe0,
0 x60, 0 x07, 0 x60, 0 x05, 0 x03, 0 x10, 0 x00, 0 x04 },
[DVBC_6] = { 0 x32, 0 x05, 0 x86, 0 x82, 0 x50, 0 x00, 0 x06, 0 x60,
0 x40, 0 x0e, 0 x60, 0 x05, 0 x33, 0 x10, 0 x00, 0 x04 },
[DVBC_8] = { 0 x53, 0 x03, 0 x88, 0 x82, 0 x50, 0 x00, 0 x06, 0 x60,
0 x40, 0 x0e, 0 x60, 0 x05, 0 x33, 0 x10, 0 x00, 0 x04 },
[ATSC] = { 0 x51, 0 x03, 0 x83, 0 x82, 0 x40, 0 x48, 0 x01, 0 xe0,
0 x40, 0 x0e, 0 x60, 0 x05, 0 x03, 0 x00, 0 x80, 0 x04 },
};
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, 0 x03, 0 x01);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R14_AGC23, 0 x40, 0 x00);
if (ret)
goto err;
/* set frequency */
buf[0 ] = ((c->frequency / 1000 ) >> 16 ) & 0 xff;
buf[1 ] = ((c->frequency / 1000 ) >> 8 ) & 0 xff;
buf[2 ] = ((c->frequency / 1000 ) >> 0 ) & 0 xff;
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, 0 x01);
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0 x01);
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, 0 xe0,
(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, 0 x07, 0 x00);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R39_SD5, 0 x03, 0 x00);
if (ret)
goto err;
/* tune again */
ret = regmap_write(dev->regmap, R2A_MSM1, 0 x01); /* tune */
if (ret)
goto err;
ret = regmap_write(dev->regmap, R2B_MSM2, 0 x01); /* 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, 0 x04, 0 x04);
if (ret)
goto err;
msleep(20 );
/* restore AGCK */
ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0 x03, 0 x03);
if (ret)
goto err;
ret = regmap_write_bits(dev->regmap, R14_AGC23, 0 x40, 0 x40);
if (ret)
goto err;
/* charge pump */
ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0 x07, 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, 0 x80, 0 x00);
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)
{
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 0 xc7:
dev->slave = false ;
break ;
case 0 x47:
dev->slave = true ;
break ;
default :
ret = -ENODEV;
goto err_kfree;
}
if (chip_id[1 ] != 0 x4a) {
ret = -ENODEV;
goto err_kfree;
}
switch (chip_id[2 ]) {
case 0 x20:
dev_info(&client->dev,
"NXP TDA18250AHN/%s successfully identified" ,
dev->slave ? "S" : "M" );
break ;
case 0 x21:
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" },
{}
};
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" );
Messung V0.5 in Prozent C=95 H=91 G=92
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-08)
¤
*© Formatika GbR, Deutschland