fc2580.c 10.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * FCI FC2580 silicon tuner driver
 *
 * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "fc2580_priv.h"

/*
 * TODO:
 * I2C write and read works only for one single register. Multiple registers
 * could not be accessed using normal register address auto-increment.
 * There could be (very likely) register to change that behavior....
 */

30 31 32
/* write single register conditionally only when value differs from 0xff
 * XXX: This is special routine meant only for writing fc2580_freq_regs_lut[]
 * values. Do not use for the other purposes. */
33
static int fc2580_wr_reg_ff(struct fc2580_dev *dev, u8 reg, u8 val)
34 35 36 37
{
	if (val == 0xff)
		return 0;
	else
38
		return regmap_write(dev->regmap, reg, val);
39 40
}

41 42
static int fc2580_set_params(struct dvb_frontend *fe)
{
43 44
	struct fc2580_dev *dev = fe->tuner_priv;
	struct i2c_client *client = dev->client;
45
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
46 47
	int ret, i;
	unsigned int uitmp, div_ref, div_ref_val, div_n, k, k_cw, div_out;
48
	u64 f_vco;
49
	u8 synth_config;
50
	unsigned long timeout;
51

52 53 54
	dev_dbg(&client->dev,
		"delivery_system=%u frequency=%u bandwidth_hz=%u\n",
		c->delivery_system, c->frequency, c->bandwidth_hz);
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	/*
	 * Fractional-N synthesizer
	 *
	 *                      +---------------------------------------+
	 *                      v                                       |
	 *  Fref   +----+     +----+     +-------+         +----+     +------+     +---+
	 * ------> | /R | --> | PD | --> |  VCO  | ------> | /2 | --> | /N.F | <-- | K |
	 *         +----+     +----+     +-------+         +----+     +------+     +---+
	 *                                 |
	 *                                 |
	 *                                 v
	 *                               +-------+  Fout
	 *                               | /Rout | ------>
	 *                               +-------+
	 */
71 72 73 74
	for (i = 0; i < ARRAY_SIZE(fc2580_pll_lut); i++) {
		if (c->frequency <= fc2580_pll_lut[i].freq)
			break;
	}
75 76
	if (i == ARRAY_SIZE(fc2580_pll_lut)) {
		ret = -EINVAL;
77
		goto err;
78
	}
79

80
	#define DIV_PRE_N 2
81
	#define F_REF dev->clk
82 83 84 85 86
	div_out = fc2580_pll_lut[i].div_out;
	f_vco = (u64) c->frequency * div_out;
	synth_config = fc2580_pll_lut[i].band;
	if (f_vco < 2600000000ULL)
		synth_config |= 0x06;
87
	else
88 89 90 91 92 93 94 95 96 97
		synth_config |= 0x0e;

	/* select reference divider R (keep PLL div N in valid range) */
	#define DIV_N_MIN 76
	if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 1)) {
		div_ref = 1;
		div_ref_val = 0x00;
	} else if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 2)) {
		div_ref = 2;
		div_ref_val = 0x10;
98
	} else {
99 100
		div_ref = 4;
		div_ref_val = 0x20;
101 102
	}

103 104 105 106 107 108 109 110
	/* calculate PLL integer and fractional control word */
	uitmp = DIV_PRE_N * F_REF / div_ref;
	div_n = div_u64_rem(f_vco, uitmp, &k);
	k_cw = div_u64((u64) k * 0x100000, uitmp);

	dev_dbg(&client->dev,
		"frequency=%u f_vco=%llu F_REF=%u div_ref=%u div_n=%u k=%u div_out=%u k_cw=%0x\n",
		c->frequency, f_vco, F_REF, div_ref, div_n, k, div_out, k_cw);
111

112 113
	ret = regmap_write(dev->regmap, 0x02, synth_config);
	if (ret)
114 115
		goto err;

116 117
	ret = regmap_write(dev->regmap, 0x18, div_ref_val << 0 | k_cw >> 16);
	if (ret)
