si2157.c 13.5 KB
Newer Older
1
/*
2
 * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Copyright (C) 2014 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.
 */

17 18
#include "si2157_priv.h"

19 20
static const struct dvb_tuner_ops si2157_ops;

21
/* execute firmware command */
22
static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
23
{
24
	struct si2157_dev *dev = i2c_get_clientdata(client);
25 26 27
	int ret;
	unsigned long timeout;

28
	mutex_lock(&dev->i2c_mutex);
29

30
	if (cmd->wlen) {
31
		/* write cmd and args for firmware */
32
		ret = i2c_master_send(client, cmd->args, cmd->wlen);
33 34
		if (ret < 0) {
			goto err_mutex_unlock;
35
		} else if (ret != cmd->wlen) {
36 37 38 39 40
			ret = -EREMOTEIO;
			goto err_mutex_unlock;
		}
	}

41 42 43 44 45
	if (cmd->rlen) {
		/* wait cmd execution terminate */
		#define TIMEOUT 80
		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
		while (!time_after(jiffies, timeout)) {
46
			ret = i2c_master_recv(client, cmd->args, cmd->rlen);
47 48 49 50 51 52 53 54 55 56
			if (ret < 0) {
				goto err_mutex_unlock;
			} else if (ret != cmd->rlen) {
				ret = -EREMOTEIO;
				goto err_mutex_unlock;
			}

			/* firmware ready? */
			if ((cmd->args[0] >> 7) & 0x01)
				break;
57 58
		}

59
		dev_dbg(&client->dev, "cmd execution took %d ms\n",
60 61
				jiffies_to_msecs(jiffies) -
				(jiffies_to_msecs(timeout) - TIMEOUT));
62

63 64 65 66
		if (!((cmd->args[0] >> 7) & 0x01)) {
			ret = -ETIMEDOUT;
			goto err_mutex_unlock;
		}
67 68
	}

69 70
	mutex_unlock(&dev->i2c_mutex);
	return 0;
71

72
err_mutex_unlock:
73
	mutex_unlock(&dev->i2c_mutex);
74
	dev_dbg(&client->dev, "failed=%d\n", ret);
75 76 77 78 79
	return ret;
}

static int si2157_init(struct dvb_frontend *fe)
{
80 81
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);
82
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
83
	int ret, len, remaining;
84
	struct si2157_cmd cmd;
85
	const struct firmware *fw;
86
	const char *fw_name;
87
	unsigned int uitmp, chip_id;
88

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

91 92 93 94 95 96 97 98 99 100 101 102
	/* Returned IF frequency is garbage when firmware is not running */
	memcpy(cmd.args, "\x15\x00\x06\x07", 4);
	cmd.wlen = 4;
	cmd.rlen = 4;
	ret = si2157_cmd_execute(client, &cmd);
	if (ret)
		goto err;

	uitmp = cmd.args[2] << 0 | cmd.args[3] << 8;
	dev_dbg(&client->dev, "if_frequency kHz=%u\n", uitmp);

	if (uitmp == dev->if_frequency / 1000)
103 104 105
		goto warm;

	/* power up */
106
	if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
107 108
		memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
		cmd.wlen = 9;
109 110 111
	} else if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
		memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10);
		cmd.wlen = 10;
112
	} else {
113 114 115
		memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
		cmd.wlen = 15;
	}
116
	cmd.rlen = 1;
117
	ret = si2157_cmd_execute(client, &cmd);
118 119 120
	if (ret)
		goto err;

121 122 123 124 125 126 127 128 129
	/* Si2141 needs a second command before it answers the revision query */
	if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
		memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7);
		cmd.wlen = 7;
		ret = si2157_cmd_execute(client, &cmd);
		if (ret)
			goto err;
	}

130 131 132 133
	/* query chip revision */
	memcpy(cmd.args, "\x02", 1);
	cmd.wlen = 1;
	cmd.rlen = 13;
134
	ret = si2157_cmd_execute(client, &cmd);
135 136 137
	if (ret)
		goto err;

138 139 140 141
	chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
			cmd.args[4] << 0;

	#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
C
CrazyCat 已提交
142
	#define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
143
	#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
