162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP TDA18250 silicon tuner driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Olli Salonen <olli.salonen@iki.fi> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "tda18250_priv.h" 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic const struct dvb_tuner_ops tda18250_ops; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic int tda18250_power_control(struct dvb_frontend *fe, 1462306a36Sopenharmony_ci unsigned int power_state) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 1762306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 1862306a36Sopenharmony_ci int ret; 1962306a36Sopenharmony_ci unsigned int utmp; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci dev_dbg(&client->dev, "power state: %d", power_state); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci switch (power_state) { 2462306a36Sopenharmony_ci case TDA18250_POWER_NORMAL: 2562306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R06_POWER2, 0x07, 0x00); 2662306a36Sopenharmony_ci if (ret) 2762306a36Sopenharmony_ci goto err; 2862306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R25_REF, 0xc0, 0xc0); 2962306a36Sopenharmony_ci if (ret) 3062306a36Sopenharmony_ci goto err; 3162306a36Sopenharmony_ci break; 3262306a36Sopenharmony_ci case TDA18250_POWER_STANDBY: 3362306a36Sopenharmony_ci if (dev->loopthrough) { 3462306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 3562306a36Sopenharmony_ci R25_REF, 0xc0, 0x80); 3662306a36Sopenharmony_ci if (ret) 3762306a36Sopenharmony_ci goto err; 3862306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 3962306a36Sopenharmony_ci R06_POWER2, 0x07, 0x02); 4062306a36Sopenharmony_ci if (ret) 4162306a36Sopenharmony_ci goto err; 4262306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 4362306a36Sopenharmony_ci R10_LT1, 0x80, 0x00); 4462306a36Sopenharmony_ci if (ret) 4562306a36Sopenharmony_ci goto err; 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 4862306a36Sopenharmony_ci R25_REF, 0xc0, 0x80); 4962306a36Sopenharmony_ci if (ret) 5062306a36Sopenharmony_ci goto err; 5162306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 5262306a36Sopenharmony_ci R06_POWER2, 0x07, 0x01); 5362306a36Sopenharmony_ci if (ret) 5462306a36Sopenharmony_ci goto err; 5562306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 5662306a36Sopenharmony_ci R0D_AGC12, &utmp); 5762306a36Sopenharmony_ci if (ret) 5862306a36Sopenharmony_ci goto err; 5962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 6062306a36Sopenharmony_ci R0D_AGC12, 0x03, 0x03); 6162306a36Sopenharmony_ci if (ret) 6262306a36Sopenharmony_ci goto err; 6362306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 6462306a36Sopenharmony_ci R10_LT1, 0x80, 0x80); 6562306a36Sopenharmony_ci if (ret) 6662306a36Sopenharmony_ci goto err; 6762306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, 6862306a36Sopenharmony_ci R0D_AGC12, 0x03, utmp & 0x03); 6962306a36Sopenharmony_ci if (ret) 7062306a36Sopenharmony_ci goto err; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci ret = -EINVAL; 7562306a36Sopenharmony_ci goto err; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_cierr: 8062306a36Sopenharmony_ci return ret; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int tda18250_wait_for_irq(struct dvb_frontend *fe, 8462306a36Sopenharmony_ci int maxwait, int step, u8 irq) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 8762306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 8862306a36Sopenharmony_ci int ret; 8962306a36Sopenharmony_ci unsigned long timeout; 9062306a36Sopenharmony_ci bool triggered; 9162306a36Sopenharmony_ci unsigned int utmp; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci triggered = false; 9462306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(maxwait); 9562306a36Sopenharmony_ci while (!time_after(jiffies, timeout)) { 9662306a36Sopenharmony_ci // check for the IRQ 9762306a36Sopenharmony_ci ret = regmap_read(dev->regmap, R08_IRQ1, &utmp); 9862306a36Sopenharmony_ci if (ret) 9962306a36Sopenharmony_ci goto err; 10062306a36Sopenharmony_ci if ((utmp & irq) == irq) { 10162306a36Sopenharmony_ci triggered = true; 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci msleep(step); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci dev_dbg(&client->dev, "waited IRQ (0x%02x) %d ms, triggered: %s", irq, 10862306a36Sopenharmony_ci jiffies_to_msecs(jiffies) - 10962306a36Sopenharmony_ci (jiffies_to_msecs(timeout) - maxwait), 11062306a36Sopenharmony_ci triggered ? "true" : "false"); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (!triggered) 11362306a36Sopenharmony_ci return -ETIMEDOUT; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_cierr: 11762306a36Sopenharmony_ci return ret; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int tda18250_init(struct dvb_frontend *fe) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 12362306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 12462306a36Sopenharmony_ci int ret, i; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* default values for various regs */ 12762306a36Sopenharmony_ci static const u8 init_regs[][2] = { 12862306a36Sopenharmony_ci { R0C_AGC11, 0xc7 }, 12962306a36Sopenharmony_ci { R0D_AGC12, 0x5d }, 13062306a36Sopenharmony_ci { R0E_AGC13, 0x40 }, 13162306a36Sopenharmony_ci { R0F_AGC14, 0x0e }, 13262306a36Sopenharmony_ci { R10_LT1, 0x47 }, 13362306a36Sopenharmony_ci { R11_LT2, 0x4e }, 13462306a36Sopenharmony_ci { R12_AGC21, 0x26 }, 13562306a36Sopenharmony_ci { R13_AGC22, 0x60 }, 13662306a36Sopenharmony_ci { R18_AGC32, 0x37 }, 13762306a36Sopenharmony_ci { R19_AGC33, 0x09 }, 13862306a36Sopenharmony_ci { R1A_AGCK, 0x00 }, 13962306a36Sopenharmony_ci { R1E_WI_FI, 0x29 }, 14062306a36Sopenharmony_ci { R1F_RF_BPF, 0x06 }, 14162306a36Sopenharmony_ci { R20_IR_MIX, 0xc6 }, 14262306a36Sopenharmony_ci { R21_IF_AGC, 0x00 }, 14362306a36Sopenharmony_ci { R2C_PS1, 0x75 }, 14462306a36Sopenharmony_ci { R2D_PS2, 0x06 }, 14562306a36Sopenharmony_ci { R2E_PS3, 0x07 }, 14662306a36Sopenharmony_ci { R30_RSSI2, 0x0e }, 14762306a36Sopenharmony_ci { R31_IRQ_CTRL, 0x00 }, 14862306a36Sopenharmony_ci { R39_SD5, 0x00 }, 14962306a36Sopenharmony_ci { R3B_REGU, 0x55 }, 15062306a36Sopenharmony_ci { R3C_RCCAL1, 0xa7 }, 15162306a36Sopenharmony_ci { R3F_IRCAL2, 0x85 }, 15262306a36Sopenharmony_ci { R40_IRCAL3, 0x87 }, 15362306a36Sopenharmony_ci { R41_IRCAL4, 0xc0 }, 15462306a36Sopenharmony_ci { R43_PD1, 0x40 }, 15562306a36Sopenharmony_ci { R44_PD2, 0xc0 }, 15662306a36Sopenharmony_ci { R46_CPUMP, 0x0c }, 15762306a36Sopenharmony_ci { R47_LNAPOL, 0x64 }, 15862306a36Sopenharmony_ci { R4B_XTALOSC1, 0x30 }, 15962306a36Sopenharmony_ci { R59_AGC2_UP2, 0x05 }, 16062306a36Sopenharmony_ci { R5B_AGC_AUTO, 0x07 }, 16162306a36Sopenharmony_ci { R5C_AGC_DEBUG, 0x00 }, 16262306a36Sopenharmony_ci }; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* crystal related regs depend on frequency */ 16562306a36Sopenharmony_ci static const u8 xtal_regs[][5] = { 16662306a36Sopenharmony_ci /* reg: 4d 4e 4f 50 51 */ 16762306a36Sopenharmony_ci [TDA18250_XTAL_FREQ_16MHZ] = { 0x3e, 0x80, 0x50, 0x00, 0x20 }, 16862306a36Sopenharmony_ci [TDA18250_XTAL_FREQ_24MHZ] = { 0x5d, 0xc0, 0xec, 0x00, 0x18 }, 16962306a36Sopenharmony_ci [TDA18250_XTAL_FREQ_25MHZ] = { 0x61, 0xa8, 0xec, 0x80, 0x19 }, 17062306a36Sopenharmony_ci [TDA18250_XTAL_FREQ_27MHZ] = { 0x69, 0x78, 0x8d, 0x80, 0x1b }, 17162306a36Sopenharmony_ci [TDA18250_XTAL_FREQ_30MHZ] = { 0x75, 0x30, 0x8f, 0x00, 0x1e }, 17262306a36Sopenharmony_ci }; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci dev_dbg(&client->dev, "\n"); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ret = tda18250_power_control(fe, TDA18250_POWER_NORMAL); 17762306a36Sopenharmony_ci if (ret) 17862306a36Sopenharmony_ci goto err; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci msleep(20); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (dev->warm) 18362306a36Sopenharmony_ci goto warm; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* set initial register values */ 18662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_regs); i++) { 18762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, init_regs[i][0], 18862306a36Sopenharmony_ci init_regs[i][1]); 18962306a36Sopenharmony_ci if (ret) 19062306a36Sopenharmony_ci goto err; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* set xtal related regs */ 19462306a36Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, R4D_XTALFLX1, 19562306a36Sopenharmony_ci xtal_regs[dev->xtal_freq], 5); 19662306a36Sopenharmony_ci if (ret) 19762306a36Sopenharmony_ci goto err; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R10_LT1, 0x80, 20062306a36Sopenharmony_ci dev->loopthrough ? 0x00 : 0x80); 20162306a36Sopenharmony_ci if (ret) 20262306a36Sopenharmony_ci goto err; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* clear IRQ */ 20562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_HW_INIT); 20662306a36Sopenharmony_ci if (ret) 20762306a36Sopenharmony_ci goto err; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* start HW init */ 21062306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2A_MSM1, 0x70); 21162306a36Sopenharmony_ci if (ret) 21262306a36Sopenharmony_ci goto err; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); 21562306a36Sopenharmony_ci if (ret) 21662306a36Sopenharmony_ci goto err; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_HW_INIT); 21962306a36Sopenharmony_ci if (ret) 22062306a36Sopenharmony_ci goto err; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* tuner calibration */ 22362306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2A_MSM1, 0x02); 22462306a36Sopenharmony_ci if (ret) 22562306a36Sopenharmony_ci goto err; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); 22862306a36Sopenharmony_ci if (ret) 22962306a36Sopenharmony_ci goto err; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_CAL); 23262306a36Sopenharmony_ci if (ret) 23362306a36Sopenharmony_ci goto err; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci dev->warm = true; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciwarm: 23862306a36Sopenharmony_ci /* power up LNA */ 23962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00); 24062306a36Sopenharmony_ci if (ret) 24162306a36Sopenharmony_ci goto err; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_cierr: 24562306a36Sopenharmony_ci dev_dbg(&client->dev, "failed=%d", ret); 24662306a36Sopenharmony_ci return ret; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int tda18250_set_agc(struct dvb_frontend *fe) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 25262306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 25362306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 25462306a36Sopenharmony_ci int ret; 25562306a36Sopenharmony_ci u8 utmp, utmp2; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dev_dbg(&client->dev, "\n"); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R1F_RF_BPF, 0x87, 0x06); 26062306a36Sopenharmony_ci if (ret) 26162306a36Sopenharmony_ci goto err; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci utmp = ((c->frequency < 100000000) && 26462306a36Sopenharmony_ci ((c->delivery_system == SYS_DVBC_ANNEX_A) || 26562306a36Sopenharmony_ci (c->delivery_system == SYS_DVBC_ANNEX_C)) && 26662306a36Sopenharmony_ci (c->bandwidth_hz == 6000000)) ? 0x80 : 0x00; 26762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R5A_H3H5, utmp); 26862306a36Sopenharmony_ci if (ret) 26962306a36Sopenharmony_ci goto err; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* AGC1 */ 27262306a36Sopenharmony_ci switch (c->delivery_system) { 27362306a36Sopenharmony_ci case SYS_ATSC: 27462306a36Sopenharmony_ci case SYS_DVBT: 27562306a36Sopenharmony_ci case SYS_DVBT2: 27662306a36Sopenharmony_ci utmp = 4; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci default: /* DVB-C/QAM */ 27962306a36Sopenharmony_ci switch (c->bandwidth_hz) { 28062306a36Sopenharmony_ci case 6000000: 28162306a36Sopenharmony_ci utmp = (c->frequency < 800000000) ? 6 : 4; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci default: /* 7.935 and 8 MHz */ 28462306a36Sopenharmony_ci utmp = (c->frequency < 100000000) ? 2 : 3; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x07, utmp); 29162306a36Sopenharmony_ci if (ret) 29262306a36Sopenharmony_ci goto err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* AGC2 */ 29562306a36Sopenharmony_ci switch (c->delivery_system) { 29662306a36Sopenharmony_ci case SYS_ATSC: 29762306a36Sopenharmony_ci case SYS_DVBT: 29862306a36Sopenharmony_ci case SYS_DVBT2: 29962306a36Sopenharmony_ci utmp = (c->frequency < 320000000) ? 20 : 16; 30062306a36Sopenharmony_ci utmp2 = (c->frequency < 320000000) ? 22 : 18; 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci default: /* DVB-C/QAM */ 30362306a36Sopenharmony_ci switch (c->bandwidth_hz) { 30462306a36Sopenharmony_ci case 6000000: 30562306a36Sopenharmony_ci if (c->frequency < 600000000) { 30662306a36Sopenharmony_ci utmp = 18; 30762306a36Sopenharmony_ci utmp2 = 22; 30862306a36Sopenharmony_ci } else if (c->frequency < 800000000) { 30962306a36Sopenharmony_ci utmp = 16; 31062306a36Sopenharmony_ci utmp2 = 20; 31162306a36Sopenharmony_ci } else { 31262306a36Sopenharmony_ci utmp = 14; 31362306a36Sopenharmony_ci utmp2 = 16; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci default: /* 7.935 and 8 MHz */ 31762306a36Sopenharmony_ci utmp = (c->frequency < 320000000) ? 16 : 18; 31862306a36Sopenharmony_ci utmp2 = (c->frequency < 320000000) ? 18 : 20; 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R58_AGC2_UP1, 0x1f, utmp2+8); 32462306a36Sopenharmony_ci if (ret) 32562306a36Sopenharmony_ci goto err; 32662306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R13_AGC22, 0x1f, utmp); 32762306a36Sopenharmony_ci if (ret) 32862306a36Sopenharmony_ci goto err; 32962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x1f, utmp2); 33062306a36Sopenharmony_ci if (ret) 33162306a36Sopenharmony_ci goto err; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci switch (c->delivery_system) { 33462306a36Sopenharmony_ci case SYS_ATSC: 33562306a36Sopenharmony_ci case SYS_DVBT: 33662306a36Sopenharmony_ci case SYS_DVBT2: 33762306a36Sopenharmony_ci utmp = 98; 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci default: /* DVB-C/QAM */ 34062306a36Sopenharmony_ci utmp = 90; 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R16_AGC25, 0xf8, utmp); 34462306a36Sopenharmony_ci if (ret) 34562306a36Sopenharmony_ci goto err; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R12_AGC21, 0x60, 34862306a36Sopenharmony_ci (c->frequency > 800000000) ? 0x40 : 0x20); 34962306a36Sopenharmony_ci if (ret) 35062306a36Sopenharmony_ci goto err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* AGC3 */ 35362306a36Sopenharmony_ci switch (c->delivery_system) { 35462306a36Sopenharmony_ci case SYS_ATSC: 35562306a36Sopenharmony_ci case SYS_DVBT: 35662306a36Sopenharmony_ci case SYS_DVBT2: 35762306a36Sopenharmony_ci utmp = (c->frequency < 320000000) ? 5 : 7; 35862306a36Sopenharmony_ci utmp2 = (c->frequency < 320000000) ? 10 : 12; 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci default: /* DVB-C/QAM */ 36162306a36Sopenharmony_ci utmp = 7; 36262306a36Sopenharmony_ci utmp2 = 12; 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R17_AGC31, (utmp << 4) | utmp2); 36662306a36Sopenharmony_ci if (ret) 36762306a36Sopenharmony_ci goto err; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* S2D */ 37062306a36Sopenharmony_ci switch (c->delivery_system) { 37162306a36Sopenharmony_ci case SYS_ATSC: 37262306a36Sopenharmony_ci case SYS_DVBT: 37362306a36Sopenharmony_ci case SYS_DVBT2: 37462306a36Sopenharmony_ci if (c->bandwidth_hz == 8000000) 37562306a36Sopenharmony_ci utmp = 0x04; 37662306a36Sopenharmony_ci else 37762306a36Sopenharmony_ci utmp = (c->frequency < 320000000) ? 0x04 : 0x02; 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci default: /* DVB-C/QAM */ 38062306a36Sopenharmony_ci if (c->bandwidth_hz == 6000000) 38162306a36Sopenharmony_ci utmp = ((c->frequency > 172544000) && 38262306a36Sopenharmony_ci (c->frequency < 320000000)) ? 0x04 : 0x02; 38362306a36Sopenharmony_ci else /* 7.935 and 8 MHz */ 38462306a36Sopenharmony_ci utmp = ((c->frequency > 320000000) && 38562306a36Sopenharmony_ci (c->frequency < 600000000)) ? 0x02 : 0x04; 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R20_IR_MIX, 0x06, utmp); 38962306a36Sopenharmony_ci if (ret) 39062306a36Sopenharmony_ci goto err; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci switch (c->delivery_system) { 39362306a36Sopenharmony_ci case SYS_ATSC: 39462306a36Sopenharmony_ci case SYS_DVBT: 39562306a36Sopenharmony_ci case SYS_DVBT2: 39662306a36Sopenharmony_ci utmp = 0; 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci default: /* DVB-C/QAM */ 39962306a36Sopenharmony_ci utmp = (c->frequency < 600000000) ? 0 : 3; 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R16_AGC25, 0x03, utmp); 40362306a36Sopenharmony_ci if (ret) 40462306a36Sopenharmony_ci goto err; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci utmp = 0x09; 40762306a36Sopenharmony_ci switch (c->delivery_system) { 40862306a36Sopenharmony_ci case SYS_ATSC: 40962306a36Sopenharmony_ci case SYS_DVBT: 41062306a36Sopenharmony_ci case SYS_DVBT2: 41162306a36Sopenharmony_ci if (c->bandwidth_hz == 8000000) 41262306a36Sopenharmony_ci utmp = 0x0c; 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci default: /* DVB-C/QAM */ 41562306a36Sopenharmony_ci utmp = 0x0c; 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R0F_AGC14, 0x3f, utmp); 41962306a36Sopenharmony_ci if (ret) 42062306a36Sopenharmony_ci goto err; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_cierr: 42462306a36Sopenharmony_ci dev_dbg(&client->dev, "failed=%d", ret); 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int tda18250_pll_calc(struct dvb_frontend *fe, u8 *rdiv, 42962306a36Sopenharmony_ci u8 *ndiv, u8 *icp) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 43262306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 43362306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 43462306a36Sopenharmony_ci int ret; 43562306a36Sopenharmony_ci unsigned int uval, exp, lopd, scale; 43662306a36Sopenharmony_ci unsigned long fvco; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ret = regmap_read(dev->regmap, R34_MD1, &uval); 43962306a36Sopenharmony_ci if (ret) 44062306a36Sopenharmony_ci goto err; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci exp = (uval & 0x70) >> 4; 44362306a36Sopenharmony_ci if (exp > 5) 44462306a36Sopenharmony_ci exp = 0; 44562306a36Sopenharmony_ci lopd = 1 << (exp - 1); 44662306a36Sopenharmony_ci scale = uval & 0x0f; 44762306a36Sopenharmony_ci fvco = lopd * scale * ((c->frequency / 1000) + dev->if_frequency); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci switch (dev->xtal_freq) { 45062306a36Sopenharmony_ci case TDA18250_XTAL_FREQ_16MHZ: 45162306a36Sopenharmony_ci *rdiv = 1; 45262306a36Sopenharmony_ci *ndiv = 0; 45362306a36Sopenharmony_ci *icp = (fvco < 6622000) ? 0x05 : 0x02; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci case TDA18250_XTAL_FREQ_24MHZ: 45662306a36Sopenharmony_ci case TDA18250_XTAL_FREQ_25MHZ: 45762306a36Sopenharmony_ci *rdiv = 3; 45862306a36Sopenharmony_ci *ndiv = 1; 45962306a36Sopenharmony_ci *icp = (fvco < 6622000) ? 0x05 : 0x02; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case TDA18250_XTAL_FREQ_27MHZ: 46262306a36Sopenharmony_ci if (fvco < 6643000) { 46362306a36Sopenharmony_ci *rdiv = 2; 46462306a36Sopenharmony_ci *ndiv = 0; 46562306a36Sopenharmony_ci *icp = 0x05; 46662306a36Sopenharmony_ci } else if (fvco < 6811000) { 46762306a36Sopenharmony_ci *rdiv = 2; 46862306a36Sopenharmony_ci *ndiv = 0; 46962306a36Sopenharmony_ci *icp = 0x06; 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci *rdiv = 3; 47262306a36Sopenharmony_ci *ndiv = 1; 47362306a36Sopenharmony_ci *icp = 0x02; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci case TDA18250_XTAL_FREQ_30MHZ: 47762306a36Sopenharmony_ci *rdiv = 2; 47862306a36Sopenharmony_ci *ndiv = 0; 47962306a36Sopenharmony_ci *icp = (fvco < 6811000) ? 0x05 : 0x02; 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci default: 48262306a36Sopenharmony_ci return -EINVAL; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci dev_dbg(&client->dev, 48662306a36Sopenharmony_ci "lopd=%d scale=%u fvco=%lu, rdiv=%d ndiv=%d icp=%d", 48762306a36Sopenharmony_ci lopd, scale, fvco, *rdiv, *ndiv, *icp); 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_cierr: 49062306a36Sopenharmony_ci return ret; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int tda18250_set_params(struct dvb_frontend *fe) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 49662306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 49762306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 49862306a36Sopenharmony_ci u32 if_khz; 49962306a36Sopenharmony_ci int ret; 50062306a36Sopenharmony_ci unsigned int i, j; 50162306a36Sopenharmony_ci u8 utmp; 50262306a36Sopenharmony_ci u8 buf[3]; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci #define REG 0 50562306a36Sopenharmony_ci #define MASK 1 50662306a36Sopenharmony_ci #define DVBT_6 2 50762306a36Sopenharmony_ci #define DVBT_7 3 50862306a36Sopenharmony_ci #define DVBT_8 4 50962306a36Sopenharmony_ci #define DVBC_6 5 51062306a36Sopenharmony_ci #define DVBC_8 6 51162306a36Sopenharmony_ci #define ATSC 7 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci static const u8 delsys_params[][16] = { 51462306a36Sopenharmony_ci [REG] = { 0x22, 0x23, 0x24, 0x21, 0x0d, 0x0c, 0x0f, 0x14, 51562306a36Sopenharmony_ci 0x0e, 0x12, 0x58, 0x59, 0x1a, 0x19, 0x1e, 0x30 }, 51662306a36Sopenharmony_ci [MASK] = { 0x77, 0xff, 0xff, 0x87, 0xf0, 0x78, 0x07, 0xe0, 51762306a36Sopenharmony_ci 0x60, 0x0f, 0x60, 0x0f, 0x33, 0x30, 0x80, 0x06 }, 51862306a36Sopenharmony_ci [DVBT_6] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0, 51962306a36Sopenharmony_ci 0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 }, 52062306a36Sopenharmony_ci [DVBT_7] = { 0x52, 0x03, 0x85, 0x82, 0x40, 0x48, 0x01, 0xe0, 52162306a36Sopenharmony_ci 0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 }, 52262306a36Sopenharmony_ci [DVBT_8] = { 0x53, 0x03, 0x87, 0x82, 0x40, 0x48, 0x06, 0xe0, 52362306a36Sopenharmony_ci 0x60, 0x07, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 }, 52462306a36Sopenharmony_ci [DVBC_6] = { 0x32, 0x05, 0x86, 0x82, 0x50, 0x00, 0x06, 0x60, 52562306a36Sopenharmony_ci 0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 }, 52662306a36Sopenharmony_ci [DVBC_8] = { 0x53, 0x03, 0x88, 0x82, 0x50, 0x00, 0x06, 0x60, 52762306a36Sopenharmony_ci 0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 }, 52862306a36Sopenharmony_ci [ATSC] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0, 52962306a36Sopenharmony_ci 0x40, 0x0e, 0x60, 0x05, 0x03, 0x00, 0x80, 0x04 }, 53062306a36Sopenharmony_ci }; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci dev_dbg(&client->dev, 53362306a36Sopenharmony_ci "delivery_system=%d frequency=%u bandwidth_hz=%u", 53462306a36Sopenharmony_ci c->delivery_system, c->frequency, c->bandwidth_hz); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci switch (c->delivery_system) { 53862306a36Sopenharmony_ci case SYS_ATSC: 53962306a36Sopenharmony_ci j = ATSC; 54062306a36Sopenharmony_ci if_khz = dev->if_atsc; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case SYS_DVBT: 54362306a36Sopenharmony_ci case SYS_DVBT2: 54462306a36Sopenharmony_ci if (c->bandwidth_hz == 0) { 54562306a36Sopenharmony_ci ret = -EINVAL; 54662306a36Sopenharmony_ci goto err; 54762306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 6000000) { 54862306a36Sopenharmony_ci j = DVBT_6; 54962306a36Sopenharmony_ci if_khz = dev->if_dvbt_6; 55062306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 7000000) { 55162306a36Sopenharmony_ci j = DVBT_7; 55262306a36Sopenharmony_ci if_khz = dev->if_dvbt_7; 55362306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 8000000) { 55462306a36Sopenharmony_ci j = DVBT_8; 55562306a36Sopenharmony_ci if_khz = dev->if_dvbt_8; 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci ret = -EINVAL; 55862306a36Sopenharmony_ci goto err; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci case SYS_DVBC_ANNEX_A: 56262306a36Sopenharmony_ci case SYS_DVBC_ANNEX_C: 56362306a36Sopenharmony_ci if (c->bandwidth_hz == 0) { 56462306a36Sopenharmony_ci ret = -EINVAL; 56562306a36Sopenharmony_ci goto err; 56662306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 6000000) { 56762306a36Sopenharmony_ci j = DVBC_6; 56862306a36Sopenharmony_ci if_khz = dev->if_dvbc_6; 56962306a36Sopenharmony_ci } else if (c->bandwidth_hz <= 8000000) { 57062306a36Sopenharmony_ci j = DVBC_8; 57162306a36Sopenharmony_ci if_khz = dev->if_dvbc_8; 57262306a36Sopenharmony_ci } else { 57362306a36Sopenharmony_ci ret = -EINVAL; 57462306a36Sopenharmony_ci goto err; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci default: 57862306a36Sopenharmony_ci ret = -EINVAL; 57962306a36Sopenharmony_ci dev_err(&client->dev, "unsupported delivery system=%d", 58062306a36Sopenharmony_ci c->delivery_system); 58162306a36Sopenharmony_ci goto err; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* set delivery system dependent registers */ 58562306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 58662306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, delsys_params[REG][i], 58762306a36Sopenharmony_ci delsys_params[MASK][i], delsys_params[j][i]); 58862306a36Sopenharmony_ci if (ret) 58962306a36Sopenharmony_ci goto err; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* set IF if needed */ 59362306a36Sopenharmony_ci if (dev->if_frequency != if_khz) { 59462306a36Sopenharmony_ci utmp = DIV_ROUND_CLOSEST(if_khz, 50); 59562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R26_IF, utmp); 59662306a36Sopenharmony_ci if (ret) 59762306a36Sopenharmony_ci goto err; 59862306a36Sopenharmony_ci dev->if_frequency = if_khz; 59962306a36Sopenharmony_ci dev_dbg(&client->dev, "set IF=%u kHz", if_khz); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci ret = tda18250_set_agc(fe); 60462306a36Sopenharmony_ci if (ret) 60562306a36Sopenharmony_ci goto err; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x01); 60862306a36Sopenharmony_ci if (ret) 60962306a36Sopenharmony_ci goto err; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x00); 61262306a36Sopenharmony_ci if (ret) 61362306a36Sopenharmony_ci goto err; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* set frequency */ 61662306a36Sopenharmony_ci buf[0] = ((c->frequency / 1000) >> 16) & 0xff; 61762306a36Sopenharmony_ci buf[1] = ((c->frequency / 1000) >> 8) & 0xff; 61862306a36Sopenharmony_ci buf[2] = ((c->frequency / 1000) >> 0) & 0xff; 61962306a36Sopenharmony_ci ret = regmap_bulk_write(dev->regmap, R27_RF1, buf, 3); 62062306a36Sopenharmony_ci if (ret) 62162306a36Sopenharmony_ci goto err; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE); 62462306a36Sopenharmony_ci if (ret) 62562306a36Sopenharmony_ci goto err; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* initial tune */ 62862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2A_MSM1, 0x01); 62962306a36Sopenharmony_ci if (ret) 63062306a36Sopenharmony_ci goto err; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); 63362306a36Sopenharmony_ci if (ret) 63462306a36Sopenharmony_ci goto err; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE); 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci goto err; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* calc ndiv and rdiv */ 64162306a36Sopenharmony_ci ret = tda18250_pll_calc(fe, &buf[0], &buf[1], &buf[2]); 64262306a36Sopenharmony_ci if (ret) 64362306a36Sopenharmony_ci goto err; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R4F_XTALFLX3, 0xe0, 64662306a36Sopenharmony_ci (buf[0] << 6) | (buf[1] << 5)); 64762306a36Sopenharmony_ci if (ret) 64862306a36Sopenharmony_ci goto err; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* clear IRQ */ 65162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE); 65262306a36Sopenharmony_ci if (ret) 65362306a36Sopenharmony_ci goto err; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, 0x00); 65662306a36Sopenharmony_ci if (ret) 65762306a36Sopenharmony_ci goto err; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R39_SD5, 0x03, 0x00); 66062306a36Sopenharmony_ci if (ret) 66162306a36Sopenharmony_ci goto err; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* tune again */ 66462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2A_MSM1, 0x01); /* tune */ 66562306a36Sopenharmony_ci if (ret) 66662306a36Sopenharmony_ci goto err; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); /* go */ 66962306a36Sopenharmony_ci if (ret) 67062306a36Sopenharmony_ci goto err; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE); 67362306a36Sopenharmony_ci if (ret) 67462306a36Sopenharmony_ci goto err; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* pll locking */ 67762306a36Sopenharmony_ci msleep(20); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R2B_MSM2, 0x04, 0x04); 68062306a36Sopenharmony_ci if (ret) 68162306a36Sopenharmony_ci goto err; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci msleep(20); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* restore AGCK */ 68662306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x03); 68762306a36Sopenharmony_ci if (ret) 68862306a36Sopenharmony_ci goto err; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x40); 69162306a36Sopenharmony_ci if (ret) 69262306a36Sopenharmony_ci goto err; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* charge pump */ 69562306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, buf[2]); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_cierr: 69962306a36Sopenharmony_ci return ret; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic int tda18250_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 70562306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci *frequency = dev->if_frequency * 1000; 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int tda18250_sleep(struct dvb_frontend *fe) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct i2c_client *client = fe->tuner_priv; 71462306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 71562306a36Sopenharmony_ci int ret; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci dev_dbg(&client->dev, "\n"); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* power down LNA */ 72062306a36Sopenharmony_ci ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00); 72162306a36Sopenharmony_ci if (ret) 72262306a36Sopenharmony_ci return ret; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* set if freq to 0 in order to make sure it's set after wake up */ 72562306a36Sopenharmony_ci dev->if_frequency = 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = tda18250_power_control(fe, TDA18250_POWER_STANDBY); 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic const struct dvb_tuner_ops tda18250_ops = { 73262306a36Sopenharmony_ci .info = { 73362306a36Sopenharmony_ci .name = "NXP TDA18250", 73462306a36Sopenharmony_ci .frequency_min_hz = 42 * MHz, 73562306a36Sopenharmony_ci .frequency_max_hz = 870 * MHz, 73662306a36Sopenharmony_ci }, 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci .init = tda18250_init, 73962306a36Sopenharmony_ci .set_params = tda18250_set_params, 74062306a36Sopenharmony_ci .get_if_frequency = tda18250_get_if_frequency, 74162306a36Sopenharmony_ci .sleep = tda18250_sleep, 74262306a36Sopenharmony_ci}; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int tda18250_probe(struct i2c_client *client) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct tda18250_config *cfg = client->dev.platform_data; 74762306a36Sopenharmony_ci struct dvb_frontend *fe = cfg->fe; 74862306a36Sopenharmony_ci struct tda18250_dev *dev; 74962306a36Sopenharmony_ci int ret; 75062306a36Sopenharmony_ci unsigned char chip_id[3]; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* some registers are always read from HW */ 75362306a36Sopenharmony_ci static const struct regmap_range tda18250_yes_ranges[] = { 75462306a36Sopenharmony_ci regmap_reg_range(R05_POWER1, R0B_IRQ4), 75562306a36Sopenharmony_ci regmap_reg_range(R21_IF_AGC, R21_IF_AGC), 75662306a36Sopenharmony_ci regmap_reg_range(R2A_MSM1, R2B_MSM2), 75762306a36Sopenharmony_ci regmap_reg_range(R2F_RSSI1, R31_IRQ_CTRL), 75862306a36Sopenharmony_ci }; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci static const struct regmap_access_table tda18250_volatile_table = { 76162306a36Sopenharmony_ci .yes_ranges = tda18250_yes_ranges, 76262306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(tda18250_yes_ranges), 76362306a36Sopenharmony_ci }; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci static const struct regmap_config tda18250_regmap_config = { 76662306a36Sopenharmony_ci .reg_bits = 8, 76762306a36Sopenharmony_ci .val_bits = 8, 76862306a36Sopenharmony_ci .max_register = TDA18250_NUM_REGS - 1, 76962306a36Sopenharmony_ci .volatile_table = &tda18250_volatile_table, 77062306a36Sopenharmony_ci }; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 77362306a36Sopenharmony_ci if (!dev) { 77462306a36Sopenharmony_ci ret = -ENOMEM; 77562306a36Sopenharmony_ci goto err; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci i2c_set_clientdata(client, dev); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci dev->fe = cfg->fe; 78162306a36Sopenharmony_ci dev->loopthrough = cfg->loopthrough; 78262306a36Sopenharmony_ci if (cfg->xtal_freq < TDA18250_XTAL_FREQ_MAX) { 78362306a36Sopenharmony_ci dev->xtal_freq = cfg->xtal_freq; 78462306a36Sopenharmony_ci } else { 78562306a36Sopenharmony_ci ret = -EINVAL; 78662306a36Sopenharmony_ci dev_err(&client->dev, "xtal_freq invalid=%d", cfg->xtal_freq); 78762306a36Sopenharmony_ci goto err_kfree; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci dev->if_dvbt_6 = cfg->if_dvbt_6; 79062306a36Sopenharmony_ci dev->if_dvbt_7 = cfg->if_dvbt_7; 79162306a36Sopenharmony_ci dev->if_dvbt_8 = cfg->if_dvbt_8; 79262306a36Sopenharmony_ci dev->if_dvbc_6 = cfg->if_dvbc_6; 79362306a36Sopenharmony_ci dev->if_dvbc_8 = cfg->if_dvbc_8; 79462306a36Sopenharmony_ci dev->if_atsc = cfg->if_atsc; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci dev->if_frequency = 0; 79762306a36Sopenharmony_ci dev->warm = false; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci dev->regmap = devm_regmap_init_i2c(client, &tda18250_regmap_config); 80062306a36Sopenharmony_ci if (IS_ERR(dev->regmap)) { 80162306a36Sopenharmony_ci ret = PTR_ERR(dev->regmap); 80262306a36Sopenharmony_ci goto err_kfree; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* read the three chip ID registers */ 80662306a36Sopenharmony_ci regmap_bulk_read(dev->regmap, R00_ID1, &chip_id, 3); 80762306a36Sopenharmony_ci dev_dbg(&client->dev, "chip_id=%02x:%02x:%02x", 80862306a36Sopenharmony_ci chip_id[0], chip_id[1], chip_id[2]); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci switch (chip_id[0]) { 81162306a36Sopenharmony_ci case 0xc7: 81262306a36Sopenharmony_ci dev->slave = false; 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci case 0x47: 81562306a36Sopenharmony_ci dev->slave = true; 81662306a36Sopenharmony_ci break; 81762306a36Sopenharmony_ci default: 81862306a36Sopenharmony_ci ret = -ENODEV; 81962306a36Sopenharmony_ci goto err_kfree; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (chip_id[1] != 0x4a) { 82362306a36Sopenharmony_ci ret = -ENODEV; 82462306a36Sopenharmony_ci goto err_kfree; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci switch (chip_id[2]) { 82862306a36Sopenharmony_ci case 0x20: 82962306a36Sopenharmony_ci dev_info(&client->dev, 83062306a36Sopenharmony_ci "NXP TDA18250AHN/%s successfully identified", 83162306a36Sopenharmony_ci dev->slave ? "S" : "M"); 83262306a36Sopenharmony_ci break; 83362306a36Sopenharmony_ci case 0x21: 83462306a36Sopenharmony_ci dev_info(&client->dev, 83562306a36Sopenharmony_ci "NXP TDA18250BHN/%s successfully identified", 83662306a36Sopenharmony_ci dev->slave ? "S" : "M"); 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci default: 83962306a36Sopenharmony_ci ret = -ENODEV; 84062306a36Sopenharmony_ci goto err_kfree; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci fe->tuner_priv = client; 84462306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &tda18250_ops, 84562306a36Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* put the tuner in standby */ 84862306a36Sopenharmony_ci tda18250_power_control(fe, TDA18250_POWER_STANDBY); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci return 0; 85162306a36Sopenharmony_cierr_kfree: 85262306a36Sopenharmony_ci kfree(dev); 85362306a36Sopenharmony_cierr: 85462306a36Sopenharmony_ci dev_dbg(&client->dev, "failed=%d", ret); 85562306a36Sopenharmony_ci return ret; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic void tda18250_remove(struct i2c_client *client) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct tda18250_dev *dev = i2c_get_clientdata(client); 86162306a36Sopenharmony_ci struct dvb_frontend *fe = dev->fe; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci dev_dbg(&client->dev, "\n"); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); 86662306a36Sopenharmony_ci fe->tuner_priv = NULL; 86762306a36Sopenharmony_ci kfree(dev); 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic const struct i2c_device_id tda18250_id_table[] = { 87162306a36Sopenharmony_ci {"tda18250", 0}, 87262306a36Sopenharmony_ci {} 87362306a36Sopenharmony_ci}; 87462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tda18250_id_table); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic struct i2c_driver tda18250_driver = { 87762306a36Sopenharmony_ci .driver = { 87862306a36Sopenharmony_ci .name = "tda18250", 87962306a36Sopenharmony_ci }, 88062306a36Sopenharmony_ci .probe = tda18250_probe, 88162306a36Sopenharmony_ci .remove = tda18250_remove, 88262306a36Sopenharmony_ci .id_table = tda18250_id_table, 88362306a36Sopenharmony_ci}; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cimodule_i2c_driver(tda18250_driver); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP TDA18250 silicon tuner driver"); 88862306a36Sopenharmony_ciMODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>"); 88962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 890