118 119
		goto err;

120 121
	ret = regmap_write(dev->regmap, 0x1a, (k_cw >> 8) & 0xff);
	if (ret)
122 123
		goto err;

124 125
	ret = regmap_write(dev->regmap, 0x1b, (k_cw >> 0) & 0xff);
	if (ret)
126 127
		goto err;

128 129
	ret = regmap_write(dev->regmap, 0x1c, div_n);
	if (ret)
130
		goto err;
131 132 133 134 135 136

	/* registers */
	for (i = 0; i < ARRAY_SIZE(fc2580_freq_regs_lut); i++) {
		if (c->frequency <= fc2580_freq_regs_lut[i].freq)
			break;
	}
137 138
	if (i == ARRAY_SIZE(fc2580_freq_regs_lut)) {
		ret = -EINVAL;
139
		goto err;
140
	}
141

142
	ret = fc2580_wr_reg_ff(dev, 0x25, fc2580_freq_regs_lut[i].r25_val);
143
	if (ret)
144 145
		goto err;

146
	ret = fc2580_wr_reg_ff(dev, 0x27, fc2580_freq_regs_lut[i].r27_val);
147
	if (ret)
148 149
		goto err;

150
	ret = fc2580_wr_reg_ff(dev, 0x28, fc2580_freq_regs_lut[i].r28_val);
151
	if (ret)
152 153
		goto err;

154
	ret = fc2580_wr_reg_ff(dev, 0x29, fc2580_freq_regs_lut[i].r29_val);
155
	if (ret)
156 157
		goto err;

158
	ret = fc2580_wr_reg_ff(dev, 0x2b, fc2580_freq_regs_lut[i].r2b_val);
159
	if (ret)
160 161
		goto err;

162
	ret = fc2580_wr_reg_ff(dev, 0x2c, fc2580_freq_regs_lut[i].r2c_val);
163
	if (ret)
164 165
		goto err;

166
	ret = fc2580_wr_reg_ff(dev, 0x2d, fc2580_freq_regs_lut[i].r2d_val);
167
	if (ret)
168 169
		goto err;

170
	ret = fc2580_wr_reg_ff(dev, 0x30, fc2580_freq_regs_lut[i].r30_val);
171
	if (ret)
172 173
		goto err;

174
	ret = fc2580_wr_reg_ff(dev, 0x44, fc2580_freq_regs_lut[i].r44_val);
175
	if (ret)
176 177
		goto err;

178
	ret = fc2580_wr_reg_ff(dev, 0x50, fc2580_freq_regs_lut[i].r50_val);
179
	if (ret)
180 181
		goto err;

182
	ret = fc2580_wr_reg_ff(dev, 0x53, fc2580_freq_regs_lut[i].r53_val);
183
	if (ret)
184 185
		goto err;

186
	ret = fc2580_wr_reg_ff(dev, 0x5f, fc2580_freq_regs_lut[i].r5f_val);
187
	if (ret)
188 189
		goto err;

190
	ret = fc2580_wr_reg_ff(dev, 0x61, fc2580_freq_regs_lut[i].r61_val);
191
	if (ret)
192 193
		goto err;

194
	ret = fc2580_wr_reg_ff(dev, 0x62, fc2580_freq_regs_lut[i].r62_val);
195
	if (ret)
196 197
		goto err;

198
	ret = fc2580_wr_reg_ff(dev, 0x63, fc2580_freq_regs_lut[i].r63_val);
199
	if (ret)
200 201
		goto err;

202
	ret = fc2580_wr_reg_ff(dev, 0x67, fc2580_freq_regs_lut[i].r67_val);
203
	if (ret)
204 205
		goto err;

206
	ret = fc2580_wr_reg_ff(dev, 0x68, fc2580_freq_regs_lut[i].r68_val);
207
	if (ret)
208 209
		goto err;

