diff mbox series

[1/3] m88ds3103: Add support for ds3103b demod

Message ID 20200201214826.22873-2-brad@nextdimension.cc (mailing list archive)
State New, archived
Headers show
Series m88ds3103: Add support for Montage 3103b DVB-S demod | expand

Commit Message

Brad Love Feb. 1, 2020, 9:48 p.m. UTC
The ds3103b demodulator identifies as an m88rs600, but requires different
clock settings and firmware, along with differences in register settings.

Changes were reverse engineered using an instrumented downstream GPLv2
driver to compare i2c traffic and clocking. The mclk functions are from
the downstream GPLv2 driver.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/dvb-frontends/m88ds3103.c      | 466 ++++++++++++++++++-
 drivers/media/dvb-frontends/m88ds3103_priv.h |  14 +-
 2 files changed, 467 insertions(+), 13 deletions(-)

Comments

kernel test robot Feb. 3, 2020, 10:03 a.m. UTC | #1
Hi Brad,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on v5.5 next-20200203]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Brad-Love/m88ds3103-Add-support-for-Montage-3103b-DVB-S-demod/20200203-135639
base:   git://linuxtv.org/media_tree.git master
config: i386-randconfig-b001-20200202 (attached as .config)
compiler: gcc-7 (Debian 7.5.0-3) 7.5.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/media/dvb-frontends/m88ds3103.c: In function 'm88ds3103_set_frontend':
>> drivers/media/dvb-frontends/m88ds3103.c:906:6: warning: this statement may fall through [-Wimplicit-fallthrough=]
      if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
         ^
   drivers/media/dvb-frontends/m88ds3103.c:911:2: note: here
     default:
     ^~~~~~~

