si2157.c 12.8 KB
Newer Older
1
/*
C
CrazyCat 已提交
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 109 110 111 112
		memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
		cmd.wlen = 9;
	} else {
		memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
		cmd.wlen = 15;
	}
113
	cmd.rlen = 1;
114
	ret = si2157_cmd_execute(client, &cmd);
115 116 117 118 119 120 121
	if (ret)
		goto err;

	/* query chip revision */
	memcpy(cmd.args, "\x02", 1);
	cmd.wlen = 1;
	cmd.rlen = 13;
122
	ret = si2157_cmd_execute(client, &cmd);
123 124 125
	if (ret)
		goto err;

126 127 128 129
	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 已提交
130
	#define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
131
	#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
132
	#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
133
	#define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
134 135 136

	switch (chip_id) {
	case SI2158_A20:
C
CrazyCat 已提交
137
	case SI2148_A20:
138
		fw_name = SI2158_A20_FIRMWARE;
139 140
		break;
	case SI2157_A30:
141
	case SI2147_A30:
142
	case SI2146_A10:
143
		fw_name = NULL;
144
		break;
145
	default:
146
		dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
O
Olli Salonen 已提交
147
				cmd.args[2], cmd.args[1],
148 149 150 151
				cmd.args[3], cmd.args[4]);
		ret = -EINVAL;
		goto err;
	}
152

153 154 155
	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]);

156
	if (fw_name == NULL)
157
		goto skip_fw_download;
158

159
	/* request the firmware, this will block and timeout */
160
	ret = request_firmware(&fw, fw_name, &client->dev);
161
	if (ret) {
162
		dev_err(&client->dev, "firmware file '%s' not found\n",
163
				fw_name);
164 165
		goto err;
	}
166

167 168
	/* firmware should be n chunks of 17 bytes */
	if (fw->size % 17 != 0) {
169
		dev_err(&client->dev, "firmware file '%s' is invalid\n",
170
				fw_name);
171
		ret = -EINVAL;
172
		goto err_release_firmware;
173
	}
174

175
	dev_info(&client->dev, "downloading firmware from file '%s'\n",
176
			fw_name);
177

178 179
	for (remaining = fw->size; remaining > 0; remaining -= 17) {
		len = fw->data[fw->size - remaining];
180 181
		if (len > SI2157_ARGLEN) {
			dev_err(&client->dev, "Bad firmware length\n");
182
			ret = -EINVAL;
183 184
			goto err_release_firmware;
		}
185 186 187
		memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
		cmd.wlen = len;
		cmd.rlen = 1;
188
		ret = si2157_cmd_execute(client, &cmd);
189
		if (ret) {
190
			dev_err(&client->dev, "firmware download failed %d\n",
O
Olli Salonen 已提交
191
					ret);
192
			goto err_release_firmware;
193 194 195
		}
	}

196 197 198
	release_firmware(fw);

skip_fw_download:
199 200 201 202
	/* reboot the tuner with new firmware? */
	memcpy(cmd.args, "\x01\x01", 2);
	cmd.wlen = 2;
	cmd.rlen = 1;
203
	ret = si2157_cmd_execute(client, &cmd);
204 205 206
	if (ret)
		goto err;

207 208 209 210 211 212 213 214 215 216
	/* 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]);
217
warm:
218 219 220 221 222 223
	/* 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));

224
	dev->active = true;
225
	return 0;
226
err_release_firmware:
227
	release_firmware(fw);
228
err:
229
	dev_dbg(&client->dev, "failed=%d\n", ret);
230
	return ret;
231 232 233 234
}

static int si2157_sleep(struct dvb_frontend *fe)
{
235 236
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);
237 238
	int ret;
	struct si2157_cmd cmd;
239

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

242
	dev->active = false;
243

244 245 246
	/* stop statistics polling */
	cancel_delayed_work_sync(&dev->stat_work);

247 248 249 250
	/* standby */
	memcpy(cmd.args, "\x16\x00", 2);
	cmd.wlen = 2;
	cmd.rlen = 1;
251
	ret = si2157_cmd_execute(client, &cmd);
252 253 254
	if (ret)
		goto err;

255
	return 0;
256
err:
257
	dev_dbg(&client->dev, "failed=%d\n", ret);
258
	return ret;
259 260 261 262
}

static int si2157_set_params(struct dvb_frontend *fe)
{
263 264
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);
265 266 267
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	int ret;
	struct si2157_cmd cmd;
268
	u8 bandwidth, delivery_system;
269
	u32 if_frequency = 5000000;
270

271
	dev_dbg(&client->dev,
O
Olli Salonen 已提交
272
			"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
273
			c->delivery_system, c->frequency, c->bandwidth_hz);
274

275
	if (!dev->active) {
276 277 278 279
		ret = -EAGAIN;
		goto err;
	}

