brintos

brintos / linux-shallow public Read only

0
0
Text · 34.5 KiB · bbc2bc7 Raw
1369 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for the MaxLinear MxL69x family of combo tuners/demods4 *5 * Copyright (C) 2020 Brad Love <brad@nextdimension.cc>6 *7 * based on code:8 * Copyright (c) 2016 MaxLinear, Inc. All rights reserved9 * which was released under GPL V210 */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_len42	};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_len59	};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_ENDIAN114	return;115#endif116	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_ENDIAN138	return;139#endif140	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, 0x80220	};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_ENDIAN273			convert_endian(sizeof(u32), plocal_buf);274#endif275			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_ENDIAN322	convert_endian(sizeof(u32) + total_len, local_buf + 2);323#endif324	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_ENDIAN348	convert_endian(sizeof(u32), plocal_buf);349#endif350	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_ENDIAN356		if (status == 0)357			convert_endian(size, buffer);358#endif359	} 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_ENDIAN483	convert_endian(4, (u8 *)&tx_header->checksum); /* cksum is big endian */484#endif485	/* 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_ENDIAN539	convert_endian(4, (u8 *)&resp_checksum_tmp); /* cksum is big endian */540#endif541	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		else1035			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			else1188				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	else1287		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_8VSB1300	},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");1369