vim +906 drivers/media/dvb-frontends/m88ds3103.c

   623	
   624	static int m88ds3103_set_frontend(struct dvb_frontend *fe)
   625	{
   626		struct m88ds3103_dev *dev = fe->demodulator_priv;
   627		struct i2c_client *client = dev->client;
   628		struct dtv_frontend_properties *c = &fe->dtv_property_cache;
   629		int ret, len;
   630		const struct m88ds3103_reg_val *init;
   631		u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
   632		u8 buf[3];
   633		u16 u16tmp;
   634		u32 tuner_frequency_khz, target_mclk, u32tmp;
   635		s32 s32tmp;
   636		static const struct reg_sequence reset_buf[] = {
   637			{0x07, 0x80}, {0x07, 0x00}
   638		};
   639	
   640		dev_dbg(&client->dev,
   641			"delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
   642			c->delivery_system, c->modulation, c->frequency, c->symbol_rate,
   643			c->inversion, c->pilot, c->rolloff);
   644	
   645		if (!dev->warm) {
   646			ret = -EAGAIN;
   647			goto err;
   648		}
   649	
   650		/* reset */
   651		ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2);
   652		if (ret)
   653			goto err;
   654	
   655		/* Disable demod clock path */
   656		if (dev->chip_id == M88RS6000_CHIP_ID) {
   657			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   658				ret = regmap_read(dev->regmap, 0xb2, &u32tmp);
   659				if (ret)
   660					goto err;
   661				if (u32tmp == 0x01) {
   662					ret = regmap_write(dev->regmap, 0x00, 0x00);
   663					if (ret)
   664						goto err;
   665					ret = regmap_write(dev->regmap, 0xb2, 0x00);
   666					if (ret)
   667						goto err;
   668				}
   669			}
   670	
   671			ret = regmap_write(dev->regmap, 0x06, 0xe0);
   672			if (ret)
   673				goto err;
   674		}
   675	
   676		/* program tuner */
   677		if (fe->ops.tuner_ops.set_params) {
   678			ret = fe->ops.tuner_ops.set_params(fe);
   679			if (ret)
   680				goto err;
   681		}
   682	
   683		if (fe->ops.tuner_ops.get_frequency) {
   684			ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency_khz);
   685			if (ret)
   686				goto err;
   687		} else {
   688			/*
   689			 * Use nominal target frequency as tuner driver does not provide
   690			 * actual frequency used. Carrier offset calculation is not
   691			 * valid.
   692			 */
   693			tuner_frequency_khz = c->frequency;
   694		}
   695	
   696		/* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */
   697		if (dev->chip_id == M88RS6000_CHIP_ID) {
   698			if (c->symbol_rate > 45010000)
   699				dev->mclk = 110250000;
   700			else
   701				dev->mclk = 96000000;
   702	
   703			if (c->delivery_system == SYS_DVBS)
   704				target_mclk = 96000000;
   705			else
   706				target_mclk = 144000000;
   707	
   708			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   709				m88ds3103b_select_mclk(dev);
   710				m88ds3103b_set_mclk(dev, target_mclk / 1000);
   711			}
   712	
   713			/* Enable demod clock path */
   714			ret = regmap_write(dev->regmap, 0x06, 0x00);
   715			if (ret)
   716				goto err;
   717			usleep_range(10000, 20000);
   718		} else {
   719		/* set M88DS3103 mclk and ts mclk. */
   720			dev->mclk = 96000000;
   721	
   722			switch (dev->cfg->ts_mode) {
   723			case M88DS3103_TS_SERIAL:
   724			case M88DS3103_TS_SERIAL_D7:
   725				target_mclk = dev->cfg->ts_clk;
   726				break;
   727			case M88DS3103_TS_PARALLEL:
   728			case M88DS3103_TS_CI:
   729				if (c->delivery_system == SYS_DVBS)
   730					target_mclk = 96000000;
   731				else {
   732					if (c->symbol_rate < 18000000)
   733						target_mclk = 96000000;
   734					else if (c->symbol_rate < 28000000)
   735						target_mclk = 144000000;
   736					else
   737						target_mclk = 192000000;
   738				}
   739				break;
   740			default:
   741				dev_dbg(&client->dev, "invalid ts_mode\n");
   742				ret = -EINVAL;
   743				goto err;
   744			}
   745	
   746			switch (target_mclk) {
   747			case 96000000:
   748				u8tmp1 = 0x02; /* 0b10 */
   749				u8tmp2 = 0x01; /* 0b01 */
   750				break;
   751			case 144000000:
   752				u8tmp1 = 0x00; /* 0b00 */
   753				u8tmp2 = 0x01; /* 0b01 */
   754				break;
   755			case 192000000:
   756				u8tmp1 = 0x03; /* 0b11 */
   757				u8tmp2 = 0x00; /* 0b00 */
   758				break;
   759			}
   760			ret = m88ds3103_update_bits(dev, 0x22, 0xc0, u8tmp1 << 6);
   761			if (ret)
   762				goto err;
   763			ret = m88ds3103_update_bits(dev, 0x24, 0xc0, u8tmp2 << 6);
   764			if (ret)
   765				goto err;
   766		}
   767	
   768		ret = regmap_write(dev->regmap, 0xb2, 0x01);
   769		if (ret)
   770			goto err;
   771	
   772		ret = regmap_write(dev->regmap, 0x00, 0x01);
   773		if (ret)
   774			goto err;
   775	
   776		switch (c->delivery_system) {
   777		case SYS_DVBS:
   778			if (dev->chip_id == M88RS6000_CHIP_ID) {
   779				len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals);
   780				init = m88rs6000_dvbs_init_reg_vals;
   781			} else {
   782				len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals);
   783				init = m88ds3103_dvbs_init_reg_vals;
   784			}
   785			break;
   786		case SYS_DVBS2:
   787			if (dev->chip_id == M88RS6000_CHIP_ID) {
   788				len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals);
   789				init = m88rs6000_dvbs2_init_reg_vals;
   790			} else {
   791				len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals);
   792				init = m88ds3103_dvbs2_init_reg_vals;
   793			}
   794			break;
   795		default:
   796			dev_dbg(&client->dev, "invalid delivery_system\n");
   797			ret = -EINVAL;
   798			goto err;
   799		}
   800	
   801		/* program init table */
   802		if (c->delivery_system != dev->delivery_system) {
   803			ret = m88ds3103_wr_reg_val_tab(dev, init, len);
   804			if (ret)
   805				goto err;
   806		}
   807	
   808		if (dev->chip_id == M88RS6000_CHIP_ID) {
   809			if (c->delivery_system == SYS_DVBS2 &&
   810			    c->symbol_rate <= 5000000) {
   811				ret = regmap_write(dev->regmap, 0xc0, 0x04);
   812				if (ret)
   813					goto err;
   814				buf[0] = 0x09;
   815				buf[1] = 0x22;
   816				buf[2] = 0x88;
   817				ret = regmap_bulk_write(dev->regmap, 0x8a, buf, 3);
   818				if (ret)
   819					goto err;
   820			}
   821			ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08);
   822			if (ret)
   823				goto err;
   824	
   825			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   826				buf[0] = m88ds3103b_dt_read(dev, 0x15);
   827				buf[1] = m88ds3103b_dt_read(dev, 0x16);
   828	
   829				if (c->symbol_rate > 45010000) {
   830					buf[0] &= ~0x03;
   831					buf[0] |= 0x02;
   832					buf[0] |= ((147 - 32) >> 8) & 0x01;
   833					buf[1] = (147 - 32) & 0xFF;
   834	
   835					dev->mclk = 110250 * 1000;
   836				} else {
   837					buf[0] &= ~0x03;
   838					buf[0] |= ((128 - 32) >> 8) & 0x01;
   839					buf[1] = (128 - 32) & 0xFF;
   840	
   841					dev->mclk = 96000 * 1000;
   842				}
   843				m88ds3103b_dt_write(dev, 0x15, buf[0]);
   844				m88ds3103b_dt_write(dev, 0x16, buf[1]);
   845	
   846				regmap_read(dev->regmap, 0x30, &u32tmp);
   847				u32tmp &= ~0x80;
   848				regmap_write(dev->regmap, 0x30, u32tmp & 0xff);
   849			}
   850	
   851			ret = regmap_write(dev->regmap, 0xf1, 0x01);
   852			if (ret)
   853				goto err;
   854	
   855			if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) {
   856				ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
   857				if (ret)
   858					goto err;
   859			}
   860		}
   861	
   862		switch (dev->cfg->ts_mode) {
   863		case M88DS3103_TS_SERIAL:
   864			u8tmp1 = 0x00;
   865			u8tmp = 0x06;
   866			break;
   867		case M88DS3103_TS_SERIAL_D7:
   868			u8tmp1 = 0x20;
   869			u8tmp = 0x06;
   870			break;
   871		case M88DS3103_TS_PARALLEL:
   872			u8tmp = 0x02;
   873			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   874				u8tmp = 0x01;
   875				u8tmp1 = 0x01;
   876			}
   877			break;
   878		case M88DS3103_TS_CI:
   879			u8tmp = 0x03;
   880			break;
   881		default:
   882			dev_dbg(&client->dev, "invalid ts_mode\n");
   883			ret = -EINVAL;
   884			goto err;
   885		}
   886	
   887		if (dev->cfg->ts_clk_pol)
   888			u8tmp |= 0x40;
   889	
   890		/* TS mode */
   891		ret = regmap_write(dev->regmap, 0xfd, u8tmp);
   892		if (ret)
   893			goto err;
   894	
   895		switch (dev->cfg->ts_mode) {
   896		case M88DS3103_TS_SERIAL:
   897		case M88DS3103_TS_SERIAL_D7:
   898			ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1);
   899			if (ret)
   900				goto err;
   901			u16tmp = 0;
   902			u8tmp1 = 0x3f;
   903			u8tmp2 = 0x3f;
   904			break;
   905		case M88DS3103_TS_PARALLEL:
 > 906			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   907				ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1);
   908				if (ret)
   909					goto err;
   910			}
   911		default:
   912			u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
   913			u8tmp1 = u16tmp / 2 - 1;
   914			u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1;
   915		}
   916	
   917		dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n",
   918			target_mclk, dev->cfg->ts_clk, u16tmp);
   919	
   920		/* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */
   921		/* u8tmp2[5:0] => ea[5:0] */
   922		u8tmp = (u8tmp1 >> 2) & 0x0f;
   923		ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp);
   924		if (ret)
   925			goto err;
   926		u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0;
   927		ret = regmap_write(dev->regmap, 0xea, u8tmp);
   928		if (ret)
   929			goto err;
   930	
   931		if (c->symbol_rate <= 3000000)
   932			u8tmp = 0x20;
   933		else if (c->symbol_rate <= 10000000)
   934			u8tmp = 0x10;
   935		else
   936			u8tmp = 0x06;
   937	
   938		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
   939			m88ds3103b_set_mclk(dev, target_mclk / 1000);
   940	
   941		ret = regmap_write(dev->regmap, 0xc3, 0x08);
   942		if (ret)
   943			goto err;
   944	
   945		ret = regmap_write(dev->regmap, 0xc8, u8tmp);
   946		if (ret)
   947			goto err;
   948	
   949		ret = regmap_write(dev->regmap, 0xc4, 0x08);
   950		if (ret)
   951			goto err;
   952	
   953		ret = regmap_write(dev->regmap, 0xc7, 0x00);
   954		if (ret)
   955			goto err;
   956	
   957		u16tmp = DIV_ROUND_CLOSEST_ULL((u64)c->symbol_rate * 0x10000, dev->mclk);
   958		buf[0] = (u16tmp >> 0) & 0xff;
   959		buf[1] = (u16tmp >> 8) & 0xff;
   960		ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2);
   961		if (ret)
   962			goto err;
   963	
   964		ret = m88ds3103_update_bits(dev, 0x4d, 0x02, dev->cfg->spec_inv << 1);
   965		if (ret)
   966			goto err;
   967	
   968		ret = m88ds3103_update_bits(dev, 0x30, 0x10, dev->cfg->agc_inv << 4);
   969		if (ret)
   970			goto err;
   971	
   972		ret = regmap_write(dev->regmap, 0x33, dev->cfg->agc);
   973		if (ret)
   974			goto err;
   975	
   976		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   977			/* enable/disable 192M LDPC clock */
   978			ret = m88ds3103_update_bits(dev, 0x29, 0x10,
   979						(c->delivery_system == SYS_DVBS) ? 0x10 : 0x0);
   980			if (ret)
   981				goto err;
   982	
   983			ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08);
   984		}
   985	
   986		dev_dbg(&client->dev, "carrier offset=%d\n",
   987			(tuner_frequency_khz - c->frequency));
   988	
   989		/* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */
   990		s32tmp = 0x10000 * (tuner_frequency_khz - c->frequency);
   991		s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk / 1000);
   992		buf[0] = (s32tmp >> 0) & 0xff;
   993		buf[1] = (s32tmp >> 8) & 0xff;
   994		ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2);
   995		if (ret)
   996			goto err;
   997	
   998		ret = regmap_write(dev->regmap, 0x00, 0x00);
   999		if (ret)
  1000			goto err;
  1001	
  1002		ret = regmap_write(dev->regmap, 0xb2, 0x00);
  1003		if (ret)
  1004			goto err;
  1005	
  1006		dev->delivery_system = c->delivery_system;
  1007	
  1008		return 0;
  1009	err:
  1010		dev_dbg(&client->dev, "failed=%d\n", ret);
  1011		return ret;
  1012	}
  1013	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