280 281 282 283 284 285 286 287 288 289
	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) {
290 291
	case SYS_ATSC:
			delivery_system = 0x00;
292
			if_frequency = 3250000;
293
			break;
294 295
	case SYS_DVBC_ANNEX_B:
			delivery_system = 0x10;
296
			if_frequency = 4000000;
297
			break;
298 299 300 301 302 303 304 305 306 307 308 309 310 311
	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;
312
	if (dev->inversion)
313
		cmd.args[5] = 0x01;
314
	cmd.wlen = 6;
315
	cmd.rlen = 4;
316
	ret = si2157_cmd_execute(client, &cmd);
317 318 319
	if (ret)
		goto err;

320
	if (dev->chiptype == SI2157_CHIPTYPE_SI2146)
321 322
		memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6);
	else
323 324
		memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6);
	cmd.args[4] = dev->if_port;
325 326
	cmd.wlen = 6;
	cmd.rlen = 4;
327
	ret = si2157_cmd_execute(client, &cmd);
328 329 330
	if (ret)
		goto err;

331 332 333 334 335 336 337 338 339 340 341 342 343 344
	/* 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;
	}

345
	/* set frequency */
346
	memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
347 348 349 350
	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;
351 352
	cmd.wlen = 8;
	cmd.rlen = 1;
353
	ret = si2157_cmd_execute(client, &cmd);
354 355 356 357 358
	if (ret)
		goto err;

	return 0;
err:
359
	dev_dbg(&client->dev, "failed=%d\n", ret);
360 361 362
	return ret;
}

363 364
static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
365 366 367 368
	struct i2c_client *client = fe->tuner_priv;
	struct si2157_dev *dev = i2c_get_clientdata(client);

	*frequency = dev->if_frequency;
369 370 371
	return 0;
}

372
static const struct dvb_tuner_ops si2157_ops = {
373
	.info = {
C
CrazyCat 已提交
374
		.name           = "Silicon Labs Si2146/2147/2148/2157/2158",
375 376
		.frequency_min  = 42000000,
		.frequency_max  = 870000000,
377 378 379 380 381
	},

	.init = si2157_init,
	.sleep = si2157_sleep,
	.set_params = si2157_set_params,
382
	.get_if_frequency = si2157_get_if_frequency,
383 384
};

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
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);
}

413
static int si2157_probe(struct i2c_client *client,
414
			const struct i2c_device_id *id)
415 416 417
{
	struct si2157_config *cfg = client->dev.platform_data;
	struct dvb_frontend *fe = cfg->fe;
418
	struct si2157_dev *dev;
419 420 421
	struct si2157_cmd cmd;
	int ret;

422 423
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev) {
424
		ret = -ENOMEM;
O
Olli Salonen 已提交
425
		dev_err(&client->dev, "kzalloc() failed\n");
426 427 428
		goto err;
	}

429
	i2c_set_clientdata(client, dev);
430 431
	dev->fe = cfg->fe;
	dev->inversion = cfg->inversion;
432
	dev->if_port = cfg->if_port;
433
	dev->chiptype = (u8)id->driver_data;
434
	dev->if_frequency = 5000000; /* default value of property 0x0706 */
435
	mutex_init(&dev->i2c_mutex);
436
	INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
437 438

	/* check if the tuner is there */
439 440
	cmd.wlen = 0;
	cmd.rlen = 1;
441
	ret = si2157_cmd_execute(client, &cmd);
442
	if (ret)
443
		goto err_kfree;
444

445
	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
446
	fe->tuner_priv = client;
447

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
#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

473
	dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
474
			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
C
CrazyCat 已提交
475
			"Si2146" : "Si2147/2148/2157/2158");
476

477
	return 0;
478 479 480

err_kfree:
	kfree(dev);
481
err:
O
Olli Salonen 已提交
482
	dev_dbg(&client->dev, "failed=%d\n", ret);
483 484 485 486 487
	return ret;
}

static int si2157_remove(struct i2c_client *client)
{
488 489
	struct si2157_dev *dev = i2c_get_clientdata(client);
	struct dvb_frontend *fe = dev->fe;
490

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

493 494 495
	/* stop statistics polling */
	cancel_delayed_work_sync(&dev->stat_work);

496 497 498 499 500
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
	if (dev->mdev)
		media_device_unregister_entity(&dev->ent);
#endif

501 502
	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
	fe->tuner_priv = NULL;
503
	kfree(dev);
504 505 506 507

	return 0;
}

508 509 510
static const struct i2c_device_id si2157_id_table[] = {
	{"si2157", SI2157_CHIPTYPE_SI2157},
	{"si2146", SI2157_CHIPTYPE_SI2146},
511 512
	{}
};
513
MODULE_DEVICE_TABLE(i2c, si2157_id_table);
514 515 516 517 518 519 520

static struct i2c_driver si2157_driver = {
	.driver = {
		.name	= "si2157",
	},
	.probe		= si2157_probe,
	.remove		= si2157_remove,
521
	.id_table	= si2157_id_table,
522 523 524 525
};

module_i2c_driver(si2157_driver);

C
CrazyCat 已提交
526
MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver");
527 528
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
529
MODULE_FIRMWARE(SI2158_A20_FIRMWARE);