xref: /linux/drivers/media/dvb-frontends/rtl2830.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
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, &regmap_bus, client,
82315d37f38SAntti Palosaari 				  &regmap_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