1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 29a0bf528SMauro Carvalho Chehab /* 39a0bf528SMauro Carvalho Chehab * Realtek RTL2830 DVB-T demodulator driver 49a0bf528SMauro Carvalho Chehab * 59a0bf528SMauro Carvalho Chehab * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> 69a0bf528SMauro Carvalho Chehab */ 79a0bf528SMauro Carvalho Chehab 89a0bf528SMauro Carvalho Chehab #include "rtl2830_priv.h" 99a0bf528SMauro Carvalho Chehab 1015d37f38SAntti Palosaari /* Our regmap is bypassing I2C adapter lock, thus we do it! */ 11d858b0e7SMauro Carvalho Chehab static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg, 1215d37f38SAntti Palosaari const void *val, size_t val_count) 139a0bf528SMauro Carvalho Chehab { 141f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 159a0bf528SMauro Carvalho Chehab int ret; 169a0bf528SMauro Carvalho Chehab 17dfecde40SPeter Rosin i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); 1815d37f38SAntti Palosaari ret = regmap_bulk_write(dev->regmap, reg, val, val_count); 19dfecde40SPeter Rosin i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); 20fd4cfa8bSAntti Palosaari return ret; 219a0bf528SMauro Carvalho Chehab } 229a0bf528SMauro Carvalho Chehab 23d858b0e7SMauro Carvalho Chehab static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg, 2415d37f38SAntti Palosaari unsigned int mask, unsigned int val) 259a0bf528SMauro Carvalho Chehab { 261f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 279a0bf528SMauro Carvalho Chehab int ret; 289a0bf528SMauro Carvalho Chehab 29dfecde40SPeter Rosin i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); 3015d37f38SAntti Palosaari ret = regmap_update_bits(dev->regmap, reg, mask, val); 31dfecde40SPeter Rosin i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); 32fd4cfa8bSAntti Palosaari return ret; 339a0bf528SMauro Carvalho Chehab } 349a0bf528SMauro Carvalho Chehab 35d858b0e7SMauro Carvalho Chehab static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg, 36d858b0e7SMauro Carvalho Chehab void *val, size_t val_count) 379a0bf528SMauro Carvalho Chehab { 3815d37f38SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 399a0bf528SMauro Carvalho Chehab int ret; 409a0bf528SMauro Carvalho Chehab 41dfecde40SPeter Rosin i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); 4215d37f38SAntti Palosaari ret = regmap_bulk_read(dev->regmap, reg, val, val_count); 43dfecde40SPeter Rosin i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); 449a0bf528SMauro Carvalho Chehab return ret; 459a0bf528SMauro Carvalho Chehab } 469a0bf528SMauro Carvalho Chehab 479a0bf528SMauro Carvalho Chehab static int rtl2830_init(struct dvb_frontend *fe) 489a0bf528SMauro Carvalho Chehab { 491f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 501f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 5147b4dbffSAntti Palosaari struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; 529a0bf528SMauro Carvalho Chehab int ret, i; 539a0bf528SMauro Carvalho Chehab struct rtl2830_reg_val_mask tab[] = { 549a0bf528SMauro Carvalho Chehab {0x00d, 0x01, 0x03}, 559a0bf528SMauro Carvalho Chehab {0x00d, 0x10, 0x10}, 569a0bf528SMauro Carvalho Chehab {0x104, 0x00, 0x1e}, 579a0bf528SMauro Carvalho Chehab {0x105, 0x80, 0x80}, 589a0bf528SMauro Carvalho Chehab {0x110, 0x02, 0x03}, 599a0bf528SMauro Carvalho Chehab {0x110, 0x08, 0x0c}, 609a0bf528SMauro Carvalho Chehab {0x17b, 0x00, 0x40}, 619a0bf528SMauro Carvalho Chehab {0x17d, 0x05, 0x0f}, 629a0bf528SMauro Carvalho Chehab {0x17d, 0x50, 0xf0}, 639a0bf528SMauro Carvalho Chehab {0x18c, 0x08, 0x0f}, 649a0bf528SMauro Carvalho Chehab {0x18d, 0x00, 0xc0}, 659a0bf528SMauro Carvalho Chehab {0x188, 0x05, 0x0f}, 669a0bf528SMauro Carvalho Chehab {0x189, 0x00, 0xfc}, 679a0bf528SMauro Carvalho Chehab {0x2d5, 0x02, 0x02}, 689a0bf528SMauro Carvalho Chehab {0x2f1, 0x02, 0x06}, 699a0bf528SMauro Carvalho Chehab {0x2f1, 0x20, 0xf8}, 709a0bf528SMauro Carvalho Chehab {0x16d, 0x00, 0x01}, 719a0bf528SMauro Carvalho Chehab {0x1a6, 0x00, 0x80}, 72b8cb50d2SAntti Palosaari {0x106, dev->pdata->vtop, 0x3f}, 73b8cb50d2SAntti Palosaari {0x107, dev->pdata->krf, 0x3f}, 749a0bf528SMauro Carvalho Chehab {0x112, 0x28, 0xff}, 75b8cb50d2SAntti Palosaari {0x103, dev->pdata->agc_targ_val, 0xff}, 769a0bf528SMauro Carvalho Chehab {0x00a, 0x02, 0x07}, 779a0bf528SMauro Carvalho Chehab {0x140, 0x0c, 0x3c}, 789a0bf528SMauro Carvalho Chehab {0x140, 0x40, 0xc0}, 799a0bf528SMauro Carvalho Chehab {0x15b, 0x05, 0x07}, 809a0bf528SMauro Carvalho Chehab {0x15b, 0x28, 0x38}, 819a0bf528SMauro Carvalho Chehab {0x15c, 0x05, 0x07}, 829a0bf528SMauro Carvalho Chehab {0x15c, 0x28, 0x38}, 83b8cb50d2SAntti Palosaari {0x115, dev->pdata->spec_inv, 0x01}, 849a0bf528SMauro Carvalho Chehab {0x16f, 0x01, 0x07}, 859a0bf528SMauro Carvalho Chehab {0x170, 0x18, 0x38}, 869a0bf528SMauro Carvalho Chehab {0x172, 0x0f, 0x0f}, 879a0bf528SMauro Carvalho Chehab {0x173, 0x08, 0x38}, 889a0bf528SMauro Carvalho Chehab {0x175, 0x01, 0x07}, 899a0bf528SMauro Carvalho Chehab {0x176, 0x00, 0xc0}, 909a0bf528SMauro Carvalho Chehab }; 919a0bf528SMauro Carvalho Chehab 929a0bf528SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(tab); i++) { 9315d37f38SAntti Palosaari ret = rtl2830_update_bits(client, tab[i].reg, tab[i].mask, 9415d37f38SAntti Palosaari tab[i].val); 959a0bf528SMauro Carvalho Chehab if (ret) 969a0bf528SMauro Carvalho Chehab goto err; 979a0bf528SMauro Carvalho Chehab } 989a0bf528SMauro Carvalho Chehab 9915d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x18f, "\x28\x00", 2); 1009a0bf528SMauro Carvalho Chehab if (ret) 1019a0bf528SMauro Carvalho Chehab goto err; 1029a0bf528SMauro Carvalho Chehab 10315d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x195, 1049a0bf528SMauro Carvalho Chehab "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); 1059a0bf528SMauro Carvalho Chehab if (ret) 1069a0bf528SMauro Carvalho Chehab goto err; 1079a0bf528SMauro Carvalho Chehab 1089a0bf528SMauro Carvalho Chehab /* TODO: spec init */ 1099a0bf528SMauro Carvalho Chehab 1109a0bf528SMauro Carvalho Chehab /* soft reset */ 11115d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x101, 0x04, 0x04); 1129a0bf528SMauro Carvalho Chehab if (ret) 1139a0bf528SMauro Carvalho Chehab goto err; 1149a0bf528SMauro Carvalho Chehab 11515d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x101, 0x04, 0x00); 1169a0bf528SMauro Carvalho Chehab if (ret) 1179a0bf528SMauro Carvalho Chehab goto err; 1189a0bf528SMauro Carvalho Chehab 11947b4dbffSAntti Palosaari /* init stats here in order signal app which stats are supported */ 120871f7025SAntti Palosaari c->strength.len = 1; 121871f7025SAntti Palosaari c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 12247b4dbffSAntti Palosaari c->cnr.len = 1; 12347b4dbffSAntti Palosaari c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1245bb11ca5SAntti Palosaari c->post_bit_error.len = 1; 1255bb11ca5SAntti Palosaari c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 1265bb11ca5SAntti Palosaari c->post_bit_count.len = 1; 1275bb11ca5SAntti Palosaari c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 12847b4dbffSAntti Palosaari 129f544f100SAntti Palosaari dev->sleeping = false; 1309a0bf528SMauro Carvalho Chehab 1319a0bf528SMauro Carvalho Chehab return ret; 1329a0bf528SMauro Carvalho Chehab err: 1337cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 1349a0bf528SMauro Carvalho Chehab return ret; 1359a0bf528SMauro Carvalho Chehab } 1369a0bf528SMauro Carvalho Chehab 1379a0bf528SMauro Carvalho Chehab static int rtl2830_sleep(struct dvb_frontend *fe) 1389a0bf528SMauro Carvalho Chehab { 1391f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 1401f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 141947debb4SAntti Palosaari 142f544f100SAntti Palosaari dev->sleeping = true; 14347b4dbffSAntti Palosaari dev->fe_status = 0; 144947debb4SAntti Palosaari 1459a0bf528SMauro Carvalho Chehab return 0; 1469a0bf528SMauro Carvalho Chehab } 1479a0bf528SMauro Carvalho Chehab 148a17ff2eeSMauro Carvalho Chehab static int rtl2830_get_tune_settings(struct dvb_frontend *fe, 1499a0bf528SMauro Carvalho Chehab struct dvb_frontend_tune_settings *s) 1509a0bf528SMauro Carvalho Chehab { 1519a0bf528SMauro Carvalho Chehab s->min_delay_ms = 500; 152f1b1eabfSMauro Carvalho Chehab s->step_size = fe->ops.info.frequency_stepsize_hz * 2; 153f1b1eabfSMauro Carvalho Chehab s->max_drift = (fe->ops.info.frequency_stepsize_hz * 2) + 1; 1549a0bf528SMauro Carvalho Chehab 1559a0bf528SMauro Carvalho Chehab return 0; 1569a0bf528SMauro Carvalho Chehab } 1579a0bf528SMauro Carvalho Chehab 1589a0bf528SMauro Carvalho Chehab static int rtl2830_set_frontend(struct dvb_frontend *fe) 1599a0bf528SMauro Carvalho Chehab { 1601f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 1611f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 1629a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1639a0bf528SMauro Carvalho Chehab int ret, i; 16466b3c4deSAntti Palosaari u64 num; 16515d37f38SAntti Palosaari u8 buf[3], u8tmp; 16666b3c4deSAntti Palosaari u32 if_ctl, if_frequency; 1673a2fca26SAntti Palosaari static const u8 bw_params1[3][34] = { 1689a0bf528SMauro Carvalho Chehab { 1699a0bf528SMauro Carvalho Chehab 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, 1709a0bf528SMauro Carvalho Chehab 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, 1719a0bf528SMauro Carvalho Chehab 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, 1729a0bf528SMauro Carvalho Chehab 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ 1739a0bf528SMauro Carvalho Chehab }, { 1749a0bf528SMauro Carvalho Chehab 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, 1759a0bf528SMauro Carvalho Chehab 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, 1769a0bf528SMauro Carvalho Chehab 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, 1779a0bf528SMauro Carvalho Chehab 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ 1789a0bf528SMauro Carvalho Chehab }, { 1799a0bf528SMauro Carvalho Chehab 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, 1809a0bf528SMauro Carvalho Chehab 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, 1819a0bf528SMauro Carvalho Chehab 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, 1829a0bf528SMauro Carvalho Chehab 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ 1839a0bf528SMauro Carvalho Chehab }, 1849a0bf528SMauro Carvalho Chehab }; 1853a2fca26SAntti Palosaari static const u8 bw_params2[3][6] = { 1863a2fca26SAntti Palosaari {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30}, /* 6 MHz */ 1873a2fca26SAntti Palosaari {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98}, /* 7 MHz */ 1883a2fca26SAntti Palosaari {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */ 1899a0bf528SMauro Carvalho Chehab }; 1909a0bf528SMauro Carvalho Chehab 1917cc39328SAntti Palosaari dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n", 1927cc39328SAntti Palosaari c->frequency, c->bandwidth_hz, c->inversion); 1939a0bf528SMauro Carvalho Chehab 1949a0bf528SMauro Carvalho Chehab /* program tuner */ 1959a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) 1969a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe); 1979a0bf528SMauro Carvalho Chehab 1989a0bf528SMauro Carvalho Chehab switch (c->bandwidth_hz) { 1999a0bf528SMauro Carvalho Chehab case 6000000: 2009a0bf528SMauro Carvalho Chehab i = 0; 2019a0bf528SMauro Carvalho Chehab break; 2029a0bf528SMauro Carvalho Chehab case 7000000: 2039a0bf528SMauro Carvalho Chehab i = 1; 2049a0bf528SMauro Carvalho Chehab break; 2059a0bf528SMauro Carvalho Chehab case 8000000: 2069a0bf528SMauro Carvalho Chehab i = 2; 2079a0bf528SMauro Carvalho Chehab break; 2089a0bf528SMauro Carvalho Chehab default: 2097cc39328SAntti Palosaari dev_err(&client->dev, "invalid bandwidth_hz %u\n", 2107cc39328SAntti Palosaari c->bandwidth_hz); 2119a0bf528SMauro Carvalho Chehab return -EINVAL; 2129a0bf528SMauro Carvalho Chehab } 2139a0bf528SMauro Carvalho Chehab 21415d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x008, 0x06, i << 1); 2159a0bf528SMauro Carvalho Chehab if (ret) 2169a0bf528SMauro Carvalho Chehab goto err; 2179a0bf528SMauro Carvalho Chehab 21866b3c4deSAntti Palosaari /* program if frequency */ 21966b3c4deSAntti Palosaari if (fe->ops.tuner_ops.get_if_frequency) 22066b3c4deSAntti Palosaari ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); 22166b3c4deSAntti Palosaari else 22266b3c4deSAntti Palosaari ret = -EINVAL; 223947debb4SAntti Palosaari if (ret) 22466b3c4deSAntti Palosaari goto err; 22566b3c4deSAntti Palosaari 226b8cb50d2SAntti Palosaari num = if_frequency % dev->pdata->clk; 22766b3c4deSAntti Palosaari num *= 0x400000; 228b8cb50d2SAntti Palosaari num = div_u64(num, dev->pdata->clk); 22966b3c4deSAntti Palosaari num = -num; 23066b3c4deSAntti Palosaari if_ctl = num & 0x3fffff; 2317cc39328SAntti Palosaari dev_dbg(&client->dev, "if_frequency=%d if_ctl=%08x\n", 2327cc39328SAntti Palosaari if_frequency, if_ctl); 23366b3c4deSAntti Palosaari 23415d37f38SAntti Palosaari buf[0] = (if_ctl >> 16) & 0x3f; 23566b3c4deSAntti Palosaari buf[1] = (if_ctl >> 8) & 0xff; 23666b3c4deSAntti Palosaari buf[2] = (if_ctl >> 0) & 0xff; 23766b3c4deSAntti Palosaari 23815d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x119, &u8tmp, 1); 23915d37f38SAntti Palosaari if (ret) 24015d37f38SAntti Palosaari goto err; 24115d37f38SAntti Palosaari 24215d37f38SAntti Palosaari buf[0] |= u8tmp & 0xc0; /* [7:6] */ 24315d37f38SAntti Palosaari 24415d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x119, buf, 3); 24566b3c4deSAntti Palosaari if (ret) 24666b3c4deSAntti Palosaari goto err; 24766b3c4deSAntti Palosaari 2489a0bf528SMauro Carvalho Chehab /* 1/2 split I2C write */ 24915d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x11c, &bw_params1[i][0], 17); 2509a0bf528SMauro Carvalho Chehab if (ret) 2519a0bf528SMauro Carvalho Chehab goto err; 2529a0bf528SMauro Carvalho Chehab 2539a0bf528SMauro Carvalho Chehab /* 2/2 split I2C write */ 25415d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x12d, &bw_params1[i][17], 17); 2559a0bf528SMauro Carvalho Chehab if (ret) 2569a0bf528SMauro Carvalho Chehab goto err; 2579a0bf528SMauro Carvalho Chehab 25815d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x19d, bw_params2[i], 6); 2599a0bf528SMauro Carvalho Chehab if (ret) 2609a0bf528SMauro Carvalho Chehab goto err; 2619a0bf528SMauro Carvalho Chehab 2629a0bf528SMauro Carvalho Chehab return ret; 2639a0bf528SMauro Carvalho Chehab err: 2647cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 2659a0bf528SMauro Carvalho Chehab return ret; 2669a0bf528SMauro Carvalho Chehab } 2679a0bf528SMauro Carvalho Chehab 2687e3e68bcSMauro Carvalho Chehab static int rtl2830_get_frontend(struct dvb_frontend *fe, 2697e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *c) 2709a0bf528SMauro Carvalho Chehab { 2711f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 2721f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 2739a0bf528SMauro Carvalho Chehab int ret; 2749a0bf528SMauro Carvalho Chehab u8 buf[3]; 2759a0bf528SMauro Carvalho Chehab 276f544f100SAntti Palosaari if (dev->sleeping) 2779a0bf528SMauro Carvalho Chehab return 0; 2789a0bf528SMauro Carvalho Chehab 27915d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x33c, buf, 2); 2809a0bf528SMauro Carvalho Chehab if (ret) 2819a0bf528SMauro Carvalho Chehab goto err; 2829a0bf528SMauro Carvalho Chehab 28315d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x351, &buf[2], 1); 2849a0bf528SMauro Carvalho Chehab if (ret) 2859a0bf528SMauro Carvalho Chehab goto err; 2869a0bf528SMauro Carvalho Chehab 2877cc39328SAntti Palosaari dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf); 2889a0bf528SMauro Carvalho Chehab 2899a0bf528SMauro Carvalho Chehab switch ((buf[0] >> 2) & 3) { 2909a0bf528SMauro Carvalho Chehab case 0: 2919a0bf528SMauro Carvalho Chehab c->modulation = QPSK; 2929a0bf528SMauro Carvalho Chehab break; 2939a0bf528SMauro Carvalho Chehab case 1: 2949a0bf528SMauro Carvalho Chehab c->modulation = QAM_16; 2959a0bf528SMauro Carvalho Chehab break; 2969a0bf528SMauro Carvalho Chehab case 2: 2979a0bf528SMauro Carvalho Chehab c->modulation = QAM_64; 2989a0bf528SMauro Carvalho Chehab break; 2999a0bf528SMauro Carvalho Chehab } 3009a0bf528SMauro Carvalho Chehab 3019a0bf528SMauro Carvalho Chehab switch ((buf[2] >> 2) & 1) { 3029a0bf528SMauro Carvalho Chehab case 0: 3039a0bf528SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_2K; 3049a0bf528SMauro Carvalho Chehab break; 3059a0bf528SMauro Carvalho Chehab case 1: 3069a0bf528SMauro Carvalho Chehab c->transmission_mode = TRANSMISSION_MODE_8K; 3079a0bf528SMauro Carvalho Chehab } 3089a0bf528SMauro Carvalho Chehab 3099a0bf528SMauro Carvalho Chehab switch ((buf[2] >> 0) & 3) { 3109a0bf528SMauro Carvalho Chehab case 0: 3119a0bf528SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_32; 3129a0bf528SMauro Carvalho Chehab break; 3139a0bf528SMauro Carvalho Chehab case 1: 3149a0bf528SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_16; 3159a0bf528SMauro Carvalho Chehab break; 3169a0bf528SMauro Carvalho Chehab case 2: 3179a0bf528SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_8; 3189a0bf528SMauro Carvalho Chehab break; 3199a0bf528SMauro Carvalho Chehab case 3: 3209a0bf528SMauro Carvalho Chehab c->guard_interval = GUARD_INTERVAL_1_4; 3219a0bf528SMauro Carvalho Chehab break; 3229a0bf528SMauro Carvalho Chehab } 3239a0bf528SMauro Carvalho Chehab 3249a0bf528SMauro Carvalho Chehab switch ((buf[0] >> 4) & 7) { 3259a0bf528SMauro Carvalho Chehab case 0: 3269a0bf528SMauro Carvalho Chehab c->hierarchy = HIERARCHY_NONE; 3279a0bf528SMauro Carvalho Chehab break; 3289a0bf528SMauro Carvalho Chehab case 1: 3299a0bf528SMauro Carvalho Chehab c->hierarchy = HIERARCHY_1; 3309a0bf528SMauro Carvalho Chehab break; 3319a0bf528SMauro Carvalho Chehab case 2: 3329a0bf528SMauro Carvalho Chehab c->hierarchy = HIERARCHY_2; 3339a0bf528SMauro Carvalho Chehab break; 3349a0bf528SMauro Carvalho Chehab case 3: 3359a0bf528SMauro Carvalho Chehab c->hierarchy = HIERARCHY_4; 3369a0bf528SMauro Carvalho Chehab break; 3379a0bf528SMauro Carvalho Chehab } 3389a0bf528SMauro Carvalho Chehab 3399a0bf528SMauro Carvalho Chehab switch ((buf[1] >> 3) & 7) { 3409a0bf528SMauro Carvalho Chehab case 0: 3419a0bf528SMauro Carvalho Chehab c->code_rate_HP = FEC_1_2; 3429a0bf528SMauro Carvalho Chehab break; 3439a0bf528SMauro Carvalho Chehab case 1: 3449a0bf528SMauro Carvalho Chehab c->code_rate_HP = FEC_2_3; 3459a0bf528SMauro Carvalho Chehab break; 3469a0bf528SMauro Carvalho Chehab case 2: 3479a0bf528SMauro Carvalho Chehab c->code_rate_HP = FEC_3_4; 3489a0bf528SMauro Carvalho Chehab break; 3499a0bf528SMauro Carvalho Chehab case 3: 3509a0bf528SMauro Carvalho Chehab c->code_rate_HP = FEC_5_6; 3519a0bf528SMauro Carvalho Chehab break; 3529a0bf528SMauro Carvalho Chehab case 4: 3539a0bf528SMauro Carvalho Chehab c->code_rate_HP = FEC_7_8; 3549a0bf528SMauro Carvalho Chehab break; 3559a0bf528SMauro Carvalho Chehab } 3569a0bf528SMauro Carvalho Chehab 3579a0bf528SMauro Carvalho Chehab switch ((buf[1] >> 0) & 7) { 3589a0bf528SMauro Carvalho Chehab case 0: 3599a0bf528SMauro Carvalho Chehab c->code_rate_LP = FEC_1_2; 3609a0bf528SMauro Carvalho Chehab break; 3619a0bf528SMauro Carvalho Chehab case 1: 3629a0bf528SMauro Carvalho Chehab c->code_rate_LP = FEC_2_3; 3639a0bf528SMauro Carvalho Chehab break; 3649a0bf528SMauro Carvalho Chehab case 2: 3659a0bf528SMauro Carvalho Chehab c->code_rate_LP = FEC_3_4; 3669a0bf528SMauro Carvalho Chehab break; 3679a0bf528SMauro Carvalho Chehab case 3: 3689a0bf528SMauro Carvalho Chehab c->code_rate_LP = FEC_5_6; 3699a0bf528SMauro Carvalho Chehab break; 3709a0bf528SMauro Carvalho Chehab case 4: 3719a0bf528SMauro Carvalho Chehab c->code_rate_LP = FEC_7_8; 3729a0bf528SMauro Carvalho Chehab break; 3739a0bf528SMauro Carvalho Chehab } 3749a0bf528SMauro Carvalho Chehab 3759a0bf528SMauro Carvalho Chehab return 0; 3769a0bf528SMauro Carvalho Chehab err: 3777cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 3789a0bf528SMauro Carvalho Chehab return ret; 3799a0bf528SMauro Carvalho Chehab } 3809a0bf528SMauro Carvalho Chehab 3810df289a2SMauro Carvalho Chehab static int rtl2830_read_status(struct dvb_frontend *fe, enum fe_status *status) 3829a0bf528SMauro Carvalho Chehab { 3831f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 384b8cb50d2SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 3854a7e445bSAntti Palosaari struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; 3864a7e445bSAntti Palosaari int ret, stmp; 3874a7e445bSAntti Palosaari unsigned int utmp; 3884a7e445bSAntti Palosaari u8 u8tmp, buf[2]; 389947debb4SAntti Palosaari 3909a0bf528SMauro Carvalho Chehab *status = 0; 3919a0bf528SMauro Carvalho Chehab 392f544f100SAntti Palosaari if (dev->sleeping) 3939a0bf528SMauro Carvalho Chehab return 0; 3949a0bf528SMauro Carvalho Chehab 39515d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x351, &u8tmp, 1); 3969a0bf528SMauro Carvalho Chehab if (ret) 3979a0bf528SMauro Carvalho Chehab goto err; 3989a0bf528SMauro Carvalho Chehab 39915d37f38SAntti Palosaari u8tmp = (u8tmp >> 3) & 0x0f; /* [6:3] */ 40015d37f38SAntti Palosaari if (u8tmp == 11) { 4019a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | 4029a0bf528SMauro Carvalho Chehab FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 40315d37f38SAntti Palosaari } else if (u8tmp == 10) { 4049a0bf528SMauro Carvalho Chehab *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | 4059a0bf528SMauro Carvalho Chehab FE_HAS_VITERBI; 4069a0bf528SMauro Carvalho Chehab } 4079a0bf528SMauro Carvalho Chehab 40847b4dbffSAntti Palosaari dev->fe_status = *status; 40947b4dbffSAntti Palosaari 4104a7e445bSAntti Palosaari /* Signal strength */ 4114a7e445bSAntti Palosaari if (dev->fe_status & FE_HAS_SIGNAL) { 4124a7e445bSAntti Palosaari /* Read IF AGC */ 4134a7e445bSAntti Palosaari ret = rtl2830_bulk_read(client, 0x359, buf, 2); 4144a7e445bSAntti Palosaari if (ret) 4154a7e445bSAntti Palosaari goto err; 4164a7e445bSAntti Palosaari 4174a7e445bSAntti Palosaari stmp = buf[0] << 8 | buf[1] << 0; 4184a7e445bSAntti Palosaari stmp = sign_extend32(stmp, 13); 4194a7e445bSAntti Palosaari utmp = clamp_val(-4 * stmp + 32767, 0x0000, 0xffff); 4204a7e445bSAntti Palosaari 4214a7e445bSAntti Palosaari dev_dbg(&client->dev, "IF AGC=%d\n", stmp); 4224a7e445bSAntti Palosaari 4234a7e445bSAntti Palosaari c->strength.stat[0].scale = FE_SCALE_RELATIVE; 4244a7e445bSAntti Palosaari c->strength.stat[0].uvalue = utmp; 4254a7e445bSAntti Palosaari } else { 4264a7e445bSAntti Palosaari c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4274a7e445bSAntti Palosaari } 4284a7e445bSAntti Palosaari 4294a7e445bSAntti Palosaari /* CNR */ 4304a7e445bSAntti Palosaari if (dev->fe_status & FE_HAS_VITERBI) { 4314a7e445bSAntti Palosaari unsigned int hierarchy, constellation; 4324a7e445bSAntti Palosaari #define CONSTELLATION_NUM 3 4334a7e445bSAntti Palosaari #define HIERARCHY_NUM 4 4344a7e445bSAntti Palosaari static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { 4354a7e445bSAntti Palosaari {70705899, 70705899, 70705899, 70705899}, 4364a7e445bSAntti Palosaari {82433173, 82433173, 87483115, 94445660}, 4374a7e445bSAntti Palosaari {92888734, 92888734, 95487525, 99770748}, 4384a7e445bSAntti Palosaari }; 4394a7e445bSAntti Palosaari 4404a7e445bSAntti Palosaari ret = rtl2830_bulk_read(client, 0x33c, &u8tmp, 1); 4414a7e445bSAntti Palosaari if (ret) 4424a7e445bSAntti Palosaari goto err; 4434a7e445bSAntti Palosaari 4444a7e445bSAntti Palosaari constellation = (u8tmp >> 2) & 0x03; /* [3:2] */ 4454a7e445bSAntti Palosaari if (constellation > CONSTELLATION_NUM - 1) 4464a7e445bSAntti Palosaari goto err; 4474a7e445bSAntti Palosaari 4484a7e445bSAntti Palosaari hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */ 4494a7e445bSAntti Palosaari if (hierarchy > HIERARCHY_NUM - 1) 4504a7e445bSAntti Palosaari goto err; 4514a7e445bSAntti Palosaari 4524a7e445bSAntti Palosaari ret = rtl2830_bulk_read(client, 0x40c, buf, 2); 4534a7e445bSAntti Palosaari if (ret) 4544a7e445bSAntti Palosaari goto err; 4554a7e445bSAntti Palosaari 4564a7e445bSAntti Palosaari utmp = buf[0] << 8 | buf[1] << 0; 4574a7e445bSAntti Palosaari if (utmp) 4584a7e445bSAntti Palosaari stmp = (constant[constellation][hierarchy] - 4594a7e445bSAntti Palosaari intlog10(utmp)) / ((1 << 24) / 10000); 4604a7e445bSAntti Palosaari else 4614a7e445bSAntti Palosaari stmp = 0; 4624a7e445bSAntti Palosaari 4634a7e445bSAntti Palosaari dev_dbg(&client->dev, "CNR raw=%u\n", utmp); 4644a7e445bSAntti Palosaari 4654a7e445bSAntti Palosaari c->cnr.stat[0].scale = FE_SCALE_DECIBEL; 4664a7e445bSAntti Palosaari c->cnr.stat[0].svalue = stmp; 4674a7e445bSAntti Palosaari } else { 4684a7e445bSAntti Palosaari c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4694a7e445bSAntti Palosaari } 4704a7e445bSAntti Palosaari 4714a7e445bSAntti Palosaari /* BER */ 4724a7e445bSAntti Palosaari if (dev->fe_status & FE_HAS_LOCK) { 4734a7e445bSAntti Palosaari ret = rtl2830_bulk_read(client, 0x34e, buf, 2); 4744a7e445bSAntti Palosaari if (ret) 4754a7e445bSAntti Palosaari goto err; 4764a7e445bSAntti Palosaari 4774a7e445bSAntti Palosaari utmp = buf[0] << 8 | buf[1] << 0; 4784a7e445bSAntti Palosaari dev->post_bit_error += utmp; 4794a7e445bSAntti Palosaari dev->post_bit_count += 1000000; 4804a7e445bSAntti Palosaari 4814a7e445bSAntti Palosaari dev_dbg(&client->dev, "BER errors=%u total=1000000\n", utmp); 4824a7e445bSAntti Palosaari 4834a7e445bSAntti Palosaari c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 4844a7e445bSAntti Palosaari c->post_bit_error.stat[0].uvalue = dev->post_bit_error; 4854a7e445bSAntti Palosaari c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 4864a7e445bSAntti Palosaari c->post_bit_count.stat[0].uvalue = dev->post_bit_count; 4874a7e445bSAntti Palosaari } else { 4884a7e445bSAntti Palosaari c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4894a7e445bSAntti Palosaari c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 4904a7e445bSAntti Palosaari } 4914a7e445bSAntti Palosaari 4924a7e445bSAntti Palosaari 4939a0bf528SMauro Carvalho Chehab return ret; 4949a0bf528SMauro Carvalho Chehab err: 4957cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 4969a0bf528SMauro Carvalho Chehab return ret; 4979a0bf528SMauro Carvalho Chehab } 4989a0bf528SMauro Carvalho Chehab 4999a0bf528SMauro Carvalho Chehab static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) 5009a0bf528SMauro Carvalho Chehab { 5016dcfe3ccSAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 5029a0bf528SMauro Carvalho Chehab 5036dcfe3ccSAntti Palosaari if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) 5046dcfe3ccSAntti Palosaari *snr = div_s64(c->cnr.stat[0].svalue, 100); 5059a0bf528SMauro Carvalho Chehab else 5069a0bf528SMauro Carvalho Chehab *snr = 0; 5079a0bf528SMauro Carvalho Chehab 5089a0bf528SMauro Carvalho Chehab return 0; 5099a0bf528SMauro Carvalho Chehab } 5109a0bf528SMauro Carvalho Chehab 5119a0bf528SMauro Carvalho Chehab static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) 5129a0bf528SMauro Carvalho Chehab { 5131f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 5141f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 5159a0bf528SMauro Carvalho Chehab 516f491391cSAntti Palosaari *ber = (dev->post_bit_error - dev->post_bit_error_prev); 517f491391cSAntti Palosaari dev->post_bit_error_prev = dev->post_bit_error; 5189a0bf528SMauro Carvalho Chehab 5199a0bf528SMauro Carvalho Chehab return 0; 5209a0bf528SMauro Carvalho Chehab } 5219a0bf528SMauro Carvalho Chehab 5229a0bf528SMauro Carvalho Chehab static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 5239a0bf528SMauro Carvalho Chehab { 5249a0bf528SMauro Carvalho Chehab *ucblocks = 0; 525947debb4SAntti Palosaari 5269a0bf528SMauro Carvalho Chehab return 0; 5279a0bf528SMauro Carvalho Chehab } 5289a0bf528SMauro Carvalho Chehab 5299a0bf528SMauro Carvalho Chehab static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 5309a0bf528SMauro Carvalho Chehab { 531d512e286SAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 5329a0bf528SMauro Carvalho Chehab 533d512e286SAntti Palosaari if (c->strength.stat[0].scale == FE_SCALE_RELATIVE) 534d512e286SAntti Palosaari *strength = c->strength.stat[0].uvalue; 5359a0bf528SMauro Carvalho Chehab else 536d512e286SAntti Palosaari *strength = 0; 5379a0bf528SMauro Carvalho Chehab 5389a0bf528SMauro Carvalho Chehab return 0; 5399a0bf528SMauro Carvalho Chehab } 5409a0bf528SMauro Carvalho Chehab 541bd336e63SMax Kellermann static const struct dvb_frontend_ops rtl2830_ops = { 5429a0bf528SMauro Carvalho Chehab .delsys = {SYS_DVBT}, 5439a0bf528SMauro Carvalho Chehab .info = { 5449a0bf528SMauro Carvalho Chehab .name = "Realtek RTL2830 (DVB-T)", 5459a0bf528SMauro Carvalho Chehab .caps = FE_CAN_FEC_1_2 | 5469a0bf528SMauro Carvalho Chehab FE_CAN_FEC_2_3 | 5479a0bf528SMauro Carvalho Chehab FE_CAN_FEC_3_4 | 5489a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | 5499a0bf528SMauro Carvalho Chehab FE_CAN_FEC_7_8 | 5509a0bf528SMauro Carvalho Chehab FE_CAN_FEC_AUTO | 5519a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | 5529a0bf528SMauro Carvalho Chehab FE_CAN_QAM_16 | 5539a0bf528SMauro Carvalho Chehab FE_CAN_QAM_64 | 5549a0bf528SMauro Carvalho Chehab FE_CAN_QAM_AUTO | 5559a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | 5569a0bf528SMauro Carvalho Chehab FE_CAN_GUARD_INTERVAL_AUTO | 5579a0bf528SMauro Carvalho Chehab FE_CAN_HIERARCHY_AUTO | 5589a0bf528SMauro Carvalho Chehab FE_CAN_RECOVER | 5599a0bf528SMauro Carvalho Chehab FE_CAN_MUTE_TS 5609a0bf528SMauro Carvalho Chehab }, 5619a0bf528SMauro Carvalho Chehab 5629a0bf528SMauro Carvalho Chehab .init = rtl2830_init, 5639a0bf528SMauro Carvalho Chehab .sleep = rtl2830_sleep, 5649a0bf528SMauro Carvalho Chehab 5659a0bf528SMauro Carvalho Chehab .get_tune_settings = rtl2830_get_tune_settings, 5669a0bf528SMauro Carvalho Chehab 5679a0bf528SMauro Carvalho Chehab .set_frontend = rtl2830_set_frontend, 5689a0bf528SMauro Carvalho Chehab .get_frontend = rtl2830_get_frontend, 5699a0bf528SMauro Carvalho Chehab 5709a0bf528SMauro Carvalho Chehab .read_status = rtl2830_read_status, 5719a0bf528SMauro Carvalho Chehab .read_snr = rtl2830_read_snr, 5729a0bf528SMauro Carvalho Chehab .read_ber = rtl2830_read_ber, 5739a0bf528SMauro Carvalho Chehab .read_ucblocks = rtl2830_read_ucblocks, 5749a0bf528SMauro Carvalho Chehab .read_signal_strength = rtl2830_read_signal_strength, 5759a0bf528SMauro Carvalho Chehab }; 5769a0bf528SMauro Carvalho Chehab 577df70ddadSAntti Palosaari static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) 578df70ddadSAntti Palosaari { 579df70ddadSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 580df70ddadSAntti Palosaari int ret; 581df70ddadSAntti Palosaari u8 u8tmp; 582df70ddadSAntti Palosaari 583df70ddadSAntti Palosaari dev_dbg(&client->dev, "onoff=%d\n", onoff); 584df70ddadSAntti Palosaari 585df70ddadSAntti Palosaari /* enable / disable PID filter */ 586df70ddadSAntti Palosaari if (onoff) 587df70ddadSAntti Palosaari u8tmp = 0x80; 588df70ddadSAntti Palosaari else 589df70ddadSAntti Palosaari u8tmp = 0x00; 590df70ddadSAntti Palosaari 59115d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x061, 0x80, u8tmp); 592df70ddadSAntti Palosaari if (ret) 593df70ddadSAntti Palosaari goto err; 594df70ddadSAntti Palosaari 595df70ddadSAntti Palosaari return 0; 596df70ddadSAntti Palosaari err: 597df70ddadSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 598df70ddadSAntti Palosaari return ret; 599df70ddadSAntti Palosaari } 600df70ddadSAntti Palosaari 601df70ddadSAntti Palosaari static int rtl2830_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, int onoff) 602df70ddadSAntti Palosaari { 603df70ddadSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 604df70ddadSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 605df70ddadSAntti Palosaari int ret; 606df70ddadSAntti Palosaari u8 buf[4]; 607df70ddadSAntti Palosaari 608df70ddadSAntti Palosaari dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n", 609df70ddadSAntti Palosaari index, pid, onoff); 610df70ddadSAntti Palosaari 611df70ddadSAntti Palosaari /* skip invalid PIDs (0x2000) */ 612df70ddadSAntti Palosaari if (pid > 0x1fff || index > 32) 613df70ddadSAntti Palosaari return 0; 614df70ddadSAntti Palosaari 615df70ddadSAntti Palosaari if (onoff) 616df70ddadSAntti Palosaari set_bit(index, &dev->filters); 617df70ddadSAntti Palosaari else 618df70ddadSAntti Palosaari clear_bit(index, &dev->filters); 619df70ddadSAntti Palosaari 620df70ddadSAntti Palosaari /* enable / disable PIDs */ 621df70ddadSAntti Palosaari buf[0] = (dev->filters >> 0) & 0xff; 622df70ddadSAntti Palosaari buf[1] = (dev->filters >> 8) & 0xff; 623df70ddadSAntti Palosaari buf[2] = (dev->filters >> 16) & 0xff; 624df70ddadSAntti Palosaari buf[3] = (dev->filters >> 24) & 0xff; 62515d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x062, buf, 4); 626df70ddadSAntti Palosaari if (ret) 627df70ddadSAntti Palosaari goto err; 628df70ddadSAntti Palosaari 629df70ddadSAntti Palosaari /* add PID */ 630df70ddadSAntti Palosaari buf[0] = (pid >> 8) & 0xff; 631df70ddadSAntti Palosaari buf[1] = (pid >> 0) & 0xff; 63215d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x066 + 2 * index, buf, 2); 633df70ddadSAntti Palosaari if (ret) 634df70ddadSAntti Palosaari goto err; 635df70ddadSAntti Palosaari 636df70ddadSAntti Palosaari return 0; 637df70ddadSAntti Palosaari err: 638df70ddadSAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 639df70ddadSAntti Palosaari return ret; 640df70ddadSAntti Palosaari } 641df70ddadSAntti Palosaari 64228c08799SAntti Palosaari /* 64315d37f38SAntti Palosaari * I2C gate/mux/repeater logic 64415d37f38SAntti Palosaari * We must use unlocked __i2c_transfer() here (through regmap) because of I2C 64515d37f38SAntti Palosaari * adapter lock is already taken by tuner driver. 64615d37f38SAntti Palosaari * Gate is closed automatically after single I2C transfer. 64728c08799SAntti Palosaari */ 648a0119159SPeter Rosin static int rtl2830_select(struct i2c_mux_core *muxc, u32 chan_id) 64928c08799SAntti Palosaari { 650a0119159SPeter Rosin struct i2c_client *client = i2c_mux_priv(muxc); 651f544f100SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 65228c08799SAntti Palosaari int ret; 65328c08799SAntti Palosaari 654fd4cfa8bSAntti Palosaari dev_dbg(&client->dev, "\n"); 655fd4cfa8bSAntti Palosaari 65615d37f38SAntti Palosaari /* open I2C repeater for 1 transfer, closes automatically */ 65715d37f38SAntti Palosaari /* XXX: regmap_update_bits() does not lock I2C adapter */ 65815d37f38SAntti Palosaari ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08); 65915d37f38SAntti Palosaari if (ret) 66028c08799SAntti Palosaari goto err; 66128c08799SAntti Palosaari 66228c08799SAntti Palosaari return 0; 66328c08799SAntti Palosaari err: 6647cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 66528c08799SAntti Palosaari return ret; 66628c08799SAntti Palosaari } 66728c08799SAntti Palosaari 66828c08799SAntti Palosaari static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client) 66928c08799SAntti Palosaari { 670f544f100SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 67128c08799SAntti Palosaari 67228c08799SAntti Palosaari dev_dbg(&client->dev, "\n"); 67328c08799SAntti Palosaari 674f544f100SAntti Palosaari return &dev->fe; 67528c08799SAntti Palosaari } 67628c08799SAntti Palosaari 67728c08799SAntti Palosaari static struct i2c_adapter *rtl2830_get_i2c_adapter(struct i2c_client *client) 67828c08799SAntti Palosaari { 679f544f100SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 68028c08799SAntti Palosaari 68128c08799SAntti Palosaari dev_dbg(&client->dev, "\n"); 68228c08799SAntti Palosaari 683a0119159SPeter Rosin return dev->muxc->adapter[0]; 68428c08799SAntti Palosaari } 68528c08799SAntti Palosaari 68615d37f38SAntti Palosaari /* 68715d37f38SAntti Palosaari * We implement own I2C access routines for regmap in order to get manual access 68815d37f38SAntti Palosaari * to I2C adapter lock, which is needed for I2C mux adapter. 68915d37f38SAntti Palosaari */ 69015d37f38SAntti Palosaari static int rtl2830_regmap_read(void *context, const void *reg_buf, 69115d37f38SAntti Palosaari size_t reg_size, void *val_buf, size_t val_size) 69215d37f38SAntti Palosaari { 69315d37f38SAntti Palosaari struct i2c_client *client = context; 69415d37f38SAntti Palosaari int ret; 69515d37f38SAntti Palosaari struct i2c_msg msg[2] = { 69615d37f38SAntti Palosaari { 69715d37f38SAntti Palosaari .addr = client->addr, 69815d37f38SAntti Palosaari .flags = 0, 69915d37f38SAntti Palosaari .len = reg_size, 70015d37f38SAntti Palosaari .buf = (u8 *)reg_buf, 70115d37f38SAntti Palosaari }, { 70215d37f38SAntti Palosaari .addr = client->addr, 70315d37f38SAntti Palosaari .flags = I2C_M_RD, 70415d37f38SAntti Palosaari .len = val_size, 70515d37f38SAntti Palosaari .buf = val_buf, 70615d37f38SAntti Palosaari } 70715d37f38SAntti Palosaari }; 70815d37f38SAntti Palosaari 70915d37f38SAntti Palosaari ret = __i2c_transfer(client->adapter, msg, 2); 71015d37f38SAntti Palosaari if (ret != 2) { 71115d37f38SAntti Palosaari dev_warn(&client->dev, "i2c reg read failed %d\n", ret); 71215d37f38SAntti Palosaari if (ret >= 0) 71315d37f38SAntti Palosaari ret = -EREMOTEIO; 71415d37f38SAntti Palosaari return ret; 71515d37f38SAntti Palosaari } 71615d37f38SAntti Palosaari return 0; 71715d37f38SAntti Palosaari } 71815d37f38SAntti Palosaari 71915d37f38SAntti Palosaari static int rtl2830_regmap_write(void *context, const void *data, size_t count) 72015d37f38SAntti Palosaari { 72115d37f38SAntti Palosaari struct i2c_client *client = context; 72215d37f38SAntti Palosaari int ret; 72315d37f38SAntti Palosaari struct i2c_msg msg[1] = { 72415d37f38SAntti Palosaari { 72515d37f38SAntti Palosaari .addr = client->addr, 72615d37f38SAntti Palosaari .flags = 0, 72715d37f38SAntti Palosaari .len = count, 72815d37f38SAntti Palosaari .buf = (u8 *)data, 72915d37f38SAntti Palosaari } 73015d37f38SAntti Palosaari }; 73115d37f38SAntti Palosaari 73215d37f38SAntti Palosaari ret = __i2c_transfer(client->adapter, msg, 1); 73315d37f38SAntti Palosaari if (ret != 1) { 73415d37f38SAntti Palosaari dev_warn(&client->dev, "i2c reg write failed %d\n", ret); 73515d37f38SAntti Palosaari if (ret >= 0) 73615d37f38SAntti Palosaari ret = -EREMOTEIO; 73715d37f38SAntti Palosaari return ret; 73815d37f38SAntti Palosaari } 73915d37f38SAntti Palosaari return 0; 74015d37f38SAntti Palosaari } 74115d37f38SAntti Palosaari 74215d37f38SAntti Palosaari static int rtl2830_regmap_gather_write(void *context, const void *reg, 74315d37f38SAntti Palosaari size_t reg_len, const void *val, 74415d37f38SAntti Palosaari size_t val_len) 74515d37f38SAntti Palosaari { 74615d37f38SAntti Palosaari struct i2c_client *client = context; 74715d37f38SAntti Palosaari int ret; 74815d37f38SAntti Palosaari u8 buf[256]; 74915d37f38SAntti Palosaari struct i2c_msg msg[1] = { 75015d37f38SAntti Palosaari { 75115d37f38SAntti Palosaari .addr = client->addr, 75215d37f38SAntti Palosaari .flags = 0, 75315d37f38SAntti Palosaari .len = 1 + val_len, 75415d37f38SAntti Palosaari .buf = buf, 75515d37f38SAntti Palosaari } 75615d37f38SAntti Palosaari }; 75715d37f38SAntti Palosaari 75815d37f38SAntti Palosaari buf[0] = *(u8 const *)reg; 75915d37f38SAntti Palosaari memcpy(&buf[1], val, val_len); 76015d37f38SAntti Palosaari 76115d37f38SAntti Palosaari ret = __i2c_transfer(client->adapter, msg, 1); 76215d37f38SAntti Palosaari if (ret != 1) { 76315d37f38SAntti Palosaari dev_warn(&client->dev, "i2c reg write failed %d\n", ret); 76415d37f38SAntti Palosaari if (ret >= 0) 76515d37f38SAntti Palosaari ret = -EREMOTEIO; 76615d37f38SAntti Palosaari return ret; 76715d37f38SAntti Palosaari } 76815d37f38SAntti Palosaari return 0; 76915d37f38SAntti Palosaari } 77015d37f38SAntti Palosaari 77128c08799SAntti Palosaari static int rtl2830_probe(struct i2c_client *client, 77228c08799SAntti Palosaari const struct i2c_device_id *id) 77328c08799SAntti Palosaari { 77428c08799SAntti Palosaari struct rtl2830_platform_data *pdata = client->dev.platform_data; 775f544f100SAntti Palosaari struct rtl2830_dev *dev; 77628c08799SAntti Palosaari int ret; 77728c08799SAntti Palosaari u8 u8tmp; 77815d37f38SAntti Palosaari static const struct regmap_bus regmap_bus = { 77915d37f38SAntti Palosaari .read = rtl2830_regmap_read, 78015d37f38SAntti Palosaari .write = rtl2830_regmap_write, 78115d37f38SAntti Palosaari .gather_write = rtl2830_regmap_gather_write, 78215d37f38SAntti Palosaari .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 78315d37f38SAntti Palosaari }; 78415d37f38SAntti Palosaari static const struct regmap_range_cfg regmap_range_cfg[] = { 78515d37f38SAntti Palosaari { 78615d37f38SAntti Palosaari .selector_reg = 0x00, 78715d37f38SAntti Palosaari .selector_mask = 0xff, 78815d37f38SAntti Palosaari .selector_shift = 0, 78915d37f38SAntti Palosaari .window_start = 0, 79015d37f38SAntti Palosaari .window_len = 0x100, 79115d37f38SAntti Palosaari .range_min = 0 * 0x100, 79215d37f38SAntti Palosaari .range_max = 5 * 0x100, 79315d37f38SAntti Palosaari }, 79415d37f38SAntti Palosaari }; 79515d37f38SAntti Palosaari static const struct regmap_config regmap_config = { 79615d37f38SAntti Palosaari .reg_bits = 8, 79715d37f38SAntti Palosaari .val_bits = 8, 79815d37f38SAntti Palosaari .max_register = 5 * 0x100, 79915d37f38SAntti Palosaari .ranges = regmap_range_cfg, 80015d37f38SAntti Palosaari .num_ranges = ARRAY_SIZE(regmap_range_cfg), 80115d37f38SAntti Palosaari }; 80228c08799SAntti Palosaari 80328c08799SAntti Palosaari dev_dbg(&client->dev, "\n"); 80428c08799SAntti Palosaari 80528c08799SAntti Palosaari if (pdata == NULL) { 80628c08799SAntti Palosaari ret = -EINVAL; 80728c08799SAntti Palosaari goto err; 80828c08799SAntti Palosaari } 80928c08799SAntti Palosaari 81028c08799SAntti Palosaari /* allocate memory for the internal state */ 811f544f100SAntti Palosaari dev = kzalloc(sizeof(*dev), GFP_KERNEL); 812f544f100SAntti Palosaari if (dev == NULL) { 81328c08799SAntti Palosaari ret = -ENOMEM; 81428c08799SAntti Palosaari goto err; 81528c08799SAntti Palosaari } 81628c08799SAntti Palosaari 81728c08799SAntti Palosaari /* setup the state */ 818f544f100SAntti Palosaari i2c_set_clientdata(client, dev); 81947b4dbffSAntti Palosaari dev->client = client; 820b8cb50d2SAntti Palosaari dev->pdata = client->dev.platform_data; 821f544f100SAntti Palosaari dev->sleeping = true; 82215d37f38SAntti Palosaari dev->regmap = regmap_init(&client->dev, ®map_bus, client, 82315d37f38SAntti Palosaari ®map_config); 82415d37f38SAntti Palosaari if (IS_ERR(dev->regmap)) { 82515d37f38SAntti Palosaari ret = PTR_ERR(dev->regmap); 82615d37f38SAntti Palosaari goto err_kfree; 82715d37f38SAntti Palosaari } 82828c08799SAntti Palosaari 82928c08799SAntti Palosaari /* check if the demod is there */ 83015d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x000, &u8tmp, 1); 83128c08799SAntti Palosaari if (ret) 83215d37f38SAntti Palosaari goto err_regmap_exit; 83328c08799SAntti Palosaari 83428c08799SAntti Palosaari /* create muxed i2c adapter for tuner */ 835a0119159SPeter Rosin dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0, 836a0119159SPeter Rosin rtl2830_select, NULL); 837a0119159SPeter Rosin if (!dev->muxc) { 838a0119159SPeter Rosin ret = -ENOMEM; 83915d37f38SAntti Palosaari goto err_regmap_exit; 84028c08799SAntti Palosaari } 841a0119159SPeter Rosin dev->muxc->priv = client; 842a0119159SPeter Rosin ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); 843a0119159SPeter Rosin if (ret) 844a0119159SPeter Rosin goto err_regmap_exit; 84528c08799SAntti Palosaari 84628c08799SAntti Palosaari /* create dvb frontend */ 847f544f100SAntti Palosaari memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops)); 8481f153c4dSAntti Palosaari dev->fe.demodulator_priv = client; 84928c08799SAntti Palosaari 85028c08799SAntti Palosaari /* setup callbacks */ 85128c08799SAntti Palosaari pdata->get_dvb_frontend = rtl2830_get_dvb_frontend; 85228c08799SAntti Palosaari pdata->get_i2c_adapter = rtl2830_get_i2c_adapter; 853df70ddadSAntti Palosaari pdata->pid_filter = rtl2830_pid_filter; 854df70ddadSAntti Palosaari pdata->pid_filter_ctrl = rtl2830_pid_filter_ctrl; 85528c08799SAntti Palosaari 85628c08799SAntti Palosaari dev_info(&client->dev, "Realtek RTL2830 successfully attached\n"); 85728c08799SAntti Palosaari 858947debb4SAntti Palosaari return 0; 85915d37f38SAntti Palosaari err_regmap_exit: 86015d37f38SAntti Palosaari regmap_exit(dev->regmap); 86128c08799SAntti Palosaari err_kfree: 862f544f100SAntti Palosaari kfree(dev); 86328c08799SAntti Palosaari err: 86428c08799SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 86528c08799SAntti Palosaari return ret; 86628c08799SAntti Palosaari } 86728c08799SAntti Palosaari 86828c08799SAntti Palosaari static int rtl2830_remove(struct i2c_client *client) 86928c08799SAntti Palosaari { 870f544f100SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 87128c08799SAntti Palosaari 87228c08799SAntti Palosaari dev_dbg(&client->dev, "\n"); 87328c08799SAntti Palosaari 874a0119159SPeter Rosin i2c_mux_del_adapters(dev->muxc); 87515d37f38SAntti Palosaari regmap_exit(dev->regmap); 876f544f100SAntti Palosaari kfree(dev); 877947debb4SAntti Palosaari 87828c08799SAntti Palosaari return 0; 87928c08799SAntti Palosaari } 88028c08799SAntti Palosaari 88128c08799SAntti Palosaari static const struct i2c_device_id rtl2830_id_table[] = { 88228c08799SAntti Palosaari {"rtl2830", 0}, 88328c08799SAntti Palosaari {} 88428c08799SAntti Palosaari }; 88528c08799SAntti Palosaari MODULE_DEVICE_TABLE(i2c, rtl2830_id_table); 88628c08799SAntti Palosaari 88728c08799SAntti Palosaari static struct i2c_driver rtl2830_driver = { 88828c08799SAntti Palosaari .driver = { 88928c08799SAntti Palosaari .name = "rtl2830", 89095e7cdb7SAntti Palosaari .suppress_bind_attrs = true, 89128c08799SAntti Palosaari }, 89228c08799SAntti Palosaari .probe = rtl2830_probe, 89328c08799SAntti Palosaari .remove = rtl2830_remove, 89428c08799SAntti Palosaari .id_table = rtl2830_id_table, 89528c08799SAntti Palosaari }; 89628c08799SAntti Palosaari 89728c08799SAntti Palosaari module_i2c_driver(rtl2830_driver); 89828c08799SAntti Palosaari 8999a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 9009a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); 9019a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 902