kernel test robot Feb. 3, 2020, 11:09 a.m. UTC | #2
Hi Brad,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on v5.5 next-20200203]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Brad-Love/m88ds3103-Add-support-for-Montage-3103b-DVB-S-demod/20200203-135639
base:   git://linuxtv.org/media_tree.git master
config: x86_64-randconfig-d002-20200202 (attached as .config)
compiler: gcc-7 (Debian 7.5.0-3) 7.5.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from arch/x86/include/asm/current.h:5:0,
                    from include/linux/sched.h:12,
                    from include/media/dvb_frontend.h:36,
                    from drivers/media/dvb-frontends/m88ds3103_priv.h:11,
                    from drivers/media/dvb-frontends/m88ds3103.c:8:
   drivers/media/dvb-frontends/m88ds3103.c: In function 'm88ds3103_set_frontend':
   include/linux/compiler.h:56:26: warning: this statement may fall through [-Wimplicit-fallthrough=]
    #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
                             ^
>> drivers/media/dvb-frontends/m88ds3103.c:906:3: note: in expansion of macro 'if'
      if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
      ^~
   drivers/media/dvb-frontends/m88ds3103.c:911:2: note: here
     default:
     ^~~~~~~
   Cyclomatic Complexity 1 arch/x86/include/asm/bitops.h:fls64
   Cyclomatic Complexity 1 include/linux/log2.h:__ilog2_u64
   Cyclomatic Complexity 1 include/linux/math64.h:div_u64_rem
   Cyclomatic Complexity 1 include/linux/math64.h:div_s64_rem
   Cyclomatic Complexity 1 include/linux/math64.h:div_u64
   Cyclomatic Complexity 1 include/linux/math64.h:div_s64
   Cyclomatic Complexity 1 include/linux/err.h:PTR_ERR
   Cyclomatic Complexity 1 include/linux/jiffies.h:_msecs_to_jiffies
   Cyclomatic Complexity 7 include/linux/jiffies.h:msecs_to_jiffies
   Cyclomatic Complexity 4 include/linux/slab.h:kmalloc_type
   Cyclomatic Complexity 84 include/linux/slab.h:kmalloc_index
   Cyclomatic Complexity 1 include/linux/slab.h:kmalloc_large
   Cyclomatic Complexity 10 include/linux/slab.h:kmalloc
   Cyclomatic Complexity 1 include/linux/slab.h:kzalloc
   Cyclomatic Complexity 1 include/linux/device.h:dev_get_drvdata
   Cyclomatic Complexity 1 include/linux/device.h:dev_set_drvdata
   Cyclomatic Complexity 1 include/linux/i2c.h:i2c_get_clientdata
   Cyclomatic Complexity 1 include/linux/i2c.h:i2c_set_clientdata
   Cyclomatic Complexity 1 include/linux/i2c-mux.h:i2c_mux_priv
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_read_ber
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_get_tune_settings
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_get_dvb_frontend
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_get_i2c_adapter
   Cyclomatic Complexity 4 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_get_agc_pwm
   Cyclomatic Complexity 4 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_read_snr
   Cyclomatic Complexity 74 include/asm-generic/getorder.h:get_order
   Cyclomatic Complexity 3 include/linux/err.h:IS_ERR_OR_NULL
   Cyclomatic Complexity 3 include/linux/i2c.h:i2c_client_has_driver
   Cyclomatic Complexity 3 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_attach
   Cyclomatic Complexity 1 include/linux/err.h:IS_ERR
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_driver_init
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_release
   Cyclomatic Complexity 4 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_remove
   Cyclomatic Complexity 19 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_wr_reg_val_tab
   Cyclomatic Complexity 56 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_get_frontend
   Cyclomatic Complexity 7 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_update_bits
   Cyclomatic Complexity 56 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_probe
   Cyclomatic Complexity 10 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_set_voltage
   Cyclomatic Complexity 12 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_set_tone
   Cyclomatic Complexity 31 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_diseqc_send_burst
   Cyclomatic Complexity 35 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_diseqc_send_master_cmd
   Cyclomatic Complexity 16 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_sleep
   Cyclomatic Complexity 82 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_read_status
   Cyclomatic Complexity 6 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103b_dt_read
   Cyclomatic Complexity 6 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103b_dt_write
   Cyclomatic Complexity 30 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103b_select_mclk
   Cyclomatic Complexity 79 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103b_set_mclk
   Cyclomatic Complexity 210 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_set_frontend
   Cyclomatic Complexity 50 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_init
   Cyclomatic Complexity 7 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_select
   Cyclomatic Complexity 1 drivers/media/dvb-frontends/m88ds3103.c:m88ds3103_driver_exit

