1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2c0adca73SAntti Palosaari /* 3c0adca73SAntti Palosaari * Realtek RTL2830 DVB-T demodulator driver 4c0adca73SAntti Palosaari * 5c0adca73SAntti Palosaari * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> 6c0adca73SAntti Palosaari */ 7c0adca73SAntti Palosaari 8c0adca73SAntti Palosaari #include "rtl2830_priv.h" 9c0adca73SAntti Palosaari 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) 130485a708SAntti Palosaari { 141f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 150485a708SAntti Palosaari int ret; 160485a708SAntti Palosaari 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; 210485a708SAntti Palosaari } 220485a708SAntti Palosaari 23d858b0e7SMauro Carvalho Chehab static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg, 2415d37f38SAntti Palosaari unsigned int mask, unsigned int val) 250485a708SAntti Palosaari { 261f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 270485a708SAntti Palosaari int ret; 280485a708SAntti Palosaari 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; 330485a708SAntti Palosaari } 340485a708SAntti Palosaari 35d858b0e7SMauro Carvalho Chehab static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg, 36d858b0e7SMauro Carvalho Chehab void *val, size_t val_count) 37c0adca73SAntti Palosaari { 3815d37f38SAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 39c0adca73SAntti Palosaari int ret; 40c0adca73SAntti Palosaari 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); 44c0adca73SAntti Palosaari return ret; 45c0adca73SAntti Palosaari } 46c0adca73SAntti Palosaari 47c0adca73SAntti Palosaari static int rtl2830_init(struct dvb_frontend *fe) 48c0adca73SAntti Palosaari { 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; 52c0adca73SAntti Palosaari int ret, i; 53c0adca73SAntti Palosaari struct rtl2830_reg_val_mask tab[] = { 54c0adca73SAntti Palosaari {0x00d, 0x01, 0x03}, 55c0adca73SAntti Palosaari {0x00d, 0x10, 0x10}, 56c0adca73SAntti Palosaari {0x104, 0x00, 0x1e}, 57c0adca73SAntti Palosaari {0x105, 0x80, 0x80}, 58c0adca73SAntti Palosaari {0x110, 0x02, 0x03}, 59c0adca73SAntti Palosaari {0x110, 0x08, 0x0c}, 60c0adca73SAntti Palosaari {0x17b, 0x00, 0x40}, 61c0adca73SAntti Palosaari {0x17d, 0x05, 0x0f}, 62c0adca73SAntti Palosaari {0x17d, 0x50, 0xf0}, 63c0adca73SAntti Palosaari {0x18c, 0x08, 0x0f}, 64c0adca73SAntti Palosaari {0x18d, 0x00, 0xc0}, 65c0adca73SAntti Palosaari {0x188, 0x05, 0x0f}, 66c0adca73SAntti Palosaari {0x189, 0x00, 0xfc}, 67c0adca73SAntti Palosaari {0x2d5, 0x02, 0x02}, 68c0adca73SAntti Palosaari {0x2f1, 0x02, 0x06}, 69c0adca73SAntti Palosaari {0x2f1, 0x20, 0xf8}, 70c0adca73SAntti Palosaari {0x16d, 0x00, 0x01}, 71c0adca73SAntti Palosaari {0x1a6, 0x00, 0x80}, 72b8cb50d2SAntti Palosaari {0x106, dev->pdata->vtop, 0x3f}, 73b8cb50d2SAntti Palosaari {0x107, dev->pdata->krf, 0x3f}, 74c0adca73SAntti Palosaari {0x112, 0x28, 0xff}, 75b8cb50d2SAntti Palosaari {0x103, dev->pdata->agc_targ_val, 0xff}, 76c0adca73SAntti Palosaari {0x00a, 0x02, 0x07}, 77c0adca73SAntti Palosaari {0x140, 0x0c, 0x3c}, 78c0adca73SAntti Palosaari {0x140, 0x40, 0xc0}, 79c0adca73SAntti Palosaari {0x15b, 0x05, 0x07}, 80c0adca73SAntti Palosaari {0x15b, 0x28, 0x38}, 81c0adca73SAntti Palosaari {0x15c, 0x05, 0x07}, 82c0adca73SAntti Palosaari {0x15c, 0x28, 0x38}, 83b8cb50d2SAntti Palosaari {0x115, dev->pdata->spec_inv, 0x01}, 84c0adca73SAntti Palosaari {0x16f, 0x01, 0x07}, 85c0adca73SAntti Palosaari {0x170, 0x18, 0x38}, 86c0adca73SAntti Palosaari {0x172, 0x0f, 0x0f}, 87c0adca73SAntti Palosaari {0x173, 0x08, 0x38}, 88c0adca73SAntti Palosaari {0x175, 0x01, 0x07}, 89c0adca73SAntti Palosaari {0x176, 0x00, 0xc0}, 90c0adca73SAntti Palosaari }; 91c0adca73SAntti Palosaari 92c0adca73SAntti Palosaari 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); 95c0adca73SAntti Palosaari if (ret) 96c0adca73SAntti Palosaari goto err; 97c0adca73SAntti Palosaari } 98c0adca73SAntti Palosaari 9915d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x18f, "\x28\x00", 2); 100c0adca73SAntti Palosaari if (ret) 101c0adca73SAntti Palosaari goto err; 102c0adca73SAntti Palosaari 10315d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x195, 104c0adca73SAntti Palosaari "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); 105c0adca73SAntti Palosaari if (ret) 106c0adca73SAntti Palosaari goto err; 107c0adca73SAntti Palosaari 108c0adca73SAntti Palosaari /* TODO: spec init */ 109c0adca73SAntti Palosaari 110c0adca73SAntti Palosaari /* soft reset */ 11115d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x101, 0x04, 0x04); 112c0adca73SAntti Palosaari if (ret) 113c0adca73SAntti Palosaari goto err; 114c0adca73SAntti Palosaari 11515d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x101, 0x04, 0x00); 116c0adca73SAntti Palosaari if (ret) 117c0adca73SAntti Palosaari goto err; 118c0adca73SAntti Palosaari 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; 130a8567cf2SAntti Palosaari 131c0adca73SAntti Palosaari return ret; 132c0adca73SAntti Palosaari err: 1337cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 134c0adca73SAntti Palosaari return ret; 135c0adca73SAntti Palosaari } 136c0adca73SAntti Palosaari 137a8567cf2SAntti Palosaari static int rtl2830_sleep(struct dvb_frontend *fe) 138a8567cf2SAntti Palosaari { 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 145a8567cf2SAntti Palosaari return 0; 146a8567cf2SAntti Palosaari } 147a8567cf2SAntti Palosaari 148a17ff2eeSMauro Carvalho Chehab static int rtl2830_get_tune_settings(struct dvb_frontend *fe, 149c0adca73SAntti Palosaari struct dvb_frontend_tune_settings *s) 150c0adca73SAntti Palosaari { 151c0adca73SAntti Palosaari 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; 154c0adca73SAntti Palosaari 155c0adca73SAntti Palosaari return 0; 156c0adca73SAntti Palosaari } 157c0adca73SAntti Palosaari 158c0adca73SAntti Palosaari static int rtl2830_set_frontend(struct dvb_frontend *fe) 159c0adca73SAntti Palosaari { 1601f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 1611f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 162c0adca73SAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 163c0adca73SAntti Palosaari 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] = { 168c0adca73SAntti Palosaari { 169c0adca73SAntti Palosaari 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, 170c0adca73SAntti Palosaari 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, 171c0adca73SAntti Palosaari 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, 172c0adca73SAntti Palosaari 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ 173c0adca73SAntti Palosaari }, { 174c0adca73SAntti Palosaari 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, 175c0adca73SAntti Palosaari 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, 176c0adca73SAntti Palosaari 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, 177c0adca73SAntti Palosaari 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ 178c0adca73SAntti Palosaari }, { 179c0adca73SAntti Palosaari 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, 180c0adca73SAntti Palosaari 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, 181c0adca73SAntti Palosaari 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, 182c0adca73SAntti Palosaari 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ 183c0adca73SAntti Palosaari }, 184c0adca73SAntti Palosaari }; 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 */ 189c0adca73SAntti Palosaari }; 190c0adca73SAntti Palosaari 1917cc39328SAntti Palosaari dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n", 1927cc39328SAntti Palosaari c->frequency, c->bandwidth_hz, c->inversion); 193c0adca73SAntti Palosaari 194c0adca73SAntti Palosaari /* program tuner */ 195c0adca73SAntti Palosaari if (fe->ops.tuner_ops.set_params) 196c0adca73SAntti Palosaari fe->ops.tuner_ops.set_params(fe); 197c0adca73SAntti Palosaari 198c0adca73SAntti Palosaari switch (c->bandwidth_hz) { 199c0adca73SAntti Palosaari case 6000000: 200c0adca73SAntti Palosaari i = 0; 201c0adca73SAntti Palosaari break; 202c0adca73SAntti Palosaari case 7000000: 203c0adca73SAntti Palosaari i = 1; 204c0adca73SAntti Palosaari break; 205c0adca73SAntti Palosaari case 8000000: 206c0adca73SAntti Palosaari i = 2; 207c0adca73SAntti Palosaari break; 208c0adca73SAntti Palosaari default: 2097cc39328SAntti Palosaari dev_err(&client->dev, "invalid bandwidth_hz %u\n", 2107cc39328SAntti Palosaari c->bandwidth_hz); 211c0adca73SAntti Palosaari return -EINVAL; 212c0adca73SAntti Palosaari } 213c0adca73SAntti Palosaari 21415d37f38SAntti Palosaari ret = rtl2830_update_bits(client, 0x008, 0x06, i << 1); 215c0adca73SAntti Palosaari if (ret) 216c0adca73SAntti Palosaari goto err; 217c0adca73SAntti Palosaari 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 248c0adca73SAntti Palosaari /* 1/2 split I2C write */ 24915d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x11c, &bw_params1[i][0], 17); 250c0adca73SAntti Palosaari if (ret) 251c0adca73SAntti Palosaari goto err; 252c0adca73SAntti Palosaari 253c0adca73SAntti Palosaari /* 2/2 split I2C write */ 25415d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x12d, &bw_params1[i][17], 17); 255c0adca73SAntti Palosaari if (ret) 256c0adca73SAntti Palosaari goto err; 257c0adca73SAntti Palosaari 25815d37f38SAntti Palosaari ret = rtl2830_bulk_write(client, 0x19d, bw_params2[i], 6); 259c0adca73SAntti Palosaari if (ret) 260c0adca73SAntti Palosaari goto err; 261c0adca73SAntti Palosaari 262c0adca73SAntti Palosaari return ret; 263c0adca73SAntti Palosaari err: 2647cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 265c0adca73SAntti Palosaari return ret; 266c0adca73SAntti Palosaari } 267c0adca73SAntti Palosaari 2687e3e68bcSMauro Carvalho Chehab static int rtl2830_get_frontend(struct dvb_frontend *fe, 2697e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *c) 270631a2b61SAntti Palosaari { 2711f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 2721f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 273631a2b61SAntti Palosaari int ret; 274631a2b61SAntti Palosaari u8 buf[3]; 275631a2b61SAntti Palosaari 276f544f100SAntti Palosaari if (dev->sleeping) 277c188637dSAntti Palosaari return 0; 278c188637dSAntti Palosaari 27915d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x33c, buf, 2); 280631a2b61SAntti Palosaari if (ret) 281631a2b61SAntti Palosaari goto err; 282631a2b61SAntti Palosaari 28315d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x351, &buf[2], 1); 284631a2b61SAntti Palosaari if (ret) 285631a2b61SAntti Palosaari goto err; 286631a2b61SAntti Palosaari 2877cc39328SAntti Palosaari dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf); 288631a2b61SAntti Palosaari 289631a2b61SAntti Palosaari switch ((buf[0] >> 2) & 3) { 290631a2b61SAntti Palosaari case 0: 291631a2b61SAntti Palosaari c->modulation = QPSK; 292631a2b61SAntti Palosaari break; 293631a2b61SAntti Palosaari case 1: 294631a2b61SAntti Palosaari c->modulation = QAM_16; 295631a2b61SAntti Palosaari break; 296631a2b61SAntti Palosaari case 2: 297631a2b61SAntti Palosaari c->modulation = QAM_64; 298631a2b61SAntti Palosaari break; 299631a2b61SAntti Palosaari } 300631a2b61SAntti Palosaari 301631a2b61SAntti Palosaari switch ((buf[2] >> 2) & 1) { 302631a2b61SAntti Palosaari case 0: 303631a2b61SAntti Palosaari c->transmission_mode = TRANSMISSION_MODE_2K; 304631a2b61SAntti Palosaari break; 305631a2b61SAntti Palosaari case 1: 306631a2b61SAntti Palosaari c->transmission_mode = TRANSMISSION_MODE_8K; 307631a2b61SAntti Palosaari } 308631a2b61SAntti Palosaari 309631a2b61SAntti Palosaari switch ((buf[2] >> 0) & 3) { 310631a2b61SAntti Palosaari case 0: 311631a2b61SAntti Palosaari c->guard_interval = GUARD_INTERVAL_1_32; 312631a2b61SAntti Palosaari break; 313631a2b61SAntti Palosaari case 1: 314631a2b61SAntti Palosaari c->guard_interval = GUARD_INTERVAL_1_16; 315631a2b61SAntti Palosaari break; 316631a2b61SAntti Palosaari case 2: 317631a2b61SAntti Palosaari c->guard_interval = GUARD_INTERVAL_1_8; 318631a2b61SAntti Palosaari break; 319631a2b61SAntti Palosaari case 3: 320631a2b61SAntti Palosaari c->guard_interval = GUARD_INTERVAL_1_4; 321631a2b61SAntti Palosaari break; 322631a2b61SAntti Palosaari } 323631a2b61SAntti Palosaari 324631a2b61SAntti Palosaari switch ((buf[0] >> 4) & 7) { 325631a2b61SAntti Palosaari case 0: 326631a2b61SAntti Palosaari c->hierarchy = HIERARCHY_NONE; 327631a2b61SAntti Palosaari break; 328631a2b61SAntti Palosaari case 1: 329631a2b61SAntti Palosaari c->hierarchy = HIERARCHY_1; 330631a2b61SAntti Palosaari break; 331631a2b61SAntti Palosaari case 2: 332631a2b61SAntti Palosaari c->hierarchy = HIERARCHY_2; 333631a2b61SAntti Palosaari break; 334631a2b61SAntti Palosaari case 3: 335631a2b61SAntti Palosaari c->hierarchy = HIERARCHY_4; 336631a2b61SAntti Palosaari break; 337631a2b61SAntti Palosaari } 338631a2b61SAntti Palosaari 339631a2b61SAntti Palosaari switch ((buf[1] >> 3) & 7) { 340631a2b61SAntti Palosaari case 0: 341631a2b61SAntti Palosaari c->code_rate_HP = FEC_1_2; 342631a2b61SAntti Palosaari break; 343631a2b61SAntti Palosaari case 1: 344631a2b61SAntti Palosaari c->code_rate_HP = FEC_2_3; 345631a2b61SAntti Palosaari break; 346631a2b61SAntti Palosaari case 2: 347631a2b61SAntti Palosaari c->code_rate_HP = FEC_3_4; 348631a2b61SAntti Palosaari break; 349631a2b61SAntti Palosaari case 3: 350631a2b61SAntti Palosaari c->code_rate_HP = FEC_5_6; 351631a2b61SAntti Palosaari break; 352631a2b61SAntti Palosaari case 4: 353631a2b61SAntti Palosaari c->code_rate_HP = FEC_7_8; 354631a2b61SAntti Palosaari break; 355631a2b61SAntti Palosaari } 356631a2b61SAntti Palosaari 357631a2b61SAntti Palosaari switch ((buf[1] >> 0) & 7) { 358631a2b61SAntti Palosaari case 0: 359631a2b61SAntti Palosaari c->code_rate_LP = FEC_1_2; 360631a2b61SAntti Palosaari break; 361631a2b61SAntti Palosaari case 1: 362631a2b61SAntti Palosaari c->code_rate_LP = FEC_2_3; 363631a2b61SAntti Palosaari break; 364631a2b61SAntti Palosaari case 2: 365631a2b61SAntti Palosaari c->code_rate_LP = FEC_3_4; 366631a2b61SAntti Palosaari break; 367631a2b61SAntti Palosaari case 3: 368631a2b61SAntti Palosaari c->code_rate_LP = FEC_5_6; 369631a2b61SAntti Palosaari break; 370631a2b61SAntti Palosaari case 4: 371631a2b61SAntti Palosaari c->code_rate_LP = FEC_7_8; 372631a2b61SAntti Palosaari break; 373631a2b61SAntti Palosaari } 374631a2b61SAntti Palosaari 375631a2b61SAntti Palosaari return 0; 376631a2b61SAntti Palosaari err: 3777cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 378631a2b61SAntti Palosaari return ret; 379631a2b61SAntti Palosaari } 380631a2b61SAntti Palosaari 3810df289a2SMauro Carvalho Chehab static int rtl2830_read_status(struct dvb_frontend *fe, enum fe_status *status) 382c0adca73SAntti Palosaari { 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 390c0adca73SAntti Palosaari *status = 0; 391c0adca73SAntti Palosaari 392f544f100SAntti Palosaari if (dev->sleeping) 393a8567cf2SAntti Palosaari return 0; 394a8567cf2SAntti Palosaari 39515d37f38SAntti Palosaari ret = rtl2830_bulk_read(client, 0x351, &u8tmp, 1); 396c0adca73SAntti Palosaari if (ret) 397c0adca73SAntti Palosaari goto err; 398c0adca73SAntti Palosaari 39915d37f38SAntti Palosaari u8tmp = (u8tmp >> 3) & 0x0f; /* [6:3] */ 40015d37f38SAntti Palosaari if (u8tmp == 11) { 401c0adca73SAntti Palosaari *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | 402c0adca73SAntti Palosaari FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; 40315d37f38SAntti Palosaari } else if (u8tmp == 10) { 404c0adca73SAntti Palosaari *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | 405c0adca73SAntti Palosaari FE_HAS_VITERBI; 406c0adca73SAntti Palosaari } 407c0adca73SAntti Palosaari 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 493c0adca73SAntti Palosaari return ret; 494c0adca73SAntti Palosaari err: 4957cc39328SAntti Palosaari dev_dbg(&client->dev, "failed=%d\n", ret); 496c0adca73SAntti Palosaari return ret; 497c0adca73SAntti Palosaari } 498c0adca73SAntti Palosaari 499c0adca73SAntti Palosaari static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) 500c0adca73SAntti Palosaari { 5016dcfe3ccSAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 502eba672a0SAntti Palosaari 5036dcfe3ccSAntti Palosaari if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) 5046dcfe3ccSAntti Palosaari *snr = div_s64(c->cnr.stat[0].svalue, 100); 505eba672a0SAntti Palosaari else 506c0adca73SAntti Palosaari *snr = 0; 507eba672a0SAntti Palosaari 508c0adca73SAntti Palosaari return 0; 509c0adca73SAntti Palosaari } 510c0adca73SAntti Palosaari 511c0adca73SAntti Palosaari static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) 512c0adca73SAntti Palosaari { 5131f153c4dSAntti Palosaari struct i2c_client *client = fe->demodulator_priv; 5141f153c4dSAntti Palosaari struct rtl2830_dev *dev = i2c_get_clientdata(client); 515525ffc19SAntti Palosaari 516f491391cSAntti Palosaari *ber = (dev->post_bit_error - dev->post_bit_error_prev); 517f491391cSAntti Palosaari dev->post_bit_error_prev = dev->post_bit_error; 518525ffc19SAntti Palosaari 519c0adca73SAntti Palosaari return 0; 520c0adca73SAntti Palosaari } 521c0adca73SAntti Palosaari 522c0adca73SAntti Palosaari static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 523c0adca73SAntti Palosaari { 524c0adca73SAntti Palosaari *ucblocks = 0; 525947debb4SAntti Palosaari 526c0adca73SAntti Palosaari return 0; 527c0adca73SAntti Palosaari } 528c0adca73SAntti Palosaari 529c0adca73SAntti Palosaari static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 530c0adca73SAntti Palosaari { 531d512e286SAntti Palosaari struct dtv_frontend_properties *c = &fe->dtv_property_cache; 53278e75075SAntti Palosaari 533d512e286SAntti Palosaari if (c->strength.stat[0].scale == FE_SCALE_RELATIVE) 534d512e286SAntti Palosaari *strength = c->strength.stat[0].uvalue; 53578e75075SAntti Palosaari else 536d512e286SAntti Palosaari *strength = 0; 53778e75075SAntti Palosaari 538c0adca73SAntti Palosaari return 0; 539c0adca73SAntti Palosaari } 540c0adca73SAntti Palosaari 541bd336e63SMax Kellermann static const struct dvb_frontend_ops rtl2830_ops = { 542c0adca73SAntti Palosaari .delsys = {SYS_DVBT}, 543c0adca73SAntti Palosaari .info = { 544c0adca73SAntti Palosaari .name = "Realtek RTL2830 (DVB-T)", 545c0adca73SAntti Palosaari .caps = FE_CAN_FEC_1_2 | 546c0adca73SAntti Palosaari FE_CAN_FEC_2_3 | 547c0adca73SAntti Palosaari FE_CAN_FEC_3_4 | 548c0adca73SAntti Palosaari FE_CAN_FEC_5_6 | 549c0adca73SAntti Palosaari FE_CAN_FEC_7_8 | 550c0adca73SAntti Palosaari FE_CAN_FEC_AUTO | 551c0adca73SAntti Palosaari FE_CAN_QPSK | 552c0adca73SAntti Palosaari FE_CAN_QAM_16 | 553c0adca73SAntti Palosaari FE_CAN_QAM_64 | 554c0adca73SAntti Palosaari FE_CAN_QAM_AUTO | 555c0adca73SAntti Palosaari FE_CAN_TRANSMISSION_MODE_AUTO | 556c0adca73SAntti Palosaari FE_CAN_GUARD_INTERVAL_AUTO | 557c0adca73SAntti Palosaari FE_CAN_HIERARCHY_AUTO | 558c0adca73SAntti Palosaari FE_CAN_RECOVER | 559c0adca73SAntti Palosaari FE_CAN_MUTE_TS 560c0adca73SAntti Palosaari }, 561c0adca73SAntti Palosaari 562c0adca73SAntti Palosaari .init = rtl2830_init, 563a8567cf2SAntti Palosaari .sleep = rtl2830_sleep, 564c0adca73SAntti Palosaari 565c0adca73SAntti Palosaari .get_tune_settings = rtl2830_get_tune_settings, 566c0adca73SAntti Palosaari 567c0adca73SAntti Palosaari .set_frontend = rtl2830_set_frontend, 568631a2b61SAntti Palosaari .get_frontend = rtl2830_get_frontend, 569c0adca73SAntti Palosaari 570c0adca73SAntti Palosaari .read_status = rtl2830_read_status, 571c0adca73SAntti Palosaari .read_snr = rtl2830_read_snr, 572c0adca73SAntti Palosaari .read_ber = rtl2830_read_ber, 573c0adca73SAntti Palosaari .read_ucblocks = rtl2830_read_ucblocks, 574c0adca73SAntti Palosaari .read_signal_strength = rtl2830_read_signal_strength, 575c0adca73SAntti Palosaari }; 576c0adca73SAntti Palosaari 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 899c0adca73SAntti Palosaari MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 900c0adca73SAntti Palosaari MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); 901c0adca73SAntti Palosaari MODULE_LICENSE("GPL"); 902