144
	#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
145
	#define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
146
	#define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0)
147 148 149

	switch (chip_id) {
	case SI2158_A20:
C
CrazyCat 已提交
150
	case SI2148_A20:
151
		fw_name = SI2158_A20_FIRMWARE;
152
		break;
153 154 155
	case SI2141_A10:
		fw_name = SI2141_A10_FIRMWARE;
		break;
156
	case SI2157_A30:
157
	case SI2147_A30:
158
	case SI2146_A10:
159
		fw_name = NULL;
160
		break;
161
	default:
162
		dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
O
Olli Salonen 已提交
163
				cmd.args[2], cmd.args[1],
164 165 166 167
				cmd.args[3], cmd.args[4]);
		ret = -EINVAL;
		goto err;
	}
168

169 170 171
	dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
			cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);

172
	if (fw_name == NULL)
173
		goto skip_fw_download;
174

175
	/* request the firmware, this will block and timeout */
176
	ret = request_firmware(&fw, fw_name, &client->dev);
177
	if (ret) {
178
		dev_err(&client->dev, "firmware file '%s' not found\n",
179
				fw_name);
180 181
		goto err;
	}
182

183 184
	/* firmware should be n chunks of 17 bytes */
	if (fw->size % 17 != 0) {
185
		dev_err(&client->dev, "firmware file '%s' is invalid\n",
186
				fw_name);
187
		ret = -EINVAL;
188
		goto err_release_firmware;
189
	}
190

191
	dev_info(&client->dev, "downloading firmware from file '%s'\n",
192
			fw_name);
193

194 195
	for (remaining = fw->size; remaining > 0; remaining -= 17) {
		len = fw->data[fw->size - remaining];
196 197
		if (len > SI2157_ARGLEN) {
			dev_err(&client->dev, "Bad firmware length\n");
198
			ret = -EINVAL;
199 200
			goto err_release_firmware;
		}
201 202 203
		memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
		cmd.wlen = len;
		cmd.rlen = 1;
204
		ret = si2157_cmd_execute(client, &cmd);
205
		if (ret) {
206
			dev_err(&client->dev, "firmware download failed %d\n",
O
Olli Salonen 已提交
207
					ret);
208
			goto err_release_firmware;
209 210 211
		}
	}

212 213 214
	release_firmware(fw);

skip_fw_download:
215 216 217 218
	/* reboot the tuner with new firmware? */
	memcpy(cmd.args, "\x01\x01", 2);
	cmd.wlen = 2;
	cmd.rlen = 1;
219
	ret = si2157_cmd_execute(client, &cmd);
220 221 222
	if (ret)
		goto err;

223 224 225 226 227 228 229 230 231 232
	/* query firmware version */
	memcpy(cmd.args, "\x11", 1);
	cmd.wlen = 1;
	cmd.rlen = 10;
	ret = si2157_cmd_execute(client, &cmd);
	if (ret)
		goto err;

	dev_info(&client->dev, "firmware version: %c.%c.%d\n",
			cmd.args[6], cmd.args[7], cmd.args[8]);
233
warm:
234 235 236 237 238 239
	/* init statistics in order signal app which are supported */
	c->strength.len = 1;
	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	/* start statistics polling */
	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(1000));

240
	dev->active = true;
241
	return 0;
242
err_release_firmware:
243
	release_firmware(fw);
244
err:
245
	dev_dbg(&client->dev, "failed=%d\n", ret);
246
	return ret;
247 248 249 250
}

static int si2157_sleep(struct dvb_frontend *fe)
{
251 252
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);
253 254
	int ret;
	struct si2157_cmd cmd;
255

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

258
	dev->active = false;
259

260 261 262
	/* stop statistics polling */
	cancel_delayed_work_sync(&dev->stat_work);

263 264 265 266
	/* standby */
	memcpy(cmd.args, "\x16\x00", 2);
	cmd.wlen = 2;
	cmd.rlen = 1;
267
	ret = si2157_cmd_execute(client, &cmd);
268 269 270
	if (ret)
		goto err;

271
	return 0;
272
err:
273
	dev_dbg(&client->dev, "failed=%d\n", ret);
274
	return ret;