vim +/if +906 drivers/media/dvb-frontends/m88ds3103.c

   623	
   624	static int m88ds3103_set_frontend(struct dvb_frontend *fe)
   625	{
   626		struct m88ds3103_dev *dev = fe->demodulator_priv;
   627		struct i2c_client *client = dev->client;
   628		struct dtv_frontend_properties *c = &fe->dtv_property_cache;
   629		int ret, len;
   630		const struct m88ds3103_reg_val *init;
   631		u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
   632		u8 buf[3];
   633		u16 u16tmp;
   634		u32 tuner_frequency_khz, target_mclk, u32tmp;
   635		s32 s32tmp;
   636		static const struct reg_sequence reset_buf[] = {
   637			{0x07, 0x80}, {0x07, 0x00}
   638		};
   639	
   640		dev_dbg(&client->dev,
   641			"delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
   642			c->delivery_system, c->modulation, c->frequency, c->symbol_rate,
   643			c->inversion, c->pilot, c->rolloff);
   644	
   645		if (!dev->warm) {
   646			ret = -EAGAIN;
   647			goto err;
   648		}
   649	
   650		/* reset */
   651		ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2);
   652		if (ret)
   653			goto err;
   654	
   655		/* Disable demod clock path */
   656		if (dev->chip_id == M88RS6000_CHIP_ID) {
   657			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   658				ret = regmap_read(dev->regmap, 0xb2, &u32tmp);
   659				if (ret)
   660					goto err;
   661				if (u32tmp == 0x01) {
   662					ret = regmap_write(dev->regmap, 0x00, 0x00);
   663					if (ret)
   664						goto err;
   665					ret = regmap_write(dev->regmap, 0xb2, 0x00);
   666					if (ret)
   667						goto err;
   668				}
   669			}
   670	
   671			ret = regmap_write(dev->regmap, 0x06, 0xe0);
   672			if (ret)
   673				goto err;
   674		}
   675	
   676		/* program tuner */
   677		if (fe->ops.tuner_ops.set_params) {
   678			ret = fe->ops.tuner_ops.set_params(fe);
   679			if (ret)
   680				goto err;
   681		}
   682	
   683		if (fe->ops.tuner_ops.get_frequency) {
   684			ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency_khz);
   685			if (ret)
   686				goto err;
   687		} else {
   688			/*
   689			 * Use nominal target frequency as tuner driver does not provide
   690			 * actual frequency used. Carrier offset calculation is not
   691			 * valid.
   692			 */
   693			tuner_frequency_khz = c->frequency;
   694		}
   695	
   696		/* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */
   697		if (dev->chip_id == M88RS6000_CHIP_ID) {
   698			if (c->symbol_rate > 45010000)
   699				dev->mclk = 110250000;
   700			else
   701				dev->mclk = 96000000;
   702	
   703			if (c->delivery_system == SYS_DVBS)
   704				target_mclk = 96000000;
   705			else
   706				target_mclk = 144000000;
   707	
   708			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   709				m88ds3103b_select_mclk(dev);
   710				m88ds3103b_set_mclk(dev, target_mclk / 1000);
   711			}
   712	
   713			/* Enable demod clock path */
   714			ret = regmap_write(dev->regmap, 0x06, 0x00);
   715			if (ret)
   716				goto err;
   717			usleep_range(10000, 20000);
   718		} else {
   719		/* set M88DS3103 mclk and ts mclk. */
   720			dev->mclk = 96000000;
   721	
   722			switch (dev->cfg->ts_mode) {
   723			case M88DS3103_TS_SERIAL:
   724			case M88DS3103_TS_SERIAL_D7:
   725				target_mclk = dev->cfg->ts_clk;
   726				break;
   727			case M88DS3103_TS_PARALLEL:
   728			case M88DS3103_TS_CI:
   729				if (c->delivery_system == SYS_DVBS)
   730					target_mclk = 96000000;
   731				else {
   732					if (c->symbol_rate < 18000000)
   733						target_mclk = 96000000;
   734					else if (c->symbol_rate < 28000000)
   735						target_mclk = 144000000;
   736					else
   737						target_mclk = 192000000;
   738				}
   739				break;
   740			default:
   741				dev_dbg(&client->dev, "invalid ts_mode\n");
   742				ret = -EINVAL;
   743				goto err;
   744			}
   745	
   746			switch (target_mclk) {
   747			case 96000000:
   748				u8tmp1 = 0x02; /* 0b10 */
   749				u8tmp2 = 0x01; /* 0b01 */
   750				break;
   751			case 144000000:
   752				u8tmp1 = 0x00; /* 0b00 */
   753				u8tmp2 = 0x01; /* 0b01 */
   754				break;
   755			case 192000000:
   756				u8tmp1 = 0x03; /* 0b11 */
   757				u8tmp2 = 0x00; /* 0b00 */
   758				break;
   759			}
   760			ret = m88ds3103_update_bits(dev, 0x22, 0xc0, u8tmp1 << 6);
   761			if (ret)
   762				goto err;
   763			ret = m88ds3103_update_bits(dev, 0x24, 0xc0, u8tmp2 << 6);
   764			if (ret)
   765				goto err;
   766		}
   767	
   768		ret = regmap_write(dev->regmap, 0xb2, 0x01);
   769		if (ret)
   770			goto err;
   771	
   772		ret = regmap_write(dev->regmap, 0x00, 0x01);
   773		if (ret)
   774			goto err;
   775	
   776		switch (c->delivery_system) {
   777		case SYS_DVBS:
   778			if (dev->chip_id == M88RS6000_CHIP_ID) {
   779				len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals);
   780				init = m88rs6000_dvbs_init_reg_vals;
   781			} else {
   782				len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals);
   783				init = m88ds3103_dvbs_init_reg_vals;
   784			}
   785			break;
   786		case SYS_DVBS2:
   787			if (dev->chip_id == M88RS6000_CHIP_ID) {
   788				len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals);
   789				init = m88rs6000_dvbs2_init_reg_vals;
   790			} else {
   791				len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals);
   792				init = m88ds3103_dvbs2_init_reg_vals;
   793			}
   794			break;
   795		default:
   796			dev_dbg(&client->dev, "invalid delivery_system\n");
   797			ret = -EINVAL;
   798			goto err;
   799		}
   800	
   801		/* program init table */
   802		if (c->delivery_system != dev->delivery_system) {
   803			ret = m88ds3103_wr_reg_val_tab(dev, init, len);
   804			if (ret)
   805				goto err;
   806		}
   807	
   808		if (dev->chip_id == M88RS6000_CHIP_ID) {
   809			if (c->delivery_system == SYS_DVBS2 &&
   810			    c->symbol_rate <= 5000000) {
   811				ret = regmap_write(dev->regmap, 0xc0, 0x04);
   812				if (ret)
   813					goto err;
   814				buf[0] = 0x09;
   815				buf[1] = 0x22;
   816				buf[2] = 0x88;
   817				ret = regmap_bulk_write(dev->regmap, 0x8a, buf, 3);
   818				if (ret)
   819					goto err;
   820			}
   821			ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08);
   822			if (ret)
   823				goto err;
   824	
   825			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   826				buf[0] = m88ds3103b_dt_read(dev, 0x15);
   827				buf[1] = m88ds3103b_dt_read(dev, 0x16);
   828	
   829				if (c->symbol_rate > 45010000) {
   830					buf[0] &= ~0x03;
   831					buf[0] |= 0x02;
   832					buf[0] |= ((147 - 32) >> 8) & 0x01;
   833					buf[1] = (147 - 32) & 0xFF;
   834	
   835					dev->mclk = 110250 * 1000;
   836				} else {
   837					buf[0] &= ~0x03;
   838					buf[0] |= ((128 - 32) >> 8) & 0x01;
   839					buf[1] = (128 - 32) & 0xFF;
   840	
   841					dev->mclk = 96000 * 1000;
   842				}
   843				m88ds3103b_dt_write(dev, 0x15, buf[0]);
   844				m88ds3103b_dt_write(dev, 0x16, buf[1]);
   845	
   846				regmap_read(dev->regmap, 0x30, &u32tmp);
   847				u32tmp &= ~0x80;
   848				regmap_write(dev->regmap, 0x30, u32tmp & 0xff);
   849			}
   850	
   851			ret = regmap_write(dev->regmap, 0xf1, 0x01);
   852			if (ret)
   853				goto err;
   854	
   855			if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) {
   856				ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
   857				if (ret)
   858					goto err;
   859			}
   860		}
   861	
   862		switch (dev->cfg->ts_mode) {
   863		case M88DS3103_TS_SERIAL:
   864			u8tmp1 = 0x00;
   865			u8tmp = 0x06;
   866			break;
   867		case M88DS3103_TS_SERIAL_D7:
   868			u8tmp1 = 0x20;
   869			u8tmp = 0x06;
   870			break;
   871		case M88DS3103_TS_PARALLEL:
   872			u8tmp = 0x02;
   873			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   874				u8tmp = 0x01;
   875				u8tmp1 = 0x01;
   876			}
   877			break;
   878		case M88DS3103_TS_CI:
   879			u8tmp = 0x03;
   880			break;
   881		default:
   882			dev_dbg(&client->dev, "invalid ts_mode\n");
   883			ret = -EINVAL;
   884			goto err;
   885		}
   886	
   887		if (dev->cfg->ts_clk_pol)
   888			u8tmp |= 0x40;
   889	
   890		/* TS mode */
   891		ret = regmap_write(dev->regmap, 0xfd, u8tmp);
   892		if (ret)
   893			goto err;
   894	
   895		switch (dev->cfg->ts_mode) {
   896		case M88DS3103_TS_SERIAL:
   897		case M88DS3103_TS_SERIAL_D7:
   898			ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1);
   899			if (ret)
   900				goto err;
   901			u16tmp = 0;
   902			u8tmp1 = 0x3f;
   903			u8tmp2 = 0x3f;
   904			break;
   905		case M88DS3103_TS_PARALLEL:
 > 906			if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   907				ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1);
   908				if (ret)
   909					goto err;
   910			}
   911		default:
   912			u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
   913			u8tmp1 = u16tmp / 2 - 1;
   914			u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1;
   915		}
   916	
   917		dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n",
   918			target_mclk, dev->cfg->ts_clk, u16tmp);
   919	
   920		/* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */
   921		/* u8tmp2[5:0] => ea[5:0] */
   922		u8tmp = (u8tmp1 >> 2) & 0x0f;
   923		ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp);
   924		if (ret)
   925			goto err;
   926		u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0;
   927		ret = regmap_write(dev->regmap, 0xea, u8tmp);
   928		if (ret)
   929			goto err;
   930	
   931		if (c->symbol_rate <= 3000000)
   932			u8tmp = 0x20;
   933		else if (c->symbol_rate <= 10000000)
   934			u8tmp = 0x10;
   935		else
   936			u8tmp = 0x06;
   937	
   938		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
   939			m88ds3103b_set_mclk(dev, target_mclk / 1000);
   940	
   941		ret = regmap_write(dev->regmap, 0xc3, 0x08);
   942		if (ret)
   943			goto err;
   944	
   945		ret = regmap_write(dev->regmap, 0xc8, u8tmp);
   946		if (ret)
   947			goto err;
   948	
   949		ret = regmap_write(dev->regmap, 0xc4, 0x08);
   950		if (ret)
   951			goto err;
   952	
   953		ret = regmap_write(dev->regmap, 0xc7, 0x00);
   954		if (ret)
   955			goto err;
   956	
   957		u16tmp = DIV_ROUND_CLOSEST_ULL((u64)c->symbol_rate * 0x10000, dev->mclk);
   958		buf[0] = (u16tmp >> 0) & 0xff;
   959		buf[1] = (u16tmp >> 8) & 0xff;
   960		ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2);
   961		if (ret)
   962			goto err;
   963	
   964		ret = m88ds3103_update_bits(dev, 0x4d, 0x02, dev->cfg->spec_inv << 1);
   965		if (ret)
   966			goto err;
   967	
   968		ret = m88ds3103_update_bits(dev, 0x30, 0x10, dev->cfg->agc_inv << 4);
   969		if (ret)
   970			goto err;
   971	
   972		ret = regmap_write(dev->regmap, 0x33, dev->cfg->agc);
   973		if (ret)
   974			goto err;
   975	
   976		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
   977			/* enable/disable 192M LDPC clock */
   978			ret = m88ds3103_update_bits(dev, 0x29, 0x10,
   979						(c->delivery_system == SYS_DVBS) ? 0x10 : 0x0);
   980			if (ret)
   981				goto err;
   982	
   983			ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08);
   984		}
   985	
   986		dev_dbg(&client->dev, "carrier offset=%d\n",
   987			(tuner_frequency_khz - c->frequency));
   988	
   989		/* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */
   990		s32tmp = 0x10000 * (tuner_frequency_khz - c->frequency);
   991		s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk / 1000);
   992		buf[0] = (s32tmp >> 0) & 0xff;
   993		buf[1] = (s32tmp >> 8) & 0xff;
   994		ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2);
   995		if (ret)
   996			goto err;
   997	
   998		ret = regmap_write(dev->regmap, 0x00, 0x00);
   999		if (ret)
  1000			goto err;
  1001	
  1002		ret = regmap_write(dev->regmap, 0xb2, 0x00);
  1003		if (ret)
  1004			goto err;
  1005	
  1006		dev->delivery_system = c->delivery_system;
  1007	
  1008		return 0;
  1009	err:
  1010		dev_dbg(&client->dev, "failed=%d\n", ret);
  1011		return ret;
  1012	}
  1013	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