210
	ret = fc2580_wr_reg_ff(dev, 0x69, fc2580_freq_regs_lut[i].r69_val);
211
	if (ret)
212 213
		goto err;

214
	ret = fc2580_wr_reg_ff(dev, 0x6a, fc2580_freq_regs_lut[i].r6a_val);
215
	if (ret)
216 217
		goto err;

218
	ret = fc2580_wr_reg_ff(dev, 0x6b, fc2580_freq_regs_lut[i].r6b_val);
219
	if (ret)
220 221
		goto err;

222
	ret = fc2580_wr_reg_ff(dev, 0x6c, fc2580_freq_regs_lut[i].r6c_val);
223
	if (ret)
224 225
		goto err;

226
	ret = fc2580_wr_reg_ff(dev, 0x6d, fc2580_freq_regs_lut[i].r6d_val);
227
	if (ret)
228 229
		goto err;

230
	ret = fc2580_wr_reg_ff(dev, 0x6e, fc2580_freq_regs_lut[i].r6e_val);
231
	if (ret)
232 233
		goto err;

234
	ret = fc2580_wr_reg_ff(dev, 0x6f, fc2580_freq_regs_lut[i].r6f_val);
235
	if (ret)
236 237 238 239 240 241 242
		goto err;

	/* IF filters */
	for (i = 0; i < ARRAY_SIZE(fc2580_if_filter_lut); i++) {
		if (c->bandwidth_hz <= fc2580_if_filter_lut[i].freq)
			break;
	}
243 244
	if (i == ARRAY_SIZE(fc2580_if_filter_lut)) {
		ret = -EINVAL;
245
		goto err;
246
	}
247

248 249
	ret = regmap_write(dev->regmap, 0x36, fc2580_if_filter_lut[i].r36_val);
	if (ret)
250 251
		goto err;

252 253 254
	uitmp = (unsigned int) 8058000 - (c->bandwidth_hz * 122 / 100 / 2);
	uitmp = div64_u64((u64) dev->clk * uitmp, 1000000000000ULL);
	ret = regmap_write(dev->regmap, 0x37, uitmp);
255
	if (ret)
256 257
		goto err;

258 259
	ret = regmap_write(dev->regmap, 0x39, fc2580_if_filter_lut[i].r39_val);
	if (ret)
260 261
		goto err;

262 263 264
	timeout = jiffies + msecs_to_jiffies(30);
	for (uitmp = ~0xc0; !time_after(jiffies, timeout) && uitmp != 0xc0;) {
		/* trigger filter */
265
		ret = regmap_write(dev->regmap, 0x2e, 0x09);
266
		if (ret)
267 268
			goto err;

269
		/* locked when [7:6] are set (val: d7 6MHz, d5 7MHz, cd 8MHz) */
270
		ret = regmap_read(dev->regmap, 0x2f, &uitmp);
271
		if (ret)
272
			goto err;
273
		uitmp &= 0xc0;
274

275
		ret = regmap_write(dev->regmap, 0x2e, 0x01);
276
		if (ret)
277 278
			goto err;
	}
279 280
	if (uitmp != 0xc0)
		dev_dbg(&client->dev, "filter did not lock %02x\n", uitmp);
281 282 283

	return 0;
err:
284
	dev_dbg(&client->dev, "failed=%d\n", ret);
285 286 287 288 289
	return ret;
}

static int fc2580_init(struct dvb_frontend *fe)
{
290 291
	struct fc2580_dev *dev = fe->tuner_priv;
	struct i2c_client *client = dev->client;
292 293
	int ret, i;

294
	dev_dbg(&client->dev, "\n");
295 296

	for (i = 0; i < ARRAY_SIZE(fc2580_init_reg_vals); i++) {
297
		ret = regmap_write(dev->regmap, fc2580_init_reg_vals[i].reg,
298
				fc2580_init_reg_vals[i].val);
299
		if (ret)
300 301 302 303 304
			goto err;
	}

	return 0;
err:
305
	dev_dbg(&client->dev, "failed=%d\n", ret);
306 307 308 309 310
	return ret;
}