275 276 277 278
}

static int si2157_set_params(struct dvb_frontend *fe)
{
279 280
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);
281 282 283
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	int ret;
	struct si2157_cmd cmd;
284
	u8 bandwidth, delivery_system;
285
	u32 if_frequency = 5000000;
286

287
	dev_dbg(&client->dev,
O
Olli Salonen 已提交
288
			"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
289
			c->delivery_system, c->frequency, c->bandwidth_hz);
290

291
	if (!dev->active) {
292 293 294 295
		ret = -EAGAIN;
		goto err;
	}

296 297 298 299 300 301 302 303 304 305
	if (c->bandwidth_hz <= 6000000)
		bandwidth = 0x06;
	else if (c->bandwidth_hz <= 7000000)
		bandwidth = 0x07;
	else if (c->bandwidth_hz <= 8000000)
		bandwidth = 0x08;
	else
		bandwidth = 0x0f;

	switch (c->delivery_system) {
306 307
	case SYS_ATSC:
			delivery_system = 0x00;
308
			if_frequency = 3250000;
309
			break;
310 311
	case SYS_DVBC_ANNEX_B:
			delivery_system = 0x10;
312
			if_frequency = 4000000;
313
			break;
314 315 316 317 318 319 320 321 322 323 324 325 326 327
	case SYS_DVBT:
	case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
			delivery_system = 0x20;
			break;
	case SYS_DVBC_ANNEX_A:
			delivery_system = 0x30;
			break;
	default:
			ret = -EINVAL;
			goto err;
	}

	memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6);
	cmd.args[4] = delivery_system | bandwidth;
328
	if (dev->inversion)
329
		cmd.args[5] = 0x01;
330
	cmd.wlen = 6;
331
	cmd.rlen = 4;
332
	ret = si2157_cmd_execute(client, &cmd);
333 334 335
	if (ret)
		goto err;

336
	if (dev->chiptype == SI2157_CHIPTYPE_SI2146)
337 338
		memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6);
	else
339 340
		memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6);
	cmd.args[4] = dev->if_port;
341 342
	cmd.wlen = 6;
	cmd.rlen = 4;
343
	ret = si2157_cmd_execute(client, &cmd);
344 345 346
	if (ret)
		goto err;

347 348 349 350 351 352 353 354 355 356 357 358 359 360
	/* set if frequency if needed */
	if (if_frequency != dev->if_frequency) {
		memcpy(cmd.args, "\x14\x00\x06\x07", 4);
		cmd.args[4] = (if_frequency / 1000) & 0xff;
		cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
		cmd.wlen = 6;
		cmd.rlen = 4;
		ret = si2157_cmd_execute(client, &cmd);
		if (ret)
			goto err;

		dev->if_frequency = if_frequency;
	}

361
	/* set frequency */
362
	memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
363 364 365 366
	cmd.args[4] = (c->frequency >>  0) & 0xff;
	cmd.args[5] = (c->frequency >>  8) & 0xff;
	cmd.args[6] = (c->frequency >> 16) & 0xff;
	cmd.args[7] = (c->frequency >> 24) & 0xff;
367 368
	cmd.wlen = 8;
	cmd.rlen = 1;
369
	ret = si2157_cmd_execute(client, &cmd);
370 371 372 373 374
	if (ret)
		goto err;

	return 0;
err:
375
	dev_dbg(&client->dev, "failed=%d\n", ret);
376 377 378
	return ret;
}

379 380
static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
381 382 383 384
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);

	*frequency = dev->if_frequency;
385 386 387
	return 0;
}

388
static const struct dvb_tuner_ops si2157_ops = {
389
	.info = {
390
		.name           = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
391 392
		.frequency_min  = 42000000,
		.frequency_max  = 870000000,
393 394 395 396 397
	},

	.init = si2157_init,
	.sleep = si2157_sleep,
	.set_params = si2157_set_params,
398
	.get_if_frequency = si2157_get_if_frequency,
399 400
};

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
static void si2157_stat_work(struct work_struct *work)
{
	struct si2157_dev *dev = container_of(work, struct si2157_dev, stat_work.work);
	struct dvb_frontend *fe = dev->fe;
	struct i2c_client *client = fe->tuner_priv;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	struct si2157_cmd cmd;
	int ret;

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

	memcpy(cmd.args, "\x42\x00", 2);
	cmd.wlen = 2;
	cmd.rlen = 12;
	ret = si2157_cmd_execute(client, &cmd);
	if (ret)
		goto err;

	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
	c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000;

	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
	return;
err:
	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	dev_dbg(&client->dev, "failed=%d\n", ret);
}