diff mbox series

Patch

diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index c96f05ff5f2f..baf21b999ccc 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -64,6 +64,92 @@  static int m88ds3103_wr_reg_val_tab(struct m88ds3103_dev *dev,
 	return ret;
 }
 
+/*
+ * m88ds3103b demod has an internal device related to clocking. First the i2c
+ * gate must be opened, for one transaction, then writes will be allowed.
+ */
+static int m88ds3103b_dt_write(struct m88ds3103_dev *dev, int reg, int data)
+{
+	struct i2c_client *client = dev->client;
+	u8 buf[] = {reg, data};
+	u8 val;
+	int ret;
+	struct i2c_msg msg = {
+		.addr = dev->dt_addr, .flags = 0, .buf = buf, .len = 2
+	};
+
+	m88ds3103_update_bits(dev, 0x11, 0x01, 0x00);
+
+	val = 0x11;
+	ret = regmap_write(dev->regmap, 0x03, val);
+	if (ret)
+		dev_dbg(&client->dev, "fail=%d\n", ret);
+
+	ret = i2c_transfer(dev->dt_client->adapter, &msg, 1);
+	if (ret != 1) {
+		dev_err(&client->dev, "0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n",
+			dev->dt_addr, ret, reg, data);
+
+		m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+		return -EREMOTEIO;
+	}
+	m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+
+	dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
+		dev->dt_addr, reg, data);
+
+	return 0;
+}
+
+/*
+ * m88ds3103b demod has an internal device related to clocking. First the i2c
+ * gate must be opened, for two transactions, then reads will be allowed.
+ */
+static int m88ds3103b_dt_read(struct m88ds3103_dev *dev, u8 reg)
+{
+	struct i2c_client *client = dev->client;
+	int ret;
+	u8 val;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = dev->dt_addr,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		},
+		{
+			.addr = dev->dt_addr,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	m88ds3103_update_bits(dev, 0x11, 0x01, 0x00);
+
+	val = 0x12;
+	ret = regmap_write(dev->regmap, 0x03, val);
+	if (ret)
+		dev_dbg(&client->dev, "fail=%d\n", ret);
+
+	ret = i2c_transfer(dev->dt_client->adapter, msg, 2);
+	if (ret != 2) {
+		dev_err(&client->dev, "0x%02x (ret=%d, reg=0x%02x)\n",
+			dev->dt_addr, ret, reg);
+
+		m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+		return -EREMOTEIO;
+	}
+	m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+
+	dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
+		dev->dt_addr, reg, b1[0]);
+
+	return b1[0];
+}
+
 /*
  * Get the demodulator AGC PWM voltage setting supplied to the tuner.
  */
