File Index
Files and directories
Sign in
FILE

mxl692.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/dvb-frontends/mxl692.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for the MaxLinear MxL69x family of combo tuners/demods
   4 *
   5 * Copyright (C) 2020 Brad Love <brad@nextdimension.cc>
   6 *
   7 * based on code:
   8 * Copyright (c) 2016 MaxLinear, Inc. All rights reserved
   9 * which was released under GPL V2
  10 */
  11
  12#include <linux/mutex.h>
  13#include <linux/i2c-mux.h>
  14#include <linux/string.h>
  15#include <linux/firmware.h>
  16
  17#include "mxl692.h"
  18#include "mxl692_defs.h"
  19
  20static const struct dvb_frontend_ops mxl692_ops;
  21
  22struct mxl692_dev {
  23	struct dvb_frontend fe;
  24	struct i2c_client *i2c_client;
  25	struct mutex i2c_lock;		/* i2c command mutex */
  26	enum MXL_EAGLE_DEMOD_TYPE_E demod_type;
  27	enum MXL_EAGLE_POWER_MODE_E power_mode;
  28	u32 current_frequency;
  29	int device_type;
  30	int seqnum;
  31	int init_done;
  32};
  33
  34static int mxl692_i2c_write(struct mxl692_dev *dev, u8 *buffer, u16 buf_len)
  35{
  36	int ret = 0;
  37	struct i2c_msg msg = {
  38		.addr = dev->i2c_client->addr,
  39		.flags = 0,
  40		.buf = buffer,
  41		.len = buf_len
  42	};
  43
  44	ret = i2c_transfer(dev->i2c_client->adapter, &msg, 1);
  45	if (ret != 1)
  46		dev_dbg(&dev->i2c_client->dev, "i2c write error!\n");
  47
  48	return ret;
  49}
  50
  51static int mxl692_i2c_read(struct mxl692_dev *dev, u8 *buffer, u16 buf_len)
  52{
  53	int ret = 0;
  54	struct i2c_msg msg = {
  55		.addr = dev->i2c_client->addr,
  56		.flags = I2C_M_RD,
  57		.buf = buffer,
  58		.len = buf_len
  59	};
  60
  61	ret = i2c_transfer(dev->i2c_client->adapter, &msg, 1);
  62	if (ret != 1)
  63		dev_dbg(&dev->i2c_client->dev, "i2c read error!\n");
  64
  65	return ret;
  66}
  67
  68static int convert_endian(u32 size, u8 *d)
  69{
  70	u32 i;
  71
  72	for (i = 0; i < (size & ~3); i += 4) {
  73		d[i + 0] ^= d[i + 3];
  74		d[i + 3] ^= d[i + 0];
  75		d[i + 0] ^= d[i + 3];
  76
  77		d[i + 1] ^= d[i + 2];
  78		d[i + 2] ^= d[i + 1];
  79		d[i + 1] ^= d[i + 2];
  80	}
  81
  82	switch (size & 3) {
  83	case 0:
  84	case 1:
  85		/* do nothing */
  86		break;
  87	case 2:
  88		d[i + 0] ^= d[i + 1];
  89		d[i + 1] ^= d[i + 0];
  90		d[i + 0] ^= d[i + 1];
  91		break;
  92
  93	case 3:
  94		d[i + 0] ^= d[i + 2];
  95		d[i + 2] ^= d[i + 0];
  96		d[i + 0] ^= d[i + 2];
  97		break;
  98	}
  99	return size;
 100}
 101
 102static int convert_endian_n(int n, u32 size, u8 *d)
 103{
 104	int i, count = 0;
 105
 106	for (i = 0; i < n; i += size)
 107		count += convert_endian(size, d + i);
 108	return count;
 109}
 110
 111static void mxl692_tx_swap(enum MXL_EAGLE_OPCODE_E opcode, u8 *buffer)
 112{
 113#ifdef __BIG_ENDIAN
 114	return;
 115#endif
 116	buffer += MXL_EAGLE_HOST_MSG_HEADER_SIZE; /* skip API header */
 117
 118	switch (opcode) {
 119	case MXL_EAGLE_OPCODE_DEVICE_INTR_MASK_SET:
 120	case MXL_EAGLE_OPCODE_TUNER_CHANNEL_TUNE_SET:
 121	case MXL_EAGLE_OPCODE_SMA_TRANSMIT_SET:
 122		buffer += convert_endian(sizeof(u32), buffer);
 123		break;
 124	case MXL_EAGLE_OPCODE_QAM_PARAMS_SET:
 125		buffer += 5;
 126		buffer += convert_endian(2 * sizeof(u32), buffer);
 127		break;
 128	default:
 129		/* no swapping - all get opcodes */
 130		/* ATSC/OOB no swapping */
 131		break;
 132	}
 133}
 134
 135static void mxl692_rx_swap(enum MXL_EAGLE_OPCODE_E opcode, u8 *buffer)
 136{
 137#ifdef __BIG_ENDIAN
 138	return;
 139#endif
 140	buffer += MXL_EAGLE_HOST_MSG_HEADER_SIZE; /* skip API header */
 141
 142	switch (opcode) {
 143	case MXL_EAGLE_OPCODE_TUNER_AGC_STATUS_GET:
 144		buffer++;
 145		buffer += convert_endian(2 * sizeof(u16), buffer);
 146		break;
 147	case MXL_EAGLE_OPCODE_ATSC_STATUS_GET:
 148		buffer += convert_endian_n(2, sizeof(u16), buffer);
 149		buffer += convert_endian(sizeof(u32), buffer);
 150		break;
 151	case MXL_EAGLE_OPCODE_ATSC_ERROR_COUNTERS_GET:
 152		buffer += convert_endian(3 * sizeof(u32), buffer);
 153		break;
 154	case MXL_EAGLE_OPCODE_ATSC_EQUALIZER_FILTER_FFE_TAPS_GET:
 155		buffer += convert_endian_n(24, sizeof(u16), buffer);
 156		break;
 157	case MXL_EAGLE_OPCODE_QAM_STATUS_GET:
 158		buffer += 8;
 159		buffer += convert_endian_n(2, sizeof(u16), buffer);
 160		buffer += convert_endian(sizeof(u32), buffer);
 161		break;
 162	case MXL_EAGLE_OPCODE_QAM_ERROR_COUNTERS_GET:
 163		buffer += convert_endian(7 * sizeof(u32), buffer);
 164		break;
 165	case MXL_EAGLE_OPCODE_QAM_CONSTELLATION_VALUE_GET:
 166	case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_DFE_START_GET:
 167	case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_DFE_MIDDLE_GET:
 168	case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_DFE_END_GET:
 169	case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_SPUR_START_GET:
 170		buffer += convert_endian_n(24, sizeof(u16), buffer);
 171		break;
 172	case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_SPUR_END_GET:
 173		buffer += convert_endian_n(8, sizeof(u16), buffer);
 174		break;
 175	case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_FFE_GET:
 176		buffer += convert_endian_n(17, sizeof(u16), buffer);
 177		break;
 178	case MXL_EAGLE_OPCODE_OOB_ERROR_COUNTERS_GET:
 179		buffer += convert_endian(3 * sizeof(u32), buffer);
 180		break;
 181	case MXL_EAGLE_OPCODE_OOB_STATUS_GET:
 182		buffer += convert_endian_n(2, sizeof(u16), buffer);
 183		buffer += convert_endian(sizeof(u32), buffer);
 184		break;
 185	case MXL_EAGLE_OPCODE_SMA_RECEIVE_GET:
 186		buffer += convert_endian(sizeof(u32), buffer);
 187		break;
 188	default:
 189		/* no swapping - all set opcodes */
 190		break;
 191	}
 192}
 193
 194static u32 mxl692_checksum(u8 *buffer, u32 size)
 195{
 196	u32 ix, div_size;
 197	u32 cur_cksum = 0;
 198	__be32 *buf;
 199
 200	div_size = DIV_ROUND_UP(size, 4);
 201
 202	buf = (__be32 *)buffer;
 203	for (ix = 0; ix < div_size; ix++)
 204		cur_cksum += be32_to_cpu(buf[ix]);
 205
 206	cur_cksum ^= 0xDEADBEEF;
 207
 208	return cur_cksum;
 209}
 210
 211static int mxl692_validate_fw_header(struct mxl692_dev *dev,
 212				     const u8 *buffer, u32 buf_len)
 213{
 214	int status = 0;
 215	u32 ix, temp;
 216	__be32 *local_buf = NULL;
 217	u8 temp_cksum = 0;
 218	static const u8 fw_hdr[] = {
 219		0x4D, 0x31, 0x10, 0x02, 0x40, 0x00, 0x00, 0x80
 220	};
 221
 222	if (memcmp(buffer, fw_hdr, 8) != 0) {
 223		status = -EINVAL;
 224		goto err_finish;
 225	}
 226
 227	local_buf = (__be32 *)(buffer + 8);
 228	temp = be32_to_cpu(*local_buf);
 229
 230	if ((buf_len - 16) != temp >> 8) {
 231		status = -EINVAL;
 232		goto err_finish;
 233	}
 234
 235	for (ix = 16; ix < buf_len; ix++)
 236		temp_cksum += buffer[ix];
 237
 238	if (temp_cksum != buffer[11])
 239		status = -EINVAL;
 240
 241err_finish:
 242	if (status)
 243		dev_dbg(&dev->i2c_client->dev, "failed\n");
 244	return status;
 245}
 246
 247static int mxl692_write_fw_block(struct mxl692_dev *dev, const u8 *buffer,
 248				 u32 buf_len, u32 *index)
 249{
 250	int status = 0;
 251	u32 ix = 0, total_len = 0, addr = 0, chunk_len = 0, prevchunk_len = 0;
 252	u8 local_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {}, *plocal_buf = NULL;
 253	int payload_max = MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_MHEADER_SIZE;
 254
 255	ix = *index;
 256
 257	if (buffer[ix] == 0x53) {
 258		total_len = buffer[ix + 1] << 16 | buffer[ix + 2] << 8 | buffer[ix + 3];
 259		total_len = (total_len + 3) & ~3;
 260		addr      = buffer[ix + 4] << 24 | buffer[ix + 5] << 16 |
 261			    buffer[ix + 6] << 8 | buffer[ix + 7];
 262		ix       += MXL_EAGLE_FW_SEGMENT_HEADER_SIZE;
 263
 264		while ((total_len > 0) && (status == 0)) {
 265			plocal_buf = local_buf;
 266			chunk_len  = (total_len < payload_max) ? total_len : payload_max;
 267
 268			*plocal_buf++ = 0xFC;
 269			*plocal_buf++ = chunk_len + sizeof(u32);
 270
 271			*(u32 *)plocal_buf = addr + prevchunk_len;
 272#ifdef __BIG_ENDIAN
 273			convert_endian(sizeof(u32), plocal_buf);
 274#endif
 275			plocal_buf += sizeof(u32);
 276
 277			memcpy(plocal_buf, &buffer[ix], chunk_len);
 278			convert_endian(chunk_len, plocal_buf);
 279			if (mxl692_i2c_write(dev, local_buf,
 280					     (chunk_len + MXL_EAGLE_I2C_MHEADER_SIZE)) < 0) {
 281				status = -EREMOTEIO;
 282				break;
 283			}
 284
 285			prevchunk_len += chunk_len;
 286			total_len -= chunk_len;
 287			ix += chunk_len;
 288		}
 289		*index = ix;
 290	} else {
 291		status = -EINVAL;
 292	}
 293
 294	if (status)
 295		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 296
 297	return status;
 298}
 299
 300static int mxl692_memwrite(struct mxl692_dev *dev, u32 addr,
 301			   u8 *buffer, u32 size)
 302{
 303	int status = 0, total_len = 0;
 304	u8 local_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {}, *plocal_buf = NULL;
 305
 306	total_len = size;
 307	total_len = (total_len + 3) & ~3;  /* 4 byte alignment */
 308
 309	if (total_len > (MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_MHEADER_SIZE))
 310		dev_dbg(&dev->i2c_client->dev, "hrmph?\n");
 311
 312	plocal_buf = local_buf;
 313
 314	*plocal_buf++ = 0xFC;
 315	*plocal_buf++ = total_len + sizeof(u32);
 316
 317	*(u32 *)plocal_buf = addr;
 318	plocal_buf += sizeof(u32);
 319
 320	memcpy(plocal_buf, buffer, total_len);
 321#ifdef __BIG_ENDIAN
 322	convert_endian(sizeof(u32) + total_len, local_buf + 2);
 323#endif
 324	if (mxl692_i2c_write(dev, local_buf,
 325			     (total_len + MXL_EAGLE_I2C_MHEADER_SIZE)) < 0) {
 326		status = -EREMOTEIO;
 327		goto err_finish;
 328	}
 329
 330	return status;
 331err_finish:
 332	dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 333	return status;
 334}
 335
 336static int mxl692_memread(struct mxl692_dev *dev, u32 addr,
 337			  u8 *buffer, u32 size)
 338{
 339	int status = 0;
 340	u8 local_buf[MXL_EAGLE_I2C_MHEADER_SIZE] = {}, *plocal_buf = NULL;
 341
 342	plocal_buf = local_buf;
 343
 344	*plocal_buf++ = 0xFB;
 345	*plocal_buf++ = sizeof(u32);
 346	*(u32 *)plocal_buf = addr;
 347#ifdef __BIG_ENDIAN
 348	convert_endian(sizeof(u32), plocal_buf);
 349#endif
 350	mutex_lock(&dev->i2c_lock);
 351
 352	if (mxl692_i2c_write(dev, local_buf, MXL_EAGLE_I2C_MHEADER_SIZE) > 0) {
 353		size = (size + 3) & ~3;  /* 4 byte alignment */
 354		status = mxl692_i2c_read(dev, buffer, (u16)size) < 0 ? -EREMOTEIO : 0;
 355#ifdef __BIG_ENDIAN
 356		if (status == 0)
 357			convert_endian(size, buffer);
 358#endif
 359	} else {
 360		status = -EREMOTEIO;
 361	}
 362
 363	mutex_unlock(&dev->i2c_lock);
 364
 365	if (status)
 366		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 367
 368	return status;
 369}
 370
 371static const char *mxl692_opcode_string(u8 opcode)
 372{
 373	if (opcode <= MXL_EAGLE_OPCODE_INTERNAL)
 374		return MXL_EAGLE_OPCODE_STRING[opcode];
 375
 376	return "invalid opcode";
 377}
 378
 379static int mxl692_opwrite(struct mxl692_dev *dev, u8 *buffer,
 380			  u32 size)
 381{
 382	int status = 0, total_len = 0;
 383	u8 local_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {}, *plocal_buf = NULL;
 384	struct MXL_EAGLE_HOST_MSG_HEADER_T *tx_hdr = (struct MXL_EAGLE_HOST_MSG_HEADER_T *)buffer;
 385
 386	total_len = size;
 387	total_len = (total_len + 3) & ~3;  /* 4 byte alignment */
 388
 389	if (total_len > (MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_PHEADER_SIZE))
 390		dev_dbg(&dev->i2c_client->dev, "hrmph?\n");
 391
 392	plocal_buf = local_buf;
 393
 394	*plocal_buf++ = 0xFE;
 395	*plocal_buf++ = (u8)total_len;
 396
 397	memcpy(plocal_buf, buffer, total_len);
 398	convert_endian(total_len, plocal_buf);
 399
 400	if (mxl692_i2c_write(dev, local_buf,
 401			     (total_len + MXL_EAGLE_I2C_PHEADER_SIZE)) < 0) {
 402		status = -EREMOTEIO;
 403		goto err_finish;
 404	}
 405err_finish:
 406	if (status)
 407		dev_dbg(&dev->i2c_client->dev, "opcode %s  err %d\n",
 408			mxl692_opcode_string(tx_hdr->opcode), status);
 409	return status;
 410}
 411
 412static int mxl692_opread(struct mxl692_dev *dev, u8 *buffer,
 413			 u32 size)
 414{
 415	int status = 0;
 416	u32 ix = 0;
 417	u8 local_buf[MXL_EAGLE_I2C_PHEADER_SIZE] = {};
 418
 419	local_buf[0] = 0xFD;
 420	local_buf[1] = 0;
 421
 422	if (mxl692_i2c_write(dev, local_buf, MXL_EAGLE_I2C_PHEADER_SIZE) > 0) {
 423		size = (size + 3) & ~3;  /* 4 byte alignment */
 424
 425		/* Read in 4 byte chunks */
 426		for (ix = 0; ix < size; ix += 4) {
 427			if (mxl692_i2c_read(dev, buffer + ix, 4) < 0) {
 428				dev_dbg(&dev->i2c_client->dev, "ix=%d   size=%d\n", ix, size);
 429				status = -EREMOTEIO;
 430				goto err_finish;
 431			}
 432		}
 433		convert_endian(size, buffer);
 434	} else {
 435		status = -EREMOTEIO;
 436	}
 437err_finish:
 438	if (status)
 439		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 440	return status;
 441}
 442
 443static int mxl692_i2c_writeread(struct mxl692_dev *dev,
 444				u8 opcode,
 445				u8 *tx_payload,
 446				u8 tx_payload_size,
 447				u8 *rx_payload,
 448				u8 rx_payload_expected)
 449{
 450	int status = 0, timeout = 40;
 451	u8 tx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
 452	u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
 453	u32 resp_checksum = 0, resp_checksum_tmp = 0;
 454	struct MXL_EAGLE_HOST_MSG_HEADER_T *tx_header;
 455	struct MXL_EAGLE_HOST_MSG_HEADER_T *rx_header;
 456
 457	mutex_lock(&dev->i2c_lock);
 458
 459	if ((tx_payload_size + MXL_EAGLE_HOST_MSG_HEADER_SIZE) >
 460	    (MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_PHEADER_SIZE)) {
 461		status = -EINVAL;
 462		goto err_finish;
 463	}
 464
 465	tx_header = (struct MXL_EAGLE_HOST_MSG_HEADER_T *)tx_buf;
 466	tx_header->opcode = opcode;
 467	tx_header->seqnum = dev->seqnum++;
 468	tx_header->payload_size = tx_payload_size;
 469	tx_header->checksum = 0;
 470
 471	if (dev->seqnum == 0)
 472		dev->seqnum = 1;
 473
 474	if (tx_payload && tx_payload_size > 0)
 475		memcpy(&tx_buf[MXL_EAGLE_HOST_MSG_HEADER_SIZE], tx_payload, tx_payload_size);
 476
 477	mxl692_tx_swap(opcode, tx_buf);
 478
 479	tx_header->checksum = 0;
 480	tx_header->checksum = mxl692_checksum(tx_buf,
 481					      MXL_EAGLE_HOST_MSG_HEADER_SIZE + tx_payload_size);
 482#ifdef __LITTLE_ENDIAN
 483	convert_endian(4, (u8 *)&tx_header->checksum); /* cksum is big endian */
 484#endif
 485	/* send Tx message */
 486	status = mxl692_opwrite(dev, tx_buf,
 487				tx_payload_size + MXL_EAGLE_HOST_MSG_HEADER_SIZE);
 488	if (status) {
 489		status = -EREMOTEIO;
 490		goto err_finish;
 491	}
 492
 493	/* receive Rx message (polling) */
 494	rx_header = (struct MXL_EAGLE_HOST_MSG_HEADER_T *)rx_buf;
 495
 496	do {
 497		status = mxl692_opread(dev, rx_buf,
 498				       rx_payload_expected + MXL_EAGLE_HOST_MSG_HEADER_SIZE);
 499		usleep_range(1000, 2000);
 500		timeout--;
 501	} while ((timeout > 0) && (status == 0) &&
 502		 (rx_header->seqnum == 0) &&
 503		 (rx_header->checksum == 0));
 504
 505	if (timeout == 0 || status) {
 506		dev_dbg(&dev->i2c_client->dev, "timeout=%d   status=%d\n",
 507			timeout, status);
 508		status = -ETIMEDOUT;
 509		goto err_finish;
 510	}
 511
 512	if (rx_header->status) {
 513		dev_dbg(&dev->i2c_client->dev, "rx header status code: %d\n", rx_header->status);
 514		status = -EREMOTEIO;
 515		goto err_finish;
 516	}
 517
 518	if (rx_header->seqnum != tx_header->seqnum ||
 519	    rx_header->opcode != tx_header->opcode ||
 520	    rx_header->payload_size != rx_payload_expected) {
 521		dev_dbg(&dev->i2c_client->dev, "Something failed seq=%s  opcode=%s  pSize=%s\n",
 522			rx_header->seqnum != tx_header->seqnum ? "X" : "0",
 523			rx_header->opcode != tx_header->opcode ? "X" : "0",
 524			rx_header->payload_size != rx_payload_expected ? "X" : "0");
 525		if (rx_header->payload_size != rx_payload_expected)
 526			dev_dbg(&dev->i2c_client->dev,
 527				"rx_header->payloadSize=%d   rx_payload_expected=%d\n",
 528				rx_header->payload_size, rx_payload_expected);
 529		status = -EREMOTEIO;
 530		goto err_finish;
 531	}
 532
 533	resp_checksum = rx_header->checksum;
 534	rx_header->checksum = 0;
 535
 536	resp_checksum_tmp = mxl692_checksum(rx_buf,
 537					    MXL_EAGLE_HOST_MSG_HEADER_SIZE + rx_header->payload_size);
 538#ifdef __LITTLE_ENDIAN
 539	convert_endian(4, (u8 *)&resp_checksum_tmp); /* cksum is big endian */
 540#endif
 541	if (resp_checksum != resp_checksum_tmp) {
 542		dev_dbg(&dev->i2c_client->dev, "rx checksum failure\n");
 543		status = -EREMOTEIO;
 544		goto err_finish;
 545	}
 546
 547	mxl692_rx_swap(rx_header->opcode, rx_buf);
 548
 549	if (rx_header->payload_size > 0) {
 550		if (!rx_payload) {
 551			dev_dbg(&dev->i2c_client->dev, "no rx payload?!?\n");
 552			status = -EREMOTEIO;
 553			goto err_finish;
 554		}
 555		memcpy(rx_payload, rx_buf + MXL_EAGLE_HOST_MSG_HEADER_SIZE,
 556		       rx_header->payload_size);
 557	}
 558err_finish:
 559	if (status)
 560		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 561
 562	mutex_unlock(&dev->i2c_lock);
 563	return status;
 564}
 565
 566static int mxl692_fwdownload(struct mxl692_dev *dev,
 567			     const u8 *firmware_buf, u32 buf_len)
 568{
 569	int status = 0;
 570	u32 ix, reg_val = 0x1;
 571	u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
 572	struct MXL_EAGLE_DEV_STATUS_T *dev_status;
 573
 574	if (buf_len < MXL_EAGLE_FW_HEADER_SIZE ||
 575	    buf_len > MXL_EAGLE_FW_MAX_SIZE_IN_KB * 1000)
 576		return -EINVAL;
 577
 578	mutex_lock(&dev->i2c_lock);
 579
 580	dev_dbg(&dev->i2c_client->dev, "\n");
 581
 582	status = mxl692_validate_fw_header(dev, firmware_buf, buf_len);
 583	if (status)
 584		goto err_finish;
 585
 586	ix = 16;
 587	status = mxl692_write_fw_block(dev, firmware_buf, buf_len, &ix); /* DRAM */
 588	if (status)
 589		goto err_finish;
 590
 591	status = mxl692_write_fw_block(dev, firmware_buf, buf_len, &ix); /* IRAM */
 592	if (status)
 593		goto err_finish;
 594
 595	/* release CPU from reset */
 596	status = mxl692_memwrite(dev, 0x70000018, (u8 *)&reg_val, sizeof(u32));
 597	if (status)
 598		goto err_finish;
 599
 600	mutex_unlock(&dev->i2c_lock);
 601
 602	if (status == 0) {
 603		/* verify FW is alive */
 604		usleep_range(MXL_EAGLE_FW_LOAD_TIME * 1000, (MXL_EAGLE_FW_LOAD_TIME + 5) * 1000);
 605		dev_status = (struct MXL_EAGLE_DEV_STATUS_T *)&rx_buf;
 606		status = mxl692_i2c_writeread(dev,
 607					      MXL_EAGLE_OPCODE_DEVICE_STATUS_GET,
 608					      NULL,
 609					      0,
 610					      (u8 *)dev_status,
 611					      sizeof(struct MXL_EAGLE_DEV_STATUS_T));
 612	}
 613
 614	return status;
 615err_finish:
 616	mutex_unlock(&dev->i2c_lock);
 617	if (status)
 618		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 619	return status;
 620}
 621
 622static int mxl692_get_versions(struct mxl692_dev *dev)
 623{
 624	int status = 0;
 625	struct MXL_EAGLE_DEV_VER_T dev_ver = {};
 626	static const char * const chip_id[] = {"N/A", "691", "248", "692"};
 627
 628	status = mxl692_i2c_writeread(dev, MXL_EAGLE_OPCODE_DEVICE_VERSION_GET,
 629				      NULL,
 630				      0,
 631				      (u8 *)&dev_ver,
 632				      sizeof(struct MXL_EAGLE_DEV_VER_T));
 633	if (status)
 634		return status;
 635
 636	dev_info(&dev->i2c_client->dev, "MxL692_DEMOD Chip ID: %s\n",
 637		 chip_id[dev_ver.chip_id]);
 638
 639	dev_info(&dev->i2c_client->dev,
 640		 "MxL692_DEMOD FW Version: %d.%d.%d.%d_RC%d\n",
 641		 dev_ver.firmware_ver[0],
 642		 dev_ver.firmware_ver[1],
 643		 dev_ver.firmware_ver[2],
 644		 dev_ver.firmware_ver[3],
 645		 dev_ver.firmware_ver[4]);
 646
 647	return status;
 648}
 649
 650static int mxl692_reset(struct mxl692_dev *dev)
 651{
 652	int status = 0;
 653	u32 dev_type = MXL_EAGLE_DEVICE_MAX, reg_val = 0x2;
 654
 655	dev_dbg(&dev->i2c_client->dev, "\n");
 656
 657	/* legacy i2c override */
 658	status = mxl692_memwrite(dev, 0x80000100, (u8 *)&reg_val, sizeof(u32));
 659	if (status)
 660		goto err_finish;
 661
 662	/* verify sku */
 663	status = mxl692_memread(dev, 0x70000188, (u8 *)&dev_type, sizeof(u32));
 664	if (status)
 665		goto err_finish;
 666
 667	if (dev_type != dev->device_type)
 668		goto err_finish;
 669
 670err_finish:
 671	if (status)
 672		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 673	return status;
 674}
 675
 676static int mxl692_config_regulators(struct mxl692_dev *dev,
 677				    enum MXL_EAGLE_POWER_SUPPLY_SOURCE_E power_supply)
 678{
 679	int status = 0;
 680	u32 reg_val;
 681
 682	dev_dbg(&dev->i2c_client->dev, "\n");
 683
 684	/* configure main regulator according to the power supply source */
 685	status = mxl692_memread(dev, 0x90000000, (u8 *)&reg_val, sizeof(u32));
 686	if (status)
 687		goto err_finish;
 688
 689	reg_val &= 0x00FFFFFF;
 690	reg_val |= (power_supply == MXL_EAGLE_POWER_SUPPLY_SOURCE_SINGLE) ?
 691					0x14000000 : 0x10000000;
 692
 693	status = mxl692_memwrite(dev, 0x90000000, (u8 *)&reg_val, sizeof(u32));
 694	if (status)
 695		goto err_finish;
 696
 697	/* configure digital regulator to high current mode */
 698	status = mxl692_memread(dev, 0x90000018, (u8 *)&reg_val, sizeof(u32));
 699	if (status)
 700		goto err_finish;
 701
 702	reg_val |= 0x800;
 703
 704	status = mxl692_memwrite(dev, 0x90000018, (u8 *)&reg_val, sizeof(u32));
 705
 706err_finish:
 707	if (status)
 708		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 709	return status;
 710}
 711
 712static int mxl692_config_xtal(struct mxl692_dev *dev,
 713			      struct MXL_EAGLE_DEV_XTAL_T *dev_xtal)
 714{
 715	int status = 0;
 716	u32 reg_val, reg_val1;
 717
 718	dev_dbg(&dev->i2c_client->dev, "\n");
 719
 720	status = mxl692_memread(dev, 0x90000000, (u8 *)&reg_val, sizeof(u32));
 721	if (status)
 722		goto err_finish;
 723
 724	/* set XTAL capacitance */
 725	reg_val &= 0xFFFFFFE0;
 726	reg_val |= dev_xtal->xtal_cap;
 727
 728	/* set CLK OUT */
 729	reg_val = dev_xtal->clk_out_enable ? (reg_val | 0x0100) : (reg_val & 0xFFFFFEFF);
 730
 731	status = mxl692_memwrite(dev, 0x90000000, (u8 *)&reg_val, sizeof(u32));
 732	if (status)
 733		goto err_finish;
 734
 735	/* set CLK OUT divider */
 736	reg_val = dev_xtal->clk_out_div_enable ? (reg_val | 0x0200) : (reg_val & 0xFFFFFDFF);
 737
 738	status = mxl692_memwrite(dev, 0x90000000, (u8 *)&reg_val, sizeof(u32));
 739	if (status)
 740		goto err_finish;
 741
 742	/* set XTAL sharing */
 743	reg_val = dev_xtal->xtal_sharing_enable ? (reg_val | 0x010400) : (reg_val & 0xFFFEFBFF);
 744
 745	status = mxl692_memwrite(dev, 0x90000000, (u8 *)&reg_val, sizeof(u32));
 746	if (status)
 747		goto err_finish;
 748
 749	/* enable/disable XTAL calibration, based on master/slave device */
 750	status = mxl692_memread(dev, 0x90000030, (u8 *)&reg_val1, sizeof(u32));
 751	if (status)
 752		goto err_finish;
 753
 754	if (dev_xtal->xtal_calibration_enable) {
 755		/* enable XTAL calibration and set XTAL amplitude to a higher value */
 756		reg_val1 &= 0xFFFFFFFD;
 757		reg_val1 |= 0x30;
 758
 759		status = mxl692_memwrite(dev, 0x90000030, (u8 *)&reg_val1, sizeof(u32));
 760		if (status)
 761			goto err_finish;
 762	} else {
 763		/* disable XTAL calibration */
 764		reg_val1 |= 0x2;
 765
 766		status = mxl692_memwrite(dev, 0x90000030, (u8 *)&reg_val1, sizeof(u32));
 767		if (status)
 768			goto err_finish;
 769
 770		/* set XTAL bias value */
 771		status = mxl692_memread(dev, 0x9000002c, (u8 *)&reg_val, sizeof(u32));
 772		if (status)
 773			goto err_finish;
 774
 775		reg_val &= 0xC0FFFFFF;
 776		reg_val |= 0xA000000;
 777
 778		status = mxl692_memwrite(dev, 0x9000002c, (u8 *)&reg_val, sizeof(u32));
 779		if (status)
 780			goto err_finish;
 781	}
 782
 783	/* start XTAL calibration */
 784	status = mxl692_memread(dev, 0x70000010, (u8 *)&reg_val, sizeof(u32));
 785	if (status)
 786		goto err_finish;
 787
 788	reg_val |= 0x8;
 789
 790	status = mxl692_memwrite(dev, 0x70000010, (u8 *)&reg_val, sizeof(u32));
 791	if (status)
 792		goto err_finish;
 793
 794	status = mxl692_memread(dev, 0x70000018, (u8 *)&reg_val, sizeof(u32));
 795	if (status)
 796		goto err_finish;
 797
 798	reg_val |= 0x10;
 799
 800	status = mxl692_memwrite(dev, 0x70000018, (u8 *)&reg_val, sizeof(u32));
 801	if (status)
 802		goto err_finish;
 803
 804	status = mxl692_memread(dev, 0x9001014c, (u8 *)&reg_val, sizeof(u32));
 805	if (status)
 806		goto err_finish;
 807
 808	reg_val &= 0xFFFFEFFF;
 809
 810	status = mxl692_memwrite(dev, 0x9001014c, (u8 *)&reg_val, sizeof(u32));
 811	if (status)
 812		goto err_finish;
 813
 814	reg_val |= 0x1000;
 815
 816	status = mxl692_memwrite(dev, 0x9001014c, (u8 *)&reg_val, sizeof(u32));
 817	if (status)
 818		goto err_finish;
 819
 820	usleep_range(45000, 55000);
 821
 822err_finish:
 823	if (status)
 824		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 825	return status;
 826}
 827
 828static int mxl692_powermode(struct mxl692_dev *dev,
 829			    enum MXL_EAGLE_POWER_MODE_E power_mode)
 830{
 831	int status = 0;
 832	u8 mode = power_mode;
 833
 834	dev_dbg(&dev->i2c_client->dev, "%s\n",
 835		power_mode == MXL_EAGLE_POWER_MODE_SLEEP ? "sleep" : "active");
 836
 837	status = mxl692_i2c_writeread(dev,
 838				      MXL_EAGLE_OPCODE_DEVICE_POWERMODE_SET,
 839				      &mode,
 840				      sizeof(u8),
 841				      NULL,
 842				      0);
 843	if (status) {
 844		dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 845		return status;
 846	}
 847
 848	dev->power_mode = power_mode;
 849
 850	return status;
 851}
 852
 853static int mxl692_init(struct dvb_frontend *fe)
 854{
 855	struct mxl692_dev *dev = fe->demodulator_priv;
 856	struct i2c_client *client = dev->i2c_client;
 857	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 858	int status = 0;
 859	const struct firmware *firmware;
 860	struct MXL_EAGLE_DEV_XTAL_T xtal_config = {};
 861
 862	dev_dbg(&dev->i2c_client->dev, "\n");
 863
 864	if (dev->init_done)
 865		goto warm;
 866
 867	dev->seqnum = 1;
 868
 869	status = mxl692_reset(dev);
 870	if (status)
 871		goto err;
 872
 873	usleep_range(50 * 1000, 60 * 1000); /* was 1000! */
 874
 875	status = mxl692_config_regulators(dev, MXL_EAGLE_POWER_SUPPLY_SOURCE_DUAL);
 876	if (status)
 877		goto err;
 878
 879	xtal_config.xtal_cap = 26;
 880	xtal_config.clk_out_div_enable = 0;
 881	xtal_config.clk_out_enable = 0;
 882	xtal_config.xtal_calibration_enable = 0;
 883	xtal_config.xtal_sharing_enable = 1;
 884	status = mxl692_config_xtal(dev, &xtal_config);
 885	if (status)
 886		goto err;
 887
 888	status = request_firmware(&firmware, MXL692_FIRMWARE, &client->dev);
 889	if (status) {
 890		dev_dbg(&dev->i2c_client->dev, "firmware missing? %s\n",
 891			MXL692_FIRMWARE);
 892		goto err;
 893	}
 894
 895	status = mxl692_fwdownload(dev, firmware->data, firmware->size);
 896	if (status)
 897		goto err_release_firmware;
 898
 899	release_firmware(firmware);
 900
 901	status = mxl692_get_versions(dev);
 902	if (status)
 903		goto err;
 904
 905	dev->power_mode = MXL_EAGLE_POWER_MODE_SLEEP;
 906warm:
 907	/* Config Device Power Mode */
 908	if (dev->power_mode != MXL_EAGLE_POWER_MODE_ACTIVE) {
 909		status = mxl692_powermode(dev, MXL_EAGLE_POWER_MODE_ACTIVE);
 910		if (status)
 911			goto err;
 912
 913		usleep_range(50 * 1000, 60 * 1000); /* was 500! */
 914	}
 915
 916	/* Init stats here to indicate which stats are supported */
 917	c->cnr.len = 1;
 918	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 919	c->post_bit_error.len = 1;
 920	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 921	c->post_bit_count.len = 1;
 922	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 923	c->block_error.len = 1;
 924	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 925
 926	dev->init_done = 1;
 927	return 0;
 928err_release_firmware:
 929	release_firmware(firmware);
 930err:
 931	dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
 932	return status;
 933}
 934
 935static int mxl692_sleep(struct dvb_frontend *fe)
 936{
 937	struct mxl692_dev *dev = fe->demodulator_priv;
 938
 939	if (dev->power_mode != MXL_EAGLE_POWER_MODE_SLEEP)
 940		mxl692_powermode(dev, MXL_EAGLE_POWER_MODE_SLEEP);
 941
 942	return 0;
 943}
 944
 945static int mxl692_set_frontend(struct dvb_frontend *fe)
 946{
 947	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 948	struct mxl692_dev *dev = fe->demodulator_priv;
 949
 950	int status = 0;
 951	enum MXL_EAGLE_DEMOD_TYPE_E demod_type;
 952	struct MXL_EAGLE_MPEGOUT_PARAMS_T mpeg_params = {};
 953	enum MXL_EAGLE_QAM_DEMOD_ANNEX_TYPE_E qam_annex = MXL_EAGLE_QAM_DEMOD_ANNEX_B;
 954	struct MXL_EAGLE_QAM_DEMOD_PARAMS_T qam_params = {};
 955	struct MXL_EAGLE_TUNER_CHANNEL_PARAMS_T tuner_params = {};
 956	u8 op_param = 0;
 957
 958	dev_dbg(&dev->i2c_client->dev, "\n");
 959
 960	switch (p->modulation) {
 961	case VSB_8:
 962		demod_type = MXL_EAGLE_DEMOD_TYPE_ATSC;
 963		break;
 964	case QAM_AUTO:
 965	case QAM_64:
 966	case QAM_128:
 967	case QAM_256:
 968		demod_type = MXL_EAGLE_DEMOD_TYPE_QAM;
 969		break;
 970	default:
 971		return -EINVAL;
 972	}
 973
 974	if (dev->current_frequency == p->frequency && dev->demod_type == demod_type) {
 975		dev_dbg(&dev->i2c_client->dev, "already set up\n");
 976		return 0;
 977	}
 978
 979	dev->current_frequency = -1;
 980	dev->demod_type = -1;
 981
 982	op_param = demod_type;
 983	status = mxl692_i2c_writeread(dev,
 984				      MXL_EAGLE_OPCODE_DEVICE_DEMODULATOR_TYPE_SET,
 985				      &op_param,
 986				      sizeof(u8),
 987				      NULL,
 988				      0);
 989	if (status) {
 990		dev_dbg(&dev->i2c_client->dev,
 991			"DEVICE_DEMODULATOR_TYPE_SET...FAIL  err 0x%x\n", status);
 992		goto err;
 993	}
 994
 995	usleep_range(20 * 1000, 30 * 1000); /* was 500! */
 996
 997	mpeg_params.mpeg_parallel = 0;
 998	mpeg_params.msb_first = MXL_EAGLE_DATA_SERIAL_MSB_1ST;
 999	mpeg_params.mpeg_sync_pulse_width = MXL_EAGLE_DATA_SYNC_WIDTH_BIT;
1000	mpeg_params.mpeg_valid_pol = MXL_EAGLE_CLOCK_POSITIVE;
1001	mpeg_params.mpeg_sync_pol = MXL_EAGLE_CLOCK_POSITIVE;
1002	mpeg_params.mpeg_clk_pol = MXL_EAGLE_CLOCK_NEGATIVE;
1003	mpeg_params.mpeg3wire_mode_enable = 0;
1004	mpeg_params.mpeg_clk_freq = MXL_EAGLE_MPEG_CLOCK_27MHZ;
1005
1006	switch (demod_type) {
1007	case MXL_EAGLE_DEMOD_TYPE_ATSC:
1008		status = mxl692_i2c_writeread(dev,
1009					      MXL_EAGLE_OPCODE_DEVICE_MPEG_OUT_PARAMS_SET,
1010					      (u8 *)&mpeg_params,
1011					      sizeof(struct MXL_EAGLE_MPEGOUT_PARAMS_T),
1012					      NULL,
1013					      0);
1014		if (status)
1015			goto err;
1016		break;
1017	case MXL_EAGLE_DEMOD_TYPE_QAM:
1018		if (qam_annex == MXL_EAGLE_QAM_DEMOD_ANNEX_A)
1019			mpeg_params.msb_first = MXL_EAGLE_DATA_SERIAL_LSB_1ST;
1020		status = mxl692_i2c_writeread(dev,
1021					      MXL_EAGLE_OPCODE_DEVICE_MPEG_OUT_PARAMS_SET,
1022					      (u8 *)&mpeg_params,
1023					      sizeof(struct MXL_EAGLE_MPEGOUT_PARAMS_T),
1024					      NULL,
1025					      0);
1026		if (status)
1027			goto err;
1028
1029		qam_params.annex_type = qam_annex;
1030		qam_params.qam_type = MXL_EAGLE_QAM_DEMOD_AUTO;
1031		qam_params.iq_flip = MXL_EAGLE_DEMOD_IQ_AUTO;
1032		if (p->modulation == QAM_64)
1033			qam_params.symbol_rate_hz = 5057000;
1034		else
1035			qam_params.symbol_rate_hz = 5361000;
1036
1037		qam_params.symbol_rate_256qam_hz = 5361000;
1038
1039		status = mxl692_i2c_writeread(dev,
1040					      MXL_EAGLE_OPCODE_QAM_PARAMS_SET,
1041					      (u8 *)&qam_params,
1042					      sizeof(struct MXL_EAGLE_QAM_DEMOD_PARAMS_T),
1043					      NULL, 0);
1044		if (status)
1045			goto err;
1046
1047		break;
1048	default:
1049		break;
1050	}
1051
1052	usleep_range(20 * 1000, 30 * 1000); /* was 500! */
1053
1054	tuner_params.freq_hz = p->frequency;
1055	tuner_params.bandwidth = MXL_EAGLE_TUNER_BW_6MHZ;
1056	tuner_params.tune_mode = MXL_EAGLE_TUNER_CHANNEL_TUNE_MODE_VIEW;
1057
1058	dev_dbg(&dev->i2c_client->dev, " Tuning Freq: %d %s\n", tuner_params.freq_hz,
1059		demod_type == MXL_EAGLE_DEMOD_TYPE_ATSC ? "ATSC" : "QAM");
1060
1061	status = mxl692_i2c_writeread(dev,
1062				      MXL_EAGLE_OPCODE_TUNER_CHANNEL_TUNE_SET,
1063				      (u8 *)&tuner_params,
1064				      sizeof(struct MXL_EAGLE_TUNER_CHANNEL_PARAMS_T),
1065				      NULL,
1066				      0);
1067	if (status)
1068		goto err;
1069
1070	usleep_range(20 * 1000, 30 * 1000); /* was 500! */
1071
1072	switch (demod_type) {
1073	case MXL_EAGLE_DEMOD_TYPE_ATSC:
1074		status = mxl692_i2c_writeread(dev,
1075					      MXL_EAGLE_OPCODE_ATSC_INIT_SET,
1076					      NULL, 0, NULL, 0);
1077		if (status)
1078			goto err;
1079		break;
1080	case MXL_EAGLE_DEMOD_TYPE_QAM:
1081		status = mxl692_i2c_writeread(dev,
1082					      MXL_EAGLE_OPCODE_QAM_RESTART_SET,
1083					      NULL, 0, NULL, 0);
1084		if (status)
1085			goto err;
1086		break;
1087	default:
1088		break;
1089	}
1090
1091	dev->demod_type = demod_type;
1092	dev->current_frequency = p->frequency;
1093
1094	return 0;
1095err:
1096	dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
1097	return status;
1098}
1099
1100static int mxl692_get_frontend(struct dvb_frontend *fe,
1101			       struct dtv_frontend_properties *p)
1102{
1103	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1104
1105	p->modulation = c->modulation;
1106	p->frequency = c->frequency;
1107
1108	return 0;
1109}
1110
1111static int mxl692_read_snr(struct dvb_frontend *fe, u16 *snr)
1112{
1113	struct mxl692_dev *dev = fe->demodulator_priv;
1114	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1115	u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
1116	struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *atsc_status;
1117	struct MXL_EAGLE_QAM_DEMOD_STATUS_T *qam_status;
1118	enum MXL_EAGLE_DEMOD_TYPE_E demod_type = dev->demod_type;
1119	int mxl_status = 0;
1120
1121	*snr = 0;
1122
1123	dev_dbg(&dev->i2c_client->dev, "\n");
1124
1125	atsc_status = (struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *)&rx_buf;
1126	qam_status = (struct MXL_EAGLE_QAM_DEMOD_STATUS_T *)&rx_buf;
1127
1128	switch (demod_type) {
1129	case MXL_EAGLE_DEMOD_TYPE_ATSC:
1130		mxl_status = mxl692_i2c_writeread(dev,
1131						  MXL_EAGLE_OPCODE_ATSC_STATUS_GET,
1132						  NULL,
1133						  0,
1134						  rx_buf,
1135						  sizeof(struct MXL_EAGLE_ATSC_DEMOD_STATUS_T));
1136		if (!mxl_status) {
1137			*snr = (u16)(atsc_status->snr_db_tenths / 10);
1138			c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1139			c->cnr.stat[0].svalue = *snr;
1140		}
1141		break;
1142	case MXL_EAGLE_DEMOD_TYPE_QAM:
1143		mxl_status = mxl692_i2c_writeread(dev,
1144						  MXL_EAGLE_OPCODE_QAM_STATUS_GET,
1145						  NULL,
1146						  0,
1147						  rx_buf,
1148						  sizeof(struct MXL_EAGLE_QAM_DEMOD_STATUS_T));
1149		if (!mxl_status)
1150			*snr = (u16)(qam_status->snr_db_tenths / 10);
1151		break;
1152	case MXL_EAGLE_DEMOD_TYPE_OOB:
1153	default:
1154		break;
1155	}
1156
1157	if (mxl_status)
1158		dev_dbg(&dev->i2c_client->dev, "err %d\n", mxl_status);
1159	return mxl_status;
1160}
1161
1162static int mxl692_read_ber_ucb(struct dvb_frontend *fe)
1163{
1164	struct mxl692_dev *dev = fe->demodulator_priv;
1165	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1166	u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
1167	struct MXL_EAGLE_ATSC_DEMOD_ERROR_COUNTERS_T *atsc_errors;
1168	enum MXL_EAGLE_DEMOD_TYPE_E demod_type = dev->demod_type;
1169	int mxl_status = 0;
1170	u32 utmp;
1171
1172	dev_dbg(&dev->i2c_client->dev, "\n");
1173
1174	atsc_errors = (struct MXL_EAGLE_ATSC_DEMOD_ERROR_COUNTERS_T *)&rx_buf;
1175
1176	switch (demod_type) {
1177	case MXL_EAGLE_DEMOD_TYPE_ATSC:
1178		mxl_status = mxl692_i2c_writeread(dev,
1179						  MXL_EAGLE_OPCODE_ATSC_ERROR_COUNTERS_GET,
1180						  NULL,
1181						  0,
1182						  rx_buf,
1183						  sizeof(struct MXL_EAGLE_ATSC_DEMOD_ERROR_COUNTERS_T));
1184		if (!mxl_status) {
1185			if (atsc_errors->error_packets == 0)
1186				utmp = 0;
1187			else
1188				utmp = ((atsc_errors->error_bytes / atsc_errors->error_packets) *
1189					atsc_errors->total_packets);
1190			/* ber */
1191			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1192			c->post_bit_error.stat[0].uvalue += atsc_errors->error_bytes;
1193			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1194			c->post_bit_count.stat[0].uvalue += utmp;
1195			/* ucb */
1196			c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1197			c->block_error.stat[0].uvalue += atsc_errors->error_packets;
1198
1199			dev_dbg(&dev->i2c_client->dev, "%llu   %llu\n",
1200				c->post_bit_count.stat[0].uvalue, c->block_error.stat[0].uvalue);
1201		}
1202		break;
1203	case MXL_EAGLE_DEMOD_TYPE_QAM:
1204	case MXL_EAGLE_DEMOD_TYPE_OOB:
1205	default:
1206		break;
1207	}
1208
1209	if (mxl_status)
1210		dev_dbg(&dev->i2c_client->dev, "err %d\n", mxl_status);
1211
1212	return mxl_status;
1213}
1214
1215static int mxl692_read_status(struct dvb_frontend *fe,
1216			      enum fe_status *status)
1217{
1218	struct mxl692_dev *dev = fe->demodulator_priv;
1219	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1220	u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
1221	struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *atsc_status;
1222	struct MXL_EAGLE_QAM_DEMOD_STATUS_T *qam_status;
1223	enum MXL_EAGLE_DEMOD_TYPE_E demod_type = dev->demod_type;
1224	int mxl_status = 0;
1225	*status = 0;
1226
1227	dev_dbg(&dev->i2c_client->dev, "\n");
1228
1229	atsc_status = (struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *)&rx_buf;
1230	qam_status = (struct MXL_EAGLE_QAM_DEMOD_STATUS_T *)&rx_buf;
1231
1232	switch (demod_type) {
1233	case MXL_EAGLE_DEMOD_TYPE_ATSC:
1234		mxl_status = mxl692_i2c_writeread(dev,
1235						  MXL_EAGLE_OPCODE_ATSC_STATUS_GET,
1236						  NULL,
1237						  0,
1238						  rx_buf,
1239						  sizeof(struct MXL_EAGLE_ATSC_DEMOD_STATUS_T));
1240		if (!mxl_status && atsc_status->atsc_lock) {
1241			*status |= FE_HAS_SIGNAL;
1242			*status |= FE_HAS_CARRIER;
1243			*status |= FE_HAS_VITERBI;
1244			*status |= FE_HAS_SYNC;
1245			*status |= FE_HAS_LOCK;
1246
1247			c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1248			c->cnr.stat[0].svalue = atsc_status->snr_db_tenths / 10;
1249		}
1250		break;
1251	case MXL_EAGLE_DEMOD_TYPE_QAM:
1252		mxl_status = mxl692_i2c_writeread(dev,
1253						  MXL_EAGLE_OPCODE_QAM_STATUS_GET,
1254						  NULL,
1255						  0,
1256						  rx_buf,
1257						  sizeof(struct MXL_EAGLE_QAM_DEMOD_STATUS_T));
1258		if (!mxl_status && qam_status->qam_locked) {
1259			*status |= FE_HAS_SIGNAL;
1260			*status |= FE_HAS_CARRIER;
1261			*status |= FE_HAS_VITERBI;
1262			*status |= FE_HAS_SYNC;
1263			*status |= FE_HAS_LOCK;
1264
1265			c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1266			c->cnr.stat[0].svalue = qam_status->snr_db_tenths / 10;
1267		}
1268		break;
1269	case MXL_EAGLE_DEMOD_TYPE_OOB:
1270	default:
1271		break;
1272	}
1273
1274	if ((*status & FE_HAS_LOCK) == 0) {
1275		/* No lock, reset all statistics */
1276		c->cnr.len = 1;
1277		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1278		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1279		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1280		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1281		return 0;
1282	}
1283
1284	if (mxl_status)
1285		dev_dbg(&dev->i2c_client->dev, "err %d\n", mxl_status);
1286	else
1287		mxl_status = mxl692_read_ber_ucb(fe);
1288
1289	return mxl_status;
1290}
1291
1292static const struct dvb_frontend_ops mxl692_ops = {
1293	.delsys = { SYS_ATSC },
1294	.info = {
1295		.name = "MaxLinear MxL692 VSB tuner-demodulator",
1296		.frequency_min_hz      = 54000000,
1297		.frequency_max_hz      = 858000000,
1298		.frequency_stepsize_hz = 62500,
1299		.caps = FE_CAN_8VSB
1300	},
1301
1302	.init         = mxl692_init,
1303	.sleep        = mxl692_sleep,
1304	.set_frontend = mxl692_set_frontend,
1305	.get_frontend = mxl692_get_frontend,
1306
1307	.read_status          = mxl692_read_status,
1308	.read_snr             = mxl692_read_snr,
1309};
1310
1311static int mxl692_probe(struct i2c_client *client)
1312{
1313	struct mxl692_config *config = client->dev.platform_data;
1314	struct mxl692_dev *dev;
1315	int ret = 0;
1316
1317	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1318	if (!dev) {
1319		ret = -ENOMEM;
1320		dev_dbg(&client->dev, "kzalloc() failed\n");
1321		goto err;
1322	}
1323
1324	memcpy(&dev->fe.ops, &mxl692_ops, sizeof(struct dvb_frontend_ops));
1325	dev->fe.demodulator_priv = dev;
1326	dev->i2c_client = client;
1327	*config->fe = &dev->fe;
1328	mutex_init(&dev->i2c_lock);
1329	i2c_set_clientdata(client, dev);
1330
1331	dev_info(&client->dev, "MaxLinear mxl692 successfully attached\n");
1332
1333	return 0;
1334err:
1335	dev_dbg(&client->dev, "failed %d\n", ret);
1336	return -ENODEV;
1337}
1338
1339static void mxl692_remove(struct i2c_client *client)
1340{
1341	struct mxl692_dev *dev = i2c_get_clientdata(client);
1342
1343	dev->fe.demodulator_priv = NULL;
1344	i2c_set_clientdata(client, NULL);
1345	kfree(dev);
1346}
1347
1348static const struct i2c_device_id mxl692_id_table[] = {
1349	{ "mxl692" },
1350	{}
1351};
1352MODULE_DEVICE_TABLE(i2c, mxl692_id_table);
1353
1354static struct i2c_driver mxl692_driver = {
1355	.driver = {
1356		.name	= "mxl692",
1357	},
1358	.probe		= mxl692_probe,
1359	.remove		= mxl692_remove,
1360	.id_table	= mxl692_id_table,
1361};
1362
1363module_i2c_driver(mxl692_driver);
1364
1365MODULE_AUTHOR("Brad Love <brad@nextdimension.cc>");
1366MODULE_DESCRIPTION("MaxLinear MxL692 demodulator/tuner driver");
1367MODULE_FIRMWARE(MXL692_FIRMWARE);
1368MODULE_LICENSE("GPL");
~/ Read-only file preview.