429
static int si2157_probe(struct i2c_client *client,
430
			const struct i2c_device_id *id)
431 432 433
{
	struct si2157_config *cfg = client->dev.platform_data;
	struct dvb_frontend *fe = cfg->fe;
434
	struct si2157_dev *dev;
435 436 437
	struct si2157_cmd cmd;
	int ret;

438 439
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev) {
440
		ret = -ENOMEM;
O
Olli Salonen 已提交
441
		dev_err(&client->dev, "kzalloc() failed\n");
442 443 444
		goto err;
	}

445
	i2c_set_clientdata(client, dev);
446 447
	dev->fe = cfg->fe;
	dev->inversion = cfg->inversion;
448
	dev->if_port = cfg->if_port;
449
	dev->chiptype = (u8)id->driver_data;
450
	dev->if_frequency = 5000000; /* default value of property 0x0706 */
451
	mutex_init(&dev->i2c_mutex);
452
	INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
453 454

	/* check if the tuner is there */
455 456
	cmd.wlen = 0;
	cmd.rlen = 1;
457
	ret = si2157_cmd_execute(client, &cmd);
458
	if (ret)
459
		goto err_kfree;
460

461
	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
462
	fe->tuner_priv = client;
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
#ifdef CONFIG_MEDIA_CONTROLLER
	if (cfg->mdev) {
		dev->mdev = cfg->mdev;

		dev->ent.name = KBUILD_MODNAME;
		dev->ent.function = MEDIA_ENT_F_TUNER;

		dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
		dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
		dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;

		ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
					     &dev->pad[0]);

		if (ret)
			goto err_kfree;

		ret = media_device_register_entity(cfg->mdev, &dev->ent);
		if (ret) {
			media_entity_cleanup(&dev->ent);
			goto err_kfree;
		}
	}
#endif

489
	dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
490
			dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
491
			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
C
CrazyCat 已提交
492
			"Si2146" : "Si2147/2148/2157/2158");
493

494
	return 0;
495 496 497

err_kfree:
	kfree(dev);
498
err:
O
Olli Salonen 已提交
499
	dev_dbg(&client->dev, "failed=%d\n", ret);
500 501 502 503 504
	return ret;
}

static int si2157_remove(struct i2c_client *client)
{
505 506
	struct si2157_dev *dev = i2c_get_clientdata(client);
	struct dvb_frontend *fe = dev->fe;
507

O
Olli Salonen 已提交
508
	dev_dbg(&client->dev, "\n");
509

510 511 512
	/* stop statistics polling */
	cancel_delayed_work_sync(&dev->stat_work);

513 514 515 516 517
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
	if (dev->mdev)
		media_device_unregister_entity(&dev->ent);
#endif

518 519
	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
	fe->tuner_priv = NULL;
520
	kfree(dev);
521 522 523 524

	return 0;
}

525 526 527
static const struct i2c_device_id si2157_id_table[] = {
	{"si2157", SI2157_CHIPTYPE_SI2157},
	{"si2146", SI2157_CHIPTYPE_SI2146},
528
	{"si2141", SI2157_CHIPTYPE_SI2141},
529 530
	{}
};
531
MODULE_DEVICE_TABLE(i2c, si2157_id_table);
532 533 534

static struct i2c_driver si2157_driver = {
	.driver = {
535 536
		.name	             = "si2157",
		.suppress_bind_attrs = true,
537 538 539
	},
	.probe		= si2157_probe,
	.remove		= si2157_remove,
540
	.id_table	= si2157_id_table,
541 542 543 544
};

module_i2c_driver(si2157_driver);

545
MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
546 547
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
548
MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
549
MODULE_FIRMWARE(SI2141_A10_FIRMWARE);