@@ -288,6 +374,253 @@  static int m88ds3103_read_status(struct dvb_frontend *fe,
 	return ret;
 }
 
+static int m88ds3103b_select_mclk(struct m88ds3103_dev *dev)
+{
+	struct i2c_client *client = dev->client;
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+	u32 adc_Freq_MHz[3] = {96, 93, 99};
+	u8  reg16_list[3] = {96, 92, 100}, reg16, reg15;
+	u32 offset_MHz[3];
+	u32 max_offset = 0;
+	u32 old_setting = dev->mclk;
+	u32 tuner_freq_MHz = c->frequency / 1000;
+	u8 i;
+	char big_symbol = 0;
+
+	big_symbol = (c->symbol_rate > 45010000) ? 1 : 0;
+
+	if (big_symbol) {
+		reg16 = 115;
+	} else {
+		reg16 = 96;
+
+		/* TODO: IS THIS NECESSARY ? */
+		for (i = 0; i < 3; i++) {
+			offset_MHz[i] = tuner_freq_MHz % adc_Freq_MHz[i];
+
+			if (offset_MHz[i] > (adc_Freq_MHz[i] / 2))
+				offset_MHz[i] = adc_Freq_MHz[i] - offset_MHz[i];
+
+			if (offset_MHz[i] > max_offset) {
+				max_offset = offset_MHz[i];
+				reg16 = reg16_list[i];
+				dev->mclk = adc_Freq_MHz[i] * 1000 * 1000;
+
+				if (big_symbol)
+					dev->mclk /= 2;
+
+				dev_dbg(&client->dev, "modifying mclk %u -> %u\n",
+					old_setting, dev->mclk);
+			}
+		}
+	}
+
+	if (dev->mclk == 93000000)
+		regmap_write(dev->regmap, 0xA0, 0x42);
+	else if (dev->mclk == 96000000)
+		regmap_write(dev->regmap, 0xA0, 0x44);
+	else if (dev->mclk == 99000000)
+		regmap_write(dev->regmap, 0xA0, 0x46);
+	else if (dev->mclk == 110250000)
+		regmap_write(dev->regmap, 0xA0, 0x4E);
+	else
+		regmap_write(dev->regmap, 0xA0, 0x44);
+
+	reg15 = m88ds3103b_dt_read(dev, 0x15);
+
+	m88ds3103b_dt_write(dev, 0x05, 0x40);
+	m88ds3103b_dt_write(dev, 0x11, 0x08);
+
+	if (big_symbol)
+		reg15 |= 0x02;
+	else
+		reg15 &= ~0x02;
+
+	m88ds3103b_dt_write(dev, 0x15, reg15);
+	m88ds3103b_dt_write(dev, 0x16, reg16);
+
+	usleep_range(5000, 5500);
+
+	m88ds3103b_dt_write(dev, 0x05, 0x00);
+	m88ds3103b_dt_write(dev, 0x11, (u8)(big_symbol ? 0x0E : 0x0A));
+
+	usleep_range(5000, 5500);
+
+	return 0;
+}
+
+static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz)
+{
+	u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp;
+	u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0, pll_ldpc_mode;
+	u16 pll_div_fb, N;
+	u32 div;
+
+	reg15 = m88ds3103b_dt_read(dev, 0x15);
+	reg16 = m88ds3103b_dt_read(dev, 0x16);
+	reg1D = m88ds3103b_dt_read(dev, 0x1D);
+
+	if (dev->cfg->ts_mode != M88DS3103_TS_SERIAL) {
+		if (reg16 == 92)
+			tmp = 93;
+		else if (reg16 == 100)
+			tmp = 99;
+		else
+			tmp = 96;
+
+		mclk_khz *= tmp;
+		mclk_khz /= 96;
+	}
+
+	pll_ldpc_mode = (reg15 >> 1) & 0x01;
+
+	pll_div_fb = (reg15 & 0x01) << 8;
+	pll_div_fb += reg16;
+	pll_div_fb += 32;
+
+	div = 9000 * pll_div_fb * 4;
+	div /= mclk_khz;
+
+	if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) {
+		reg11 |= 0x02;
+
+		if (div <= 32) {
+			N = 2;
+
+			f0 = 0;
+			f1 = div / N;
+			f2 = div - f1;
+			f3 = 0;
+		} else if (div <= 34) {
+			N = 3;
+
+			f0 = div / N;
+			f1 = (div - f0) / (N - 1);
+			f2 = div - f0 - f1;
+			f3 = 0;
+		} else if (div <= 64) {
+			N = 4;
+
+			f0 = div / N;
+			f1 = (div - f0) / (N - 1);
+			f2 = (div - f0 - f1) / (N - 2);
+			f3 = div - f0 - f1 - f2;
+		} else {
+			N = 4;
+
+			f0 = 16;
+			f1 = 16;
+			f2 = 16;
+			f3 = 16;
+		}
+
+		if (f0 == 16)
+			f0 = 0;
+		else if ((f0 < 8) && (f0 != 0))
+			f0 = 8;
+
+		if (f1 == 16)
+			f1 = 0;
+		else if ((f1 < 8) && (f1 != 0))
+			f1 = 8;
+
+		if (f2 == 16)
+			f2 = 0;
+		else if ((f2 < 8) && (f2 != 0))
+			f2 = 8;
+
+		if (f3 == 16)
+			f3 = 0;
+		else if ((f3 < 8) && (f3 != 0))
+			f3 = 8;
+	} else {
+		reg11 &= ~0x02;
+
+		if (div <= 32) {
+			N = 2;
+
+			f0 = 0;
+			f1 = div / N;
+			f2 = div - f1;
+			f3 = 0;
+		} else if (div <= 48) {
+			N = 3;
+
+			f0 = div / N;
+			f1 = (div - f0) / (N - 1);
+			f2 = div - f0 - f1;
+			f3 = 0;
+		} else if (div <= 64) {
+			N = 4;
+
+			f0 = div / N;
+			f1 = (div - f0) / (N - 1);
+			f2 = (div - f0 - f1) / (N - 2);
+			f3 = div - f0 - f1 - f2;
+		} else {
+			N = 4;
+
+			f0 = 16;
+			f1 = 16;
+			f2 = 16;
+			f3 = 16;
+		}
+
+		if (f0 == 16)
+			f0 = 0;
+		else if ((f0 < 9) && (f0 != 0))
+			f0 = 9;
+
+		if (f1 == 16)
+			f1 = 0;
+		else if ((f1 < 9) && (f1 != 0))
+			f1 = 9;
+
+		if (f2 == 16)
+			f2 = 0;
+		else if ((f2 < 9) && (f2 != 0))
+			f2 = 9;
+
+		if (f3 == 16)
+			f3 = 0;
+		else if ((f3 < 9) && (f3 != 0))
+			f3 = 9;
+	}
+
+	sm = N - 1;
+
+	/* Write to registers */
+	//reg15 &= 0x01;
+	//reg15 |= (pll_div_fb >> 8) & 0x01;
+
+	//reg16 = pll_div_fb & 0xFF;
+
+	reg1D &= ~0x03;
+	reg1D |= sm;
+	reg1D |= 0x80;
+
+	reg1E = ((f3 << 4) + f2) & 0xFF;
+	reg1F = ((f1 << 4) + f0) & 0xFF;
+
+	m88ds3103b_dt_write(dev, 0x05, 0x40);
+	m88ds3103b_dt_write(dev, 0x11, 0x08);
+	m88ds3103b_dt_write(dev, 0x1D, reg1D);
+	m88ds3103b_dt_write(dev, 0x1E, reg1E);
+	m88ds3103b_dt_write(dev, 0x1F, reg1F);
+
+	m88ds3103b_dt_write(dev, 0x17, 0xc1);
+	m88ds3103b_dt_write(dev, 0x17, 0x81);
+
+	usleep_range(5000, 5500);
+
+	m88ds3103b_dt_write(dev, 0x05, 0x00);
+	m88ds3103b_dt_write(dev, 0x11, 0x0A);
+
+	usleep_range(5000, 5500);
+
+	return 0;
+}
+
 static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 {
 	struct m88ds3103_dev *dev = fe->demodulator_priv;
@@ -298,7 +631,7 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 	u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
 	u8 buf[3];
 	u16 u16tmp;
-	u32 tuner_frequency_khz, target_mclk;
+	u32 tuner_frequency_khz, target_mclk, u32tmp;
 	s32 s32tmp;
 	static const struct reg_sequence reset_buf[] = {
 		{0x07, 0x80}, {0x07, 0x00}
@@ -321,6 +654,20 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 
 	/* Disable demod clock path */
 	if (dev->chip_id == M88RS6000_CHIP_ID) {
+		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+			ret = regmap_read(dev->regmap, 0xb2, &u32tmp);
+			if (ret)
+				goto err;
+			if (u32tmp == 0x01) {
+				ret = regmap_write(dev->regmap, 0x00, 0x00);
+				if (ret)
+					goto err;
+				ret = regmap_write(dev->regmap, 0xb2, 0x00);
+				if (ret)
+					goto err;
+			}
+		}
+
 		ret = regmap_write(dev->regmap, 0x06, 0xe0);
 		if (ret)
 			goto err;
@@ -346,7 +693,7 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 		tuner_frequency_khz = c->frequency;
 	}
 
-	/* select M88RS6000 demod main mclk and ts mclk from tuner die. */
+	/* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */
 	if (dev->chip_id == M88RS6000_CHIP_ID) {
 		if (c->symbol_rate > 45010000)
 			dev->mclk = 110250000;
@@ -358,6 +705,11 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 		else
 			target_mclk = 144000000;
 
+		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+			m88ds3103b_select_mclk(dev);
+			m88ds3103b_set_mclk(dev, target_mclk / 1000);
+		}
+
 		/* Enable demod clock path */
 		ret = regmap_write(dev->regmap, 0x06, 0x00);
 		if (ret)
@@ -469,12 +821,42 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 		ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08);
 		if (ret)
 			goto err;