static int fc2580_sleep(struct dvb_frontend *fe)
{
311 312
	struct fc2580_dev *dev = fe->tuner_priv;
	struct i2c_client *client = dev->client;
313 314
	int ret;

315
	dev_dbg(&client->dev, "\n");
316

317 318
	ret = regmap_write(dev->regmap, 0x02, 0x0a);
	if (ret)
319 320 321 322
		goto err;

	return 0;
err:
323
	dev_dbg(&client->dev, "failed=%d\n", ret);
324 325 326 327 328
	return ret;
}

static int fc2580_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
329 330
	struct fc2580_dev *dev = fe->tuner_priv;
	struct i2c_client *client = dev->client;
331

332
	dev_dbg(&client->dev, "\n");
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352

	*frequency = 0; /* Zero-IF */

	return 0;
}

static const struct dvb_tuner_ops fc2580_tuner_ops = {
	.info = {
		.name           = "FCI FC2580",
		.frequency_min  = 174000000,
		.frequency_max  = 862000000,
	},

	.init = fc2580_init,
	.sleep = fc2580_sleep,
	.set_params = fc2580_set_params,

	.get_if_frequency = fc2580_get_if_frequency,
};

353 354 355
static int fc2580_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
356
	struct fc2580_dev *dev;
357 358 359
	struct fc2580_platform_data *pdata = client->dev.platform_data;
	struct dvb_frontend *fe = pdata->dvb_frontend;
	int ret;
360 361 362 363 364
	unsigned int uitmp;
	static const struct regmap_config regmap_config = {
		.reg_bits = 8,
		.val_bits = 8,
	};
365 366 367 368 369 370 371 372 373 374 375 376

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		ret = -ENOMEM;
		goto err;
	}

	if (pdata->clk)
		dev->clk = pdata->clk;
	else
		dev->clk = 16384000; /* internal clock */
	dev->client = client;
377 378 379 380 381
	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
	if (IS_ERR(dev->regmap)) {
		ret = PTR_ERR(dev->regmap);
		goto err_kfree;
	}
382 383

	/* check if the tuner is there */
384 385
	ret = regmap_read(dev->regmap, 0x01, &uitmp);
	if (ret)
386 387
		goto err_kfree;

388
	dev_dbg(&client->dev, "chip_id=%02x\n", uitmp);
389

390
	switch (uitmp) {
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
	case 0x56:
	case 0x5a:
		break;
	default:
		goto err_kfree;
	}

	fe->tuner_priv = dev;
	memcpy(&fe->ops.tuner_ops, &fc2580_tuner_ops,
			sizeof(struct dvb_tuner_ops));
	i2c_set_clientdata(client, dev);

	dev_info(&client->dev, "FCI FC2580 successfully identified\n");
	return 0;
err_kfree:
	kfree(dev);
err:
	dev_dbg(&client->dev, "failed=%d\n", ret);
	return ret;
}

static int fc2580_remove(struct i2c_client *client)
{
414
	struct fc2580_dev *dev = i2c_get_clientdata(client);
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440

	dev_dbg(&client->dev, "\n");

	kfree(dev);
	return 0;
}

static const struct i2c_device_id fc2580_id_table[] = {
	{"fc2580", 0},
	{}
};
MODULE_DEVICE_TABLE(i2c, fc2580_id_table);

static struct i2c_driver fc2580_driver = {
	.driver = {
		.owner	= THIS_MODULE,
		.name	= "fc2580",
		.suppress_bind_attrs = true,
	},
	.probe		= fc2580_probe,
	.remove		= fc2580_remove,
	.id_table	= fc2580_id_table,
};

module_i2c_driver(fc2580_driver);

441 442 443
MODULE_DESCRIPTION("FCI FC2580 silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");