+
+		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+			buf[0] = m88ds3103b_dt_read(dev, 0x15);
+			buf[1] = m88ds3103b_dt_read(dev, 0x16);
+
+			if (c->symbol_rate > 45010000) {
+				buf[0] &= ~0x03;
+				buf[0] |= 0x02;
+				buf[0] |= ((147 - 32) >> 8) & 0x01;
+				buf[1] = (147 - 32) & 0xFF;
+
+				dev->mclk = 110250 * 1000;
+			} else {
+				buf[0] &= ~0x03;
+				buf[0] |= ((128 - 32) >> 8) & 0x01;
+				buf[1] = (128 - 32) & 0xFF;
+
+				dev->mclk = 96000 * 1000;
+			}
+			m88ds3103b_dt_write(dev, 0x15, buf[0]);
+			m88ds3103b_dt_write(dev, 0x16, buf[1]);
+
+			regmap_read(dev->regmap, 0x30, &u32tmp);
+			u32tmp &= ~0x80;
+			regmap_write(dev->regmap, 0x30, u32tmp & 0xff);
+		}
+
 		ret = regmap_write(dev->regmap, 0xf1, 0x01);
 		if (ret)
 			goto err;
-		ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
-		if (ret)
-			goto err;
+
+		if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) {
+			ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
+			if (ret)
+				goto err;
+		}
 	}
 
 	switch (dev->cfg->ts_mode) {
@@ -488,6 +870,10 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 		break;
 	case M88DS3103_TS_PARALLEL:
 		u8tmp = 0x02;
+		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+			u8tmp = 0x01;
+			u8tmp1 = 0x01;
+		}
 		break;
 	case M88DS3103_TS_CI:
 		u8tmp = 0x03;
@@ -516,6 +902,12 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 		u8tmp1 = 0x3f;
 		u8tmp2 = 0x3f;
 		break;
+	case M88DS3103_TS_PARALLEL:
+		if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+			ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1);
+			if (ret)
+				goto err;
+		}
 	default:
 		u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
 		u8tmp1 = u16tmp / 2 - 1;
@@ -543,6 +935,9 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 	else
 		u8tmp = 0x06;
 
+	if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
+		m88ds3103b_set_mclk(dev, target_mclk / 1000);
+
 	ret = regmap_write(dev->regmap, 0xc3, 0x08);
 	if (ret)
 		goto err;
@@ -578,6 +973,16 @@  static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 	if (ret)
 		goto err;
 
+	if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+		/* enable/disable 192M LDPC clock */
+		ret = m88ds3103_update_bits(dev, 0x29, 0x10,
+					(c->delivery_system == SYS_DVBS) ? 0x10 : 0x0);
+		if (ret)
+			goto err;
+
+		ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08);
+	}
+
 	dev_dbg(&client->dev, "carrier offset=%d\n",
 		(tuner_frequency_khz - c->frequency));
 
@@ -642,7 +1047,7 @@  static int m88ds3103_init(struct dvb_frontend *fe)
 	if (utmp)
 		goto warm;
 
-	/* global reset, global diseqc reset, golbal fec reset */
+	/* global reset, global diseqc reset, global fec reset */
 	ret = regmap_write(dev->regmap, 0x07, 0xe0);
 	if (ret)
 		goto err;
@@ -652,12 +1057,15 @@  static int m88ds3103_init(struct dvb_frontend *fe)
 
 	/* cold state - try to download firmware */
 	dev_info(&client->dev, "found a '%s' in cold state\n",
-		 m88ds3103_ops.info.name);
+		 dev->fe.ops.info.name);
 
-	if (dev->chip_id == M88RS6000_CHIP_ID)
+	if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
+		name = M88DS3103B_FIRMWARE;
+	else if (dev->chip_id == M88RS6000_CHIP_ID)
 		name = M88RS6000_FIRMWARE;
 	else
 		name = M88DS3103_FIRMWARE;
+
 	/* request the firmware, this will block and timeout */
 	ret = request_firmware(&firmware, name, &client->dev);
 	if (ret) {
@@ -700,10 +1108,16 @@  static int m88ds3103_init(struct dvb_frontend *fe)
 	}
 
 	dev_info(&client->dev, "found a '%s' in warm state\n",
-		 m88ds3103_ops.info.name);
+		 dev->fe.ops.info.name);
 	dev_info(&client->dev, "firmware version: %X.%X\n",
 		 (utmp >> 4) & 0xf, (utmp >> 0 & 0xf));
 
+	if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+		m88ds3103b_dt_write(dev, 0x21, 0x92);
+		m88ds3103b_dt_write(dev, 0x15, 0x6C);
+		m88ds3103b_dt_write(dev, 0x17, 0xC1);
+		m88ds3103b_dt_write(dev, 0x17, 0x81);
+	}
 warm:
 	/* warm state */
 	dev->warm = true;
@@ -1393,6 +1807,8 @@  static int m88ds3103_probe(struct i2c_client *client,
 		goto err_kfree;
 
 	dev->chip_id = utmp >> 1;
+	dev->chiptype = (u8)id->driver_data;
+
 	dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id);
 
 	switch (dev->chip_id) {
@@ -1459,7 +1875,10 @@  static int m88ds3103_probe(struct i2c_client *client,
 
 	/* create dvb_frontend */
 	memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
-	if (dev->chip_id == M88RS6000_CHIP_ID)
+	if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
+		strscpy(dev->fe.ops.info.name, "Montage Technology M88DS3103B",
+			sizeof(dev->fe.ops.info.name));
+	else if (dev->chip_id == M88RS6000_CHIP_ID)
 		strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000",
 			sizeof(dev->fe.ops.info.name));
 	if (!pdata->attach_in_use)
@@ -1470,6 +1889,25 @@  static int m88ds3103_probe(struct i2c_client *client,
 	/* setup callbacks */
 	pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend;
 	pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter;
+
+	if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+		/* enable i2c repeater for tuner */
+		m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+
+		/* get frontend address */
+		ret = regmap_read(dev->regmap, 0x29, &utmp);
+		if (ret)
+			goto err_kfree;
+		dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1;
+		dev_err(&client->dev, "dt addr is 0x%02x", dev->dt_addr);
+
+		dev->dt_client = i2c_new_dummy_device(client->adapter, dev->dt_addr);
+		if (!dev->dt_client) {
+			ret = -ENODEV;
+			goto err_kfree;
+		}
+	}
+
 	return 0;
 err_kfree:
 	kfree(dev);
@@ -1484,6 +1922,9 @@  static int m88ds3103_remove(struct i2c_client *client)
 
 	dev_dbg(&client->dev, "\n");
 
+	if (dev->dt_client)
+		i2c_unregister_device(dev->dt_client);
+
 	i2c_mux_del_adapters(dev->muxc);
 
 	kfree(dev);
@@ -1491,7 +1932,9 @@  static int m88ds3103_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id m88ds3103_id_table[] = {
-	{"m88ds3103", 0},
+	{"m88ds3103",  M88DS3103_CHIPTYPE_3103},
+	{"m88rs6000",  M88DS3103_CHIPTYPE_RS6000},
+	{"m88ds3103b", M88DS3103_CHIPTYPE_3103B},
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table);
@@ -1513,3 +1956,4 @@  MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(M88DS3103_FIRMWARE);
 MODULE_FIRMWARE(M88RS6000_FIRMWARE);
+MODULE_FIRMWARE(M88DS3103B_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index c825032f07ab..aa5306f40201 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -16,13 +16,20 @@ 
 #include <linux/regmap.h>
 #include <linux/math64.h>
 
-#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
-#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw"
+#define M88DS3103B_FIRMWARE "dvb-demod-m88ds3103b.fw"
+#define M88DS3103_FIRMWARE  "dvb-demod-m88ds3103.fw"
+#define M88RS6000_FIRMWARE  "dvb-demod-m88rs6000.fw"
+
 #define M88RS6000_CHIP_ID 0x74
 #define M88DS3103_CHIP_ID 0x70
 
+#define M88DS3103_CHIPTYPE_3103   0
+#define M88DS3103_CHIPTYPE_RS6000 1
+#define M88DS3103_CHIPTYPE_3103B  2
+
 struct m88ds3103_dev {
 	struct i2c_client *client;
+	struct i2c_client *dt_client;
 	struct regmap_config regmap_config;
 	struct regmap *regmap;
 	struct m88ds3103_config config;
@@ -35,10 +42,13 @@  struct m88ds3103_dev {
 	struct i2c_mux_core *muxc;
 	/* auto detect chip id to do different config */
 	u8 chip_id;
+	/* chip type to differentiate m88rs6000 from m88ds3103b */
+	u8 chiptype;
 	/* main mclk is calculated for M88RS6000 dynamically */
 	s32 mclk;
 	u64 post_bit_error;
 	u64 post_bit_count;
+	u8 dt_addr;
 };
 
 struct m88ds3103_reg_val {